adding claude file and some plans

This commit is contained in:
2026-08-12 18:55:18 -06:00
parent b206964417
commit 4da16c7573
19 changed files with 1294 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
# 17 — Decision Log
Judgment calls made during planning, with rationale. Build agents: **do not relitigate these.** If implementation reveals a hard blocker, note it here and surface it to the owner instead of silently deviating. (Prose by design — these aren't work items.)
## Product decisions (owner-confirmed)
1. **Two work-item levels (epics + issues), not Taiga's four.** Taiga's Epic→Story→Task + Issue split is its single biggest complexity driver (4 status sets, 4 custom-field sets, promotion paths). Sub-issues + epics cover the same needs at small scale.
2. **Fixed statuses, no per-project workflow customization.** Consistent UX, no admin screens, kanban columns are stable. Labels absorb remaining taxonomy needs.
3. **No sprints, backlog view, swimlanes, WIP limits, custom roles, or discovery/social features.** Deliberately out of scope for <10-user teams; Taiga's enterprise surface was surveyed and dropped.
4. **Owner/member + instance admin only.** A viewer role and permission matrices were considered and rejected.
5. **PostgreSQL over SQLite** (owner choice; first iteration used SQLite). Compose file keeps ops one-command.
6. **Meilisearch for search** (owner choice) rather than Postgres tsvector — better typo-tolerant UX, at the cost of a second service and event-driven sync.
7. **Story points (1,2,3,5,8,13) over t-shirt sizes.** Owner preference; points also make epic rollups meaningful (points sums shown on epic progress).
8. **Sessions + PATs** (not JWT). Server-side scs sessions are simplest/safest for a same-origin SPA; PATs cover scripting. PATs have **no scopes in v1** — they act as the user; revisit if the API gains external consumers.
9. **`oauth_accounts` table over a single `provider` column** (owner-approved). Kills the duplicate-account problem documented in the first iteration; enables local+GitHub+Gitea on one identity. Link only on **verified** provider email.
10. **SSE over WebSockets.** One-way push is all the app needs; SSE is stdlib-friendly, auto-reconnecting, proxy-tolerant.
## Architecture decisions
11. **Hand-rolled transactional outbox + Postgres job queue, not River / external brokers / fire-and-forget goroutines.** Goroutines lose work on crash (unacceptable for notifications/webhooks/search); River adds dependency weight for a <10-user single-instance app. ~300 LOC buys at-least-once delivery surviving restarts. **Explicit constraint: one app instance** (`SKIP LOCKED` keeps accidental multi-instance safe, but the SSE hub is per-process).
12. **Audit log written synchronously in the mutation transaction** (exactly-once), while everything else is async via the outbox. Activity feeds are therefore never stale or lossy.
13. **Single firehose SSE stream per user**, client filters. Per-page topic subscriptions would cut noise but add protocol complexity; at <10 users the firehose is trivially cheap.
14. **Polymorphic `links`/`attachments` tables** (resource_type + resource_id) replacing three tables each. Loses FK integrity on the target; acceptable because hard deletes flow exclusively through the culling job, which handles cascades (and must anyway, for disk files).
15. **Native Postgres enums for statuses/priorities.** Safe because sets are fixed by product decision (#2). Adding a value later is one `ALTER TYPE … ADD VALUE` migration.
16. **Fractional lexicographic ranks (`board_rank`/`epic_rank` text)** for drag ordering — O(1) writes per move, no renumbering transactions; rebalancing deferred (not needed at target scale).
17. **`ON DELETE RESTRICT` everywhere + app-level culling cascades** (carried from first iteration). A DB cascade cannot delete attachment files from disk; one deletion path (the cull job) keeps rows and files consistent.
18. **Denormalized `project_id` on audit_log** so activity feeds are one indexed query. Zero-maintenance denormalization (audit rows are immutable).
19. **Per-project issue numbers via a `next_issue_number` counter** updated in the insert transaction — no sequence-per-project, no gaps from rollbacks visible in practice, concurrency-safe.
20. **Server extracts mentions/#refs; client renders markdown.** Rendering in one place (client) avoids double-sanitization drift; the server only needs entities for notifications, which must not depend on client honesty.
## Scope cuts (v1) — revisit only when the owner asks
21. **No project import** (export format is versioned and designed to be importable later).
22. **No wiki page history**, no comment edit-history; `updated_at` + conflict warning only.
23. **No email invitations** — members are picked from existing instance users (registration is open on the instance).
24. **No server-side thumbnails**, no image processing.
25. **No custom fields, votes/likes, due-date buckets, CSV-feed tokens, videoconferencing, telemetry** — Taiga features consciously excluded.
26. **Audit log kept forever** (first iteration left retention open; forever is the safe default at this scale — revisit if instances grow).
27. **Incoming push-event automation** (commit messages moving issues) recorded but ignored in v1; only PR-merged `closes #N` acts.