Loud Project Engine and general operations management system.
- Python 56.7%
- JavaScript 37.9%
- CSS 5%
- HTML 0.2%
- 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.22complete: Site Works Report PDFs use the LOUD letterhead content grid with refined typography, bold metadata labels, and a curated sign-off treatmentv0.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 now use the structured/opt/loud-engine/uploads/rack-symbols/devices/frontand/opt/loud-engine/uploads/rack-symbols/devices/sidefolders and sync 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: DeliverablesSHARE PACKAGEnow supports both legacy completed export packages and current generated deliverable artifacts, with a skinned public client download page, individual-file/package download options, and backend download trackingv0.22in progress: Generated Circuit Schedule/Site Wide HP rows now use the HP deep-red schedule palette instead of falling back to HPD greenv0.22in progress: Deliverables020.0 MEP Specificationsnow has an Options flow to upload and choose active shared circuit-type spec PDF versions, then regenerates a merged project MEP specs PDF from the saved Site Wide Circuit Patch type order, with an incomplete cover/page-row pill when source pages are missingv0.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: Generated Circuit Schedule and Site Wide deliverable CSS now includes the deep-redHP - Hot Powerpalette instead of falling back to HPD greenv0.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 usersv0.22in progress: Site Access quick issue now creates a complete issued access package from the selected client/venue/staff, includes active LOUD company documents, generates the HSE PDF, issues the backend package snapshot, creates a public attendance share link, and exposes Copy/Open/Download Package actions.v0.22in progress: Site Access package exports now use the browser-facing attendance share-link origin, flatten generated HSE PDFs, and write issued ZIPs to001 Trade Licence,002 RA & MS,003 Staff Details, and004 Insurancefolders with site-specific documents at the archive root.v0.22closed for current Site Access scope: package history/delete, public package page, MS Agreement, Risk Assessment, ATP Permit + appended Staff List, staff document previews, flattened generated PDFs, and day-first generated document dates are complete for the owner-defined workflow.v0.22Site Access extension: issued package history now hasEditfor marking permits granted; granted permits can be uploaded as PDF/JPEG/PNG, image uploads are converted to PDF, non-ATP permits are placed in the package root, ATP approved permits replace the generated ATP form with the staff-list page appended again, existing ZIP/share downloads are rebuilt, and GRANTED pills show in package history and the public access-package page.v0.22Site Access general permit extension: every issued package now includes a backend-generated, two-page LOUD General Permit Application with universal special-work requirements, client/venue authorization, selected-personnel identity details, optional digital LOUD signature placement, and ATP paperwork retained as an additional venue-specific form.v0.22Deliverables sharing extension:SHARE SELECTEDadded besideSHARE PACKAGE; operators can enter row-selection mode, choose issued generated deliverables, and create one public share link containing only those selected files.v0.22Deliverables revision control: revision dropdown now loads backend project revisions, always keepsRev 0available, opens on the latest revision, and includesNew Revisionto create/switch to a backend revision before uploading or regenerating files.v0.22Deliverables revision isolation follow-up: generated-artifact row state and rendered preview caches are now keyed by project/stage/revision so a new revision cannot inheritISSUEDpills or cached previews from an older revision. New Revision creation also skips revision numbers whose artifact folders already contain generated files from older frontend-only revision runs.v0.22CAD notes/options follow-up:001.xCAD options revision rows now size short fields correctly, the Notes Section editor supports plain-text paste with preserved line breaks, and CAD template PDF notes auto-scale to fit the mapped notes body box. API and worker were restarted after the renderer change so regenerated CAD PDFs use the auto-fit path.v0.22Rack Room Drawing baseline:008.0now has a backend-owned rack-room layout contract, rack-core STEP asset discovery, and a Rack Room / 3D mini-CAD dialog for line/polygon drawing, snapping, door placement, and draggable rack placement next to Edit Rack Layout. The mini-CAD editor now behaves more like real CAD: scroll-zoom-to-cursor, pan (Pan tool / Space-drag / middle-mouse), click-drag or chained wall drawing with ortho/45° snapping, rack rotate snapping, automatic rack-to-wall dimension lines, an adaptive grid, and a live coordinate/length readout (all view-only, contract unchanged). The008.0ISO view is now rendered with EXACT analytic hidden-line (OpenCASCADE via FreeCADTechDraw.projectEx), matching Vectorworks-native quality (opaque, smooth curves, full device detail, no tuning constants). Open blocker: device parts modelled as open shells render see-through (exact HLR needs closed solids); owner to re-export symbols as solids. Surrounding deliverable elements (room, containment, power, dimensions, labels, populated title block) not started - rack element first.- Site Access date convention: human-visible generated document dates are
DD-MM-YYYY/DD/MM/YYYY; filename/date suffix tokens stay sortableYYYYMMDD; month-first display dates are not allowed. - Latest functional code commit before this documentation handoff:
d2a57cb Auto-fit CAD notes text - Current default CAD template:
LOUD GENERAL LIGHTINGfor001.0 - Next focus: new session should start from the current owner priority. Site Access is closed unless package testing reports a specific issue or a new venue-specific form is required.
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).
- Current Site Works Report PDF composition aligns the report title, metadata, body, and sign-off with the supplied letterhead logo/footer margins. Regeneration applies this layout to saved manual or AI-assisted reports without changing their content.
- 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 and side rack element metadata for 600/800/1000 DXF assets, plus a project rack
include_castorsflag so rendered rack height can follow real 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/frontanduploads/rack-symbols/devices/sidesyncs complete pairs into a project-global searchable rack item library. - Rack Drawing rack-power layouts are now backend-persisted per rack and included in the render hash/output. The layout editor saves ordered power items, and generated PDFs reserve a left-side
Lighting Rack Powerpanel when a rack has power entries. - Rack Drawing power DXF assets are expected under
uploads/rack-symbols/power/with the configured namesPOWER-16A.dxf,POWER-32A.dxf,POWER-32A-3PH.dxf,POWER-63A-3PH.dxf,POWER-1PH-ISO.dxf, andPOWER-3PH-ISO.dxf; the renderer falls back to simple vector symbols until those files are supplied. - Rack Drawing side-view device DXFs now align by detected front vertical edge, set back
16mmfrom the side rack left edge, and are clipped to the rack aperture before side rack linework is redrawn. - Rack Drawing symbol names can be edited in the Symbol Library; manual symbol creation requires and preserves the typed name instead of deriving names from filenames.
- Rack Drawing render staleness now includes device asset file fingerprints, so replacing a DXF at the same path causes old PDFs to become stale and the next render uses the new file.