docs(08): Phase 8 close-out — SUMMARY + VERIFICATION + tracking #4
@@ -39,8 +39,8 @@ Each requirement maps to exactly one roadmap phase (see Traceability).
|
|||||||
|
|
||||||
### CI — Gitea continuous integration
|
### CI — Gitea continuous integration
|
||||||
|
|
||||||
- [ ] **CI-01**: Every pull request targeting `main` runs full regression — lint, typecheck (both apps), unit tests, API integration tests against a MariaDB service container, **and the Phase 7 mobile Playwright harness as a UI-regression step (CI brings up the API + PWA dev servers + MariaDB service container with `DEV_AUTH_BYPASS` in the runner and runs the harness specs headlessly against the authed PWA)** — and the result gates the merge.
|
- [x] **CI-01**: Every pull request targeting `main` runs full regression — lint, typecheck (both apps), unit tests, API integration tests against a MariaDB service container, **and the Phase 7 mobile Playwright harness as a UI-regression step (CI brings up the API + PWA dev servers + MariaDB service container with `DEV_AUTH_BYPASS` in the runner and runs the harness specs headlessly against the authed PWA)** — and the result gates the merge.
|
||||||
- [ ] **CI-02**: On merge to `main`, the API Docker image is built and published to the Gitea container registry.
|
- [x] **CI-02**: On merge to `main`, the API Docker image is built and published to the Gitea container registry.
|
||||||
|
|
||||||
### Test — Mobile-emulated authed browser harness
|
### Test — Mobile-emulated authed browser harness
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@ Maps each REQ-ID to its phase. v1.1 phases continue v1.0 numbering (v1.0 ended a
|
|||||||
|--------|-------|--------|
|
|--------|-------|--------|
|
||||||
| TEST-01 | Phase 7 (Mobile Test Harness) | Complete |
|
| TEST-01 | Phase 7 (Mobile Test Harness) | Complete |
|
||||||
| TEST-02 | Phase 7 (Mobile Test Harness) | Complete |
|
| TEST-02 | Phase 7 (Mobile Test Harness) | Complete |
|
||||||
| CI-01 | Phase 8 (Gitea CI) | In progress |
|
| CI-01 | Phase 8 (Gitea CI) | Complete |
|
||||||
| CI-02 | Phase 8 (Gitea CI) | Pending |
|
| CI-02 | Phase 8 (Gitea CI) | Complete |
|
||||||
| CAL-15 | Phase 9 (Faster Write-Back) | Pending |
|
| CAL-15 | Phase 9 (Faster Write-Back) | Pending |
|
||||||
| ADMIN-01 | Phase 10 (Admin Role & Settings) | Pending |
|
| ADMIN-01 | Phase 10 (Admin Role & Settings) | Pending |
|
||||||
| ADMIN-02 | Phase 10 (Admin Role & Settings) | Pending |
|
| ADMIN-02 | Phase 10 (Admin Role & Settings) | Pending |
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Full phase detail archived in [`milestones/v1.0-ROADMAP.md`](milestones/v1.0-ROA
|
|||||||
Make FamilySync configurable, administrable, and maintainable for real multi-member use — without hand-editing env files or the database. The new critical path runs **mobile test harness → Gitea CI** (CI consumes the harness specs for UI regression), and the **admin role → reminders / setup wizard** chain (a single `/api/admin` + `/api/setup` route surface carrying the v1.1 DB migration). Faster write-back is a fully independent track.
|
Make FamilySync configurable, administrable, and maintainable for real multi-member use — without hand-editing env files or the database. The new critical path runs **mobile test harness → Gitea CI** (CI consumes the harness specs for UI regression), and the **admin role → reminders / setup wizard** chain (a single `/api/admin` + `/api/setup` route surface carrying the v1.1 DB migration). Faster write-back is a fully independent track.
|
||||||
|
|
||||||
- [x] **Phase 7: Mobile Test Harness** - Mobile-emulated, authenticated PWA browser harness so the assistant (and CI) can catch mobile-only defects (completed 2026-06-11)
|
- [x] **Phase 7: Mobile Test Harness** - Mobile-emulated, authenticated PWA browser harness so the assistant (and CI) can catch mobile-only defects (completed 2026-06-11)
|
||||||
- [ ] **Phase 8: Gitea CI** - Full regression on PR to main (lint/typecheck/unit/API-integration vs a MariaDB service container **+ the Phase 7 mobile harness as a UI-regression step against a CI-hosted dev stack**) + Docker image publish on merge
|
- [x] **Phase 8: Gitea CI** - Full regression on PR to main (lint/typecheck/unit/API-integration vs a MariaDB service container **+ the Phase 7 mobile harness as a UI-regression step against a CI-hosted dev stack**) + Docker image publish on merge (completed 2026-06-11)
|
||||||
- [ ] **Phase 9: Faster Write-Back** - Event-driven outbox drain so edits land in ~1-2s instead of ~15s, preserving every outbox durability guarantee
|
- [ ] **Phase 9: Faster Write-Back** - Event-driven outbox drain so edits land in ~1-2s instead of ~15s, preserving every outbox durability guarantee
|
||||||
- [ ] **Phase 10: Admin Role & Settings** - DB foundation (is_admin / reminder_lead / app_config) + role-gated admin UI to rotate app passwords and designate the shared calendar
|
- [ ] **Phase 10: Admin Role & Settings** - DB foundation (is_admin / reminder_lead / app_config) + role-gated admin UI to rotate app passwords and designate the shared calendar
|
||||||
- [ ] **Phase 11: Per-Event Reminders** - Reminder selector on the event form (incl. "None") serialized as VALARM, with a variable-lead scheduler that honors each event's choice
|
- [ ] **Phase 11: Per-Event Reminders** - Reminder selector on the event form (incl. "None") serialized as VALARM, with a variable-lead scheduler that honors each event's choice
|
||||||
@@ -109,7 +109,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem
|
|||||||
|
|
||||||
**Wave 4** *(blocked on Wave 3 completion)*
|
**Wave 4** *(blocked on Wave 3 completion)*
|
||||||
|
|
||||||
- [ ] 08-04-PLAN.md — ci.yml: publish job (build production image + push :latest + :v1.1-<sha> via --password-stdin)
|
- [x] 08-04-PLAN.md — ci.yml: publish job (build production image + push :latest + :v1.1-<sha> via --password-stdin)
|
||||||
|
|
||||||
**UI hint**: yes
|
**UI hint**: yes
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem
|
|||||||
| 5. Web Push Notifications | v1.0 | 8/8 | Complete | 2026-06-10 |
|
| 5. Web Push Notifications | v1.0 | 8/8 | Complete | 2026-06-10 |
|
||||||
| 6. UX Polish | v1.0 | 6/6 | Complete | 2026-06-10 |
|
| 6. UX Polish | v1.0 | 6/6 | Complete | 2026-06-10 |
|
||||||
| 7. Mobile Test Harness | v1.1 | 4/4 | Complete | 2026-06-11 |
|
| 7. Mobile Test Harness | v1.1 | 4/4 | Complete | 2026-06-11 |
|
||||||
| 8. Gitea CI | v1.1 | 3/4 | In Progress| |
|
| 8. Gitea CI | v1.1 | 4/4 | Complete | 2026-06-11 |
|
||||||
| 9. Faster Write-Back | v1.1 | 0/? | Not started | - |
|
| 9. Faster Write-Back | v1.1 | 0/? | Not started | - |
|
||||||
| 10. Admin Role & Settings | v1.1 | 0/? | Not started | - |
|
| 10. Admin Role & Settings | v1.1 | 0/? | Not started | - |
|
||||||
| 11. Per-Event Reminders | v1.1 | 0/? | Not started | - |
|
| 11. Per-Event Reminders | v1.1 | 0/? | Not started | - |
|
||||||
|
|||||||
+17
-16
@@ -2,16 +2,16 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.1
|
milestone: v1.1
|
||||||
milestone_name: Operability & Polish
|
milestone_name: Operability & Polish
|
||||||
status: executing
|
status: phase-complete
|
||||||
stopped_at: 08-03 complete — advancing to 08-04 (Wave 4, publish job)
|
stopped_at: Phase 08 complete — all 4 plans executed, CI-01 + CI-02 delivered, publish job verified green (run #14)
|
||||||
last_updated: "2026-06-11T20:00:00.000Z"
|
last_updated: "2026-06-11T22:00:00.000Z"
|
||||||
last_activity: "2026-06-11 -- 08-03 complete; harness job green on cold CI run (run #11): 58 specs passed across iphone/WebKit + pixel/Chromium in 1.6 min; 4 infrastructure fixes (API-reap, IPv4-first, dev-user seed, reporter forwarding); no Phase 7 harness file modified; advancing to 08-04"
|
last_activity: "2026-06-11 -- 08-04 complete; publish job green (run #14, merge commit 98acff8): both image tags pushed (familysync-api:latest + :v1.1-98acff8), PAT masked, --password-stdin confirmed. REGISTRY_PAT naming fix (73eecf7). Phase 8 (Gitea CI) complete — all 6 ROADMAP criteria met."
|
||||||
progress:
|
progress:
|
||||||
total_phases: 16
|
total_phases: 16
|
||||||
completed_phases: 1
|
completed_phases: 2
|
||||||
total_plans: 8
|
total_plans: 8
|
||||||
completed_plans: 6
|
completed_plans: 8
|
||||||
percent: 6
|
percent: 12
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -25,10 +25,10 @@ See: .planning/PROJECT.md (updated 2026-06-10)
|
|||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 08 (gitea-ci) — EXECUTING
|
Phase: 08 (gitea-ci) — COMPLETE
|
||||||
Plan: 4 of 4 (08-04 next — Wave 4, publish job)
|
Plan: 4 of 4 (08-04 complete)
|
||||||
Status: Executing — 08-03 complete, harness green (58 specs, both profiles, cold CI run)
|
Status: Phase 08 complete — all 4 plans executed, CI-01 + CI-02 delivered
|
||||||
Last activity: 2026-06-11 -- 08-03 complete; harness job green on cold CI run (run #11): 58 specs passed across iphone/WebKit + pixel/Chromium in 1.6 min; 4 infrastructure fixes (API-reap, IPv4-first, dev-user seed, reporter forwarding); no Phase 7 harness file modified; advancing to 08-04
|
Last activity: 2026-06-11 -- 08-04 complete; publish job green (run #14): both tags pushed, PAT masked, REGISTRY_PAT naming fix applied. Phase 8 fully complete.
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -98,6 +98,7 @@ Recent decisions affecting current work:
|
|||||||
- D-PROBE-06 (2026-06-11, 08-01): ChristopherHX/gitea-upload-artifact@v4 works — MUST use this fork; actions/upload-artifact@v4 broken on Gitea.
|
- D-PROBE-06 (2026-06-11, 08-01): ChristopherHX/gitea-upload-artifact@v4 works — MUST use this fork; actions/upload-artifact@v4 broken on Gitea.
|
||||||
- D-PROBE-07 (2026-06-11, 08-01): ${GITHUB_SHA:0:7} produces 7 chars — D-04 publish tag expression valid.
|
- D-PROBE-07 (2026-06-11, 08-01): ${GITHUB_SHA:0:7} produces 7 chars — D-04 publish tag expression valid.
|
||||||
- D-PROBE-08 (2026-06-11, 08-01): GITEA_REGISTRY_PAT deferred to Plan 04; PAT not exercised in probe.
|
- D-PROBE-08 (2026-06-11, 08-01): GITEA_REGISTRY_PAT deferred to Plan 04; PAT not exercised in probe.
|
||||||
|
- D-PAT-NAMING (2026-06-11, 08-04): Gitea runner silently drops secrets with the `GITEA_` prefix (reserved namespace). Secret renamed from GITEA_REGISTRY_PAT → REGISTRY_PAT in both repo secret and ci.yml (commit 73eecf7). Use REGISTRY_PAT in any future registry operations.
|
||||||
- CAL-08 RESOLVED → GO (Phase 1): per-member Fastmail app password reaches all of that account's calendars; no cross-account ACL needed. Unified view stands; no shared-only fallback. See CAL-08-DECISION.md.
|
- CAL-08 RESOLVED → GO (Phase 1): per-member Fastmail app password reaches all of that account's calendars; no cross-account ACL needed. Unified view stands; no shared-only fallback. See CAL-08-DECISION.md.
|
||||||
- D-14 (2026-06-04): Phase 1 Gate 2 (live Authelia/Pangolin) deferred. SSE-over-Pangolin smoke = hard gate before Phase 4; live AUTH smoke incl. iOS standalone-PWA folded into Phase 3. Phases 2–3 build behind a dev-auth bypass. Tracked in 01-HUMAN-UAT.md + docs/deployment.md.
|
- D-14 (2026-06-04): Phase 1 Gate 2 (live Authelia/Pangolin) deferred. SSE-over-Pangolin smoke = hard gate before Phase 4; live AUTH smoke incl. iOS standalone-PWA folded into Phase 3. Phases 2–3 build behind a dev-auth bypass. Tracked in 01-HUMAN-UAT.md + docs/deployment.md.
|
||||||
- D-15 (2026-06-04): Validate real topology via local Newt connector + test subdomain through Pangolin (Mode A), not an Unraid deploy; Unraid reserved for go-live.
|
- D-15 (2026-06-04): Validate real topology via local Newt connector + test subdomain through Pangolin (Mode A), not an Unraid deploy; Unraid reserved for go-live.
|
||||||
@@ -199,11 +200,11 @@ Recent decisions affecting current work:
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-06-11T20:00:00.000Z
|
Last session: 2026-06-11T22:00:00.000Z
|
||||||
Stopped at: 08-03 complete — advancing to 08-04 (Wave 4, publish job)
|
Stopped at: Phase 08 complete — CI-01 + CI-02 delivered, publish job verified, SUMMARY + VERIFICATION written
|
||||||
Resume file: .planning/phases/08-gitea-ci/08-04-PLAN.md
|
Resume file: None — start Phase 09 with /gsd-plan-phase 9
|
||||||
|
|
||||||
## Operator Next Steps
|
## Operator Next Steps
|
||||||
|
|
||||||
- Review the reordered v1.1 roadmap in `.planning/ROADMAP.md` (Phases 7–12).
|
- **Phase 8 is complete.** CI pipeline is fully operational on the self-hosted Gitea runner.
|
||||||
- Plan the first phase with `/gsd-plan-phase 7` (Mobile Test Harness — independent, goes first; Phase 8 CI runs its specs). Alternatives that can start in parallel: `/gsd-plan-phase 9` (Faster Write-Back — independent, lowest risk) or `/gsd-plan-phase 10` (Admin Role & Settings — carries the DB migration that Phases 11 & 12 depend on).
|
- Next: `/gsd-plan-phase 9` (Faster Write-Back — fully independent, lowest risk) or `/gsd-plan-phase 10` (Admin Role & Settings — carries the v1.1 DB migration that Phases 11 & 12 depend on). These can run in parallel once planned.
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
---
|
||||||
|
phase: 08-gitea-ci
|
||||||
|
plan: "04"
|
||||||
|
subsystem: infra
|
||||||
|
tags: [gitea, docker, ci, registry, publish, security]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 08-03
|
||||||
|
provides: harness job in ci.yml; dev-stack bring-up confirmed in CI
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- publish job in .gitea/workflows/ci.yml (push to main → build + push API Docker image)
|
||||||
|
- familysync-api:latest and familysync-api:v1.1-<7charsha> tags in Gitea registry
|
||||||
|
- --password-stdin docker login pattern (REGISTRY_PAT secret, never plaintext)
|
||||||
|
|
||||||
|
affects: [phase-09, phase-10, phase-11, phase-12]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "docker login --password-stdin (PAT piped via stdin; -p flag forbidden)"
|
||||||
|
- "dual-tag publish: :latest + :<milestone>-<shortsha> (D-04 traceability)"
|
||||||
|
- "docker build from repo root: -f apps/api/Dockerfile . (Dockerfile requires workspace manifest)"
|
||||||
|
- "docker logout in always() step to drop credential from runner after push"
|
||||||
|
- "Gitea secret prefix exclusion: REGISTRY_PAT not GITEA_REGISTRY_PAT (Gitea reserves GITEA_ prefix)"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- .gitea/workflows/ci.yml
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "D-PAT-NAMING: Gitea runner silently ignores secrets with the GITEA_ prefix; secret renamed from GITEA_REGISTRY_PAT to REGISTRY_PAT in both the Gitea repo secret and ci.yml (commit 73eecf7). This is the load-bearing fix that unblocked the publish job."
|
||||||
|
- "D-SHELL-FORM: Used shell docker login/build/push (not docker/login-action or docker/build-push-action) — matches 08-RESEARCH §Pattern 6 recommendation; simpler and has no marketplace action dependency."
|
||||||
|
- "D-DUAL-TAG: Two docker push calls for :latest and :v1.1-<shortsha>; same digest, two tags. Traceability tag links image to the exact merge commit."
|
||||||
|
- "D-LOGOUT: docker logout in always() step — drops stored credential from runner regardless of push success/failure (security hygiene)."
|
||||||
|
|
||||||
|
requirements-completed: [CI-02]
|
||||||
|
|
||||||
|
duration: checkpoint-verified
|
||||||
|
completed: "2026-06-11"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 08 Plan 04: Publish Job Summary
|
||||||
|
|
||||||
|
**Publish job wired to push-to-main: API Docker production image pushed to Gitea registry under :latest and :v1.1-<7charsha>, PAT authenticated via --password-stdin (never plaintext), security audit passed — CI-02 delivered.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** multi-step (Task 1 executed, Task 2 was a human-verify checkpoint — verified green on run #14)
|
||||||
|
- **Started:** 2026-06-11
|
||||||
|
- **Completed:** 2026-06-11
|
||||||
|
- **Tasks:** 2 (1 auto + 1 human-verify checkpoint)
|
||||||
|
- **Files modified:** 1
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Added the `publish` job to `.gitea/workflows/ci.yml`: gated on `github.event_name == 'push' && github.ref == 'refs/heads/main'`, never fires on pull_request.
|
||||||
|
- Run #14 (merge commit 98acff8 pushed to main) confirmed SUCCESS (1m): docker login succeeded, both image tags pushed (same digest sha256:ce724852…) — `familysync-api:latest` and `familysync-api:v1.1-98acff8` present in Gitea Packages API.
|
||||||
|
- Security audit of the CI log passed: PAT masked as `***` throughout (Gitea secret scrubber); `--password-stdin` used exclusively; no `-p`/`--password` form anywhere; `docker logout` ran in the `always()` cleanup step. No plaintext token anywhere in the log.
|
||||||
|
- Identified and fixed the GITEA_-prefix secret naming bug: Gitea runner silently drops secrets whose names start with `GITEA_`; renamed secret from `GITEA_REGISTRY_PAT` to `REGISTRY_PAT` in both the repo secret and ci.yml (commit 73eecf7).
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
1. **Task 1: Add the publish job** - `ebcc38d` (feat)
|
||||||
|
2. **Task 1 fix: REGISTRY_PAT naming** - `73eecf7` (fix — GITEA_ prefix exclusion)
|
||||||
|
3. **Pre-merge cleanup: remove throwaway runner-probe.yml** - `dcf4242` (chore)
|
||||||
|
4. **Task 2: Human-verify checkpoint** — verified green (run #14); no code commit required
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `.gitea/workflows/ci.yml` — publish job added (push-to-main guard, --password-stdin docker login, build --target production from repo root, dual push :latest + :v1.1-<sha>, docker logout always())
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- **REGISTRY_PAT naming (D-PAT-NAMING):** Gitea reserves the `GITEA_` prefix for built-in variables and silently strips any user-defined secret with that prefix from the runner environment. The original plan named the secret `GITEA_REGISTRY_PAT`; the fix renames it to `REGISTRY_PAT` (commit 73eecf7). Downstream plans must use `REGISTRY_PAT` if they add registry operations.
|
||||||
|
- **Shell form over marketplace actions:** `echo "${{ secrets.REGISTRY_PAT }}" | docker login ... --password-stdin` + `docker build` + `docker push` rather than `docker/login-action` / `docker/build-push-action`. This matches the 08-RESEARCH §Pattern 6 preferred path; no external action marketplace dependency.
|
||||||
|
- **Dual push:** two separate `docker push` calls (`:latest` + `:<milestone>-<sha>`) — same digest, two references. `:latest` is the moving pointer; `:<milestone>-<sha>` is the immutable traceability tag per D-04.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 1 - Bug] GITEA_REGISTRY_PAT secret prefix rejected by Gitea runner**
|
||||||
|
- **Found during:** Task 1 → human-verify checkpoint (run #14 initially failed login)
|
||||||
|
- **Issue:** Gitea Actions runner silently ignores secrets with the `GITEA_` prefix (reserved namespace). The `GITEA_REGISTRY_PAT` secret was never injected into the job environment, causing `docker login` to fail with an empty password.
|
||||||
|
- **Fix:** Renamed the Gitea repo secret from `GITEA_REGISTRY_PAT` to `REGISTRY_PAT` and updated the ci.yml reference accordingly (commit 73eecf7).
|
||||||
|
- **Files modified:** `.gitea/workflows/ci.yml`
|
||||||
|
- **Verification:** Run #14 succeeded — "Login Succeeded" in log; both tags pushed; PAT masked.
|
||||||
|
- **Committed in:** `73eecf7`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 1 auto-fixed (Rule 1 - Bug)
|
||||||
|
**Impact on plan:** Required for the publish job to function at all. No scope creep. Security outcome (no plaintext PAT) unchanged.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
The GITEA_-prefix restriction was not documented in the plan or research notes; it was discovered empirically when the first publish run failed at docker login. The fix was straightforward once identified. No other issues encountered.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- Phase 8 (Gitea CI) is fully complete — all six ROADMAP success criteria met (see 08-VERIFICATION.md).
|
||||||
|
- CI-01 (PR regression: lint + typecheck + unit + API integration + mobile harness) delivered by plans 02 + 03.
|
||||||
|
- CI-02 (push-to-main publish) delivered by this plan (04).
|
||||||
|
- The Gitea registry now has a pullable `familysync-api:latest` image. Future phases can reference it for deployment documentation or smoke tests.
|
||||||
|
- Phase 9 (Faster Write-Back) is fully independent and can start immediately.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 08-gitea-ci*
|
||||||
|
*Completed: 2026-06-11*
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# Phase 8: Gitea CI — Verification
|
||||||
|
|
||||||
|
**Status: PASSED**
|
||||||
|
**Verified:** 2026-06-11
|
||||||
|
**Evidence basis:** Gitea Actions run log + Gitea Packages API inspection by operator
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase Goal
|
||||||
|
|
||||||
|
Every PR to `main` runs a full regression that gates the merge — lint, typecheck, unit, API-integration against a MariaDB service container, and the Phase 7 mobile Playwright harness as a UI-regression step — and a merge to `main` builds and publishes the API Docker image. All on the existing self-hosted Gitea Actions runner.
|
||||||
|
|
||||||
|
## Six-Criteria Evidence Table
|
||||||
|
|
||||||
|
| # | Success Criterion | Status | Evidence |
|
||||||
|
|---|-------------------|--------|----------|
|
||||||
|
| 1 | PR triggers lint + typecheck + unit + API-integration vs MariaDB service container; failing run blocks merge | **PASSED** | Runs #11 and #12: `fast-checks` (191s, lint no-op + tsc both apps + PWA vitest) and `api` (238s, MariaDB cold start + drizzle-kit migrate + DB-backed integration tests) both green. Run blocking enforced by Gitea branch protection on `main`. |
|
||||||
|
| 2 | API integration tests connect to service-container MariaDB (DB_HOST=127.0.0.1) and pass reliably on cold first run | **PASSED** | Run #11 cold start: MariaDB readiness wait (mysql2 loop) completed before migrate; squashed migration baseline (commit c0f892c) eliminated false drizzle-kit destructive diff; all API integration tests passed on first attempt. |
|
||||||
|
| 3 | PR workflow brings up dev stack (API + PWA dev servers + MariaDB, DEV_AUTH_BYPASS=true) and runs Phase 7 mobile Playwright harness headlessly; harness failure blocks merge | **PASSED** | Run #11: `harness` job — 58 specs across iphone/WebKit + pixel/Chromium — all green in 1.6 min. Four CI-specific infrastructure fixes applied (API-reap timeout, ipv4first/127.0.0.1 DNS, dev-user seed, direct test:e2e call). No Phase 7 harness files modified. |
|
||||||
|
| 4 | Harness step waits for both API and PWA dev servers before launching Playwright (no startup-race flake) | **PASSED** | mysql2 readiness loop (DB) → `:3000/health` poll (API) → global-setup `:5173` poll (PWA) — three sequential readiness gates before Playwright launches. No flake observed on cold or warm runs. |
|
||||||
|
| 5 | Merge to `main` builds and pushes API Docker image under a sensible tag | **PASSED** | Run #14 (push of merge commit 98acff8): `docker build --target production -f apps/api/Dockerfile .` succeeded; both tags pushed — `familysync-api:latest` and `familysync-api:v1.1-98acff8` — same digest `sha256:ce724852…`; confirmed present in Gitea Packages API. |
|
||||||
|
| 6 | Registry credentials never appear in plaintext in the CI logs | **PASSED** | Log audit of run #14: PAT masked as `***` throughout (Gitea secret scrubber); `--password-stdin` used exclusively (token piped via stdin); no `-p`/`--password` argument form anywhere; `docker logout` ran in `always()` cleanup. REGISTRY_PAT naming used (GITEA_ prefix excluded to avoid Gitea's silent secret-drop behavior). |
|
||||||
|
|
||||||
|
## Plans Delivering the Criteria
|
||||||
|
|
||||||
|
| Plan | Contribution |
|
||||||
|
|------|-------------|
|
||||||
|
| 08-01 | Runner probe — confirmed ubuntu-latest label, Docker executor (/.dockerenv), GITHUB_SHA availability, Playwright deps install cleanly |
|
||||||
|
| 08-02 | ci.yml: fast-checks job (lint, tsc, PWA vitest) + api job (MariaDB service, mysql2 readiness, drizzle-kit migrate, integration tests). Delivers criteria 1 + 2. |
|
||||||
|
| 08-03 | ci.yml: harness job (dev-stack bring-up, readiness waits, pnpm test:e2e). Delivers criteria 3 + 4. Four CI infrastructure fixes (no Phase 7 files modified). |
|
||||||
|
| 08-04 | ci.yml: publish job (docker login --password-stdin, build --target production from repo root, dual push :latest + :v1.1-<sha>, docker logout). Delivers criteria 5 + 6. |
|
||||||
|
|
||||||
|
## Key Fixes Applied During Phase 8 (CI-side only, no harness changes)
|
||||||
|
|
||||||
|
1. **squashed migration baseline** (commit c0f892c) — single `0000_baseline.sql` replaces the incremental migration history; eliminates the false drizzle-kit destructive diff that aborted the first cold CI run.
|
||||||
|
2. **API-reap + ipv4first** — `pkill -f "tsx watch"` reap guard + `--dns-result-order=ipv4first` flag ensures the API dev server binds on 127.0.0.1 (not ::1), matching the harness readiness poll.
|
||||||
|
3. **dev-user seed** — global-setup inserts the DEV_AUTH_BYPASS user (id=1) before Playwright launches, so the authed bypass session is valid on first spec.
|
||||||
|
4. **direct test:e2e** — `pnpm --filter @familysync/pwa test:e2e` called directly (not via Makefile) to avoid shell-expansion issues in the runner.
|
||||||
|
5. **REGISTRY_PAT naming** (commit 73eecf7) — Gitea runner silently drops secrets whose names begin with `GITEA_`; secret renamed from `GITEA_REGISTRY_PAT` to `REGISTRY_PAT`.
|
||||||
|
|
||||||
|
## Requirements Delivered
|
||||||
|
|
||||||
|
| REQ-ID | Description | Status |
|
||||||
|
|--------|-------------|--------|
|
||||||
|
| CI-01 | PR regression gates merge (lint + typecheck + unit + API-integration + mobile harness) | **Complete** |
|
||||||
|
| CI-02 | Push to main builds + publishes API Docker image | **Complete** |
|
||||||
|
|
||||||
|
## Phase 8 Outcome
|
||||||
|
|
||||||
|
Phase 8 is complete. The Gitea CI pipeline is fully operational on the self-hosted runner. Future merges to `main` will automatically run the full regression gate and publish a new image — no manual steps required.
|
||||||
Reference in New Issue
Block a user