Add Compose stack & Caddy deploy artifacts (task 05)
Multi-stage Dockerfile (pnpm fetch/offline, standalone output, non-root nextjs user), deploy/compose.yaml with famapp + famapp-db + full Authentik stack on famapp_net, Caddyfile.snippet for fam/auth.ginnoir.com, and .env.production.example. Added .dockerignore and public/.gitkeep. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
e00c95d4d6
commit
f59753404e
@@ -0,0 +1,10 @@
|
|||||||
|
node_modules
|
||||||
|
.next
|
||||||
|
.git
|
||||||
|
deploy
|
||||||
|
drizzle
|
||||||
|
docs
|
||||||
|
*.md
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
|
.vscode
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# ── famapp ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Public URL for the app (used in share links, OIDC redirect URIs, etc.)
|
||||||
|
NEXT_PUBLIC_APP_URL=https://fam.ginnoir.com
|
||||||
|
|
||||||
|
# famapp Postgres credentials (used to build DATABASE_URL inside compose.yaml)
|
||||||
|
FAMAPP_DB_USER=famapp
|
||||||
|
FAMAPP_DB_PASSWORD=replace-with-strong-password
|
||||||
|
FAMAPP_DB_NAME=famapp
|
||||||
|
|
||||||
|
# Auth.js session secret — generate with: openssl rand -base64 32
|
||||||
|
AUTH_SECRET=replace-with-openssl-rand-base64-32
|
||||||
|
|
||||||
|
# OIDC provider (Authentik) — task 06 will fill these in after bootstrapping
|
||||||
|
AUTH_OIDC_ISSUER=https://auth.ginnoir.com/application/o/famapp/
|
||||||
|
AUTH_OIDC_CLIENT_ID=replace-me
|
||||||
|
AUTH_OIDC_CLIENT_SECRET=replace-me
|
||||||
|
|
||||||
|
# Web Push VAPID keys — generate with: pnpm vapid:generate
|
||||||
|
VAPID_PUBLIC_KEY=
|
||||||
|
VAPID_PRIVATE_KEY=
|
||||||
|
# Must be "mailto:<address>" or a URL
|
||||||
|
VAPID_SUBJECT=mailto:you@example.com
|
||||||
|
|
||||||
|
# ntfy (optional push fallback — leave blank to disable)
|
||||||
|
NTFY_URL=
|
||||||
|
NTFY_TOPIC=
|
||||||
|
|
||||||
|
# Log level: error | warn | info | debug
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
|
# ── Authentik ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Authentik Postgres credentials (separate DB per Matt's rule)
|
||||||
|
AUTHENTIK_DB_USER=authentik
|
||||||
|
AUTHENTIK_DB_PASSWORD=replace-with-strong-password
|
||||||
|
AUTHENTIK_DB_NAME=authentik
|
||||||
|
|
||||||
|
# Authentik secret key — generate with: openssl rand -base64 60
|
||||||
|
AUTHENTIK_SECRET_KEY=replace-with-openssl-rand-base64-60
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# ── Stage 1: fetch dependencies ───────────────────────────────────────────────
|
||||||
|
FROM node:22-alpine AS deps
|
||||||
|
RUN corepack enable && corepack prepare pnpm@10.33.3 --activate
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json pnpm-lock.yaml .npmrc ./
|
||||||
|
# Populate the pnpm virtual store; this layer is cached until lock file changes.
|
||||||
|
RUN pnpm fetch
|
||||||
|
|
||||||
|
# ── Stage 2: build ────────────────────────────────────────────────────────────
|
||||||
|
FROM deps AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
# CI=true prevents pnpm from prompting for TTY confirmation when removing modules dir
|
||||||
|
ENV CI=true
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
COPY . .
|
||||||
|
RUN pnpm install --offline --frozen-lockfile
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# ── Stage 3: production runtime ───────────────────────────────────────────────
|
||||||
|
FROM node:22-alpine AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
|
ENV HOSTNAME=0.0.0.0
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs \
|
||||||
|
&& adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["node", "server.js"]
|
||||||
@@ -9,9 +9,11 @@ Living progress tracker. Update at the end of each task. The canonical brief is
|
|||||||
- **03 — Drizzle + Postgres setup**. drizzle-orm + postgres driver + drizzle-kit wired up. `src/modules/_core/schema.ts` declares `users`, `households`, `household_members`. `docker-compose.dev.yaml` starts Postgres 16. `drizzle/0000_silent_magma.sql` generated and applied. `tsc --noEmit` passes.
|
- **03 — Drizzle + Postgres setup**. drizzle-orm + postgres driver + drizzle-kit wired up. `src/modules/_core/schema.ts` declares `users`, `households`, `household_members`. `docker-compose.dev.yaml` starts Postgres 16. `drizzle/0000_silent_magma.sql` generated and applied. `tsc --noEmit` passes.
|
||||||
- **04 — Module loader & registry**. `src/modules/_core/module.ts` types (`ModuleManifest`, `EntityTypeRegistration`, `DashboardWidget`, etc.), `registry.ts` singleton with `registerModule`/`getRegistry`/`getEntityType`/`getWidget`, barrel `_core/index.ts`. Stub manifests for `calendar`, `lists`, `notes`. `src/modules/index.ts` loader. Root layout imports loader; `AppNav` reads registry for nav links. `/debug/registry` dumps full registry JSON (dev only). Uses zod v4 + built-in `z.toJSONSchema()`. `tsc --noEmit`, `pnpm build`, `pnpm lint` all clean.
|
- **04 — Module loader & registry**. `src/modules/_core/module.ts` types (`ModuleManifest`, `EntityTypeRegistration`, `DashboardWidget`, etc.), `registry.ts` singleton with `registerModule`/`getRegistry`/`getEntityType`/`getWidget`, barrel `_core/index.ts`. Stub manifests for `calendar`, `lists`, `notes`. `src/modules/index.ts` loader. Root layout imports loader; `AppNav` reads registry for nav links. `/debug/registry` dumps full registry JSON (dev only). Uses zod v4 + built-in `z.toJSONSchema()`. `tsc --noEmit`, `pnpm build`, `pnpm lint` all clean.
|
||||||
|
|
||||||
|
- **05 — Compose + Caddy**. `Dockerfile` (3-stage: deps/builder/runner, pnpm fetch + offline install, non-root `nextjs` user, `output: standalone`), `deploy/compose.yaml` (famapp + famapp-db + full Authentik stack on `famapp_net`), `deploy/Caddyfile.snippet`, `.env.production.example`. `docker build -t famapp .` succeeds (~311 MB); `docker compose -f deploy/compose.yaml config` validates clean. Added `.dockerignore` and `public/.gitkeep`.
|
||||||
|
|
||||||
## Next up
|
## Next up
|
||||||
|
|
||||||
- **05 — Compose + Caddy** ([brief](docs/tasks/05-compose-caddy.md)).
|
- **06 — Authentik OIDC** ([brief](docs/tasks/06-authentik-oidc.md)).
|
||||||
|
|
||||||
## Phase 1 remaining
|
## Phase 1 remaining
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Include from main Caddyfile or paste into the existing one.
|
||||||
|
|
||||||
|
fam.ginnoir.com {
|
||||||
|
reverse_proxy famapp:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
auth.ginnoir.com {
|
||||||
|
reverse_proxy authentik-server:9000
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user