docs(adr): adopt ADR-0027 for frontend/backend split (#177) #189

Merged
james merged 2 commits from 177-adr-frontend-backend-split into main 2026-06-20 16:20:45 +00:00
Owner

Summary

  • New ADR-0027 documents the architectural shift recorded in epic #176: Carol's frontend leaves the Next.js process and lives in a universal Expo Router + React Native Web client; Next.js becomes API-only; the boundary between them is an OpenAPI 3.1 spec generated from the existing zod schemas.
  • The ADR captures eight sub-decisions (separation, universal client, design-spec source-of-truth, OpenAPI contract, generated typed client, dual-mode auth, i18n runtime swap, repo layout) plus full Alternatives Considered (Flutter, Tauri-as-shell, Capacitor, PWA-only, share-logic-only, Compose Multiplatform).
  • Status lines on ADR-0004 (sessions), ADR-0015 (OAuth2), and ADR-0025 (i18n) record the extension; ADR-0025 specifically calls out that the next-intl runtime is superseded while the JSON catalog survives.
  • CLAUDE.md "Shape of the system" rewritten from three pieces (service + PWA + native) to two artifacts (API service + universal client) with OpenAPI as the contract.
  • idea.md preamble and Service section rewritten to match; Releases line reworded.
  • docs/adr/README.md index gains the ADR-0027 entry.

This is a doc-only PR — no code changes. The rest of epic #176 (#178–#188) implements what this ADR records.

Follow-up worth flagging

Ticket #184 ("Port existing screens to Expo Router") uses the word port and says "read the current Next.js page, render the same UI in apps/client." That should be reworded to "implement from the design spec + feature ticket, against the API" so future contributors don't treat the Next.js source as the migration target. The design package + per-screen feature tickets (#143, #144, #145…) are the source of truth, not the Next.js code being deleted in #185. Doing this rewording is out of scope here.

Test plan

  • ls docs/adr/0027-*.md returns the new file.
  • grep -n "Extended by ADR-0027" docs/adr/{0004,0015,0025}-*.md returns one hit per file, all on the Status line.
  • grep -n "ADR-0027" docs/adr/README.md returns the new index entry.
  • grep -n "Universal client" CLAUDE.md hits the rewritten section; grep -n "the same Next.js app" CLAUDE.md returns nothing.
  • grep -n "OpenAPI" idea.md hits the rewritten architecture description.
  • Read ADR-0027 top-to-bottom and confirm it agrees with CLAUDE.md "Shape of the system" — same architecture, same words.
  • CI's commits job passes (Conventional Commits subject).

Closes #177. First ticket under epic #176.

## Summary - New **ADR-0027** documents the architectural shift recorded in epic #176: Carol's frontend leaves the Next.js process and lives in a universal Expo Router + React Native Web client; Next.js becomes API-only; the boundary between them is an OpenAPI 3.1 spec generated from the existing zod schemas. - The ADR captures eight sub-decisions (separation, universal client, design-spec source-of-truth, OpenAPI contract, generated typed client, dual-mode auth, i18n runtime swap, repo layout) plus full Alternatives Considered (Flutter, Tauri-as-shell, Capacitor, PWA-only, share-logic-only, Compose Multiplatform). - Status lines on ADR-0004 (sessions), ADR-0015 (OAuth2), and ADR-0025 (i18n) record the extension; ADR-0025 specifically calls out that the next-intl runtime is superseded while the JSON catalog survives. - `CLAUDE.md` "Shape of the system" rewritten from three pieces (service + PWA + native) to two artifacts (API service + universal client) with OpenAPI as the contract. - `idea.md` preamble and Service section rewritten to match; Releases line reworded. - `docs/adr/README.md` index gains the ADR-0027 entry. This is a doc-only PR — no code changes. The rest of epic #176 (#178–#188) implements what this ADR records. ## Follow-up worth flagging Ticket **#184** ("Port existing screens to Expo Router") uses the word *port* and says "read the current Next.js page, render the same UI in `apps/client`." That should be reworded to "implement from the design spec + feature ticket, against the API" so future contributors don't treat the Next.js source as the migration target. The design package + per-screen feature tickets (#143, #144, #145…) are the source of truth, not the Next.js code being deleted in #185. Doing this rewording is out of scope here. ## Test plan - [ ] `ls docs/adr/0027-*.md` returns the new file. - [ ] `grep -n "Extended by ADR-0027" docs/adr/{0004,0015,0025}-*.md` returns one hit per file, all on the Status line. - [ ] `grep -n "ADR-0027" docs/adr/README.md` returns the new index entry. - [ ] `grep -n "Universal client" CLAUDE.md` hits the rewritten section; `grep -n "the same Next.js app" CLAUDE.md` returns nothing. - [ ] `grep -n "OpenAPI" idea.md` hits the rewritten architecture description. - [ ] Read ADR-0027 top-to-bottom and confirm it agrees with `CLAUDE.md` "Shape of the system" — same architecture, same words. - [ ] CI's `commits` job passes (Conventional Commits subject). Closes #177. First ticket under epic #176.
docs(adr): adopt ADR-0027 for frontend/backend split (#177)
Some checks failed
Commits / Conventional Commits (pull_request) Successful in 10s
PR / Static analysis (pull_request) Successful in 32s
PR / OSV-Scanner (pull_request) Successful in 58s
PR / Trivy (image) (pull_request) Failing after 1m6s
PR / Package age policy (soft) (pull_request) Successful in 34s
PR / npm audit (pull_request) Successful in 1m20s
PR / Typecheck (pull_request) Successful in 1m28s
PR / Lint (pull_request) Successful in 1m32s
Secrets / gitleaks (pull_request) Successful in 33s
PR / Test (sqlite) (pull_request) Successful in 1m41s
PR / Coverage (soft) (pull_request) Successful in 1m37s
PR / Test (postgres) (pull_request) Successful in 1m46s
PR / Build (pull_request) Successful in 1m57s
0de0ec9381
Carol's frontend leaves the Next.js process and lives in a universal
Expo Router + React Native Web client; Next.js becomes API-only; the
boundary between them is an OpenAPI 3.1 spec generated from the
existing zod schemas.

- New ADR-0027 documents the decision, alternatives (Flutter, Tauri,
  Capacitor, PWA-only, Compose Multiplatform), and the eight
  sub-decisions that follow (separation, universal client, design-spec
  source-of-truth, OpenAPI contract, generated typed client, dual-mode
  auth, i18n runtime swap, repo layout).
- Status lines updated on ADR-0004 (sessions), ADR-0015 (OAuth2), and
  ADR-0025 (i18n) to record the extension; 0025 calls out that the
  next-intl runtime is superseded while the JSON catalog survives.
- CLAUDE.md "Shape of the system" rewritten from three pieces
  (service + PWA + native) to two artifacts (API service + universal
  client) with OpenAPI as the contract.
- idea.md preamble and Service section rewritten to match; Releases
  line reworded.
- docs/adr/README.md index gains the ADR-0027 entry.

Follow-up (not in scope here): ticket #184 "Port existing screens to
Expo Router" uses the word "port" — should be reworded to "implement
from the design spec + feature ticket" so future contributors don't
treat the Next.js source as the migration target.

Closes #177. First ticket under epic #176.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Trivy (container image)

Threshold: high  ·  Total findings: 121  ·  At/above threshold: 1

critical high medium low
0 1 50 70
severity id package installed / range fix
high CVE-2026-12151 undici 6.25.0 6.27.0, 7.28.0, 8.5.0
<!-- scanner-comment: trivy --> ### Trivy (container image) **Threshold:** `high` &nbsp;·&nbsp; **Total findings:** 121 &nbsp;·&nbsp; **At/above threshold:** 1 | critical | high | medium | low | |---:|---:|---:|---:| | 0 | 1 | 50 | 70 | | severity | id | package | installed / range | fix | |---|---|---|---|---| | high | [CVE-2026-12151](https://avd.aquasec.com/nvd/cve-2026-12151) | undici | 6.25.0 | `6.27.0, 7.28.0, 8.5.0` |

📊 Test coverage

Patch coverage: no testable lines changed.

Overall (app/, lib/, db/, excluding UI per ADR-0019):

Metric Value Soft target
Lines 75.3% ≥ 50%
Branches 80.8% ≥ 75%
Functions 88.2% informational

Soft thresholds per ADR-0019. Coverage is informational and does not block merge.

<!-- coverage-comment --> ## 📊 Test coverage **Patch coverage:** no testable lines changed. **Overall** (`app/`, `lib/`, `db/`, excluding UI per ADR-0019): | Metric | Value | Soft target | |---|---|---| | Lines | 75.3% ✅ | ≥ 50% | | Branches | 80.8% ✅ | ≥ 75% | | Functions | 88.2% | informational | Soft thresholds per [ADR-0019](docs/adr/0019-coverage-soft-targets.md). Coverage is informational and does not block merge.
docs(adr): name the PWA bundle as a release artifact in idea.md (#177)
Some checks failed
Commits / Conventional Commits (pull_request) Successful in 9s
PR / OSV-Scanner (pull_request) Successful in 26s
PR / Trivy (image) (pull_request) Failing after 28s
PR / Static analysis (pull_request) Successful in 34s
PR / Package age policy (soft) (pull_request) Successful in 11s
Secrets / gitleaks (pull_request) Successful in 13s
PR / npm audit (pull_request) Successful in 1m50s
PR / Typecheck (pull_request) Successful in 2m29s
PR / Lint (pull_request) Successful in 2m30s
PR / Test (sqlite) (pull_request) Successful in 2m54s
PR / Coverage (soft) (pull_request) Successful in 2m50s
PR / Test (postgres) (pull_request) Successful in 2m59s
PR / Build (pull_request) Successful in 3m3s
a4a4bb0f5f
The Releases line called out Android + Linux Flatpak builds but left the
PWA web bundle implicit. ADR-0027 explicitly ships three client forms
from one codebase, and the PWA bundle is a real release artifact (it
gets baked into the API container image, per the single-container
deployment ticket). Naming all three keeps the doc honest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
james merged commit 062daea5e0 into main 2026-06-20 16:20:45 +00:00
james deleted branch 177-adr-frontend-backend-split 2026-06-20 16:20:45 +00:00
Sign in to join this conversation.
No description provided.