---
phase: 09-testing-qa
plan: 03
type: execute
wave: 2
depends_on: ["09-01"]
files_modified:
- .gitea/workflows/ci.yml
autonomous: false
requirements:
- QA-07
must_haves:
truths:
- "CI pipeline YAML exists and is syntactically valid for Gitea Actions"
- "Pipeline stages enforce fail-fast: lint/type-check block unit tests, unit tests block E2E"
- "Pipeline includes backend tests (lint, type-check, pytest) and portal tests (build, E2E, Lighthouse)"
- "Test reports (JUnit XML, HTML) are uploaded as artifacts"
artifacts:
- path: ".gitea/workflows/ci.yml"
provides: "Complete CI pipeline for Gitea Actions"
contains: "playwright test"
key_links:
- from: ".gitea/workflows/ci.yml"
to: "packages/portal/playwright.config.ts"
via: "npx playwright test command"
pattern: "playwright test"
- from: ".gitea/workflows/ci.yml"
to: "packages/portal/e2e/lighthouse/lighthouserc.json"
via: "npx lhci autorun --config"
pattern: "lhci autorun"
---
Create the Gitea Actions CI pipeline that runs the full test suite (backend lint + type-check + pytest, portal build + E2E + Lighthouse) on every push and PR to main.
Purpose: Makes the test suite CI-ready so quality gates are enforced automatically, not just locally. Completes the beta-readiness quality infrastructure.
Output: .gitea/workflows/ci.yml with fail-fast stages and artifact uploads.
@/home/adelorenzo/.claude/get-shit-done/workflows/execute-plan.md
@/home/adelorenzo/.claude/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/09-testing-qa/09-CONTEXT.md
@.planning/phases/09-testing-qa/09-RESEARCH.md
@.planning/phases/09-testing-qa/09-01-SUMMARY.md
Depends on Plan 01 for: Playwright config and test files that CI will execute
Task 1: Create Gitea Actions CI workflow
.gitea/workflows/ci.yml
Create `.gitea/workflows/ci.yml` based on RESEARCH Pattern 7 with these specifics:
1. Triggers: push to main, pull_request to main
2. Job 1: `backend` (Backend Tests)
- runs-on: ubuntu-latest
- Service containers:
- postgres: pgvector/pgvector:pg16, env POSTGRES_DB/USER/PASSWORD, health-cmd pg_isready
- redis: redis:7-alpine, health-cmd "redis-cli ping"
- Env vars: DATABASE_URL (asyncpg to konstruct_app), DATABASE_ADMIN_URL (asyncpg to postgres), REDIS_URL
- Steps:
- actions/checkout@v4
- actions/setup-python@v5 python-version 3.12
- pip install uv
- uv sync
- uv run ruff check packages/ tests/
- uv run ruff format --check packages/ tests/
- uv run pytest tests/ -x --tb=short --junitxml=test-results.xml
- Upload test-results.xml as artifact (if: always())
3. Job 2: `portal` (Portal E2E) -- needs: backend
- runs-on: ubuntu-latest
- Service containers: same postgres + redis
- Steps:
- actions/checkout@v4
- actions/setup-node@v4 node-version 22
- actions/setup-python@v5 python-version 3.12 (for gateway)
- Install portal deps: `cd packages/portal && npm ci`
- Build portal: `cd packages/portal && npm run build` with NEXT_PUBLIC_API_URL env
- Copy standalone assets: `cd packages/portal && cp -r .next/static .next/standalone/.next/static && cp -r public .next/standalone/public`
- Install Playwright browsers: `cd packages/portal && npx playwright install --with-deps chromium firefox webkit`
- Start gateway (background):
```
pip install uv && uv sync
uv run alembic upgrade head
uv run python -c "from shared.db import seed_admin; import asyncio; asyncio.run(seed_admin())" || true
uv run uvicorn gateway.main:app --host 0.0.0.0 --port 8001 &
```
env: DATABASE_URL, DATABASE_ADMIN_URL, REDIS_URL, LLM_POOL_URL (http://localhost:8004)
- Wait for gateway: `timeout 30 bash -c 'until curl -sf http://localhost:8001/health; do sleep 1; done'`
- Run E2E tests: `cd packages/portal && npx playwright test e2e/flows/ e2e/accessibility/`
env: CI=true, PLAYWRIGHT_BASE_URL, API_URL, AUTH_SECRET, E2E_ADMIN_EMAIL, E2E_ADMIN_PASSWORD, E2E_CADMIN_EMAIL, E2E_CADMIN_PASSWORD, E2E_OPERATOR_EMAIL, E2E_OPERATOR_PASSWORD
(Use secrets for credentials: ${{ secrets.E2E_ADMIN_EMAIL }} etc.)
- Run Lighthouse CI: `cd packages/portal && npx lhci autorun --config=e2e/lighthouse/lighthouserc.json`
env: LHCI_BUILD_CONTEXT__CURRENT_HASH: ${{ github.sha }}
- Upload Playwright report (if: always()): actions/upload-artifact@v4, path packages/portal/playwright-report/
- Upload Playwright JUnit (if: always()): actions/upload-artifact@v4, path packages/portal/playwright-results.xml
- Upload Lighthouse report (if: always()): actions/upload-artifact@v4, path packages/portal/.lighthouseci/
IMPORTANT: Do NOT include mypy --strict step (existing codebase may not be fully strict-typed). Only include ruff check and ruff format --check for linting.
NOTE: The seed_admin call may not exist -- include `|| true` so it doesn't block. The E2E auth setup creates test users via the login form, so the admin user must already exist in the database. If there's a migration seed, it will handle this.
Pipeline target: < 5 minutes total.
test -f /home/adelorenzo/repos/konstruct/.gitea/workflows/ci.yml && python3 -c "import yaml; yaml.safe_load(open('/home/adelorenzo/repos/konstruct/.gitea/workflows/ci.yml'))" && echo "VALID YAML"
CI pipeline YAML exists at .gitea/workflows/ci.yml, is valid YAML, has 2 jobs (backend + portal), portal depends on backend (fail-fast), includes lint/format/pytest/E2E/Lighthouse/artifact-upload steps
Task 2: Verify test suite and CI pipeline
Complete E2E test suite (7 flow specs + accessibility + visual regression + Lighthouse CI) and Gitea Actions CI pipeline. Tests cover login, tenant CRUD, agent deployment, chat with mocked WebSocket, RBAC enforcement, i18n language switching, mobile viewport behavior, accessibility (axe-core), and visual regression at 3 viewports.
1. Run the full E2E test suite locally:
```
cd packages/portal
npx playwright test --project=chromium --reporter=list
```
Expected: All flow tests + accessibility tests pass
2. Run cross-browser:
```
npx playwright test e2e/flows/ --reporter=list
```
Expected: All tests pass on chromium, firefox, webkit
3. Check the Playwright HTML report:
```
npx playwright show-report
```
Expected: Opens browser with detailed test results
4. Review the CI pipeline:
```
cat .gitea/workflows/ci.yml
```
Expected: Valid YAML with backend job (lint + pytest) and portal job (build + E2E + Lighthouse), portal depends on backend
5. (Optional) Push a branch to trigger CI on git.oe74.net and verify pipeline runs
Type "approved" if tests pass and CI pipeline looks correct, or describe issues
1. `.gitea/workflows/ci.yml` exists and is valid YAML
2. Pipeline has 2 jobs: backend (lint + pytest) and portal (build + E2E + Lighthouse)
3. Portal job depends on backend job (fail-fast enforced)
4. Secrets referenced for credentials (not hardcoded)
5. Artifacts uploaded for test reports
- CI pipeline YAML is syntactically valid
- Pipeline stages enforce fail-fast ordering
- Backend job: ruff check + ruff format --check + pytest
- Portal job: npm build + Playwright E2E + Lighthouse CI
- Test reports uploaded as artifacts (JUnit XML, HTML, Lighthouse)
- Human approves test suite and pipeline structure