Phase 3-4 of maintenance reminders.
scripts/maintenance-reminders.ts: thin CLI that opens the same
pg pool as the app and calls runRemindersOnce. Flags:
--soon-days N (default 7), --company <id> (default all),
--dry-run (count without firing), --backfill (mark all currently
due as already-sent, mutually exclusive with --dry-run). Prints a
single-line JSON summary so journald/jq handles it cleanly.
package.json: + reminders:check script.
DEPLOYMENT.md: documents the systemd .service + .timer pair for
06:00 daily, with Persistent=true so a missed run during host
downtime still fires on next boot. Includes the first-deploy
protocol (--dry-run to scope, then either let day-one alert or
--backfill for a clean slate).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`pnpm install --prod` skips devDependencies, so husky is not on
PATH when the prepare lifecycle script runs on the deploy host. Append
`|| true` so the script succeeds in both dev (hooks installed) and
prod (no-op).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pin Node 24 via .node-version/.nvmrc and pnpm 9.15.0 via
package.json#packageManager. Regenerate lockfile as pnpm-lock.yaml.
Rewrite README setup + scripts table around pnpm, and add a
production deployment guide covering systemd, nginx, upgrades,
rollback, and backups.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stack matches sibling buildfor_life_* apps: SvelteKit 5 with adapter-node,
Svelte 5 runes, TypeScript, Tailwind v4 with @theme inline tokens,
PostgreSQL via Drizzle ORM, Argon2id sessions via @node-rs/argon2 and
@oslojs/crypto, EasyMDE ready for wiki/decision markdown, Sharp for
thumbnails.
Included in this commit:
- Config: package.json, svelte.config.js, vite.config.ts, tsconfig.json,
drizzle.config.ts, .gitignore, .env.example, .gitattributes, .npmrc
- Tenancy schema: companies, users, company_users, sessions
(10 enums pre-declared for the full domain so downstream migrations
don't re-diff them; decision_scope widened to include asset +
work_package per product decision)
- Auth: password hashing + SHA-256-hashed session cookies,
session lifetime 30d with sliding renewal at T-15d,
login + logout + session refresh in hooks
- Storage: StorageAdapter interface + LocalDiskStorage with HMAC-signed
URLs served by /api/files, S3 drop-in with zero schema change
- UI shell: dark-mode bootstrap in app.html identical to siblings,
sidebar (w-64, h-14 header, amber attention band pattern from repair),
topbar with breadcrumbs, theme toggle with cross-tab sync via
storage event, blue-600 primary, responsive drawer
- Routes: (app) authed group with auto-redirect to /login,
(auth) login group, dashboard placeholder, error page, signed-file API
- Scripts: create-user script for bootstrapping first admin user
- Drizzle: initial migration generated (0000_init.sql)
- Shared agents and skills committed under .claude/; per-user
permissions gitignored
Typecheck: 0 errors / 0 warnings across 555 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>