Loud Project Engine and general operations management system.
  • Python 56.5%
  • JavaScript 38%
  • CSS 5%
  • HTML 0.3%
  • Shell 0.2%
Find a file
2026-06-16 15:44:08 +04:00
apps Allow quote venue name correction 2026-06-16 15:44:08 +04:00
docs Improve split quantity editing and dimmer totals 2026-05-27 03:25:11 +04:00
infra/scripts v0.7: add phase6 deployment profile baseline 2026-02-20 17:10:51 +04:00
scripts Add CAD template designer and registry workflow 2026-04-05 07:25:50 +04:00
uploads Document repo handoff and server cleanup 2026-04-28 05:27:19 +04:00
.env.example v0.18 reporting workspace: backend site-reports lifecycle, AI regen/edit/delete UX, and venue identity fix 2026-02-26 23:18:39 +04:00
.gitignore Document repo handoff and server cleanup 2026-04-28 05:27:19 +04:00
buglog.md Allow quote venue name correction 2026-06-16 15:44:08 +04:00
changelog.md Allow quote venue name correction 2026-06-16 15:44:08 +04:00
continuation_prompt.md Allow quote venue name correction 2026-06-16 15:44:08 +04:00
docker-compose.yml v0.18 reporting workspace: backend site-reports lifecycle, AI regen/edit/delete UX, and venue identity fix 2026-02-26 23:18:39 +04:00
estimation_module_prompt.md Document repo handoff and server cleanup 2026-04-28 05:27:19 +04:00
featurelog.md Allow quote venue name correction 2026-06-16 15:44:08 +04:00
README.md Allow quote venue name correction 2026-06-16 15:44:08 +04:00

Loud Engine

Production-grade lighting infrastructure documentation platform.

