Middleware & Route Protection
1.1 routePipelines
Location: src/middleware/routePipelines.ts
Purpose: Defines route patterns and their associated handler pipelines for middleware-based access control.
Description: This configuration array maps URL patterns (using regex) to arrays of handler functions that execute sequentially. Each handler can allow or deny access, redirect users, or perform other middleware operations.
Structure:
{
pattern: RegExp, // Regex pattern to match URL paths
handlers: Array<HandlerFunction> // Array of handler functions to execute
}
Key Routes:
/[primaryTeam]- Primary team access validation/[primaryTeam]/campaign/*- Campaign-specific routes/api/essearch- Elasticsearch API access/api/duplicate- Duplicate checking API
Example:
{
pattern: /^\/[^/]+\/campaign\/[^/]+\/add-signatures$/,
handlers: [
checkCampaignHome,
genCampaignHandler("campaigns-signatures-create")
]
}
Notes:
- Handlers execute in order
- If any handler returns a redirect, subsequent handlers are skipped
- Patterns use regex for flexible matching
1.2 checkCampaignHome
Location: src/middleware/validators/campaign-route.ts
Purpose: Validates that a user has access to a specific campaign before allowing access to campaign routes.
Signature:
async function checkCampaignHome({
session,
request
}: HandlerContext): Promise<NextResponse>
Parameters:
session- User session object containingallowed_campaignsarrayrequest- Next.js request object
Returns: NextResponse - Either continues to next handler or redirects
Logic:
- Extracts
teamIdfrom URL path (first segment) - Extracts
campaignIdfrom URL path (third segment) - Checks if
campaignIdexists insession.allowed_campaigns - Redirects to team home if access denied
Example:
// URL: /my-team/campaign/campaign-123/dashboard
// Checks if "campaign-123" is in session.allowed_campaigns
Error Handling:
- Redirects to
/{teamId}if campaign access denied - Returns
NextResponse.next()if access granted
1.3 checkCampaignGenFeat
Location: src/middleware/validators/campaign-route.ts
Purpose: Validates that a user has a specific permission for a campaign route.
Signature:
async function checkCampaignGenFeat({
session,
request,
checkID
}: CheckGenFeatContext): Promise<NextResponse>
Parameters:
session- User session withpermissionsarrayrequest- Next.js request objectcheckID- Permission ID to check (e.g., "campaigns-signatures-create")
Returns: NextResponse - Either continues or redirects to campaign home
Logic:
- Extracts team and campaign IDs from URL
- Checks if
checkIDexists insession.permissions - Redirects to campaign home if permission missing
Common Permission IDs:
campaigns-signatures-create- Create signaturescampaigns-signatures-read- View signaturescampaigns-rates-create- Create ratescampaigns-dashboard- View dashboard
1.4 checkPrimaryTeamAllowed
Location: src/middleware/validators/team-route.ts
Purpose: Validates that a user has access to the primary team in the URL.
Signature:
async function checkPrimaryTeamAllowed({
session,
request
}: HandlerContext): Promise<NextResponse>
Parameters:
session- User session withallowed_teamsarrayrequest- Next.js request object
Returns: NextResponse - Either continues or redirects to home
Logic:
- Extracts team ID from first URL segment
- Checks if team ID exists in
session.allowed_teams - Redirects to home (
/) if access denied
Example:
// URL: /my-team/campaigns
// Checks if "my-team" is in session.allowed_teams
1.5 checkGenFeat
Location: src/middleware/validators/team-route.ts
Purpose: Generic permission checker for team-level features.
Signature:
async function checkGenFeat({
session,
request,
checkID
}: CheckGenFeatContext): Promise<NextResponse>
Parameters:
session- User session withpermissionsarrayrequest- Next.js request objectcheckID- Permission ID to validate
Returns: NextResponse - Either continues or redirects to team home
Logic:
- Extracts team ID from URL
- Checks if
checkIDexists insession.permissions - Redirects to
/{teamId}if permission missing
1.6 checkVoterSearchControl
Location: src/middleware/validators/api-routes.ts
Purpose: Validates voter search API access permissions.
Signature:
async function checkVoterSearchControl({
session,
request
}: HandlerContext): Promise<NextResponse>
Logic:
- Checks for
voter-searchORadmin-voter-searchpermissions - Redirects to home if neither permission exists
1.7 checkEssearchFeat
Location: src/middleware/validators/api-routes.ts
Purpose: Validates Elasticsearch API access for signature creation.
Signature:
async function checkEssearchFeat({
session,
request
}: HandlerContext): Promise<NextResponse>
Logic:
- Requires
campaigns-signatures-createpermission - Used for
/api/essearchand/api/duplicateroutes