Skip to content

EPIC-05: Budget Management — promote to stable#160

Merged
steilerDev merged 69 commits into
mainfrom
beta
Feb 23, 2026
Merged

EPIC-05: Budget Management — promote to stable#160
steilerDev merged 69 commits into
mainfrom
beta

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

@steilerDev steilerDev commented Feb 20, 2026

Summary

Promotes EPIC-05 (Budget Management) from beta to main for stable release.

Stories Completed (12/12)

# Story PR
#142 5.1: Budget Categories CRUD #150
#143 5.2: Vendor Management #151
#144 5.3: Invoice Tracking #152
#145 5.4: Budget Sources (Financing) #153
#146 5.5: Subsidy Programs #154
#147 5.6: Work Item Budget Properties #156
#148 5.7: Budget Overview Dashboard #157
#149 5.8: Budget Navigation & Polish #158
#183 5.9: Schema Migration + Budget Lines CRUD API #187
#184 5.10: Update Dependent Services #187
#185 5.11: Budget Overview Rework (Blended Projected Model) #192
#186 5.12: Frontend Rework #193

Refinement: PR #159

Additional Fix/Improvement PRs

PR Description
#163 fix(e2e): update budget page heading selectors
#166 fix(e2e): resolve 220 test failures
#171 fix(work-items): reduce vendor pageSize from 500 to 100
#172 test(e2e): add full page coverage for 11 uncovered pages
#173 fix(e2e): correct API response shape parsing
#174 fix(e2e): resolve POM locator mismatches
#176 fix(e2e): resolve modal backdrop click and WebKit timeout failures
#177 fix(budget): unwrap server response wrappers in API client
#178-#181 fix(e2e): various vendor detail and timeout fixes
#188 fix(e2e): update E2E tests for budget lines rework
#189 fix(budget): fix 4 budget overview bugs
#195 feat(budget): redesign overview with hero bar + category filter
#196 fix(test): resolve CI test flakiness
#197 feat(budget): invoice-aware budget calculations
#201 fix(budget): surface budget line deletion errors
#202 fix(budget): fix invoice edit modal + add invoice popover
#203 feat(invoices): standalone invoices view
#207 fix(e2e): improve robustness of flaky tablet/mobile tests
#208 fix(budget): fix invoice/work-item cross-linking
#209 ci: path-based change detection
#211-#213 chore/fix: worktree config, pre-commit, financing source depletion
#214 docs: budget management guides

Features

  • Budget Categories: 10 seeded categories with CRUD, color swatches, sort ordering
  • Vendor Management: Paginated list with search, detail pages, contact info, specialty
  • Invoice Tracking: Full lifecycle (pending/paid/claimed) with line items linked to budget lines
  • Financing Sources: Track sources with total amounts and actual invoice-based depletion
  • Subsidy Programs: Percentage or fixed reductions, application status, category eligibility
  • Work Item Budget Lines: Per-work-item lines connecting category + source with confidence levels (Own Estimate ±20%, Professional Estimate ±10%, Quote ±5%, Invoice ±0%)
  • Budget Overview Dashboard: Blended projected model, 4 remaining-budget perspectives, hero bar, category breakdown with filter, financing source summary, subsidy impact
  • Standalone Invoices Page: Browse all invoices with status filtering
  • Budget Sub-Navigation: Horizontal tabs, consistent EUR formatting

Database Migrations

  • 0003: Creates 8 tables (budget_categories, vendors, invoices, budget_sources, subsidy_programs, subsidy_program_categories, work_item_vendors, work_item_subsidies)
  • 0004: Adds budget columns to work_items
  • 0005: Budget rework — adds work_item_budgets, invoice_lines; drops flat budget fields

Test Coverage

  • 845+ E2E tests (desktop, tablet, mobile)
  • Comprehensive unit + integration suites for all budget services
  • All quality gates pass

Documentation

steilerDev and others added 13 commits February 19, 2026 21:59
chore: merge-back v1.8.0 (main → beta)
Add version, CI, and Docker badges. Consolidate the features section
by grouping work item properties (tags, notes, subtasks, dependencies)
under a single Work Items heading and separating list view capabilities.
Rename Application Shell and Design System sections to user-friendly
Appearance and Infrastructure headings. Replace the redundant Planned
Features bullet list with a concise Coming Soon paragraph. Normalize
bold item casing to sentence case for consistency.

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@v4...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#150)