Current Version

  • Working version: 0.9 (complete)
  • v0.12 closed: Deliverables Circuit Schedule (003.0) backend-locked generation and template finalization complete
  • v0.13 in progress: Circuit Schedule (003.0) multi-page pagination density + per-page frame cleanup applied
  • v0.13 in progress: Circuit Schedule (003.0) totals/advisory row now follows last data row with final-page fit guards
  • v0.13 in progress: Circuit Schedule (003.0) v3 flow layout corrected to stop totals/advisory from dropping to page bottom
  • v0.13 in progress: Dimmer Schedule (004.0) backend generation baseline added with DIM/EDIM-only rows, 4-channel grouping, and per-group subtotal rows
  • v0.13 in progress: Dimmer Schedule subtotal strip refined to compact right-aligned solid dark-grey bar (Dimmer N | * W | * A)
  • v0.13 in progress: Dimmer subtotal amps now round up to whole amps (0 decimal places)
  • v0.13 in progress: Dimmer subtotal W/A cells aligned to match row W/A column widths
  • v0.13 in progress: Dimmer subtotal PDF alignment fine-tuned to row-chip spacing/anchor geometry
  • v0.13 in progress: Dimmer header labels normalized for consistent typography across all header cells
  • v0.13 in progress: Dimmer whole-sheet total strip added (Total Load | * kW | * A) with watt-sum-derived kW and A (220V, ceil 1dp)
  • v0.13 in progress: Dimmer subtotal strips updated to lighter grey palette (total-load strip unchanged)
  • v0.13 in progress: Dimmer grouped pagination hardened so 4+subtotal blocks and trailing total strip do not split across pages
  • v0.13 in progress: Dimmer one-page space usage corrected by limiting reserve behavior to multi-page schedules
  • v0.13 in progress: Site Wide (006.0) backend generation baseline added with dedicated template/CSS and all-circuit-type rows
  • v0.13 in progress: Site Wide cell palette aligned to locked schedule style (Circuit colored chip; other active cells white; placeholders grey)
  • v0.13 in progress: Site Wide Circuit column width reduced to ~50% with adjacent column rebalance
  • v0.13 in progress: Site Wide header+rows horizontally scaled (~30% effective width gain) with title bar unchanged
  • v0.13 in progress: Site Wide scaling corrected to proportional scale-to-fit (no horizontal squash), with width compensation
  • v0.13 in progress: Site Wide typography aligned to locked schedule characteristics (bold headers, lighter body text, colored circuit prefix + bold black numeric suffix)
  • v0.13 in progress: Site Wide Rack width now matches locked Universe width, with centered text
  • v0.13 in progress: Site Wide Phase Load/Rack/Node now backend-contract fields with conditional greying only when values are missing
  • v0.13 in progress: Site Wide pagination now prioritizes fuller page usage (tail rebalance removed) with scaled-density row packing calibration in active tuning
  • v0.13 in progress: Site Wide moved from transform-based body scaling to intrinsic scaled row/header metrics to improve true page-fill behavior
  • v0.13 in progress: Site Wide intrinsic scale calibration narrowed to preserve prior visual proportions while maintaining full-page row packing and per-page frame chunking
  • v0.13 in progress: Site Wide now mirrors Circuit Schedule special type rules for GFS/ARC/ETH/FIB power-cell blank+grey behavior, with GFS/ARC DB source resolved via control-circuit mapping
  • v0.13 in progress: Site Wide DB rules aligned: GFS/ARC use control-circuit remap output; ETH/FIB render PoE only when wattage > 0 (else -)
  • v0.13 in progress: Site Wide (006.0) contract lock validation completed: backend row payload now includes control_circuit_* fields required for GFS/ARC remap generation parity
  • v0.13 in progress: Circuit Schedule source parity updated: ETH/FIB Source now follows conditional PoE rule (max_watts > 0) with - fallback
  • v0.13 in progress: Design workspace UX update: floating circular up-arrow button added to Site Wide Circuit Patch editor (appears on scroll-down, smooth-scrolls to top, hides near top)
  • v0.14 in progress: Deliverables CAD template baseline (001.0) started with PDF-native A1 composition (LIGHTING_PLAN_TEMPLATE) for viewport + right-sidebar metadata rendering
  • v0.14 in progress: Deliverables 001.0 CAD options dialog baseline added (opened from Options) with notes/revision/sidebar field inputs and temporary no-viewport render support for layout testing
  • v0.14 in progress: CAD compositor/runtime path alignment completed (/uploads in containers), with template fidelity pass to match owner blank frame geometry and tighter sidebar logo fit
  • v0.14 in progress: CAD field-mapping calibration started with owner-provided center-coordinate mapping for copyright text box
  • v0.14 in progress: Copyright disclaimer now backend-locked and rendered justified (11-line cap) in calibrated title-block box (dialog input removed from authority)
  • v0.14 in progress: Copyright disclaimer sizing tuned to target full 11-line fill in calibrated box
  • v0.14 in progress: Copyright disclaimer font tuned to 11.8pt (owner calibration pass)
  • v0.14 in progress: Notes header mapping updated; fixed NOTES title at 12.5pt bold now left-aligned with text-left edge x=734.5mm
  • v0.14 in progress: Notes body text region now mapped to owner-provided center/bounds (x=781.04, y=414.23, 93.2mm x 173.7mm)
  • v0.14 in progress: 001.0 Notes editor UX upgraded to a dedicated modal (Notes Section) with single-box rich input and inline Regular/Bold/Italic; backend notes renderer now supports italic + inline run flow
  • v0.14 in progress: Notes overflow guard pass applied: wider Notes editor, hard-wrap for unbroken text in UI, and backend hard-wrap in PDF renderer to prevent off-page spill
  • v0.14 in progress: Notes toolbar formatting fix: selection-preserving Regular/Bold/Italic now applies visibly in-editor and persists to output
  • v0.14 in progress: CAD options persistence hardened: saved Options/Notes now persist by project+stage+revision+doc, reopen reliably, and seed forward into newer revisions when empty
  • v0.14 in progress: Notes modal layout cleanup applied (calibration caption removed, compact uniform width, right-side dead space removed)
  • v0.14 in progress: 001.0 viewport upload workflow added: filename display + Upload action in Options dialog, persisted by project/stage/revision with carry-forward and historical recall by revision
  • v0.14 in progress: CAD viewport upload now validates source PDF page size (713mm x 575mm, ±1mm) before accepting server storage
  • v0.14 in progress: viewport upload stack now uses proper multipart file handling (python-multipart) in API runtime (temporary base64 workaround removed)
  • v0.14 in progress: viewport placement frame in compositor locked to owner geometry (713mm x 575mm, center x=364.5, y=299.41)
  • v0.18 in progress: Reporting workspace reset to shared Clients/Venues with backend Site Reports authority (letterhead PDF generation + manual/summary draft flow)
  • v0.18 in progress: Reporting post-generation lifecycle added (persisted report Edit with rich formatting + AI Regenerate, and latched Remove Report deletion mode)
  • v0.20 in progress: Office user role added for quote-only internal operations, with backend-authoritative quote management access (clients, venues, grants, uploads, view/download/archive/delete)
  • v0.20 in progress: Deliverables workspace recovery hardened so issued rows can be reconstructed from backend-generated artifact authority when browser-local plan state is missing
  • v0.20 in progress: CAD deliverables now have a standalone backend-authoritative Template Designer with saved named templates, default template assignment, base-PDF upload, and mapped text/image field rendering
  • v0.20 in progress: Rack Drawing module architecture approved as a standalone backend subsystem, with DB-backed symbol/rack/slot contracts now started separately from the CAD template designer
  • v0.20 in progress: Rack Drawing now has a standalone app workspace (/rack-drawing) for symbol uploads, project rack definitions, backend-owned slot editing, paired device-library DXF assets, and backend render jobs
  • v0.20 in progress: Rack Drawing generated artifacts can now be previewed, downloaded, and deleted directly from the Rack Drawing workspace
  • v0.20 in progress: Rack device rendering now uses shared rack scale, hidden-line DXF output, paired FRONT / SIDE device assets, and DXF text-anchor handling rather than placeholder fit-to-box geometry
  • v0.20 in progress: 008.0 is now explicitly split out as a later Rack Room module with separate room/spatial rendering requirements
  • v0.20 in progress: Rack device assets can now be dropped under /opt/loud-engine/uploads/rack-symbols/devices and synced into a shared system-wide rack item library
  • v0.20 in progress: Rack slot equipment selection now supports searchable/autocomplete library lookup across projects
  • v0.20 in progress: Rack Layout editor replacement has been rebuilt around backend position_u slot semantics, preserving DOM-targeted drag/drop while removing the failed dual-coordinate draft model
  • v0.20 in progress: Rack Layout drag presentation now uses a consistent compact ghost across device heights while rack-slot preview remains the authority for true occupied span
  • v0.20 in progress: Cost Estimation backend baseline started with a standalone /api/v1/estimations module, DB-backed estimation projects/lines/FX snapshots, fixture-library commercial fields, locking/snapshot authority, and admin/designer-only access
  • v0.20 in progress: Cost Estimation currencies now support manual live refresh from the free open.er-api.com feed into backend-owned AED-normalized DB rates via an admin-only refresh action, keeping budgets stable until the operator explicitly pulls new rates
  • v0.20 in progress: Cost Estimation now has a backend regenerate action that rebuilds project-linked estimation lines from saved site-wide patch quantities while preserving manual advisory lines
  • v0.20 in progress: Cost Estimation now has a first internal web workspace with project-scoped advisory totals, current line breakdown, manual Pull Currency Rates, and backend-driven Regenerate Pricing
  • v0.20 in progress: Cost Estimation workspace now supports project pricing controls, line editing, and admin-owned fixture commercial defaults so regenerated pricing can be maintained from backend library data
  • v0.20 in progress: Cost Estimation workspace can now add linked estimation lines directly from the current project fixture library without requiring a full regenerate pass
  • v0.20 in progress: Cost Estimation now auto-derives cable and install allowances in backend calculations when project overrides are left at 0, with discounts applying to commercial products (products + cables) but not install
  • v0.21 closed: CAD 001.0 Logo Registry upload, vector viewport rendering, landscape normalization, title-comment project-location binding, and BOQ Advice module completed
  • v0.21 closed: BOQ Advice is backend-derived from the current saved Site Wide patch and project fixture library, excludes Decor Lighting (DL), preserves unresolved patch items as review warnings, and exports PDF/XLSX from the same adjusted backend payload
  • v0.21 closed: BOQ Advice supports project-scoped control-system devices, backend-owned reused/existing-kit Adjustment deductions, fixture-library-style dialogs, and adjusted UI/PDF/Excel totals
  • v0.22 in progress: Server Fixture Library now has optional backend-owned Brand and BOQ Ledger fields per system fixture row, editable from the admin server library UI
  • v0.22 in progress: Site Wide Circuit Patch rows now preserve backend fixture identity (project_fixture_entry_id + fixture_code) and BOQ Advice resolves by that identity so same-code server fixture renames propagate cleanly into patch/advice output
  • v0.22 in progress: BOQ Advice control-system device rows now present as CS - Control System and Networking, with BOQ additional-kit storage fully migrated to CS-xx.0 codes and additional-kit rows also allowed in MI - Miscellaneous
  • v0.22 in progress: CS is now a first-class Server Fixture Library and Project Fixture Library section, while MI - Miscellaneous remains available for non-networking miscellaneous items
  • v0.22 in progress: BOQ Advice Additional Kit can add BOQ-only rows to CS or MI without affecting Circuit Patch
  • v0.22 in progress: BOQ Advice category output is backend-sorted so the original lighting/rack sections remain above, followed by CS - Control System and Networking, then MI - Miscellaneous as the final normal kit section
  • v0.22 in progress: BOQ Advice item output columns are Code | Brand | Order Code | Description | Qty across the page, PDF/HTML render, and XLSX export
  • v0.22 in progress: Server Fixture Library rows now include backend-owned BOQ price metadata with AED default currency plus GBP/EUR/USD options for future estimation-system use
  • v0.22 in progress: CAD Template Options now carry forward from prior project stages when the current stage has no saved options yet, while saving back only to the current stage scope
  • v0.22 in progress: CAD 001.H / 001.L options now seed from 001.0 when their own variant scope is empty, then remain isolated after saving
  • v0.22 in progress: Estimation workspace has been rebuilt around backend BOQ Advice data, Server Fixture Library BOQ retail pricing, Additional Kit rows, cable/install factors, discount, VAT, and category/section totals
  • v0.22 in progress: BOQ Additional Kit CS/MI rows are mirrored into the Server Fixture Library so Estimation can price and inline-edit them through the same system fixture backend
  • v0.22 in progress: Estimation-only Grouping can collapse selected current-project CS/MI items into named LOT-priced CS-00.x / MI-00.x quote rows without altering BOQ Advice or fixture libraries
  • v0.22 in progress: Server Fixture Library manual fixture codes now allow one-decimal suffixes such as LA-05.1; auto-numbering remains whole .0 only
  • v0.22 in progress: Site Wide Circuit Patch rows now sort numerically within each circuit type from the backend save/read contract, so a restored lower-numbered circuit slots back into order after Save
  • v0.22 in progress: Added HP - Hot Power as a normal power circuit type after EHPD and before GFS, and corrected TP to Track Power
  • v0.22 in progress: Project Split module added as a non-destructive backend-owned split layer for BOQ Advice and Estimation, with retained phases, Boneyard reconciliation, phase-filtered BOQ exports, and phase Estimation totals
  • v0.22 in progress: Quotes Manage Venue now supports confirmed venue-name correction through the existing backend venue update contract for Admin/Office users
  • Latest functional code commit before this documentation handoff: d3113a1 Add project split module baseline
  • Current default CAD template: LOUD GENERAL LIGHTING for 001.0
  • Next focus: live Project Split calibration on the current split project, especially assignment ergonomics and any phase-specific export wording.

Repository Remote

  • Canonical commit/push target: https://repo.calhta.com/calum/Loud-Engine.git
  • Remote name: origin
  • Transport: HTTPS only; SSH is not used for this repo handoff.
  • Git HTTPS user: calum
  • Server credentials are stored through the local Git credential helper, outside tracked files.
  • A session closeout commit must be pushed to origin/main; local-only commits are not considered complete unless the owner explicitly asks not to push.

