Files
familysync/.planning/phases/08-gitea-ci/08-02-SUMMARY.md
T

9.2 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
08-gitea-ci 02 infra
gitea-actions
ci
mariadb
vitest
drizzle
pnpm
playwright
phase provides
08-01 runner-mode probe answers (Docker-executor, ubuntu-latest, cache-skip, no mysql CLI)
PR-gating fast-checks job (lint + typecheck + PWA unit tests)
PR-gating api job (MariaDB 11 service container + drizzle-kit migrate + 238 API tests)
Single CI workflow file .gitea/workflows/ci.yml
08-03
08-04
phase-09
phase-10
phase-11
phase-12
added patterns
Docker-executor services: mariadb (not docker-run) — confirmed by 08-01 probe
Node mysql2 poll for MariaDB readiness (no mysql CLI in runner image)
drizzle-kit migrate (never db:push) on single squashed baseline migration
pnpm -r --if-present lint as auto-gate (exits 0 until a package lint script lands)
created modified
.gitea/workflows/ci.yml
apps/api/src/db/migrations/0000_baseline.sql
package.json
D-PROBE-01/02 honored: runs-on ubuntu-latest (not self-hosted), DB_HOST=mariadb (Docker-executor services:)
Cache DISABLED — actions/cache@v4 timed out in 08-01 probe (D-PROBE-04)
Readiness: Node mysql2 poll (90s deadline) — no mysql CLI available in runner image (D-PROBE-03)
Migration squash: all migrations collapsed to 0000_baseline.sql to fix broken cold drizzle-kit migrate
Lint is a documented no-op placeholder; root script changed to pnpm -r --if-present lint; real ESLint deferred to BACKLOG 999.16
PR-gate pattern: parallel fast-checks (no DB) + api (MariaDB services:) jobs both gated on pull_request
Readiness poll pattern: Node mysql2 script with 90s deadline before drizzle-kit migrate
CI-01
~90min (including squash fix, PR push, and cold-run verification) 2026-06-11

Phase 08 Plan 02: PR-Gating CI Jobs Summary

Gitea Actions ci.yml delivers parallel PR-gating fast-checks (191 PWA tests green) and api (MariaDB 11 service container, squashed baseline migration, 238 API tests green) jobs on a cold first run — CI-01 non-harness half complete

Performance

  • Duration: ~90 min
  • Started: 2026-06-11T15:00:00Z
  • Completed: 2026-06-11T~17:00:00Z
  • Tasks: 3 (including 1 checkpoint verified by operator)
  • Files modified: 3

Accomplishments

  • Created .gitea/workflows/ci.yml with parallel fast-checks and api jobs triggered on pull_request → main
  • fast-checks job: Node 22 + pnpm via corepack, lint (no-op gate), tsc typecheck (both apps including pwa tsconfig.e2e.json), 191/191 PWA unit tests green
  • api job: MariaDB 11 via services: (Docker-executor confirmed by 08-01), Node mysql2 readiness poll (90s), drizzle-kit migrate, 238/238 API integration tests green — passed cold on first run
  • Fixed broken cold drizzle-kit migrate by squashing all migrations to a single 0000_baseline.sql (deviation, see below)
  • Fixed root lint script from pnpm -r lintpnpm -r --if-present lint so it exits 0 today and auto-gates once a package lint script lands
  • Gitea Actions run #5 (PR #3, head 0b148b9): both jobs SUCCESS on a cold pull_request run

Task Commits

  1. Task 1: Create ci.yml with the fast-checks job - 667f017 (feat)
  2. Task 2: Add the API job (MariaDB service + migrate + DB-backed tests) - 3343f36 (feat)
  3. Task 3 (out-of-plan deviation — migration squash) - c0f892c (fix)
  4. Task 3 (out-of-plan deviation — lint fix) - dc31d4e (fix)
  5. Task 3 (out-of-plan — probe set to manual-only after CI verified) - 0b148b9 (chore)

Task 3 was a checkpoint:human-verify; operator confirmed both jobs green on cold run.

Files Created/Modified

  • .gitea/workflows/ci.yml — PR-gating workflow: fast-checks + api jobs in parallel
  • apps/api/src/db/migrations/0000_baseline.sql — Squashed baseline migration (replaces multiple fragmented migrations)
  • package.json — Root lint script changed from pnpm -r lint to pnpm -r --if-present lint

