Code-side
src/lib/dev-login-config.ts — startup assertion: throws if NODE_ENV=production + ENABLE_DEV_LOGIN=true, scoped to runtime (skipped during next build).
Container
scripts/migrate.mjs — runs Drizzle migrations against DATABASE_URL.
deploy/docker-entrypoint.sh — runs migrations then exec node server.js. Skip with RUN_MIGRATIONS=false.
Dockerfile — copies drizzle/, scripts/migrate.mjs, entrypoint into runner stage; ENTRYPOINT now points at the script.
Compose
deploy/compose.yaml — famapp now image: ${FAMAPP_IMAGE:-ghcr.io/ginnoir/famapp:latest} (build still works locally as fallback). Authentik pinned via AUTHENTIK_IMAGE_TAG (default 2024.12.3). New RUN_MIGRATIONS env passed through.
.env.production.example — documents FAMAPP_IMAGE, AUTHENTIK_IMAGE_TAG, RUN_MIGRATIONS.
CI/CD
.github/workflows/ci.yml — push/PR: typecheck + lint + format:check + build.
.github/workflows/release.yml — v* tag: build + push ghcr.io/ginnoir/famapp:vX.Y.Z, :X.Y, :latest to GHCR.
Docs
deploy/README.md — full deploy/rollback/release runbook.
CHANGELOG.md — release log seeded with an Unreleased entry.
docs/tasks/09-pre-deploy-checklist.md — task 09 reframed from one-shot removal to a recurring pre-deploy checklist.
STATUS.md — updated.
Verified: pnpm typecheck, pnpm format, pnpm build, and docker compose config all clean.
This commit is contained in:
@@ -25,11 +25,19 @@ Cheap to set up before modules exist, painful to retrofit afterwards. Locking in
|
||||
Use shadcn's CSS-variable conventions, scoped by `data-theme` on `<html>`:
|
||||
|
||||
```css
|
||||
:root { /* default light tokens */ }
|
||||
.dark { /* default dark tokens */ }
|
||||
:root {
|
||||
/* default light tokens */
|
||||
}
|
||||
.dark {
|
||||
/* default dark tokens */
|
||||
}
|
||||
|
||||
[data-theme="warm"] { /* warm light */ }
|
||||
[data-theme="warm"].dark { /* warm dark */ }
|
||||
[data-theme="warm"] {
|
||||
/* warm light */
|
||||
}
|
||||
[data-theme="warm"].dark {
|
||||
/* warm dark */
|
||||
}
|
||||
```
|
||||
|
||||
Ship at least **two** themes (`default` + one more) so the architecture is actually exercised. Token values can be placeholder — refining the palettes is a separate later concern.
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# 09 — Pre-deploy checklist (recurring)
|
||||
|
||||
Run this before every production deploy (first deploy and each tagged release). Dev-login is intentionally retained behind a double gate; this checklist is what keeps that gate honest.
|
||||
|
||||
## Env hygiene
|
||||
|
||||
- [ ] Server `.env` (next to `deploy/compose.yaml`) does **not** set:
|
||||
- `ENABLE_DEV_LOGIN`
|
||||
- `DEV_LOGIN_EMAIL`, `DEV_LOGIN_NAME`, `DEV_HOUSEHOLD_NAME`
|
||||
- [ ] Server `.env` sets real values for:
|
||||
- `NEXT_PUBLIC_APP_URL` (https)
|
||||
- `AUTH_SECRET` (`openssl rand -base64 32`)
|
||||
- `AUTH_OIDC_ISSUER`, `AUTH_OIDC_CLIENT_ID`, `AUTH_OIDC_CLIENT_SECRET`
|
||||
- `VAPID_PUBLIC_KEY`, `VAPID_PRIVATE_KEY`, `VAPID_SUBJECT`
|
||||
- `FAMAPP_DB_*`, `AUTHENTIK_DB_*`, `AUTHENTIK_SECRET_KEY`
|
||||
- [ ] `FAMAPP_IMAGE` pins a specific version tag (`ghcr.io/ginnoir/famapp:vX.Y.Z`), not `latest`, after first deploy.
|
||||
|
||||
## Code-side guard
|
||||
|
||||
`src/lib/dev-login-config.ts` throws on import if `NODE_ENV=production` and `ENABLE_DEV_LOGIN=true`. Container will refuse to start.
|
||||
|
||||
- [ ] Confirm guard is still present (do not remove without updating this checklist).
|
||||
|
||||
## Smoke after deploy
|
||||
|
||||
- [ ] `https://fam.ginnoir.com/login` shows only **Sign in with SSO** (no Dev login button).
|
||||
- [ ] Real Authentik sign-in succeeds, lands on dashboard.
|
||||
- [ ] First user appears in DB with household membership, default calendars, default lists.
|
||||
- [ ] No `dev@famapp.local` row in production `users` table.
|
||||
- [ ] Push opt-in works (settings → enable → test notification arrives).
|
||||
- [ ] A share link created from `/settings` resolves at `/s/<token>` while signed out.
|
||||
|
||||
## Backup / rollback
|
||||
|
||||
- [ ] Last `famapp-backup` cron run succeeded (check container logs).
|
||||
- [ ] Previous image tag is known and recorded in `CHANGELOG.md`, so rollback = bump `FAMAPP_IMAGE` and `docker compose up -d famapp`.
|
||||
@@ -1,47 +0,0 @@
|
||||
# 09 — Production dev-login removal gate
|
||||
|
||||
## Goal
|
||||
|
||||
Before the first production deployment, verify that development-only login/test shortcuts cannot be enabled accidentally in production.
|
||||
|
||||
## Depends on
|
||||
|
||||
- 06
|
||||
- 07
|
||||
- local dev-login setup in `docs/dev-login.md`
|
||||
|
||||
## Scope
|
||||
|
||||
- Review all production env sources:
|
||||
- `.env.production.example`
|
||||
- `deploy/compose.yaml`
|
||||
- any host-level Docker Compose override files
|
||||
- deployment secrets on the server
|
||||
- Confirm production does not set:
|
||||
- `ENABLE_DEV_LOGIN=true`
|
||||
- `DEV_LOGIN_EMAIL`
|
||||
- `DEV_LOGIN_NAME`
|
||||
- `DEV_HOUSEHOLD_NAME`
|
||||
- Confirm production Authentik variables are real:
|
||||
- `AUTH_OIDC_ISSUER`
|
||||
- `AUTH_OIDC_CLIENT_ID`
|
||||
- `AUTH_OIDC_CLIENT_SECRET`
|
||||
- Build with production-like env and verify `/login` renders only the SSO login path.
|
||||
- Verify the app still protects private routes without a valid Auth.js session cookie.
|
||||
- Verify real Authentik login creates the expected user, household membership, default calendars, and default lists.
|
||||
- Remove any accidental dev users from the production database.
|
||||
|
||||
## Optional hardening
|
||||
|
||||
- Remove `src/lib/dev-login.ts` and the Dev login form from `src/app/login/page.tsx` entirely before first production deployment.
|
||||
- If retaining the code for future local development, keep the current double gate:
|
||||
- `NODE_ENV !== "production"`
|
||||
- `ENABLE_DEV_LOGIN=true`
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Production env cannot enable Dev login accidentally.
|
||||
- [ ] `/login` in production does not show **Dev login**.
|
||||
- [ ] Direct dev-login action execution is unavailable in production.
|
||||
- [ ] Real Authentik login works on the production domain.
|
||||
- [ ] No `dev@famapp.local` or configured dev-login user exists in production data.
|
||||
@@ -6,7 +6,7 @@ Implement the `calendar` module: first-class **calendars** (multiple per househo
|
||||
|
||||
## Why
|
||||
|
||||
Calendars are entities, not a singleton concept. A user might run a *Personal* (private) calendar, a *Family* (household-shared) calendar, and a *Wedding planning* calendar that gets share-linked publicly. The calendar module ships that abstraction; widgets and the share-link service then reuse it generically.
|
||||
Calendars are entities, not a singleton concept. A user might run a _Personal_ (private) calendar, a _Family_ (household-shared) calendar, and a _Wedding planning_ calendar that gets share-linked publicly. The calendar module ships that abstraction; widgets and the share-link service then reuse it generically.
|
||||
|
||||
## Depends on
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Each user can create any number of named dashboards, switch between them, and ch
|
||||
|
||||
## Why
|
||||
|
||||
Decouples "the dashboard" from "user's home page". A user might have a *Daily*, *Garden*, and *Wedding planning* dashboard, each composing different widgets. This task introduces the entity; task 26 adds the editor.
|
||||
Decouples "the dashboard" from "user's home page". A user might have a _Daily_, _Garden_, and _Wedding planning_ dashboard, each composing different widgets. This task introduces the entity; task 26 adds the editor.
|
||||
|
||||
## Depends on
|
||||
|
||||
|
||||
@@ -52,8 +52,15 @@ Same component is reused for **Configure** on an already-placed widget. Re-runs
|
||||
{
|
||||
"version": 1,
|
||||
"widgets": [
|
||||
{ "widgetId": "lists.list", "config": { "listIds": ["..."], "showCompleted": false }, "x": 0, "y": 0, "w": 6, "h": 4 }
|
||||
]
|
||||
{
|
||||
"widgetId": "lists.list",
|
||||
"config": { "listIds": ["..."], "showCompleted": false },
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 6,
|
||||
"h": 4,
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user