ginnoir
30af9f63bf
chore: add release workflow (commitlint, husky, lint-staged, release-it)
2026-06-01 18:33:37 -05:00
ginnoir and Claude Sonnet 4.6
285a460eb8
Implement tasks 60, 61, 62: backups, rate limiting, structured logging
...
Task 60 — Postgres backups:
- deploy/backups/: backup.sh (pg_dump -Fc nightly), retain.sh (14/8/6 tiers),
restore.sh, entrypoint.sh, crontab
- famapp-backup Alpine service + backups volume added to deploy/compose.yaml
- Restore procedure in deploy/backups/README.md
Task 61 — Rate limiting on share links:
- src/lib/rate-limit.ts: Edge-compatible sliding-window counter (50/min, LRU eviction)
with consume(), isRateLimited(), recordFailure() exports
- middleware.ts: enforces 429 with Retry-After: 60 for /s/[token] (IP + token prefix)
- /s/[token]/page.tsx: tracks only failed resolveShareToken calls via recordFailure()
Task 62 — Structured logging:
- pino + pino-pretty installed; serverExternalPackages added to next.config.ts
- src/lib/logger.ts: JSON in production, pretty in dev, level from LOG_LEVEL env
- middleware.ts: structured JSON request log (method, path, status, ms, authenticated)
- _core/push.ts, notify.ts, reminders.ts: console.error/log → logger.error/info
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 17:23:29 -05:00
ginnoir and Claude Sonnet 4.6
b6abe052c9
Implement tasks 40, 41, 42: web push, notification bus, reminders engine
...
Task 40 — Web Push (VAPID):
- Add web-push package + @types/web-push
- pnpm vapid:generate script prints VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, NEXT_PUBLIC_VAPID_PUBLIC_KEY
- push_subscriptions schema + migration 0013
- _core/push.ts: sendPush() iterates subscriptions, prunes 404/410 stale entries
- SW push/notificationclick event handlers added to generated sw.js template
- PushOptIn client component on /settings (opt-in, disable, send test)
Task 42 — Notification bus + ntfy adapter:
- notifications table + notif_push/notif_inapp/notif_ntfy user columns (migration 0013)
- _core/notify.ts: notify() fans out to push, in-app DB, and optional ntfy POST
- NotificationBell server component in AppNav: unread badge, dropdown inbox, mark-read
- NotifyChannelToggles client component in /settings
Task 41 — Reminders engine:
- fired_at + created_by added to reminders; default channel changed to 'auto'
- _core/reminders.ts: scheduleReminder (upsert), cancelReminder, listReminders, tickReminders
- tickReminders uses pg_try_advisory_xact_lock for horizontal-scale safety
- src/instrumentation.ts starts reminder worker (30s tick) on Node.js boot
- Notes actions use scheduleReminder/cancelReminder instead of raw SQL
- Calendar createEvent: optional remindMinutesBefore, deleteEvent: cancelReminder
- Calendar-shell: "Remind me 30 min before" checkbox on new event form
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 16:55:02 -05:00
ginnoir and Claude Sonnet 4.6
d5a8bf9d95
Implement tasks 25, 26 + completion visibility setting
...
Task 25: Multiple dashboards — dashboards table + migration, /d/[slug]
route, root redirect, dashboard tabs in nav with create/rename/delete/
set-default. Task 26: Editable dashboard — react-grid-layout drag/resize
editor, widget picker modal with per-widget configurator auto-generated
from default config, save/reset server actions with Zod validation.
Completion visibility: server-side per-user setting (hours) replaces
localStorage timer; queries filter completed items by updatedAt cutoff;
Settings page dropdown persists preference via server action.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 15:52:59 -05:00
ginnoir and Claude Sonnet 4.6
1133fa8aac
Implement quick-add registry (task 21)
...
- Add url field to QuickAddAction; make action optional
- Add getQuickAdds() + SerializedQuickAddItem to registry so quick-add
data can cross the server→client RSC boundary without serializing fns
- Update calendar/lists/notes manifests with navigation URLs
- QuickAddProvider wraps root layout: holds sheet/palette open state and
global cmd/ctrl+k shortcut
- QuickAddSheet: bottom drawer on mobile, right-side popover on desktop,
actions grouped by module
- CommandPalette: cmdk-powered modal with fuzzy filter and full keyboard
nav (arrows + enter + esc)
- QuickAddFab: client button replacing the plain + stub in the dashboard
- Add .claude/** to ESLint ignores to prevent stale worktree artifacts
from failing lint
All 4 E2E specs pass; typecheck, lint, and build clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 13:44:33 -05:00
ginnoir
744c1119a9
Implement calendar module
2026-05-06 03:10:28 -05:00
ginnoir and Claude Sonnet 4.6
6710c8b231
Add household seeding & session (task 07)
...
- scripts/seed.ts: idempotent pnpm db:seed inserts "Home" household if none exists (powered by tsx)
- signIn callback: first member of household gets owner role, subsequent users get member
- src/lib/session.ts: getCurrentSession() returns { user, household, role }, throws if unauthenticated or unmembered
- /settings/household: member list for all roles; rename form gated to owner only (server action also enforces)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 02:42:48 -05:00
ginnoir and Claude Sonnet 4.6
5da472d6ff
Add Authentik OIDC integration (task 06)
...
- next-auth@beta + @auth/drizzle-adapter wired up with database sessions
- src/lib/auth.ts: OIDC provider, authorized callback, signIn household-attach, getCurrentUser()
- src/middleware.ts: protects all routes except /login, /s/*, /api/auth/*
- src/app/api/auth/[...nextauth]/route.ts: mounts Auth.js handlers
- src/app/login/page.tsx: single SSO sign-in button (server action)
- Schema: users extended (name/emailVerified/image), accounts/sessions/verificationTokens added
- drizzle/0001_auth_tables.sql: migration for schema changes
- deploy/authentik/README.md: manual bootstrap steps for Authentik
- src/lib/db.ts: pass schema to drizzle for relational query builder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 02:37:41 -05:00
ginnoir and Claude Sonnet 4.6
e237fe8449
Add module loader & registry (task 04)
...
Implements the extensibility foundation: ModuleManifest/DashboardWidget/EntityTypeRegistration types in _core/module.ts, a plain-Map registry singleton with registerModule/getRegistry/getEntityType/getWidget, and stub manifests for calendar/lists/notes. Root layout imports src/modules/index.ts for side-effect registration; AppNav reads the registry to render nav links. /debug/registry dumps the full registry JSON in dev using zod v4 + z.toJSONSchema(). Adding a fourth module requires one folder + one line in index.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 01:52:47 -05:00
ginnoir and Claude Sonnet 4.6
37977568ed
Add Drizzle + Postgres setup (task 03)
...
drizzle-orm + postgres driver + drizzle-kit wired up. Core schema declares
users, households, and household_members. docker-compose.dev.yaml runs
Postgres 16 locally. Initial migration generated and verified applied.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 01:21:40 -05:00
ginnoir and Claude Sonnet 4.6
453c75ea4c
Add Next.js 15 app skeleton with Tailwind v4 and shadcn/ui
...
Next.js 15 + React 19, Tailwind v4, shadcn/ui (button, card, input,
dialog), postcss config, standalone output. ESLint extended with
next/core-web-vitals via eslint-config-next flat export. node-linker=hoisted
in .npmrc to allow standalone builds on Windows (symlink restriction).
next-env.d.ts added to .gitignore.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-06 00:47:57 -05:00
ginnoir
b89690a9f2
Initial scaffold: tooling, plan, task briefs
...
- pnpm 10 workspace + TypeScript strict + ESLint flat + Prettier
- CLAUDE.md as canonical brief
- docs/tasks/ — 22 task briefs broken out by phase for sub-sessions
- docs/decisions/ — ADR scaffold
Implements task 01 (repo-init).
2026-05-06 00:05:50 -05:00