Decisions Made

  • runs-on: ubuntu-latest — plan text said self-hosted but 08-01 probe confirmed the runner has no self-hosted label; ubuntu-latest is the only working value (D-PROBE-01).
  • services: mariadb (Docker-executor path) — 08-01 confirmed Docker-executor (/.dockerenv present); used services: mariadb:11 with DB_HOST: mariadb, not the host-mode docker-run fallback.
  • Cache DISABLED — actions/cache@v4 timed out in the 08-01 probe run; omitted entirely (D-PROBE-04).
  • Node mysql2 readiness poll — no mysql CLI in runner image (D-PROBE-03), and mysqladmin ping was removed in MariaDB 11. Used a Node.js script that polls mysql2.createConnection().query('SELECT 1') with a 90s deadline.
  • Migration squash — cold drizzle-kit migrate failed because 0001_lists_schema recreated tables already created in 0000 (duplicates lists/list_shares/list_items + calendars unique constraint). Squashed to a single 0000_baseline.sql generated from current schema.ts. See Deviations.
  • Lint no-op gatepnpm lint (pnpm -r --if-present lint) exits 0 today (no package defines a lint script). This is intentional: the gate exists structurally and will auto-block once ESLint is wired. Real lint wiring deferred to BACKLOG 999.16 (operator decision).

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Squashed fragmented drizzle-kit migrations to fix broken cold migrate

  • Found during: Task 3 (PR cold-run verification)
  • Issue: Cold drizzle-kit migrate failed with "table already exists" — migration 0001_lists_schema recreated lists, list_shares, list_items, and the calendars unique-constraint that migration 0000 had already created. An orphaned migration 0001_calendars_user_url_unique also existed. Cold migration was impossible on a fresh DB.
  • Fix: Squashed all migrations into a single apps/api/src/db/migrations/0000_baseline.sql regenerated from schema.ts via drizzle-kit generate. Verified: fresh db:migrate succeeds, schema is structurally identical to dev DB, drizzle-kit generate reports no drift, 238 API tests pass. Local dev DBs must be rebuilt (drop + db:migrate); no production DB exists.
  • Files modified: apps/api/src/db/migrations/0000_baseline.sql, removed orphaned 0001 files
  • Verification: CI run #5 cold api job passed; drizzle-kit generate reports no drift post-squash
  • Committed in: c0f892c

2. [Rule 1 - Bug] Fixed root lint script to exit 0 on no-script workspaces

  • Found during: Task 1/2 (fast-checks job authoring)
  • Issue: pnpm -r lint emits ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT and exits non-zero when no package has a lint script. This would immediately block the CI gate even though ESLint is not yet wired.
  • Fix: Changed root package.json lint script from pnpm -r lint to pnpm -r --if-present lint. The --if-present flag silently skips packages without the script; exits 0. When any package adds a lint script, it is auto-gated. ESLint wiring deferred to BACKLOG 999.16.
  • Files modified: package.json
  • Verification: CI fast-checks job passes lint step; no ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT in run #5 log
  • Committed in: dc31d4e

Total deviations: 2 auto-fixed (2 Rule 1 bugs) Impact on plan: Both fixes were required for the cold-run pass. No scope creep.

Issues Encountered

  • MariaDB 11 does not include mysqladmin ping (removed upstream) — plan text mentioned it as a readiness option but this is a known pitfall (08-PITFALLS Pitfall 2). Used Node mysql2 poll instead.
  • healthcheck.sh --connect --innodb_initialized is available in the MariaDB 11 container image but not callable from the step shell in Docker-executor mode without a docker exec into the sidecar. Node mysql2 poll was simpler and equivalent.
  • 08-01 probe workflow was left as push + pull_request-triggered after CI verification — set to workflow_dispatch only (commit 0b148b9) to stop redundant re-runs on unrelated PRs.

Threat Surface Scan

No new endpoints, auth paths, file access patterns, or schema changes at trust boundaries introduced in this plan. The ci.yml uses throwaway creds (familysync/testpass, root/root) scoped to ephemeral MariaDB service containers only — T-08-03 mitigated. db:push absent from workflow — T-08-04 mitigated. Node mysql2 readiness poll with 90s deadline — T-08-05 mitigated.

Known Stubs

None — this plan produces CI workflow config only.

Next Phase Readiness

  • 08-03 (PWA harness): ci.yml is the target file for Plans 03 and 04. The push: branches: [main] trigger is already declared in ci.yml for the publish job (Plan 04). Plan 03 adds the harness job; both fast-checks and api jobs are green and stable.
  • Local dev note: After the migration squash, any local dev DB that was created before c0f892c must be rebuilt: DROP DATABASE familysync; CREATE DATABASE familysync; pnpm --filter @familysync/api db:migrate.
  • BACKLOG 999.16: ESLint wiring is explicitly deferred. The --if-present lint gate in ci.yml will auto-activate once any package adds a lint script — no ci.yml change needed.

Phase: 08-gitea-ci Completed: 2026-06-11