Drop the two-subdomain split (ADR 0004): report at /, view defects at
/defects, with a shared layout + header nav. Renames the dashboard page to
defects.vue and updates plan/README. Transparency over separation now that
auth gates everyone, and it removes the Coolify two-domain routing question.
GET /api/defects returns a newest-first feed joined to the project name,
bounded by limit; ?section=ID narrows to one section's history. GET
/api/defects/counts returns { sectionId: n } for the weak-point map. Adds a
(section_id, created_at) index and a db:seed script; ~2k rows query in ~20ms.
Specs truncate the test DB between tests; with multiple DB-backed spec files
running in parallel workers they clobbered each other. Suffix the database
name with VITEST_POOL_ID so each worker is isolated.
The dialog autofocuses the project input on open; opening the dropdown on
focus made it spring open with no user interaction. Open on click or typing
instead, so the field is type-ready on open without showing the list.
DaisyUI's modal drives the native <dialog> via showModal/close, so Escape,
focus-trapping and the backdrop work without custom handling. The parent's
sectionId controls open/close and the dialog's native close event maps to the
component's close emit.
POST /api/defects validates the body with arktype (known section, uuid
project, non-empty trimmed verbatim) and resolves the reporter through a dev
seam (getReporter, ADR 0002) until OAuth lands. DefectForm is a DaisyUI modal
opened by a section click — pick a project, describe the problem, submit.
Tailwind v4 integrates as a Vite plugin and configures daisyui via the
CSS @plugin directive; the light theme is selected with data-theme on
<html>. Heading font sizes are re-asserted because Tailwind's preflight
resets them, which would otherwise shrink the hand-crafted headings.
Source is copied before install because the root postinstall (nuxt prepare)
needs it, so the dependency layer can't be cached by ordering alone. A
BuildKit cache mount on pnpm's store keeps packages across builds instead.
- GET /api/projects returns the shared global list; POST /api/projects
creates a project, deduped case-insensitively (F3).
- Repository find-or-create trims and matches on lower(name); a unique index
on lower(name) enforces the same rule at the DB (replacing the case-
sensitive column unique constraint) — migration 0001.
- ProjectAutocomplete: creatable autocomplete that lists projects, offers to
create an unknown name inline, and selects it without reload.
- Integration test (dedupe/list against Postgres) + component test.
Component/runtime specs (*.nuxt.spec.ts) run in the Nuxt environment; all
other specs run in a plain node environment where node_modules stay external,
so native CJS deps like `pg` load correctly (the Nuxt runtime inlines them and
breaks pg's internal `class … extends Pool`). Adds tests/helpers/db.ts, which
spins up and migrates a dedicated test database for repository integration
tests, and renames the board spec to the .nuxt suffix.
- Add Nitro plugin to apply Drizzle migrations on server boot (skips when
DATABASE_URL is unset, e.g. during build).
- Split compose: docker-compose.dev.yml (hot-reload + Postgres) vs
docker-compose.yml (production/self-host, env-driven, Coolify-deployable).
- Add .dockerignore; parameterise compose env; document the autodeploy
decision (Coolify watches main, no CI workflow needed) in ADR 0003 and
plan.md T12.
Drizzle schema for projects, defects, push_subscriptions (C8); generated
migration; a defects repository (createDefect / listRecentDefects); a
programmatic migrator; and a db:verify script. section_id is a plain string
referencing in-code board ids, no FK (ADR 0001). Verified against real
Postgres: migration applies, a defect round-trips, /api/health reports db up.
Render A-series sheets in landscape (√2:1), size them off a single
--sheet-base variable so A2/A3/A4 keep exact ISO ratios while leaving room
for labels (which now wrap). Load Playfair Display + Cutive Mono via the
coollabs fonts API: Playfair Display for headings, Cutive Mono for the board.
Encode the board as blocks of stacked-section columns (C1) and render it as
the ASCII-styled DOM grid (C2) with hover highlight and a select emit. Layout
mirrors the physical board (Client Satisfaction above Product Architecture;
Macroplan above Defect Visualisation, both left of Feature Kanban) and boxes
use true ISO 216 proportions (1:√2, each step up scaled by √2). Both views
render from the one definition; tests pin section presence, click, hover,
layout order, and a snapshot.
Nuxt 4 (app/ structure) + TypeScript, ESLint, Vitest + @nuxt/test-utils,
Drizzle + pg, a /api/health route with a DB ping, and a dev docker-compose
(app + Postgres). Verified: pnpm test, lint, and build pass; the built
server answers /api/health.