# Professional Management Platform ## Full REST-First System Design Plan > **Revision:** v2 — Review-integrated architecture > **Status:** Implementation-ready baseline, not a claim of regulatory or production certification. > **Primary vertical:** Engineering > **API style:** REST + JSON + OpenAPI 3.1 > **Backend style:** Modular monolith > **Data:** PostgreSQL + profession-specific tables > **Tenant model:** Organization-scoped, explicit tenant context ### Review Integration Notes The external review was incorporated selectively rather than mechanically. Accepted and strengthened: - explicit session management and refresh-token rotation - token reuse detection and revocation - idempotency for high-risk commands - richer engineering design and inspection state machines - legal conflict-check workflow - healthcare record history and access auditing - standardized error taxonomy - permission matrices and credential-aware authorization - layered caching with explicit invalidation - database index conventions - rate-limiting framework - CI/CD, migration compatibility, and deployment gates - OpenAPI contract validation - performance and security test categories Adjusted rather than copied: - tenant-scoped endpoints **always require `X-Organization-Id`**; no silent auto-selection - no extra `X-Organization-Context` header - idempotency is not mandatory for every PATCH; it is required for commands where duplicate execution is dangerous - critical idempotency records are durable in PostgreSQL; Redis may accelerate lookups but is not the sole source of truth - UUIDv7 remains the identifier standard; UUIDv4 `gen_random_uuid()` examples are not adopted - high-risk credential checks are revalidated against authoritative data rather than trusting a stale cache - healthcare prescribing rules are jurisdiction-specific and are not hard-coded to a single profession or U.S.-only credential - signed clinical records are amended/versioned rather than casually overwritten by PATCH - read replicas, materialized views, trigram indexes, and fixed rate-limit numbers are introduced only when workload evidence justifies them - database migrations use expand/contract compatibility; production rollback is not assumed to be a simple reverse migration ## 1. Product Vision Build one shared backend platform that powers multiple profession-specific management applications. Initial professions: - Engineering - Legal - Healthcare Future professions may include accounting, architecture, consulting, property management, veterinary practices, financial advisory, and other regulated or professional-service industries. The core design principle is: > **Share infrastructure, not domain meaning.** Engineering projects, legal matters, and medical patients are fundamentally different concepts and should not be forced into the same universal business table. --- ## 2. Core Architecture Decision The platform will use: - REST - JSON - OpenAPI - Versioned endpoints - PostgreSQL - Modular monolith backend - Profession-specific frontends - Profession-specific database tables - Shared identity, security, billing, documents, audit, and infrastructure Base API path: ```text /api/v1 ``` GraphQL is not part of v1. --- ## 3. High-Level Architecture ```text FRONTENDS ┌──────────────────┼──────────────────┐ │ │ │ Engineering Web Legal Web Healthcare Web │ │ │ └──────────────────┼──────────────────┘ │ ▼ REST API /api/v1 │ ┌───────────┼───────────┐ │ │ │ Core Engineering Legal │ │ │ │ Healthcare │ │ │ │ └───────────┼───────────┘ │ PostgreSQL │ ┌───────────────┼────────────────┐ │ │ │ Shared Tables Profession Tables Audit/Event Tables ``` Shared infrastructure: ```text PostgreSQL Redis Object Storage Queue / Workers Audit Notifications Billing Observability ``` --- ## 4. System Architecture Strategy Start with a modular monolith. Do not start with microservices. Initial deployment: ```text Frontend Apps │ ▼ Backend API │ ├── PostgreSQL ├── Redis ├── Object Storage └── Worker Queue ``` Benefits: - simpler transactions - easier development - easier deployment - clearer domain boundaries - lower operational burden - easier refactoring - future service extraction remains possible --- ## 5. Repository Structure Recommended monorepo: ```text professional-platform/ │ ├── apps/ │ ├── engineering-web/ │ ├── legal-web/ │ ├── healthcare-web/ │ ├── platform-admin/ │ ├── api/ │ └── workers/ │ ├── packages/ │ ├── ui/ │ ├── api-client/ │ ├── auth-client/ │ ├── validation/ │ ├── types/ │ ├── config/ │ └── testing/ │ ├── database/ │ ├── migrations/ │ ├── seeds/ │ └── scripts/ │ ├── infrastructure/ │ ├── docker/ │ ├── deployment/ │ └── monitoring/ │ └── docs/ ├── architecture/ ├── api/ ├── security/ └── domains/ ``` --- ## 6. Frontend Strategy Every profession receives its own frontend application. Avoid one giant frontend filled with profession checks. ### Engineering Frontend Suggested navigation: ```text Dashboard Clients Projects Project Phases Project Team Sites Designs Design Reviews Inspections Specifications Tasks Documents Timesheets Billing Reports Administration ``` ### Legal Frontend Suggested navigation: ```text Dashboard Clients Matters Cases Hearings Courts Deadlines Documents Conflict Checks Time Tracking Retainers Billing Reports Administration ``` ### Healthcare Frontend Suggested navigation: ```text Dashboard Patients Appointments Practitioners Encounters Clinical Records Diagnoses Prescriptions Insurance Documents Billing Reports Administration ``` ### Platform Admin Frontend Suggested functions: ```text Organizations Users Profession Modules Subscriptions System Health Audit Support Global Configuration ``` Platform administrators and organization administrators are separate concepts. --- ## 7. REST API Structure Shared endpoints: ```text /api/v1/auth /api/v1/me /api/v1/organizations /api/v1/memberships /api/v1/membership-invitations /api/v1/roles /api/v1/permissions /api/v1/documents /api/v1/invoices /api/v1/payments /api/v1/audit-events ``` Engineering: ```text /api/v1/engineering/clients /api/v1/engineering/projects /api/v1/engineering/project-members /api/v1/engineering/phases /api/v1/engineering/sites /api/v1/engineering/tasks /api/v1/engineering/designs /api/v1/engineering/inspections /api/v1/engineering/specifications /api/v1/engineering/time-entries ``` Legal: ```text /api/v1/legal/clients /api/v1/legal/matters /api/v1/legal/cases /api/v1/legal/hearings /api/v1/legal/deadlines /api/v1/legal/conflict-checks /api/v1/legal/retainers /api/v1/legal/time-entries ``` Healthcare: ```text /api/v1/healthcare/patients /api/v1/healthcare/practitioners /api/v1/healthcare/appointments /api/v1/healthcare/encounters /api/v1/healthcare/clinical-records /api/v1/healthcare/diagnoses /api/v1/healthcare/prescriptions /api/v1/healthcare/insurance ``` --- ## 8. REST Conventions All APIs use JSON over HTTPS. Typical tenant-scoped request: ```http Authorization: Bearer X-Organization-Id: org_123 X-Request-Id: req_123 Content-Type: application/json ``` ### Organization Context `X-Organization-Id` is mandatory for every tenant-scoped endpoint. It is deliberately explicit even when a user currently belongs to only one organization. Silent organization selection creates ambiguous clients and becomes dangerous the moment the user later joins a second organization. Global endpoints such as these do not require tenant context: ```http POST /api/v1/auth/login POST /api/v1/auth/token/refresh GET /api/v1/me GET /api/v1/me/organizations GET /api/v1/auth/sessions ``` Tenant-context resolution rules: ```yaml Organization Context: header_missing_on_tenant_endpoint: status: 400 code: ORGANIZATION_CONTEXT_REQUIRED organization_not_found: status: 404 code: RESOURCE_NOT_FOUND membership_not_found: status: 404 code: RESOURCE_NOT_FOUND membership_inactive: status: 403 code: AUTHZ_MEMBERSHIP_INACTIVE organization_inactive: status: 403 code: AUTHZ_ORGANIZATION_INACTIVE resource.organization_id_mismatch: status: 404 code: RESOURCE_NOT_FOUND ``` Do not return another organization's name or membership details in tenant-error responses. ### Idempotency Use: ```http Idempotency-Key: 8f7d6c5e-4b3a-2b1c-9d8e-7f6a5b4c3d2e ``` Idempotency is required for commands where duplicate execution can create financial, regulated, external, or otherwise material side effects. Examples: ```http POST /api/v1/invoices POST /api/v1/invoices/{id}/payments POST /api/v1/payments/{id}/refund POST /api/v1/engineering/designs/{id}/approve POST /api/v1/engineering/inspections/{id}/complete POST /api/v1/legal/retainers POST /api/v1/legal/conflict-checks/{id}/approve POST /api/v1/healthcare/prescriptions POST /api/v1/healthcare/clinical-records/{id}/sign ``` Do not require idempotency on every ordinary PATCH by default. Idempotency records must include: ```text organization_id actor_id route/action idempotency_key canonical_request_hash response_status response_body or resource reference created_at expires_at ``` Rules: ```yaml Same key + same operation + same request hash: return: original result Same key + different request hash: status: 409 code: IDEMPOTENCY_KEY_CONFLICT ``` Durability: - PostgreSQL is authoritative for critical idempotency records. - Redis may cache recent records for speed. - Redis eviction must not make a payment or regulated command executable twice. - Downstream providers should receive their own idempotency key where supported. ## 9. Standard Response Format Single resource: ```json { "data": { "id": "project_123", "name": "Central Tower" } } ``` Collection: ```json { "data": [], "meta": { "pagination": { "nextCursor": null, "hasMore": false } } } ``` Standard error: ```json { "error": { "code": "RESOURCE_NOT_FOUND", "message": "Resource not found.", "details": {}, "requestId": "req_123" } } ``` Clients depend on `error.code`, not message text. ### Error Taxonomy Authentication: ```text AUTH_INVALID_CREDENTIALS AUTH_TOKEN_EXPIRED AUTH_TOKEN_INVALID AUTH_MFA_REQUIRED AUTH_SESSION_REVOKED AUTH_REFRESH_TOKEN_REUSED ``` Authorization: ```text AUTHZ_PERMISSION_DENIED AUTHZ_ORGANIZATION_INACTIVE AUTHZ_MEMBERSHIP_INACTIVE AUTHZ_CREDENTIAL_INVALID AUTHZ_SCOPE_MISMATCH ``` Tenant context: ```text ORGANIZATION_CONTEXT_REQUIRED ``` Resource/state: ```text RESOURCE_NOT_FOUND RESOURCE_ALREADY_EXISTS RESOURCE_CONCURRENT_MODIFICATION RESOURCE_INVALID_STATE RESOURCE_ARCHIVED ``` Validation: ```text VALIDATION_ERROR VALIDATION_REQUIRED_FIELD VALIDATION_INVALID_FORMAT VALIDATION_BUSINESS_RULE ``` Idempotency: ```text IDEMPOTENCY_KEY_REQUIRED IDEMPOTENCY_KEY_CONFLICT ``` Rate limiting: ```text RATE_LIMIT_EXCEEDED ``` System/dependency: ```text INTERNAL_ERROR SERVICE_UNAVAILABLE DATABASE_UNAVAILABLE DEPENDENCY_FAILED ``` Validation example: ```json { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed.", "requestId": "req_123", "details": { "fields": [ { "field": "email", "code": "INVALID_FORMAT", "message": "Must be a valid email address" } ] } } } ``` Business-state example: ```json { "error": { "code": "RESOURCE_INVALID_STATE", "message": "Cannot approve design in current state.", "requestId": "req_123", "details": { "resourceType": "engineering_design", "resourceId": "design_123", "currentState": "draft", "requiredState": "under_review", "allowedActions": [ "submit_review" ] } } } ``` Do not expose internal stack traces, SQL, policy internals, secrets, or cross-tenant information. ## 10. HTTP Status Rules ```text 200 Success 201 Created 202 Accepted 204 No Content 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 409 Conflict 422 Validation Error 429 Too Many Requests 500 Internal Server Error ``` Cross-tenant resource access should return 404. --- ## 11. API Versioning Current API: ```text /api/v1 ``` Breaking changes require: ```text /api/v2 ``` Additive fields generally do not require a new version. --- ## 12. Authentication Initial authentication: ```text Email + Password + Access Token + Refresh Token + Server-side Session ``` Endpoints: ```http POST /api/v1/auth/register POST /api/v1/auth/login POST /api/v1/auth/token/refresh POST /api/v1/auth/token/revoke POST /api/v1/auth/token/revoke-all GET /api/v1/auth/sessions DELETE /api/v1/auth/sessions/{sessionId} GET /api/v1/me ``` ### Access Token Policy ```yaml Access Token: lifetime: 15 minutes format: signed JWT encrypted: false preferred_signing: asymmetric key or managed signing service claims: - subject/userId - sessionId - issuer - audience - issuedAt - expiresAt organizationId: optional: true authority: false ``` If `organizationId` appears in the token, it is a convenience hint only. The request header and active membership still determine tenant context. Do not embed the user's full permission set into long-lived access tokens. ### Refresh Token Policy ```yaml Refresh Token: lifetime: 7 days format: cryptographically random opaque token storage: hashed rotation: every successful refresh sliding_expiration: configurable reuse_detection: required ``` If a previously rotated refresh token is reused: 1. treat it as possible token theft 2. revoke the token family/session 3. optionally revoke all user sessions according to risk policy 4. generate a security audit event 5. require reauthentication ### Session Model Suggested fields: ```text id user_id refresh_token_family_id refresh_token_hash device_id device_type device_os app_version ip_address user_agent created_at last_active_at expires_at revoked_at revocation_reason ``` Example response: ```json { "data": { "id": "sess_123", "userId": "user_456", "deviceInfo": { "type": "mobile", "os": "iOS", "appVersion": "2.1.0", "deviceId": "device_789" }, "createdAt": "2026-08-20T12:00:00Z", "lastActiveAt": "2026-08-26T01:30:00Z", "expiresAt": "2026-08-27T12:00:00Z", "isActive": true } } ``` Do not trust user-supplied device metadata as security proof. It is session context and audit information. Future authentication capabilities: - MFA - passkeys/WebAuthn - SSO - OAuth/OIDC - enterprise identity providers - risk-based authentication ## 13. Shared Core Backend Recommended modules: ```text core/ ├── auth/ ├── users/ ├── organizations/ ├── memberships/ ├── roles/ ├── permissions/ ├── authorization/ ├── documents/ ├── billing/ ├── notifications/ ├── audit/ └── events/ ``` Dependency rule: ```text Profession module → Core ``` Never: ```text Core → Profession module ``` --- ## 14. Organizations Organizations are tenants. Examples: ```text Atlas Structural Engineering Smith & Associates Law North Shore Medical Practice ``` Suggested fields: ```text id name slug status country_code timezone currency_code created_at updated_at ``` --- ## 15. Profession Enablement Use: ```text organization_professions ``` Suggested fields: ```text organization_id profession enabled_at configuration ``` Possible professions: ```text engineering legal healthcare ``` An organization may eventually enable more than one profession module. --- ## 16. Users and Memberships Users are global identities. A user gains tenant access through membership. ```text User │ ▼ Membership │ ▼ Organization ``` Suggested `users` fields: ```text id email first_name last_name phone avatar_url status created_at updated_at ``` Suggested `memberships` fields: ```text id organization_id user_id status joined_at created_at updated_at ``` --- ## 17. Membership Invitations Keep invitations separate from memberships. Suggested table: ```text membership_invitations ``` Fields: ```text id organization_id email invited_by_user_id expires_at accepted_at revoked_at created_at ``` Flow: ```text Invitation ↓ Accepted ↓ User ↓ Membership ``` --- ## 18. Authorization Use: ```text RBAC + Permission Scope + Resource Policies + Professional Qualification Policies + Domain State Rules ``` Decision flow: ```text Authenticated User ↓ Explicit Organization Context ↓ Active Membership ↓ Enabled Profession Module ↓ Roles ↓ Permissions ↓ Permission Scope ↓ Tenant-scoped Resource Query ↓ Resource Policy ↓ Credential/Jurisdiction Policy ↓ Domain State Rule ↓ ALLOW / DENY ``` Default decision: ```text DENY ``` Authorization rules: 1. Controllers never perform ad-hoc role comparisons. 2. Tenant resource queries always include `organization_id`. 3. Do not load an arbitrary resource first and then discover it belongs to another tenant. 4. High-risk professional actions perform credential checks at command execution time. 5. A permission grants the ability to attempt an action, not a guarantee the domain state allows it. 6. Cross-tenant resources appear nonexistent. 7. Profession module enablement is checked before profession-specific authorization. ## 19. Roles and Permissions Roles are organization-scoped collections of permissions. Example roles: ```text Owner Administrator Project Manager Engineer Reviewer Inspector Lawyer Paralegal Doctor Nurse Billing Manager Viewer ``` Roles are not professional credentials. ### Engineering Permissions ```text engineering.clients.read engineering.clients.create engineering.clients.update engineering.clients.archive engineering.projects.read engineering.projects.create engineering.projects.update engineering.projects.activate engineering.projects.close engineering.projects.archive engineering.project_members.manage engineering.phases.manage engineering.tasks.manage engineering.sites.manage engineering.documents.read engineering.documents.upload engineering.documents.delete engineering.designs.read engineering.designs.create engineering.designs.update engineering.designs.review engineering.designs.approve engineering.designs.reject engineering.designs.supersede engineering.inspections.read engineering.inspections.manage engineering.inspections.complete engineering.time_entries.manage engineering.reports.read ``` ### Legal Permissions ```text legal.clients.read legal.clients.create legal.clients.update legal.matters.read legal.matters.create legal.matters.update legal.matters.close legal.matters.reopen legal.cases.read legal.cases.manage legal.hearings.manage legal.deadlines.manage legal.documents.read legal.documents.upload legal.conflicts.manage legal.conflicts.approve legal.retainers.manage legal.time_entries.manage ``` ### Healthcare Permissions ```text healthcare.patients.read healthcare.patients.create healthcare.patients.update healthcare.appointments.read healthcare.appointments.manage healthcare.encounters.read healthcare.encounters.manage healthcare.records.read healthcare.records.write healthcare.records.sign healthcare.records.amend healthcare.records.access_log.read healthcare.prescriptions.read healthcare.prescriptions.write healthcare.prescriptions.sign healthcare.insurance.read healthcare.insurance.manage ``` ### Shared Permissions ```text documents.read documents.upload billing.read invoices.create invoices.issue invoices.void payments.record payments.refund members.read members.invite members.update members.remove roles.read roles.manage audit.read ``` Avoid vague permissions such as `admin_everything` in normal tenant RBAC. ## 20. Permission Scopes Initial scopes: ```text assigned organization ``` Examples: ```text Engineer: engineering.projects.read = assigned Principal Engineer: engineering.projects.read = organization ``` Potential future scopes: ```text owned team department restricted ``` Do not implement until required. --- ## 21. Professional Credentials Professional qualification is separate from RBAC. Suggested shared profile: ```text professional_profiles ``` Fields: ```text id organization_id user_id profession title credential_status primary_license_number primary_license_jurisdiction valid_from expires_at created_at updated_at ``` Profession modules may add dedicated credential tables when one generic profile is insufficient. ### Credential Policy Examples Engineering design approval may require: ```yaml permission: engineering.designs.approve credential: profession_family: engineering status: verified active_license: true jurisdiction_match: when required discipline_match: when required ``` Healthcare record signing may require: ```yaml permission: healthcare.records.sign credential: profession_allowed_by_policy: true status: verified active_license: true scope_of_practice_allows_action: true jurisdiction_match: true ``` Prescribing must **not** be hard-coded to `profession = doctor` or to a single U.S. credential such as a DEA number. Prescribing authority varies by: - jurisdiction - profession - drug class - supervising relationship - organization policy - credential status Therefore use a policy concept such as: ```text PrescribingAuthorityPolicy ``` rather than a permanent global rule. ### Cache Safety Credential status may be cached briefly for ordinary reads, but high-risk writes such as: ```text engineering.designs.approve healthcare.records.sign healthcare.prescriptions.sign ``` must use authoritative or revocation-aware credential validation. A five-minute stale cache is unacceptable if a license was just suspended. ## 22. Database Architecture Use PostgreSQL. Start with: ```text One database + Shared schema + Profession-specific tables ``` Do not begin with database-per-profession or database-per-customer unless compliance or residency requirements force that choice. --- ## 23. Shared Tables Recommended shared tables: ```text organizations organization_professions users user_credentials sessions memberships membership_invitations roles permissions role_permissions membership_roles professional_profiles documents document_versions invoices invoice_items payments notifications notification_deliveries audit_events outbox_events ``` --- ## 24. Multi-Tenancy Rule Every tenant-owned row must contain: ```text organization_id ``` Examples: ```text engineering_projects.organization_id legal_matters.organization_id healthcare_patients.organization_id ``` Enforce tenant boundaries at: - API layer - authorization layer - repository/query layer - database constraints --- ## 25. Tenant-Safe Foreign Keys Use composite tenant-aware foreign keys when possible. Example: ```text engineering_projects organization_id client_id ``` references: ```text engineering_clients organization_id id ``` This prevents linking a resource from one organization to another organization's data. --- # Engineering Domain ## 26. Engineering Tables Initial tables: ```text engineering_clients engineering_projects engineering_project_members engineering_project_phases engineering_sites engineering_tasks engineering_designs engineering_design_versions engineering_design_reviews engineering_inspections engineering_inspection_findings engineering_specifications engineering_change_requests engineering_time_entries ``` --- ## 27. Engineering Clients Suggested fields: ```text id organization_id client_type display_name legal_name contact_name email phone address_line_1 address_line_2 city region postal_code country_code status created_at updated_at version ``` REST: ```http GET /api/v1/engineering/clients POST /api/v1/engineering/clients GET /api/v1/engineering/clients/{clientId} PATCH /api/v1/engineering/clients/{clientId} POST /api/v1/engineering/clients/{clientId}/archive POST /api/v1/engineering/clients/{clientId}/restore GET /api/v1/engineering/clients/{clientId}/projects GET /api/v1/engineering/clients/{clientId}/invoices ``` A client may only be restored if retention and organization policy permit it. Example response: ```json { "data": { "id": "client_123", "organizationId": "org_456", "clientType": "commercial", "displayName": "Riverside Development Corp", "legalName": "Riverside Development Corporation LLC", "contactName": "Jane Williams", "email": "jwilliams@example.com", "phone": "+15125551234", "address": { "line1": "789 Riverside Dr", "city": "Austin", "region": "TX", "postalCode": "78701", "country": "US" }, "status": "active", "version": 1, "createdAt": "2026-08-20T10:00:00Z", "updatedAt": "2026-08-26T01:00:00Z" } } ``` ## 28. Engineering Projects Suggested fields: ```text id organization_id client_id project_number name description discipline stage status project_manager_user_id start_date expected_completion_date completed_date budget_minor currency_code created_at updated_at version ``` REST: ```http GET /api/v1/engineering/projects POST /api/v1/engineering/projects GET /api/v1/engineering/projects/{projectId} PATCH /api/v1/engineering/projects/{projectId} POST /api/v1/engineering/projects/{projectId}/activate POST /api/v1/engineering/projects/{projectId}/close POST /api/v1/engineering/projects/{projectId}/archive ``` Purpose-built read models may be added when the frontend requires them: ```http GET /api/v1/engineering/projects/{projectId}/summary GET /api/v1/engineering/projects/{projectId}/timeline GET /api/v1/engineering/projects/{projectId}/budget ``` These are read-model endpoints, not necessarily separate aggregate tables. Do not put arbitrary budget-breakdown JSON into the core project row merely because the response can display it. Model detailed budget data in dedicated tables when that feature is implemented. ## 29. Engineering Project Members Suggested fields: ```text id organization_id project_id user_id project_role joined_at left_at ``` REST: ```http GET /api/v1/engineering/projects/{projectId}/members POST /api/v1/engineering/projects/{projectId}/members PATCH /api/v1/engineering/projects/{projectId}/members/{memberId} DELETE /api/v1/engineering/projects/{projectId}/members/{memberId} ``` --- ## 30. Engineering Project Phases Suggested fields: ```text id organization_id project_id name sequence status start_date end_date created_at updated_at ``` Typical phases: ```text Concept Preliminary Design Detailed Design Construction Inspection Closeout ``` REST: ```http GET /api/v1/engineering/projects/{projectId}/phases POST /api/v1/engineering/projects/{projectId}/phases PATCH /api/v1/engineering/projects/{projectId}/phases/{phaseId} POST /api/v1/engineering/projects/{projectId}/phases/{phaseId}/complete ``` --- ## 31. Engineering Sites Suggested fields: ```text id organization_id project_id name address latitude longitude created_at updated_at ``` REST: ```http POST /api/v1/engineering/projects/{projectId}/sites GET /api/v1/engineering/projects/{projectId}/sites GET /api/v1/engineering/sites/{siteId} PATCH /api/v1/engineering/sites/{siteId} ``` --- ## 32. Engineering Tasks Suggested fields: ```text id organization_id project_id title description status priority created_by_user_id assigned_to_user_id due_at completed_at created_at updated_at version ``` REST: ```http POST /api/v1/engineering/tasks GET /api/v1/engineering/tasks GET /api/v1/engineering/tasks/{taskId} PATCH /api/v1/engineering/tasks/{taskId} POST /api/v1/engineering/tasks/{taskId}/complete POST /api/v1/engineering/tasks/{taskId}/reopen POST /api/v1/engineering/tasks/{taskId}/cancel ``` --- ## 33. Engineering Designs Suggested fields: ```text id organization_id project_id design_number title description discipline status owner_user_id prepared_by_user_id approved_by_user_id approved_at created_at updated_at version ``` States: ```text draft under_review changes_requested approved rejected superseded ``` REST: ```http GET /api/v1/engineering/projects/{projectId}/designs POST /api/v1/engineering/projects/{projectId}/designs GET /api/v1/engineering/designs/{designId} PATCH /api/v1/engineering/designs/{designId} POST /api/v1/engineering/designs/{designId}/submit-review POST /api/v1/engineering/designs/{designId}/request-changes POST /api/v1/engineering/designs/{designId}/approve POST /api/v1/engineering/designs/{designId}/reject POST /api/v1/engineering/designs/{designId}/supersede GET /api/v1/engineering/designs/{designId}/versions POST /api/v1/engineering/designs/{designId}/versions GET /api/v1/engineering/designs/{designId}/reviews POST /api/v1/engineering/designs/{designId}/reviews ``` ### Design State Machine ```text draft └── submit-review ───────────────► under_review under_review ├── request-changes ─────────────► changes_requested ├── approve ─────────────────────► approved └── reject ──────────────────────► rejected changes_requested └── submit-review ───────────────► under_review approved └── supersede ───────────────────► superseded rejected └── revise ──────────────────────► draft ``` Authorization policy examples: ```yaml submit_review: permissions: - engineering.designs.review resource_policy: - design owner OR project manager request_changes: permissions: - engineering.designs.review approve: permissions: - engineering.designs.approve requires: - project access - valid professional qualification - valid design state - organization approval policy reject: permissions: - engineering.designs.reject supersede: permissions: - engineering.designs.supersede ``` Design approval must be audited and idempotent. Do not approve by generic PATCH of `status`. ## 34. Design Versions and Reviews `engineering_design_versions`: ```text id design_id version_number document_id created_by_user_id created_at ``` `engineering_design_reviews`: ```text id organization_id design_id reviewer_user_id status comments reviewed_at ``` Possible review statuses: ```text pending approved changes_requested rejected ``` --- ## 35. Engineering Inspections Suggested fields: ```text id organization_id project_id site_id inspection_type inspector_user_id status scheduled_at started_at performed_at cancelled_at summary created_at updated_at version ``` REST: ```http GET /api/v1/engineering/projects/{projectId}/inspections POST /api/v1/engineering/projects/{projectId}/inspections GET /api/v1/engineering/inspections/{inspectionId} PATCH /api/v1/engineering/inspections/{inspectionId} POST /api/v1/engineering/inspections/{inspectionId}/schedule POST /api/v1/engineering/inspections/{inspectionId}/start POST /api/v1/engineering/inspections/{inspectionId}/complete POST /api/v1/engineering/inspections/{inspectionId}/cancel GET /api/v1/engineering/inspections/{inspectionId}/findings POST /api/v1/engineering/inspections/{inspectionId}/findings ``` Example state model: ```text draft └── schedule ─────► scheduled scheduled ├── start ────────► in_progress └── cancel ───────► cancelled in_progress ├── complete ─────► completed └── cancel ───────► cancelled ``` Inspection completion is a domain command that should: 1. validate inspector/project access 2. validate required findings/fields 3. update state 4. write audit event 5. write outbox event 6. trigger follow-up workflows if required ## 36. Inspection Findings Suggested fields: ```text id inspection_id severity description status resolved_at ``` Possible severities: ```text observation minor major critical ``` REST: ```http POST /api/v1/engineering/inspections/{inspectionId}/findings PATCH /api/v1/engineering/inspection-findings/{findingId} POST /api/v1/engineering/inspection-findings/{findingId}/resolve ``` --- ## 37. Engineering Specifications Suggested fields: ```text id organization_id project_id specification_number title version status document_id created_at updated_at ``` --- ## 38. Engineering Change Requests Suggested fields: ```text id organization_id project_id request_number title description status requested_by_user_id approved_by_user_id estimated_cost_minor created_at updated_at ``` --- ## 39. Engineering Time Entries Suggested fields: ```text id organization_id project_id user_id work_date duration_minutes description billable billing_rate_minor currency_code created_at updated_at ``` REST: ```http POST /api/v1/engineering/time-entries GET /api/v1/engineering/time-entries GET /api/v1/engineering/time-entries/{id} PATCH /api/v1/engineering/time-entries/{id} ``` Store duration as integer minutes. --- # Legal Domain ## 40. Legal Tables Initial tables: ```text legal_clients legal_matters legal_matter_members legal_cases legal_case_parties legal_courts legal_hearings legal_deadlines legal_documents legal_time_entries legal_retainers legal_conflict_checks legal_conflict_parties legal_conflict_matches ``` REST namespace: ```text /api/v1/legal ``` Core examples: ```http GET /api/v1/legal/matters POST /api/v1/legal/matters GET /api/v1/legal/matters/{matterId} PATCH /api/v1/legal/matters/{matterId} POST /api/v1/legal/matters/{matterId}/close POST /api/v1/legal/matters/{matterId}/reopen GET /api/v1/legal/matters/{matterId}/cases GET /api/v1/legal/matters/{matterId}/documents GET /api/v1/legal/matters/{matterId}/time-entries GET /api/v1/legal/matters/{matterId}/invoices POST /api/v1/legal/conflict-checks GET /api/v1/legal/conflict-checks/{conflictCheckId} POST /api/v1/legal/conflict-checks/{conflictCheckId}/approve POST /api/v1/legal/conflict-checks/{conflictCheckId}/decline ``` Legal remains a later vertical. These endpoints define intended boundaries, not a P0 build commitment. ## 41. Legal Matters Suggested fields: ```text id organization_id client_id matter_number title practice_area responsible_lawyer_user_id status opened_date closed_date created_at updated_at ``` --- ## 42. Legal Cases Suggested fields: ```text id organization_id matter_id case_number court_id jurisdiction case_type status filed_date created_at updated_at ``` --- ## 43. Legal Hearings Suggested fields: ```text id organization_id case_id hearing_type scheduled_at courtroom judge status notes ``` --- ## 44. Legal Conflict Checks Suggested tables: ```text legal_conflict_checks legal_conflict_parties legal_conflict_matches ``` Conflict-check fields: ```text id organization_id potential_client_name matter_description requested_by_user_id reviewed_by_user_id status decision decision_reason created_at reviewed_at version ``` Request example: ```json { "potentialClientName": "Acme Corporation", "relatedParties": [ { "name": "John Smith", "relationship": "CEO" }, { "name": "Acme Subsidiary LLC", "relationship": "Subsidiary" } ], "matterDescription": "Corporate acquisition" } ``` Response may contain possible matches: ```json { "data": { "id": "conflict_123", "status": "pending_review", "potentialConflicts": [ { "type": "possible_direct_adversity", "partyName": "Acme Corporation", "existingMatterId": "matter_456", "existingMatterNumber": "MAT-2026-089" } ] } } ``` The system should distinguish: ```text automated possible match ``` from: ```text lawyer-approved conflict determination ``` The software may assist discovery; it should not silently make the professional judgment. Approvals and declines are auditable commands. ## 45. Healthcare Tables Initial tables: ```text healthcare_patients healthcare_patient_contacts healthcare_patient_addresses healthcare_practitioners healthcare_appointments healthcare_encounters healthcare_clinical_records healthcare_clinical_record_versions healthcare_clinical_record_amendments healthcare_diagnoses healthcare_prescriptions healthcare_insurance_policies healthcare_allergies healthcare_medications ``` REST namespace: ```text /api/v1/healthcare ``` Examples: ```http GET /api/v1/healthcare/patients POST /api/v1/healthcare/patients GET /api/v1/healthcare/patients/{patientId} PATCH /api/v1/healthcare/patients/{patientId} POST /api/v1/healthcare/patients/{patientId}/archive GET /api/v1/healthcare/patients/{patientId}/appointments GET /api/v1/healthcare/patients/{patientId}/encounters GET /api/v1/healthcare/patients/{patientId}/clinical-records GET /api/v1/healthcare/patients/{patientId}/prescriptions GET /api/v1/healthcare/patients/{patientId}/allergies POST /api/v1/healthcare/encounters POST /api/v1/healthcare/encounters/{encounterId}/clinical-records GET /api/v1/healthcare/clinical-records/{recordId} GET /api/v1/healthcare/clinical-records/{recordId}/history GET /api/v1/healthcare/clinical-records/{recordId}/access-log POST /api/v1/healthcare/clinical-records/{recordId}/sign POST /api/v1/healthcare/clinical-records/{recordId}/amend ``` Healthcare is intentionally not treated as ordinary CRM plus extra columns. ## 46. Healthcare Patients Core patient fields: ```text id organization_id patient_number first_name middle_name last_name date_of_birth sex_or_administrative_gender_as_required status created_at updated_at version ``` Do not make a single default patient DTO return every available PHI field. Use minimum-necessary response shapes. Example general patient response: ```json { "data": { "id": "patient_123", "patientNumber": "PAT-2026-001", "name": { "firstName": "Alice", "middleName": "Marie", "lastName": "Johnson" }, "dateOfBirth": "1985-03-15", "status": "active", "version": 2 } } ``` More sensitive subresources should have separate permissions and endpoints where useful: ```text contact information addresses emergency contacts insurance policies clinical records prescriptions ``` Do not return insurance member IDs or emergency contact details on every patient read merely because the database has them. ## 47. Healthcare Practitioners Suggested fields: ```text id organization_id user_id specialty license_number license_jurisdiction credential_status created_at updated_at ``` --- ## 48. Healthcare Appointments Suggested fields: ```text id organization_id patient_id practitioner_id appointment_type starts_at ends_at status reason created_at updated_at ``` --- ## 49. Healthcare Encounters Suggested fields: ```text id organization_id patient_id practitioner_id appointment_id encounter_type started_at ended_at status ``` --- ## 50. Clinical Records Suggested tables: ```text healthcare_clinical_records healthcare_clinical_record_versions healthcare_clinical_record_amendments ``` Core record fields: ```text id organization_id patient_id encounter_id author_practitioner_id record_type sensitivity_level status signed_by_practitioner_id signed_at created_at updated_at version ``` Draft content may be editable according to workflow. Once signed/finalized: - do not overwrite history - create amendments or new versions - preserve previous signed content - audit reads when policy requires - audit all writes/signatures/amendments REST: ```http POST /api/v1/healthcare/encounters/{encounterId}/clinical-records GET /api/v1/healthcare/clinical-records/{recordId} PATCH /api/v1/healthcare/clinical-records/{recordId} # Only when editable/draft according to policy. POST /api/v1/healthcare/clinical-records/{recordId}/sign POST /api/v1/healthcare/clinical-records/{recordId}/amend GET /api/v1/healthcare/clinical-records/{recordId}/history GET /api/v1/healthcare/clinical-records/{recordId}/access-log ``` Clinical content representation should be designed around actual healthcare requirements and interoperability needs rather than permanently committing to one ad-hoc JSON SOAP-note structure. Sensitive record access should support an `accessReason` when organization or regulatory policy requires it. ## 51. Documents Use shared object storage. Database: ```text documents document_versions ``` Actual binary files: ```text S3-compatible Object Storage ``` Suggested `documents` fields: ```text id organization_id name mime_type size_bytes created_by_user_id created_at updated_at ``` Suggested `document_versions` fields: ```text id document_id version_number storage_key checksum size_bytes uploaded_by_user_id created_at ``` --- ## 52. Document Upload Flow ```text Frontend ↓ Request upload URL ↓ Backend authorizes ↓ Signed upload URL ↓ Frontend uploads to object storage ↓ Backend finalizes document ↓ Virus/security scan ↓ Document becomes available ``` REST: ```http POST /api/v1/documents/upload-url POST /api/v1/documents/{documentId}/complete-upload GET /api/v1/documents/{documentId} GET /api/v1/documents/{documentId}/download-url POST /api/v1/documents/{documentId}/versions ``` --- ## 53. Profession-Specific Document Links Use explicit tables where possible. Engineering: ```text engineering_project_documents engineering_design_documents engineering_inspection_documents ``` Legal: ```text legal_matter_documents legal_case_documents ``` Healthcare: ```text healthcare_patient_documents healthcare_encounter_documents ``` This gives stronger foreign-key integrity than generic polymorphic document links. --- ## 54. Billing Shared financial core: ```text invoices invoice_items payments ``` Profession-specific modules may extend billing workflows. Engineering examples: ```text project billing hourly billing milestone billing ``` Legal examples: ```text matter billing time billing retainers trust accounting ``` Healthcare examples: ```text insurance claims patient billing ``` REST: ```http POST /api/v1/invoices GET /api/v1/invoices GET /api/v1/invoices/{invoiceId} PATCH /api/v1/invoices/{invoiceId} POST /api/v1/invoices/{invoiceId}/issue POST /api/v1/invoices/{invoiceId}/void POST /api/v1/invoices/{invoiceId}/payments POST /api/v1/payments/{paymentId}/refund ``` --- ## 55. Money Representation Use integer minor units: ```json { "amountMinor": 12550, "currency": "USD" } ``` Meaning: ```text $125.50 ``` Never use floating point for money. --- ## 56. Audit Logging Table: ```text audit_events ``` Suggested fields: ```text id organization_id actor_type actor_user_id actor_service_account_id action resource_type resource_id request_id correlation_id ip_address user_agent metadata occurred_at ``` Audit events are append-only. ### Mandatory Engineering Audit Events ```text engineering.projects.create engineering.projects.close engineering.designs.approve engineering.designs.reject engineering.designs.supersede engineering.inspections.complete ``` ### Mandatory Legal Audit Events ```text legal.matters.create legal.matters.close legal.matters.reopen legal.conflicts.approve legal.conflicts.decline legal.retainers.manage ``` ### Mandatory Healthcare Audit Events ```text healthcare.records.read healthcare.records.write healthcare.records.sign healthcare.records.amend healthcare.prescriptions.write healthcare.prescriptions.sign ``` Example: ```json { "id": "audit_123", "organizationId": "org_456", "actorUserId": "user_789", "action": "healthcare.records.read", "resourceType": "healthcare_clinical_record", "resourceId": "record_456", "requestId": "req_abc", "ipAddress": "192.0.2.10", "userAgent": "Mozilla/5.0", "metadata": { "patientId": "patient_123", "recordType": "progress_note", "accessReason": "clinical_review" }, "occurredAt": "2026-08-26T01:30:00Z" } ``` Audit metadata must never contain: - passwords - access or refresh tokens - full clinical note content - secret keys - unnecessary payment data REST: ```http GET /api/v1/audit-events ``` No public create/update/delete endpoints. ## 57. Domain Events and Transactional Outbox Profession modules produce internal domain events. Examples: ```text engineering.project.created engineering.design.approved engineering.inspection.completed legal.matter.closed legal.conflict_check.approved healthcare.appointment.created healthcare.clinical_record.signed invoice.issued payment.recorded ``` Consumers: ```text notifications webhooks analytics search indexing integrations background workflows ``` Use: ```text outbox_events ``` Suggested fields: ```text id organization_id event_type aggregate_type aggregate_id payload occurred_at available_at processed_at attempt_count last_error dead_lettered_at ``` Correct transaction pattern: ```text BEGIN business change audit event outbox event COMMIT ``` The outbox component does **not** own or prematurely commit the caller's business transaction. Workers claim committed outbox rows using a safe concurrency strategy such as: ```sql SELECT ... FROM outbox_events WHERE processed_at IS NULL AND available_at <= now() ORDER BY occurred_at FOR UPDATE SKIP LOCKED LIMIT ... ``` Worker behavior: 1. claim event 2. execute handler 3. mark processed on success 4. increment attempt count on failure 5. apply exponential/backoff policy 6. dead-letter after configured failure threshold 7. preserve enough metadata for replay and diagnosis A best-effort post-commit notification may wake workers, but workers must also poll. Otherwise a lost wake-up can strand committed events forever. Event consumers must be idempotent. ## 58. Background Jobs Workers handle: ```text Email SMS Notifications Report generation PDF generation File scanning Document processing Imports Exports Webhook delivery Search indexing Large data operations ``` Architecture: ```text API ↓ Queue ↓ Worker ``` --- ## 59. Redis Use Redis as an acceleration and coordination layer, not the authoritative system of record. Appropriate uses: ```text job queue rate-limit counters short-lived authorization caches organization configuration cache session lookup acceleration idempotency lookup acceleration distributed locks when justified ``` ### Cache Layers L1 optional application-memory cache: ```text static permission definitions non-sensitive configuration ``` L2 Redis shared cache: ```text organization settings membership snapshots role permission snapshots rate-limit counters session lookup cache recent idempotency lookups ``` CDN: ```text frontend static assets explicitly public assets only ``` Do not cache private professional API responses at a CDN by default. ### Cache Invalidation Invalidate or version caches when: ```text membership changes role permissions change organization settings change professional credentials change session is revoked profession module enablement changes ``` High-risk authorization decisions must not depend solely on stale cached credential state. ### Idempotency Durability Redis may improve idempotency lookup latency, but PostgreSQL remains authoritative for high-risk commands. ## 60. Pagination Use cursor pagination. Example: ```http GET /api/v1/engineering/projects?limit=25 ``` Response: ```json { "data": [], "meta": { "pagination": { "nextCursor": "...", "hasMore": true } } } ``` Maximum page size: ```text 100 ``` --- ## 61. Filtering Use explicit resource-specific filters. Examples: ```http GET /api/v1/engineering/projects?status=active&discipline=structural GET /api/v1/engineering/tasks?status=todo&assignedToUserId=user_123 ``` Do not build a generic query DSL in v1. --- ## 62. Sorting Examples: ```http GET /api/v1/engineering/projects?sort=createdAt GET /api/v1/engineering/projects?sort=-createdAt ``` Only explicitly supported fields may be sorted. --- ## 63. Search Start with PostgreSQL search. Engineering search may cover: ```text project number project name client name ``` Legal: ```text matter number client case number ``` Healthcare: ```text patient number patient identity ``` Healthcare search requires stricter privacy and authorization controls. Potential PostgreSQL capabilities: - B-tree indexes for exact/filter queries - PostgreSQL full-text search where appropriate - `pg_trgm` only when fuzzy search requirements justify it Do not introduce Elasticsearch/OpenSearch until real query volume, relevance requirements, or indexing features justify another distributed system. Do not create every conceivable search index on day one. Indexes cost memory, storage, and write performance. ## 64. Optimistic Concurrency Important mutable resources should use a version field. Example: ```json { "id": "project_123", "version": 6 } ``` Update: ```json { "version": 6, "name": "Central Tower Phase II" } ``` If the current database version differs: ```text 409 CONCURRENT_MODIFICATION ``` --- ## 65. Domain-Oriented REST Important state transitions use explicit command endpoints. Good: ```http POST /engineering/projects/{id}/close POST /engineering/designs/{id}/approve POST /engineering/tasks/{id}/complete POST /engineering/inspections/{id}/complete POST /invoices/{id}/issue ``` Avoid: ```http PATCH /resource/{id} { "status": "approved" } ``` when the change has significant rules or side effects. --- ## 66. Transaction Boundaries Create project: ```text BEGIN create project assign project manager write audit event write outbox event COMMIT ``` Approve design: ```text BEGIN validate permission validate project access validate credentials validate design state create review result mark approved write audit event write outbox event COMMIT ``` --- ## 67. Request Context Every authenticated request should resolve: ```text RequestContext { requestId userId sessionId organizationId membershipId permissions } ``` Profession modules consume this context. --- ## 68. Request IDs Every request has: ```http X-Request-Id ``` If missing, the server generates one. Use it in: - logs - audit context - error diagnostics - asynchronous correlation --- ## 69. OpenAPI Maintain: ```text openapi.yaml ``` Use OpenAPI 3.1. Production server example: ```yaml servers: - url: https://api.example.com/api/v1 ``` The server URL and path definitions must remain consistent with the platform base path. OpenAPI defines: - routes - request DTOs - response DTOs - security schemes - organization header - request IDs - idempotency header - pagination - filters - error schemas - examples - profession tags Security scheme: ```yaml components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT ``` Reusable headers/parameters: ```text X-Organization-Id X-Request-Id Idempotency-Key limit cursor ``` CI must validate the OpenAPI document. Contract tests should detect drift between implementation and specification. Generated clients may be used by the separate frontends, but generated transport code should not dictate frontend domain architecture. ## 70. DTO Rule Database models are not public API contracts. Use: ```text Request DTO Response DTO ``` A database migration should not accidentally change the public API. --- ## 71. Backend Module Structure Recommended: ```text src/ ├── core/ │ ├── auth/ │ ├── organizations/ │ ├── memberships/ │ ├── authorization/ │ ├── documents/ │ ├── billing/ │ ├── audit/ │ └── events/ │ ├── engineering/ │ ├── clients/ │ ├── projects/ │ ├── project-members/ │ ├── phases/ │ ├── sites/ │ ├── tasks/ │ ├── designs/ │ ├── inspections/ │ └── specifications/ │ ├── legal/ │ ├── clients/ │ ├── matters/ │ ├── cases/ │ ├── hearings/ │ ├── conflicts/ │ └── retainers/ │ └── healthcare/ ├── patients/ ├── practitioners/ ├── appointments/ ├── encounters/ ├── records/ └── prescriptions/ ``` --- ## 72. Internal Module Structure Example: ```text projects/ ├── domain/ │ ├── project.entity.ts │ ├── project-status.ts │ └── project.errors.ts │ ├── application/ │ ├── commands/ │ │ ├── create-project.ts │ │ ├── update-project.ts │ │ └── close-project.ts │ │ │ └── queries/ │ ├── get-project.ts │ └── list-projects.ts │ ├── infrastructure/ │ └── project.repository.ts │ └── api/ ├── project.controller.ts ├── project.request.ts └── project.response.ts ``` --- ## 73. Controllers Controllers should handle: ```text HTTP authentication context input DTO parsing application command/query invocation response mapping ``` Controllers should not contain: ```text business rules raw SQL role logic transaction orchestration email sending audit implementation ``` --- ## 74. Commands and Queries Mutations use commands. Examples: ```text CreateEngineeringProjectCommand ApproveEngineeringDesignCommand CloseLegalMatterCommand CompleteHealthcareEncounterCommand ``` Reads use queries. Examples: ```text GetEngineeringProjectQuery ListLegalMattersQuery GetHealthcarePatientQuery ``` --- ## 75. Repositories Use domain-specific repositories. Examples: ```text EngineeringProjectRepository LegalMatterRepository HealthcarePatientRepository ``` Avoid one massive generic repository abstraction that eventually needs dozens of flags. --- ## 76. Security Baseline Minimum controls: ```text TLS everywhere strong password hashing short-lived access tokens refresh-token rotation refresh-token reuse detection server-side session revocation rate limiting RBAC resource policies credential-aware authorization tenant isolation input validation SQL injection protection signed object-storage URLs virus/malware scanning for uploaded files audit trails secret management encryption at rest dependency scanning security headers request/correlation IDs backup and restore testing ``` ### Rate Limiting Framework Rate limits are endpoint-specific policy, not permanent architecture constants. Required categories: ```text authentication attempts password reset/recovery general authenticated API traffic search file upload initiation expensive report generation clinical record access webhook/API integration traffic ``` Use Redis-backed counters or a managed gateway. Responses: ```http 429 Too Many Requests Retry-After: ... ``` Use: ```text RATE_LIMIT_EXCEEDED ``` in the error body. Authentication endpoints should have substantially stricter anti-abuse controls than ordinary reads. Healthcare record access may require anomaly detection beyond simple rate limits. Exact numeric limits are established through load testing, product usage, and security analysis, not copied from a design review. ### Secrets Production secrets should live in a managed secret/key system where possible. Avoid treating a checked-in `.env` file as secret management. Prefer asymmetric JWT signing or managed signing keys where practical, with rotation support. ## 77. Data Classification Suggested classes: ### Public ```text marketing configuration ``` ### Internal ```text organization settings tasks ``` ### Confidential ```text engineering documents legal matters billing ``` ### Highly Sensitive ```text clinical records professional credentials authentication secrets ``` --- ## 78. Healthcare Security Before healthcare production use, define: ```text privacy model minimum-necessary access model clinical access policies break-glass/emergency access policy if required audit policy record-signing policy amendment policy retention policy credential policy scope-of-practice policy jurisdiction requirements encryption strategy consent requirements data residency requirements backup/restore handling export/portability requirements breach-response requirements ``` Healthcare is a stricter security tier. Key rules: 1. default patient responses do not contain all available PHI 2. clinical record reads may be auditable events 3. signed records are immutable except through explicit amendment/version workflows 4. prescribing authorization is jurisdiction-specific 5. privileged clinical commands revalidate professional authority 6. caches must not allow revoked credentials to remain effective for high-risk writes 7. healthcare search results themselves are protected data 8. access logs may require dedicated permissions 9. do not claim regulatory compliance from architecture alone ## 79. Observability Use: ```text structured logs metrics distributed tracing request IDs correlation IDs ``` Recommended: ```text OpenTelemetry ``` Track: ```text API latency error rate database latency database connection pool saturation queue depth outbox backlog worker failures authentication failures refresh-token reuse detections authorization denials credential-policy denials rate-limit events external dependency failures file-processing failures ``` ### Performance SLOs Define performance targets per environment and endpoint class. Do not hard-code claims such as "100k-row list query under 100 ms" or "100 MB upload under 30 seconds" into architecture without measurement. Direct-to-object-storage upload performance depends heavily on client network and storage provider. Establish: ```text p50 p95 p99 error budget throughput concurrency ``` from realistic load tests. Reporting endpoints may have different SLOs from interactive CRUD endpoints. ## 80. Logging Useful fields: ```text request_id route method status duration user_id when appropriate organization_id when appropriate ``` Never log: ```text passwords tokens clinical record text full sensitive documents payment secrets ``` --- ## 81. Testing Strategy ### Unit Tests Test: ```text domain rules state transitions authorization policies credential policies money calculations idempotency request hashing ``` ### Integration Tests Test: ```text repositories PostgreSQL constraints tenant-aware foreign keys transactions outbox persistence idempotency persistence cache invalidation hooks ``` ### API Tests Every important endpoint should cover: ```text happy path request validation authentication organization context permission denial scope denial credential denial where relevant cross-tenant access concurrent modification invalid state transition idempotent replay idempotency conflict audit event creation outbox event creation ``` ### Engineering Design Approval Tests At minimum: ```text qualified assigned approver → success missing permission → 403 invalid credential → 403 wrong organization → 404 wrong state → 422/409 according to contract duplicate idempotency key + same payload → same result duplicate idempotency key + different payload → 409 approval creates audit event approval creates outbox event ``` ### Healthcare Record Tests At minimum: ```text authorized record read → success + audit where required unauthorized practitioner → deny wrong organization → 404 signed record direct overwrite → deny amendment creates preserved history access-log permission enforced credential revocation blocks high-risk command immediately ``` ### Performance Tests Create workload profiles rather than one universal test: ```text interactive reads interactive writes search dashboard read models reporting file-upload orchestration outbox processing notification bursts ``` Record p50/p95/p99 latency and database saturation. Targets become release gates only after a realistic baseline is established. ## 82. Tenant Security Tests For every major resource, attempt: ```text Organization A resource using Organization B context ``` Test: ```text read update delete/action list filtering search documents ``` Expected result: ```text 404 / denied ``` --- ## 83. Engineering MVP Engineering is the first vertical. Initial features: ```text Authentication Organization management Users / memberships / roles Engineering clients Projects Project members Project phases Tasks Sites Documents Basic design records Inspections Time entries Basic billing Audit history ``` Do not initially build: ```text advanced CAD integration BIM integration full document markup advanced resource planning procurement complex accounting AI design analysis IoT integrations ``` --- ## 84. Engineering MVP Workflow ```text User registers ↓ Creates engineering organization ↓ Invites engineer ↓ Assigns role ↓ Creates client ↓ Creates project ↓ Assigns project team ↓ Creates project phases ↓ Creates tasks ↓ Uploads documents ↓ Creates design ↓ Reviews / approves design ↓ Schedules inspection ↓ Records inspection findings ↓ Records engineering time ↓ Creates invoice ↓ Records payment ↓ Closes project ↓ Audit history contains lifecycle ``` --- ## 85. Development Phases ### Phase 0: Architecture Foundation Deliver: ```text domain boundaries database conventions REST conventions authorization model organization-context rules session/token policy idempotency strategy error taxonomy OpenAPI skeleton engineering state machines migration conventions threat model ``` ### Phase 1: Shared Platform Core Build: ```text auth sessions token rotation and revocation users organizations organization professions membership invitations memberships roles permissions authorization audit outbox request context idempotency persistence rate-limit framework ``` ### Phase 2: Engineering CRM Build: ```text engineering_clients client archive/restore client-project relationship ``` ### Phase 3: Engineering Projects Build: ```text engineering_projects engineering_project_members engineering_project_phases project activation/close/archive commands ``` ### Phase 4: Work Management Build: ```text engineering_tasks engineering_sites ``` ### Phase 5: Documents Build: ```text documents document_versions object storage signed uploads malware scanning engineering document links ``` ### Phase 6: Designs Build: ```text engineering_designs engineering_design_versions engineering_design_reviews explicit design state machine credential-aware approval approval audit/outbox/idempotency ``` ### Phase 7: Inspections Build: ```text engineering_inspections inspection state machine engineering_inspection_findings follow-ups attachments completion audit/outbox/idempotency ``` ### Phase 8: Time and Billing Build: ```text engineering_time_entries invoices invoice_items payments financial idempotency provider reconciliation ``` ### Phase 9: Notifications Build: ```text in-app notifications email worker processing retry/dead-letter handling ``` ### Phase 10: Reporting and Search Initial reports: ```text project status overdue tasks inspection status billable time revenue outstanding invoices ``` Add advanced indexes, materialized views, read replicas, or external search only if measurement justifies them. ### Phase 11: Legal Vertical Implement legal domain only after shared core assumptions survive the engineering product. ### Phase 12: Healthcare Readiness Before implementation: ```text healthcare threat model privacy review jurisdiction analysis credential/scope-of-practice policy record signing/amendment model retention model audit requirements ``` Then build the healthcare vertical. ## 86. Legal Expansion Only after engineering proves the shared platform assumptions. Build: ```text Legal Client ↓ Matter ↓ Case ↓ Hearings / Deadlines / Documents ``` Do not redesign engineering around legal terminology. Extract only genuinely reusable infrastructure. --- ## 87. Healthcare Expansion Healthcare comes after: - core platform is stable - audit model is proven - permission model is proven - tenant isolation is tested - retention and encryption strategies are defined Healthcare should be treated as its own security and compliance workstream. --- ## 88. Deployment Environments Use: ```text development testing staging production ``` Each environment has independent: ```text database object storage secrets queues API keys ``` --- ## 89. Initial Deployment Architecture ```text CDN │ ├── Engineering Web ├── Legal Web └── Healthcare Web Load Balancer │ Backend API │ ├── PostgreSQL ├── Redis ├── Object Storage └── Queue │ Workers ``` Prefer managed infrastructure where practical. --- ## 90. Backup Strategy Database: ```text automated backups point-in-time recovery tested restores ``` Object storage: ```text versioning retention policies backup or replication where required ``` A backup strategy is incomplete until restoration is tested. --- ## 91. Migration Strategy Use explicit immutable migration files. Recommended naming: ```text YYYYMMDDHHMMSS_description.sql ``` Example: ```text 20260826010000_create_organizations.sql 20260826011000_create_users.sql 20260826012000_create_memberships.sql 20260826013000_create_rbac.sql 20260826014000_create_audit_outbox.sql 20260826015000_create_engineering_clients.sql ``` ### UUID Standard The platform standard remains UUIDv7. Do not silently switch to PostgreSQL `gen_random_uuid()` if that produces UUIDv4 and violates the identifier convention. Generate UUIDv7 in the application or use a database UUIDv7 implementation whose behavior is explicitly controlled and tested. ### Production Migration Rules Use expand/contract migration patterns: ```text 1. add backward-compatible schema 2. deploy code supporting old + new schema 3. migrate/backfill data 4. switch reads/writes 5. remove obsolete schema in a later deployment ``` Do not assume every production migration can be cleanly rolled back by executing a reverse SQL file. For destructive changes: - backup/restore plan - compatibility window - dry run on production-like data - explicit operational approval Never use automatic ORM schema synchronization in production. ## 92. Technology Recommendation Backend: ```text TypeScript NestJS or Fastify-based architecture ``` Database: ```text PostgreSQL ``` ORM/query layer candidates: ```text Prisma Drizzle Kysely ``` Frontend: ```text React / Next.js ``` Queue: ```text Redis + BullMQ ``` Storage: ```text S3-compatible storage ``` Observability: ```text OpenTelemetry ``` Containers: ```text Docker ``` --- ## 93. REST API Milestones ### Milestone 1: Platform Access and Security ```http POST /auth/register POST /auth/login POST /auth/token/refresh POST /auth/token/revoke POST /auth/token/revoke-all GET /auth/sessions DELETE /auth/sessions/{sessionId} GET /me POST /organizations GET /me/organizations POST /membership-invitations GET /memberships GET /roles POST /roles GET /permissions ``` Includes: ```text explicit organization context session revocation refresh-token reuse detection audit foundation outbox foundation idempotency foundation rate limiting ``` ### Milestone 2: Engineering Clients ```http GET /engineering/clients POST /engineering/clients GET /engineering/clients/{id} PATCH /engineering/clients/{id} POST /engineering/clients/{id}/archive POST /engineering/clients/{id}/restore GET /engineering/clients/{id}/projects ``` ### Milestone 3: Engineering Projects ```http GET /engineering/projects POST /engineering/projects GET /engineering/projects/{id} PATCH /engineering/projects/{id} POST /engineering/projects/{id}/activate POST /engineering/projects/{id}/close POST /engineering/projects/{id}/archive GET /engineering/projects/{id}/summary ``` Timeline and budget read models follow when the frontend requires them. ### Milestone 4: Collaboration ```http POST /engineering/projects/{id}/members GET /engineering/projects/{id}/members POST /engineering/tasks GET /engineering/tasks POST /engineering/tasks/{id}/complete ``` ### Milestone 5: Sites and Documents Build: ```text engineering sites signed file uploads document versions malware scanning project document links ``` ### Milestone 6: Designs Build: ```text design lifecycle versions reviews submit-review request-changes approve reject supersede credential validation audit + outbox + idempotency ``` ### Milestone 7: Inspections Build: ```text schedule start complete cancel findings finding resolution audit + outbox + idempotency ``` ### Milestone 8: Commercial Workflows Build: ```text time entries invoices payments refunds financial idempotency reports ``` ## 94. Architecture Rules to Freeze 1. REST is the primary frontend and integration API. 2. Base path is `/api/v1`. 3. OpenAPI 3.1 is the public REST contract. 4. GraphQL is not part of v1. 5. One shared backend platform is deployed initially as a modular monolith. 6. Each profession has a separate frontend application. 7. Each profession owns its domain tables and state machines. 8. Shared modules contain infrastructure, not forced cross-profession business semantics. 9. Every tenant-owned row has `organization_id`. 10. Tenant-scoped endpoints require explicit `X-Organization-Id`. 11. The API never silently chooses a tenant. 12. Tenant isolation is enforced in queries and database relationships. 13. Cross-tenant resources appear nonexistent. 14. Authorization is server-side and deny-by-default. 15. Roles and professional qualifications are separate. 16. High-risk professional actions revalidate authoritative credential state. 17. Healthcare prescribing authority is jurisdiction/policy driven, not hard-coded to one profession. 18. Signed clinical records use version/amendment workflows, not destructive overwrite. 19. Important state changes use explicit REST command endpoints. 20. Important/regulated mutations are audited. 21. Clinical record reads are auditable where policy requires. 22. Domain events use a transactional outbox. 23. Outbox consumers are idempotent. 24. High-risk POST commands use durable idempotency records. 25. Redis may accelerate idempotency but is not the sole source of truth for financial/regulated commands. 26. PostgreSQL is the authoritative application datastore. 27. UUIDv7 is the identifier standard. 28. Files live in object storage and use signed access. 29. File uploads support security scanning before availability. 30. Background side effects run through workers. 31. Cache invalidation is explicit for memberships, roles, sessions, module settings, and credentials. 32. Do not trust stale credential caches for regulated write authorization. 33. Rate limits are endpoint-specific policies calibrated by testing. 34. Search starts in PostgreSQL. 35. Materialized views, read replicas, external search, and specialized indexes require workload evidence. 36. Database models and public DTOs are separate contracts. 37. API collections use cursor pagination. 38. Mutable important resources use optimistic concurrency. 39. Do not replace proper domain modeling with arbitrary JSON blobs. 40. Do not hard-delete professional or financial records without explicit retention rules. 41. Production migrations follow expand/contract compatibility. 42. Do not assume destructive migrations are trivially reversible. 43. Secrets are managed outside source control. 44. CI validates OpenAPI, tests, migrations, types, and security checks. 45. Engineering remains the first product vertical. 46. Legal follows after the engineering platform proves shared assumptions. 47. Healthcare requires an explicit security/privacy/compliance readiness review before implementation. 48. Architecture documentation must distinguish "designed for" from "certified/compliant". ## 95. Required Design Artifacts Prepare and maintain: ```text 01_PROJECT_ARCHITECTURE.md 02_DATABASE_CONVENTIONS.md 03_AUTHORIZATION_MODEL.md 04_ENGINEERING_DOMAIN.md 05_ENGINEERING_DATABASE_SCHEMA.md 06_API_CONVENTIONS.md 07_ENGINEERING_API_SPEC.md 08_FRONTEND_ARCHITECTURE.md 09_SECURITY_MODEL.md 10_DEPLOYMENT_ARCHITECTURE.md 11_TESTING_STRATEGY.md 12_MVP_BACKLOG.md 13_OPENAPI.yaml ``` --- ## 96. Recommended Implementation Order ```text Foundation ↓ Authentication ↓ Organizations ↓ Memberships ↓ RBAC ↓ Engineering Clients ↓ Engineering Projects ↓ Project Team ↓ Tasks ↓ Sites ↓ Documents ↓ Designs ↓ Inspections ↓ Time Tracking ↓ Billing ↓ Notifications ↓ Reports ↓ Legal Vertical ↓ Healthcare Vertical ``` --- ## 97A. Database Indexing Strategy All tenant-owned tables should have an index supporting tenant lookup. Baseline patterns: ```text (organization_id, id) (organization_id, created_at) ``` Add query-specific indexes based on real access patterns: ```text (organization_id, status) (organization_id, client_id) (organization_id, project_id) (organization_id, assigned_to_user_id) ``` Rules: 1. every index must correspond to a known query or constraint 2. composite index order follows the actual WHERE/ORDER BY pattern 3. verify with `EXPLAIN (ANALYZE, BUFFERS)` on representative data 4. do not index every column 5. index write cost is part of the decision 6. full-text/trigram indexes are introduced when search requirements are known Read replicas and materialized views are later scaling tools, not baseline dependencies. --- ## 97B. CI/CD and Deployment Gates Pipeline stages: ```text lint/typecheck ↓ unit tests ↓ integration tests ↓ OpenAPI validation + contract tests ↓ security/dependency scan ↓ container build + image scan ↓ migration compatibility check ↓ deploy development ↓ smoke tests ↓ deploy staging ↓ E2E + performance/security baseline ↓ manual production approval ↓ production deployment ↓ post-deploy verification ``` Production deployment should support: ```text rolling or blue/green application deployment backward-compatible database migrations health checks fast application rollback feature flags for incomplete features observability gates ``` Database schema rollback is not treated as equivalent to application rollback. ### Configuration and Secrets Non-secret configuration may use environment variables. Secrets should use a managed secret store where possible: ```text database credentials Redis credentials JWT/private signing keys object storage credentials SMTP/API provider credentials monitoring credentials ``` Do not publish real secrets in sample configuration. Organization profession enablement remains primarily data-driven through `organization_professions`. Global feature flags may be used for staged rollout, kill switches, or incomplete features. --- ## 97C. Review-Driven Deferred Decisions The following ideas are valid possibilities but are explicitly **not frozen into v1**: ```text read replicas materialized views Elasticsearch/OpenSearch universal 100 MB file limit fixed 100 req/min user limit fixed 1000 req/hour organization limit specific cache-hit-ratio target specific p95 latency promise database-per-tenant microservices GraphQL ``` These require evidence from: ```text load tests security analysis customer requirements compliance requirements real production workloads ``` This prevents benchmark-shaped guesses from becoming architecture law. --- ## 97. Final Design Position The platform is not a generic management system with profession names painted on top. It is: ```text One Shared Platform │ ├── Shared Identity ├── Shared Security ├── Shared Infrastructure ├── Shared Documents ├── Shared Financial Core ├── Shared Audit/Event Platform │ ├── Engineering Product │ ├── Engineering Frontend │ ├── Engineering REST APIs │ └── Engineering Tables │ ├── Legal Product │ ├── Legal Frontend │ ├── Legal REST APIs │ └── Legal Tables │ └── Healthcare Product ├── Healthcare Frontend ├── Healthcare REST APIs └── Healthcare Tables ``` The system shares infrastructure where reuse is valuable while preserving independent domain models where professional workflows differ. This document is an implementation-ready architectural baseline. It is **not** by itself proof of production readiness, regulatory compliance, security certification, or performance at a particular scale. Those claims require implementation evidence, threat modeling, testing, operational controls, and profession/jurisdiction-specific review.