* feat(budget): implement budget categories CRUD endpoints (Story #142)

Implements the foundation for EPIC-05 (Budget Management) with:

- SQL migration (0003_create_budget_tables.sql) creating all 8 budget
  tables: budget_categories, vendors, invoices, budget_sources,
  subsidy_programs, and junction tables work_item_vendors,
  work_item_subsidies, subsidy_program_categories. Includes 10 seeded
  default budget categories (Materials, Labor, Permits, etc.).

- Drizzle ORM schema additions for all 8 new tables with correct types
  (real for monetary fields), indexes, and FK relationships.

- Shared types in @cornerstone/shared: BudgetCategory entity,
  CreateBudgetCategoryRequest, UpdateBudgetCategoryRequest,
  BudgetCategoryListResponse, BudgetCategoryResponse.

- CATEGORY_IN_USE error code added to shared ErrorCode union and
  CategoryInUseError class added to AppError.

- budgetCategoryService with getAll, getById, create, update, and
  delete methods. Create/update enforce case-insensitive name
  uniqueness. Delete checks for subsidy program references (409 if
  in-use) with details payload.

- budgetCategories route handler implementing all 5 endpoints:
  GET/POST /api/budget-categories and GET/PATCH/DELETE
  /api/budget-categories/:id with JSON schema validation.

- Route registered in app.ts at prefix /api/budget-categories.

Fixes #142

Co-Authored-By: Claude backend-developer (Sonnet 4.5) <noreply@anthropic.com>

* feat(budget): implement budget categories management UI (Story #142)

- Add budgetCategoriesApi.ts with typed client functions (fetch, create, update, delete)
- Add BudgetCategoriesPage with inline create/edit forms, color swatch, sort order,
  delete confirmation modal with 409 in-use error handling, loading/error/empty states
- Update App.tsx: replace BudgetPage placeholder with nested /budget routes;
  /budget redirects to /budget/categories; BudgetCategoriesPage at /budget/categories
- Update Sidebar: rename "Budget" link to "Budget Categories", update href to
  /budget/categories (active state matches sub-paths automatically)
- Update Sidebar.test.tsx and App.test.tsx to reflect navigation change
  (trivial test fixes required due to route/label change)

Fixes #142

Co-Authored-By: Claude frontend-developer (Sonnet 4.5) <noreply@anthropic.com>

* test(budget): add unit, integration, and E2E tests for budget categories

- 62 service unit tests for budgetCategoryService (CRUD + validation)
- 39 route integration tests for /api/budget-categories
- 21 schema tests for all 8 new budget tables
- 18 API client tests for budgetCategoriesApi
- 41 component tests for BudgetCategoriesPage
- 38 Playwright E2E tests with BudgetCategoriesPage POM

Fixes #142

Co-Authored-By: Claude qa-integration-tester (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude e2e-test-engineer (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
* feat(budget): implement vendor management API endpoints (Story #143)

- Add vendor shared types (Vendor, VendorDetail, CRUD request/response)
- Add VENDOR_IN_USE error code
- Implement vendorService with paginated list, search, CRUD, invoice stats
- Implement vendor routes (GET/POST/PATCH/DELETE /api/vendors)
- Outstanding balance computed from pending+overdue invoices

Co-Authored-By: Claude backend-developer (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude product-architect (Opus 4.6) <noreply@anthropic.com>

* feat(vendors): implement vendor/contractor management UI (Story #143)

Add complete frontend for vendor management including:
- Typed API client (vendorsApi.ts) matching GET/POST/PATCH/DELETE /api/vendors
- VendorsPage: paginated list with search, desktop table, mobile cards,
  create modal, delete with 409 conflict handling, empty states
- VendorDetailPage: breadcrumb navigation, stats cards (invoice count,
  outstanding balance with Intl.NumberFormat), inline editing, delete
  confirmation, invoices placeholder section
- Routes /budget/vendors and /budget/vendors/:id registered in App.tsx
- "Vendors" NavLink added to Sidebar (adjacent to Budget Categories)
- Sidebar.test.tsx link count updated from 10 to 11

Fixes #143

Co-Authored-By: Claude frontend-developer (Sonnet 4.6) <noreply@anthropic.com>

* test(e2e): add Playwright E2E tests for vendor/contractor management (Story #143)

Coverage for all automated UAT scenarios on /budget/vendors and /budget/vendors/:id:
- Scenario 1: Empty state (no vendors, search no-match)
- Scenario 2: Create vendor — full details (happy path)
- Scenario 3: Create vendor — name only (minimal required fields)
- Scenario 4: Create validation — disabled submit when name empty, cancel cancels
- Scenario 5: View vendor detail page — all fields, stats, invoices placeholder
- Scenario 6: Edit vendor details — phone/notes persist; cancel restores; empty name guard
- Scenario 8: Delete no-reference vendor — modal confirms name; list updated
- Scenario 9: Delete blocked (409) — error shown in modal; confirm button hidden
- Scenario 11: Pagination — controls visible when totalPages > 1; hidden on single page
- Scenario 12: Search by name (case-insensitive, URL param synced)
- Scenario 13: Search by specialty
- Scenario 14: Table shows scannable key info (name, specialty, phone, email, columns)
- Navigation: vendor → detail → breadcrumb back to list
- Scenario 17: Responsive layout — no horizontal scroll; mobile cards vs desktop table
- Dark mode: list, detail, modal all render without layout breakage

New files:
- e2e/pages/VendorsPage.ts (POM for /budget/vendors)
- e2e/pages/VendorDetailPage.ts (POM for /budget/vendors/:id)
- e2e/tests/budget/vendors.spec.ts (38 tests across 12 describe groups)
- e2e/fixtures/testData.ts (added budgetVendors route + vendors API endpoint)

Fixes #143

Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <noreply@anthropic.com>

* test(vendors): add unit and integration tests for Story #143 vendor management

Adds 230 tests across 5 test files covering the complete vendor/contractor
management feature: service layer, API routes, API client, and both React pages.

- server/src/services/vendorService.test.ts (75 tests)
  listVendors: pagination, search, sorting, LIKE wildcard escaping
  getVendorById: found/not found, invoice stats, createdBy resolution
  createVendor: success, all fields, trimming, validation errors
  updateVendor: partial update, null clearing, updatedAt refresh, validation
  deleteVendor: success, not found, VendorInUseError (invoices + work items)

- server/src/routes/vendors.test.ts (44 tests)
  GET/POST/GET:id/PATCH/DELETE endpoints; auth (401), 404, 409, validation (400)
  All routes verify auth-required and member access

- client/src/lib/vendorsApi.test.ts (27 tests)
  fetchVendors: query string params, search/sort/page, response parsing
  fetchVendor/createVendor/updateVendor/deleteVendor: request/response, errors

- client/src/pages/VendorsPage/VendorsPage.test.tsx (42 tests)
  Loading, empty state, search-empty state, vendor list, pagination, sort controls
  Create modal: field validation, success/error flows
  Delete modal: 409 VENDOR_IN_USE, confirm button hiding after error

- client/src/pages/VendorDetailPage/VendorDetailPage.test.tsx (42 tests)
  Loading, error (404/500/network), vendor detail display, stats, links
  Edit mode: pre-fill, validation, save/cancel, error handling
  Delete modal: VENDOR_IN_USE (409), confirm button hiding, navigation

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <noreply@anthropic.com>

* style(vendors): format test files

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
* feat(shared): add invoice types for Story #144

Add shared TypeScript types for invoice CRUD operations:
- Invoice, InvoiceStatus, CreateInvoiceRequest, UpdateInvoiceRequest
- InvoiceListResponse, InvoiceResponse wrapper types
- Exported from @cornerstone/shared index

Invoices are nested under vendors (/api/vendors/:vendorId/invoices)
with 3 statuses: pending, paid, overdue.

Co-Authored-By: Claude product-architect (Opus 4.6) <noreply@anthropic.com>

* feat(budget): implement invoice CRUD API endpoints (Story #144)

- Add invoiceService with list, create, update, delete operations
- Vendor ownership enforced on all invoice operations
- Date validation (ISO format, dueDate >= date)
- Amount validation (> 0)
- Invoice routes nested under /api/vendors/:vendorId/invoices
- Register invoice routes in app.ts

Co-Authored-By: Claude backend-developer (Opus 4.6) <noreply@anthropic.com>

* chore: add Docker cagent agent.yaml configuration

Convert the 10 Claude Code agent definitions (.claude/agents/*.md) to
Docker's cagent YAML format with an additional root orchestrator agent.
The existing .claude/agents/ files are retained for Claude Code
compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(invoices): implement invoice management UI for vendor detail page (Story #144)

- Add invoicesApi.ts with fetchInvoices, createInvoice, updateInvoice, deleteInvoice
- Replace "coming soon" placeholder on VendorDetailPage with full invoice section:
  - Invoice table (desktop) with Invoice #, Amount, Date, Due Date, Status badge, Actions
  - Invoice card list (mobile) hidden on desktop via CSS media query
  - Status badges: paid (green), pending (gray), overdue (red)
  - Outstanding balance display (pending + overdue amounts)
  - Add Invoice modal with full form (number, amount, date, due date, status, notes)
  - Edit Invoice modal pre-filled from selected row
  - Delete Invoice confirmation modal
  - Loading, error (with Retry), and empty states
  - Re-fetches vendor stats after create/update/delete to sync stats cards
- Add select element styles and invoice-specific tokens to VendorDetailPage.module.css
- No hardcoded hex values; all colors use design system tokens

Note: VendorDetailPage.test.tsx "coming soon" test needs QA update to mock invoicesApi
and verify the new invoice section behavior.

Fixes #144

Co-Authored-By: Claude frontend-developer (Sonnet 4.6) <noreply@anthropic.com>

* test(invoices): add unit and integration tests for Story #144 invoice management

Add comprehensive test coverage for the invoice management feature:

- server/src/services/invoiceService.test.ts (53 tests): Unit tests for all
  service methods — listInvoices, createInvoice, updateInvoice, deleteInvoice.
  Covers vendor-not-found checks, amount validation (>0), date/dueDate format
  validation, ownership checks (invoice must belong to the given vendor), and
  partial updates.

- server/src/routes/invoices.test.ts (42 tests): Integration tests using
  app.inject() for all four routes (GET, POST, PATCH, DELETE). Covers auth
  requirements, 404 vendor/invoice-not-found, ownership mismatch, schema
  validation (exclusiveMinimum, enum, minProperties), and member access.

- client/src/lib/invoicesApi.test.ts (30 tests): API client unit tests for
  fetchInvoices, createInvoice, updateInvoice, deleteInvoice. Covers request
  URL construction, envelope unwrapping, and error propagation.

- client/src/pages/VendorDetailPage/VendorDetailPage.test.tsx: Updated to
  replace "coming soon" placeholder tests with 39 new invoice section tests
  covering: list rendering, status badges, outstanding balance calculation,
  empty state, error state with retry, create modal (open/close/submit/error),
  edit modal (pre-fill/save/error), and delete modal (confirm/error/hide-button).

Total test count: 1555 → 1725 (+170 tests), 66 → 69 suites.

Fixes #144

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* chore: remove spurious agent.yaml

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

* style: format test files for invoice management

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
* feat(budget): implement budget sources CRUD endpoints (Story #145)

Add complete backend for budget financing sources management:
- shared types: BudgetSource, BudgetSourceType/Status, CRUD request/response shapes
- service: listBudgetSources, getBudgetSourceById, createBudgetSource,
  updateBudgetSource, deleteBudgetSource with computed usedAmount/availableAmount
- routes: GET/POST /api/budget-sources, GET/PATCH/DELETE /api/budget-sources/:id
- BudgetSourceInUseError (BUDGET_SOURCE_IN_USE, 409) for future work item linkage
- usedAmount is 0 until Story 6 adds budget_source_id FK to work_items

Fixes #145

Co-Authored-By: Claude backend-developer (Sonnet 4.6) <noreply@anthropic.com>

* feat(budget): implement budget sources management UI (Story #145)

- Add budgetSourcesApi.ts: typed API client for all CRUD operations
- Add BudgetSourcesPage with inline CRUD pattern (list, create, edit, delete)
  - Source type badges: Bank Loan (blue), Credit Line (gray), Savings (green), Other (neutral)
  - Status badges: Active (green), Exhausted (gray), Closed (gray)
  - Currency formatting ($X,XXX.XX) and percentage formatting (X.XX%) for rates
  - Delete confirmation modal with 409 conflict handling
  - Full responsive layout (mobile stack, tablet touch targets)
  - All values via CSS tokens; zero hardcoded hex colors
- Register /budget/sources route in App.tsx
- Add "Budget Sources" NavLink in Sidebar (budget section)
- Update Sidebar and AppShell tests for new link count (11 nav + 1 footer)

Fixes #145

Co-Authored-By: Claude frontend-developer (Sonnet 4.5) <noreply@anthropic.com>

* test(budget-sources): add unit and integration tests for Story #145

Adds 202 tests across 4 test files covering the budget source management
feature end-to-end.

- server/src/services/budgetSourceService.test.ts: 65 unit tests for
  listBudgetSources, getBudgetSourceById, createBudgetSource (all
  validation paths), updateBudgetSource (partial/full updates), and
  deleteBudgetSource. Service coverage: 98.66% statements, 100% functions.

- server/src/routes/budgetSources.test.ts: 57 integration tests using
  app.inject() covering all 5 endpoints (GET list, POST, GET by ID,
  PATCH, DELETE), 401 auth checks, validation errors, 404s, and member
  vs admin access.

- client/src/lib/budgetSourcesApi.test.ts: 29 API client tests for all
  5 functions (fetchBudgetSources, fetchBudgetSource, createBudgetSource,
  updateBudgetSource, deleteBudgetSource) with mock fetch verification
  and error propagation. API client coverage: 100%.

- client/src/pages/BudgetSourcesPage/BudgetSourcesPage.test.tsx: 51
  component tests covering loading state, empty state, list display
  (type/status badges, currency formatting, interest rate %), create
  form (validation, success/error paths), inline edit form
  (pre-fill, save/cancel, error handling), delete confirmation modal
  (in-use 409 handling, success removal), and success message behavior.

Fixes #145

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* style: format budget source test files

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
* feat(budget): implement subsidy program management endpoints (Story #146)

Add complete CRUD for subsidy programs with category linkage support.

- Add SubsidyProgram, SubsidyReductionType, SubsidyApplicationStatus types to @cornerstone/shared
- Add CreateSubsidyProgramRequest and UpdateSubsidyProgramRequest interfaces
- Add SubsidyProgramListResponse and SubsidyProgramResponse types
- Add SUBSIDY_PROGRAM_IN_USE error code to shared errors.ts
- Add SubsidyProgramInUseError (409) to server AppError.ts
- Implement subsidyProgramService: listSubsidyPrograms, getSubsidyProgramById,
  createSubsidyProgram (with categoryIds validation), updateSubsidyProgram
  (replace category links when categoryIds provided), deleteSubsidyProgram
  (blocks deletion if referenced by work_item_subsidies)
- Implement subsidyPrograms routes: GET /api/subsidy-programs, POST (201),
  GET /:id, PATCH /:id, DELETE /:id (204 or 409)
- Register /api/subsidy-programs prefix in app.ts

Fixes #146

Co-Authored-By: Claude backend-developer (Sonnet 4.5) <noreply@anthropic.com>

* feat(budget): implement subsidy program management UI (Story #146)

Add SubsidyProgramsPage with full inline CRUD following the BudgetSourcesPage
pattern. Includes status badges (eligible/applied/approved/received/rejected),
reduction display (percentage or fixed currency amount), category multi-select
checkboxes, deadline picker, and 409-aware delete confirmation modal.

- client/src/lib/subsidyProgramsApi.ts — typed API client for /api/subsidy-programs
- client/src/pages/SubsidyProgramsPage/ — page component + CSS module (zero hardcoded hex)
- client/src/App.tsx — adds /budget/subsidies route (lazy-loaded)
- client/src/components/Sidebar/Sidebar.tsx — adds Subsidies nav link in budget section
- client/src/components/Sidebar/Sidebar.test.tsx — update link count 12→13 (nav) + 1 GitHub

Fixes #146

Co-Authored-By: Claude frontend-developer (Sonnet 4.6) <noreply@anthropic.com>

* test(subsidy-programs): add unit and integration tests for Story #146

Add 228 tests covering subsidyProgramService, subsidyPrograms routes,
subsidyProgramsApi client, and SubsidyProgramsPage component. Achieves
95%+ coverage across all new code introduced in Story #146.

Fixes #146

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <noreply@anthropic.com>

* style: format subsidy program test files

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
* feat(budget): add budget properties to work items (Story #147)

- Migration 0004: adds planned_budget, actual_cost, confidence_percent,
  budget_category_id, budget_source_id columns to work_items table
- Drizzle schema updated with 5 new columns and FK references to
  budget_categories and budget_sources
- WorkItem shared types updated: WorkItemDetail, CreateWorkItemRequest,
  UpdateWorkItemRequest all include the new budget fields
- workItemService: validates and persists budget fields on create/update,
  returns them in all responses; validates FK references exist
- workItems routes: JSON schemas updated for create and PATCH endpoints
- New workItemVendorService + workItemVendors routes:
  GET/POST/DELETE /api/work-items/:workItemId/vendors
- New workItemSubsidyService + workItemSubsidies routes:
  GET/POST/DELETE /api/work-items/:workItemId/subsidies
- budgetSourceService: computeUsedAmount now queries work_items.actual_cost
  where budget_source_id matches; deleteBudgetSource enforces FK constraint
- budgetCategoryService: deleteBudgetCategory now checks work item references
- Client test fixtures updated to include new required WorkItemDetail fields

Fixes #147

Co-Authored-By: Claude backend-developer (Sonnet 4.5) <noreply@anthropic.com>

* feat(work-items): add budget properties UI for Story #147

- Add vendor/subsidy linking API functions to workItemsApi.ts
  (fetchWorkItemVendors, linkWorkItemVendor, unlinkWorkItemVendor,
  fetchWorkItemSubsidies, linkWorkItemSubsidy, unlinkWorkItemSubsidy)
- WorkItemDetailPage: add Budget section with inline edit for
  plannedBudget, actualCost, confidencePercent, budgetCategoryId,
  budgetSourceId; linked vendors and subsidy programs with add/remove
  controls; net cost display after subsidy reductions
- WorkItemCreatePage: add Budget section to the create form with all
  5 budget fields and validation
- CSS: confidence badge (green/yellow/red), linked item chips, link
  picker rows, net cost row — all using design tokens only
- Update test mocks to include all new API modules

Fixes #147

Co-Authored-By: Claude frontend-developer (Sonnet 4.5) <noreply@anthropic.com>

* test(budget): add unit and integration tests for Story #147 work item budget properties

- workItemVendorService.test.ts: 20 unit tests covering list, link, unlink, 404/409 errors
- workItemSubsidyService.test.ts: 21 unit tests covering list, link, unlink, 404/409 errors
- workItemVendors.test.ts: 17 route integration tests (GET/POST/DELETE, auth, validation, 404/409)
- workItemSubsidies.test.ts: 17 route integration tests (GET/POST/DELETE, auth, validation, 404/409)
- workItemService.test.ts: +34 tests for new budget fields (plannedBudget, actualCost,
  confidencePercent, budgetCategoryId, budgetSourceId) on createWorkItem and updateWorkItem;
  added budget category/source helpers
- budgetSourceService.test.ts: +12 tests for computeUsedAmount (sums work item actualCost),
  deleteBudgetSource blocking when work items reference source; updated Story 6 placeholders
- workItemsApi.test.ts: +18 client tests for fetchWorkItemVendors, linkWorkItemVendor,
  unlinkWorkItemVendor, fetchWorkItemSubsidies, linkWorkItemSubsidy, unlinkWorkItemSubsidy

Total: 2289 tests passing, 81 suites

Also filed GitHub Issue #155: fetchWorkItemSubsidies reads wrong response key
(route sends 'subsidies', client reads 'subsidyPrograms')

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* fix(budget): fix subsidy API client response key mismatch

The fetchWorkItemSubsidies client function expected { subsidyPrograms }
but the server sends { subsidies }. Fixed to match the server response.

Also formats test files.

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

* fix(budget): update subsidy API test to match corrected response key

Tests now use { subsidies: [...] } matching the server response
and the fixed client code.

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
* feat(budget): implement budget overview dashboard endpoint (Story #148)

Add GET /api/budget/overview aggregation endpoint that returns project-level
budget totals, per-category summaries, financing source usage, vendor payment
totals, and subsidy reduction estimates in a single response.

- shared/src/types/budgetOverview.ts: CategoryBudgetSummary, BudgetOverview,
  BudgetOverviewResponse interfaces
- server/src/services/budgetOverviewService.ts: getBudgetOverview() using
  raw SQL aggregations via Drizzle sql`` tagged template
- server/src/routes/budgetOverview.ts: GET /overview route, auth required
- server/src/app.ts: register budgetOverviewRoutes at /api/budget prefix

Fixes #148

Co-Authored-By: Claude backend-developer (Sonnet 4.5) <noreply@anthropic.com>

* feat(budget): budget overview dashboard page and tests (Story #148)

- BudgetOverviewPage with 4 summary cards (total budget, financing,
  vendors, subsidies) and category breakdown table
- Responsive layout: 4-col desktop, 2-col tablet, 1-col mobile
- Empty state, loading state, and error handling with retry
- Budget overview API client (fetchBudgetOverview)
- Route at /budget/overview, budget index redirects to overview
- Sidebar link for Budget Overview
- 99 tests: service (55), routes (13), API client (12), component (19)

Fixes #148

Co-Authored-By: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
…h (Story #149) (#158)

Implements Story #149: Budget sub-navigation tabs, currency formatting
consistency, and general budget section polish.

Key changes:
- New BudgetSubNav component: horizontal tab bar for the five budget
  sub-pages (Overview, Categories, Vendors, Sources, Subsidies). Uses
  NavLink with end prop so each tab highlights only its exact path.
  Scrolls horizontally on mobile. Fully token-based styling.
- Shared formatters.ts utility: formatCurrency(amount) (EUR, 2 dp)
  and formatPercent(rate) extracted to client/src/lib/formatters.ts
  so every budget page produces identical output. Replaces four separate
  local implementations that used USD or different locale strings.
- Integrated BudgetSubNav into all five budget section pages. Each page
  now shows a shared Budget h1 plus a section-level h2 (e.g. Categories,
  Sources). Loading and error states also render the sub-nav so the tab
  bar is always visible.
- Consolidated sidebar budget links: five individual links collapsed into
  a single Budget NavLink pointing to /budget (no end, so it stays active
  across all budget sub-paths). VendorDetailPage remains outside sub-nav.
- Added sectionHeader/sectionTitle CSS rules with mobile stacking to
  BudgetCategoriesPage, VendorsPage, BudgetSourcesPage, SubsidyProgramsPage.
- Updated affected test files to reflect new h1/h2 heading structure and
  EUR currency symbols to keep CI green.

All quality gates pass: lint (0 errors), format:check, typecheck,
2388 tests, npm audit --omit=dev (0 vulns).

Fixes #149

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
)

- Fix 409 error message to mention both invoices and work items (VendorDetailPage + VendorsPage)
- Add :focus-visible ring to .contactLink in VendorsPage
- Correct search placeholder to match actual backend search scope (name/specialty only)
- Always render Notes row in VendorDetailPage info list, showing "—" when null
- Change .pageTitle from font-size-4xl to font-size-3xl in VendorDetailPage
- Convert breadcrumb back-link from <button> to <Link> for proper semantics
- Add :focus-visible ring to .infoLink in VendorDetailPage
- Change .secondaryButton, .cancelButton, .sortOrderButton :hover to use
  --color-bg-hover instead of --color-border for better dark mode contrast
- Update test assertions to match new error message text and link role

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.9 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Remove 4 low-value agents (uat-validator, docs-writer, e2e-test-engineer,
ux-designer) and redistribute their responsibilities:

- qa-integration-tester absorbs all E2E/Playwright test ownership
- product-owner absorbs UAT scenario drafting and README updates
- frontend-developer references tokens.css/Style Guide directly

Simplify per-story workflow from 16 to 11 steps:
- Remove pre-dev UAT ceremony (3 agents + user approval gate)
- Remove visual spec step
- Remove refinement phase (fix in story PRs or as bugs)
- Reduce PR reviewers from 4 to 2 (product-architect + security-engineer)

Release model (beta/main) and CI/CD unchanged.

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.10 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

…ent-driven waits (#162)

- Increase CI Playwright workers from 1 to 4 (GitHub Actions has 4 vCPUs)
- Consolidate 5 viewport projects to 3 (desktop, tablet, mobile) — drop
  redundant desktop-md and mobile-android viewports while preserving both
  chromium and webkit engine coverage
- Tag 8 viewport-sensitive test files with @Responsive; mobile project
  only runs tagged tests (desktop + tablet run all)
- Replace waitForTimeout(400) with waitForResponse in VendorsPage and
  UserManagementPage for deterministic debounce handling
- Reduce POM navigation timeouts from 15s to 8s (pages load in <2s)
- Parallelize app + proxy container startup in global setup
- Scope npm ci to e2e workspace in CI to skip unused dependencies

Expected impact: ~810 → ~401 test executions, ~25-35min → ~4-8min E2E step

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.11 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

…n h1 (#163)

The EPIC-05 refinement changed all budget page h1 headings from
page-specific titles ("Budget Categories", "Vendors") to a shared
<h1>Budget</h1> with sub-navigation tabs. The E2E page objects and
test assertions were never updated, causing all budget-categories and
vendors E2E tests to timeout waiting for headings that no longer exist.

- BudgetCategoriesPage POM: heading selector "Budget Categories" → "Budget"
- VendorsPage POM: heading selector "Vendors" → "Budget"
- budget-categories.spec.ts: h1 assertion updated, added h2 "Categories" check
- vendors.spec.ts: h1 assertion updated, added h2 "Vendors" check

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.12 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

…se parallelism (#164)

Reduce per-test failure time from 60s (30s + retry) to 30s (15s + retry)
by halving the test timeout to 15s and adding explicit actionTimeout (5s)
and navigationTimeout (10s). Increase CI workers from 4 to 8 for higher
throughput. Reduce CI job timeout from 60 to 30 minutes and global suite
timeout from 45 to 30 minutes.

Also tighten POM waitFor timeouts (8-10s → 5s) and test-level explicit
timeouts (15s → 8s for dark mode, 10s → 8s for data load/modal waits).

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.13 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Add Docker cagent framework configuration for gradual migration from
Claude Code agent orchestration. Creates cagent.yaml with 7-agent
hierarchy (orchestrator + 6 specialists), migrated prompt files, and
a secondary sandbox Dockerfile.

- cagent.yaml: root config with Opus 4.6 (planning) and Sonnet 4.5 (dev) models
- .cagent/prompts/project-instructions.md: shared context extracted from CLAUDE.md
- .cagent/prompts/orchestrator.md: explicit orchestrator with 11-step story cycle
- .cagent/prompts/{6 agents}.md: migrated from .claude/agents/ (no YAML frontmatter,
  adapted memory/tool references, preserved all domain-specific content)
- .sandbox/Dockerfile.cagent: cagent base image + Node 24, gh CLI, gwq
- .gitignore: added .cagent/memory/
- scripts/worktree-create.sh: added .cagent/memory/ symlink for worktrees

Existing .claude/ directory is preserved for gradual transition.

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.14 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

…es (#166)

* fix(e2e): resolve 220 test failures — data isolation, locators, cookies

Root-cause analysis of CI run #22233849015 (220 failed, 182 passed)
identified three categories of failures:

**Test data isolation (~150 failures):**
- Add `testPrefix` fixture (worker index + project name) to prevent
  entity name collisions across parallel workers sharing one SQLite DB
- All vendor/category creation uses unique prefixed names
- Count assertions check default category presence, not exact totals
- Admin/profile tests that mutate shared user use serial mode

**Locator and route fixes (~40 failures):**
- Fix categoriesListHeading: /^Categories/ → /^Categories \(/ to avoid
  matching the sub-nav heading (strict mode violations)
- Update ROUTES.budget from /budget to /budget/overview (Story #149)
- Fix redirect test to expect /budget/overview
- Add cardsContainer to waitForVendorsLoaded() Promise.race for mobile

**WebKit session cookie fix (~28 failures):**
- Change sameSite from 'strict' to 'lax' on all session cookies
- WebKit enforces SameSite=Strict more strictly than Chromium, blocking
  cookies after cross-origin redirects (OIDC flow, proxy setup)

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

* fix(test): update auth tests for SameSite=Lax and remove unused imports

Update 2 auth.test.ts assertions from SameSite=Strict to SameSite=Lax
to match the production cookie change. Remove 3 pre-existing lint
warnings: unused VendorListQuery import, unused eq import, unused
userId variable.

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

* fix(e2e): wait for sidebar element to be attached before openSidebar/closeSidebar

On mobile viewports, openSidebar() and closeSidebar() could race against the
React app-shell mount cycle. When called immediately after page.goto(), the
<aside> element may not yet be in the DOM. isSidebarOpen() would read null
for data-open (returning false) and then menuButton.click() could fail if
the header had not finished rendering.

Adding `await this.sidebar.waitFor({ state: 'attached' })` at the top of
both methods ensures the sidebar is part of the DOM before any attribute
read or click action. This resolves 5 intermittent failures on mobile where
sidebar navigation tests called openSidebar() immediately after navigation.

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.15 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Playwright requires the first argument of fixture functions to use
object destructuring syntax. The `_fixtures` parameter caused
"First argument must use the object destructuring pattern" at runtime.

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.16 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

* perf(e2e): add resource profiling and bump workers to 12

Add a background resource profiler to the E2E CI job that logs CPU,
memory, load average, and Docker container stats every 5 seconds. The
profiling log is included in the existing e2e-test-results artifact.

Bump Playwright workers from 8 to 12 (3x vCPU count) since workers are
I/O-bound and can oversubscribe CPUs. Profiling data will guide further
tuning.

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

* perf(e2e): revert workers to 8 after profiling showed CPU saturation

Profiling data from the 12-worker run:
- Peak memory: 9,766/16,384 MB (60% — headroom exists)
- Peak load avg: 126.82 on 4 vCPUs (31.7x oversubscription)
- Test results: 208 failed vs ~0 with 8 workers

The runner is CPU-bound, not memory-bound. 12 browser workers
(Chromium + WebKit) create extreme context switching, causing
test timeouts. 8 workers (2x vCPU) is the empirically validated
maximum.

Keeping the resource profiler for one more run to baseline the
8-worker configuration.

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

* chore(e2e): remove profiler after data collection complete

Profiling data collected, CI workflow restored to original.
Net change: updated worker count comment with empirical findings.

Co-Authored-By: Claude orchestrator (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.52 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

steilerDev and others added 2 commits February 23, 2026 14:01
…#213)

Replace the misleading planned-allocation display (Total/Used/Available) with
actual invoice-based metrics (Total/Claimed/Unclaimed/Available). Planned
allocation is now shown as a subtle secondary line for reference.

- Add unclaimedAmount (paid but not claimed invoices) to BudgetSource type
- Add computeUnclaimedAmount() to backend budget source service
- Rework frontend source card to show claimed/unclaimed/actual-available
- Update all related unit and integration tests

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.53 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Replace budget placeholder with comprehensive user guides covering
categories, financing sources, work item budgets, vendors & invoices,
subsidies, and the budget overview dashboard. Update roadmap and
README to reflect EPIC-05 completion.

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.54 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@steilerDev
Copy link
Copy Markdown
Owner Author

UAT Validation Instructions

Setup

Pull and run the latest beta Docker image:

docker pull steilerdev/cornerstone:beta
docker run -d --name cornerstone-uat -p 3000:3000 -v cornerstone-uat:/app/data steilerdev/cornerstone:beta

Open http://localhost:3000 and complete the setup wizard if this is a fresh instance.

Cleanup after testing: docker stop cornerstone-uat && docker rm cornerstone-uat && docker volume rm cornerstone-uat


Validation Checklist

Budget Categories (Story 5.1 — #142)

  • Navigate to Budget > Categories — see 10 default categories with colored swatches
  • Create a new category (e.g., "Testing Category") with a custom color
  • Edit an existing category's name and color
  • Delete a category that has no budget lines — should succeed
  • Attempt to delete a category with budget lines — should show conflict error

Vendor Management (Story 5.2 — #143)

  • Navigate to Budget > Vendors — see empty state or vendor list
  • Create a vendor with name, specialty, and contact info
  • Search vendors by name
  • Click a vendor to see its detail page with invoices section
  • Edit vendor details on the detail page

Invoice Tracking (Story 5.3 — #144)

  • On a vendor detail page, add a new invoice (number, amount, date, due date)
  • Edit invoice status: pending → paid → claimed
  • Delete an invoice
  • Navigate to Budget > Invoices — see all invoices across vendors
  • Filter invoices by status (pending / paid / claimed)

Financing Sources (Story 5.4 — #145)

  • Navigate to Budget > Sources — see empty state or list
  • Create a financing source (e.g., "Construction Loan") with total amount
  • Edit a source's amount
  • After linking budget lines + invoices, verify depletion shows actual invoice-based costs

Subsidy Programs (Story 5.5 — #146)

  • Navigate to Budget > Subsidies — see empty state or list
  • Create a percentage-based subsidy (e.g., "Energy Grant — 30%") linked to a budget category
  • Create a fixed-amount subsidy (e.g., "Municipal Rebate — €500")
  • Change subsidy status: pending → approved → disbursed
  • Verify rejected subsidies don't appear in budget calculations

Work Item Budget Lines (Stories 5.6/5.9/5.10 — #147/#183/#184)

  • Open a work item detail page — see Budget tab
  • Add a budget line: select category, financing source, enter amount, choose confidence level
  • Verify confidence margins display: Own Estimate (±20%), Professional Estimate (±10%), Quote (±5%), Invoice (±0%)
  • Link a budget line to a vendor invoice — confidence locks to "Invoice", amount from invoice
  • Delete a budget line — verify it's removed

Budget Overview Dashboard (Stories 5.7/5.11/5.12 — #148/#185/#186)

  • Navigate to Budget > Overview — see hero progress bar and summary cards
  • Toggle between 4 remaining perspectives: vs Min Planned, vs Max Planned, vs Actual Cost, vs Actual Paid
  • Verify blended projected model: invoiced lines show actual cost, non-invoiced show confidence margins
  • Verify category breakdown table with per-category amounts
  • Filter by budget category — overview recalculates
  • Verify financing source summary shows actual depletion
  • Verify subsidy reductions appear in calculations
  • Test empty state (no budget data)

Navigation & Polish (Story 5.8 — #149)

  • Sub-navigation tabs visible on all budget pages
  • Active tab highlights correctly when switching
  • EUR currency formatting consistent across all pages
  • Dark mode works on all budget pages
  • Responsive layout — test on mobile/tablet viewport

Decision

  • APPROVE — All scenarios pass, merge betamain
  • REQUEST CHANGES — List failing scenarios below

…sts (#215)

* docs: add budget management guides and update roadmap for EPIC-05

Replace budget placeholder with comprehensive user guides covering
categories, financing sources, work item budgets, vendors & invoices,
subsidies, and the budget overview dashboard. Update roadmap and
README to reflect EPIC-05 completion.

Co-Authored-By: Claude docs-writer (Opus 4.6) <noreply@anthropic.com>

* fix(e2e): increase timeouts for vendor detail and login screenshot tests

Wait for loading state to clear on vendor detail page and add
networkidle wait for login screenshot test. Both tests fail on slow
CI runners where 7s default isn't enough for API fetch + render.

Co-Authored-By: Claude qa-integration-tester (Opus 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.55 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

)

* docs: add budget management guides and update roadmap for EPIC-05

Replace budget placeholder with comprehensive user guides covering
categories, financing sources, work item budgets, vendors & invoices,
subsidies, and the budget overview dashboard. Update roadmap and
README to reflect EPIC-05 completion.

Co-Authored-By: Claude docs-writer (Opus 4.6) <noreply@anthropic.com>

* fix(e2e): increase timeouts for vendor detail and login screenshot tests

Wait for loading state to clear on vendor detail page and add
networkidle wait for login screenshot test. Both tests fail on slow
CI runners where 7s default isn't enough for API fetch + render.

Co-Authored-By: Claude qa-integration-tester (Opus 4.6) <noreply@anthropic.com>

* fix(e2e): increase waitForURL timeouts in vendor tests for slow CI

The vendor detail navigation test fails on CI runners because
page.waitForURL uses an 8000ms timeout which is insufficient for
slow GitHub Actions runners. Increased all waitForURL and related
assertion timeouts to 15000ms for consistency with the other CI
timeout fixes in this file.

Co-Authored-By: Claude <qa-integration-tester> (opus-4) <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.56 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

)

Replace the single E2E job with an 8-shard matrix strategy using
Playwright's --shard flag. Each shard runs ~3-4 test files with 4
workers (1 per vCPU) instead of 8, reducing CPU contention and
flakiness. A merge-reports job combines blob reports into a single
HTML artifact.

Delete the standalone e2e.yml workflow that ran on beta pushes —
all E2E runs now happen in ci.yml on main-targeting PRs.

- Workers: 8 → 4 per shard (reduced CPU contention)
- Reporter: conditional blob (sharding) vs html (local/non-sharded)
- New scripts: test:e2e:shard, test:e2e:merge-reports
- Timeout: 30 min → 15 min per shard
- Expected wall-clock improvement: ~25-30 min → ~5-8 min

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.57 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

* ci(e2e): cache Playwright browser binaries across CI runs

Cache ~/.cache/ms-playwright using actions/cache keyed on the
Playwright version and runner OS. On cache hit, browser binary
downloads (~1GB) are skipped entirely — only system dependencies
(apt packages) are installed since they don't persist on ephemeral
runners. Both e2e-smoke and sharded e2e jobs share the same cache
key so whichever runs first warms the cache for the others.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: skip Docker PR release for PRs targeting main

PRs targeting main are epic promotions (beta → main) which get
proper releases via semantic-release in release.yml on merge.
Publishing a pr-<number> image for these is redundant and confusing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci(e2e): cache apt packages and enable force-unsafe-io for faster system deps

Cache /var/cache/apt/archives so Playwright's install-deps reuses
locally stored .deb files instead of re-downloading ~60 packages on
every E2E job. Also enable dpkg force-unsafe-io to skip fsync on
ephemeral CI runners. Applies to both e2e-smoke and sharded e2e jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(ci): strip whitespace from Playwright version in cache keys

`npx playwright --version` outputs "Version 1.58.2" (with a space),
which would produce invalid cache keys. Pipe through `tr -d '[:space:]'`
to produce a clean key like "Version1.58.2".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.58 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Two fixes for the apt caching added in #218:

1. Set `Keep-Downloaded-Packages "true"` so apt retains .deb files
   after install (Ubuntu runners clean them by default)
2. Use explicit cache/restore + cache/save instead of actions/cache
   so archives are captured immediately after install, not in a
   post-job step where they may already be cleaned

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.59 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Add a dedicated e2e-warmup job that runs once to populate both
Playwright browser and apt caches, eliminating redundant installs
and cache save races across e2e-smoke (1 job) and e2e shards (8 jobs).
Downstream jobs now only restore from pre-warmed caches.

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.60 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Restructure the E2E Cache Warmup job:
- Restore both caches upfront; if both hit, all remaining steps skip
- Browser cache miss: install browsers, save cache
- Apt cache miss: download-only system deps (APT::Get::Download-Only),
  save cache with runner-user ownership

Downstream jobs (smoke, sharded e2e) always run install-deps since
the warmup only downloads debs without installing. With the apt cache
restored, install-deps uses local .deb files (no network download).

Cache key changes:
- Lowercased Playwright version in all cache keys
- v3 prefix to bust stale caches from previous formats
- chown before restore to prevent tar utime/chmod errors

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.61 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

…uts (#227)

Desktop E2E tests were hitting the 10s timeout on CI due to CPU contention
with 4 Playwright workers on ubuntu-latest (2 vCPUs). Halve workers to 2
and double shards from 8 to 16 to reduce per-runner load. Bump the global
test timeout from 10s to 15s as an additional safety margin.

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.9.0-beta.62 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

The Login page screenshot test used `browser.newContext()` to get an
unauthenticated session, but this bare context lacked all project-level
settings (viewport, baseURL, timeouts, device emulation), causing the
SPA to never render within the timeout on CI.

Switch to `test.use({ storageState: { cookies: [], origins: [] } })`
which clears auth cookies while preserving all project settings —
matching the proven pattern used by auth-guard and login-logout tests.

Also fix the `screenshots` script in e2e/package.json to reference the
correct `desktop` project name (not the non-existent `desktop-lg`).

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant