# Co-op Check-in (WebForm-mw) Standalone Next.js middleware that lets external co-op contacts update their organization's tracking data on CiviCRM, sidestepping the limitations of Webform CiviCRM's admin UI. This app is the **v2** delivery path described in `../docs/superpowers/specs/2026-05-08-civi-webform-design.md`. ## What it does A form-filler clicks a tokenized link in an email: ``` https://check-in.fci.coop/?cid=&cs= ``` The app: 1. Verifies the checksum against CiviCRM. 2. Resolves the org from the contact's **Primary Form Contact** relationship. 3. Reads the org's **Framework Stage** (`Food_Co_op_Organizing.Stage`) — text-keyed values like `Inquiry`, `Organizing`, `Feasibility`, `Business feasibility`, `Store Implementation`, `Stabilize newly opened co-op`. 4. Walks the org's past `Org Engagement Submission` activities DESC and assembles per-field-most-recent prefill values (the exact behaviour the WCM admin UI cannot express). 5. Renders the form with stage-conditional sections — Stage 0 (Inquiry / core check-in fields, ~32 of them) is always visible; Stages 1–5 each appear when `current_stage` is in their visibility set. 6. On submit, creates a **new immutable** `Org Engagement Submission` activity with the visible-field values plus a `stage_at_submission` audit field. ## Tech stack - Next.js 16 (App Router) + React 19 + TypeScript - Tailwind CSS 4 (CSS-based `@theme` config) - `react-hook-form` for state + validation - `axios` (only used in earlier scaffolding; this version uses native `fetch`) ## Project structure ``` app/ layout.tsx Root layout, fonts (Inter + Source Serif 4) page.tsx Public form entry; reads cid+cs from URL globals.css Tailwind 4 + theme tokens (leaf + stone palettes) api/ data/route.ts GET form data + per-field-most-recent prefill submit/route.ts POST submission → creates new Civi activity components/ EngagementForm.tsx Top-level orchestrator StageSection.tsx Collapsible accordion card per stage section SiteChrome.tsx Header + footer chrome (logo placeholder included) fields/ FieldRenderer.tsx One renderer for all 12 field types config/ form.ts The 123-field form definition lib/ civicrm.ts APIv4 client (Bearer-style auth) conditional.ts Visibility rule engine prefill.ts Per-field-most-recent walk types/ form.ts FormConfig, FieldConfig, VisibilityRule, etc. ``` ## Configuration The app falls back to **STUB MODE** with hardcoded mock data when any of these environment variables are missing. The UI renders fully and the form is interactive, but no CiviCRM calls are made. ```bash # .env.local CIVI_BASE_URL=https://crm.fci.coop CIVI_API_KEY= CIVI_SITE_KEY= ``` The exact auth header strategy depends on which CiviCRM auth extension is active. The default in `lib/civicrm.ts` uses the AuthX-style Bearer header for the API key plus the legacy `X-Civi-Key` for the site key. If your instance uses a different scheme (e.g. classic APIv3 `api_key`+`key` query params), adjust `lib/civicrm.ts` accordingly. ### Custom-field references (CiviCRM APIv4) Form fields write to CiviCRM custom fields via the `civiField` property. The convention is APIv4's `.` format. For now, `config/form.ts` uses placeholder `custom_` references for all but the Framework Stage. **Before going live, replace each `civiField` value with the actual APIv4 reference** for that custom field on the `Org Engagement Submission` activity type. To inventory the actual field names, query APIv4 from the Civi UI: ``` /civicrm/api4#/explorer → CustomField.get select: ["name", "label", "custom_group_id:name"] where: [["custom_group_id:name", "IN", ["Stage_0_Inquiry", "Stage_1_*", ...]]] ``` ## Running locally ```bash npm install npm run dev # open http://localhost:3000/?cid=anything&cs=anything (any non-empty cs while in stub mode) ``` ## Building ```bash npm run build ``` ## Deploying The simplest deployment is Vercel. The app is a standard App Router project: ```bash vercel ``` Set the three CiviCRM env vars in the Vercel project settings; the app auto-leaves stub mode the moment all three are present. For self-hosting, any Node 20+ environment supporting Next.js 16 will work: ```bash npm run build && npm start ``` ## Accessibility - All inputs have proper `