diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..c4b1e1f --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,344 @@ +# famapp Architecture Diagram + +## System Overview + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ EXTERNAL LAYER │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Browser │ │ Mobile PWA │ │ Share Link │ │ +│ │ (Next.js) │ │ (Installed) │ │ (Public) │ │ +│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ +│ │ │ │ │ +│ └────────────────────────┴────────────────────────┘ │ +│ │ │ +│ HTTPS (Caddy Reverse Proxy) │ +│ │ │ +│ fam.ginnoir.com → :3000 │ +│ auth.ginnoir.com → :9000 │ +└──────────────────────────────────┼───────────────────────────────────────────┘ + │ +┌──────────────────────────────────┼───────────────────────────────────────────┐ +│ APPLICATION LAYER │ +├──────────────────────────────────┼───────────────────────────────────────────┤ +│ │ │ +│ ┌────────────────────────┴────────────────────────┐ │ +│ │ Next.js 15 App Router │ │ +│ │ (Node 24 LTS Container) │ │ +│ └────────────────────────┬────────────────────────┘ │ +│ │ │ +│ ┌───────────────────────────────┼───────────────────────────────┐ │ +│ │ │ │ │ +│ │ ┌───────────────────────────┐│ ┌───────────────────────────┐│ │ +│ │ │ Middleware ││ │ Auth (NextAuth) ││ │ +│ │ │ - Rate limiting ││ │ - OIDC (Authentik) ││ │ +│ │ │ - Session check ││ │ - Session management ││ │ +│ │ └───────────┬───────────────┘│ └───────────┬───────────────┘│ │ +│ │ │ │ │ │ │ +│ │ ┌───────────┴───────────────┐│ ┌───────────┴───────────────┐│ │ +│ │ │ Routes (app/) ││ │ Module Registry ││ │ +│ │ │ / → /d/{slug} ││ │ - Entity types ││ │ +│ │ │ /d/[slug] (dashboard) ││ │ - Dashboard widgets ││ │ +│ │ │ /calendar ││ │ - Quick-add actions ││ │ +│ │ │ /lists ││ │ - Share handlers ││ │ +│ │ │ /notes ││ │ - Search adapters ││ │ +│ │ │ /garden ││ │ - Reminder handlers ││ │ +│ │ │ /s/[token] (share) ││ │ - Activity renderers ││ │ +│ │ │ /settings ││ │ - Toggle hooks ││ │ +│ │ │ /api/* ││ └───────────┬───────────────┘│ │ +│ │ └───────────┬───────────────┘ │ │ │ +│ │ │ │ │ │ +│ │ ┌───────────┴───────────────┬────────────────┴───────────────┐│ │ +│ │ │ │ ││ │ +│ │ │ ┌───────────────────────┴──────────────────────────────┐││ │ +│ │ │ │ MODULE SYSTEM (src/modules/) │││ │ +│ │ │ │ │││ │ +│ │ │ │ ┌────────────────────────────────────────────────┐ │││ │ +│ │ │ │ │ _core/ │ │││ │ +│ │ │ │ │ - schema.ts (users, households, activity_log, │ │││ │ +│ │ │ │ │ share_links, dashboards, reminders, push) │ │││ │ +│ │ │ │ │ - registry.ts (module registration) │ │││ │ +│ │ │ │ │ - share.ts (share-link service) │ │││ │ +│ │ │ │ │ - push.ts (web push notifications) │ │││ │ +│ │ │ │ │ - reminders.ts (reminder scheduling) │ │││ │ +│ │ │ │ │ - activity.ts (activity logging) │ │││ │ +│ │ │ │ │ - themes.ts (theme configuration) │ │││ │ +│ │ │ │ └────────────────────────────────────────────────┘ │││ │ +│ │ │ │ │││ │ +│ │ │ │ ┌────────────────────────────────────────────────┐ │││ │ +│ │ │ │ │ calendar/ │ │││ │ +│ │ │ │ │ - schema.ts (calendars, calendar_events) │ │││ │ +│ │ │ │ │ - server/ (queries, mutations, share-queries) │ │││ │ +│ │ │ │ │ - components/ (shared-view, calendar views) │ │││ │ +│ │ │ │ │ - manifest.tsx (widgets: upcoming, month) │ │││ │ +│ │ │ │ └────────────────────────────────────────────────┘ │││ │ +│ │ │ │ │││ │ +│ │ │ │ ┌────────────────────────────────────────────────┐ │││ │ +│ │ │ │ │ lists/ │ │││ │ +│ │ │ │ │ - schema.ts (lists, list_items) │ │││ │ +│ │ │ │ │ - server/ (queries, mutations, share-queries) │ │││ │ +│ │ │ │ │ - components/ (shared-view, list-widget) │ │││ │ +│ │ │ │ │ - manifest.tsx (widget: list items) │ │││ │ +│ │ │ │ └────────────────────────────────────────────────┘ │││ │ +│ │ │ │ │││ │ +│ │ │ │ ┌────────────────────────────────────────────────┐ │││ │ +│ │ │ │ │ notes/ │ │││ │ +│ │ │ │ │ - schema.ts (notes) │ │││ │ +│ │ │ │ │ - server/ (queries, mutations, share-queries) │ │││ │ +│ │ │ │ │ - components/ (shared-view) │ │││ │ +│ │ │ │ │ - manifest.tsx (widget: notes) │ │││ │ +│ │ │ │ └────────────────────────────────────────────────┘ │││ │ +│ │ │ │ │││ │ +│ │ │ │ ┌────────────────────────────────────────────────┐ │││ │ +│ │ │ │ │ garden/ │ │││ │ +│ │ │ │ │ - schema.ts (plants, containers, care_logs) │ │││ │ +│ │ │ │ │ - server/ (queries, mutations, share-queries) │ │││ │ +│ │ │ │ │ - components/ (plant-widget, shared-view) │ │││ │ +│ │ │ │ │ - manifest.tsx (widgets: care-due, overview) │ │││ │ +│ │ │ │ └────────────────────────────────────────────────┘ │││ │ +│ │ │ │ │││ │ +│ │ │ │ ┌────────────────────────────────────────────────┐ │││ │ +│ │ │ │ │ bangs/ │ │││ │ +│ │ │ │ │ - schema.ts (bang_events) │ │││ │ +│ │ │ │ │ - server/ (queries) │ │││ │ +│ │ │ │ │ - components/ (bang-widget) │ │││ │ +│ │ │ │ │ - manifest.tsx (widget: bang counter) │ │││ │ +│ │ │ │ └────────────────────────────────────────────────┘ │││ │ +│ │ │ │ │││ │ +│ │ │ └────────────────────────────────────────────────────┘││ │ +│ │ │ ││ │ +│ │ └─────────────────────────────────────────────────────────┘│ │ +│ │ │ │ +│ └────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌───────────────────────────────────────────────────────────────┐ │ +│ │ Shared Libraries (src/lib/) │ │ +│ │ - db.ts (Drizzle client) │ │ +│ │ - auth.ts (NextAuth configuration) │ │ +│ │ - session.ts (session helpers) │ │ +│ │ - dashboard.ts (dashboard helpers) │ │ +│ │ - logger.ts (pino logging) │ │ +│ │ - minio.ts (S3 client for uploads) │ │ +│ │ - rate-limit.ts (rate limiting) │ │ +│ └───────────────────────────────────────────────────────────────┘ │ +│ │ +└───────────────────────────────────────┬─────────────────────────────────────┘ + │ +┌───────────────────────────────────────┼─────────────────────────────────────┐ +│ DATA LAYER │ +├───────────────────────────────────────┼─────────────────────────────────────┤ +│ │ │ +│ ┌─────────────────────────────┴──────────────────────────┐ │ +│ │ Postgres 16 (famapp-db) │ │ +│ │ (Dedicated Container) │ │ +│ └─────────────────────────────┬──────────────────────────┘ │ +│ │ │ +│ ┌────────────────────────────────────┼────────────────────────────┐ │ +│ │ │ │ │ +│ │ Core Tables │ Module Tables │ │ +│ │ ┌──────────────────────────────┐ │ ┌──────────────────────┐ │ │ +│ │ │ users │ │ │ calendars │ │ │ +│ │ │ accounts │ │ │ calendar_events │ │ │ +│ │ │ sessions │ │ │ lists │ │ │ +│ │ │ verification_tokens │ │ │ list_items │ │ │ +│ │ │ households │ │ │ notes │ │ │ +│ │ │ household_members │ │ │ garden_plants │ │ │ +│ │ │ activity_log │ │ │ garden_containers │ │ │ +│ │ │ share_links │ │ │ garden_care_logs │ │ │ +│ │ │ dashboards │ │ │ bang_events │ │ │ +│ │ │ reminders │ │ └──────────────────────┘ │ │ +│ │ │ push_subscriptions │ │ │ │ +│ │ │ notifications │ │ │ │ +│ │ └──────────────────────────────┘ │ │ │ +│ │ │ │ │ +│ └────────────────────────────────────┴────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ AUTHENTICATION LAYER │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────────────┐ │ +│ │ Authentik (auth.ginnoir.com) │ │ +│ │ (Separate Docker Stack) │ │ +│ │ │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │ authentik- │ │ authentik- │ │ authentik- │ │ │ +│ │ │ server │ │ worker │ │ redis │ │ │ +│ │ │ (:9000) │ │ │ │ │ │ │ +│ │ └──────┬───────┘ └──────────────┘ └──────┬───────┘ │ │ +│ │ │ │ │ │ +│ │ └────────────────┬─────────────────┘ │ │ +│ │ │ │ │ +│ │ ┌───────────────────────┴──────────────────┐ │ │ +│ │ │ authentik-db (Postgres 16) │ │ │ +│ │ │ (Dedicated Container) │ │ │ +│ │ └──────────────────────────────────────────┘ │ │ +│ │ │ │ +│ │ - OIDC Provider for famapp │ │ +│ │ - Forward-auth for *arr apps (future) │ │ +│ │ - User management │ │ +│ └─────────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +## Module System Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ MODULE REGISTRATION FLOW │ +└─────────────────────────────────────────────────────────────────────────────┘ + +1. Module Registration (src/modules/index.ts) + ┌─────────────────────────────────────────────────────────────────────┐ + │ import { registerModule } from "./_core/registry"; │ + │ import coreManifest from "./_core/manifest"; │ + │ import calendarManifest from "./calendar/manifest"; │ + │ import listsManifest from "./lists/manifest"; │ + │ import notesManifest from "./notes/manifest"; │ + │ import gardenManifest from "./garden/manifest"; │ + │ import bangsManifest from "./bangs/manifest"; │ + │ │ + │ registerModule(coreManifest); │ + │ registerModule(calendarManifest); │ + │ registerModule(listsManifest); │ + │ registerModule(notesManifest); │ + │ registerModule(gardenManifest); │ + │ registerModule(bangsManifest); │ + └─────────────────────────────────────────────────────────────────────┘ + +2. Registry Storage (src/modules/_core/registry.ts) + ┌─────────────────────────────────────────────────────────────────────┐ + │ const modules = new Map(); │ + │ const entityTypes = new Map(); │ + │ const widgets = new Map(); │ + │ │ + │ registerModule() stores: │ + │ - Module metadata (id, name, nav) │ + │ - Entity types (with share/reminder/search handlers) │ + │ - Dashboard widgets (with render functions) │ + │ - Quick-add actions │ + └─────────────────────────────────────────────────────────────────────┘ + +3. Module Manifest Structure (src/modules/_core/module.ts) + ┌─────────────────────────────────────────────────────────────────────┐ + │ ModuleManifest { │ + │ id: string; // "calendar", "lists", etc. │ + │ name: string; // "Calendar", "Lists", etc. │ + │ nav?: { // Navigation entry │ + │ href: string; // "/calendar" │ + │ label: string; // "Calendar" │ + │ icon?: string; // "calendar" │ + │ }; │ + │ entities: EntityTypeRegistration[]; // Entity type declarations │ + │ dashboardWidgets?: DashboardWidget[]; // Widget declarations │ + │ quickAdds?: QuickAddAction[]; // Quick-add actions │ + │ } │ + └─────────────────────────────────────────────────────────────────────┘ + +4. Entity Type Registration + ┌─────────────────────────────────────────────────────────────────────┐ + │ EntityTypeRegistration { │ + │ type: string; // "calendar.event", "lists.item", etc. │ + │ label: { singular, plural }; │ + │ share?: { │ + │ canShare: boolean; │ + │ defaultCapabilities?: string[]; │ + │ }; │ + │ reminder?: { canRemind: boolean }; │ + │ search?: { search: (query, householdId) => SearchResult[] }; │ + │ resolveUrl: (id) => string; │ + │ canShareEntity?: (id, ctx) => Promise; │ + │ loadForShare?: (id, ctx) => Promise; │ + │ renderSharedView?: (data, capabilities, token) => ReactNode; │ + │ renderActivity?: (entry) => string; │ + │ } │ + └─────────────────────────────────────────────────────────────────────┘ + +5. Dashboard Widget Registration + ┌─────────────────────────────────────────────────────────────────────┐ + │ DashboardWidget { │ + │ id: string; // "calendar.upcoming", "lists.list", etc│ + │ title: string; │ + │ description: string; │ + │ category?: string; // "Calendar", "Lists", etc. │ + │ defaultSize: { w, h }; │ + │ minSize?: { w, h }; │ + │ maxSize?: { w, h }; │ + │ defaultPriority: number; // For default dashboard ordering │ + │ configSchema: ZodType; // Zod schema for widget config │ + │ defaultConfig: unknown; │ + │ resolveConfigOptions?: (ctx) => Promise; │ + │ render: (props) => ReactNode; // Server component render │ + │ } │ + └─────────────────────────────────────────────────────────────────────┘ +``` + +## Data Flow Patterns + +### Share Link Flow +``` +User creates share link + → Module's canShareEntity() checks permissions + → Core share.ts creates share_links record + → Returns token: /s/ + +Public viewer accesses /s/ + → Middleware rate-limits by IP:token prefix + → Share viewer loads share_links record + → Module's loadForShare() loads entity data + → Module's renderSharedView() renders public view + → Share-link grants scoped read/write per capabilities +``` + +### Activity Logging Flow +``` +Any entity mutation (server action) + → Core activity.ts logs activity_log entry + → Includes: entityType, entityId, actorId, action, payload + → Dashboard activity widget queries activity_log + → Module's renderActivity() formats entry for display +``` + +### Reminder Flow +``` +Entity with remind_at field (note, event) + → Module schedules reminder via core reminders.ts + → reminders table stores: entityType, entityId, fireAt, channel + → Background worker (planned) fires reminders + → notify() fans out to: web push, in-app, optional ntfy +``` + +### Dashboard Widget Flow +``` +User configures dashboard layout + → dashboards.layout stores: [{ widgetId, config, x, y, w, h }] + → Dashboard page loads layout + → For each widget: calls module's render() with config + → Widget component queries data via module's server/ queries + → Renders widget in grid layout +``` + +## Key Design Principles + +1. **Module Isolation**: Modules only import from `_core` and `lib/` - never from sibling modules +2. **Generic Core Services**: Sharing, reminders, activity log, search work against any registered entity type +3. **Household Scoping**: All entity data scoped to household_id; permissions gated by household membership +4. **Server Actions**: All mutations use Next.js server actions; route handlers only for webhooks/SSE/share viewer +5. **Type Safety**: TypeScript strict mode; Drizzle schema inference; Zod validation for all configs +6. **Extensibility**: Adding new features requires only creating a new module - no core changes needed +7. **PWA First**: Installable PWA with web(push) notifications; no native apps required +8. **Privacy-First Sharing**: Share links are temporary, scoped, and revocable + +## Future (Phase 9) + +Placeholders only — details land with tasks 85–88: + +- **`journal/` module** — per-user journal (task 86, Gitea #19) +- **Versioned HTTP API** (`/api/v1/…`) with token auth alongside OIDC session (task 87, Gitea #15) +- **LLM agent chat** — OpenAI-compatible tools over the API (task 88) + diff --git a/STATUS.md b/STATUS.md index 97a9af4..c82c5f7 100644 --- a/STATUS.md +++ b/STATUS.md @@ -42,9 +42,19 @@ Living progress tracker. Update at the end of each task. Codex and Claude Code b ## Next up -- **Ready to tag v0.1.0.** All phase 1–7 tasks complete and production wiring verified. -- Run `docs/tasks/09-pre-deploy-checklist.md` before pushing the tag. -- On the server: clone repo to `/srv/famapp`, copy `.env.production.example` → `/srv/famapp/deploy/.env`, fill in secrets (AUTH_SECRET, DB passwords, AUTHENTIK_SECRET_KEY, VAPID keys, AUTH_OIDC_CLIENT_ID/SECRET), add the Caddyfile snippet, bootstrap Authentik per `deploy/authentik/README.md`, then `docker compose -f deploy/compose.yaml up -d`. +Phase 9 — Post-v0.1 (see `docs/superpowers/specs/2026-07-03-backlog-triage-design.md`, `docs/issues-map.md`). + +**Batch order:** + +1. Bugs: tasks 80–84 (quick-add, dashboard edit, garden count, bangs, back-nav) +2. API foundation: task 87 (+ ADR 0006) +3. Shared rich-text + notes overhaul: task 85 (+ ADR 0004); closes notes mobile overflow +4. Journal: task 86 (+ ADR 0005), including journal API endpoints +5. LLM agent chat: task 88 + +P2/P3 backlog is filed on Gitea only (no task briefs yet) — see `docs/issues-map.md` designs 7–9, 11–12, 15–19. + +**How to resume:** Read AGENTS.md / CLAUDE.md / STATUS.md, open the next unchecked task in `docs/tasks/80`–`88`, stop at acceptance criteria. ## Development login/testing notes diff --git a/docs/decisions/0004-rich-text-editor.md b/docs/decisions/0004-rich-text-editor.md new file mode 100644 index 0000000..1980266 --- /dev/null +++ b/docs/decisions/0004-rich-text-editor.md @@ -0,0 +1,16 @@ +# 0004 — Rich-text editor library and storage format + +Date: 2026-07-03 +Status: proposed + +## Context + +Journal (task 86) and notes overhaul (task 85) need a shared rich-text editor with emoji support. Research and choose an existing library (e.g. TipTap/ProseMirror-family) rather than building one. Gitea: [#8](https://gitea.ginnoir.com/ginnoir/famapp/issues/8) (epic [#7](https://gitea.ginnoir.com/ginnoir/famapp/issues/7)). + +## Decision + +To be filled when research completes. + +## Consequences + +To be filled when research completes. diff --git a/docs/decisions/0005-journal-research.md b/docs/decisions/0005-journal-research.md new file mode 100644 index 0000000..77801f8 --- /dev/null +++ b/docs/decisions/0005-journal-research.md @@ -0,0 +1,16 @@ +# 0005 — Journal / mood tracking research + +Date: 2026-07-03 +Status: proposed + +## Context + +Journal module (task 86) needs mood multi-select, charts over time, and insights. Research existing libraries/components for mood tracking or journaling and record build-vs-adopt. Gitea: [#20](https://gitea.ginnoir.com/ginnoir/famapp/issues/20) (epic [#19](https://gitea.ginnoir.com/ginnoir/famapp/issues/19)). + +## Decision + +To be filled when research completes. + +## Consequences + +To be filled when research completes. diff --git a/docs/decisions/0006-api-llm-agent.md b/docs/decisions/0006-api-llm-agent.md new file mode 100644 index 0000000..e247d05 --- /dev/null +++ b/docs/decisions/0006-api-llm-agent.md @@ -0,0 +1,16 @@ +# 0006 — API auth and LLM agent architecture + +Date: 2026-07-03 +Status: proposed + +## Context + +P1 needs a documented API with token auth coexisting with OIDC session auth, plus a provider-agnostic OpenAI-compatible agent that tool-calls the API. Decide MCP vs direct tools. Gitea: [#14](https://gitea.ginnoir.com/ginnoir/famapp/issues/14) (epic [#13](https://gitea.ginnoir.com/ginnoir/famapp/issues/13)). Tasks 87 then 88. + +## Decision + +To be filled when research completes. + +## Consequences + +To be filled when research completes. diff --git a/docs/decisions/README.md b/docs/decisions/README.md index ec8fc93..00aba59 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -26,4 +26,7 @@ What this costs us, what it buys us. - [0002 — List realtime uses Postgres NOTIFY and SSE](0002-list-sse-notify.md) - [0003 — Release workflow (commitlint + release-it)](0003-release-workflow.md) +- [0004 — Rich-text editor library and storage format](0004-rich-text-editor.md) (proposed) +- [0005 — Journal / mood tracking research](0005-journal-research.md) (proposed) +- [0006 — API auth and LLM agent architecture](0006-api-llm-agent.md) (proposed) diff --git a/docs/issues-map.md b/docs/issues-map.md new file mode 100644 index 0000000..12db726 --- /dev/null +++ b/docs/issues-map.md @@ -0,0 +1,56 @@ +# Issue map + +Design IDs from `docs/superpowers/specs/2026-07-03-backlog-triage-design.md` → Gitea (`ginnoir/famapp`). + +| Design | Gitea | Title | URL | +| --- | --- | --- | --- | +| 1 | 1 | Quick-add opens create UI, not module page | https://gitea.ginnoir.com/ginnoir/famapp/issues/1 | +| 2 | 2 | Dashboard edit mode renders live widgets at true size | https://gitea.ginnoir.com/ginnoir/famapp/issues/2 | +| 3 | 3 | Garden container plant count is wrong | https://gitea.ginnoir.com/ginnoir/famapp/issues/3 | +| 4 | 4 | Bangs are not editable (add edit and delete) | https://gitea.ginnoir.com/ginnoir/famapp/issues/4 | +| 5 | 5 | Notes overflow horizontally on mobile | https://gitea.ginnoir.com/ginnoir/famapp/issues/5 | +| 6 | 6 | Missing back navigation on detail pages (audit + shared affordance) | https://gitea.ginnoir.com/ginnoir/famapp/issues/6 | +| 7 | 28 | Calendar reminders overhaul | https://gitea.ginnoir.com/ginnoir/famapp/issues/28 | +| 8 | 29 | Lists index: inline task add + list property edit | https://gitea.ginnoir.com/ginnoir/famapp/issues/29 | +| 9 | 30 | Comments on lists and tasks | https://gitea.ginnoir.com/ginnoir/famapp/issues/30 | +| 10 | 7 | Notes editor overhaul (shared rich-text component) | https://gitea.ginnoir.com/ginnoir/famapp/issues/7 | +| 10.1 | 8 | Research ADR: rich-text editor library and storage format | https://gitea.ginnoir.com/ginnoir/famapp/issues/8 | +| 10.2 | 9 | Shared rich-text editor component | https://gitea.ginnoir.com/ginnoir/famapp/issues/9 | +| 10.3 | 10 | Wire shared editor into notes create/edit | https://gitea.ginnoir.com/ginnoir/famapp/issues/10 | +| 10.4 | 11 | Render note formatting on all notes surfaces | https://gitea.ginnoir.com/ginnoir/famapp/issues/11 | +| 10.5 | 12 | Fix notes mobile horizontal overflow | https://gitea.ginnoir.com/ginnoir/famapp/issues/12 | +| 11 | 31 | Bang stats dashboard widget | https://gitea.ginnoir.com/ginnoir/famapp/issues/31 | +| 12 | 35 | Appearance / theming options | https://gitea.ginnoir.com/ginnoir/famapp/issues/35 | +| 13 | 19 | Journal module | https://gitea.ginnoir.com/ginnoir/famapp/issues/19 | +| 13.1 | 20 | Research ADR: journal/mood tracking build-vs-adopt | https://gitea.ginnoir.com/ginnoir/famapp/issues/20 | +| 13.2 | 21 | Journal schema + CRUD | https://gitea.ginnoir.com/ginnoir/famapp/issues/21 | +| 13.3 | 22 | Journal index (recent, browse, entry calendar) | https://gitea.ginnoir.com/ginnoir/famapp/issues/22 | +| 13.4 | 23 | Journal entry detail and create | https://gitea.ginnoir.com/ginnoir/famapp/issues/23 | +| 13.5 | 24 | Journal mood tracker view | https://gitea.ginnoir.com/ginnoir/famapp/issues/24 | +| 13.6 | 25 | Journal insights/stats views | https://gitea.ginnoir.com/ginnoir/famapp/issues/25 | +| 13.7 | 26 | Journal E2E happy path | https://gitea.ginnoir.com/ginnoir/famapp/issues/26 | +| 13.8 | 27 | Journal API endpoints | https://gitea.ginnoir.com/ginnoir/famapp/issues/27 | +| 14 | 13 | API + LLM agent chat | https://gitea.ginnoir.com/ginnoir/famapp/issues/13 | +| 14.1 | 14 | Research ADR: API auth, surface shape, and LLM agent architecture | https://gitea.ginnoir.com/ginnoir/famapp/issues/14 | +| 14.2 | 15 | API surface + token auth for existing modules | https://gitea.ginnoir.com/ginnoir/famapp/issues/15 | +| 14.3 | 16 | LLM agent chat UI | https://gitea.ginnoir.com/ginnoir/famapp/issues/16 | +| 14.4 | 17 | Map agent tool-calling to API | https://gitea.ginnoir.com/ginnoir/famapp/issues/17 | +| 14.5 | 18 | Agent smoke tests with mock provider | https://gitea.ginnoir.com/ginnoir/famapp/issues/18 | +| 15 | 32 | Pets module | https://gitea.ginnoir.com/ginnoir/famapp/issues/32 | +| 16 | 33 | Shopping/pantry module | https://gitea.ginnoir.com/ginnoir/famapp/issues/33 | +| 17 | 34 | Backups and exports | https://gitea.ginnoir.com/ginnoir/famapp/issues/34 | +| 18 | 36 | GPS locations for calendar events | https://gitea.ginnoir.com/ginnoir/famapp/issues/36 | +| 19 | 37 | Lists and notes cohesion (research proposal) | https://gitea.ginnoir.com/ginnoir/famapp/issues/37 | + +## Dependencies (P1) + +| Issue | Depends on | +| --- | --- | +| #5 (notes overflow) | #7 (rich-text epic) | +| #12 (mobile overflow child) | #8 (rich-text research ADR) | +| #19 (journal epic) | #7 (rich-text epic), #15 (API surface) | +| #16 (agent UI) | #15 (API surface) | +| #17 (tool-calling) | #15 (API surface) | +| #27 (journal API) | #15 (API surface) | + +Native Gitea issue dependencies API 404s on this instance; dependencies are also noted as comments on the issues above. diff --git a/docs/tasks/80-quick-add-create-ui.md b/docs/tasks/80-quick-add-create-ui.md new file mode 100644 index 0000000..91c2c99 --- /dev/null +++ b/docs/tasks/80-quick-add-create-ui.md @@ -0,0 +1,36 @@ +# 80 — Quick-add opens create UI + +## Goal + +Make every quick-add action open the entity's creation dialog/sheet instead of only navigating to a module page. + +## Why + +Task 21 shipped URL navigation as a placeholder. Users expect "New event" to start creating an event immediately. + +## Depends on + +- 21 (quick-add registry) + +## Scope + +- Extend `QuickAddAction` / client handling so actions can open create UI (dialog/sheet) in-place. +- Wire calendar, lists, notes, garden, bangs (and any other registered) quick-adds to their create UIs. +- Keep FAB sheet and cmd-k behavior identical per action. +- Playwright: extend `tests/e2e/dashboard.spec.ts` and/or add `tests/e2e/quick-add.spec.ts`. + +## Out of scope + +- Fuzzy search across entities. +- New entity types. + +## Acceptance criteria + +- [ ] Each registered quick-add opens create UI with create controls visible. +- [ ] No quick-add is navigation-only unless explicitly documented as view-only (none in v1 set). +- [ ] E2E: FAB → action opens dialog/sheet (not only route change). + +## Notes + +- Gitea: [ginnoir/famapp#1](https://gitea.ginnoir.com/ginnoir/famapp/issues/1) +- Prefer reusing existing create dialogs/sheets over new ones. diff --git a/docs/tasks/81-dashboard-edit-live-widgets.md b/docs/tasks/81-dashboard-edit-live-widgets.md new file mode 100644 index 0000000..6aca567 --- /dev/null +++ b/docs/tasks/81-dashboard-edit-live-widgets.md @@ -0,0 +1,34 @@ +# 81 — Dashboard edit mode live widgets + +## Goal + +In dashboard edit mode, render each widget's real data at its true final size so layout matches the saved view. + +## Why + +Edit mode currently shows empty placeholders; on save, content-heavy widgets (e.g. Recent activity) expand and the grid reflows. + +## Depends on + +- 26 (customizable layout + widget configuration) + +## Scope + +- `DashboardEditor` / edit mode loads real widget components and data (not empty shells). +- Widgets size to content consistently between edit and view modes. +- Playwright: extend `tests/e2e/dashboard.spec.ts` — enter `?edit=1`, assert real content visible. Prefer height-stability assertion only if non-flaky. + +## Out of scope + +- Redesigning the widget picker or config schemas. +- New widget types. + +## Acceptance criteria + +- [ ] Edit mode shows real widget content for registered widgets. +- [ ] Saving layout does not cause a large content-driven reflow for content-heavy widgets. +- [ ] E2E covers real content visible in edit mode. + +## Notes + +- Gitea: [ginnoir/famapp#2](https://gitea.ginnoir.com/ginnoir/famapp/issues/2) diff --git a/docs/tasks/82-garden-plant-count.md b/docs/tasks/82-garden-plant-count.md new file mode 100644 index 0000000..ad7cca9 --- /dev/null +++ b/docs/tasks/82-garden-plant-count.md @@ -0,0 +1,33 @@ +# 82 — Garden container plant count + +## Goal + +Fix container plant counts so a container with N plants displays N, and audit sibling counts for the same bug. + +## Why + +Containers (e.g. "plantie cabinet") show "0 plants" despite containing plants — likely a query/join or association bug. + +## Depends on + +- 71 (garden containers), 72 (garden plants) + +## Scope + +- Find and fix the count query in `src/modules/garden/server/queries.ts` (and related UI). +- Audit other garden counts (lists, widgets) for the same pattern; fix or file follow-ups. +- Playwright: extend `tests/e2e/garden.spec.ts` — plant in container → count ≥ 1. + +## Out of scope + +- New garden features. + +## Acceptance criteria + +- [ ] Container with N plants displays N (not 0). +- [ ] Sibling counts audited; fixed or follow-ups filed. +- [ ] E2E covers plant-in-container count. + +## Notes + +- Gitea: [ginnoir/famapp#3](https://gitea.ginnoir.com/ginnoir/famapp/issues/3) diff --git a/docs/tasks/83-bang-edit-delete.md b/docs/tasks/83-bang-edit-delete.md new file mode 100644 index 0000000..8c6084d --- /dev/null +++ b/docs/tasks/83-bang-edit-delete.md @@ -0,0 +1,35 @@ +# 83 — Bang edit and delete + +## Goal + +Allow editing and deleting bang entries after creation (e.g. wrong date). + +## Why + +Bangs can be recorded but not corrected. Only create exists today. + +## Depends on + +- Bangs module (in tree; no prior task number) + +## Scope + +- Server actions for update and delete. +- UI on the bang widget (and any list surface) for edit/delete. +- Activity log for update/delete if other modules log similarly. +- Playwright: new `tests/e2e/bangs.spec.ts` — record → edit date → assert → delete → assert gone. + +## Out of scope + +- Bang stats widget (design #11 / Gitea #31) — separate P2 issue. + +## Acceptance criteria + +- [ ] Edit a bang (e.g. change date) and see the update. +- [ ] Delete a bang and it no longer appears. +- [ ] E2E covers edit and delete. + +## Notes + +- Gitea: [ginnoir/famapp#4](https://gitea.ginnoir.com/ginnoir/famapp/issues/4) +- Related (not blocking): #31 bang stats widget. diff --git a/docs/tasks/84-back-navigation.md b/docs/tasks/84-back-navigation.md new file mode 100644 index 0000000..353e33b --- /dev/null +++ b/docs/tasks/84-back-navigation.md @@ -0,0 +1,34 @@ +# 84 — Back navigation on detail pages + +## Goal + +Audit detail routes lacking back affordances and add a shared header/back pattern consistently. + +## Why + +Individual plant pages (and other detail routes) have no in-page "back" except global nav. + +## Depends on + +- Existing app routes under `src/app/` + +## Scope + +- Audit all routes in `src/app/` for detail pages missing back; list them in the PR description. +- Shared back affordance (header/back component). +- Apply consistently to plant, note, list, and other detail pages. +- Playwright: `tests/e2e/navigation.spec.ts` or per-module — Back visible and returns to parent. + +## Out of scope + +- Redesigning global nav or dashboard tabs. + +## Acceptance criteria + +- [ ] Audit list included in PR. +- [ ] Shared back control on detail pages. +- [ ] E2E covers representative detail routes. + +## Notes + +- Gitea: [ginnoir/famapp#6](https://gitea.ginnoir.com/ginnoir/famapp/issues/6) diff --git a/docs/tasks/85-rich-text-notes.md b/docs/tasks/85-rich-text-notes.md new file mode 100644 index 0000000..c4133f2 --- /dev/null +++ b/docs/tasks/85-rich-text-notes.md @@ -0,0 +1,42 @@ +# 85 — Rich-text notes overhaul + +## Goal + +Land a shared rich-text editor (ADR 0004), wire it through notes create/edit and all display surfaces, and fix mobile horizontal overflow. + +## Why + +Journal (86) and notes need modern formatting and emoji. Notes currently overflow sideways on mobile. P1 pulls the full notes overhaul into this batch. + +## Depends on + +- 12 (notes module) +- ADR `0004-rich-text-editor.md` (research child: Gitea #8) +- Batch order: after bugs 80–84 and API foundation 87 is preferred for notes API extension, but editor work can proceed once ADR is accepted + +## Scope + +- Research and accept ADR 0004 (library e.g. TipTap, storage format, shared component contract). +- Shared editor component used by notes (and later journal). +- Notes create/edit use the shared editor. +- Render formatting on index, widgets, and share view. +- Fix mobile overflow (closes Gitea #5 / design #5). +- Playwright: extend `tests/e2e/notes.spec.ts` — formatted note visible; 375px no horizontal overflow. + +## Out of scope + +- Journal module (86) — consumes the shared editor after this lands. +- Appearance/theming epic. + +## Acceptance criteria + +- [ ] ADR 0004 accepted with library and storage format chosen. +- [ ] Shared editor component in tree. +- [ ] Notes create/edit use it. +- [ ] Formatting renders on all notes surfaces. +- [ ] Mobile overflow fixed; E2E green. + +## Notes + +- Gitea epic: [#7](https://gitea.ginnoir.com/ginnoir/famapp/issues/7); children #8–#12; overflow bug [#5](https://gitea.ginnoir.com/ginnoir/famapp/issues/5) +- Design: `docs/superpowers/specs/2026-07-03-backlog-triage-design.md` diff --git a/docs/tasks/86-journal-module.md b/docs/tasks/86-journal-module.md new file mode 100644 index 0000000..b6ae913 --- /dev/null +++ b/docs/tasks/86-journal-module.md @@ -0,0 +1,45 @@ +# 86 — Journal module + +## Goal + +Ship a per-user journal module with entries, mood tracking, insights, and journal API endpoints on the existing API foundation. + +## Why + +P1 personal journaling with mood/stress/pills tracking and stats, without blocking on P2 work. + +## Depends on + +- 85 (shared rich-text editor) +- 87 (API surface for existing modules — journal adds endpoints the same way) +- ADR `0005-journal-research.md` (Gitea #20) + +## Scope + +- Research ADR 0005 (mood/journal libs; build-vs-adopt). +- Schema + CRUD (per-user entries). +- Index: last 5–10 entries compact, browse all, small calendar of days with entries. +- Entry detail and create: **date (default today) and time (default now) required**; everything else optional. +- Fields: rich note text (shared editor); numerical stress; mood with color/emoji options and **multi-select**; took-my-pills-today boolean. +- Module-level mood-tracker view over time. +- Per-user insights/stats (trends, streaks, correlations — propose specifics in ADR/implementation). +- Journal API endpoints (additive on 87). +- Playwright: new `tests/e2e/journal.spec.ts` — minimal entry → recent list → detail → mood tracker loads. + +## Out of scope + +- Household-shared journals (per-user only). +- LLM agent tools for journal (88 can add later). + +## Acceptance criteria + +- [ ] ADR 0005 accepted. +- [ ] Create entry with only date/time. +- [ ] Index, detail, mood tracker, and insights views work. +- [ ] Journal API endpoints documented and callable with token auth. +- [ ] E2E happy path green. + +## Notes + +- Gitea epic: [#19](https://gitea.ginnoir.com/ginnoir/famapp/issues/19); children #20–#27 +- Depends on #7 (rich-text) and #15 (API surface) diff --git a/docs/tasks/87-api-surface.md b/docs/tasks/87-api-surface.md new file mode 100644 index 0000000..ba40d42 --- /dev/null +++ b/docs/tasks/87-api-surface.md @@ -0,0 +1,39 @@ +# 87 — API surface + token auth + +## Goal + +Documented HTTP API for existing modules (calendar, lists, notes, garden, bangs) with token auth suitable for non-browser clients, coexisting with OIDC session auth. + +## Why + +API-early batch order: foundation lands after bugs so journal and notes can extend it; LLM agent (88) maps tools onto it. + +## Depends on + +- ADR `0006-api-llm-agent.md` research half (Gitea #14) — auth model and API shape decided before implementation + +## Scope + +- Architecture ADR 0006: token auth vs OIDC session coexistence; API shape; additive versioning (no freeze that blocks journal). +- Token auth for non-browser clients. +- Endpoints for existing entities: events, lists/items, notes, garden, bangs (dashboards as needed). +- API docs (OpenAPI or equivalent living doc). +- Vitest for auth + route handlers; optional Playwright smoke only if useful. + +## Out of scope + +- LLM agent chat UI and tool-calling (88). +- Journal endpoints (86 adds them). + +## Acceptance criteria + +- [ ] ADR 0006 documents auth coexistence and API shape. +- [ ] Token-authenticated client can read/write covered entities. +- [ ] Session (OIDC) auth still works for the web app. +- [ ] Docs list endpoints and auth. +- [ ] Unit/integration tests for auth and handlers. + +## Notes + +- Gitea: epic [#13](https://gitea.ginnoir.com/ginnoir/famapp/issues/13); research [#14](https://gitea.ginnoir.com/ginnoir/famapp/issues/14); implementation [#15](https://gitea.ginnoir.com/ginnoir/famapp/issues/15) +- Batch step 6 (after bugs 80–84) diff --git a/docs/tasks/88-llm-agent-chat.md b/docs/tasks/88-llm-agent-chat.md new file mode 100644 index 0000000..53549ae --- /dev/null +++ b/docs/tasks/88-llm-agent-chat.md @@ -0,0 +1,39 @@ +# 88 — LLM agent chat + +## Goal + +Natural-language chat that acts on the app via tool-calling against the API, using a provider-agnostic OpenAI-compatible endpoint (self-hosted on the homelab). + +## Why + +Users should say "add milk to the shopping list" or "what's on the calendar Friday?" and have the agent use the API. + +## Depends on + +- 87 (API surface) +- ADR `0006-api-llm-agent.md` agent half (MCP yes/no, tool mapping) + +## Scope + +- Agent chat UI in the app. +- OpenAI-compatible client (provider-agnostic). +- Tool-calling mapped to API endpoints from 87 (and journal if present). +- Decide MCP vs direct tools in ADR 0006. +- Smoke tests with **mock/stub** provider in CI — no live LLM in CI. + +## Out of scope + +- Training or fine-tuning models. +- Forward-auth for other homelab apps. + +## Acceptance criteria + +- [ ] Chat UI sends prompts and shows responses. +- [ ] Tools call the API successfully in dev against the homelab endpoint. +- [ ] CI uses mock provider only. +- [ ] ADR 0006 records provider and MCP decisions. + +## Notes + +- Gitea: [#16](https://gitea.ginnoir.com/ginnoir/famapp/issues/16), [#17](https://gitea.ginnoir.com/ginnoir/famapp/issues/17), [#18](https://gitea.ginnoir.com/ginnoir/famapp/issues/18) +- Depends on [#15](https://gitea.ginnoir.com/ginnoir/famapp/issues/15) diff --git a/docs/tasks/README.md b/docs/tasks/README.md index f0c75c1..55f29cb 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -79,3 +79,17 @@ Every task file has these sections: - [73 — Garden care tracking](73-garden-care-tracking.md) - [74 — Garden integrations](74-garden-integrations.md) - [75 — Garden dashboard](75-garden-dashboard.md) + +### Phase 9 — Post-v0.1 + +Batch order (bugs → API → editor/notes → journal → agent). Design: [`docs/superpowers/specs/2026-07-03-backlog-triage-design.md`](../superpowers/specs/2026-07-03-backlog-triage-design.md). Issue map: [`docs/issues-map.md`](../issues-map.md). + +- [80 — Quick-add create UI](80-quick-add-create-ui.md) +- [81 — Dashboard edit live widgets](81-dashboard-edit-live-widgets.md) +- [82 — Garden plant count](82-garden-plant-count.md) +- [83 — Bang edit/delete](83-bang-edit-delete.md) +- [84 — Back navigation](84-back-navigation.md) +- [85 — Rich-text notes overhaul](85-rich-text-notes.md) +- [86 — Journal module](86-journal-module.md) +- [87 — API surface](87-api-surface.md) +- [88 — LLM agent chat](88-llm-agent-chat.md)