Export Output Path Safety

  • Export artifact paths are restricted to EXPORT_OUTPUT_ROOT (default: /tmp/loud_engine_exports).
  • Absolute or relative paths outside that root are rejected with 422 invalid_export_output_path.
  • Public share-link URLs default to PUBLIC_SHARE_BASE_URL (default: http://localhost:8000).

Local Development (Scaffold)

  1. Copy env file:
    • cp .env.example .env
  2. Start stack:
    • docker compose up --build
  3. API health:
    • http://localhost:8000/health
    • http://localhost:8000/api/v1/system/health
  4. Web app:
    • http://localhost:5173

UI Kickoff (v0.6 baseline, expanded through v0.9)

  • Added branded dark-grey shell inspired by loud-dxb.com tone:
    • high-contrast monochrome baseline
    • bold uppercase hero typography
    • card-based module overview layout
  • Added theme toggle (dark/light) with logo switching.
  • Brand assets wired:
    • dark surfaces: /brand/loud-logo-white.png
    • light surfaces: /brand/loud-logo-black.png
  • New frontend files:
    • apps/web/src/styles.css
    • updated apps/web/src/main.jsx
    • reusable UI panels: apps/web/src/components/dashboardPanels.jsx
    • reusable auth/session hook: apps/web/src/hooks/useLoudSession.js
    • reusable dashboard orchestration hook: apps/web/src/hooks/useDashboardData.js
  • Frontend build scripts:
    • npm run build
    • npm run preview
  • Added first API-connected dashboard slice:
    • login form against JWT auth endpoints (/api/v1/auth/login, /api/v1/auth/refresh)
    • session persistence in browser storage with token refresh lifecycle handling
    • live project list (GET /api/v1/projects)
    • selected project detail context (name/code/stage/lock)
    • live validation summary + issue list for selected project (GET /api/v1/projects/{id}/validation)
    • live export stats and package list/detail for selected project:
      • GET /api/v1/projects/{id}/exports/stats
      • GET /api/v1/projects/{id}/exports
      • GET /api/v1/projects/{id}/exports/{export_package_id}
    • async export queue action from UI (POST /api/v1/projects/{id}/exports/generate-async)
    • package status transition control from UI (PATCH /api/v1/projects/{id}/exports/{export_package_id}/status)
    • export document controls in selected package panel:
      • template-aware add/replace (POST /api/v1/projects/{id}/exports/{export_package_id}/documents)
      • document delete (DELETE /api/v1/projects/{id}/exports/{export_package_id}/documents/{document_id})
      • template metadata source (GET /api/v1/reference/export-templates)
      • payload-field editor generated from template payload_schema
      • per-field payload validation hints before submit
    • async export task polling view (GET /api/v1/projects/{id}/exports/tasks/{task_id})
    • recent task shortcut list for quick re-polling
    • action feedback toasts for export + task operations
    • timeline-style action history panel for recent export/task events
    • action history taxonomy filters (all, generate, status, document, task, system)
    • copy-ready payload preview JSON block with one-click copy action
    • persistent action journal (browser storage-backed)
    • doc-type payload preset management (save/load/delete)
    • preset library transfer box for JSON export/import across browsers
    • preset transfer schema bundle (__meta.schema_version) for cross-version portability
    • preset import compatibility diagnostics (legacy vs versioned schema, imported counts)
    • optional encrypted preset transfer bundle (AES-GCM + passphrase) for sensitive workflows
    • shared dashboard response typedefs expanded for action journal and preset import diagnostics contracts
    • export panel distribution controls:
      • share-link creation/list with one-click URL copy
      • share-link lifecycle controls (deactivate/reactivate, expiry update, revoke)
      • share-link tracking visibility for total downloads + last download timestamp
      • share-link activity drill-down (filter + paged event rows)
      • sync-to-folder job trigger with inline status feedback
      • sync-job history list for selected export package
    • dedicated share-link tracking panel:
      • selected-project share-link list view
      • global share-link list view across projects
      • click-through event timeline with date/time and request metadata
      • server-side list filters (status + created/download date windows)
    • permit tracking panel:
      • selected-project and global permit lists
      • status-filtered permit scope views
      • click-through permit status timeline with date/time checkpoints
      • permit create/status-transition/approval controls
    • field callout tracking panel:
      • selected-project and global callout lists
      • status/priority/due filters
      • click-through callout status timeline and note trail
      • callout create/status-transition/note controls
    • report workflow panel:
      • selected-project and global report lists
      • manual authoring fields (summary + sections)
      • formatted rendered output preview
      • publish action + revision history tracking
    • collaboration workflow panel:
      • selected-project and global collaboration thread lists
      • status/priority/context filtered views
      • assignment + thread status updates
      • thread comments and review actions with traceable timeline
    • module navigation split:
      • core lighting operations remain on /
      • Site Attendance module shell mounted on /attendance with separated navigation placement
      • Site Attendance panel grouping now contains permits/callouts/reports/collaboration/share-link tracking
    • Site Attendance permissions baseline:
      • PROJECT_MANAGER has full write access for permits/callouts/reports/collaboration workflows
    • attendance package workflow baseline:
      • selected-project and global attendance package lists
      • attendance package create/update/issue controls
      • attendance package event timeline (created/updated/issued/status-changed)
      • package builder references for venue/staff/company-document IDs
    • attendance package share-link baseline:
      • package-level share-link issuance/listing/revoke controls
      • global + selected-project attendance share-link tracking
      • public no-auth attendance share page + JSON download endpoint
      • tracked events (view, download) with date/time trail
    • attendance staff database baseline:
      • selected-project and global staff record lists
      • mandatory identity fields: ID number, passport number, visa reference
      • optional license/certification list
      • create/update controls in Site Attendance module
    • attendance venue database baseline:
      • selected-project and global venue record lists
      • required venue code/name with duplicate-code protection per project
      • venue paperwork requirements, escape-route notes, and key contacts
      • create/update controls in Site Attendance module
    • attendance company document vault baseline:
      • global LOUD company document records for compliance and access templates
      • active-only filtering and document detail editing controls
      • code/title/type contracts with JSON payload metadata support
    • action journal retention controls (max entries, max age days, manual clear)
  • Added quick UX polish:
    • persisted theme choice in browser storage
    • refresh button for selected project data modules
    • clearer selected-project context and issue/status presentation
    • explicit export workflow guardrail hints (allowed status transitions, complete-package immutability)
    • Site Wide line universe field now resolves live from latest address-plan data per mapped circuit (circuit_id/circuit_tag with type+number fallback)
    • GFS lines now support control-circuit-driven universe rules (HPD/EHPD control source) with GFS-ID replacing load field
    • ARC lines now include backend ArcLamp intelligence (name-detected ArcLamp counts, computed ARC load, and auto driver/channel reference allocation such as ARC-150-01/1)
    • ARC rows now use staged Control Circuit behavior like GFS, and replace Load with Driver Patch to show computed ARC driver reference output (ARC-700-01/1 style)
    • ArcLamp allocation now prioritizes fewer total drivers by consuming existing spare channels across the project before creating new drivers; ARC includes a Calculate Driver Patch action for explicit non-save recomputation
    • VCN/EVCN/ETH/FIB rows now repurpose fields for network workflows: Universe -> ETH Patch; DB stays on VCN/EVCN and becomes read-only PoE on ETH/FIB; ETH/FIB Load -> VLAN-ID (fed from a minimal backend networking feed endpoint placeholder)
    • ETH auto legend baseline: default LCN Circuit, switches to sequential WAP_001 style when EAP device names are present, with manual legend override retained
    • Site Wide filename/save controls now float into the top page banner on long scroll so save state remains accessible
  • Frontend maintainability refactor:
    • moved large dashboard JSX blocks into focused component modules
    • kept API/state orchestration in main.jsx to preserve behavior while improving change velocity
    • extracted theme/session persistence + login/logout + token refresh lifecycle into useLoudSession
    • extracted project/export/template/task orchestration (loaders/actions/polling) into useDashboardData
    • added in-hook toast queue + payload normalization for schema-driven doc upsert inputs
  • Dev proxy enabled in Vite:
    • /api and /health route to API service in Docker dev (http://api:8000)

Database Bootstrap

  1. Apply baseline migration:
    • docker compose exec api alembic -c alembic.ini upgrade head
  2. Seed reference/lifecycle data:
    • docker compose exec api python -m app.db.seeds --profile reference
  3. Seed demo bootstrap data (optional for local dev):
    • docker compose exec api python -m app.db.seeds --profile demo

Auth (JWT Baseline)

  1. Login:
    • curl -sS -X POST http://localhost:8000/api/v1/auth/login -H 'Content-Type: application/json' -d '{"email":"admin@local.dev","password":"change_me_now"}'
  2. Use returned access_token:
    • curl -sS http://localhost:8000/api/v1/system/me/roles -H "Authorization: Bearer <ACCESS_TOKEN>"
  3. Refresh:
    • curl -sS -X POST http://localhost:8000/api/v1/auth/refresh -H 'Content-Type: application/json' -d '{"refresh_token":"<REFRESH_TOKEN>"}'

Project API (v0.5 baseline, expanded through v0.9)

  • GET /api/v1/projects
  • POST /api/v1/projects
  • GET /api/v1/projects/{project_id}
  • PATCH /api/v1/projects/{project_id}
  • GET /api/v1/projects/{project_id}/permits
  • GET /api/v1/projects/{project_id}/attendance/packages
  • GET /api/v1/projects/{project_id}/attendance/staff
  • POST /api/v1/projects/{project_id}/attendance/staff
  • GET /api/v1/projects/{project_id}/attendance/staff/{staff_id}
  • PATCH /api/v1/projects/{project_id}/attendance/staff/{staff_id}
  • GET /api/v1/projects/{project_id}/attendance/venues
  • POST /api/v1/projects/{project_id}/attendance/venues
  • GET /api/v1/projects/{project_id}/attendance/venues/{venue_id}
  • PATCH /api/v1/projects/{project_id}/attendance/venues/{venue_id}
  • POST /api/v1/projects/{project_id}/attendance/packages
  • GET /api/v1/projects/{project_id}/attendance/packages/{package_id}
  • PATCH /api/v1/projects/{project_id}/attendance/packages/{package_id}
  • POST /api/v1/projects/{project_id}/attendance/packages/{package_id}/issue
  • GET /api/v1/projects/{project_id}/attendance/packages/{package_id}/events
  • POST /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-links
  • GET /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-links
  • PATCH /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-links/{share_link_id}
  • DELETE /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-links/{share_link_id}
  • GET /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-links/{share_link_id}/events
  • GET /api/v1/projects/{project_id}/attendance/share-links
  • POST /api/v1/projects/{project_id}/permits
  • GET /api/v1/projects/{project_id}/permits/{permit_id}
  • PATCH /api/v1/projects/{project_id}/permits/{permit_id}
  • POST /api/v1/projects/{project_id}/permits/{permit_id}/status-events
  • GET /api/v1/projects/{project_id}/permits/{permit_id}/status-events
  • POST /api/v1/projects/{project_id}/permits/{permit_id}/approvals
  • GET /api/v1/projects/{project_id}/permits/{permit_id}/approvals
  • GET /api/v1/projects/{project_id}/callouts
  • POST /api/v1/projects/{project_id}/callouts
  • GET /api/v1/projects/{project_id}/callouts/{callout_id}
  • PATCH /api/v1/projects/{project_id}/callouts/{callout_id}
  • POST /api/v1/projects/{project_id}/callouts/{callout_id}/status-events
  • GET /api/v1/projects/{project_id}/callouts/{callout_id}/status-events
  • POST /api/v1/projects/{project_id}/callouts/{callout_id}/notes
  • GET /api/v1/projects/{project_id}/callouts/{callout_id}/notes
  • GET /api/v1/projects/{project_id}/reports
  • POST /api/v1/projects/{project_id}/reports
  • GET /api/v1/projects/{project_id}/reports/{report_id}
  • PATCH /api/v1/projects/{project_id}/reports/{report_id}
  • POST /api/v1/projects/{project_id}/reports/{report_id}/publish
  • GET /api/v1/projects/{project_id}/reports/{report_id}/versions
  • GET /api/v1/projects/{project_id}/collaboration/threads
  • POST /api/v1/projects/{project_id}/collaboration/threads
  • GET /api/v1/projects/{project_id}/collaboration/threads/{thread_id}
  • PATCH /api/v1/projects/{project_id}/collaboration/threads/{thread_id}
  • GET /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/comments
  • POST /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/comments
  • GET /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/review-actions
  • POST /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/review-actions
  • GET /api/v1/projects/{project_id}/circuits
  • POST /api/v1/projects/{project_id}/circuits
  • PATCH /api/v1/projects/{project_id}/circuits/{circuit_id}
  • GET /api/v1/projects/{project_id}/fixtures
  • POST /api/v1/projects/{project_id}/fixtures
  • PATCH /api/v1/projects/{project_id}/fixtures/{fixture_id}
  • GET /api/v1/projects/{project_id}/address-plans
  • GET /api/v1/projects/{project_id}/address-plans/{plan_id}
  • POST /api/v1/projects/{project_id}/address-plans/generate
  • POST /api/v1/projects/{project_id}/address-plans/{plan_id}/freeze
  • POST /api/v1/projects/{project_id}/address-plans/{plan_id}/overrides
  • GET /api/v1/projects/{project_id}/stage-history
  • GET /api/v1/projects/{project_id}/audit-logs?limit=100
  • POST /api/v1/projects/{project_id}/stage-transitions
  • GET /api/v1/projects/{project_id}/site-wide-circuit-patch
  • POST /api/v1/projects/{project_id}/site-wide-circuit-patch/save
  • POST /api/v1/projects/{project_id}/site-wide-circuit-patch/calculate
  • GET /api/v1/projects/{project_id}/network/vlan-feed
  • GET /api/v1/projects/{project_id}/fixture-library
  • POST /api/v1/projects/{project_id}/fixture-library/entries
  • PATCH /api/v1/projects/{project_id}/fixture-library/entries/{entry_id}
  • DELETE /api/v1/projects/{project_id}/fixture-library/entries/{entry_id}
  • GET /api/v1/projects/{project_id}/fixture-library/system-search
  • GET /api/v1/projects/{project_id}/revisions
  • POST /api/v1/projects/{project_id}/revisions
  • GET /api/v1/projects/{project_id}/revisions/{revision_id}/diff?against_revision_id=...

Fixture Library API (v0.4 baseline)

  • GET /api/v1/fixture-types
  • POST /api/v1/fixture-types
  • GET /api/v1/fixture-types/{fixture_type_id}/versions
  • POST /api/v1/fixture-types/{fixture_type_id}/versions

Export API (v0.5 baseline, expanded through v0.9)

  • GET /api/v1/projects/{project_id}/exports
    • supports query params: status, limit, offset
  • GET /api/v1/projects/{project_id}/exports/stats
  • GET /api/v1/projects/{project_id}/validation
  • GET /api/v1/projects/{project_id}/exports/{export_package_id}
  • POST /api/v1/projects/{project_id}/exports/generate
    • supports optional idempotency_token to safely deduplicate retries
    • each document supports optional typed template_payload (validated by doc_type)
  • POST /api/v1/projects/{project_id}/exports/generate-async
    • async retries with the same idempotency_token now short-circuit to:
      • state='SUCCESS'
      • idempotent_hit=true
      • existing export_package_id
  • GET /api/v1/projects/{project_id}/exports/tasks/{task_id}
  • PATCH /api/v1/projects/{project_id}/exports/{export_package_id}/status
    • status transitions are constrained:
      • queued -> queued|processing|failed
      • processing -> processing|complete|failed
      • failed -> failed|queued
      • complete -> complete
    • transitioning to complete requires at least one export document
  • POST /api/v1/projects/{project_id}/exports/{export_package_id}/documents
    • blocked for completed packages (409 export_package_immutable_when_complete)
  • GET /api/v1/projects/{project_id}/exports/{export_package_id}/documents/{document_id}/preview
  • GET /api/v1/system/attendance/packages
  • GET /api/v1/system/attendance/staff
  • GET /api/v1/system/attendance/venues
  • GET /api/v1/system/attendance/company-documents
  • POST /api/v1/system/attendance/company-documents
  • GET /api/v1/system/attendance/company-documents/{document_id}
  • PATCH /api/v1/system/attendance/company-documents/{document_id}
  • GET /api/v1/system/attendance/share-links
  • GET /api/v1/public/attendance-share-links/{share_token}
  • GET /api/v1/public/attendance-share-links/{share_token}/download.json
  • DELETE /api/v1/projects/{project_id}/exports/{export_package_id}/documents/{document_id}
  • DELETE /api/v1/projects/{project_id}/exports/{export_package_id}
    • blocked while package is processing (409 export_package_processing_delete_forbidden)
  • Distribution contract endpoints:
    • GET /api/v1/system/distribution/share-links
    • GET /api/v1/projects/{project_id}/distribution/share-links
    • POST /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/share-links
      • supports package scope (default)
      • supports single-file scope via:
        • document_ids (export-document scoped), or
        • issued-artifact scoped payload (artifact_stage_name, artifact_revision, artifact_code, artifact_file_path)
    • GET /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/share-links
    • PATCH /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/share-links/{share_link_id}
    • DELETE /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/share-links/{share_link_id}
      • lifecycle revoke/deactivate (can be re-enabled via PATCH is_active=true)
    • DELETE /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/share-links/{share_link_id}/permanent
      • permanent share-link delete (does not delete source export files)
    • GET /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/share-links/{share_link_id}/events
    • POST /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/sync-jobs
    • GET /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/sync-jobs

Share-link list filters supported on global and project list endpoints:

  • status: active | inactive | revoked | expired
  • created_from, created_to (ISO datetime)
  • download_from, download_to (ISO datetime; based on doc/zip download events)

Public distribution endpoints:

  • GET /api/v1/public/share-links/{share_token}
  • GET /api/v1/public/share-links/{share_token}/documents/{document_id}
  • GET /api/v1/public/share-links/{share_token}/download.zip

Public web route:

  • /public/share/{share_token} renders a package page with:
    • package metadata
    • explicit scope metadata (package or single file, including issued-artifact share links)
    • lightweight package access counters (views/file downloads/ZIP downloads)
    • per-document download actions
    • one-click full ZIP download

Task polling now returns progress metadata when available:

  • progress_percent
  • detail.message

Reference API

  • GET /api/v1/reference/export-templates
    • now includes payload_schema metadata per doc type/template version
    • LIGHTING_PLAN_TEMPLATE template available for A1 CAD viewport composition into 001.0 layout frame with sidebar metadata fields
    • CIRCUIT_SCHEDULE now includes include_dimmers payload control (default false)
    • DIMMER_SCHEDULE template available for dimmable-only circuit schedule output
    • SHOW_POWER_SCHEDULE template available with voltage-based total/domain load summaries
    • SITE_WIDE_CIRCUIT_PATCH template available with patched/unpatched circuit mapping summaries
    • CAT6_PATCH_SHEET, ARTNET_NODE_PATCH_SHEET, and BOQ_ADVICE template contracts are available

System API

  • GET /api/v1/system/fixture-library (admin)
  • POST /api/v1/system/fixture-library/items (admin)
  • PATCH /api/v1/system/fixture-library/items/{item_id} (admin)
  • DELETE /api/v1/system/fixture-library/items/{item_id} (admin; permanent delete across linked project entries)
  • GET /api/v1/system/validation/projects
    • supports query params: limit, offset, errors_only
  • GET /api/v1/system/permits
    • supports query params: status, limit, offset
  • GET /api/v1/system/callouts
    • supports query params: status, priority, due_from, due_to, limit, offset
  • GET /api/v1/system/reports
    • supports query params: status, report_type, limit, offset
  • GET /api/v1/system/collaboration/threads
    • supports query params: status, priority, context_type, limit, offset

Validation responses include explicit blocking semantics:

  • project validation payload now includes has_blocking_issues, blocking_issue_count, validation_policy
  • system validation summary now includes has_blocking_issues, blocking_issue_count
  • stage rulesets can now override validation behavior per issue code via validation_policy.issue_overrides
    • supports severity (warning|error), blocking (true|false), and disabled (true|false)

Test Scaffolding (v0.5)

  • apps/api/tests/test_export_service.py
  • apps/api/tests/test_permit_service.py
  • apps/api/tests/test_callout_service.py
  • apps/api/tests/test_report_service.py
  • apps/api/tests/test_collaboration_service.py
  • apps/api/tests/test_validation_service.py
  • run in container: docker compose exec api pytest -q tests
  • API integration scaffold:
    • apps/api/tests/integration/test_export_lifecycle_api.py
    • apps/api/tests/integration/test_validation_stage_async_api.py
    • run from worker container against live API:
      • docker compose exec worker env RUN_API_INTEGRATION=1 API_BASE_URL=http://api:8000 pytest -q /app/tests/integration

Test Strategy (v0.7)

  • Strategy doc: docs/quality/test-strategy-v0.7.md
  • Seed strategy doc: docs/quality/seed-strategy-v0.7.md
  • Backup/restore runbook: docs/operations/backup-restore-v0.7.md
  • Observability runbook: docs/operations/observability-v0.7.md
  • Deployment runbook: docs/operations/deployment-debian-compose-v0.7.md
  • Standard local matrix script:
    • infra/scripts/run-test-matrix.sh
  • Backup/restore scripts:
    • infra/scripts/backup-runtime.sh
    • infra/scripts/restore-runtime.sh
    • infra/scripts/deploy-compose.sh

Observability env controls:

  • LOG_LEVEL (default INFO)
  • ENABLE_REQUEST_LOGGING (default true)
  • API pytest markers:
    • unit
    • service
    • api_integration

Audit API

  • GET /api/v1/projects/{project_id}/audit-logs
    • supports query params: limit, entity_name, action

Current Artifacts

  • Database baseline: docs/architecture/data-model-v0.1.md
  • SQL baseline: docs/architecture/schema-v0.1.sql
  • Lifecycle ruleset: docs/architecture/lifecycle-ruleset-v0.1.md
  • Permit baseline: docs/architecture/permit-management-v0.7.md
  • Callout baseline: docs/architecture/callout-tracking-v0.7.md
  • Report workflow baseline: docs/architecture/report-workflows-v0.7.md
  • Collaboration workflow baseline: docs/architecture/collaboration-workflows-v0.7.md
  • Product backlog: featurelog.md
  • Change tracking + operating laws: changelog.md

Notes

  • PM role currently has write access for Site Attendance workflows; finer-grained permission tuning remains deferred.
  • Transition gating uses lifecycle ruleset policies including required export document types.
  • AI-assisted report drafting is deferred as a future module; v0.7 reports remain manual-entry and fully trackable.
  • CAD template preview/regenerate can run long on heavy viewport PDFs; dev proxy timeout is set to 10 minutes in apps/web/vite.config.js for /api and /health.
  • 001.0 CAD viewport uploads are preprocessed into cached raster artifacts (cad-viewports-cache/{sha256}.png) for fallback resilience; generated deliverables use the uploaded vector PDF whenever available.
  • 001.0 generation is fidelity-locked to vector viewport merge whenever source PDF is available; raster cache is fallback-only.
  • 001.0 regenerate now uses async task orchestration (preview-pdf-async + task polling + download endpoint) to avoid long blocking HTTP render requests.
  • Deliverables UI now surfaces CAD regenerate stage text with animated activity bars for 001.0 (preparing / rendering / finalizing).
  • generated CAD PDFs are post-processed with lossless Ghostscript optimization (no downsampling), and optimized output is used only when smaller.
  • Deliverables action row includes REGENERATE PACKAGE with In Place and New Revision queueing flows for submission-wide regeneration.
  • package regenerate queue state is persisted client-side and auto-resumes after refresh; all rows display queue lifecycle states (queued / running / complete) during package runs.
  • deliverables row regenerate action width is fixed to prevent progress/status layout shift while a row transitions to Regenerating....
  • package row progress indicators are cleared automatically after package completion (including resumed runs after refresh).
  • REGENERATE PACKAGE is right-aligned in the Deliverables action row for stable control placement.
  • 002.0 is now wired as upload-only CAD (.dwg) with row-level Upload dialog and regenerate/export rename flow; revision 0 omits revision suffix in filename while revision 1+ appends rev.xx.
  • CAD upload dialogs now retain and display the original uploaded filename (tracking label) even after regenerate/export applies LOUD output renaming.
  • Deliverables row Upload now opens the same upload-dialog pattern for both 001.0 and 002.0 (with type-specific file rules: 001.0 PDF, 002.0 DWG).
  • Upload action is intentionally hidden (with preserved row-action gap alignment) for 003.0, 004.0, 006.0, and 020.0.
  • Deliverables row action label is scope-aware: button shows Generate until first successful render for the current project + stage + revision + code, then switches to Regenerate.
  • Generate/Regenerate label now includes artifact-presence fallback signals for existing scopes (render cache, CAD upload presence, and completed export package in scope) so established rows do not falsely reset to Generate.
  • Deliverables row action columns are now explicit slot-aligned (including Options/Upload gaps) to keep all button columns visually aligned across rows.
  • Backend now exposes generated-artifact authority endpoints per stage/revision scope; row regenerate persists rendered outputs server-side and export prioritizes server-stored artifacts.
  • Deliverables selection plans are now also persisted server-side per project + stage + revision (deliverables-plans/...) and auto-synced from the UI, so issued package composition survives browser/local-storage loss.
  • 001.x CAD template geometry now has a versioned backend manifest authority at apps/api/app/assets/cad_layout_v1.json; the compositor loads layout coordinates/slots from that manifest instead of relying only on scattered code constants.
  • CAD-missing generate failures now set a scope-persisted inline warning banner beside the deliverable title and keep it across refresh until successful generation clears it.
  • Non-negotiable engineering rule: deliverables generation state is backend-authoritative and persisted; UI-only draft truth is disallowed.
  • Generated artifact storage now separates internal server filename from user-facing filename; downloads/share naming uses canonical human filename (with compatibility fallback for older artifacts).
  • Expected CAD-missing generate failures are handled inline on the deliverable row and no longer emit raw global error-card codes.
  • Client download helper now preserves deliverable extensions (including .dwg) and no longer forces .pdf suffix on non-PDF files.
  • Backend now enforces canonical user-facing naming policy for 001.0 and 002.0 generated artifacts (including .dwg extension guarantee for 002.0).
  • 002.0 generate path now hard-requires DWG source; non-DWG legacy scoped files are rejected instead of being renamed/exported as PDF variants.
  • CAD upload endpoints now preserve the operator-uploaded filename for stored source files (no sanitize/UUID rename), so upload dialog tracking reflects the true upload name.
  • CAD upload dialogs now support editable source filename labels and post them to backend (original_name_override) to handle short-alias filename environments (e.g. browser-provided ~1 names).
  • CAD template family now includes 001.0, 001.H, and 001.L on the same backend-first pipeline (PDF upload + options + async regenerate/export/view), with code-specific naming and titles.
  • CAD template family now also includes 007.0 and 008.0 with the same workflow parity (PDF upload + options + async regenerate/export/view) and code-specific naming/titles.
  • Dynamic 010.* detail-drawing deliverables now use the same CAD template workflow parity (PDF upload + options + async regenerate/export/view), including per-row title baselines and discovered generated-artifact status.
  • Distribution share links now persist origin-aware host metadata (share_base_url) at creation time and generate public URLs from the accessed system host instead of localhost/IP fallbacks.
  • Deliverables workspace now supports package-level share creation (SHARE PACKAGE) and single-file share link creation per row (Share) when a complete package exists for the selected stage/revision.
  • Deliverables rows now show an ISSUED tick when backend generated-artifact authority confirms an issued file exists for current project/stage/revision/code.
  • Row-level Share now uses issued-artifact authority (not export-doc-type mapping), so CAD/hybrid rows with doc_type = null can still be shared after regenerate.
  • Share creation now opens a copy-first modal UX: click link field to copy and auto-close, with explicit Cancel option.
  • Public share links now include social-preview metadata (Open Graph / Twitter) with LOUD branding image so pasted links can render rich preview cards in chat tools that support URL unfurling.
  • Share preview image now uses dedicated asset path: /brand/share-preview-logo.png (source managed in apps/web/public/brand/share-preview-logo.png).
  • Share preview description follows: Secure Link: ProjectStatus - Venue - Revision, with runtime public-share values injected from loaded share payload.
  • Public share URLs are canonicalized as /public/share/{token}.
  • Web server now injects per-token public-share metadata for /public/share/{token} at request time (Vite middleware), so unfurl clients receive true values:
    • Secure Link: {ProjectStatus} - {Venue} - Rev {revision_no}
  • Public share payload now emits stage display labels (owner-facing status) instead of internal canonical stage keys (e.g. Detailed Design instead of Coordinated).
  • Sharing is now a dedicated top-level module with grouped tracking by project/stage and row-level controls: revoke/re-enable, permanent link delete, URL copy, and download counters.
    • POST /api/v1/projects/{project_id}/deliverables/generated-artifacts/share-links
      • creates single-file public share links directly from issued generated artifacts (stage/revision/code/file path payload), without requiring an already-complete export package in that scope.
  • Site Attendance package payloads now resolve to a backend-owned canonical access structure (001 Trade Licence, 002 RA & MS, 003 Staff Details, 004 Insurance, 005 Venue Specific) using selected venue/staff/company-document refs.
  • Site Attendance package payloads now include backend-generated expiry_alerts for company docs and staff ID/passport/visa timelines.
  • Company document vault now supports explicit expiry controls (expires_at, warning_days) and computed status flags (is_expired, is_expiring) via backend contracts.
  • Project attendance now exposes expiry monitoring endpoint:
    • GET /api/v1/projects/{project_id}/attendance/alerts/expiry?warning_window_days=45
  • Site attendance now supports file-backed package sharing:
    • issue action snapshots referenced package files into /uploads/attendance-packages/{project_id}/{package_id}/issue-{timestamp}/
    • public attendance share links expose:
      • per-file download (/api/v1/public/attendance-share-links/{token}/documents/{document_id})
      • package ZIP download (/api/v1/public/attendance-share-links/{token}/download.zip)
      • JSON payload download remains available (/api/v1/public/attendance-share-links/{token}/download.json)
  • New upload endpoints for attendance sources:
    • POST /api/v1/system/attendance/company-documents/{document_id}/upload (multipart)
    • POST /api/v1/projects/{project_id}/attendance/staff/{staff_id}/documents/upload (multipart)
  • Attendance module UI now includes operator upload controls for:
    • selected company document file (vault panel)
    • selected staff member document (staff panel)
  • New standalone operations reporting backend domain is now available and intentionally separate from design-build projects:
    • distinct venue registry (ops_reporting_venues)
    • attendance call records (ops_reporting_attendance_calls)
    • reporting records (ops_reporting_reports)
  • New reporting APIs (system scope):
    • GET/POST/PATCH /api/v1/system/ops-reporting/venues
    • GET/POST/PATCH /api/v1/system/ops-reporting/attendance-calls
    • GET/POST/PATCH /api/v1/system/ops-reporting/reports
    • POST /api/v1/system/ops-reporting/reports/{report_id}/issue
  • UI navigation now includes dedicated Reporting module beside Site Attendance.
  • Reporting module now includes a working operator UI for:
    • ops venue creation/selection
    • attendance-call creation/selection (scoped to selected venue)
    • report creation/listing/issue flow (scoped to selected attendance call, with status filtering).
  • Reporting summary generation can run against local Ollama for real LLM rewriting:
    • compose service: ollama (docker compose up -d ollama)
    • configured via:
      • SITE_REPORT_AI_OLLAMA_URL=http://ollama:11434
      • SITE_REPORT_AI_OLLAMA_MODEL=qwen2.5:7b-instruct
    • first-time model pull:
      • docker compose exec ollama ollama pull qwen2.5:7b-instruct
    • backend falls back to deterministic heuristic summary only when Ollama is unavailable or generation fails.
  • Quotes repository baseline is now available:
    • finance quote PDF upload + storage (server-retained)
    • quote indexing by ops venue + client name
    • backend PDF text analysis for extracted title/total metadata
    • searchable quote listing and authenticated quote download endpoints.
  • Quotes workflow upgraded to backend-first v0.17 contracts:
    • dedicated quote entities and grants now exist:
      • ops_quote_clients
      • ops_quote_venues
      • ops_quote_client_access
      • ops_quote_venue_access
      • ops_quote_documents
    • parse/finalize lifecycle is backend-owned:
      • POST /api/v1/system/quotes/parse (parse-only, no persistence)
      • POST /api/v1/system/quotes/upload (final persistence + rename policy)
      • final quote filename contract:
        • Venue - Location - QuoteNumber.pdf
        • venue/location abbreviations override full labels when configured.
      • date parser supports month-name, slash, hyphen, and dot numeric formats (including DD.MM.YYYY).
      • flattened-header hardening: explicit full-text Date: extraction with Expiry Date exclusion plus filename fallback (DDMMYYYY) when needed.
      • notes parser supports Item Description and Description headings, including flattened same-line note+heading extraction.
    • storage path now scales by client/venue/year/month:
      • uploads/quotes/{client_id}/{venue_id}/{year}/{month}/...
    • internal management APIs added for client/venue CRUD and grant/revoke:
      • GET/POST /api/v1/system/quote-clients
      • GET/POST /api/v1/system/quote-clients/{client_id}/venues (POST accepts optional name_abbreviation / location_abbreviation)
      • PATCH /api/v1/system/quote-venues/{venue_id} (venue naming overrides for file token precedence)
      • POST /api/v1/system/quote-clients/{client_id}/grant|revoke
      • POST /api/v1/system/quote-venues/{venue_id}/grant|revoke
      • GET /api/v1/system/quote-venues/{venue_id}/quotes
      • DELETE /api/v1/system/quotes/{quote_id}
      • POST /api/v1/system/quotes/{quote_id}/archive
    • venue-level filename token overrides are now backend-managed:
      • optional name_abbreviation and location_abbreviation persisted on ops_quote_venues
      • when present, these override venue/location tokens in generated quote filenames.
    • shared venue identity contract (Quotes/Site Access/Reporting):
      • venue uniqueness is client + venue_name + location (case-insensitive),
      • allowing multiple branches with the same brand name under one client.
  • New CLIENT role is now supported:
    • client users can be provisioned via Settings -> Manage Users (Client)
    • client users are restricted to dedicated quote-view area only (no access to internal project modules)
    • venue-scoped access control for client users is backend-managed via client-to-venue assignments.
  • Client portal quote APIs expanded:
    • GET /api/v1/client/quote-portal/summary
    • POST /api/v1/client/quotes/{quote_id}/archive
  • Quotes UI refinement notes (v0.17):
    • internal module now uses explicit Venues / Users and Upload split-pane labeling.
    • staged upload review displays backend-parsed fields as read-only summary before finalize.
    • client/venue listing emphasizes recency ordering and compact scroll density for operator speed.
    • visual polish pass applied for selected-row clarity, upload empty-state composition, and grant/revoke suggestion-list ergonomics.
    • client quote portal browser-tab branding is client-session scoped:
      • tab title: Loud Quote Portal
      • favicon: system-theme aware
        • dark mode: /brand/loud-logo-white.png
        • light mode: /brand/loud-logo-black.png
    • client quote portal username displays as a grey pill badge for immediate account-context clarity.
    • subtle spacing buffer added between username pill and client-name line for readability.
    • client quote portal mobile topbar behavior:
      • no refresh button
      • top-right action row with Light/Dark to the left of Sign Out.
      • compact theme-toggle label in portal mode: Light / Dark.
      • Project Engine subtitle remains visible under LOUD logo in compact centered form.
    • client quote portal mobile quote rows now display normalized identity:
      • Venue - Location
      • QU-*
      • with quote date value directly underneath.
    • quote-row Archive and Download actions are right-pushed and held in a stable single-row alignment group.
    • client portal quote-row actions now stack vertically (Archive above Download) while staying right-aligned.
    • desktop client portal quote-row actions render on one line (Archive, Download) while mobile remains vertically stacked.
    • archived client-portal quotes support 2-second press-and-hold unarchive interaction.
    • mobile QU-* line has a slight font-size bump for readability.
    • mobile quote identity block (Venue - Location, QU-*, date) is center-aligned.
    • mobile quote rows include notes line between QU-* and date in reduced text size.
    • desktop quote rows show notes and date on the same second metadata line (notes first, date second).
    • desktop notes/date metadata line includes | separator between notes and date.
    • desktop separator spacing tuned with slightly larger post-| gap.
    • portal quote title display omits trailing .pdf extension for cleaner UI.
  • Backend Contract Law (permanent):
    • business rules and persistence authority live in backend services/contracts.
    • frontend is orchestration/presentation only; no parallel/fallback business rule implementations.
    • conflicting or duplicated backend behavior is treated as a bug and logged for repair (buglog.md).
  • Server Fixture Library edits (admin settings dialog) now persist reliably and propagate to linked Project Fixture Library entries, including fixture attributes (wattage, dmx_channels, weight, order_code) as well as name/code.
  • Circuit field terminology now uses Termination in operator-facing UI and deliverable schedule headers (003.0, 004.0, 006.0); backend storage keys remain unchanged to preserve existing data.
  • Site Wide Circuit Patch now supports Add Copy per circuit type section:
    • duplicates the latest line in that type as a starting point
    • assigns the next sequential circuit number
    • preserves existing Add behavior for blank new lines.
  • Site Wide Circuit Patch network-row label refinement:
    • ETH/FIB PoE field is now labeled Termination (UI terminology alignment only).
  • Site Wide Circuit Patch ETH/FIB termination behavior now matches other non-control circuits:
    • field is editable text (no PoE auto-value substitution)
    • deliverables (003.0, 006.0) render entered termination text directly.
  • Site Wide Circuit Patch ETH/FIB termination save persistence fixed:
    • ETH/FIB termination values are no longer cleared during frontend normalize/save cycles.
    • ETH/FIB now persist custom text entries (e.g. Main Rack) exactly like other termination fields.
  • Site Wide Circuit Patch ETH description edit persistence hardened:
    • normalized description section fallback logic now avoids rehydrating stale split-section fragments.
    • ETH descriptions now persist cleanly after save without legacy section-data reversion behavior.
  • Site Wide Circuit Patch Add Copy now supports row-select copy mode:
    • pressing Add Copy enters per-type copy mode instead of cloning last row immediately.
    • a green tick selector appears on each row (same slot as remove X).
    • selecting a row copies that rows data into the next sequential circuit number, then exits copy mode for that type.
  • CAD options dialog now supports viewport-file removal for fast alignment iterations:
    • Remove PDF button added beside Upload in 001.0 CAD viewport controls.
    • action clears scoped viewport path/raster/filename fields from CAD options store without affecting generated artifacts.
  • CAD overlay status label calibration update:
    • added explicit bold Status: text on the PDF overlay.
    • positioned from A1 bottom-left coordinate input at top-left anchor:
      • x=734.44, y=275.6.
  • CAD overlay notes heading punctuation update:
    • notes heading now renders as NOTES: (with trailing colon).
  • CAD overlay status value calibration update:
    • backend project-status value field now renders center/center at:
      • x=781.05, y=271.64
    • font size set to 13pt.
  • CAD overlay consultant label calibration update:
    • added bold left-aligned Lighting Consultant: label.
    • top-left anchored at:
      • x=734.44, y=257.6
    • font size set to 10pt.
  • CAD overlay party label calibration update:
    • added bold left-aligned labels:
      • Client: at x=734.44, y=210
      • Interior Designer: at x=734.44, y=190
    • both top-left anchored, 10pt.
  • CAD overlay title-block label expansion:
    • added bold left-aligned labels (top-left anchored, 10pt):
      • Main Contractor: at x=734.44, y=170
      • MEP Contractor: at x=734.44, y=150
      • Lighting Integrator: at x=734.44, y=130
      • As Per Drawing: at x=734.44, y=102
      • Site: at x=734.44, y=69
      • Title: at x=734.44, y=49
      • Scale At A1: at x=734.44, y=29
  • CAD overlay status/title-block vertical tune:
    • moved all fields from Status: through Revision: down by 2.0mm as a uniform Y shift.
  • CAD overlay lower title-block refinement (Scale through Revision):
    • moved this subset back up by 1.0mm (half of prior down-shift).
    • reduced label font size for this subset by 0.2pt (10.0pt -> 9.8pt).
  • CAD overlay lower title-block micro refinement (Scale through Revision):
    • moved this subset up by an additional 0.5mm.
    • reduced label font size by a further 0.1pt (9.8pt -> 9.7pt).
  • CAD overlay consultant/party label typography refinement:
    • reduced label size by 0.2pt for:
      • Client
      • Interior Designer
      • Main Contractor
      • MEP Contractor
      • Lighting Integrator
      • As Per Drawing
  • CAD overlay consultant/title-block follow-up refinement:
    • reduced label size by 0.2pt for:
      • Lighting Consultant
      • Site
      • Title
    • moved this display group up by 0.5mm:
      • Lighting Consultant
      • Client
      • Interior Designer
      • Main Contractor
      • MEP Contractor
      • Lighting Integrator
      • Site
      • Title
  • CAD notes heading typography refinement:
    • reduced NOTES: heading font by 0.2pt (12.5pt -> 12.3pt).
  • CAD status value positional refinement:
    • moved project status value field (not Status: label) up by 0.5mm.
  • CAD logo registry workflow (backend-authoritative) is now available:
    • added global system logo registry for CAD roles:
      • Client
      • Interior Designer
      • Main Contractor
      • MEP Contractor
      • Lighting Consultant
      • Lighting Integrator
    • CAD options dialog now uses backend-driven dropdowns for these roles (no manual path typing).
    • each role row supports Upload:
      • prompts for server display name
      • accepts image file from local machine
      • stores logo in server uploads + registry
      • uploaded logo becomes selectable in dropdown and is auto-selected for current CAD options scope.
    • migration required before use:
      • apps/api/alembic/versions/0026_cad_logo_registry.py
  • CAD logo placement calibration (center-point coordinates) and scale policy:
    • removed extra logo downscale factor in CAD compositor (full slot-fit, no additional shrink multiplier).
    • updated center-point placement for:
      • Lighting Consultant center: x=781.02, y=236.6 (84x23 slot)
      • Client center: x=781.02, y=198.8 (84x11 slot)
      • Interior Designer center: x=781.02, y=178.93 (84x11 slot)
      • Main Contractor center: x=781.02, y=158.3 (84x11 slot)
      • MEP Contractor center: x=781.02, y=138.3 (84x11 slot)
      • Lighting Integrator center: x=781.02, y=119.4 (84x11 slot)
  • Site Access workspace staging reset (v0.17 -> v0.18 prep):
    • Site Access module UI is intentionally reduced to a single full-width shell card.
    • module button now uses latched highlight behavior (matching Quotes) and unlatches Design/Deliverables selection when activated.
    • project selection card is hidden while Site Access module is active.
  • Site Access workspace starter expansion:
    • restored Site Access to three cards.
    • first card now provides a dedicated client/venue selector UI patterned from Quotes left pane.
    • this selector reads from the same backend quote clients/venues model and endpoints (shared data source, separate UI implementation).
  • Site Access UI sizing pass:
    • Site Access cards now use a taller 160% height profile (scoped to Site Access only).
    • client/venue selector list viewport is constrained to ~3 visible rows before scroll.
  • Site Access client selector create action:
    • added Create Client button + modal in Site Access client/venue card.
    • action writes to the shared quotes clients backend model and refreshes selector list on success.
  • Site Access selector metric alignment:
    • removed quote-access user pills and quote counters from Site Access selector rows.
    • added backend-driven ACCESS PACKAGES counters.
    • quote client/venue system contracts now include access_package_count computed from issued attendance packages.
  • Site Access create-action context behavior:
    • selector action now switches from Create Client to Create Venue when inside a selected client's venues list.
    • venue creation uses shared quote venues backend contract.
  • Site Access card 2 baseline:
    • card 2 heading now set to Staff / Document Control.
    • card 2 heading typography aligned with Site Access card 1 heading style.
  • Site Access card 2 staff controls:
    • includes Staff subheading, search, and scroll list sized for ~5 visible entries.
    • includes Add Staff dialog path and Remove Staff latch mode with per-row red remove trigger.
    • remove flow confirmed via backend delete endpoint and storage cleanup for associated staff documents.
  • Site Access add-staff contract alignment:
    • add dialog now omits project picker and notes field.
    • staff code is backend-generated as LS-### (next available), not user-editable.
    • added backend-backed Job autocomplete source via GET /api/v1/system/attendance/staff/jobs.
    • attendance staff contracts now include job_title for create/update/read flows.
  • Staff row visual polish:
    • remove X trigger now sits fully within row bounds.
    • each staff row now displays a right-aligned settings cog icon.
  • Staff document upload/storage baseline remains active:
    • endpoint: POST /api/v1/projects/{project_id}/attendance/staff/{staff_id}/documents/upload
    • persisted path: uploads/attendance-staff-documents/<project_id>/<staff_id>/...
  • Site Access staff settings workflow baseline:
    • cog button now opens Edit Staff Member dialog.
    • top staff details load as read-only by default with explicit Edit Details toggle.
    • Full Name and Staff Code remain non-editable in edit mode.
    • upload controls added for EID, Passport, Visa, and Licences.
    • licence uploads now persist license_name + license_abbreviation metadata and upsert backend licence registry for autocomplete reuse.
    • backend autocomplete endpoints available:
      • GET /api/v1/system/attendance/staff/jobs
      • GET /api/v1/system/attendance/staff/licenses
    • migration added for backend licence registry:
      • apps/api/alembic/versions/0029_attendance_staff_license_registry.py
    • runtime note:
      • apply migration 0029 (alembic upgrade head) to enable licence registry persistence/autocomplete.
      • backend guards now prevent upload-path 500s if migration is temporarily missing.
  • Site Access staff document filename contract (backend-authoritative):
    • on upload, staff docs are renamed to:
      • StaffCode - FullName - Document.ext
    • Document uses doc kind (EID, PASSPORT, VISA) and uses license_name for license uploads when supplied.
    • file extension is preserved/inferred backend-side.
    • upload replacement policy:
      • uploading a document for an existing staff document slot replaces in place (same metadata id and same stored path/name when present).
      • slot matching:
        • EID/PASSPORT/VISA: one slot per kind
        • LICENSE: one slot per license name
      • metadata stores sha256 for uploaded file content.
    • issued package/share links now resolve live backend document sources (not frozen snapshot copies), so updated staff documents are reflected in previously issued package downloads.
  • Site Access company document control baseline:
    • system-level company documents can be managed from Site Access via backend-backed upload actions.
    • required upload slots:
      • Trade Licence
      • Insurance Certificate
      • Insurance Schedule
      • Insurance Policy
    • persistence is immediate on upload (no draft-only frontend state).
    • company-document upload naming contract:
      • Loud - <Document Title>.<ext>
    • replacement behavior:
      • uploads replace in place for existing document records (stable storage path when present).
  • Site Access create access package baseline:
    • card 3 is now an active backend-connected package creation flow.
    • selecting a venue in Site Access card 1 unlocks package fields in card 3.
    • top context fields shown as system text (server-sourced selection + system date):
      • client
      • venue
      • location
      • date
    • manual fields persisted in package payload:
      • prepared by
      • operator
      • security
      • main contractor
      • works commencing date/time
      • works ending date
      • project overview
      • exit routes
    • staff selection workflow in card 3:
      • Select Staff -> selectable list with green selected state
      • Cancel + Confirm Staff actions while selecting
      • confirmed staff list rendered in grey with staff code/name and license pills
    • Create Access Package now creates a persisted attendance package record immediately via backend API.
  • Site Access HSE package generation status (002 RAMS):
    • previously attempted HSE generation slice has been intentionally purged/reset by owner instruction.
    • no active HSE generation endpoints/UI test pane are currently wired.
    • next implementation pass should rebuild HSE generation from clean backend-first architecture using owner templates under:
      • uploads/access-package-templates/002-rams/
    • update (2026-02-26): clean backend-first rebuild completed.
      • active endpoints:
        • POST /api/v1/projects/{project_id}/attendance/packages/{package_id}/documents/hse
        • GET /api/v1/projects/{project_id}/attendance/packages/{package_id}/documents/hse/download
      • active template source:
        • /uploads/access-package-templates/002-rams/Loud HSE - v01.pdf
      • generation metadata persisted in:
        • package_payload.generated_documents.hse_package
      • temporary full-width Site Access HSE output test card restored for iterative validation.
    • update (2026-02-26, repair):
      • HSE rendering now preserves template formatting by doing in-place placeholder replacement on the uploaded PDF template (no secondary full-body overlay).
    • update (2026-02-26, calibration):
      • added field-placement refinements to reduce overlap in edge placeholder positions (including shared venue/location site line behavior).
    • update (2026-02-26, bullets):
      • normalized introduction applicability list markers from * to bullet points during backend generation for visual consistency.
    • update (2026-02-26, stability cutover):
      • generation now uses fillable-PDF AcroForm field population (template-form mode) with required-field validation.
      • primary template:
        • /uploads/access-package-templates/002-rams/Loud HSE - Prep.pdf
    • update (2026-02-26, template v2):
      • primary form template updated to:
        • /uploads/access-package-templates/002-rams/Loud HSE - Prep - v2.pdf
    • update (2026-02-26, field appearance):
      • AcroForm output now enforces Prepared Name text-size style for all filled fields except Venue and Location.
    • update (2026-02-26, multiline fields):
      • Project Overview and Exit Routes are rendered as backend text-box overlays (wrapped/top-aligned) for stable layout.
    • update (2026-02-26, template v5):
      • primary form template updated to:
        • /uploads/access-package-templates/002-rams/Loud HSE - Prep - v5.pdf
      • added fixed-field mapping:
        • Loud -> Loud and Clear Audio Visual Equipment Trading LLC.
    • update (2026-02-26, alignment tweak):
      • Prepared Name receives a small backend vertical offset adjustment for visual alignment.
    • update (2026-02-26, readonly export):
      • generated form fields are written in read-only mode to reduce viewer field-highlighting artifacts.
  • Deliverables CAD template workflow (001.x) update:
    • active layout authority now begins with:
      • apps/api/app/assets/cad_layout_v1.json
    • backend compositor:
      • apps/api/app/services/cad_template_pdf.py
    • local extraction/inspection helper:
      • scripts/extract_cad_layout_manifest.py
    • host-side reference workflow:
      • run the extractor with /opt/loud-engine/.venv-tools/bin/python to inspect the owner-filled reference PDF, compare measured label geometry to the manifest, and derive suggested manifest updates/value-slot guidance without retuning code constants by eye.
    • render-mode update:
      • compositor now supports filled_reference_static_base mode from the manifest.
      • when active, the owner-filled reference PDF becomes the static chrome/background, the backend clears only dynamic regions, merges the live viewport, and redraws only mutable content.
    • mapping workflow update:
      • CAD options now expose a backend-persisted Template Mapping editor for 001.x-style outputs.
      • the editor uses a clean structural background generated by backend authority and saves draft text/image field rectangles via system endpoints.
  • Rack Drawing (007.0) render jobs are backend-authoritative artifacts: only complete, non-stale jobs with a real stored PDF are eligible as the current viewport source, and jobs remain queued until the worker actually begins rendering.
  • Rack Drawing render lifecycle is auditable end-to-end: duplicate rack selections are rejected, and queue/start/fail/complete transitions are recorded in project audit history.
  • Rack Drawing artifact reads are uploads-root constrained on the backend for both symbol SVGs and rendered PDFs.
  • Rack Drawing 007.0 backend rendering now outputs front-plus-side rack views rather than a single elevation-only stack representation.
  • Rack Drawing UI has been simplified back to a single full-width workspace card with project-context gating, a top-right Symbol Library dialog, and rack creation now includes a backend-owned rack number field.
  • Rack symbols no longer use a width tag in authoring or validation; equipment is treated as 19-inch rack equipment regardless of outer rack enclosure width.
  • Rack Drawing backend now carries owner-supplied core front-rack element metadata and a project rack include_castors flag so rendered rack height can follow real front assembly pieces more closely.
  • Rack Drawing device symbols are now treated as paired rack-item assets: a library item is only complete when it has both FRONT and SIDE DXF files, and the shared device library under uploads/rack-symbols/devices/ syncs complete pairs into a project-global searchable rack item library.