Loud Project Engine and general operations management system.
- Python 56.5%
- JavaScript 38%
- CSS 5%
- HTML 0.3%
- Shell 0.2%
| apps | ||
| docs | ||
| infra/scripts | ||
| scripts | ||
| uploads | ||
| .env.example | ||
| .gitignore | ||
| buglog.md | ||
| changelog.md | ||
| continuation_prompt.md | ||
| docker-compose.yml | ||
| estimation_module_prompt.md | ||
| featurelog.md | ||
| README.md | ||
Loud Engine
Production-grade lighting infrastructure documentation platform.
Current Version
- Working version:
0.9(complete) v0.12closed: Deliverables Circuit Schedule (003.0) backend-locked generation and template finalization completev0.13in progress: Circuit Schedule (003.0) multi-page pagination density + per-page frame cleanup appliedv0.13in progress: Circuit Schedule (003.0) totals/advisory row now follows last data row with final-page fit guardsv0.13in progress: Circuit Schedule (003.0) v3 flow layout corrected to stop totals/advisory from dropping to page bottomv0.13in progress: Dimmer Schedule (004.0) backend generation baseline added with DIM/EDIM-only rows, 4-channel grouping, and per-group subtotal rowsv0.13in progress: Dimmer Schedule subtotal strip refined to compact right-aligned solid dark-grey bar (Dimmer N | * W | * A)v0.13in progress: Dimmer subtotal amps now round up to whole amps (0decimal places)v0.13in progress: Dimmer subtotalW/Acells aligned to match rowW/Acolumn widthsv0.13in progress: Dimmer subtotal PDF alignment fine-tuned to row-chip spacing/anchor geometryv0.13in progress: Dimmer header labels normalized for consistent typography across all header cellsv0.13in progress: Dimmer whole-sheet total strip added (Total Load | * kW | * A) with watt-sum-derivedkWandA(220V, ceil 1dp)v0.13in progress: Dimmer subtotal strips updated to lighter grey palette (total-load strip unchanged)v0.13in progress: Dimmer grouped pagination hardened so 4+subtotal blocks and trailing total strip do not split across pagesv0.13in progress: Dimmer one-page space usage corrected by limiting reserve behavior to multi-page schedulesv0.13in progress: Site Wide (006.0) backend generation baseline added with dedicated template/CSS and all-circuit-type rowsv0.13in progress: Site Wide cell palette aligned to locked schedule style (Circuitcolored chip; other active cells white; placeholders grey)v0.13in progress: Site WideCircuitcolumn width reduced to ~50% with adjacent column rebalancev0.13in progress: Site Wide header+rows horizontally scaled (~30% effective width gain) with title bar unchangedv0.13in progress: Site Wide scaling corrected to proportional scale-to-fit (no horizontal squash), with width compensationv0.13in progress: Site Wide typography aligned to locked schedule characteristics (bold headers, lighter body text, colored circuit prefix + bold black numeric suffix)v0.13in progress: Site WideRackwidth now matches lockedUniversewidth, with centered textv0.13in progress: Site WidePhase Load/Rack/Nodenow backend-contract fields with conditional greying only when values are missingv0.13in progress: Site Wide pagination now prioritizes fuller page usage (tail rebalance removed) with scaled-density row packing calibration in active tuningv0.13in progress: Site Wide moved from transform-based body scaling to intrinsic scaled row/header metrics to improve true page-fill behaviorv0.13in progress: Site Wide intrinsic scale calibration narrowed to preserve prior visual proportions while maintaining full-page row packing and per-page frame chunkingv0.13in progress: Site Wide now mirrors Circuit Schedule special type rules forGFS/ARC/ETH/FIBpower-cell blank+grey behavior, withGFS/ARCDB source resolved via control-circuit mappingv0.13in progress: Site Wide DB rules aligned:GFS/ARCuse control-circuit remap output;ETH/FIBrenderPoEonly when wattage > 0 (else-)v0.13in progress: Site Wide (006.0) contract lock validation completed: backend row payload now includescontrol_circuit_*fields required forGFS/ARCremap generation parityv0.13in progress: Circuit Schedule source parity updated:ETH/FIBSource now follows conditionalPoErule (max_watts > 0) with-fallbackv0.13in 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.14in progress: Deliverables CAD template baseline (001.0) started with PDF-native A1 composition (LIGHTING_PLAN_TEMPLATE) for viewport + right-sidebar metadata renderingv0.14in progress: Deliverables001.0CAD options dialog baseline added (opened fromOptions) with notes/revision/sidebar field inputs and temporary no-viewport render support for layout testingv0.14in progress: CAD compositor/runtime path alignment completed (/uploadsin containers), with template fidelity pass to match owner blank frame geometry and tighter sidebar logo fitv0.14in progress: CAD field-mapping calibration started with owner-provided center-coordinate mapping for copyright text boxv0.14in progress: Copyright disclaimer now backend-locked and rendered justified (11-line cap) in calibrated title-block box (dialog input removed from authority)v0.14in progress: Copyright disclaimer sizing tuned to target full 11-line fill in calibrated boxv0.14in progress: Copyright disclaimer font tuned to11.8pt(owner calibration pass)v0.14in progress: Notes header mapping updated; fixedNOTEStitle at12.5ptbold now left-aligned with text-left edgex=734.5mmv0.14in progress: Notes body text region now mapped to owner-provided center/bounds (x=781.04,y=414.23,93.2mm x 173.7mm)v0.14in progress:001.0Notes editor UX upgraded to a dedicated modal (Notes Section) with single-box rich input and inlineRegular/Bold/Italic; backend notes renderer now supports italic + inline run flowv0.14in 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 spillv0.14in progress: Notes toolbar formatting fix: selection-preservingRegular/Bold/Italicnow applies visibly in-editor and persists to outputv0.14in progress: CAD options persistence hardened: saved Options/Notes now persist by project+stage+revision+doc, reopen reliably, and seed forward into newer revisions when emptyv0.14in progress: Notes modal layout cleanup applied (calibration caption removed, compact uniform width, right-side dead space removed)v0.14in progress:001.0viewport upload workflow added: filename display + Upload action in Options dialog, persisted by project/stage/revision with carry-forward and historical recall by revisionv0.14in progress: CAD viewport upload now validates source PDF page size (713mm x 575mm, ±1mm) before accepting server storagev0.14in progress: viewport upload stack now uses proper multipart file handling (python-multipart) in API runtime (temporary base64 workaround removed)v0.14in progress: viewport placement frame in compositor locked to owner geometry (713mm x 575mm, centerx=364.5,y=299.41)v0.18in progress: Reporting workspace reset to shared Clients/Venues with backend Site Reports authority (letterhead PDF generation + manual/summary draft flow)v0.18in progress: Reporting post-generation lifecycle added (persisted reportEditwith rich formatting +AI Regenerate, and latchedRemove Reportdeletion mode)v0.20in 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.20in progress: Deliverables workspace recovery hardened so issued rows can be reconstructed from backend-generated artifact authority when browser-local plan state is missingv0.20in progress: CAD deliverables now have a standalone backend-authoritativeTemplate Designerwith saved named templates, default template assignment, base-PDF upload, and mapped text/image field renderingv0.20in 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 designerv0.20in 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 jobsv0.20in progress: Rack Drawing generated artifacts can now be previewed, downloaded, and deleted directly from the Rack Drawing workspacev0.20in progress: Rack device rendering now uses shared rack scale, hidden-line DXF output, pairedFRONT/SIDEdevice assets, and DXF text-anchor handling rather than placeholder fit-to-box geometryv0.20in progress:008.0is now explicitly split out as a later Rack Room module with separate room/spatial rendering requirementsv0.20in progress: Rack device assets can now be dropped under/opt/loud-engine/uploads/rack-symbols/devicesand synced into a shared system-wide rack item libraryv0.20in progress: Rack slot equipment selection now supports searchable/autocomplete library lookup across projectsv0.20in progress: Rack Layout editor replacement has been rebuilt around backendposition_uslot semantics, preserving DOM-targeted drag/drop while removing the failed dual-coordinate draft modelv0.20in progress: Rack Layout drag presentation now uses a consistent compact ghost across device heights while rack-slot preview remains the authority for true occupied spanv0.20in progress: Cost Estimation backend baseline started with a standalone/api/v1/estimationsmodule, DB-backed estimation projects/lines/FX snapshots, fixture-library commercial fields, locking/snapshot authority, and admin/designer-only accessv0.20in progress: Cost Estimation currencies now support manual live refresh from the freeopen.er-api.comfeed into backend-owned AED-normalized DB rates via an admin-only refresh action, keeping budgets stable until the operator explicitly pulls new ratesv0.20in progress: Cost Estimation now has a backendregenerateaction that rebuilds project-linked estimation lines from saved site-wide patch quantities while preserving manual advisory linesv0.20in progress: Cost Estimation now has a first internal web workspace with project-scoped advisory totals, current line breakdown, manualPull Currency Rates, and backend-drivenRegenerate Pricingv0.20in 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 datav0.20in progress: Cost Estimation workspace can now add linked estimation lines directly from the current project fixture library without requiring a full regenerate passv0.20in progress: Cost Estimation now auto-derives cable and install allowances in backend calculations when project overrides are left at0, with discounts applying to commercial products (products + cables) but not installv0.21closed: CAD001.0Logo Registry upload, vector viewport rendering, landscape normalization, title-comment project-location binding, and BOQ Advice module completedv0.21closed: 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 payloadv0.21closed: BOQ Advice supports project-scoped control-system devices, backend-owned reused/existing-kitAdjustmentdeductions, fixture-library-style dialogs, and adjusted UI/PDF/Excel totalsv0.22in progress: Server Fixture Library now has optional backend-ownedBrandandBOQ Ledgerfields per system fixture row, editable from the admin server library UIv0.22in 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 outputv0.22in progress: BOQ Advice control-system device rows now present asCS - Control System and Networking, with BOQ additional-kit storage fully migrated toCS-xx.0codes and additional-kit rows also allowed inMI - Miscellaneousv0.22in progress:CSis now a first-class Server Fixture Library and Project Fixture Library section, whileMI - Miscellaneousremains available for non-networking miscellaneous itemsv0.22in progress: BOQ AdviceAdditional Kitcan add BOQ-only rows toCSorMIwithout affecting Circuit Patchv0.22in progress: BOQ Advice category output is backend-sorted so the original lighting/rack sections remain above, followed byCS - Control System and Networking, thenMI - Miscellaneousas the final normal kit sectionv0.22in progress: BOQ Advice item output columns areCode | Brand | Order Code | Description | Qtyacross the page, PDF/HTML render, and XLSX exportv0.22in 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 usev0.22in 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 scopev0.22in progress: CAD001.H/001.Loptions now seed from001.0when their own variant scope is empty, then remain isolated after savingv0.22in 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 totalsv0.22in progress: BOQ Additional KitCS/MIrows are mirrored into the Server Fixture Library so Estimation can price and inline-edit them through the same system fixture backendv0.22in progress: Estimation-only Grouping can collapse selected current-projectCS/MIitems into named LOT-pricedCS-00.x/MI-00.xquote rows without altering BOQ Advice or fixture librariesv0.22in progress: Server Fixture Library manual fixture codes now allow one-decimal suffixes such asLA-05.1; auto-numbering remains whole.0onlyv0.22in 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 Savev0.22in progress: AddedHP - Hot Poweras a normal power circuit type afterEHPDand beforeGFS, and correctedTPtoTrack Powerv0.22in 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 totalsv0.22in progress: QuotesManage Venuenow 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 LIGHTINGfor001.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)
- Copy env file:
cp .env.example .env
- Start stack:
docker compose up --build
- API health:
http://localhost:8000/healthhttp://localhost:8000/api/v1/system/health
- Web app:
http://localhost:5173
UI Kickoff (v0.6 baseline, expanded through v0.9)
- Added branded dark-grey shell inspired by
loud-dxb.comtone:- 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
- dark surfaces:
- 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 buildnpm 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/statsGET /api/v1/projects/{id}/exportsGET /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
- template-aware add/replace (
- 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
/attendancewith separated navigation placement - Site Attendance panel grouping now contains permits/callouts/reports/collaboration/share-link tracking
- core lighting operations remain on
- Site Attendance permissions baseline:
PROJECT_MANAGERhas 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)
- login form against JWT auth endpoints (
- 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_tagwith type+number fallback) - GFS lines now support control-circuit-driven universe rules (
HPD/EHPDcontrol source) withGFS-IDreplacing 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 Circuitbehavior like GFS, and replaceLoadwithDriver Patchto show computed ARC driver reference output (ARC-700-01/1style) - ArcLamp allocation now prioritizes fewer total drivers by consuming existing spare channels across the project before creating new drivers; ARC includes a
Calculate Driver Patchaction for explicit non-save recomputation - VCN/EVCN/ETH/FIB rows now repurpose fields for network workflows:
Universe -> ETH Patch;DBstays on VCN/EVCN and becomes read-onlyPoEon ETH/FIB; ETH/FIBLoad -> VLAN-ID(fed from a minimal backend networking feed endpoint placeholder) - ETH auto legend baseline: default
LCN Circuit, switches to sequentialWAP_001style whenEAPdevice 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.jsxto 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:
/apiand/healthroute to API service in Docker dev (http://api:8000)
Database Bootstrap
- Apply baseline migration:
docker compose exec api alembic -c alembic.ini upgrade head
- Seed reference/lifecycle data:
docker compose exec api python -m app.db.seeds --profile reference
- Seed demo bootstrap data (optional for local dev):
docker compose exec api python -m app.db.seeds --profile demo
Auth (JWT Baseline)
- 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"}'
- Use returned
access_token:curl -sS http://localhost:8000/api/v1/system/me/roles -H "Authorization: Bearer <ACCESS_TOKEN>"
- 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/projectsPOST /api/v1/projectsGET /api/v1/projects/{project_id}PATCH /api/v1/projects/{project_id}GET /api/v1/projects/{project_id}/permitsGET /api/v1/projects/{project_id}/attendance/packagesGET /api/v1/projects/{project_id}/attendance/staffPOST /api/v1/projects/{project_id}/attendance/staffGET /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/venuesPOST /api/v1/projects/{project_id}/attendance/venuesGET /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/packagesGET /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}/issueGET /api/v1/projects/{project_id}/attendance/packages/{package_id}/eventsPOST /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-linksGET /api/v1/projects/{project_id}/attendance/packages/{package_id}/share-linksPATCH /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}/eventsGET /api/v1/projects/{project_id}/attendance/share-linksPOST /api/v1/projects/{project_id}/permitsGET /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-eventsGET /api/v1/projects/{project_id}/permits/{permit_id}/status-eventsPOST /api/v1/projects/{project_id}/permits/{permit_id}/approvalsGET /api/v1/projects/{project_id}/permits/{permit_id}/approvalsGET /api/v1/projects/{project_id}/calloutsPOST /api/v1/projects/{project_id}/calloutsGET /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-eventsGET /api/v1/projects/{project_id}/callouts/{callout_id}/status-eventsPOST /api/v1/projects/{project_id}/callouts/{callout_id}/notesGET /api/v1/projects/{project_id}/callouts/{callout_id}/notesGET /api/v1/projects/{project_id}/reportsPOST /api/v1/projects/{project_id}/reportsGET /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}/publishGET /api/v1/projects/{project_id}/reports/{report_id}/versionsGET /api/v1/projects/{project_id}/collaboration/threadsPOST /api/v1/projects/{project_id}/collaboration/threadsGET /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}/commentsPOST /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/commentsGET /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/review-actionsPOST /api/v1/projects/{project_id}/collaboration/threads/{thread_id}/review-actionsGET /api/v1/projects/{project_id}/circuitsPOST /api/v1/projects/{project_id}/circuitsPATCH /api/v1/projects/{project_id}/circuits/{circuit_id}GET /api/v1/projects/{project_id}/fixturesPOST /api/v1/projects/{project_id}/fixturesPATCH /api/v1/projects/{project_id}/fixtures/{fixture_id}GET /api/v1/projects/{project_id}/address-plansGET /api/v1/projects/{project_id}/address-plans/{plan_id}POST /api/v1/projects/{project_id}/address-plans/generatePOST /api/v1/projects/{project_id}/address-plans/{plan_id}/freezePOST /api/v1/projects/{project_id}/address-plans/{plan_id}/overridesGET /api/v1/projects/{project_id}/stage-historyGET /api/v1/projects/{project_id}/audit-logs?limit=100POST /api/v1/projects/{project_id}/stage-transitionsGET /api/v1/projects/{project_id}/site-wide-circuit-patchPOST /api/v1/projects/{project_id}/site-wide-circuit-patch/savePOST /api/v1/projects/{project_id}/site-wide-circuit-patch/calculateGET /api/v1/projects/{project_id}/network/vlan-feedGET /api/v1/projects/{project_id}/fixture-libraryPOST /api/v1/projects/{project_id}/fixture-library/entriesPATCH /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-searchGET /api/v1/projects/{project_id}/revisionsPOST /api/v1/projects/{project_id}/revisionsGET /api/v1/projects/{project_id}/revisions/{revision_id}/diff?against_revision_id=...
Fixture Library API (v0.4 baseline)
GET /api/v1/fixture-typesPOST /api/v1/fixture-typesGET /api/v1/fixture-types/{fixture_type_id}/versionsPOST /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
- supports query params:
GET /api/v1/projects/{project_id}/exports/statsGET /api/v1/projects/{project_id}/validationGET /api/v1/projects/{project_id}/exports/{export_package_id}POST /api/v1/projects/{project_id}/exports/generate- supports optional
idempotency_tokento safely deduplicate retries - each document supports optional typed
template_payload(validated bydoc_type)
- supports optional
POST /api/v1/projects/{project_id}/exports/generate-async- async retries with the same
idempotency_tokennow short-circuit to:state='SUCCESS'idempotent_hit=true- existing
export_package_id
- async retries with the same
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|failedprocessing -> processing|complete|failedfailed -> failed|queuedcomplete -> complete
- transitioning to
completerequires at least one export document
- status transitions are constrained:
POST /api/v1/projects/{project_id}/exports/{export_package_id}/documents- blocked for completed packages (
409 export_package_immutable_when_complete)
- blocked for completed packages (
GET /api/v1/projects/{project_id}/exports/{export_package_id}/documents/{document_id}/previewGET /api/v1/system/attendance/packagesGET /api/v1/system/attendance/staffGET /api/v1/system/attendance/venuesGET /api/v1/system/attendance/company-documentsPOST /api/v1/system/attendance/company-documentsGET /api/v1/system/attendance/company-documents/{document_id}PATCH /api/v1/system/attendance/company-documents/{document_id}GET /api/v1/system/attendance/share-linksGET /api/v1/public/attendance-share-links/{share_token}GET /api/v1/public/attendance-share-links/{share_token}/download.jsonDELETE /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)
- blocked while package is
- Distribution contract endpoints:
GET /api/v1/system/distribution/share-linksGET /api/v1/projects/{project_id}/distribution/share-linksPOST /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-linksPATCH /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)
- lifecycle revoke/deactivate (can be re-enabled via
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}/eventsPOST /api/v1/projects/{project_id}/exports/{export_package_id}/distribution/sync-jobsGET /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 | expiredcreated_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 (
packageorsingle 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_percentdetail.message
Reference API
GET /api/v1/reference/export-templates- now includes
payload_schemametadata per doc type/template version LIGHTING_PLAN_TEMPLATEtemplate available for A1 CAD viewport composition into001.0layout frame with sidebar metadata fieldsCIRCUIT_SCHEDULEnow includesinclude_dimmerspayload control (defaultfalse)DIMMER_SCHEDULEtemplate available for dimmable-only circuit schedule outputSHOW_POWER_SCHEDULEtemplate available with voltage-based total/domain load summariesSITE_WIDE_CIRCUIT_PATCHtemplate available with patched/unpatched circuit mapping summariesCAT6_PATCH_SHEET,ARTNET_NODE_PATCH_SHEET, andBOQ_ADVICEtemplate contracts are available
- now includes
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
- supports query params:
GET /api/v1/system/permits- supports query params:
status,limit,offset
- supports query params:
GET /api/v1/system/callouts- supports query params:
status,priority,due_from,due_to,limit,offset
- supports query params:
GET /api/v1/system/reports- supports query params:
status,report_type,limit,offset
- supports query params:
GET /api/v1/system/collaboration/threads- supports query params:
status,priority,context_type,limit,offset
- supports query params:
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), anddisabled(true|false)
- supports
Test Scaffolding (v0.5)
apps/api/tests/test_export_service.pyapps/api/tests/test_permit_service.pyapps/api/tests/test_callout_service.pyapps/api/tests/test_report_service.pyapps/api/tests/test_collaboration_service.pyapps/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.pyapps/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.shinfra/scripts/restore-runtime.shinfra/scripts/deploy-compose.sh
Observability env controls:
LOG_LEVEL(defaultINFO)ENABLE_REQUEST_LOGGING(defaulttrue)- API pytest markers:
unitserviceapi_integration
Audit API
GET /api/v1/projects/{project_id}/audit-logs- supports query params:
limit,entity_name,action
- supports query params:
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.jsfor/apiand/health. 001.0CAD 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.0generation is fidelity-locked to vector viewport merge whenever source PDF is available; raster cache is fallback-only.001.0regenerate 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 PACKAGEwithIn PlaceandNew Revisionqueueing 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 PACKAGEis right-aligned in the Deliverables action row for stable control placement.002.0is now wired as upload-only CAD (.dwg) with row-level Upload dialog and regenerate/export rename flow; revision0omits revision suffix in filename while revision1+appendsrev.xx.- CAD upload dialogs now retain and display the original uploaded filename (tracking label) even after regenerate/export applies LOUD output renaming.
- Deliverables row
Uploadnow opens the same upload-dialog pattern for both001.0and002.0(with type-specific file rules:001.0PDF,002.0DWG). Uploadaction is intentionally hidden (with preserved row-action gap alignment) for003.0,004.0,006.0, and020.0.- Deliverables row action label is scope-aware: button shows
Generateuntil first successful render for the currentproject + stage + revision + code, then switches toRegenerate. - 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/Uploadgaps) 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.xCAD template geometry now has a versioned backend manifest authority atapps/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.pdfsuffix on non-PDF files. - Backend now enforces canonical user-facing naming policy for
001.0and002.0generated artifacts (including.dwgextension guarantee for002.0). 002.0generate 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~1names). - CAD template family now includes
001.0,001.H, and001.Lon 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.0and008.0with 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
ISSUEDtick when backend generated-artifact authority confirms an issued file exists for current project/stage/revision/code. - Row-level
Sharenow uses issued-artifact authority (not export-doc-type mapping), so CAD/hybrid rows withdoc_type = nullcan still be shared after regenerate. - Share creation now opens a copy-first modal UX: click link field to copy and auto-close, with explicit
Canceloption. - 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 inapps/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 Designinstead ofCoordinated). - 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 (
001Trade Licence,002RA & MS,003Staff Details,004Insurance,005Venue Specific) using selected venue/staff/company-document refs. - Site Attendance package payloads now include backend-generated
expiry_alertsfor 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)
- per-file download (
- issue action snapshots referenced package files into
- 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)
- distinct venue registry (
- New reporting APIs (system scope):
GET/POST/PATCH /api/v1/system/ops-reporting/venuesGET/POST/PATCH /api/v1/system/ops-reporting/attendance-callsGET/POST/PATCH /api/v1/system/ops-reporting/reportsPOST /api/v1/system/ops-reporting/reports/{report_id}/issue
- UI navigation now includes dedicated
Reportingmodule besideSite 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:11434SITE_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.
- compose service:
- 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_clientsops_quote_venuesops_quote_client_accessops_quote_venue_accessops_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 withExpiry Dateexclusion plus filename fallback (DDMMYYYY) when needed. - notes parser supports
Item DescriptionandDescriptionheadings, 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-clientsGET/POST /api/v1/system/quote-clients/{client_id}/venues(POSTaccepts optionalname_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|revokePOST /api/v1/system/quote-venues/{venue_id}/grant|revokeGET /api/v1/system/quote-venues/{venue_id}/quotesDELETE /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_abbreviationandlocation_abbreviationpersisted onops_quote_venues - when present, these override venue/location tokens in generated quote filenames.
- optional
- 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.
- venue uniqueness is
- dedicated quote entities and grants now exist:
- New
CLIENTrole 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 users can be provisioned via Settings -> Manage Users (
- Client portal quote APIs expanded:
GET /api/v1/client/quote-portal/summaryPOST /api/v1/client/quotes/{quote_id}/archive
- Quotes UI refinement notes (v0.17):
- internal module now uses explicit
Venues / UsersandUploadsplit-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
- dark mode:
- tab title:
- 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/Darkto the left ofSign Out. - compact theme-toggle label in portal mode:
Light/Dark. Project Enginesubtitle remains visible under LOUD logo in compact centered form.
- client quote portal mobile quote rows now display normalized identity:
Venue - LocationQU-*- with quote date value directly underneath.
- quote-row
ArchiveandDownloadactions are right-pushed and held in a stable single-row alignment group. - client portal quote-row actions now stack vertically (
ArchiveaboveDownload) 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
.pdfextension for cleaner UI.
- internal module now uses explicit
- 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
Terminationin 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 Copyper circuit type section:- duplicates the latest line in that type as a starting point
- assigns the next sequential circuit number
- preserves existing
Addbehavior for blank new lines.
- Site Wide Circuit Patch network-row label refinement:
- ETH/FIB PoE field is now labeled
Termination(UI terminology alignment only).
- ETH/FIB PoE field is now labeled
- 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 Copynow supports row-select copy mode:- pressing
Add Copyenters 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 row’s data into the next sequential circuit number, then exits copy mode for that type.
- pressing
- CAD options dialog now supports viewport-file removal for fast alignment iterations:
Remove PDFbutton added besideUploadin001.0CAD 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.
- added explicit bold
- CAD overlay notes heading punctuation update:
- notes heading now renders as
NOTES:(with trailing colon).
- notes heading now renders as
- 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.
- backend project-status value field now renders center/center at:
- 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.
- added bold left-aligned
- CAD overlay party label calibration update:
- added bold left-aligned labels:
Client:atx=734.44,y=210Interior Designer:atx=734.44,y=190
- both top-left anchored,
10pt.
- added bold left-aligned labels:
- CAD overlay title-block label expansion:
- added bold left-aligned labels (top-left anchored,
10pt):Main Contractor:atx=734.44,y=170MEP Contractor:atx=734.44,y=150Lighting Integrator:atx=734.44,y=130As Per Drawing:atx=734.44,y=102Site:atx=734.44,y=69Title:atx=734.44,y=49Scale At A1:atx=734.44,y=29
- added bold left-aligned labels (top-left anchored,
- CAD overlay status/title-block vertical tune:
- moved all fields from
Status:throughRevision:down by2.0mmas a uniform Y shift.
- moved all fields from
- CAD overlay lower title-block refinement (
ScalethroughRevision):- 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).
- moved this subset back up by
- CAD overlay lower title-block micro refinement (
ScalethroughRevision):- moved this subset up by an additional
0.5mm. - reduced label font size by a further
0.1pt(9.8pt->9.7pt).
- moved this subset up by an additional
- CAD overlay consultant/party label typography refinement:
- reduced label size by
0.2ptfor:ClientInterior DesignerMain ContractorMEP ContractorLighting IntegratorAs Per Drawing
- reduced label size by
- CAD overlay consultant/title-block follow-up refinement:
- reduced label size by
0.2ptfor:Lighting ConsultantSiteTitle
- moved this display group up by
0.5mm:Lighting ConsultantClientInterior DesignerMain ContractorMEP ContractorLighting IntegratorSiteTitle
- reduced label size by
- CAD notes heading typography refinement:
- reduced
NOTES:heading font by0.2pt(12.5pt->12.3pt).
- reduced
- CAD status value positional refinement:
- moved project status value field (not
Status:label) up by0.5mm.
- moved project status value field (not
- CAD logo registry workflow (backend-authoritative) is now available:
- added global system logo registry for CAD roles:
ClientInterior DesignerMain ContractorMEP ContractorLighting ConsultantLighting 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
- added global system logo registry for CAD roles:
- 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 Consultantcenter:x=781.02,y=236.6(84x23 slot)Clientcenter:x=781.02,y=198.8(84x11 slot)Interior Designercenter:x=781.02,y=178.93(84x11 slot)Main Contractorcenter:x=781.02,y=158.3(84x11 slot)MEP Contractorcenter:x=781.02,y=138.3(84x11 slot)Lighting Integratorcenter:x=781.02,y=119.4(84x11 slot)
- removed extra logo downscale factor in CAD compositor (
- 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 Clientbutton + modal in Site Access client/venue card. - action writes to the shared quotes clients backend model and refreshes selector list on success.
- added
- Site Access selector metric alignment:
- removed quote-access user pills and quote counters from Site Access selector rows.
- added backend-driven
ACCESS PACKAGEScounters. - quote client/venue system contracts now include
access_package_countcomputed from issued attendance packages.
- Site Access create-action context behavior:
- selector action now switches from
Create ClienttoCreate Venuewhen inside a selected client's venues list. - venue creation uses shared quote venues backend contract.
- selector action now switches from
- 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.
- card 2 heading now set to
- Site Access card 2 staff controls:
- includes
Staffsubheading, search, and scroll list sized for ~5 visible entries. - includes
Add Staffdialog path andRemove Stafflatch mode with per-row red remove trigger. - remove flow confirmed via backend delete endpoint and storage cleanup for associated staff documents.
- includes
- 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
Jobautocomplete source viaGET /api/v1/system/attendance/staff/jobs. - attendance staff contracts now include
job_titlefor create/update/read flows.
- Staff row visual polish:
- remove
Xtrigger now sits fully within row bounds. - each staff row now displays a right-aligned settings cog icon.
- remove
- 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>/...
- endpoint:
- Site Access staff settings workflow baseline:
- cog button now opens
Edit Staff Memberdialog. - top staff details load as read-only by default with explicit
Edit Detailstoggle. Full NameandStaff Coderemain non-editable in edit mode.- upload controls added for
EID,Passport,Visa, andLicences. - licence uploads now persist
license_name+license_abbreviationmetadata and upsert backend licence registry for autocomplete reuse. - backend autocomplete endpoints available:
GET /api/v1/system/attendance/staff/jobsGET /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.
- apply migration
- cog button now opens
- Site Access staff document filename contract (backend-authoritative):
- on upload, staff docs are renamed to:
StaffCode - FullName - Document.ext
Documentuses doc kind (EID,PASSPORT,VISA) and useslicense_namefor 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
idand same stored path/name when present). - slot matching:
EID/PASSPORT/VISA: one slot per kindLICENSE: one slot per license name
- metadata stores
sha256for uploaded file content.
- uploading a document for an existing staff document slot replaces in place (same metadata
- 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.
- on upload, staff docs are renamed to:
- 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 LicenceInsurance CertificateInsurance ScheduleInsurance 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 stateCancel+Confirm Staffactions while selecting- confirmed staff list rendered in grey with staff code/name and license pills
Create Access Packagenow 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/hseGET /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.
- active endpoints:
- 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.
- normalized introduction applicability list markers from
- 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
- primary form template updated to:
- update (2026-02-26, field appearance):
- AcroForm output now enforces
Prepared Nametext-size style for all filled fields exceptVenueandLocation.
- AcroForm output now enforces
- update (2026-02-26, multiline fields):
Project OverviewandExit Routesare 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.
- primary form template updated to:
- update (2026-02-26, alignment tweak):
Prepared Namereceives 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/pythonto 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.
- run the extractor with
- render-mode update:
- compositor now supports
filled_reference_static_basemode 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.
- compositor now supports
- mapping workflow update:
- CAD options now expose a backend-persisted
Template Mappingeditor for001.x-style outputs. - the editor uses a clean structural background generated by backend authority and saves draft text/image field rectangles via system endpoints.
- CAD options now expose a backend-persisted
- active layout authority now begins with:
- 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 remainqueueduntil 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.0backend 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_castorsflag 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
FRONTandSIDEDXF files, and the shared device library underuploads/rack-symbols/devices/syncs complete pairs into a project-global searchable rack item library.