refactor(app): serve one domain — /defects route and header nav
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.
This commit is contained in:
10
README.md
10
README.md
@@ -8,11 +8,13 @@ company-wide (Dantotsu).
|
|||||||
|
|
||||||
Two apps, one codebase, behind Google SSO (`@theodo.com`):
|
Two apps, one codebase, behind Google SSO (`@theodo.com`):
|
||||||
|
|
||||||
- **`andon.apoena.dev`** — the reporting view: click an ASCII board section, pick
|
- **`/`** — the reporting view: click an ASCII board section, pick your project,
|
||||||
your project, describe the problem.
|
describe the problem.
|
||||||
- **`dashboard-andon.apoena.dev`** — the same board as a red-dot defect map, a
|
- **`/defects`** — the same board as a red-dot defect map, a
|
||||||
reverse-chronological feed, and verbatims in a modal.
|
reverse-chronological feed, and verbatims in a modal.
|
||||||
|
|
||||||
|
Both live on one domain, `andon.apoena.dev` (ADR 0004).
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
**Design phase.** No code yet — the documentation below captures the agreed
|
**Design phase.** No code yet — the documentation below captures the agreed
|
||||||
@@ -60,7 +62,7 @@ migrate step is needed.
|
|||||||
2. Create a **managed Postgres** in Coolify (automatic backups — [ADR 0003](./docs/adr/0003-use-coolify-managed-postgres-over-sqlite.md))
|
2. Create a **managed Postgres** in Coolify (automatic backups — [ADR 0003](./docs/adr/0003-use-coolify-managed-postgres-over-sqlite.md))
|
||||||
and set `DATABASE_URL` to it. _(Alternatively deploy `docker-compose.yml`, which bundles a Postgres service.)_
|
and set `DATABASE_URL` to it. _(Alternatively deploy `docker-compose.yml`, which bundles a Postgres service.)_
|
||||||
3. Set the env vars from [`.env.example`](./.env.example) (`NUXT_SESSION_SECRET`,
|
3. Set the env vars from [`.env.example`](./.env.example) (`NUXT_SESSION_SECRET`,
|
||||||
Google OAuth, VAPID) and route `andon.apoena.dev` + `dashboard-andon.apoena.dev` to the service.
|
Google OAuth, VAPID) and route `andon.apoena.dev` to the service.
|
||||||
4. **Enable Coolify's autodeploy** so it builds and deploys on every push to
|
4. **Enable Coolify's autodeploy** so it builds and deploys on every push to
|
||||||
`main`. Protect `main` with required PR review + CI so only vetted commits
|
`main`. Protect `main` with required PR review + CI so only vetted commits
|
||||||
reach production.
|
reach production.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<NuxtRouteAnnouncer />
|
<NuxtRouteAnnouncer />
|
||||||
|
<NuxtLayout>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
26
app/layouts/default.vue
Normal file
26
app/layouts/default.vue
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Single domain (ADR 0004): report at `/`, view all defects at `/defects`,
|
||||||
|
// with a persistent header to move between them.
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="min-h-screen">
|
||||||
|
<header class="navbar border-base-300 border-b">
|
||||||
|
<NuxtLink to="/" class="btn btn-ghost text-xl">Andon</NuxtLink>
|
||||||
|
<nav class="ml-auto flex gap-1">
|
||||||
|
<NuxtLink to="/" class="btn btn-ghost btn-sm" exact-active-class="btn-active">
|
||||||
|
Report
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
to="/defects"
|
||||||
|
class="btn btn-ghost btn-sm"
|
||||||
|
exact-active-class="btn-active"
|
||||||
|
>
|
||||||
|
View defects
|
||||||
|
</NuxtLink>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<main>
|
|
||||||
<h1>Andon — weak point dashboard</h1>
|
|
||||||
<BoardView />
|
|
||||||
<p>The red-dot defect map lands in Task 7.</p>
|
|
||||||
</main>
|
|
||||||
</template>
|
|
||||||
17
app/pages/defects.vue
Normal file
17
app/pages/defects.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Defect-viewing route (`/defects`) — the read-only board with the weak-point
|
||||||
|
// map and feed. Same domain as reporting (ADR 0004).
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main class="mx-auto flex max-w-5xl flex-col items-center gap-6 p-6">
|
||||||
|
<header class="text-center">
|
||||||
|
<h1>Andon — weak points</h1>
|
||||||
|
<p class="opacity-70">Every defect filed on the board.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<BoardView />
|
||||||
|
|
||||||
|
<p class="opacity-60">The red-dot map (T7) and defect feed (T8) land next.</p>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Serve one domain with routes, not two subdomains
|
||||||
|
|
||||||
|
The `/deep-design` plan served the app on two domains — `andon.apoena.dev`
|
||||||
|
(reporting) and `dashboard-andon.apoena.dev` (viewing) — with host-based routing
|
||||||
|
selecting the view. The original intent was to keep reporting clean and separate
|
||||||
|
the owner's weak-point view.
|
||||||
|
|
||||||
|
Once **every request is gated to `@theodo.com`** (F9) and **transparency** is the
|
||||||
|
goal — everyone sees the defects — that separation buys little. We serve
|
||||||
|
everything from **`andon.apoena.dev`**: `/` reports a defect (kept clean: click a
|
||||||
|
section → file) and **`/defects`** shows the weak-point map and feed, with a
|
||||||
|
header to move between them.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- No host-based routing in the app; the two views are plain Nuxt routes
|
||||||
|
(`pages/index.vue`, `pages/defects.vue`) sharing one layout and nav.
|
||||||
|
- Deployment simplifies to one domain, one TLS cert, one service — this
|
||||||
|
**resolves the open T12 question** about routing two subdomains in Coolify.
|
||||||
|
- The reporting page stays free of viewing noise; viewing lives on its own route.
|
||||||
|
- **Supersedes** the "single Nuxt app, two domains / host-based routing" decision
|
||||||
|
in plan.md and the two-domain references in DESIGN.md / README.
|
||||||
@@ -3,19 +3,19 @@
|
|||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Build the Andon app per [DESIGN.md](../DESIGN.md): a Nuxt 3 full-stack Vue app
|
Build the Andon app per [DESIGN.md](../DESIGN.md): a Nuxt 3 full-stack Vue app
|
||||||
serving two domains (`andon.apoena.dev` reporting, `dashboard.andon.apoena.dev`
|
on one domain (`andon.apoena.dev`) — `/` reports a defect, `/defects` shows the
|
||||||
viewing), backed by SQLite/Drizzle, gated by Google SSO, with Web Push to the
|
weak-point view (ADR 0004) — backed by Postgres/Drizzle, gated by Google SSO,
|
||||||
owner. Team members file **Defects** about board **Sections**; the dashboard
|
with Web Push to the owner. Team members file **Defects** about board
|
||||||
renders a red-dot **Weak Point** map. Build order follows the House of Quality
|
**Sections**; `/defects` renders a red-dot **Weak Point** map. Build order follows the House of Quality
|
||||||
weights: the board definition (F1) is the spine, then frictionless filing
|
weights: the board definition (F1) is the spine, then frictionless filing
|
||||||
(F2/F3), then the weak-point map (F4/F5), then auth (F9), notifications (F7/F8),
|
(F2/F3), then the weak-point map (F4/F5), then auth (F9), notifications (F7/F8),
|
||||||
and deployment/durability (F10).
|
and deployment/durability (F10).
|
||||||
|
|
||||||
## Architecture Decisions
|
## Architecture Decisions
|
||||||
|
|
||||||
- **Single Nuxt 3 app, two domains** — host-based routing selects the reporting
|
- **Single Nuxt 3 app, one domain, two routes** — `/` reports, `/defects` views;
|
||||||
vs dashboard view; one auth layer, one DB, one board-definition module shared
|
one auth layer, one DB, one board-definition module shared by both (F1).
|
||||||
by both (DESIGN §3, F1). Avoids drift between the apps.
|
Transparency over separation now that auth gates everyone (ADR 0004).
|
||||||
- **Coolify-managed PostgreSQL + Drizzle (`pg` driver)** — automatic backups and
|
- **Coolify-managed PostgreSQL + Drizzle (`pg` driver)** — automatic backups and
|
||||||
no single-instance deploy constraint; chosen over SQLite once deploying on
|
no single-instance deploy constraint; chosen over SQLite once deploying on
|
||||||
Coolify (DESIGN T5, F10, ADR 0003). Local dev runs Postgres via docker-compose.
|
Coolify (DESIGN T5, F10, ADR 0003). Local dev runs Postgres via docker-compose.
|
||||||
@@ -175,12 +175,12 @@ auto. Target ≤3 interactions / ≤15s.
|
|||||||
**Description:** `GET /api/defects` returning a reverse-chronological feed
|
**Description:** `GET /api/defects` returning a reverse-chronological feed
|
||||||
(bounded slice) and `GET /api/defects/counts` returning per-section counts;
|
(bounded slice) and `GET /api/defects/counts` returning per-section counts;
|
||||||
`GET /api/defects?section=ID` for one section's history (lazy, for the modal).
|
`GET /api/defects?section=ID` for one section's history (lazy, for the modal).
|
||||||
Index `(section_id, created_at)`. Target ≤1s at ~2k rows.
|
Index `(section_id, created_at)`. Target ≤350ms at ~2k rows.
|
||||||
|
|
||||||
**Acceptance criteria:**
|
**Acceptance criteria:**
|
||||||
- [ ] Feed returns newest-first, bounded.
|
- [ ] Feed returns newest-first, bounded.
|
||||||
- [ ] Counts endpoint returns `{ sectionId: n }` for all sections.
|
- [ ] Counts endpoint returns `{ sectionId: n }` for all sections.
|
||||||
- [ ] With 2,000 seeded defects, dashboard queries return in ≤1s.
|
- [ ] With 2,000 seeded defects, dashboard queries return in ≤350ms.
|
||||||
|
|
||||||
**Verification:**
|
**Verification:**
|
||||||
- [ ] API test: `pnpm test -- defects-read`
|
- [ ] API test: `pnpm test -- defects-read`
|
||||||
@@ -232,7 +232,7 @@ list beside the board shows all defects newest-first.
|
|||||||
|
|
||||||
### Checkpoint: Weak points visible
|
### Checkpoint: Weak points visible
|
||||||
- [ ] Dashboard shows the dot map, feed, and modal end-to-end
|
- [ ] Dashboard shows the dot map, feed, and modal end-to-end
|
||||||
- [ ] ≤1s render with 2k seeded defects
|
- [ ] ≤350ms render with 2k seeded defects
|
||||||
- [ ] Review with human before proceeding
|
- [ ] Review with human before proceeding
|
||||||
|
|
||||||
### Phase 4 — Authentication (Goal G4)
|
### Phase 4 — Authentication (Goal G4)
|
||||||
|
|||||||
Reference in New Issue
Block a user