CI - Test & Build / Lint & Type Check (push) Canceled after 0s
CI - Test & Build / Backend Unit Tests (push) Canceled after 0s
CI - Test & Build / Frontend Build (push) Canceled after 0s
CI - Test & Build / Security Scan (push) Canceled after 0s
CI - Test & Build / E2E Tests (Playwright) (push) Canceled after 0s
CI - Test & Build / CI Summary (push) Canceled after 0s
* feat: move login credentials to a DB-backed users table with an admin management page Replaces the hardcoded AUTH_USERNAME/AUTH_PASSWORD login check with a new auth_accounts table (bcrypt-hashed passwords, admin/user roles). Adds admin-only /api/users CRUD routes and a "Brugere" admin page in the frontend for managing logins without redeploying. Removes the unused, unmounted duplicate login route in src/routes/auth.js. * docs: add architecture codemaps with diagrams for the whole system Adds codemaps/architecture.md, backend.md, frontend.md, and data.md — Mermaid-diagrammed design documentation verified against the live codebase and database rather than assumed from CLAUDE.md. Covers the unified-server.js request flow (mounted routers + ~183 inline routes), 68 backend services grouped by domain, the frontend's state-driven view-switch (no React Router in practice despite BrowserRouter being present), and the full 122-table DB schema with the auth_accounts vs unrelated users table naming trap flagged explicitly. Links added from the root README. Co-Authored-By: Claude Sonnet 5 <[email protected]> * feat: ship canonical roof quote workflow * fix: keep migration dry-run idempotent * [verified] feat: complete Smart Pakker management * [verified] fix: ignore blank task dependencies * [verified] fix: align package duplication with schema * [verified] fix: enforce Discord status limits * [verified] fix: link Smart Pakke materials safely * [verified] fix: harden material link review * [verified] feat: improve material matching * fix: scope pitch validation to roof packages * fix: support canonical snapshots on production schema * [verified] fix: hide internal package metadata from PDF * [verified] feat: deliver sales-ready customer PDF * [verified] feat: ship sales-ready PDF with AI overview * [verified] fix: authenticate project list requests * [verified] fix: refresh project-list authentication * [verified] fix: open existing project details * [verified] fix: keep roof components searchable in builder * [verified] fix: expose all Smart Package categories * [verified] fix: authenticate project creation * [verified] feat: make Smart Pakker the universal project flow * [verified] feat: preview Smart Package contents * [verified] test: keep generic release isolated from downpipe work * feat: add first-class Smart Pakke rentals * [verified] feat: add gutter and downpipe smart packages * [verified] fix: prepare six-house gutter quote flow * [verified] fix: open generic quotes without roof geometry * [verified] fix: review generic quotes with authenticated APIs * [verified] fix: calculate generic Smart Package quotes * [verified] fix: return generic calculation breakdown * feat: checkpoint generic signed snapshot validation with red-green tests * feat: complete fail-closed generic quote approval and customer PDF flow * feat: use generic signed snapshot in final review * feat: redesign generic quote final review * fix: harden generic review summaries * feat: add auditable six-house package basis * [verified] feat: finish auditable Smart Pakke UI * [verified] fix: bind auditable quantity and price bases * [verified] fix: keep six-house basis across package versions * [verified] fix: complete smart package discovery management * [verified] fix: simplify composition and generic scope * [verified] test: keep explicit roof contracts fail closed * [verified] fix: harden generic quote snapshots * fix: make generic quote delivery customer safe * [verified] fix: secure package catalog reads * [verified] fix: close workspace provenance blockers * fix: harden customer document language boundary * [verified] fix: secure smart package internal reads * fix: version package child mutations atomically * feat: add generic customer quote text flow * [verified] fix: allow manual customer numbers * [verified] fix: expose optional roof geometry * [verified] fix: rebase hydrated packages after geometry edits * [verified] feat: add free editable site area map * [verified] fix: harden map recovery and geocoding gate * fix: bind map quantities to authoritative geometry * fix: release geocoder lock before dispatch * fix: separate roof and site geometry provenance * fix: revoke stale admin authorization * fix: migrate task geometry basis * fix: make backend CI dependency-complete * ci: seed isolated e2e login account * fix: allow clean database bootstrap * fix: skip indexes for optional tables * test: use canonical mansard geometry in e2e * [verified] fix(auth): enforce live operator boundary * fix: fail close Ordrestyring offer transport * fix(frontend): authenticate customer project requests * fix: align canonical roof type contract * [verified] fix: reconcile legacy package labor safely * [verified] fix: audit site geometry deletion * docs: add PR 31 reviewer guide * docs: synchronize Obsidian vault * docs: sync integrated reviewer guide to Obsidian * ci: seed isolated auth account explicitly * fix: close offer bootstrap and service readiness gaps * fix: authenticate protected package callers * fix: provision initial admin and disable generic send * [verified] fix: close final quote release blockers * [verified] fix: seed gutter packages before deployment --------- Co-authored-by: alexpolo1 <[email protected]> Co-authored-by: Claude Sonnet 5 <[email protected]>
321 lines
9.0 KiB
YAML
321 lines
9.0 KiB
YAML
name: CI - Test & Build
|
|
|
|
on:
|
|
push:
|
|
branches: [ main, develop, 'feature/**', 'claude/**' ]
|
|
pull_request:
|
|
branches: [ main, develop ]
|
|
|
|
env:
|
|
NODE_VERSION: '22'
|
|
|
|
jobs:
|
|
# ============================================
|
|
# Lint & Type Check
|
|
# ============================================
|
|
lint:
|
|
name: Lint & Type Check
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install root dependencies
|
|
run: npm ci
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: frontend
|
|
run: npm ci
|
|
|
|
- name: Install backend dependencies
|
|
working-directory: backend
|
|
run: npm ci
|
|
|
|
- name: Run lint gate
|
|
run: npm run lint
|
|
|
|
# ============================================
|
|
# Backend Unit Tests
|
|
# ============================================
|
|
backend-tests:
|
|
name: Backend Unit Tests
|
|
runs-on: ubuntu-latest
|
|
services:
|
|
mariadb:
|
|
image: mariadb:10.11
|
|
env:
|
|
MYSQL_ROOT_PASSWORD: testpassword
|
|
MYSQL_DATABASE: tilbudgivern_test
|
|
MYSQL_USER: testuser
|
|
MYSQL_PASSWORD: testpassword
|
|
ports:
|
|
- 3306:3306
|
|
options: >-
|
|
--health-cmd="mysqladmin ping -h localhost"
|
|
--health-interval=10s
|
|
--health-timeout=5s
|
|
--health-retries=5
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install backend dependencies
|
|
working-directory: backend
|
|
run: npm ci
|
|
|
|
- name: Wait for MariaDB
|
|
run: |
|
|
while ! mysqladmin ping -h"127.0.0.1" --silent; do
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run backend tests
|
|
working-directory: backend
|
|
env:
|
|
DB_HOST: 127.0.0.1
|
|
DB_PORT: 3306
|
|
DB_USER: testuser
|
|
DB_PASSWORD: testpassword
|
|
DB_NAME: tilbudgivern_test
|
|
NODE_ENV: test
|
|
run: npm test -- --coverage --passWithNoTests
|
|
|
|
- name: Upload coverage report
|
|
uses: actions/upload-artifact@v7
|
|
if: always()
|
|
# Artifact upload must never fail the job (storage quota can be full)
|
|
continue-on-error: true
|
|
with:
|
|
name: backend-coverage
|
|
path: backend/coverage
|
|
retention-days: 3
|
|
|
|
# ============================================
|
|
# Frontend Build
|
|
# ============================================
|
|
frontend-build:
|
|
name: Frontend Build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: frontend
|
|
run: npm ci
|
|
|
|
- name: Build frontend
|
|
working-directory: frontend
|
|
env:
|
|
CI: false # Prevent treating warnings as errors
|
|
run: npm run build
|
|
|
|
- name: Upload frontend build artifact
|
|
uses: actions/upload-artifact@v7
|
|
# Artifact upload must never fail the job (storage quota can be full)
|
|
continue-on-error: true
|
|
with:
|
|
name: frontend-build
|
|
path: frontend/build
|
|
retention-days: 3
|
|
|
|
# ============================================
|
|
# E2E Tests (Playwright)
|
|
# ============================================
|
|
e2e-tests:
|
|
name: E2E Tests (Playwright)
|
|
runs-on: ubuntu-latest
|
|
needs: [frontend-build, backend-tests]
|
|
if: github.event_name == 'pull_request'
|
|
services:
|
|
mariadb:
|
|
image: mariadb:10.11
|
|
env:
|
|
MYSQL_ROOT_PASSWORD: testpassword
|
|
MYSQL_DATABASE: tilbudgivern_test
|
|
MYSQL_USER: testuser
|
|
MYSQL_PASSWORD: testpassword
|
|
ports:
|
|
- 3306:3306
|
|
options: >-
|
|
--health-cmd="mysqladmin ping -h localhost"
|
|
--health-interval=10s
|
|
--health-timeout=5s
|
|
--health-retries=5
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
npm ci
|
|
cd frontend && npm ci
|
|
cd ../backend && npm ci
|
|
cd ../tests && npm ci
|
|
|
|
# Build in-job instead of downloading the frontend-build artifact -
|
|
# artifact upload is best-effort and can be skipped on full quota
|
|
- name: Build frontend
|
|
working-directory: frontend
|
|
env:
|
|
CI: false
|
|
run: npm run build
|
|
|
|
- name: Install Playwright browsers
|
|
working-directory: tests
|
|
run: npx playwright install --with-deps chromium
|
|
|
|
- name: Wait for MariaDB
|
|
run: |
|
|
while ! mysqladmin ping -h"127.0.0.1" --silent; do
|
|
sleep 1
|
|
done
|
|
|
|
- name: Seed isolated CI login account
|
|
env:
|
|
DB_HOST: 127.0.0.1
|
|
DB_PORT: 3306
|
|
DB_USER: testuser
|
|
DB_PASSWORD: testpassword
|
|
DB_NAME: tilbudgivern_test
|
|
NODE_ENV: test
|
|
CI: true
|
|
AUTH_USERNAME: ci-test-user
|
|
AUTH_PASSWORD: ci-test-password
|
|
run: |
|
|
node database/migrations/20260904_users_table.js
|
|
node backend/scripts/seed-ci-auth-account.js
|
|
|
|
- name: Start server
|
|
env:
|
|
DB_HOST: 127.0.0.1
|
|
DB_PORT: 3306
|
|
DB_USER: testuser
|
|
DB_PASSWORD: testpassword
|
|
DB_NAME: tilbudgivern_test
|
|
PORT: 4032
|
|
NODE_ENV: test
|
|
JWT_ACCESS_SECRET: ci-only-access-secret-not-for-production
|
|
JWT_REFRESH_SECRET: ci-only-refresh-secret-not-for-production
|
|
AUTH_USERNAME: ci-test-user
|
|
AUTH_PASSWORD: ci-test-password
|
|
ORDRESTYRING_API_TOKEN: ci-test-token-no-network-use
|
|
ORDRESTYRING_AUTO_SYNC_DISABLED: true
|
|
run: |
|
|
cd backend && node unified-server.js &
|
|
sleep 10
|
|
curl -f http://localhost:4032/api/health || exit 1
|
|
|
|
- name: Run blocking carpenter smoke test
|
|
working-directory: tests
|
|
env:
|
|
PLAYWRIGHT_BASE_URL: http://localhost:4032
|
|
PLAYWRIGHT_USERNAME: ci-test-user
|
|
PLAYWRIGHT_PASSWORD: ci-test-password
|
|
run: npx playwright test full-roof-quote-flow.spec.js --project=chromium --reporter=list
|
|
|
|
- name: Run extended Playwright tests
|
|
working-directory: tests
|
|
env:
|
|
PLAYWRIGHT_BASE_URL: http://localhost:4032
|
|
PLAYWRIGHT_USERNAME: ci-test-user
|
|
PLAYWRIGHT_PASSWORD: ci-test-password
|
|
run: npx playwright test --project=chromium --reporter=html --grep-invert "full carpenter roof quote smoke flow"
|
|
continue-on-error: true
|
|
|
|
- name: Upload Playwright report
|
|
uses: actions/upload-artifact@v7
|
|
if: always()
|
|
continue-on-error: true
|
|
with:
|
|
name: playwright-report
|
|
path: tests/playwright-report
|
|
retention-days: 3
|
|
|
|
- name: Upload Playwright screenshots
|
|
uses: actions/upload-artifact@v7
|
|
if: failure()
|
|
continue-on-error: true
|
|
with:
|
|
name: playwright-screenshots
|
|
path: tests/test-results
|
|
retention-days: 3
|
|
|
|
# ============================================
|
|
# Security Scan
|
|
# ============================================
|
|
security-scan:
|
|
name: Security Scan
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
npm ci
|
|
cd frontend && npm ci
|
|
cd ../backend && npm ci
|
|
|
|
- name: Run npm audit (frontend)
|
|
working-directory: frontend
|
|
run: npm audit --audit-level=high
|
|
continue-on-error: true
|
|
|
|
- name: Run npm audit (backend)
|
|
working-directory: backend
|
|
run: npm audit --audit-level=high
|
|
continue-on-error: true
|
|
|
|
# ============================================
|
|
# Summary Job
|
|
# ============================================
|
|
ci-summary:
|
|
name: CI Summary
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, backend-tests, frontend-build, security-scan, e2e-tests]
|
|
if: always()
|
|
steps:
|
|
- name: Check CI status
|
|
run: |
|
|
if [[ "${{ needs.lint.result }}" == "failure" ]] || \
|
|
[[ "${{ needs.backend-tests.result }}" == "failure" ]] || \
|
|
[[ "${{ needs.frontend-build.result }}" == "failure" ]] || \
|
|
[[ "${{ needs.e2e-tests.result }}" == "failure" ]]; then
|
|
echo "CI failed!"
|
|
exit 1
|
|
fi
|
|
echo "CI passed successfully!"
|