Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions AI_INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@ when the token is unset.
workflow, #168 — owner contact is staff-only via authorized server
actions), `reports` (#179 — aggregate metrics workspace + audited CSV
export; public counterpart is `/statistics`, a separate suppressed DTO)
- **Production gate**: `SITE_MAINTENANCE_MODE=true` (Vercel Production
only) redirects all public paths to `/under-construction`; `/login`,
`/admin`, `/api/auth`, and static assets stay reachable
- **Pre-launch access**: Vercel Deployment Protection (Vercel
Authentication, All Deployments) — deployment configuration, not code.
- **Maintenance mode** (operational, not the launch gate):
`SITE_MAINTENANCE_MODE=true` (Vercel Production
only) redirects public paths to `/under-construction` unless the request
has a verified admin session; `/login`, `/admin`, `/portal`, `/api/auth`,
`/api/cron`, `/api/webhooks`, and static assets stay reachable, so portal,
cron, and webhook writes continue

## Architectural invariants — do not casually violate

Expand Down
41 changes: 35 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,41 @@ boundary and §18 for the Storage procedure.
1. Push code to GitHub
2. Import the project in [Vercel](https://vercel.com)
3. Add all environment variables from `.env.example` in the Vercel dashboard
4. Deploy
4. Before the first deploy, enable Vercel Authentication → **All Deployments**
(see Pre-launch access below) so production is never briefly public
5. Deploy

### Pre-launch access (Vercel Deployment Protection)
Comment thread
sourcery-ai[bot] marked this conversation as resolved.

Pre-launch access to the whole site is controlled by Vercel, not by the
application: Vercel → Settings → Deployment Protection → Vercel
Authentication → **All Deployments** restricts production domains, generated
`*.vercel.app` URLs and previews to Vercel team members. At launch, switch to
**Standard Protection** (previews stay protected). Standard Protection alone
does not protect the production domain. Check for Protection Exceptions,
Shareable Links and unused Protection Bypass for Automation secrets.

While All Deployments protection is on, unauthenticated machine callers are
blocked before reaching the app — notably the Resend webhook
(`/api/webhooks/resend`) and owner `/portal` links in reminder emails. Confirm
Vercel Cron reaches `/api/cron/*` in the cron logs. If a machine caller must
get through, give only that caller's URL a Protection Bypass for Automation
secret. The secret is project-wide (it bypasses protection on every
deployment), so treat it as a credential and rotate it if exposed. Never use a
Protection Exception; the routes keep their own authentication
(`RESEND_WEBHOOK_SECRET`, `CRON_SECRET`).

Application authorization (`admin`/`editor` roles in `admin_users`, owner
`/portal` sessions) is independent of Vercel settings.

### Maintenance mode

The production public site can be gated behind `/under-construction` while
`/login`, `/admin`, the auth session API, and framework/static assets stay
reachable.
Maintenance mode is an operational control for risky work, not the pre-launch
gate. The production public site can be gated behind `/under-construction`
while `/login`, `/admin`, `/portal`, `/api/auth/*`, `/api/cron/*`,
`/api/webhooks/*`, and framework/static assets stay reachable; verified admins
also bypass the redirect. It does **not** stop owner `/portal` actions, cron
jobs, or webhook writebacks — pausing those needs a separate action.
Comment thread
spizeck marked this conversation as resolved.

- **Enable (production only):** set `SITE_MAINTENANCE_MODE=true` in the
Vercel **Production** environment and redeploy.
Expand Down Expand Up @@ -466,8 +494,9 @@ placeholder-only variable lists. Categories:
`NEXT_PUBLIC_FIREBASE_*`, `NEXT_PUBLIC_GTM_ID`, `NEXT_PUBLIC_SITE_URL`
- **Server-only secrets** (never commit): `FIREBASE_ADMIN_*`,
`ADMIN_EMAILS`, `VERCEL_TOKEN`, `VERCEL_PROJECT_ID`
- **Behavior flags** (server-only): `SITE_MAINTENANCE_MODE` (production
gate, see Deployment); `NEXT_PUBLIC_USE_FIREBASE_EMULATOR` is set only
- **Behavior flags** (server-only): `SITE_MAINTENANCE_MODE` (operational
maintenance mode, see Deployment — pre-launch access is Vercel Deployment
Protection); `NEXT_PUBLIC_USE_FIREBASE_EMULATOR` is set only
by the E2E harness — never set it for real deployments

Analytics runs through Google Tag Manager (`NEXT_PUBLIC_GTM_ID`), which
Expand Down
Loading