Phase 1 & 2: full-stack family dashboard scaffold
- pnpm monorepo (apps/client + apps/server)
- Server: Express + node:sqlite with numbered migration runner,
REST API for all 9 features (members, events, chores, shopping,
meals, messages, countdowns, photos, settings)
- Client: React 18 + Vite + TypeScript + Tailwind + Framer Motion + Zustand
- Theme system: dark/light + 5 accent colors, CSS custom properties,
anti-FOUC script, ThemeToggle on every surface
- AppShell: collapsible sidebar, animated route transitions, mobile drawer
- Phase 2 features: Calendar (custom month grid, event chips, add/edit modal),
Chores (card grid, complete/reset, member filter, streaks),
Shopping (multi-list tabs, animated check-off, quick-add bar, member assign)
- Family member CRUD with avatar, color picker
- Settings page: theme/accent, photo folder, slideshow, weather, date/time
- Docker: multi-stage Dockerfile, docker-compose.yml, entrypoint with PUID/PGID
- Unraid: CA XML template, CLI install script, UNRAID.md guide
- .gitignore covering node_modules, dist, db files, secrets, build artifacts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 21:56:30 -05:00
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
# Stage 1 — Build client
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
FROM node:22-alpine AS client-builder
|
|
|
|
|
|
|
|
|
|
WORKDIR /build
|
|
|
|
|
|
|
|
|
|
# Install pnpm
|
|
|
|
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
|
|
|
|
|
|
|
|
# Copy workspace manifests first for better layer caching
|
|
|
|
|
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml* ./
|
|
|
|
|
COPY apps/client/package.json ./apps/client/
|
|
|
|
|
COPY apps/server/package.json ./apps/server/
|
|
|
|
|
COPY tsconfig.base.json ./
|
|
|
|
|
|
|
|
|
|
# Install all workspace deps
|
|
|
|
|
RUN pnpm install --frozen-lockfile
|
|
|
|
|
|
|
|
|
|
# Copy client source and build
|
|
|
|
|
COPY apps/client ./apps/client/
|
|
|
|
|
RUN pnpm --filter client build
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
# Stage 2 — Build server
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
FROM node:22-alpine AS server-builder
|
|
|
|
|
|
|
|
|
|
WORKDIR /build
|
|
|
|
|
|
|
|
|
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
|
|
|
|
|
|
|
|
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml* ./
|
|
|
|
|
COPY apps/server/package.json ./apps/server/
|
|
|
|
|
COPY apps/client/package.json ./apps/client/
|
|
|
|
|
COPY tsconfig.base.json ./
|
|
|
|
|
|
|
|
|
|
# Install only server production deps + rebuild native modules for target arch
|
|
|
|
|
RUN pnpm install --frozen-lockfile
|
|
|
|
|
|
|
|
|
|
COPY apps/server ./apps/server/
|
|
|
|
|
RUN pnpm --filter server build
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
# Stage 3 — Production runtime
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
FROM node:22-alpine AS runtime
|
|
|
|
|
|
|
|
|
|
# Install tini for proper PID 1 signal handling
|
|
|
|
|
RUN apk add --no-cache tini su-exec
|
|
|
|
|
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
|
|
|
|
|
# No native deps — runtime only needs node_modules for pure-JS packages (express, cors, etc.)
|
2026-03-29 22:00:15 -05:00
|
|
|
# pnpm hoists everything to the root node_modules (shamefully-hoist=true in .npmrc)
|
Phase 1 & 2: full-stack family dashboard scaffold
- pnpm monorepo (apps/client + apps/server)
- Server: Express + node:sqlite with numbered migration runner,
REST API for all 9 features (members, events, chores, shopping,
meals, messages, countdowns, photos, settings)
- Client: React 18 + Vite + TypeScript + Tailwind + Framer Motion + Zustand
- Theme system: dark/light + 5 accent colors, CSS custom properties,
anti-FOUC script, ThemeToggle on every surface
- AppShell: collapsible sidebar, animated route transitions, mobile drawer
- Phase 2 features: Calendar (custom month grid, event chips, add/edit modal),
Chores (card grid, complete/reset, member filter, streaks),
Shopping (multi-list tabs, animated check-off, quick-add bar, member assign)
- Family member CRUD with avatar, color picker
- Settings page: theme/accent, photo folder, slideshow, weather, date/time
- Docker: multi-stage Dockerfile, docker-compose.yml, entrypoint with PUID/PGID
- Unraid: CA XML template, CLI install script, UNRAID.md guide
- .gitignore covering node_modules, dist, db files, secrets, build artifacts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 21:56:30 -05:00
|
|
|
COPY --from=server-builder /build/node_modules ./node_modules
|
|
|
|
|
|
|
|
|
|
# Copy compiled server output (includes dist/db/migrations/*.js compiled by tsc)
|
|
|
|
|
COPY --from=server-builder /build/apps/server/dist ./apps/server/dist
|
|
|
|
|
|
|
|
|
|
# Copy built client into the path the server expects
|
|
|
|
|
COPY --from=client-builder /build/apps/client/dist ./apps/client/dist
|
|
|
|
|
|
|
|
|
|
# ── Runtime configuration ─────────────────────────────────────────────────
|
|
|
|
|
ENV NODE_ENV=production \
|
|
|
|
|
PORT=3001 \
|
|
|
|
|
DATA_DIR=/data \
|
|
|
|
|
PHOTOS_DIR=/photos \
|
|
|
|
|
PUID=99 \
|
|
|
|
|
PGID=100 \
|
|
|
|
|
TZ=UTC \
|
|
|
|
|
NODE_NO_WARNINGS=1
|
|
|
|
|
|
|
|
|
|
# /data — persistent: SQLite database
|
|
|
|
|
# /photos — bind-mount: read-only user photo library
|
|
|
|
|
VOLUME ["/data"]
|
|
|
|
|
|
|
|
|
|
EXPOSE 3001
|
|
|
|
|
|
|
|
|
|
# Entrypoint: fix ownership then drop to PUID/PGID
|
|
|
|
|
COPY docker-entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
|
|
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
|
|
|
|
|
|
|
|
|
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/entrypoint.sh"]
|
|
|
|
|
CMD ["node", "apps/server/dist/index.js"]
|