Files
tech-log-frontend/README.md
T
DongHyeonkaandClaude Opus 5 68c5dbdaa3 docs: state when contract-set verification actually fails the dev boot
The README framed a missing `contractSet` package as a caveat of switching to
`HTTP`. It is not conditional on `TECH_LOG_STUDIO_SOURCE` at all —
`public/config.json` never set that key, and `pnpm dev` still failed to boot in
the default `MOCK` mode. Filing a total dev-server outage under an opt-in
switch is what let it sit unnoticed.

Says plainly that verification runs unconditionally at boot, which half can
drift, and what keeps the two in sync. Drops the "graceful, non-blank error
screen" reassurance for the default path: a developer running `pnpm dev` and
getting a boot error has a broken dev server whatever the screen looks like.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 14:07:40 +09:00

267 lines
13 KiB
Markdown

# Tech Log Frontend
Initialized from `clean-architecture-frontend-template` revision
`4dc033cf33a5b6173bbf960d5eb464a406dc4c92`. The exact source identity is
recorded in `template.lock.json`.
A React/Vite TechLog application where architecture boundaries, integration
behavior, release coherence, accessibility, performance, and operations are
executable contracts rather than conventions.
## Start locally
Requirements: the exact Node.js version in `.nvmrc` (currently 24.14.0) and
Corepack. The repository pins pnpm in `package.json`.
Product source, tests, build/quality scripts, and supported tool configuration
are TypeScript/TSX. `allowJs` is disabled. Node-side `.ts` scripts run directly
on the pinned Node 24 runtime and are checked with NodeNext resolution plus
erasable-syntax enforcement. Project-owned executable source contains no
JavaScript-family files; negative architecture, security, and type-compatibility
fixtures are TypeScript/TSX as well.
```bash
corepack pnpm install --frozen-lockfile
corepack pnpm dev
```
Runtime-public settings live in `public/config.json` and are validated before
the product tree mounts. Client secrets are forbidden.
## TechLog experience
The default build mounts the source-faithful TechLog Public and Studio
experience. Public routes provide discovery, search, documents, topics,
projects, releases, and profile content. `/studio` provides the session-scoped
mock authoring workflow: create, edit, validate, preview, publish, unpublish,
and immutable publication history.
The 27 canonical route definitions are divided into `PUBLIC` and `STUDIO`
nested layouts. Studio authentication remains deliberately deferred; its mock
gateway state lasts for one Studio shell session and resets on a full document
load. The exact route, dependency, stylesheet, asset, and parity inventory is
recorded in
[`docs/operations/techlog-ui-migration-baseline.md`](docs/operations/techlog-ui-migration-baseline.md).
`corepack pnpm build` emits a self-contained `dist/server.mjs` production
boundary. `corepack pnpm preview --host 127.0.0.1 --port 4174` serves known
Public and Studio routes as SPA documents, preserves the in-shell Studio 404,
and returns source-exact raw `404 text/plain` responses for missing Public
content. With the read-only source temp-copy server on `4375`, run:
```bash
TECH_LOG_SOURCE_URL=http://127.0.0.1:4375 \
TECH_LOG_TARGET_URL=http://127.0.0.1:4174 \
corepack pnpm verify:tech-log-source-parity
```
### Studio backend source
`TECH_LOG_STUDIO_SOURCE` (`MOCK` | `HTTP`) selects which `StudioGateway`
adapter the composition root wires up. It defaults to `MOCK` — the
session-scoped in-memory Studio described above — so the existing Studio
workflow and its test suites are unaffected unless the switch is deliberately
turned on. Setting it to `HTTP` wires the HTTP `StudioGateway` instead, which
calls the canonical `@tech-log/studio-contract` operations against
`API_BASE_URL`. With no backend reachable at that URL, Studio still boots and
its shell renders; the specific panels that need the backend show an inline
"failed to load" state rather than a blank screen or an unhandled exception.
The switch is a field on the versioned runtime config document
(`RuntimeConfigV2`), not a build-time flag:
- `config/runtime/{local,development,staging,production}.json` are the
deployment profiles `corepack pnpm build` (via
`scripts/generate-runtime-config.ts`) materializes into `dist/config.json`
for a real build.
- `corepack pnpm dev` does not run that step. Plain `vite` serves
`public/config.json` (and `public/release-manifest.json`) verbatim as dev
fixtures — editing `config/runtime/local.json` alone has no effect on
`pnpm dev`. To exercise `HTTP` mode under `pnpm dev`, set
`TECH_LOG_STUDIO_SOURCE` in `public/config.json` directly.
### The dev release manifest must declare the compiled contract set
Contract-set verification runs unconditionally at boot, before any adapter is
selected. It is not an `HTTP`-mode caveat: if `public/release-manifest.json`'s
`contractSet` does not match the set the build compiled, `corepack pnpm dev`
does not start the app at all — it renders the fail-closed boot screen
(`CONTRACT_SET_MISMATCH` / `CONTRACT_SET_PACKAGE_MISSING`) in the **default
`MOCK` mode** too. A developer who runs `pnpm dev` and gets a boot error has a
broken dev server, however tidy the screen looks; treat it as a defect in the
fixture, never as expected behaviour.
The expectation comes from `EXPECTED_CONTRACT_SET_PACKAGES`
(`src/features/installed-contract-contributions.ts`), and a real build writes it
into `dist/release-manifest.json` from `scripts/generate-contract-set.ts`, so
production builds are always self-consistent. Only the hand-maintained dev
fixture can drift, and it drifts whenever either half moves — a regenerated
contract (new package digest or version) or a contribution added to or removed
from `installed-contract-contributions.ts`. Two things keep it honest:
- `corepack pnpm generate:tech-log-contract` refreshes the fixture's
`contractSet` block as its last step, so regenerating the contract can never
leave the two out of step. `corepack pnpm generate:dev-release-manifest`
refreshes the same block on its own, for the contribution-list case that does
not go through contract generation.
- `corepack pnpm check:dev-release-manifest` is the gate. It compares the
fixture's `setAlgorithm`, `setDigest` and package set against the compiled
set and fails on any difference. It runs in CI as part of FE-GATE-010, which
is what catches the changes the generation step cannot see.
### TechLog contract generation
The Studio HTTP contract is vendored from a canonical OpenAPI source, not
hand-written:
- `corepack pnpm generate:tech-log-contract` regenerates
`src/features/tech-log/contracts/studio/studio-api.openapi.yaml`,
`generated.ts`, and `canonical-source.json` from the canonical
`tech-log-design-package` repository (path from `TECH_LOG_DESIGN_PACKAGE`,
default `/home/donghyeon/workspace/tech-log-design-package`). It needs that
repository checked out locally and network access, because type generation
runs in an isolated `pnpm dlx` sandbox (this repo pins TypeScript 7, which
has no classic compiler API for `openapi-typescript` to use). Run it after
the canonical contract changes, then commit the regenerated files.
- `corepack pnpm check:tech-log-contract` is the drift gate: it hashes the
vendored yaml against the recorded digest and confirms every recorded
`operationId` is present in both the yaml and the generated types. It needs
neither the canonical repository nor the network, so it runs in CI and in
this sandbox. Run it any time to confirm the vendored contract has not
drifted from what was last generated.
## Architecture
Dependencies point inward:
```text
presentation -> application -> domain
adapters -----^
bootstrap composes concrete adapters
contracts own cross-cutting registries
```
See `docs/architecture/overview.md`, `docs/architecture/layers.md`, and
`docs/architecture/starter-experience.md`. TechLog is one feature boundary
under `src/features/tech-log`. Its immutable Public catalog and session-scoped
Studio mock gateway are injected through the application feature input;
Public and Studio presentation code shares the typed content renderer without
importing concrete adapters. The retained reference feature remains a
non-product platform contract fixture and can be removed without changing the
TechLog route set.
### Platform capability review
The starter shell is implemented, but the repository review also records the
remaining work required before feature teams can use every declared contract
through one end-to-end application path:
- [platform capability review](docs/architecture/frontend-platform-capability-review.md)
- [ports, adapters, and feature boundaries](docs/architecture/frontend-ports-adapters-and-boundaries.md)
- [REST, GraphQL, Connect/gRPC-Web, Schema, Mapper, and Server State](docs/architecture/api-contract-schema-mapper-and-server-state.md)
- [Protobuf browser transports and REST Gateway](docs/architecture/protobuf-browser-transport-and-rest-gateway.md)
- [backend API and Server State handoff contract](docs/architecture/backend-api-and-server-state-contract.md)
- [TypeScript, state ownership, and data flow](docs/architecture/typescript-state-and-data-flow.md)
- [routing, page templates, and reusable patterns](docs/architecture/routing-pages-and-patterns.md)
- [browser data capability completion ledger](docs/architecture/browser-data-capability-completion-ledger.md)
- [browser file and origin-storage platform](docs/architecture/browser-file-and-origin-storage.md)
- [client cache and storage](docs/architecture/client-cache-and-storage.md)
- [realtime events, Web Push, and bounded polling](docs/architecture/realtime-events-web-push-and-bounded-polling.md)
- [presigned transfer, resumable upload, streaming download, and Image CDN](docs/architecture/presigned-transfer-and-image-cdn.md)
- [server file capability infrastructure](docs/architecture/server-file-capability-infrastructure.md)
- [design-system platform](docs/styling/design-system-platform.md)
- [frontend platform testing strategy](docs/testing/frontend-platform-testing-strategy.md)
- [implementation roadmap](docs/architecture/frontend-platform-implementation-roadmap.md)
These documents distinguish repository defaults from opt-in adapters and
project-owned integrations. They are target designs and review findings; a
capability is not treated as implemented until its branch acceptance criteria
and executable gates pass.
## Verification
Common local checks:
```bash
corepack pnpm lint
corepack pnpm check:types
corepack pnpm check:types:app
corepack pnpm check:types:node
corepack pnpm check:types:test
corepack pnpm check:architecture
corepack pnpm test:all
corepack pnpm test:e2e
corepack pnpm test:a11y
corepack pnpm build
corepack pnpm check:bundle
corepack pnpm test:performance
corepack pnpm verify:compatibility
corepack pnpm verify:release
corepack pnpm check:registries
corepack pnpm drill:runbooks
corepack pnpm check:ci
corepack pnpm exec vitest run tests/features/tech-log
corepack pnpm exec playwright test tests/e2e/tech-log-public-discovery.spec.ts tests/e2e/tech-log-studio-workflow.spec.ts tests/e2e/tech-log-responsive.spec.ts tests/e2e/tech-log-accessibility.spec.ts --project=chromium
corepack pnpm test:visual
```
`check:types`는 source, Node scripts/config와 tests를 분리된 TypeScript
project로 모두 검사한다. type/architecture/security/registry의 invalid
fixture는 `config/ci/gates.json`에서 “실패해야 통과”하는 negative gate로
실행된다. 도구 호환성 결정은
[VD-01](docs/architecture/decisions/VD-01-typescript-lint-tooling.md)에 기록돼
있다.
Application feature input은 module augmentation으로 닫힌 ID와 정확한 input
shape를 제공하며, 공통 `Result<Value, Failure = AppFailure>`는 error registry의
failure kind만 application/presentation 경계를 통과시킨다. Architecture gate는
TypeScript/TSX의 static, dynamic, type import를 별도 정적 그래프로 분석하고
runtime/source 영역의 JavaScript 재유입도 거절한다. 해석되지 않은 import,
parse failure, 금지 계층 edge와 순환 의존은 모두 fail-closed이며 전용
TypeScript/TSX negative fixture로도 검증된다.
Install the pinned Playwright browser engines before the first cross-browser
run:
```bash
corepack pnpm exec playwright install --with-deps chromium firefox webkit
```
Two gates intentionally need external evidence:
- `review:a11y-manual` needs a signed human keyboard/focus/screen-reader review
for all 27 registered routes:
`NOT_FOUND`, `TECH_LOG_CASE`, `TECH_LOG_EXPLORE`, `TECH_LOG_EXPLORE_KIND`,
`TECH_LOG_HOME`, `TECH_LOG_PROFILE`, `TECH_LOG_PROJECT`,
`TECH_LOG_PROJECTS`, `TECH_LOG_PROJECT_ACTIVITY`,
`TECH_LOG_PROJECT_DECISIONS`, `TECH_LOG_PROJECT_RECORDS`,
`TECH_LOG_QUESTION`, `TECH_LOG_REFERENCE`, `TECH_LOG_RELEASE`,
`TECH_LOG_RELEASES`, `TECH_LOG_SEARCH`, `TECH_LOG_STUDIO_DOCUMENTS`,
`TECH_LOG_STUDIO_DOCUMENT_EDIT`, `TECH_LOG_STUDIO_DOCUMENT_NEW`,
`TECH_LOG_STUDIO_DOCUMENT_PREVIEW`, `TECH_LOG_STUDIO_DOCUMENT_PUBLISH`,
`TECH_LOG_STUDIO_DOCUMENT_VALIDATION`, `TECH_LOG_STUDIO_HOME`,
`TECH_LOG_STUDIO_NOT_FOUND`, `TECH_LOG_STUDIO_PUBLICATIONS`,
`TECH_LOG_STUDIO_PUBLICATION_PREVIEW`, `TECH_LOG_TOPIC`.
`verify:documentation` derives that list from the route registry and fails if
this paragraph falls behind it.
- `collect:web-vitals-evidence` stays `FAIL_UNVERIFIED` until a reviewed minimum
eligible-sample threshold and 28 days of production data exist.
Live release verification additionally requires `HOSTING_BASE_URL`.
## CI and evidence
The 26-gate registry is `config/ci/gates.json`; the Gitea workflow is
`.gitea/workflows/quality-gates.yml`. It follows:
```text
MERGE_READY -> RELEASE_READY -> PROD_PROMOTION_READY -> FIELD_SLO_READY
```
`DOCUMENTATION_READY` is independent. No gate is downgraded to a warning.
Machine-readable evidence is written below `artifacts/`; generated evidence is
ignored by Git while `.gitkeep` files preserve the taxonomy.
Operational details are in `docs/operations/`, with incident procedures in
`docs/runbooks/`.