8.9 KiB
8.9 KiB
Phase 8: Gitea CI - Context
Gathered: 2026-06-11 Status: Ready for planning
## Phase BoundaryPhase 8 adds CI on the existing self-hosted Gitea Actions runner. Two outcomes:
- PR regression gate — every PR targeting
mainruns lint, typecheck (both apps), unit tests, API-integration tests against a MariaDB service container, and the Phase 7 mobile Playwright harness (against a CI-brought-up dev stack withDEV_AUTH_BYPASS=true). Any failure blocks the merge. - Publish on merge — a push to
mainbuilds and publishes the API Docker image to the Gitea container registry.
This phase owns only the CI plumbing: workflow files, dev-stack bring-up + readiness waits, image build/push. It does not modify the Phase 7 harness specs (CI reuses them unchanged), the Dockerfile (already multi-stage, builds API + PWA), or application code. Requirements: CI-01, CI-02.
## Implementation DecisionsDev-stack bring-up in CI (for the harness step)
- D-01: Bring up the stack with bare background processes + a MariaDB service container — NOT docker compose, NOT a production image.
- MariaDB runs as a Gitea service container (the same one the API-integration job needs;
DB_HOST=127.0.0.1, service creds). - The API runs as a background process via
pnpm dev:api(or equivalent) withDEV_AUTH_BYPASS=trueandDB_HOST=127.0.0.1, listening on:3000. - The PWA Vite dev server is started by Playwright's own
webServerconfig (already present;reuseExistingServer: !process.env.CI), on:5173. Vite proxies/api,/health,/callback→:3000. - Rationale: no docker-in-docker on the self-hosted runner; matches the Phase 7 dev-server harness contract exactly; reuses the MariaDB service container already required for integration tests.
- MariaDB runs as a Gitea service container (the same one the API-integration job needs;
- D-02: The harness step MUST wait for both the API (
:3000) and the PWA Vite server (:5173) to accept connections before Playwright launches. The harness already pollsbaseURL/health(proxied to the API) inglobal-setup.ts; CI must additionally ensure the API process is up first. This is on top of the MariaDB-11 readiness loop (Pitfall 11 —healthcheck.sh --connect --innodb_initialized, nevermysqladmin ping).
Workflow topology & jobs
- D-03: One workflow file with parallel, event-gated jobs.
pull_request→main: fast-checks job (lint + typecheck both apps + unit tests) runs in parallel with the heavier API-integration job and the harness job. Fast feedback — a lint failure does not wait behind the harness.push→main(merge): build-and-publish job runs.- Single file so the whole regression + publish story lives in one place; accept the minor setup duplication (checkout, pnpm cache, Node-22 pin) across jobs.
Docker image tag strategy (CI-02)
- D-04: On merge to
main, publish the API image with two tags::latest(moving pointer) and:<milestone>-<shortsha>(immutable, e.g.v1.1-4303a1b).- The milestone string (e.g.
v1.1) is read from PROJECT.md / ROADMAP.md, not hardcoded inline if avoidable. <shortsha>is the short commit SHA of the merge commit.- Rationale:
:latestfor easy pulls; the milestone-prefixed SHA tag groups builds by release line and stays immutable for rollback/traceability.
- The milestone string (e.g.
Failure artifacts & browser matrix
- D-05: Run both device profiles in CI — iPhone 14/WebKit and Pixel 7/Chromium (the full Phase 7 matrix). Install whatever system deps WebKit needs on the runner (probe in the runner-probe step).
- D-06: On harness failure, upload Playwright traces / screenshots / videos as CI artifacts for debugging. The config already emits
trace/videoon-first-retryandscreenshot: only-on-failure; CI must upload thetest-results/output. Note the config'sreporter: 'github'may not render natively in Gitea Actions — verify during the runner probe and fall back tolist/htmlif annotations don't surface.
Claude's Discretion
- Exact job names, step ordering within a job, pnpm store cache key strategy, and whether fast-checks is one job or split — planner/executor decide.
- Whether the API background process is launched with
pnpm dev:apivs a builtnode dist— pick whatever gives reliable:3000readiness underDEV_AUTH_BYPASS; the harness only needs the authed PWA reachable (Dev User 1 has no CalDAV creds, so verify layout/flows, not live event-create). - Registry hostname / image repository path under the Gitea registry.
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Phase scope & requirements
.planning/ROADMAP.md§"Phase 8: Gitea CI" — goal, 6 success criteria, pitfalls this phase owns..planning/REQUIREMENTS.md— CI-01 (PR regression incl. harness), CI-02 (publish image on merge)..planning/PITFALLS.md— Pitfalls 11 (MariaDB-11 readiness), 12 (runner-probe first), 13 (--password-stdin), 15 (SW block, harness side).
Harness the CI step runs (reused unchanged from Phase 7)
apps/pwa/playwright.config.ts— device matrix,serviceWorkers: 'block',webServer(Vite-only,reuseExistingServer: !CI),retries/workers/reporterunderCI, env-drivenPLAYWRIGHT_BASE_URL.apps/pwa/e2e/global-setup.ts—/healthreadiness poll,/api/meDEV_AUTH_BYPASS reachability gate, fail-closed env guard (refusesNODE_ENV=productionor missingDEV_AUTH_BYPASS), mysql2 truncate-and-seed (calendar id 10, lists/items for user 1)..planning/phases/07-mobile-test-harness/07-CONTEXT.md— Phase 7 decisions D-01..D-10 (auth strategy, SW block, env baseURL, compose-managed backend).
Infra the CI builds/runs against
apps/api/Dockerfile— multi-stage:builder(API),pwa-builder(PWA dist →./public),productiontarget. CI publishes theproductiontarget.docker-compose.yml/docker-compose.dev.yml— service shape, MariaDB 11 healthcheck (healthcheck.sh --connect --innodb_initialized), dev override exposing 3306, APIdevbuild target.apps/pwa/vite.config.ts— dev proxy (/api,/health,/callback→:3000) the harness depends on.package.json(root) — scripts:dev:api,dev:pwa,test,test:e2e,lint,typecheck.
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
- Playwright config + global-setup (Phase 7): ready to run headlessly in CI.
retries: 2,workers: 1,reporter: 'github'already gated onprocess.env.CI. CI setsCI=trueandPLAYWRIGHT_BASE_URLand the harness behaves correctly. No spec changes. - MariaDB service-container pattern: API-integration tests already require a real MariaDB with
DB_HOST=127.0.0.1+ service creds + Drizzlegenerate+migratefor schema. The harness'sglobal-setupseeds the same DB directly via mysql2. One MariaDB service container can back both the integration job and the harness job. - Multi-stage Dockerfile:
productiontarget already builds API + PWA and serves both on:3000. CI build/push is a thin wrapper (docker build --target production+docker login --password-stdin+docker push).
Established Patterns
- Gitea, not GitHub: origin is self-hosted Gitea;
mainis protected (PRs only). Gitea Actions is GitHub-Actions-syntax-compatible but do not assumeactions/setup-nodebehaves identically — runner-probe first (Pitfall 12), pin Node 22 explicitly. - node-cron lesson (long-running process): not directly relevant to CI, but the API in CI is short-lived/background — no scheduler concerns.
Integration Points
- CI orchestrates, in order, for the harness job: MariaDB service container (readiness loop) → Drizzle generate+migrate → API background process (
DEV_AUTH_BYPASS=true,:3000, readiness wait) → Playwright (webServerstarts Vite:5173,global-setuppolls/health+/api/me) → specs → upload artifacts on failure. - Publish job depends on
apps/api/Dockerfileproductiontarget + Gitea registry credentials (PAT withwrite:package, piped via--password-stdin).
</code_context>
## Specific Ideas- Image tag format locked to
:latest+:v1.1-<shortsha>(milestone prefix + short SHA). Example:v1.1-4303a1b. - Start the very first CI iteration as a runner-probe only:
node --version/pnpm --version/ Docker access / WebKit dep availability on theself-hostedrunner — before any real test/build steps are designed.
- ROADMAP status fix: ROADMAP.md line 29 marks Phase 8 "completed 2026-06-11" while line 204 says "Not started" and no Phase 8 artifacts exist. This is a bookkeeping error to correct (Phase 8 is being started now) — a docs/roadmap cleanup, not Phase 8 scope.
- None other — discussion stayed within phase scope.
Phase: 8-Gitea CI Context gathered: 2026-06-11