From b4fdf18d074c7b7fe3ebf6b6c045021f8a8f6cf6 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 27 Aug 2026 21:52:21 -0400 Subject: [PATCH] add more design improvement --- healthcare-api-foundation_4.yaml | 1778 ++++ mermaid-diagram (1).png | Bin 0 -> 177894 bytes mermaid-diagram.png | Bin 0 -> 722990 bytes professional-platform-openapi_1.yaml | 5041 ++++++++++ professional-platform-openapi_10.yaml | 8778 +++++++++++++++++ professional-platform-openapi_2.yaml | 3010 ++++++ professional-platform-openapi_3.yaml | 3848 ++++++++ professional-platform-openapi_4.yaml | 5041 ++++++++++ professional-platform-openapi_5.yaml | 5737 +++++++++++ professional-platform-openapi_6.yaml | 6373 ++++++++++++ professional-platform-openapi_7.yaml | 7025 +++++++++++++ professional-platform-openapi_8.yaml | 7350 ++++++++++++++ professional-platform-openapi_9.yaml | 7964 +++++++++++++++ professional_management_platform_rest_plan.md | 3163 ++++++ ...sional_management_platform_rest_plan_v2.md | 4581 +++++++++ ...sional_management_platform_rest_plan_v3.md | 5679 +++++++++++ ...sional_management_platform_rest_plan_v4.md | 6298 ++++++++++++ ...onal_management_platform_rest_plan_v4_1.md | 6642 +++++++++++++ ...onal_management_platform_rest_plan_v4_2.md | 6773 +++++++++++++ ...onal_management_platform_rest_plan_v4_3.md | 6773 +++++++++++++ ...onal_management_platform_rest_plan_v4_5.md | 7236 ++++++++++++++ 21 files changed, 109090 insertions(+) create mode 100644 healthcare-api-foundation_4.yaml create mode 100644 mermaid-diagram (1).png create mode 100644 mermaid-diagram.png create mode 100644 professional-platform-openapi_1.yaml create mode 100644 professional-platform-openapi_10.yaml create mode 100644 professional-platform-openapi_2.yaml create mode 100644 professional-platform-openapi_3.yaml create mode 100644 professional-platform-openapi_4.yaml create mode 100644 professional-platform-openapi_5.yaml create mode 100644 professional-platform-openapi_6.yaml create mode 100644 professional-platform-openapi_7.yaml create mode 100644 professional-platform-openapi_8.yaml create mode 100644 professional-platform-openapi_9.yaml create mode 100644 professional_management_platform_rest_plan.md create mode 100644 professional_management_platform_rest_plan_v2.md create mode 100644 professional_management_platform_rest_plan_v3.md create mode 100644 professional_management_platform_rest_plan_v4.md create mode 100644 professional_management_platform_rest_plan_v4_1.md create mode 100644 professional_management_platform_rest_plan_v4_2.md create mode 100644 professional_management_platform_rest_plan_v4_3.md create mode 100644 professional_management_platform_rest_plan_v4_5.md diff --git a/healthcare-api-foundation_4.yaml b/healthcare-api-foundation_4.yaml new file mode 100644 index 0000000..356d27b --- /dev/null +++ b/healthcare-api-foundation_4.yaml @@ -0,0 +1,1778 @@ +openapi: 3.1.0 +info: + title: Professional Platform Healthcare API + version: 0.2.0-openemr-informed + summary: Clean-room healthcare identity and encounter API. + description: | + A proprietary healthcare API informed by established EHR workflows and public + interoperability standards. This contract does not copy OpenEMR source code, + database structures, or API routes. + + This foundation intentionally covers patients, practitioners, and encounters + only. Clinical records, diagnoses, allergies, medications, prescriptions, + appointments, insurance, claims, and billing require separate threat models + and domain contracts. + + Every operation is tenant scoped. Cross-tenant identifiers return 404. + Mutable resources use ETags and require If-Match. Creation and commands use + Idempotency-Key. Responses containing patient data must not be cached. + contact: + name: Healthcare API Team +servers: + - url: https://api.example.com/api/v1 + description: Production + - url: https://sandbox-api.example.com/api/v1 + description: Sandbox +tags: + - name: Healthcare Patients + - name: Healthcare Practitioners + - name: Healthcare Encounters + - name: Healthcare Locations + - name: Healthcare Appointments + - name: Healthcare Allergies + - name: Healthcare Conditions + - name: Healthcare Medications + - name: Healthcare Clinical Records + +security: + - bearerAuth: [] + +paths: + /healthcare/patients: + get: + tags: [Healthcare Patients] + operationId: listHealthcarePatients + summary: List patients using minimum-necessary projections + description: | + Search results are protected health information. By default, this operation + returns only the summary projection. Access is audited. Free-text searching + across clinical content is prohibited. + x-permission: healthcare.patients.read + x-audit-event: healthcare.patient.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/Cursor' + - $ref: '#/components/parameters/PageSize' + - name: patientNumber + in: query + schema: {type: string, maxLength: 64} + - name: familyName + in: query + schema: {type: string, maxLength: 120} + - name: birthDate + in: query + schema: {type: string, format: date} + - name: status + in: query + schema: {$ref: '#/components/schemas/PatientStatus'} + responses: + '200': + description: Patient summaries. + headers: + Cache-Control: {$ref: '#/components/headers/NoStore'} + X-Request-Id: {$ref: '#/components/headers/RequestId'} + content: + application/json: + schema: {$ref: '#/components/schemas/PatientListResponse'} + '401': {$ref: '#/components/responses/Unauthorized'} + '403': {$ref: '#/components/responses/Forbidden'} + '422': {$ref: '#/components/responses/ValidationError'} + post: + tags: [Healthcare Patients] + operationId: createHealthcarePatient + summary: Create a patient + description: | + The service performs deterministic duplicate screening within the tenant. + A suspected match returns PATIENT_POSSIBLE_DUPLICATE and requires an + authorized human to resolve it. Names alone never trigger automatic merging. + x-permission: healthcare.patients.create + x-audit-event: healthcare.patient.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/PatientCreate'} + responses: + '201': + description: Patient created. + headers: + Location: {$ref: '#/components/headers/Location'} + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + X-Request-Id: {$ref: '#/components/headers/RequestId'} + content: + application/json: + schema: {$ref: '#/components/schemas/PatientResponse'} + '401': {$ref: '#/components/responses/Unauthorized'} + '403': {$ref: '#/components/responses/Forbidden'} + '409': {$ref: '#/components/responses/Conflict'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/patients/{patientId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + get: + tags: [Healthcare Patients] + operationId: getHealthcarePatient + summary: Retrieve a patient + x-permission: healthcare.patients.read + x-audit-event: healthcare.patient.read + responses: + '200': + description: Patient record. + headers: + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + X-Request-Id: {$ref: '#/components/headers/RequestId'} + content: + application/json: + schema: {$ref: '#/components/schemas/PatientResponse'} + '401': {$ref: '#/components/responses/Unauthorized'} + '403': {$ref: '#/components/responses/Forbidden'} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Patients] + operationId: updateHealthcarePatient + summary: Update patient demographics + description: Patient number, organization, status, and archival fields are not patchable. + x-permission: healthcare.patients.update + x-audit-event: healthcare.patient.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/merge-patch+json: + schema: {$ref: '#/components/schemas/PatientPatch'} + responses: + '200': + description: Patient updated. + headers: + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + X-Request-Id: {$ref: '#/components/headers/RequestId'} + content: + application/json: + schema: {$ref: '#/components/schemas/PatientResponse'} + '401': {$ref: '#/components/responses/Unauthorized'} + '403': {$ref: '#/components/responses/Forbidden'} + '404': {$ref: '#/components/responses/NotFound'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/patients/{patientId}/archive: + post: + tags: [Healthcare Patients] + operationId: archiveHealthcarePatient + summary: Archive a duplicate or erroneous patient shell + description: | + Archival never deletes clinical history. A patient with encounters may only + be archived after an authorized reconciliation workflow confirms the target. + x-permission: healthcare.patients.archive + x-audit-event: healthcare.patient.archived + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/ReasonCommand'} + responses: + '200': + description: Patient archived. + headers: + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + content: + application/json: + schema: {$ref: '#/components/schemas/PatientResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/patients/{patientId}/restore: + post: + tags: [Healthcare Patients] + operationId: restoreHealthcarePatient + summary: Restore an archived patient + x-permission: healthcare.patients.archive + x-audit-event: healthcare.patient.restored + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + responses: + '200': + description: Patient restored. + headers: + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + content: + application/json: + schema: {$ref: '#/components/schemas/PatientResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/practitioners: + get: + tags: [Healthcare Practitioners] + operationId: listHealthcarePractitioners + summary: List practitioners + x-permission: healthcare.practitioners.read + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/Cursor' + - $ref: '#/components/parameters/PageSize' + - name: status + in: query + schema: {$ref: '#/components/schemas/PractitionerStatus'} + responses: + '200': + description: Practitioners. + content: + application/json: + schema: {$ref: '#/components/schemas/PractitionerListResponse'} + '401': {$ref: '#/components/responses/Unauthorized'} + '403': {$ref: '#/components/responses/Forbidden'} + post: + tags: [Healthcare Practitioners] + operationId: createHealthcarePractitioner + summary: Create a practitioner assignment + description: | + The referenced user must have an active organization membership. Credential + records remain authoritative in the shared professional credential registry. + x-permission: healthcare.practitioners.manage + x-audit-event: healthcare.practitioner.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/PractitionerCreate'} + responses: + '201': + description: Practitioner assignment created. + headers: + Location: {$ref: '#/components/headers/Location'} + ETag: {$ref: '#/components/headers/ETag'} + content: + application/json: + schema: {$ref: '#/components/schemas/PractitionerResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/practitioners/{practitionerId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PractitionerId' + get: + tags: [Healthcare Practitioners] + operationId: getHealthcarePractitioner + summary: Retrieve a practitioner + x-permission: healthcare.practitioners.read + responses: + '200': + description: Practitioner. + headers: {ETag: {$ref: '#/components/headers/ETag'}} + content: + application/json: + schema: {$ref: '#/components/schemas/PractitionerResponse'} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Practitioners] + operationId: updateHealthcarePractitioner + summary: Update practitioner specialty or status + description: userId and professionalProfileId are immutable after creation. + x-permission: healthcare.practitioners.manage + x-audit-event: healthcare.practitioner.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/merge-patch+json: + schema: {$ref: '#/components/schemas/PractitionerPatch'} + responses: + '200': + description: Practitioner updated. + headers: {ETag: {$ref: '#/components/headers/ETag'}} + content: + application/json: + schema: {$ref: '#/components/schemas/PractitionerResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/encounters: + get: + tags: [Healthcare Encounters] + operationId: listHealthcareEncounters + summary: List encounters + x-permission: healthcare.encounters.read + x-audit-event: healthcare.encounter.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/Cursor' + - $ref: '#/components/parameters/PageSize' + - name: patientId + in: query + schema: {$ref: '#/components/schemas/Uuid'} + - name: practitionerId + in: query + schema: {$ref: '#/components/schemas/Uuid'} + - name: status + in: query + schema: {$ref: '#/components/schemas/EncounterStatus'} + - name: from + in: query + schema: {type: string, format: date-time} + - name: to + in: query + schema: {type: string, format: date-time} + responses: + '200': + description: Encounter summaries. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterListResponse'} + '422': {$ref: '#/components/responses/ValidationError'} + post: + tags: [Healthcare Encounters] + operationId: createHealthcareEncounter + summary: Create a planned encounter + description: | + Patient and practitioner must be active in the same tenant. Clinical narrative + is not accepted by this endpoint. + x-permission: healthcare.encounters.create + x-audit-event: healthcare.encounter.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterCreate'} + responses: + '201': + description: Encounter created. + headers: + Location: {$ref: '#/components/headers/Location'} + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/encounters/{encounterId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/EncounterId' + get: + tags: [Healthcare Encounters] + operationId: getHealthcareEncounter + summary: Retrieve an encounter + x-permission: healthcare.encounters.read + x-audit-event: healthcare.encounter.read + responses: + '200': + description: Encounter. + headers: + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterResponse'} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Encounters] + operationId: updateHealthcareEncounter + summary: Update a planned encounter + description: Only planned encounters are patchable; status changes use commands. + x-permission: healthcare.encounters.update + x-audit-event: healthcare.encounter.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/merge-patch+json: + schema: {$ref: '#/components/schemas/EncounterPatch'} + responses: + '200': + description: Encounter updated. + headers: + ETag: {$ref: '#/components/headers/ETag'} + Cache-Control: {$ref: '#/components/headers/NoStore'} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/encounters/{encounterId}/start: + post: + tags: [Healthcare Encounters] + operationId: startHealthcareEncounter + summary: Start a planned encounter + x-permission: healthcare.encounters.conduct + x-audit-event: healthcare.encounter.started + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/EncounterId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + content: + application/json: + schema: {$ref: '#/components/schemas/StartEncounterCommand'} + responses: + '200': + description: Encounter started. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/encounters/{encounterId}/finish: + post: + tags: [Healthcare Encounters] + operationId: finishHealthcareEncounter + summary: Finish an in-progress encounter + description: Finishing an encounter does not sign associated clinical records. + x-permission: healthcare.encounters.conduct + x-audit-event: healthcare.encounter.finished + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/EncounterId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + content: + application/json: + schema: {$ref: '#/components/schemas/FinishEncounterCommand'} + responses: + '200': + description: Encounter finished. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/encounters/{encounterId}/cancel: + post: + tags: [Healthcare Encounters] + operationId: cancelHealthcareEncounter + summary: Cancel a planned encounter + x-permission: healthcare.encounters.update + x-audit-event: healthcare.encounter.cancelled + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/EncounterId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/ReasonCommand'} + responses: + '200': + description: Encounter cancelled. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: + application/json: + schema: {$ref: '#/components/schemas/EncounterResponse'} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/locations: + get: + tags: [Healthcare Locations] + operationId: listHealthcareLocations + summary: List care locations + x-permission: healthcare.locations.read + parameters: &tenantListParameters + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/Cursor' + - $ref: '#/components/parameters/PageSize' + responses: + '200': + description: Care locations. + content: {application/json: {schema: {$ref: '#/components/schemas/LocationListResponse'}}} + post: + tags: [Healthcare Locations] + operationId: createHealthcareLocation + summary: Create a care location + x-permission: healthcare.locations.manage + x-audit-event: healthcare.location.created + parameters: &tenantCreateParameters + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/LocationCreate'}}} + responses: + '201': + description: Location created. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}} + content: {application/json: {schema: {$ref: '#/components/schemas/LocationResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/locations/{locationId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/LocationId' + get: + tags: [Healthcare Locations] + operationId: getHealthcareLocation + summary: Retrieve a care location + x-permission: healthcare.locations.read + responses: + '200': + description: Location. + headers: {ETag: {$ref: '#/components/headers/ETag'}} + content: {application/json: {schema: {$ref: '#/components/schemas/LocationResponse'}}} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Locations] + operationId: updateHealthcareLocation + summary: Update a care location + x-permission: healthcare.locations.manage + x-audit-event: healthcare.location.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/merge-patch+json: {schema: {$ref: '#/components/schemas/LocationPatch'}}} + responses: + '200': + description: Location updated. + headers: {ETag: {$ref: '#/components/headers/ETag'}} + content: {application/json: {schema: {$ref: '#/components/schemas/LocationResponse'}}} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/appointments: + get: + tags: [Healthcare Appointments] + operationId: listHealthcareAppointments + summary: List appointments + x-permission: healthcare.appointments.read + x-audit-event: healthcare.appointment.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/Cursor' + - $ref: '#/components/parameters/PageSize' + - name: patientId + in: query + schema: {$ref: '#/components/schemas/Uuid'} + - name: practitionerId + in: query + schema: {$ref: '#/components/schemas/Uuid'} + - name: from + in: query + schema: {type: string, format: date-time} + - name: to + in: query + schema: {type: string, format: date-time} + - name: status + in: query + schema: {$ref: '#/components/schemas/AppointmentStatus'} + responses: + '200': + description: Appointments. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AppointmentListResponse'}}} + post: + tags: [Healthcare Appointments] + operationId: createHealthcareAppointment + summary: Book an appointment + description: Scheduling conflicts return APPOINTMENT_CONFLICT; the server never silently double-books. + x-permission: healthcare.appointments.create + x-audit-event: healthcare.appointment.created + parameters: *tenantCreateParameters + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/AppointmentCreate'}}} + responses: + '201': + description: Appointment booked. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AppointmentResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/appointments/{appointmentId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/AppointmentId' + get: + tags: [Healthcare Appointments] + operationId: getHealthcareAppointment + summary: Retrieve an appointment + x-permission: healthcare.appointments.read + x-audit-event: healthcare.appointment.read + responses: + '200': + description: Appointment. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AppointmentResponse'}}} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Appointments] + operationId: updateHealthcareAppointment + summary: Reschedule or update a booked appointment + description: Status changes use commands; fulfilled appointments are immutable. + x-permission: healthcare.appointments.update + x-audit-event: healthcare.appointment.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/merge-patch+json: {schema: {$ref: '#/components/schemas/AppointmentPatch'}}} + responses: + '200': + description: Appointment updated. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AppointmentResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/appointments/{appointmentId}/{command}: + post: + tags: [Healthcare Appointments] + operationId: commandHealthcareAppointment + summary: Confirm, check in, fulfil, cancel, or mark an appointment as no-show + description: | + Allowed transitions: booked to confirmed/cancelled; confirmed to checked_in/cancelled/no_show; + checked_in to fulfilled. Fulfilment requires a linked encounter. + x-permission: healthcare.appointments.update + x-audit-event: healthcare.appointment.commanded + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/AppointmentId' + - name: command + in: path + required: true + schema: {type: string, enum: [confirm, check-in, fulfil, cancel, no-show]} + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + content: {application/json: {schema: {$ref: '#/components/schemas/OptionalReasonCommand'}}} + responses: + '200': + description: Appointment transitioned. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AppointmentResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/patients/{patientId}/allergies: + get: + tags: [Healthcare Allergies] + operationId: listPatientAllergies + summary: List recorded allergies and intolerances + x-permission: healthcare.allergies.read + x-audit-event: healthcare.allergy.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + responses: + '200': + description: Allergy records. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AllergyListResponse'}}} + post: + tags: [Healthcare Allergies] + operationId: createPatientAllergy + summary: Record an allergy or intolerance + x-permission: healthcare.allergies.create + x-audit-event: healthcare.allergy.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/AllergyCreate'}}} + responses: + '201': + description: Allergy recorded. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AllergyResponse'}}} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/allergies/{allergyId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/AllergyId' + get: + tags: [Healthcare Allergies] + operationId: getPatientAllergy + summary: Retrieve an allergy + x-permission: healthcare.allergies.read + x-audit-event: healthcare.allergy.read + responses: + '200': + description: Allergy. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AllergyResponse'}}} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Allergies] + operationId: updatePatientAllergy + summary: Update verification or clinical status + description: Substance identity is immutable; incorrect entries become entered_in_error. + x-permission: healthcare.allergies.update + x-audit-event: healthcare.allergy.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/merge-patch+json: {schema: {$ref: '#/components/schemas/AllergyPatch'}}} + responses: + '200': + description: Allergy updated. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/AllergyResponse'}}} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/patients/{patientId}/conditions: + get: + tags: [Healthcare Conditions] + operationId: listPatientConditions + summary: List problems, diagnoses, and health concerns + x-permission: healthcare.conditions.read + x-audit-event: healthcare.condition.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + - name: category + in: query + schema: {$ref: '#/components/schemas/ConditionCategory'} + responses: + '200': + description: Conditions. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ConditionListResponse'}}} + post: + tags: [Healthcare Conditions] + operationId: createPatientCondition + summary: Record a problem, diagnosis, or health concern + x-permission: healthcare.conditions.create + x-audit-event: healthcare.condition.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/ConditionCreate'}}} + responses: + '201': + description: Condition recorded. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ConditionResponse'}}} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/conditions/{conditionId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/ConditionId' + get: + tags: [Healthcare Conditions] + operationId: getPatientCondition + summary: Retrieve a condition + x-permission: healthcare.conditions.read + x-audit-event: healthcare.condition.read + responses: + '200': + description: Condition. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ConditionResponse'}}} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Conditions] + operationId: updatePatientCondition + summary: Update condition lifecycle or verification + x-permission: healthcare.conditions.update + x-audit-event: healthcare.condition.updated + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/merge-patch+json: {schema: {$ref: '#/components/schemas/ConditionPatch'}}} + responses: + '200': + description: Condition updated. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ConditionResponse'}}} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/patients/{patientId}/medications: + get: + tags: [Healthcare Medications] + operationId: listPatientMedications + summary: List medication statements and orders + x-permission: healthcare.medications.read + x-audit-event: healthcare.medication.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + responses: + '200': + description: Medications. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/MedicationListResponse'}}} + post: + tags: [Healthcare Medications] + operationId: createPatientMedication + summary: Record a medication statement + description: This operation records medication history; it does not prescribe or dispense. + x-permission: healthcare.medications.create + x-audit-event: healthcare.medication.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/PatientId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/MedicationCreate'}}} + responses: + '201': + description: Medication statement recorded. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/MedicationResponse'}}} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/medications/{medicationId}: + patch: + tags: [Healthcare Medications] + operationId: updatePatientMedication + summary: Update a medication statement lifecycle + x-permission: healthcare.medications.update + x-audit-event: healthcare.medication.updated + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/MedicationId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/merge-patch+json: {schema: {$ref: '#/components/schemas/MedicationPatch'}}} + responses: + '200': + description: Medication updated. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/MedicationResponse'}}} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/encounters/{encounterId}/clinical-records: + get: + tags: [Healthcare Clinical Records] + operationId: listEncounterClinicalRecords + summary: List clinical records for an encounter + x-permission: healthcare.clinical_records.read + x-audit-event: healthcare.clinical_record.listed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/EncounterId' + responses: + '200': + description: Clinical record summaries; narrative content is excluded. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordListResponse'}}} + post: + tags: [Healthcare Clinical Records] + operationId: createEncounterClinicalRecord + summary: Create a draft clinical record + x-permission: healthcare.clinical_records.create + x-audit-event: healthcare.clinical_record.created + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/EncounterId' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordCreate'}}} + responses: + '201': + description: Draft record created with version 1. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordResponse'}}} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/clinical-records/{recordId}: + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/ClinicalRecordId' + get: + tags: [Healthcare Clinical Records] + operationId: getClinicalRecord + summary: Retrieve a clinical record and current content version + x-permission: healthcare.clinical_records.read + x-audit-event: healthcare.clinical_record.read + responses: + '200': + description: Clinical record. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordResponse'}}} + '404': {$ref: '#/components/responses/NotFound'} + patch: + tags: [Healthcare Clinical Records] + operationId: updateDraftClinicalRecord + summary: Create a new version of a draft clinical record + description: Signed records reject PATCH; use the amendment command. + x-permission: healthcare.clinical_records.update + x-audit-event: healthcare.clinical_record.version_created + parameters: + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/merge-patch+json: {schema: {$ref: '#/components/schemas/ClinicalRecordPatch'}}} + responses: + '200': + description: New draft version created. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + + /healthcare/clinical-records/{recordId}/sign: + post: + tags: [Healthcare Clinical Records] + operationId: signClinicalRecord + summary: Sign and freeze the current clinical record version + description: Revalidates active practitioner status and credential authority at execution time. + x-permission: healthcare.clinical_records.sign + x-audit-event: healthcare.clinical_record.signed + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/ClinicalRecordId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/SignClinicalRecordCommand'}}} + responses: + '200': + description: Record signed and immutable. + headers: {ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/clinical-records/{recordId}/amend: + post: + tags: [Healthcare Clinical Records] + operationId: amendClinicalRecord + summary: Amend a signed clinical record without overwriting history + x-permission: healthcare.clinical_records.amend + x-audit-event: healthcare.clinical_record.amended + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/ClinicalRecordId' + - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: {application/json: {schema: {$ref: '#/components/schemas/AmendClinicalRecordCommand'}}} + responses: + '201': + description: Signed amendment version created with provenance links. + headers: {Location: {$ref: '#/components/headers/Location'}, ETag: {$ref: '#/components/headers/ETag'}, Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordResponse'}}} + '409': {$ref: '#/components/responses/Conflict'} + '412': {$ref: '#/components/responses/PreconditionFailed'} + '422': {$ref: '#/components/responses/ValidationError'} + + /healthcare/clinical-records/{recordId}/history: + get: + tags: [Healthcare Clinical Records] + operationId: getClinicalRecordHistory + summary: Retrieve immutable version and amendment history + x-permission: healthcare.clinical_records.history + x-audit-event: healthcare.clinical_record.history_read + parameters: + - $ref: '#/components/parameters/OrganizationId' + - $ref: '#/components/parameters/RequestId' + - $ref: '#/components/parameters/ClinicalRecordId' + responses: + '200': + description: Version history. + headers: {Cache-Control: {$ref: '#/components/headers/NoStore'}} + content: {application/json: {schema: {$ref: '#/components/schemas/ClinicalRecordHistoryResponse'}}} + '404': {$ref: '#/components/responses/NotFound'} + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + parameters: + OrganizationId: + name: X-Organization-Id + in: header + required: true + schema: {$ref: '#/components/schemas/Uuid'} + RequestId: + name: X-Request-Id + in: header + required: false + schema: {type: string, maxLength: 128} + IdempotencyKey: + name: Idempotency-Key + in: header + required: true + schema: {type: string, minLength: 16, maxLength: 128} + IfMatch: + name: If-Match + in: header + required: true + schema: {type: string, pattern: '^"[1-9][0-9]*"$'} + Cursor: + name: cursor + in: query + schema: {type: string, maxLength: 512} + PageSize: + name: pageSize + in: query + schema: {type: integer, minimum: 1, maximum: 100, default: 25} + PatientId: + name: patientId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + PractitionerId: + name: practitionerId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + EncounterId: + name: encounterId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + LocationId: + name: locationId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + AppointmentId: + name: appointmentId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + AllergyId: + name: allergyId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + ConditionId: + name: conditionId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + MedicationId: + name: medicationId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + ClinicalRecordId: + name: recordId + in: path + required: true + schema: {$ref: '#/components/schemas/Uuid'} + headers: + ETag: + schema: {type: string, pattern: '^"[1-9][0-9]*"$'} + Location: + schema: {type: string, format: uri-reference} + RequestId: + schema: {type: string} + NoStore: + schema: {type: string, const: 'private, no-store'} + responses: + Unauthorized: + description: Authentication is missing or invalid. + content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}} + Forbidden: + description: The caller lacks permission or professional authority. + content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}} + NotFound: + description: Resource not found in the active tenant. + content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}} + Conflict: + description: State conflict, uniqueness conflict, or possible duplicate. + content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}} + PreconditionFailed: + description: If-Match does not match the current version. + content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}} + ValidationError: + description: Request validation failed. + content: {application/problem+json: {schema: {$ref: '#/components/schemas/Problem'}}} + schemas: + Uuid: + type: string + format: uuid + PatientStatus: + type: string + enum: [active, inactive, deceased, archived] + PractitionerStatus: + type: string + enum: [active, suspended, inactive] + EncounterStatus: + type: string + enum: [planned, in_progress, finished, cancelled, entered_in_error] + AppointmentStatus: + type: string + enum: [booked, confirmed, checked_in, fulfilled, cancelled, no_show, entered_in_error] + ClinicalStatus: + type: string + enum: [active, inactive, resolved, entered_in_error] + VerificationStatus: + type: string + enum: [unconfirmed, provisional, differential, confirmed, refuted, entered_in_error] + ConditionCategory: + type: string + enum: [problem_list, encounter_diagnosis, health_concern] + CodeableConcept: + type: object + additionalProperties: false + required: [system, code, display] + properties: + system: {type: string, format: uri, maxLength: 500} + code: {type: string, minLength: 1, maxLength: 100} + display: {type: string, minLength: 1, maxLength: 300} + text: {type: [string, 'null'], maxLength: 300} + AdministrativeGender: + type: string + enum: [female, male, other, unknown] + description: Administrative classification only; not a clinical assertion. + HumanName: + type: object + additionalProperties: false + required: [given, family] + properties: + prefix: {type: [string, 'null'], maxLength: 40} + given: + type: array + minItems: 1 + maxItems: 5 + items: {type: string, minLength: 1, maxLength: 120} + family: {type: string, minLength: 1, maxLength: 120} + suffix: {type: [string, 'null'], maxLength: 40} + ContactPoint: + type: object + additionalProperties: false + required: [system, value, use] + properties: + system: {type: string, enum: [phone, email]} + value: {type: string, minLength: 3, maxLength: 254} + use: {type: string, enum: [home, work, mobile, temporary]} + isPrimary: {type: boolean, default: false} + Address: + type: object + additionalProperties: false + required: [use, line1, city, countryCode] + properties: + use: {type: string, enum: [home, work, temporary]} + line1: {type: string, minLength: 1, maxLength: 200} + line2: {type: [string, 'null'], maxLength: 200} + city: {type: string, minLength: 1, maxLength: 120} + region: {type: [string, 'null'], maxLength: 120} + postalCode: {type: [string, 'null'], maxLength: 32} + countryCode: {type: string, pattern: '^[A-Z]{2}$'} + isPrimary: {type: boolean, default: false} + PatientCreate: + type: object + additionalProperties: false + required: [name, birthDate] + properties: + patientNumber: + type: string + maxLength: 64 + description: Optional client-supplied number; generated when omitted. + name: {$ref: '#/components/schemas/HumanName'} + birthDate: {type: string, format: date} + administrativeGender: {$ref: '#/components/schemas/AdministrativeGender'} + sexAtBirth: {type: [string, 'null'], maxLength: 80} + genderIdentity: {type: [string, 'null'], maxLength: 120} + contacts: + type: array + maxItems: 10 + items: {$ref: '#/components/schemas/ContactPoint'} + addresses: + type: array + maxItems: 10 + items: {$ref: '#/components/schemas/Address'} + PatientPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + name: {$ref: '#/components/schemas/HumanName'} + birthDate: {type: string, format: date} + administrativeGender: {$ref: '#/components/schemas/AdministrativeGender'} + sexAtBirth: {type: [string, 'null'], maxLength: 80} + genderIdentity: {type: [string, 'null'], maxLength: 120} + contacts: + type: array + maxItems: 10 + items: {$ref: '#/components/schemas/ContactPoint'} + addresses: + type: array + maxItems: 10 + items: {$ref: '#/components/schemas/Address'} + Patient: + allOf: + - $ref: '#/components/schemas/PatientCreate' + - type: object + required: [id, organizationId, patientNumber, status, version, createdAt, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + patientNumber: {type: string} + status: {$ref: '#/components/schemas/PatientStatus'} + archivedAt: {type: [string, 'null'], format: date-time} + version: {type: integer, minimum: 1} + createdAt: {type: string, format: date-time} + updatedAt: {type: string, format: date-time} + PatientSummary: + type: object + additionalProperties: false + required: [id, patientNumber, name, birthDate, status] + properties: + id: {$ref: '#/components/schemas/Uuid'} + patientNumber: {type: string} + name: {$ref: '#/components/schemas/HumanName'} + birthDate: {type: string, format: date} + status: {$ref: '#/components/schemas/PatientStatus'} + PatientResponse: + type: object + additionalProperties: false + required: [data] + properties: {data: {$ref: '#/components/schemas/Patient'}} + PatientListResponse: + type: object + additionalProperties: false + required: [data, page] + properties: + data: {type: array, items: {$ref: '#/components/schemas/PatientSummary'}} + page: {$ref: '#/components/schemas/CursorPage'} + PractitionerCreate: + type: object + additionalProperties: false + required: [userId, professionalProfileId, specialtyCode] + properties: + userId: {$ref: '#/components/schemas/Uuid'} + professionalProfileId: {$ref: '#/components/schemas/Uuid'} + specialtyCode: {type: string, minLength: 1, maxLength: 64} + PractitionerPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + specialtyCode: {type: string, minLength: 1, maxLength: 64} + status: {$ref: '#/components/schemas/PractitionerStatus'} + Practitioner: + allOf: + - $ref: '#/components/schemas/PractitionerCreate' + - type: object + required: [id, organizationId, status, credentialState, version, createdAt, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + status: {$ref: '#/components/schemas/PractitionerStatus'} + credentialState: + type: string + enum: [verified, expiring, expired, incomplete, suspended] + readOnly: true + version: {type: integer, minimum: 1} + createdAt: {type: string, format: date-time} + updatedAt: {type: string, format: date-time} + PractitionerResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/Practitioner'}} + PractitionerListResponse: + type: object + required: [data, page] + properties: + data: {type: array, items: {$ref: '#/components/schemas/Practitioner'}} + page: {$ref: '#/components/schemas/CursorPage'} + EncounterCreate: + type: object + additionalProperties: false + required: [patientId, practitionerId, encounterType] + properties: + patientId: {$ref: '#/components/schemas/Uuid'} + practitionerId: {$ref: '#/components/schemas/Uuid'} + appointmentId: {oneOf: [{$ref: '#/components/schemas/Uuid'}, {type: 'null'}]} + encounterType: {type: string, enum: [ambulatory, emergency, inpatient, virtual, home]} + scheduledStart: {type: [string, 'null'], format: date-time} + reasonForVisit: {type: [string, 'null'], maxLength: 500} + EncounterPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + practitionerId: {$ref: '#/components/schemas/Uuid'} + appointmentId: {oneOf: [{$ref: '#/components/schemas/Uuid'}, {type: 'null'}]} + encounterType: {type: string, enum: [ambulatory, emergency, inpatient, virtual, home]} + scheduledStart: {type: [string, 'null'], format: date-time} + reasonForVisit: {type: [string, 'null'], maxLength: 500} + Encounter: + allOf: + - $ref: '#/components/schemas/EncounterCreate' + - type: object + required: [id, organizationId, status, version, createdAt, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + status: {$ref: '#/components/schemas/EncounterStatus'} + startedAt: {type: [string, 'null'], format: date-time} + endedAt: {type: [string, 'null'], format: date-time} + cancellationReason: {type: [string, 'null'], maxLength: 500} + version: {type: integer, minimum: 1} + createdAt: {type: string, format: date-time} + updatedAt: {type: string, format: date-time} + EncounterResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/Encounter'}} + EncounterListResponse: + type: object + required: [data, page] + properties: + data: {type: array, items: {$ref: '#/components/schemas/Encounter'}} + page: {$ref: '#/components/schemas/CursorPage'} + LocationCreate: + type: object + additionalProperties: false + required: [name, type, timezone, status] + properties: + name: {type: string, minLength: 1, maxLength: 160} + type: {type: string, enum: [clinic, hospital, office, virtual]} + timezone: {type: string, minLength: 1, maxLength: 64} + status: {type: string, enum: [active, suspended, inactive]} + address: {oneOf: [{$ref: '#/components/schemas/Address'}, {type: 'null'}]} + LocationPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + name: {type: string, minLength: 1, maxLength: 160} + timezone: {type: string, minLength: 1, maxLength: 64} + status: {type: string, enum: [active, suspended, inactive]} + address: {oneOf: [{$ref: '#/components/schemas/Address'}, {type: 'null'}]} + HealthcareLocation: + allOf: + - $ref: '#/components/schemas/LocationCreate' + - type: object + required: [id, organizationId, version, createdAt, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + version: {type: integer, minimum: 1} + createdAt: {type: string, format: date-time} + updatedAt: {type: string, format: date-time} + LocationResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/HealthcareLocation'}} + LocationListResponse: + type: object + required: [data, page] + properties: + data: {type: array, items: {$ref: '#/components/schemas/HealthcareLocation'}} + page: {$ref: '#/components/schemas/CursorPage'} + AppointmentCreate: + type: object + additionalProperties: false + required: [patientId, practitionerId, locationId, appointmentType, startsAt, endsAt] + properties: + patientId: {$ref: '#/components/schemas/Uuid'} + practitionerId: {$ref: '#/components/schemas/Uuid'} + locationId: {$ref: '#/components/schemas/Uuid'} + appointmentType: {type: string, minLength: 1, maxLength: 64} + startsAt: {type: string, format: date-time} + endsAt: {type: string, format: date-time} + reason: {type: [string, 'null'], maxLength: 500} + AppointmentPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + practitionerId: {$ref: '#/components/schemas/Uuid'} + locationId: {$ref: '#/components/schemas/Uuid'} + appointmentType: {type: string, minLength: 1, maxLength: 64} + startsAt: {type: string, format: date-time} + endsAt: {type: string, format: date-time} + reason: {type: [string, 'null'], maxLength: 500} + Appointment: + allOf: + - $ref: '#/components/schemas/AppointmentCreate' + - type: object + required: [id, organizationId, status, version, createdAt, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + status: {$ref: '#/components/schemas/AppointmentStatus'} + encounterId: {oneOf: [{$ref: '#/components/schemas/Uuid'}, {type: 'null'}]} + cancellationReason: {type: [string, 'null'], maxLength: 500} + version: {type: integer, minimum: 1} + createdAt: {type: string, format: date-time} + updatedAt: {type: string, format: date-time} + AppointmentResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/Appointment'}} + AppointmentListResponse: + type: object + required: [data, page] + properties: + data: {type: array, items: {$ref: '#/components/schemas/Appointment'}} + page: {$ref: '#/components/schemas/CursorPage'} + AllergyCreate: + type: object + additionalProperties: false + required: [substance, category, criticality, recordedByPractitionerId] + properties: + substance: {$ref: '#/components/schemas/CodeableConcept'} + category: {type: string, enum: [food, medication, environment, biologic]} + criticality: {type: string, enum: [low, high, unable_to_assess]} + verificationStatus: {$ref: '#/components/schemas/VerificationStatus'} + reaction: {type: [string, 'null'], maxLength: 500} + recordedByPractitionerId: {$ref: '#/components/schemas/Uuid'} + AllergyPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + clinicalStatus: {$ref: '#/components/schemas/ClinicalStatus'} + verificationStatus: {$ref: '#/components/schemas/VerificationStatus'} + criticality: {type: string, enum: [low, high, unable_to_assess]} + reaction: {type: [string, 'null'], maxLength: 500} + Allergy: + allOf: + - $ref: '#/components/schemas/AllergyCreate' + - type: object + required: [id, organizationId, patientId, clinicalStatus, version, recordedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + patientId: {$ref: '#/components/schemas/Uuid'} + clinicalStatus: {$ref: '#/components/schemas/ClinicalStatus'} + version: {type: integer, minimum: 1} + recordedAt: {type: string, format: date-time} + AllergyResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/Allergy'}} + AllergyListResponse: + type: object + required: [data] + properties: {data: {type: array, items: {$ref: '#/components/schemas/Allergy'}}} + ConditionCreate: + type: object + additionalProperties: false + required: [code, category, recordedByPractitionerId] + properties: + code: {$ref: '#/components/schemas/CodeableConcept'} + category: {$ref: '#/components/schemas/ConditionCategory'} + encounterId: {oneOf: [{$ref: '#/components/schemas/Uuid'}, {type: 'null'}]} + onsetAt: {type: [string, 'null'], format: date-time} + note: {type: [string, 'null'], maxLength: 1000} + recordedByPractitionerId: {$ref: '#/components/schemas/Uuid'} + ConditionPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + clinicalStatus: {$ref: '#/components/schemas/ClinicalStatus'} + verificationStatus: {$ref: '#/components/schemas/VerificationStatus'} + abatementAt: {type: [string, 'null'], format: date-time} + note: {type: [string, 'null'], maxLength: 1000} + Condition: + allOf: + - $ref: '#/components/schemas/ConditionCreate' + - type: object + required: [id, organizationId, patientId, clinicalStatus, verificationStatus, version, recordedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + patientId: {$ref: '#/components/schemas/Uuid'} + clinicalStatus: {$ref: '#/components/schemas/ClinicalStatus'} + verificationStatus: {$ref: '#/components/schemas/VerificationStatus'} + abatementAt: {type: [string, 'null'], format: date-time} + version: {type: integer, minimum: 1} + recordedAt: {type: string, format: date-time} + ConditionResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/Condition'}} + ConditionListResponse: + type: object + required: [data] + properties: {data: {type: array, items: {$ref: '#/components/schemas/Condition'}}} + MedicationCreate: + type: object + additionalProperties: false + required: [medication, source, recordedByPractitionerId] + properties: + medication: {$ref: '#/components/schemas/CodeableConcept'} + source: {type: string, enum: [patient_reported, external_record, clinician_recorded]} + doseText: {type: [string, 'null'], maxLength: 300} + route: {type: [string, 'null'], maxLength: 120} + frequency: {type: [string, 'null'], maxLength: 120} + startedAt: {type: [string, 'null'], format: date-time} + recordedByPractitionerId: {$ref: '#/components/schemas/Uuid'} + MedicationPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + status: {type: string, enum: [active, completed, stopped, entered_in_error]} + doseText: {type: [string, 'null'], maxLength: 300} + route: {type: [string, 'null'], maxLength: 120} + frequency: {type: [string, 'null'], maxLength: 120} + endedAt: {type: [string, 'null'], format: date-time} + Medication: + allOf: + - $ref: '#/components/schemas/MedicationCreate' + - type: object + required: [id, organizationId, patientId, status, version, recordedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + patientId: {$ref: '#/components/schemas/Uuid'} + status: {type: string, enum: [active, completed, stopped, entered_in_error]} + endedAt: {type: [string, 'null'], format: date-time} + version: {type: integer, minimum: 1} + recordedAt: {type: string, format: date-time} + MedicationResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/Medication'}} + MedicationListResponse: + type: object + required: [data] + properties: {data: {type: array, items: {$ref: '#/components/schemas/Medication'}}} + ClinicalRecordCreate: + type: object + additionalProperties: false + required: [recordType, sensitivity, authorPractitionerId, content] + properties: + recordType: {type: string, enum: [progress_note, consultation_note, discharge_summary, procedure_note]} + sensitivity: {type: string, enum: [normal, restricted, highly_restricted]} + authorPractitionerId: {$ref: '#/components/schemas/Uuid'} + content: {type: string, minLength: 1, maxLength: 100000} + contentFormat: {type: string, enum: [text_markdown, structured_json], default: text_markdown} + ClinicalRecordPatch: + type: object + additionalProperties: false + minProperties: 1 + properties: + content: {type: string, minLength: 1, maxLength: 100000} + sensitivity: {type: string, enum: [normal, restricted, highly_restricted]} + ClinicalRecord: + type: object + additionalProperties: false + required: [id, organizationId, patientId, encounterId, recordType, sensitivity, status, authorPractitionerId, currentVersion, version, createdAt, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + organizationId: {$ref: '#/components/schemas/Uuid'} + patientId: {$ref: '#/components/schemas/Uuid'} + encounterId: {$ref: '#/components/schemas/Uuid'} + recordType: {type: string} + sensitivity: {type: string, enum: [normal, restricted, highly_restricted]} + status: {type: string, enum: [draft, signed, amended, entered_in_error]} + authorPractitionerId: {$ref: '#/components/schemas/Uuid'} + signedByPractitionerId: {oneOf: [{$ref: '#/components/schemas/Uuid'}, {type: 'null'}]} + signedAt: {type: [string, 'null'], format: date-time} + currentVersion: {$ref: '#/components/schemas/ClinicalRecordVersion'} + version: {type: integer, minimum: 1} + createdAt: {type: string, format: date-time} + updatedAt: {type: string, format: date-time} + ClinicalRecordVersion: + type: object + additionalProperties: false + required: [id, versionNumber, content, contentFormat, contentHash, createdByPractitionerId, createdAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + versionNumber: {type: integer, minimum: 1} + content: {type: string, maxLength: 100000} + contentFormat: {type: string, enum: [text_markdown, structured_json]} + contentHash: {type: string, pattern: '^[a-f0-9]{64}$'} + createdByPractitionerId: {$ref: '#/components/schemas/Uuid'} + createdAt: {type: string, format: date-time} + ClinicalRecordResponse: + type: object + required: [data] + properties: {data: {$ref: '#/components/schemas/ClinicalRecord'}} + ClinicalRecordSummary: + type: object + required: [id, recordType, sensitivity, status, authorPractitionerId, version, updatedAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + recordType: {type: string} + sensitivity: {type: string} + status: {type: string} + authorPractitionerId: {$ref: '#/components/schemas/Uuid'} + version: {type: integer} + updatedAt: {type: string, format: date-time} + ClinicalRecordListResponse: + type: object + required: [data] + properties: {data: {type: array, items: {$ref: '#/components/schemas/ClinicalRecordSummary'}}} + SignClinicalRecordCommand: + type: object + additionalProperties: false + required: [practitionerId, attestation] + properties: + practitionerId: {$ref: '#/components/schemas/Uuid'} + attestation: {type: string, minLength: 10, maxLength: 500} + AmendClinicalRecordCommand: + type: object + additionalProperties: false + required: [practitionerId, amendmentType, reason, content] + properties: + practitionerId: {$ref: '#/components/schemas/Uuid'} + amendmentType: {type: string, enum: [correction, addendum, clarification]} + reason: {type: string, minLength: 3, maxLength: 1000} + content: {type: string, minLength: 1, maxLength: 100000} + ClinicalRecordHistoryResponse: + type: object + required: [recordId, versions, amendments] + properties: + recordId: {$ref: '#/components/schemas/Uuid'} + versions: {type: array, items: {$ref: '#/components/schemas/ClinicalRecordVersion'}} + amendments: + type: array + items: + type: object + required: [id, sourceVersionId, resultVersionId, practitionerId, amendmentType, reason, createdAt] + properties: + id: {$ref: '#/components/schemas/Uuid'} + sourceVersionId: {$ref: '#/components/schemas/Uuid'} + resultVersionId: {$ref: '#/components/schemas/Uuid'} + practitionerId: {$ref: '#/components/schemas/Uuid'} + amendmentType: {type: string, enum: [correction, addendum, clarification]} + reason: {type: string} + createdAt: {type: string, format: date-time} + StartEncounterCommand: + type: object + additionalProperties: false + properties: + startedAt: {type: string, format: date-time} + FinishEncounterCommand: + type: object + additionalProperties: false + properties: + endedAt: {type: string, format: date-time} + ReasonCommand: + type: object + additionalProperties: false + required: [reason] + properties: + reason: {type: string, minLength: 3, maxLength: 500} + OptionalReasonCommand: + type: object + additionalProperties: false + properties: + reason: {type: string, minLength: 3, maxLength: 500} + CursorPage: + type: object + additionalProperties: false + required: [hasMore] + properties: + nextCursor: {type: [string, 'null']} + hasMore: {type: boolean} + FieldError: + type: object + additionalProperties: false + required: [field, code, message] + properties: + field: {type: string} + code: {type: string} + message: {type: string} + Problem: + type: object + additionalProperties: false + required: [type, title, status, code, requestId] + properties: + type: {type: string, format: uri-reference} + title: {type: string} + status: {type: integer, minimum: 400, maximum: 599} + detail: {type: string} + code: {type: string} + requestId: {type: string} + errors: {type: array, items: {$ref: '#/components/schemas/FieldError'}} diff --git a/mermaid-diagram (1).png b/mermaid-diagram (1).png new file mode 100644 index 0000000000000000000000000000000000000000..c98f319967809d97f0a6c1693cdb1e0f50b15b31 GIT binary patch literal 177894 zcmZ^L1yE2=)UR}RcS$KF4I(8S64H${(jw9!B@KdfDIkcXv@}R}cZVol((v{w`v1N+ z@69lbv+Uiw_tc*Ko!>D;`H3_JDkNp-#p{Rgy0hAPuaUH_$Qq{`Mym5&o{}=$-sfd>9;T z@Z)y`Kh2mM5dQ0je1*jAq~uWFfbfq$G1aAh4^XqhtUVWo#pO&cR#Kz;{S*w2B^nr* z{y;W{3=PQ0i=Ihjx-&9Oz z#N%^vCMgh`gg-F-mbvO-)ce4>af2_*L-a&+a~|%!Grm@<&d@4%ptunx-Rf4J3G zIV~6{oP3^N2GpPf+sz0|t1Jyn;U}_g0`9HepU?uy$GYp<5T(+V0*E>f0+re&hSOR2vPH)j@yeOh)T@zY(VQzqgG2_#%mcx$=LH29Cn zudU}>=uNrp7xK(+WjZ(vKa5JkI%lc=cRLc9zaaZgFD?3QUSQr!>Os#0AZAam52QRK zFhA0Hw1e{m!5>&3gPr#{zq>ch1UvlbIlh~|Cj8IGqMDy5fbc3zKEM6*a*50=pn;8z z9nBSJ0P-_Dzh&?ee2Z-S+kH^OGJ}tifl<_kzU9x9|Kxisa6#Y>D$@|KIO{g$6_!KZXA1MRbtA1@(!TMkB`3jvG~N6B$6hOzNcfXcbGB)ZVOhpNk?YeeX5C+d zkFg|AO6LaNjUO7`oNJzTh+N}%pRFZ)v?;zv4_l}JL>qQAZ&$lb$UE=4QgS@58=U4c z&Adp(VI+!QIc@zpP}?Gnho#|k*|;;BW(oNGt747)FPGpSL>wYlM^B4St>MdcNqjD5 z7FwJ~6p5}czl#LZMG0~0IkpijHNjz_KQAbiN_1=|X}vmGSg=!!oPKe+-+>f>9`K1N zv+Mfu`eJv;tG7P@6_&MnnVhi7xOmkwV>6v=+I=UZ_c6GsCNvblov#+xZ}-;thug45RDu9T*=@# zkEv_+S#e|?q~38u#T9ipe7ep;lIgR=RaiCeZd}&K+k^N%d3cp%*h1N*K6)Qb5o{8L9&0sje@@TSJUp&?FY>h(al(u5xOoTfhrNwFH`diFb#F};N(3ISQz>z=S=`wFi|@>n zc7SKQUNmVuYL>4&mPE>jq9!F?v^Z3@b0aXj0*?44SDSs|>449*Nk91ohybXc3%)O@$9;_DC?vRe_JTK%pnSBw=Goi<&=Q3sHhg3FT zVi&;h^I5y#I$sNT z&yj>T_>A(Wh|Oe)O<``bb$&q#>xj0}YdC!ZXF`sLyLB%_eNAh3S@cg}AMzo(uyPGa z_Y!_9qtn72a2a*`p2n9PlckgtQzqPSww{898a=xL1nQOOGHq3M0{_tW+yx~>kIRa0 zj5dq~H?NqFCGGSagOr;|?huHGi!2=b=iy?1)!mT6F9X6C0iSZy1XYHbR=Y<*B1t^g;3W9r~3ODMa%h0l*o?U)Rl;0y|!HrE3wPxmkDu~ z33D3Rt>_ej+>9#pC*rI=GXn48a*KfLjuO1uW^dmZvfo^x!EgLoV%#czbA1Ju73fOt zO{p48;X>R`-YOG=w3=j*KJ{E@4%f+cSyRh6F#5wlc06&I<%veh(5C zr@a!h^&Cx8r6v&bDe~y(rqVOt7P2>9ax!jn_OQgRoTP^^rt_Z??ITfnE@tWWd-d^5 zm~QrJJPANRt3K$y-={q)r9AU$!3&O^bq65>Mr`~7hZ1~UsqY|(((@nH(x2qt&#BJh z_2Oz#+SB1vSJR%J?um<++qH#ekNB(>^?0J3m-5A(SL}kGt?31qy zvqtrcuhGm0>^^1B%TCCUY4q1CZ!Wk@^Nz9_k{QZ~OQpPIlc#Ku?ZtHUneB7BL&tB9 z>p6=+q=(IFaasaS1jfrXcAtH*AOjcy%2Fo}o>#6el*l&g^ny>t!l=;h)6S<8gI7ffRsb z@RqRMj#=trHmcWj^2#@2J|HJ-Mg#HW&O}(QSyvF3lBcjaJclsLjuf^u$3e^8mv?*7 zCrmV2zME;lh(%lsw%~Xsy{GZI{MzgC?QEDa&T&Hjl{U`M6HaqW>}AUpy%&A&B37y% zG{fUbT$dk5a%%1?eL4|;f`3dQh7pShA%E~bK-MDn(4bP1;z-sTjiz^R#Vkbo-pc$2$bEuraf`{fpmmF z7`Eg-Th(jow$!vsOv{d1xVq%snqjI1E3_8(v_kv%lzu2_v?@pJ8H}D9{1fDAZeb{(-G{v)m zGjJym)n}$6|4VlvlxeF6OyzwbEH+~BM7%uP2IGBRySMMB;zUEYWe8;U}q#(iC2JKhkbOfWe#LjW&7*Y1IHCr(wO zC97cg5U=RtjL*ClPlBds;knF7yj;tw!{*SA&u#h8qMj542ZR%Dy)-9Rj(hB8d(g!g z700TQen>}^+~ySMgM%9+*4fD?XYoyf6dg-=T;0*5HEjOE@euae-O6FP`%8VK+^v0F z9po<(xxNUb;rr1a;GeGKhLe;MkdARaTn;;!I9Zb2IsNLz5GyMej}ewTAXOgi@3B54 z9c=Nucj$OsY=fImycrHl$Y}m`WuMEM{5Q0bWi9iSz~|T8E_#dQoXfAJnNO0}6rX!Y zkslG-1tcjh*=G(tm zz_-hTN@N(yb2_PTnF3ZUw(&_7M0o{eY7XJr7<&?5R>$vYuM8$Fvm!p2^bUD`UmNJ` zCfc>&95gn{w%JF1P>0OKC>&;FMeN0i$|I7cA(eNgaLMuM)x2BB7s84aF0Qj_JA?<@ z_IA_eJE}GToRyp!Blw@~RqL^}SW_>8rZ^6{MpmTK(Dqos0gMU$!K?_unY*sqSqG?6|!MDZ`bX?jB7%!So^DTDtpvK*|!mjh)T-dlk7p3%24#UD|zZs!D37KF@YE z5@fBjVfw%_MPke`?u|!x_3s-Jzs5YrB#in}uzT~MotRE~C}9r!I>+d&uCG#RH>x&C zVBh$t_C#|;e{INTDE~pM#cS9Q<9EBl6%IQ-!|tuS6PIoHRjm44(``F}?$?zmF-p0k zvf@%`zqr{M#=TX>O*bj2T%K9LWAT4vWK4BvNv=RmLn*&;^PQH=!+MCIC33=OtW#H| zZIQc!MDE~=6*Kdl60{eE|QJPlB|!(LG;|G zan^%9`|JWAcURn|mKIx;xsR@^XV94U`7ihB!>m3g1ua%`c#rp!s&#u=TM=p*`7x0- zu5=C^GYXeY5{z=*Kpt~xTZLZETaX8Nj9T2Z2Ds~N+`0cz72I3Kv8e(lK4@ERl?mIJ zWz94f;c|aJdxH89hWP!yQx&%?Zx3!Txs%MIaj5d@$lkIPQIm`NH$(9)^Ce03(D$B| zJm&{!H7g^V-qV8VQBSeFv}(i=b#anje)=f3KR)p(k*rNCBdCm`|Ix|pA_kYVFa{UL zyx}N?Ja!{rB4-r6m9~AIEt7q`Q-%&H-a(yFv#}W~TDDBv=GhFJDuLugG&p5QTWqU7 zT*-$F5d|~9uTH2;6N=NGH{QJ8!>)mu^*l~vzvG>xK+@Yi9pdq5ubM#2t59~uIJ(}` z=iJ>9MRIjs$k9i^e3myCf}A}^;A(T4`DNDeNukRd?S@!Ozb5;Zg~uEWb$YG8jC=45 zRZI4qw#ARxstT-gioe^}>b%qtSc5KF!exfsSo})@p;@9jU>4&TvNA?@a_#OU9qwb)eo{Z^K%mP&9msgfE8YdYCu@0&WT)Vn!dNS#98K3xR=IpmRPipR%M_N; zS4YQLnZK#$Qr1PdnVQ*Fs5e8dD;%{)WS={nt=W+(XS|z7ECkwuak9Z!RP}-5E%n=m*1~lLJ6#MZEFPbpmGOJOB0wD?pMKYu zx+wEibINfo_QPh}?unEj=8}9Ud+t1omuftTc|q^C?a?R8gg_eS#9FiD45B8zLv;zN_dS|gl3!YH8E^)qx`Ug&F zj+T@$^MLKms4r~p!hzu;EMavU?b)_e!H#EjdlGzY#Jc42%;Y2kVGk)StbQ6_P*Bch zfe>lYZ+68-SGjtgBhvqxgws^!4VoOXyJrWISN>@)%-Pj@C(i*Sgr({acOO=rQtau5 zOoX7uKixg$i=2Gcu znW8T_jvJwIBbh`G@LSdk1F!+x!9k`OesAmBV5XkCbrSsHC2mf-|pFB@tyACs6ff-4u2t=8h6l~L{t98hDiYyIs0()p!_jqFke^Zh5i z9HnlX?ENz0Q9AGNhsKWnoJCmo*Lu-2=4-XhO=iAetwi$>AF3NXu``njNnquYIGM4SVmW$U1~U5#ESpM0>tO#>D1YOh~V)x+JLBS#klkL$r2y zvF?63&Xmv`U{7THE*YFJ_X|HCBq#x4ob{5vZS@K0svS`aV$HTXFyl;W64SeeQwEWb zjZzdDm*v6f5DC`(;Rm|S=y2by7o*514RSNQ-4{)?lN5@?wHabjJRRRf8J*!Iu=}T> zjlwkh+a?MZkwZ`o#pK%_WbW(eTylfn(byrrYYonQtC#U|a)ly>7ROe$UEdaz=C?=M z=fY2uP>g0+Uf(}a62kCaR>oZOB)pVmi0!J^d^?OC^o+fd@49MrP8h=up4Pn3p#$S( z)O`)k72im-?;Q??9f#QMUcGNo8k4fW(o8nx($*>)v4W&XbCkA=yy5|dtH$93;Z z_b0wHft)yZ$)q_dm%hCSd>1c*@1Vis#k%t>#l&T8!=~JPxIr^kQbc%QLpQ-$$vZo*}Bw^ zp$MZ|=Bx*w+1--vt?NaAivWMgcsMNyoe<^QL>M?ke4#`CVAiL{LZcZz*Jq;M25L;H zw7$wn0ZDnd1lLRO3ez%E;le{^nR8nX@6!ng7oxWmCUh5`*;kBd&`-cEy%jRwkmuy8 zus1H4!PCe$9v$eo8fP~EXh93<^ zg#F7aJ>)KrY>Ea72u@&I2)G1h8)r|5`wMB(_{ewK>j!q>{C%ZoEbn{on8XL8dd-IO zmUw=v@2l_F4S7!2w5Lzmz2upEnuMnj<+Ry%fN;F5v&FD-BKc5&EiI=@fdLPh&wM}W zt=#VY#~$8`a#~|+v*Ao`d4A>OTSd}KrthW;V7C>MDiS_}PXf|B zkMmtzANkCT71efcDrU}$OYM>}WtX8i5BzlDg{x?&LB6XL&aFwIPKINN1I|I6>?}1! zfc^{OL@(+x4t`ZQ#Lm-K{QnoDZYx&*yBLK}N39?KEI^RcKwL`NrIr*FL6kLN)AnH5 zv=efQR$rDPLLlHG=HMCtc?Era4VowhyR4t#f?Jxb8a@M5GEtNg9mDa{fC^6p9*Qsj z*1-rtjVlX5P*%Nw3P#wf??nA{cpbuoIdtvoU-BRJa&2mcFw_rc0N~sxXxEneDbJY$ zaYw_+^*0}`G1Zqie*Ms?ad@uB+W&YF0`)v$;_b!u(oh!?*+*1tm3UdQG%`M1E|MYY|sbC_YPH)JIJ6NrGj=<_q_0h_LT zj^+8|9lQOn-Gzk@rW4Uk(KL@+QeX6wEDj_{%h!xTP_iQL)zL_Bl6f-oX2N4ok|_nd z;f`-Cn!gKg2XIguMQkS5t|?8?v)5(}PrJpCrf64XWETU84458%pZD0MfUsg2jv9cX z_#f*|Au#)cLdO^g19^g~1e2lg^Ij)&HWdH?jV;iPTxaCCK3xfh&~98#^K`fM_2Lq1 zCRhpy5KNI?x|H!&s2oEW8SLgwqNbr2k8VV1JL!G0>ps2()7Dt>EU5@ofPy<#gLAkA z0FyYN$PlpyKu!kwzM!kqm8hu$=}7V<3?(N|fWb_auO3?Ek-fY*`<_wOJQ{39iLd!- z1Yp)g-Zxh#HlECpRNkjFLi^wFVDyn(VoLPXrPKQeUxk>jvgScPc*hSKY3NVy=b zoMxWzr&uE2)^+KoCwNqwH+~%eh7}uiyvHW(0bd`1Z(0($Ia8W1ClsSBYUW`@PpQKa zJ~gVo`ZWW0g1t?x2dcH1DIi(4!#tnyg9inYO3N!MiaRcf#IOC}kjz^lTorvb zoi_$;NPj-;VJVYv1TeS_zV}ifk<_s^sH4K^I(!;=7RE|QsAKuwSKKr%uPH;*z>VIa zp2Q;cL5VyZ=4Mf?U7~%%SqtXFEoEwpH}FY7NPGqLzow0YNX(J1E>5r>?o^vh0@S1x zk<13$9N2CNxTObzqfD?gRm>kz()R4T$W2m&^jU1f{yHcf^|rHr>7-Smq#78ObM1fR|H8tY_%-Z*==7W=OcKhnZAybJ}k@iB!>&ttnnh4c!Pp^=Tz#Vplf^Izq_6Q_M-_9voXAK~ifr`!9YbPtYx*epSx zmvo7tO_Ow8`Utvv^Iz_@wt|EtS&OQ2iB^c?KF-0V$=!w))cdOhQrMjbrV+0J#J_CW z)w0_kLOV-ka8Q?>MB~^Ta|k{ybj#^FZrTSKv$F3UNqF{i4m!ss7$gbX)1RM<-RVou zALwQgWcU5W0{ooriEB0Jvuvpf0)O&&_x=vfh6IRzf~6B<>u;LWo+=VRPV%p)K3 z6x&Ls@M?fWS232)JVP{DiQwyZBjFle04UuDqDSl*J8?AbOI$5pz>Hb*%zpt3rh2EC zQaR@`Q!-;$i!hCY@awXaB#P30{40R4vtnF%Gkcnm)4uM4oU*?AN9fKm)%zYKRV){; zCVvVlVLM>8SS-h<94Tki8G)_urm(rntw5Guv0+1H26w=3SF;x1G{q>KJcVTbA+fK- zw)@+QOidxyrTNsC6qlMg$s^U`gpoSg zP%-lS2vzEai>Xr+0;6hw=6`;ziMu9w2^A*kBKc{zYIhs_PJyxYTcCt{zJRq}6#xJh ztRPM5lTb1*ID^+N0`auOAt_WBU}BiLs6&dt#a0;{7jABviw-| zpGvq7K`}CrZ^4sm7C>4!QACEG51yHvC0_Z(o|S6P3*2IV{(PLEY++5^i*B22^cv*@ z|8)tA7!^T2Ss6v|UNmLv6k{)EX?Z#DnE<>e{4^zANgjT#=;E>sBv{K2$edYWyg)qm z%PG!^6uieV;y);!N)o{LqKDA$2|bAWPdyB_*;4MXo3eB4iLXh9f5>CE0VoL;K+ha_ zH$W|NAnB}AN^QvT=cin$GNL2}2HktQ_A6NjAUaT!Mfs};$Rkugn9zHn_@=Skit07m zejqyR6hN)82@PDAQcYJyR-+%&)+2?95_7&{-40{>$|PMHYZeQYLG+xKLl`kxPEJJw zuy#-Ej<}eD^;v~ewW&n#{D%vp5_I7OV?;y5r5Hb`q)1XH+$p;g-ohG3kNcv-HlD?E zGE6_qZMV2GB_}YOGl|6L$j))YB9W{fv-n|C+)eWHBC8>RU&JQ(K5F57^R6&{Efx|~ zuczQ!Kn;hrpmTH+K?oFIHry|bQQl19%sO&)-Hnxy%O~uQ!~yGTG42xs)EUm5KVCRv zxws7y7q#+b*ANQ+s1y#9pXg=V8%nVTn+?pP?HN9@zRKZ(+dRl+TY|p znp{hS?%64Ivxl-@NY=3Zcp+v*gy2)fPpmMFbhHhW8O~0iAjfgyo-mqyx%e=pBLeEyt7;)5k}qIUT{)A6P(R*Xu|f8+gP#!;m_)M2EXo6%KT?PP=hv`3aosmBKID>b2k z4Q~kRr+C6z5`@P;$2hXk!bDL)>{Ate8sC4n31_)sE%ouz)qLOn6f!O0y5UCMB}*z% zdCdwhyOW5?+pg7q%5NhHn^9H4Ce1yp{zn6kPRKRJw?Hvg`xSj8cWA=?W@&AE%cQ~c zox3SzY%Hlc>8A%FZCxOVV@d<3>aaGmSuh>|*AQUYsaml`bemgB*{c^}3ktMBP4bJK z2%R{!u1V=i5LWmZYc4XyKKHv*3vi~U{&Fyv^6ZeMU+Xw@64ex9**OV~WvTkM(sP^@ zVC|+X(RYGDblx=3zNd)SqxrsYi*|4b%GI1tKJTw#i#9ECEBCa@qv*pmhWWnqX*nf) zlQRQ?y8l8APKFr&R!OT<{3Adn#6?EaBA4AFXvM zhm3U@Y4r0--k2+b-&0?FY3@BZO`{@w04k*^T<7`BhOvE!&H`^6?hg~Bo`|4dz3l=u z#n%hta_yj6e%}TZtoX~;LGi!)>l&0iLl;wbm+mP)_}`_h#GNF%tYuz)Pm zk0UC`Vb|ivH!739+`$B`XCX}?F-*$8HYeDX(+8g3=QFfE7KdfOZUp5tKlbo16z>Eb zPe;2LGg7NikrBNve)Y9uQ3~;&FW+PI-2r)v-!F#)b6&Bi6+i;mag3P$u7(wRl~`^C*Y=$iI3I5)CUs+UO2! zX1MHWKjz&gmAMTzY6Y#sq0dI^O9wsd17}4j?DNL0K?ovmD~0NO`y%>!((JwV9$|Vc z*?#F_2yv4&WNk%Bn=th8D$Z(}Vs3F!`zbMps*lCsiS{km*y{C]uN>uVT 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%0AK4BH%W>?^k6(fu*HE2n_@ugNou#nv|pp zFNFHPmjE&+Blk4Bcs6Y4MRfISpXRNU1Pb^ci2(@Zsj4z^gwCy#F>G%^;`c$P5ljyC zGN7Bod&1D%hjJ~Xvb>o1F!ZMX*>99~BcMJCipcO{+9*mv*x@_EOEea){q? zh92u@nhw^p(Fo_zZT%J7YMy7oFgi-p{!lz6{Um`l^o0{V2*PrfHXOMQ*>qZ?VZ80O zXVdwQd=x;D18Zxy#3wQ31GR_ScRS&2+bdSw0wCYTpUiG7lK=*z_JWD~$>d!Y+u)U! zhVJ0y;{((USlA*bfeCpwTa*ZEpe-mC_2?r1j$<1;FuR8%$Uuk0=AlLDCveo)~%u|>_JaL-TnVxTt- zKeZq-p(&(^0*U@MMhjnk5u|~@pnuS|umqDze4)KkMmQ1kZTPOVv&;4@aUk02gg3#d z1G+8ArD&ZmBEJnU%L!9Tacp4WDCv3hRWmx2k`H5npPhs1Z*Lh}kd}f~24q0bom&zS zgV)Wrp5#Uh>k=0FicqK1o1bQ|d==+xe*XY~04|GMM{T`bv;ri%9l}6-+aCEw?n{bWyKH-u8Xaor5=E zazEQZH*ghkKN}z!sQUt@nsTMDCHcFL#qzb&(*t!LVoA3sl>0AaBP;`!- zqHs=XvQ;Mp`ucThR*M4mF>OcrX7R|GYE^w#ITT+FhsG=P6_B%&+F^3Q*5xgA)kAd=GrDTCBn26?LoenwPT zZaqP(6PZbKs8HCfAXr`$qD0t^abNkUHI#q9=GEPDw)tvLW8)9FNMsdBBjCji3wH&S zXysA3r*-P1slPLV+^5X{L9H6?6U~C9qYjh}zYlG1j)vEI7A`~Pq?kH}F0!Udw0_44 zSsh?bzCxA%wS=M!s*?;QZ~3&P$4LeE#pKUZcXMGPwrFiO%df!=b#8I)$3Uz8#i;9z06 zx7Sk<$!coUAC|57pD61L?6$%~$^-h}sb7PW&6p!C7f z>+=O&DsT}$*zf~gzEGg0 zMSU}@`M%D;?0p{v#ZO&}IA;I?86=0eI|mC!4%_HK0P}LJ8CWo}O%;||g@oaCr!Paz zxZ%H#J?A-#o90}Vk;8%)PYv-Z;$G1#Nz#7)tAbraPdFNEwDH~fPu-9(#_4{WhG0su zHNC7%t?7E`?EOkUt*o;YW(s`k8wE>vn|qnyv^Bsyi$P@B#n3EEmd?hk?9GZyk~Rz5 zsec_)PLvTyEY{K#>;+{}i*UrTqhG~I;H+UGheYKak{mFr{Bc&_(fM|(6_^rCj&`6c z`&}m~;IG2hJ^3D%Qr!oHizJcALsmzrxja0B zRlq4T$o*8hbSaaCvov{S$5f!NoWfH>$$85Y7?;a-cUm)vMt%hXOK#u8HzvH>bq?*x z7UAK1R!s-leZG+Uqac4e6^Zlv$PUD#t$3`Ykw)Sz1+;1mw15t?+fpabMOu5BCtNAi zIaq=$r_L0TjIp0QnsmB&((?=uhF(W55@{g*L8*be^q8An%KMUq`q%T@osp^YmF=IQ z4^0;Sz_?{XA^PP6yGwOnZxsG08x-EFzBPfm`buTIbISVd7=w9ESx|*5Ser5!m4`e# zVUcC(a5C9gkgOYnGbd<;NoKHt5w*HAlEvak5bFDONTX^~93?K*zLg;6fA7_h{2mDP z3uifaD9WxwHP8f2P0v24!2hse3y(q&n39XA35;_zOZ1b->pj2;H=MEdaF2Ydd-CmO z)TtZrQm8wRA*aYti+vl=gLKI8?S@iJ zI?;1buouM9CO+o#S(P&DnU3)@KO~7E<_*XgzMa(y0s~25!NjTI666fc`7X>&D)L(< z9*I+T6zrf#5u`=tM*LlB`;3){j|ub|A*8cMms5U<1$j;kbo9%IDY~uKGI-TXy~>YC7bm-&r)C#Nzt7Ca(A@Sy+R+Wt25<<`5OWmJ#<1(SwqRCm zwiJYU)CVRr13svt6s-%H<5Zpczic}KKn@Yd6s-@P^g-#uFE(voJzgoWdCEyN@{%GP z`TC=v_`D;sMnU_=us$8iFt*pi!GFywREyUa>l>cmPO@T(z8(>5 z6q85Xw-P_`F|Abph9u`xLRj3seQ{t|OTDc5Rx=jcLR&FIMNL~ zI7F$xi z#CN5!mgi(rlsZ`^dn^ej5{kAq1~F@Jeq9G8(gfM0xf*IaWsZ)VL!4=%pj@u&Z`foZ zyPM|;4s+Pj-lymZWq^X>n5;K-)N;~IokRD{g3SJyhaX1A2NNpmeycls4E^-+*IHlb z$m18Q@7z+n{ci<%!lZn4^NG+d|L_^0^h97^{ovtsI7EIFB(7k0CPeSY|0+O%ayiY$ z68}Qqi;<(56C#kE^iG0Zj^o9!d$XdL%Z64Wr5Sm5+xBD*;?}8;IVsjE zgi+>cA|U;J;_3E>0`c;D%fZNfvU~pLglvMwWb$`MO9>CYmRzhX%VNE31ZW{Dh0YDc z-?Ym){dN^$g%I+QU12DitUiwN)+QltX*;PjNi5cfp$Z_=E#mtUjk$Ml^EPQ5Z(Z6k zsXU}+M8-a~KU9j0WxcRovv?cIMagC)h)G1T+IPKT>yLxPT<`W7)_Sg@k*ptLyieX3KD#gHi#Z;oNE=R;4exxadq!nU z1@DPZ#ZG_*OC;b}_K$~P`an2bD53#FbK#twgnV(DIE^Elrf;x3GrzJJD5RWN^nH)p zH&!w7E{tLn*FL6^(vp4cf$Fi})3B?miY~!H%^l-rSEXn*P3n`JE2cE~aFcs~g2|=x z&m6tEUIz(X6!;szAQK{qPjMqgtb6wDx{s5!gI?xdrOeU(v&za0ws-V^O=X%JKG_Ea zHjKrfYZv)H!&2KG;$s^I`js>(@onC8@M~s(kW|Cm)l4Yp?2eV|XTHGN6@P}00?*>; zt(L;{>M0>2TzRsg0*fkQh|AlP@XgT>SFjxftR@kQRS}2{f=1A4zBLn`2&s!t(bZJ*nw_j(@%Jm5bRe1vx5|O%IjWr{Skz+4msh58CwdwG_ zo5$(y(von}e#Y87;z7Wav$iZz?9gsKti$2|r4Ec}a2_)oe3Q=@-?WnTA)4r`!&$<> z3tid;Y0GmG8}Bl#yJDS-fYsy*|S^-z>cIfBY%m-X*yAGuClBvl7L z*qkhoqm&Wm4n3}Ccy}G1g<**Q+m%g zSQ#aJNO*O^!+7njf_d5e(W(D;jhhJBZ_TOD1VikM(hqjCKc_yG2&iAOb0tv!j9aLx zbiqhk=lbTcKiWWSU~c$3p~gvl+1Ar2)#MM<8=>lnFYYw19M5SZpZm39t=y&v@4=RF z-KkM>9tBbBeiyEgSnUsK2JlbV{H4&%O|$3bc^AbY*e2OnzEG=PQZ^*JEPSt97{E zpMdSJ9)X#V9Z(-y(Y}5?lR|B#`*16~f~1C4icqg(|87#}dpzZSE4sCEROWUdBt1jP(k;_~0roO4=>2&GS zJ?R3<4>Fbw@S8-NT{2@?-uWUaPlyFw>O#7*kVl&NqAIdED9qO28*a3wN(n?0B?EO? z$Q1v!J9Nn$pkjy&QvYUSd@6C_(E}&aRY@Pbe6aJm=rZ1pVt>;8Z{XoFNz&`*Y zI)Nh#uPNYJEzkEAP;bL|?uk5|({H9f&b-9KXVDePZYF4mbta9WA>fre= zlvF2k559xzmRB%0sEgiGum_u%{a0(1U}yWWZs{5t?C!mvixcav$ju*`#VB&MN|^+m zdHWEotOJgb9C2WFO7yu=xVv1no;9WLaO)YH_FG1{e`_h8r7h8IkyO$pQyOURgMAHC z-+~RwS*097Zmy*F2Ko9cE%hRqpZB>BQTK<7^xS*ZQFE*x z9fw`fP9$_QH6_&ZO|p3n3{C^4j-_@bUy~bYlEUm>-|P=7ejtOo4fHmfeC%uzb4xX3 zY=lWsXjsT8{7xyFXgUec7m)oYEM^B~tXydESgX#>Ch_C7oIZ3iVl=vjjRd#!MiED{ zHY$#M!{fGijN7T{UVZFcSJly8qS$OW>+f-{oLdyUe6wXIT+;6J9gb_SiEa=U3}^8ayZp~e4Zt@+ieN#uQB&Xv^; zyfM=7R7pb37YXsT=jRAqq4{Ak`(aXNP1|?X$J3|RR2s)WmELtp#yBB&&7SQJF9Hv> zft?P1MRslj-1hK6)@@*0g>6VaDieGIq9)?zmJSqo&A#KCn#$k^A^)RH?EkM9O*mju0(uC5q*8{%ZiQHKS%TvElDH7&12J zy{OfCv(=@q1#QfYj7<*XND@GN@1EQ)b=mH?y>^-+yX`FW- zf!Pa{CTAfsD^v6CTw;M;ji@AKig`SXFR}NCOffIuDQGZWB8$)6)Z8O~Otr;%yCLgE zP3%p#fc62y9^KhD)7e=O1syh2mCKNNNG-jle!_adDihxT)7nw)bLqk9d3IM$%=il4 zB(`igio7pVLQ*cf4Ed92}OA^qmk;CPW*QL3$YNK2bGp$FgQ}LXR+vZ_#=4 z+2>cxA(tY0_j7;PyqlNDR8Rx&mBFl*`ep3u6Rt9@GPCMut21fN;Xx$lNrW%6pM(bX zT_8lXJgac~hAi)_qi2<-)X2QYfqf{`F~C&gQzbyPdOt{YARS}CzVn3u+tlUb>x)^P zgd^ifC!v|>1n4k8;lzM>OI|T9H$~f?Fl_m<)mX9&C!PbRn+I<mHZbtiMe(a7lkJhfmve;wIWQ=JB2qA>2*Xtj!OL zuSL@PRL5UvM$+e@Jk*W`E5TjKURU86cULy%8^5BmGHY!xsU3CgMrD%Gl2lE`=Sq?l zZ;=k9KWQ{VjR>!z6@1siR)#ji1&VC4a3x&fFc=;N91?p(+MV=WnO~n2iU%^jIxwm- zsw|+@Sgst@_z1lFwm0A`5vdk%q-m=?m*rlh9|0rpxI1kB$3=-)s8*rnEw@FLdYaEK zBN@3@0!~g^SlX;9Y!wtwF5gvnjLsrm@&tdwF`-Csc>3iiVbrp(qL?CTvpV|dvzpV- zz&o|;4(|*k?`*p-hw9(;zp!331z)|`nyhhfk|r^HqS^ifLI8XLhz@1sWNkJ;tXgU-=)8lM&V|9i z`g{%3`j$@Tyh9s-H>chZBYR zNmLGV#-E7rF*8(7ZFE1+yu27-f)m-XW@rN?7#y)r*6)2N0dA$6*ZufuJ@}O&xI6fC z7S4T}$pHw>Ui-r)kFG1X2OvRH^e>_|Y8zP)NUX2d^rs>v2Puz(@vD%ip&hRkDlQ;f z4ChhNBX#KF<-o;T*>6mnAshiWO{@%w`73<5MbU1=*EnBvjNWQRetUwR)K&cYAv9`_ z72&;X0c+Bv{aQ39G<-Wm2-d*csuR4IG={zIMN_sA--rM90tgH?3E*0wkFU-y6-U1U zJrrb1?g>oTyrA!+6(F#BpnceVah_8?KE&_x+x;fzDu{gd)XTIZLcm`Acwz(amh;j; z(k45X@*6*3gr??KdGOK}cMG&uFj6ldJ2fcS$P1`IDi{_Lmw~wt74U#-grS1sxHOp( zoQiuPr@OKPv4d0=jczC%sdF2UrQ;eg#ej>U!pkSE(|N!Pz)h1%B?-U>=uxZhT`Zql zOclLUquNOoV)+VmQB389U$Ae1`JWb1DnAGt`#H3TLEc@s_GlG^%-+tg5b!aMWg4J4 z+iBr`WOUYq5DB*7RUOBPC+KMbCZ83Hb_snbnRNQn&`n z7Z9Fsy_SU035*}9XmWgWd`6TudW}FLD;##&sVa$=JrIYf`gz+Nf=X5tYf$~Ca5%SIReb_g_Ho5!t6RtZs^i#Xv_JxPpMZ zIS=}x-Jo$f3yHzBV)UD+HzC)$LRSZ1WT!?gQ95Gk0<0Fp{@!nk7oR)VH*)7zrKksf z3~FwWpVYlA&1Dz473esPOEy_N0e-omKx-8`?tfX2d)Zs8v;xUC!@4-@U1aYw zbxA7M@lkMfl^=KH#nHY2IHH!Z9E4=^w=@}aZ{mriVy$1->18I#p*kh z1YB9ujTTfoGAxp_2{`KLY*h{Fy$-HpxZDju4T}(IaqMXQEBL%()zR$Em>A|?EJ>$i z76;NknRe%coHd0m-Q6|o=s_RQyJWxNRjbn%h#2?X;tfjMj9lAGYTke>6_L3Z_%v@D4q~(DMa5&HFyU&H#|l{FweW= zfmj%pobUmj6KQH7`pTsni~B4P`U|M;@aMuwQOLlURMu6A{lYxLo$EoYbx!RYnF^E0 z1IvC==?_&sIt0^IYM>{x;&cD=#{yzU76N*;Mp>xZmyw$zJ(kDoAC zXZ_G!zxX3}B)kidOsd2Qo{*cM@-)}`gvMcdhH5eQB5jgHs%wS#jrLjwWvb4feaPAR zei@%NnT3%wNb_pQ58#zZjQv10gmN4{3n`>(r)hN)uU1I7F3jI;0h24#j;8{^a7q>{ zWSnFXz_qK+Bi#K6BT&Hb$!3Ud;gQ%FSkozO$dA7dQ98osP&LbEeyYHpE+f4`_%*mD zY1ln42o#3!H$hBuQlQH-ZOl`gJKtTNF5Zj3+0ZaK?@{*{iRBX6_6d9>Jro&e9oLvz z#w7D}cM`c)gApB}=`au;i|dVqW1%Gr849)z>cL+~IUs`~GfdoZ686za@iDCo#|8~l zM#^2K1Kv`BgIJA!p<5P=#DV#1%1?UdXP5eR56D#bfX)CiQ**f6T(kkIIg{ETpi1|(9o(|!+# z+@1jlxo7~bRW&pGFqU_W1U&iqX<-qaf3W(g-r4tF3N(REwg6q;NW6+3tsz&bmc92) z^UBNCEjc|}1VK@A$Eq2CxOb|5-GvAKxc*OwH~tj)rlQ8jxBLYY75imy!#T30Fgt~C z4of7_h`JO_0yqT>SX7iLeZt9fY~6+H$5~GjBJDCD@ZZFuUAdZH<-7J$!a-5-Y4RD_ zc;>n>z(XWZDuhE3*KY!PxI;OavFqKHR

2khV>-Ht|crkv%nyvmLD6Cg$tTZXe2c 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%0A&UxO6ZPSj!Faz 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

am-(G>w(W5aQuoeOBPA! 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 5!qd{k4 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%0Dwd;>2099X;X-WroYL4 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¬?{JMW#$smpekSE0RQ_p`0KYYmP2BkkMnUm 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%0Ac2SxbhLHv>Yy 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ß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 **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. + +Typical headers: + +```http +Authorization: Bearer +X-Organization-Id: org_123 +Content-Type: application/json +``` + +Every tenant-scoped request requires organization context. + +The server must verify: + +1. user is authenticated +2. organization exists +3. membership exists +4. membership is active +5. required permission is present +6. resource belongs to the organization +7. resource policy permits access +8. profession-specific rules pass + +--- + +## 9. Standard Response Format + +Single resource: + +```json +{ + "data": { + "id": "project_123", + "name": "Central Tower" + } +} +``` + +Collection: + +```json +{ + "data": [], + "meta": { + "pagination": { + "nextCursor": null, + "hasMore": false + } + } +} +``` + +Error: + +```json +{ + "error": { + "code": "PROJECT_NOT_FOUND", + "message": "Project not found.", + "details": {} + } +} +``` + +Clients should rely on `error.code`, not human-readable messages. + +--- + +## 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 +``` + +Endpoints: + +```http +POST /api/v1/auth/register +POST /api/v1/auth/login +POST /api/v1/auth/refresh +POST /api/v1/auth/logout +GET /api/v1/me +``` + +Access tokens: + +- short-lived +- signed +- identify user/session + +Refresh tokens: + +- rotated +- revocable +- stored hashed + +Future: + +- MFA +- passkeys +- SSO +- OAuth +- enterprise identity providers + +--- + +## 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 ++ +Resource Policies ++ +Professional Qualifications +``` + +Decision flow: + +```text +Authenticated User + ↓ +Organization Membership + ↓ +Roles + ↓ +Permissions + ↓ +Permission Scope + ↓ +Resource Policy + ↓ +Professional Qualification Rule + ↓ +Domain State Rule + ↓ +ALLOW / DENY +``` + +Default decision: + +```text +DENY +``` + +--- + +## 19. Roles and Permissions + +Example roles: + +```text +Owner +Administrator +Project Manager +Engineer +Lawyer +Paralegal +Doctor +Nurse +Billing Manager +Viewer +``` + +Example permissions: + +```text +clients.read +clients.create +clients.update + +documents.read +documents.upload + +billing.read +invoices.issue +payments.record + +engineering.projects.read +engineering.projects.manage +engineering.designs.approve + +legal.matters.read +legal.matters.manage + +healthcare.records.read +healthcare.records.write +``` + +--- + +## 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 table: + +```text +professional_profiles +``` + +Fields: + +```text +organization_id +user_id +profession +title +license_number +registration_number +jurisdiction +status +expiry_date +``` + +A user having a permission does not automatically mean they are professionally qualified to perform every regulated action. + +--- + +## 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 +status +created_at +updated_at +``` + +REST: + +```http +POST /api/v1/engineering/clients +GET /api/v1/engineering/clients +GET /api/v1/engineering/clients/{clientId} +PATCH /api/v1/engineering/clients/{clientId} +POST /api/v1/engineering/clients/{clientId}/archive +``` + +--- + +## 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 +POST /api/v1/engineering/projects +GET /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 +``` + +--- + +## 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 +prepared_by_user_id +approved_by_user_id +created_at +updated_at +version +``` + +Possible statuses: + +```text +draft +under_review +changes_requested +approved +superseded +``` + +REST: + +```http +POST /api/v1/engineering/projects/{projectId}/designs +GET /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 +``` + +Important approvals use explicit commands, not generic status PATCH operations. + +--- + +## 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 +performed_at +summary +created_at +updated_at +``` + +REST: + +```http +POST /api/v1/engineering/projects/{projectId}/inspections +GET /api/v1/engineering/projects/{projectId}/inspections +GET /api/v1/engineering/inspections/{inspectionId} +PATCH /api/v1/engineering/inspections/{inspectionId} + +POST /api/v1/engineering/inspections/{inspectionId}/start +POST /api/v1/engineering/inspections/{inspectionId}/complete +``` + +--- + +## 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 +``` + +REST namespace: + +```text +/api/v1/legal +``` + +Examples: + +```http +GET /api/v1/legal/clients +POST /api/v1/legal/matters +GET /api/v1/legal/matters/{id} +POST /api/v1/legal/matters/{id}/close +GET /api/v1/legal/cases +POST /api/v1/legal/hearings +POST /api/v1/legal/conflict-checks +``` + +--- + +## 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 fields: + +```text +id +organization_id +potential_client_name +related_parties +requested_by_user_id +reviewed_by_user_id +status +result +created_at +reviewed_at +``` + +--- + +# Healthcare Domain + +## 45. Healthcare Tables + +Initial tables: + +```text +healthcare_patients +healthcare_practitioners +healthcare_appointments +healthcare_encounters +healthcare_clinical_records +healthcare_diagnoses +healthcare_prescriptions +healthcare_insurance +healthcare_allergies +healthcare_medications +``` + +REST namespace: + +```text +/api/v1/healthcare +``` + +Examples: + +```http +GET /api/v1/healthcare/patients +POST /api/v1/healthcare/patients +POST /api/v1/healthcare/appointments +POST /api/v1/healthcare/encounters +GET /api/v1/healthcare/clinical-records/{id} +POST /api/v1/healthcare/prescriptions +``` + +Healthcare must have stricter privacy, auditing, retention, and credential checks. + +--- + +## 46. Healthcare Patients + +Suggested fields: + +```text +id +organization_id +patient_number +first_name +middle_name +last_name +date_of_birth +sex +phone +email +address +status +created_at +updated_at +``` + +--- + +## 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 fields: + +```text +id +organization_id +patient_id +encounter_id +author_practitioner_id +record_type +content +created_at +updated_at +``` + +Sensitive clinical content may require application-level encryption. + +--- + +# Shared Platform Services + +## 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_user_id +action +resource_type +resource_id +request_id +ip_address +user_agent +metadata +occurred_at +``` + +Examples: + +```text +engineering.project.created +engineering.design.approved +legal.matter.created +legal.document.viewed +healthcare.record.viewed +invoice.issued +membership.role_changed +``` + +Audit logs are append-only. + +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.inspection.completed +legal.hearing.scheduled +healthcare.appointment.created +invoice.issued +``` + +Consumers: + +```text +notifications +webhooks +analytics +search +integrations +background workflows +``` + +Use: + +```text +outbox_events +``` + +Transaction pattern: + +```text +BEGIN + +business update +audit event +outbox event + +COMMIT +``` + +Worker processes outbox events after commit. + +--- + +## 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 for: + +```text +job queue +rate limiting +short-lived caching +distributed locks +optional session support +``` + +PostgreSQL remains the authoritative source of truth. + +--- + +## 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 tighter privacy controls. + +Do not introduce Elasticsearch/OpenSearch until PostgreSQL is genuinely insufficient. + +--- + +## 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 +``` + +OpenAPI should define: + +- routes +- request DTOs +- response DTOs +- authentication +- error schemas +- pagination +- filters +- examples + +Generate frontend API clients when practical. + +--- + +## 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 +secure refresh token storage +rate limiting +RBAC +tenant isolation +input validation +SQL injection protection +signed object-storage URLs +audit trails +secret management +encryption at rest +dependency scanning +security headers +session revocation +``` + +--- + +## 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 +clinical access model +audit policy +retention policy +credential model +jurisdiction requirements +encryption strategy +consent requirements +data residency requirements +``` + +Healthcare should be treated as a stricter security tier. + +--- + +## 79. Observability + +Use: + +```text +structured logs +metrics +distributed tracing +request IDs +``` + +Recommended: + +```text +OpenTelemetry +``` + +Track: + +```text +API latency +error rate +database latency +database connections +queue depth +worker failures +authentication failures +authorization denials +external service failures +``` + +--- + +## 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 +authorization policies +calculations +state transitions +``` + +### Integration Tests + +Test: + +```text +repositories +PostgreSQL constraints +transactions +``` + +### API Tests + +Test: + +```text +routes +validation +authentication +authorization +error responses +``` + +### End-to-End Tests + +Test complete professional workflows. + +--- + +## 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 design +Database conventions +REST conventions +Authorization rules +Repository structure +Engineering workflows +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +Auth +Users +Organizations +Organization professions +Membership invitations +Memberships +Roles +Permissions +Authorization +Audit +Outbox +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering_clients +``` + +### Phase 3: Engineering Projects + +Build: + +```text +engineering_projects +engineering_project_members +engineering_project_phases +``` + +### Phase 4: Work Management + +Build: + +```text +engineering_tasks +engineering_sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +document_versions +object storage +signed uploads +engineering document links +``` + +### Phase 6: Designs + +Build: + +```text +engineering_designs +engineering_design_versions +engineering_design_reviews +approval rules +credential-aware authorization +``` + +### Phase 7: Inspections + +Build: + +```text +engineering_inspections +engineering_inspection_findings +follow-ups +attachments +``` + +### Phase 8: Time and Billing + +Build: + +```text +engineering_time_entries +invoices +invoice_items +payments +``` + +### Phase 9: Notifications + +Build: + +```text +in-app notifications +email +worker processing +``` + +### Phase 10: Reporting + +Initial reports: + +```text +project status +overdue tasks +inspection status +billable time +revenue +outstanding invoices +``` + +--- + +## 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 numbered migrations. + +Example: + +```text +001_core_organizations +002_core_users +003_core_memberships +004_core_rbac +005_core_audit +006_engineering_clients +007_engineering_projects +008_engineering_project_members +009_engineering_phases +010_engineering_tasks +``` + +Do not 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 + +```http +POST /auth/register +POST /auth/login +POST /auth/refresh +GET /me + +POST /organizations +GET /me/organizations + +POST /membership-invitations +GET /memberships + +GET /roles +POST /roles +GET /permissions +``` + +Goal: + +```text +Create account +↓ +Create organization +↓ +Invite team +↓ +Assign roles +``` + +### Milestone 2: Engineering Clients + +```http +POST /engineering/clients +GET /engineering/clients +GET /engineering/clients/{id} +PATCH /engineering/clients/{id} +``` + +### Milestone 3: Engineering Projects + +```http +POST /engineering/projects +GET /engineering/projects +GET /engineering/projects/{id} +PATCH /engineering/projects/{id} + +POST /engineering/projects/{id}/activate +POST /engineering/projects/{id}/close +``` + +### 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 +project document links +``` + +### Milestone 6: Designs and Inspections + +Build: + +```text +designs +reviews +approvals +inspections +findings +``` + +### Milestone 7: Commercial Workflows + +Build: + +```text +time entries +invoices +payments +reports +``` + +--- + +## 94. Architecture Rules to Freeze + +1. REST is the primary frontend and integration API. +2. Base path is `/api/v1`. +3. GraphQL is not part of v1. +4. One shared backend platform. +5. Separate frontend application for each profession. +6. Each profession owns its database tables. +7. Shared modules contain infrastructure, not profession-specific semantics. +8. Every tenant-owned row has `organization_id`. +9. Tenant isolation is enforced by both application and database. +10. Authorization is always server-side. +11. Roles and professional credentials are different concepts. +12. Profession-specific permissions use namespaces. +13. PostgreSQL is the source of truth. +14. Files live in object storage. +15. Important business transitions use explicit REST command endpoints. +16. Important mutations are audited. +17. Domain events use a transactional outbox. +18. Background side effects run through workers. +19. Start as a modular monolith. +20. Do not start with microservices. +21. Do not replace proper domain modeling with JSON blobs. +22. Do not hard-delete important professional or financial records without explicit retention rules. +23. Database models and public API DTOs are separate contracts. +24. The frontend never determines authorization. +25. Healthcare receives stricter security treatment than ordinary CRM data. +26. Engineering is the first implemented vertical. +27. Legal follows after engineering validates the platform. +28. Healthcare follows after security and compliance requirements are explicitly designed. +29. OpenAPI is the source of truth for the REST contract. +30. Reconsider GraphQL only if a demonstrated client-composition problem justifies the added complexity. + +--- + +## 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 +``` + +--- + +## 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. diff --git a/professional_management_platform_rest_plan_v2.md b/professional_management_platform_rest_plan_v2.md new file mode 100644 index 0000000..4709e56 --- /dev/null +++ b/professional_management_platform_rest_plan_v2.md @@ -0,0 +1,4581 @@ +# 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. diff --git a/professional_management_platform_rest_plan_v3.md b/professional_management_platform_rest_plan_v3.md new file mode 100644 index 0000000..be182b3 --- /dev/null +++ b/professional_management_platform_rest_plan_v3.md @@ -0,0 +1,5679 @@ +# Professional Management Platform +## Full REST-First System Design Plan + +> **Revision:** v3 — Implementation Architecture Baseline +> **Status:** Engineering-MVP implementation baseline; production readiness still requires measured evidence, security review, and profession/jurisdiction-specific validation. +> **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 + +### v3 Integration Notes + +v3 incorporates the strongest additions from the second design review while correcting several implementation traps. + +Added or strengthened: + +- webhook configuration, delivery history, retries, secret rotation, and signing +- asynchronous import/export/report job model +- engineering client contact management +- project document-link APIs +- design assignment, cancellation/withdrawal, and richer lifecycle rules +- engineering project budget and budget-item modeling +- document classification, retention, content hashing, and categories +- refresh-token family lineage with separate session and token records +- rate-limit policy framework without freezing arbitrary limits +- property-based testing for state machines +- chaos/reliability testing for transactional outbox consumers +- operational and security metrics +- explicit pre-production quality gates +- expand/contract migration requirements +- PostgreSQL 18 native UUIDv7 option +- minimum viable file-policy framework +- production checklist and observability requirements + +Corrected rather than copied literally: + +- refresh-token rotation does not create a schema conflict with `UNIQUE(refresh_token_family_id)` +- webhook HMAC secrets are not stored as one-way hashes if the server needs them for signing +- async export is modeled as a job resource rather than a side-effecting `GET` +- inspection follow-up is modeled as an outcome/linked workflow rather than overloading inspection lifecycle state +- document checksum is authoritative on document versions, not the parent document +- document confidentiality is modeled as classification rather than a single boolean +- nullable document-category uniqueness must use explicit PostgreSQL null semantics or partial indexes +- budget spent/committed values must not become uncontrolled duplicate sources of financial truth +- property-based tests distinguish valid and invalid transitions +- outbox processing assumes at-least-once delivery and therefore requires idempotent consumers +- tenant attack signals are distinct from internal tenant-isolation invariant failures +- implementation phases are milestones, not a fictional calendar commitment +- coverage percentage is a diagnostic metric, not a substitute for critical-path tests + +--- +--- + +## 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 ++ +Short-Lived Access Token ++ +Opaque Refresh Token ++ +Server-Side Session +``` + +REST 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 + +```yaml +format: JWT +lifetime: 15 minutes by default +signed: true +encrypted: false +preferred signing: asymmetric key or managed signing service +claims: + - sub / userId + - sessionId + - issuer + - audience + - issuedAt + - expiresAt +organizationId: + optional_hint: true + authorization_authority: false +``` + +The organization header and active membership remain authoritative for tenant access. + +Do not embed the complete permission set in access tokens. + +### Session and Refresh-Token Model + +A login session and a refresh token are different resources. + +Use: + +```text +sessions +refresh_tokens +``` + +Suggested `sessions` fields: + +```text +id +user_id + +device_id +device_type +device_os +app_version + +ip_address +user_agent + +created_at +last_active_at +expires_at + +revoked_at +revocation_reason +``` + +Suggested `refresh_tokens` fields: + +```text +id +session_id +family_id + +token_hash + +issued_at +expires_at + +rotated_at +replaced_by_token_id + +revoked_at +revocation_reason +``` + +Indexes/constraints: + +```text +UNIQUE(refresh_tokens.token_hash) + +INDEX(refresh_tokens.family_id) +INDEX(refresh_tokens.session_id) +INDEX(sessions.user_id, sessions.revoked_at) +``` + +Do **not** make `family_id` unique. Every rotated refresh token in the same lineage shares the same family. + +Conceptually: + +```text +Session + │ + └── Refresh Token Family + │ + ├── Token A [rotated] + │ ↓ + ├── Token B [rotated] + │ ↓ + └── Token C [current] +``` + +### Refresh Rotation + +On successful refresh: + +1. hash supplied refresh token +2. load token and session +3. validate token/session status and expiry +4. issue replacement token in same family +5. mark old token rotated +6. link `replaced_by_token_id` +7. return new access + refresh tokens + +### Reuse Detection + +If a previously rotated token is used again: + +```text +possible token theft + ↓ +revoke token family + ↓ +revoke affected session + ↓ +security audit event + ↓ +reauthentication required +``` + +Policy may escalate to revoking all user sessions for higher-risk environments. + +Audit event: + +```text +auth.refresh_token.reuse_detected +``` + +### Device Metadata + +Device metadata is useful for: + +```text +session display +security alerts +audit context +user-initiated revocation +``` + +It is not identity proof. + +Future authentication: + +- MFA +- passkeys / WebAuthn +- OIDC / SSO +- 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 core client fields: + +```text +id +organization_id +client_type +display_name +legal_name +status +created_at +updated_at +version +``` + +Do not permanently squeeze all contacts into one `email`, one `phone`, and one `contact_name`. + +Engineering customers commonly have multiple: + +```text +technical contacts +billing contacts +executive contacts +site contacts +contract contacts +``` + +Use: + +```text +engineering_client_contacts +``` + +Suggested contact fields: + +```text +id +organization_id +client_id + +name +title +department + +email +phone + +contact_type +is_primary + +created_at +updated_at +``` + +Client 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 +``` + +Contact REST: + +```http +GET /api/v1/engineering/clients/{clientId}/contacts +POST /api/v1/engineering/clients/{clientId}/contacts +PATCH /api/v1/engineering/clients/{clientId}/contacts/{contactId} +DELETE /api/v1/engineering/clients/{clientId}/contacts/{contactId} +``` + +Delete may be implemented as archival when contact history matters. + +Client restore is allowed only when organization policy and retention rules permit it. + +## 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 +``` + +Suggested states: + +```text +draft +under_review +changes_requested +approved +rejected +cancelled +withdrawn +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}/cancel +POST /api/v1/engineering/designs/{designId}/withdraw +POST /api/v1/engineering/designs/{designId}/supersede + +POST /api/v1/engineering/designs/{designId}/assign +POST /api/v1/engineering/designs/{designId}/unassign + +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 +``` + +### Assignment Model + +Use: + +```text +engineering_design_assignments +``` + +Possible assignment roles: + +```text +owner +designer +reviewer +approver +checker +``` + +Suggested fields: + +```text +id +organization_id +design_id +user_id +assignment_role +notes +assigned_by_user_id +assigned_at +unassigned_at +``` + +Assignment does not automatically grant platform permission. Both RBAC and resource policy still apply. + +### Design State Machine + +```text +draft + ├── submit-review ───────────────► under_review + └── cancel ──────────────────────► cancelled + +under_review + ├── request-changes ─────────────► changes_requested + ├── approve ─────────────────────► approved + ├── reject ──────────────────────► rejected + └── withdraw ────────────────────► withdrawn + +changes_requested + ├── submit-review ───────────────► under_review + └── withdraw ────────────────────► withdrawn + +rejected + └── revise ──────────────────────► draft + +approved + └── supersede ───────────────────► superseded +``` + +Use `cancelled` for work stopped before formal review. + +Use `withdrawn` for work intentionally removed after review workflow has started. + +Approval requires: + +```text +permission ++ +project access ++ +appropriate assignment/policy ++ +valid professional qualification ++ +valid design state ++ +organization approval policy +``` + +Approval, rejection, withdrawal, and supersession are audited. + +Approval is idempotent. + +Do not approve by PATCHing `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 +outcome + +scheduled_at +started_at +performed_at +cancelled_at + +summary + +created_at +updated_at +version +``` + +Lifecycle status: + +```text +draft +scheduled +in_progress +completed +cancelled +``` + +Outcome is separate: + +```text +passed +passed_with_observations +followup_required +failed +``` + +This distinction matters. + +An inspection can be fully completed and still require corrective work. + +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 + +POST /api/v1/engineering/inspections/{inspectionId}/followups +GET /api/v1/engineering/inspections/{inspectionId}/followups +``` + +A follow-up may be: + +```text +corrective task +new inspection +or both +``` + +Do not encode all follow-up workflow into the original inspection's lifecycle state. + +Inspection completion: + +1. validate inspector and project access +2. validate required fields +3. validate findings +4. calculate or confirm outcome +5. complete inspection +6. create corrective work/follow-up records when required +7. audit +8. write outbox event +9. notify appropriate participants + +Completion is idempotent. + +## 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 +``` + +--- + +## 38A. Engineering Project Budgets + +A single `budget_minor` column is sufficient only for a very early project total. + +When budget management enters scope, introduce: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries +``` + +### Budget + +Suggested fields: + +```text +id +organization_id +project_id + +name +currency_code +status + +approved_by_user_id +approved_at + +created_at +updated_at +version +``` + +### Budget Item + +Suggested fields: + +```text +id +organization_id +budget_id + +category +description + +allocated_amount_minor + +created_at +updated_at +``` + +Do not casually store mutable: + +```text +spent_amount_minor +committed_amount_minor +``` + +as independent sources of truth if those values are derived from time entries, expenses, purchase commitments, or invoices. + +Prefer: + +```text +authoritative cost/commitment records + ↓ +derived budget projections +``` + +If denormalized totals are needed for performance, update them transactionally and reconcile them. + +Potential REST: + +```http +GET /api/v1/engineering/projects/{projectId}/budgets +POST /api/v1/engineering/projects/{projectId}/budgets +GET /api/v1/engineering/budgets/{budgetId} +PATCH /api/v1/engineering/budgets/{budgetId} + +POST /api/v1/engineering/budgets/{budgetId}/approve +GET /api/v1/engineering/budgets/{budgetId}/items +POST /api/v1/engineering/budgets/{budgetId}/items +``` + +Budget approval is an explicit command. + +--- + +## 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 +document_categories +retention_policies +``` + +Binary data: + +```text +S3-compatible object storage +``` + +### Document + +Suggested fields: + +```text +id +organization_id + +name +category_id + +classification + +retention_policy_id + +current_version_id + +created_by_user_id +created_at +updated_at +``` + +Classification examples: + +```text +public +internal +confidential +restricted +regulated +``` + +Avoid a single `is_confidential` boolean as the long-term security model. + +### Document Version + +Suggested fields: + +```text +id +organization_id +document_id + +version_number + +storage_key + +mime_type +size_bytes + +content_hash +hash_algorithm + +uploaded_by_user_id +created_at +``` + +The authoritative checksum belongs on the version because each binary revision has different content. + +Optional document-level metadata may include: + +```text +current_version_id +current_version_number +``` + +but should not replace version-level integrity data. + +### Metadata + +Use JSONB only for genuinely extensible metadata that does not deserve stable relational columns. + +Examples: + +```text +CAD-specific extraction results +scanner metadata +non-authoritative document properties +``` + +Do not place access control, retention state, ownership, or lifecycle rules inside arbitrary metadata JSON. + +### Document Categories + +Suggested fields: + +```text +id +organization_id +profession nullable +name +parent_category_id +created_at +``` + +If `profession` is nullable and shared categories must remain unique, PostgreSQL uniqueness must explicitly handle nulls. + +Options include: + +```text +UNIQUE NULLS NOT DISTINCT +``` + +where supported, or separate partial unique indexes for: + +```text +profession IS NULL +profession IS NOT NULL +``` + +Do not rely on a plain nullable composite unique constraint and assume NULL behaves like a normal value. + +### Upload Security + +Validate: + +```text +declared MIME +extension +magic bytes/content signature +file size +malware scan +organization quota +classification policy +``` + +A renamed executable is not a PDF merely because the filename developed ambition. + +## 52. Document Upload Flow + +```text +Frontend + ↓ +Request upload authorization + ↓ +Backend validates tenant + permission + upload policy + ↓ +Create pending document/version + ↓ +Return signed upload URL + ↓ +Frontend uploads directly to object storage + ↓ +Backend finalizes upload + ↓ +Verify size / checksum / content type + ↓ +Malware and security scanning + ↓ +Apply classification / retention + ↓ +Mark version 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 +``` + +### File Policy + +Do not freeze arbitrary product quotas into architecture. + +Model a policy: + +```text +document_upload_policy +├── max_file_size_bytes +├── allowed_file_classes +├── organization_storage_quota_bytes +├── profession_overrides +└── plan/tier overrides +``` + +Engineering may eventually allow file classes such as: + +```text +PDF +images +DWG/DXF +spreadsheets +office documents +``` + +Healthcare may later have different file policies. + +Exact limits are product/configuration decisions validated against storage cost, threat model, and customer needs. + +## 53. Profession-Specific Document Links + +Use explicit relationship tables. + +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 +``` + +### Engineering Project Documents + +Suggested link fields: + +```text +id +organization_id +project_id +document_id + +category +classification_override nullable + +linked_by_user_id +linked_at +unlinked_at +``` + +REST: + +```http +GET /api/v1/engineering/projects/{projectId}/documents +POST /api/v1/engineering/projects/{projectId}/documents + +DELETE /api/v1/engineering/project-documents/{documentLinkId} +``` + +Link deletion may preserve historical linkage through `unlinked_at` when required. + +Example response: + +```json +{ + "data": [ + { + "documentLinkId": "projdoc_123", + "category": "calculations", + "document": { + "id": "doc_456", + "name": "structural_calculations.pdf", + "classification": "confidential", + "currentVersion": 2, + "mimeType": "application/pdf", + "sizeBytes": 2457600 + } + } + ] +} +``` + +Explicit link resources give stronger referential integrity than generic polymorphic foreign keys. + +## 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 +``` + +Transaction: + +```text +BEGIN + +business change +audit event +outbox event + +COMMIT +``` + +The outbox is **at-least-once delivery**, not magically exactly-once. + +Worker claim example: + +```sql +SELECT id +FROM outbox_events +WHERE processed_at IS NULL + AND dead_lettered_at IS NULL + AND available_at <= now() +ORDER BY occurred_at +FOR UPDATE SKIP LOCKED +LIMIT 100; +``` + +Worker responsibilities: + +1. claim committed event +2. process consumer action +3. mark processed on success +4. increment attempts on failure +5. schedule retry with backoff +6. dead-letter after policy threshold +7. emit metrics +8. preserve replay/debug metadata + +### Critical Failure Case + +A worker may: + +```text +perform external side effect + ↓ +crash + ↓ +fail to mark event processed + ↓ +event is retried +``` + +Therefore every external consumer must support idempotency. + +Examples: + +```text +payment provider command → provider idempotency key +webhook delivery → delivery/event ID +email notification → dedupe key if duplicate mail is unacceptable +search indexing → upsert by entity/version +``` + +`FOR UPDATE SKIP LOCKED` prevents concurrent claims. It does **not** prevent duplicate side effects after a crash. + +Workers may be awakened by queue notifications, but must still poll durable outbox state so lost wake-ups do not strand events. + +## 57A. Webhooks and External Integrations + +Webhooks are a shared platform capability, not profession-specific transport code. + +Configuration REST: + +```http +GET /api/v1/webhooks +POST /api/v1/webhooks +GET /api/v1/webhooks/{webhookId} +PATCH /api/v1/webhooks/{webhookId} +DELETE /api/v1/webhooks/{webhookId} + +POST /api/v1/webhooks/{webhookId}/test +POST /api/v1/webhooks/{webhookId}/rotate-secret +``` + +Delivery REST: + +```http +GET /api/v1/webhook-deliveries +GET /api/v1/webhook-deliveries/{deliveryId} +POST /api/v1/webhook-deliveries/{deliveryId}/retry +``` + +Suggested tables: + +```text +webhooks +webhook_event_subscriptions +webhook_deliveries +``` + +Webhook fields: + +```text +id +organization_id +url +status +secret_ciphertext or signing_key_reference +created_by_user_id +created_at +updated_at +``` + +Do not return a secret hash to the client. + +### Secret Handling + +If using symmetric HMAC signing: + +```text +generate secret + ↓ +show plaintext once + ↓ +encrypt using KMS/key-management system + ↓ +store ciphertext + ↓ +decrypt only for signing +``` + +A one-way hash alone is insufficient because the server must possess the signing material. + +Alternative: + +```text +asymmetric signing ++ +published verification key +``` + +### Delivery Model + +Each delivery records: + +```text +id +organization_id +webhook_id +event_id + +attempt_number +request_timestamp +response_status +response_summary + +delivered_at +failed_at +next_attempt_at +``` + +Webhook workers require: + +```text +timeouts +retry with backoff +dead-letter/failure state +request signing +event IDs +idempotency guidance for consumers +delivery history +manual replay +``` + +Events should include stable identifiers so consumers can deduplicate. + +Example: + +```json +{ + "id": "evt_123", + "type": "engineering.design.approved", + "organizationId": "org_456", + "occurredAt": "2026-08-26T12:00:00Z", + "data": { + "designId": "design_789" + } +} +``` + +--- + +## 58. Background Jobs + +Workers handle: + +```text +Email +SMS +Notifications + +PDF/report generation + +File security scanning +Document processing + +Imports +Exports +Bulk updates + +Webhook delivery +Search indexing + +Large data operations +``` + +Architecture: + +```text +API + ↓ +Queue + ↓ +Worker +``` + +### Async Job Resource + +Use a shared job model for long-running user-requested operations. + +Suggested table: + +```text +jobs +``` + +Fields: + +```text +id +organization_id +requested_by_user_id + +job_type +status + +input_reference +result_reference + +progress_percent + +created_at +started_at +completed_at +failed_at + +error_code +error_summary +``` + +States: + +```text +queued +running +completed +failed +cancelled +``` + +REST: + +```http +GET /api/v1/jobs/{jobId} +GET /api/v1/jobs/{jobId}/result +POST /api/v1/jobs/{jobId}/cancel +``` + +### Import / Export + +Do not create asynchronous side effects with `GET`. + +Engineering examples: + +```http +POST /api/v1/engineering/project-imports +POST /api/v1/engineering/project-exports + +POST /api/v1/engineering/time-entry-imports +POST /api/v1/engineering/time-entry-exports +``` + +Response: + +```http +202 Accepted +``` + +```json +{ + "data": { + "jobId": "job_123", + "status": "queued" + } +} +``` + +Initial formats may include: + +```text +CSV +JSON +``` + +Import requirements: + +```text +validation report +row-level errors +all-or-partial mode explicitly defined +idempotency strategy +audit event +job result artifact +``` + +Export requirements: + +```text +authorization applied before generation +signed result URL +expiration +audit where data sensitivity requires it +``` + +## 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 +Argon2id or equivalent strong password hashing +short-lived access tokens +refresh-token rotation +refresh-token reuse detection +server-side session revocation + +rate limiting +anti-automation controls + +RBAC +resource policies +credential-aware authorization +tenant isolation + +input validation +SQL injection protection + +signed object-storage URLs +file-content validation +malware scanning + +audit trails +secret management +encryption at rest + +dependency scanning +container/image scanning +security headers + +request/correlation IDs +backup and restore testing +``` + +### Rate Limiting + +Model policy rather than baking arbitrary numbers into architecture. + +Example: + +```typescript +interface RateLimitRule { + routePattern: string; + method: string; + windowSeconds: number; + maxRequests: number; + scope: 'user' | 'organization' | 'ip' | 'email' | 'session'; +} +``` + +Policy classes: + +```text +authentication +password recovery +general API +search +upload authorization +report generation +webhooks/integrations +clinical record reads +``` + +Rate-limit values are configuration derived from: + +```text +security testing +load testing +observed traffic +customer tier +endpoint cost +abuse risk +``` + +Do not grant normal tenant roles blanket rate-limit bypass. + +Administrative exceptions, if any, require explicit trusted-system policy. + +Return: + +```http +429 Too Many Requests +Retry-After: ... +``` + +Error: + +```text +RATE_LIMIT_EXCEEDED +``` + +### Secrets + +Use managed secrets/key management where possible. + +Never put real secrets in source-controlled examples. + +Prefer JWT asymmetric signing or managed signing keys with rotation capability. + +## 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 +``` + +### Core Metrics + +API: + +```text +api_requests_total +api_errors_total +api_request_duration_seconds +``` + +Authentication: + +```text +auth_login_attempts_total +auth_token_refresh_total +auth_refresh_reuse_detections_total +auth_sessions_revoked_total +``` + +Authorization/security: + +```text +cross_tenant_access_attempts_total +tenant_isolation_invariant_failures_total +authorization_denials_total +credential_policy_denials_total +rate_limit_events_total +``` + +Important distinction: + +```text +cross_tenant_access_attempt += +request attempted another tenant's resource +``` + +This may be a stale link, mistake, or attack. + +```text +tenant_isolation_invariant_failure += +our system nearly or actually created/returned cross-tenant data +``` + +That is a high-severity internal correctness/security incident. + +Outbox/jobs/webhooks: + +```text +outbox_events_pending +outbox_events_failed_total +outbox_processing_duration_seconds + +jobs_queued +jobs_failed_total +job_duration_seconds + +webhook_delivery_attempts_total +webhook_delivery_failures_total +webhook_delivery_latency_seconds +``` + +Database: + +```text +db_pool_active +db_pool_waiting +db_query_duration_seconds +db_transaction_duration_seconds +``` + +Business metrics may include: + +```text +engineering_projects_created_total +engineering_designs_approved_total +engineering_inspections_completed_total +invoices_issued_total +``` + +Avoid patient-specific or sensitive identifiers in metric labels. + +### Alerts + +Examples: + +```text +refresh token reuse detected +tenant isolation invariant failure +outbox backlog exceeds SLO +webhook failure spike +database pool saturation +error-rate spike +latency regression +backup failure +malware scanner unavailable +``` + +Thresholds are calibrated from real environments rather than copied from a review document. + +### SLOs + +Define by endpoint class. + +Interactive CRUD, reports, file orchestration, and background jobs should not share one arbitrary latency target. + +## 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 +``` + +### Property-Based Tests + +Use property-based testing for high-value domain state machines. + +Candidates: + +```text +engineering design lifecycle +engineering inspection lifecycle +invoice lifecycle +payment state transitions +membership/role invariants +``` + +Correct properties: + +```text +every successful transition ends in a valid state + +every forbidden transition is rejected + +terminal states reject prohibited actions + +required invariants survive every valid transition + +transition sequences never bypass required approval/credential rules +``` + +Do not assert that every random state/action pair succeeds. Many are supposed to fail. + +### Integration Tests + +Test: + +```text +repositories +tenant-aware foreign keys +PostgreSQL constraints +transactions +outbox persistence +idempotency persistence +cache invalidation +job persistence +webhook delivery persistence +``` + +### API Tests + +Every important endpoint covers: + +```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 creation +outbox creation +``` + +### Outbox Reliability / Chaos Tests + +Test: + +```text +worker crash before side effect +worker crash after side effect but before marking processed +two workers competing for same row +temporary dependency outage +retry/backoff behavior +dead-letter behavior +consumer idempotency +lost worker wake-up +replay +``` + +The dangerous scenario is: + +```text +external side effect succeeds +worker dies +event retries +``` + +Tests must prove the consumer does not create an unacceptable duplicate. + +### Tenant Security Tests + +Test both: + +```text +external cross-tenant access attempts +``` + +and: + +```text +internal cross-tenant data invariant failures +``` + +These are different classes of failure. + +### Performance Tests + +Create realistic profiles: + +```text +interactive reads +interactive writes +search +dashboard read models +reporting +file upload orchestration +outbox processing +webhook bursts +notification bursts +``` + +Measure: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +``` + +Set production SLO gates only after a realistic baseline exists. + +### Coverage + +Track code coverage. + +Do not treat a single percentage such as `90%` as proof of quality. + +Critical-path expectations are stronger: + +```text +all tenant-isolation paths tested +all financial commands tested +all regulated commands tested +all state transitions tested +all critical authorization policies tested +``` + +## 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 model +idempotency strategy +error taxonomy +OpenAPI skeleton +engineering state machines +migration conventions +threat model +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +auth +sessions +refresh-token families +token rotation/revocation + +users +organizations +organization professions + +membership invitations +memberships +roles +permissions +authorization + +audit +outbox + +request context +idempotency persistence +rate-limit framework + +observability foundation +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering_clients +engineering_client_contacts +client archive/restore +``` + +### Phase 3: Engineering Projects + +Build: + +```text +engineering_projects +engineering_project_members +engineering_project_phases +activation/close/archive +``` + +### Phase 4: Work and Site Management + +Build: + +```text +engineering_tasks +engineering_sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +document_versions +document categories +classification +retention policy references +signed uploads +content verification +malware scanning +engineering document links +``` + +### Phase 6: Engineering Designs + +Build: + +```text +engineering_designs +design assignments +design versions +design reviews +state machine +credential-aware approval +audit +outbox +idempotency +``` + +### Phase 7: Engineering Inspections + +Build: + +```text +inspection lifecycle +inspection outcome +findings +corrective work +follow-up inspections +attachments +audit +outbox +idempotency +``` + +### Phase 8: Time, Budgets, and Billing + +Build: + +```text +engineering_time_entries +project budgets when in product scope +invoices +invoice items +payments +financial idempotency +reconciliation +``` + +### Phase 9: Notifications, Jobs, and Webhooks + +Build: + +```text +in-app notifications +email +async jobs +imports/exports +webhook configuration +webhook delivery/retry +dead-letter handling +``` + +### Phase 10: Reporting and Search + +Build: + +```text +project status +overdue work +inspection status +billable time +revenue +outstanding invoices +engineering dashboard read models +``` + +Add advanced indexes, materialized views, read replicas, or external search only if measured need justifies them. + +### Phase 11: Legal Vertical + +Validate the shared core against: + +```text +matters +cases +conflicts +legal deadlines +retainers +ethical-wall/restricted access requirements +``` + +### Phase 12: Healthcare Readiness and Vertical + +Before implementation: + +```text +healthcare threat model +privacy review +jurisdiction analysis +credential/scope-of-practice policy +record signing/amendment model +retention model +audit requirements +``` + +Then implement healthcare. + +### Estimation Rule + +These are dependency-ordered milestones, not calendar promises. + +Calendar estimates are produced only after: + +```text +team size +frontend scope +UX designs +cloud choices +third-party providers +security requirements +QA capacity +engineering-domain details +``` + +are known. + +## 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 uses UUIDv7. + +Supported implementation choices: + +```text +PostgreSQL 18+: + use native uuidv7() if database-generated identifiers are desired + +Earlier PostgreSQL: + generate UUIDv7 in the application or use a controlled extension +``` + +Database columns remain PostgreSQL `UUID`. + +The rule is consistency, not ideological loyalty to one generation layer. + +Do not silently fall back to UUIDv4 while documenting UUIDv7. + +### Production Migration Rules + +Use expand/contract: + +```text +1. add backward-compatible schema +2. deploy code supporting old + new schema +3. backfill/migrate +4. switch reads/writes +5. observe +6. remove obsolete schema later +``` + +For destructive changes: + +```text +backup/restore plan +compatibility window +production-like dry run +explicit approval +post-migration verification +``` + +Do not assume a destructive database migration can always be reversed by a simple down migration. + +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 API contract. +4. GraphQL is not part of v1. +5. Begin as one modular monolith backend. +6. Each profession has its own frontend. +7. Each profession owns its domain tables and state machines. +8. Shared modules provide infrastructure rather than forced domain abstractions. +9. Every tenant-owned row contains `organization_id`. +10. Tenant-scoped requests require explicit `X-Organization-Id`. +11. The API never silently selects an organization. +12. Tenant boundaries are enforced in queries and database constraints. +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 commands validate authoritative credential state. +17. Sessions and refresh-token records are separate concepts. +18. Refresh-token rotation uses token families and reuse detection. +19. UUIDv7 is the identifier standard. +20. PostgreSQL 18 native `uuidv7()` may be used when PostgreSQL 18+ is the baseline. +21. Important domain transitions use explicit REST command endpoints. +22. High-risk commands use durable idempotency. +23. Redis may accelerate idempotency but is not authoritative for financial/regulated commands. +24. Profession-specific state transitions are explicitly modeled and tested. +25. Engineering design cancellation and post-review withdrawal are semantically distinct where needed. +26. Inspection lifecycle and inspection outcome are separate dimensions. +27. Follow-up inspection work is linked work, not an overloaded lifecycle status. +28. Shared document binaries live in object storage. +29. Document checksum belongs to document versions. +30. Document classification is multi-level, not a single confidentiality boolean. +31. File upload policy is configurable by organization/profession/product tier. +32. Uploads validate declared MIME, extension, content signature, size, quota, and malware status. +33. Explicit document-link tables are preferred over generic polymorphic references. +34. Domain events use a transactional outbox. +35. Outbox semantics are at-least-once. +36. Every outbox consumer that can create external side effects is idempotent. +37. Webhooks are a shared platform service with delivery history and retry. +38. HMAC webhook signing material must be recoverable securely, normally encrypted with managed key protection. +39. Async imports, exports, and reports use job resources and return `202 Accepted`. +40. `GET` endpoints do not create export jobs. +41. Engineering clients support multiple contacts. +42. Engineering budget detail uses dedicated tables when budget management enters scope. +43. Derived spent/committed budget totals must not become uncontrolled duplicate financial truth. +44. PostgreSQL remains the authoritative transactional datastore. +45. Redis is an acceleration/coordination layer. +46. Search starts with PostgreSQL. +47. External search, read replicas, materialized views, and partitioning require measured evidence. +48. API collections use cursor pagination. +49. Important mutable resources use optimistic concurrency. +50. Database entities are not serialized directly as public API contracts. +51. Errors use stable codes. +52. Important and regulated actions are audited. +53. Sensitive healthcare reads are audited when policy requires. +54. Signed clinical records use sign/amend/version workflows. +55. Prescribing authority is jurisdiction and scope-of-practice policy, not a hard-coded profession. +56. Production migrations follow expand/contract. +57. Destructive schema changes are not assumed to be trivially reversible. +58. Secrets are managed outside source control. +59. Rate limits are configurable policies calibrated by security/load evidence. +60. CI validates types, tests, OpenAPI, migrations, and security scans. +61. Property-based tests are used for high-value state machines. +62. Outbox/job/webhook reliability is tested under failure and concurrency. +63. Internal tenant-isolation invariant failures and external cross-tenant attempts are separate observability signals. +64. Critical-path tests matter more than a vanity coverage percentage. +65. Engineering is the first implemented product vertical. +66. Legal follows after the engineering product validates shared assumptions. +67. Healthcare requires explicit security/privacy/jurisdiction readiness work before implementation. +68. Architecture documentation never equates "designed for" with "certified/compliant". +69. Milestones define implementation order; calendar estimates require actual delivery context. + +## 95. Required Design Artifacts + +Maintain: + +```text +01_PROJECT_ARCHITECTURE.md +02_DATABASE_CONVENTIONS.md +03_AUTHORIZATION_MODEL.md +04_AUTH_SESSION_MODEL.md +05_ENGINEERING_DOMAIN.md +06_ENGINEERING_DATABASE_SCHEMA.md +07_API_CONVENTIONS.md +08_ENGINEERING_API_SPEC.md +09_FRONTEND_ARCHITECTURE.md +10_DOCUMENT_SECURITY_MODEL.md +11_WEBHOOK_INTEGRATION_MODEL.md +12_ASYNC_JOB_MODEL.md +13_SECURITY_MODEL.md +14_DEPLOYMENT_ARCHITECTURE.md +15_OBSERVABILITY_MODEL.md +16_TESTING_STRATEGY.md +17_MVP_BACKLOG.md +18_OPENAPI.yaml +``` + +Supporting state-machine documents should exist for: + +```text +engineering projects +engineering designs +engineering inspections +invoices/payments +clinical records when healthcare begins +``` + +## 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 need efficient tenant scoping. + +Baseline: + +```text +(organization_id, id) +``` + +Common list access often benefits from: + +```text +(organization_id, created_at) +``` + +Query-specific examples: + +```text +(organization_id, status) +(organization_id, client_id) +(organization_id, project_id) +(organization_id, assigned_to_user_id) +``` + +### Rules + +1. every index corresponds to a known query, ordering, or constraint +2. column order follows real predicates +3. validate with `EXPLAIN (ANALYZE, BUFFERS)` +4. include production-like cardinality in testing +5. measure write amplification +6. do not index every field +7. introduce trigram/full-text indexes only for actual search requirements + +Potential later tools: + +```text +covering indexes +materialized views +read replicas +table partitioning +external search +``` + +These are evidence-driven scaling mechanisms, not baseline dependencies. + +### Document Category Uniqueness + +If a nullable field such as profession participates in uniqueness: + +```text +organization_id +profession nullable +name +``` + +do not assume plain uniqueness treats NULL as one shared value. + +Use PostgreSQL-supported null-aware uniqueness or partial unique indexes according to the selected PostgreSQL version. + +--- + +## 97B.## 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. + +--- + +## 97D. Production Readiness Gates + +Architecture being coherent does not mean production is safe. + +Before production, require evidence in these categories. + +### Security + +```text +TLS configured +password hashing configured +refresh rotation/reuse detection tested +session revocation tested +tenant isolation tests passing +authorization/credential policies tested +rate limiting active +secrets managed outside source control +file security scanning active +security review completed +``` + +### Reliability + +```text +database backups automated +restore tested +object storage recovery strategy tested +outbox monitoring active +job queue monitoring active +webhook retry/dead-letter behavior tested +health checks configured +dependency failures tested +``` + +### Data Integrity + +```text +tenant-aware foreign keys present where required +financial invariants tested +migration tested on production-like data +idempotency tested for high-risk commands +optimistic concurrency tested +audit integrity tested +``` + +### Contract / API + +```text +OpenAPI validates +contract tests pass +error schema consistent +versioning rules documented +client SDK generation validated if used +``` + +### Performance + +```text +load test executed +realistic SLOs defined +database pool configured +key queries analyzed +outbox/job backlogs remain within SLO +``` + +### Critical Domain Coverage + +Rather than a magic overall coverage number, require explicit test coverage for: + +```text +tenant boundaries +design approval +inspection completion +invoice issue +payment/refund +membership privilege changes +clinical record signing/amendment when healthcare exists +prescribing authorization when healthcare exists +``` + +### Release Gate Principle + +No single metric such as: + +```text +90% test coverage +``` + +is sufficient evidence of production readiness. + +Quality gates are based on critical behavior, not vanity percentages. + +--- + +## 97. Final Design Position + +The platform is: + +```text +One Shared Platform + │ + ├── Shared Identity / Sessions + ├── Shared Security / Authorization + ├── Shared Documents + ├── Shared Financial Core + ├── Shared Audit / Outbox + ├── Shared Jobs / Webhooks / Notifications + │ + ├── Engineering Product + │ ├── Engineering Frontend + │ ├── Engineering REST APIs + │ ├── Engineering State Machines + │ └── Engineering Tables + │ + ├── Legal Product + │ ├── Legal Frontend + │ ├── Legal REST APIs + │ └── Legal Tables + │ + └── Healthcare Product + ├── Healthcare Frontend + ├── Healthcare REST APIs + ├── Healthcare Security Policies + └── Healthcare Tables +``` + +The system shares infrastructure where reuse is valuable while preserving independent domain semantics where professional workflows differ. + +v3 is the implementation baseline for the Engineering MVP. + +It is not, by itself, evidence of: + +```text +production certification +regulatory compliance +security certification +performance at a specific scale +``` + +Those claims require implementation evidence, security testing, operational controls, measured load results, restore tests, and profession/jurisdiction-specific review. + + + +--- + +# v3 Changelog + +Compared with v2, v3 adds or changes: + +```text +✓ corrected refresh-token family persistence +✓ PostgreSQL 18 UUIDv7 option +✓ engineering client contacts +✓ engineering design assignments +✓ cancelled vs withdrawn design semantics +✓ inspection outcome separate from lifecycle +✓ linked follow-up inspection workflow +✓ project budget domain model +✓ version-level document checksums +✓ document classification and categories +✓ upload policy and content validation +✓ webhook configuration and delivery model +✓ encrypted/recoverable webhook signing material +✓ async job architecture +✓ import/export as POST + 202 job creation +✓ at-least-once outbox semantics made explicit +✓ idempotent outbox consumers required +✓ property-based state-machine testing +✓ chaos tests for outbox/job processing +✓ separate tenant-attack and invariant-failure metrics +✓ milestone-based delivery planning +✓ critical-path production readiness gates +✓ no arbitrary code-coverage production target +``` diff --git a/professional_management_platform_rest_plan_v4.md b/professional_management_platform_rest_plan_v4.md new file mode 100644 index 0000000..2bd0505 --- /dev/null +++ b/professional_management_platform_rest_plan_v4.md @@ -0,0 +1,6298 @@ +# Professional Management Platform +## Full REST-First System Design Plan + +> **Revision:** v4 — Final Broad Architecture Baseline +> **Status:** Final broad architecture baseline for Engineering MVP implementation. Further changes should move into ADRs, OpenAPI, schemas, migrations, and backlog items rather than repeatedly reopening platform architecture. +> **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 + +### v4 Integration Notes + +v4 incorporates the remaining high-value refinements from the latest architecture review without reopening settled platform decisions. + +Added: + +- dedicated engineering client portal architecture +- external-user access grants distinct from internal organization memberships +- client review/acceptance separated from professional engineering approval +- explicit project-document publication controls for external audiences +- synchronous batch-command semantics for small batches +- asynchronous job escalation for large batch operations +- explicit atomic vs partial-success batch behavior +- native object-storage multipart upload orchestration for very large engineering files +- rate-limit metadata policy without freezing legacy `X-RateLimit-*` headers +- technology ADR requirements instead of treating framework suggestions as settled architecture +- provisional performance objectives separated from contractual SLOs +- risk register with impact, mitigation, owner, phase, and status +- API error-standard ADR to evaluate RFC 9457 Problem Details compatibility +- final architecture-change governance to prevent endless review churn + +Explicitly rejected as permanent architecture: + +- client contacts becoming ordinary internal organization memberships +- external client acceptance being represented as professional design approval +- API servers proxying multi-gigabyte file chunks +- fixed `X-RateLimit-Limit/Remaining/Reset` as permanent contract +- framework/ORM choices being declared "confirmed" without an ADR +- arbitrary maturity percentages such as 95% architecture readiness +- fixed calendar promises before delivery context exists + +--- +--- +--- + +## 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. + +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 expose another organization's identity in tenant-error responses. + +### Idempotency + +Use: + +```http +Idempotency-Key: 8f7d6c5e-4b3a-2b1c-9d8e-7f6a5b4c3d2e +``` + +Idempotency is required where duplicate execution can create 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 +``` + +Idempotency records include: + +```text +organization_id +actor_id +route/action +idempotency_key +canonical_request_hash +response_status +response_body or result reference +created_at +expires_at +``` + +Rules: + +```yaml +same_key_same_request: + return: original result + +same_key_different_request: + status: 409 + code: IDEMPOTENCY_KEY_CONFLICT +``` + +PostgreSQL is authoritative for critical idempotency records. + +Redis may accelerate lookup. + +### Rate-Limit Responses + +Rate-limited requests return: + +```http +429 Too Many Requests +Retry-After: +``` + +Additional quota metadata may be exposed. + +Do **not** freeze legacy `X-RateLimit-*` header names into the architecture. + +The exact rate-limit response-header convention is selected and documented in the API ADR/OpenAPI contract based on the gateway and adopted standard at implementation time. + +### Error Standard Decision + +The current platform error envelope remains valid: + +```json +{ + "error": { + "code": "RESOURCE_NOT_FOUND", + "message": "Resource not found.", + "details": {}, + "requestId": "req_123" + } +} +``` + +Before OpenAPI v1 is frozen, create an ADR evaluating compatibility with RFC 9457 Problem Details. + +Do not silently change the error envelope during implementation. + +## 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 ++ +Short-Lived Access Token ++ +Opaque Refresh Token ++ +Server-Side Session +``` + +REST 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 + +```yaml +format: JWT +lifetime: 15 minutes by default +signed: true +encrypted: false +preferred signing: asymmetric key or managed signing service +claims: + - sub / userId + - sessionId + - issuer + - audience + - issuedAt + - expiresAt +organizationId: + optional_hint: true + authorization_authority: false +``` + +The organization header and active membership remain authoritative for tenant access. + +Do not embed the complete permission set in access tokens. + +### Session and Refresh-Token Model + +A login session and a refresh token are different resources. + +Use: + +```text +sessions +refresh_tokens +``` + +Suggested `sessions` fields: + +```text +id +user_id + +device_id +device_type +device_os +app_version + +ip_address +user_agent + +created_at +last_active_at +expires_at + +revoked_at +revocation_reason +``` + +Suggested `refresh_tokens` fields: + +```text +id +session_id +family_id + +token_hash + +issued_at +expires_at + +rotated_at +replaced_by_token_id + +revoked_at +revocation_reason +``` + +Indexes/constraints: + +```text +UNIQUE(refresh_tokens.token_hash) + +INDEX(refresh_tokens.family_id) +INDEX(refresh_tokens.session_id) +INDEX(sessions.user_id, sessions.revoked_at) +``` + +Do **not** make `family_id` unique. Every rotated refresh token in the same lineage shares the same family. + +Conceptually: + +```text +Session + │ + └── Refresh Token Family + │ + ├── Token A [rotated] + │ ↓ + ├── Token B [rotated] + │ ↓ + └── Token C [current] +``` + +### Refresh Rotation + +On successful refresh: + +1. hash supplied refresh token +2. load token and session +3. validate token/session status and expiry +4. issue replacement token in same family +5. mark old token rotated +6. link `replaced_by_token_id` +7. return new access + refresh tokens + +### Reuse Detection + +If a previously rotated token is used again: + +```text +possible token theft + ↓ +revoke token family + ↓ +revoke affected session + ↓ +security audit event + ↓ +reauthentication required +``` + +Policy may escalate to revoking all user sessions for higher-risk environments. + +Audit event: + +```text +auth.refresh_token.reuse_detected +``` + +### Device Metadata + +Device metadata is useful for: + +```text +session display +security alerts +audit context +user-initiated revocation +``` + +It is not identity proof. + +Future authentication: + +- MFA +- passkeys / WebAuthn +- OIDC / SSO +- 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 core client fields: + +```text +id +organization_id +client_type +display_name +legal_name +status +created_at +updated_at +version +``` + +Do not permanently squeeze all contacts into one `email`, one `phone`, and one `contact_name`. + +Engineering customers commonly have multiple: + +```text +technical contacts +billing contacts +executive contacts +site contacts +contract contacts +``` + +Use: + +```text +engineering_client_contacts +``` + +Suggested contact fields: + +```text +id +organization_id +client_id + +name +title +department + +email +phone + +contact_type +is_primary + +created_at +updated_at +``` + +Client 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 +``` + +Contact REST: + +```http +GET /api/v1/engineering/clients/{clientId}/contacts +POST /api/v1/engineering/clients/{clientId}/contacts +PATCH /api/v1/engineering/clients/{clientId}/contacts/{contactId} +DELETE /api/v1/engineering/clients/{clientId}/contacts/{contactId} +``` + +Delete may be implemented as archival when contact history matters. + +Client restore is allowed only when organization policy and retention rules permit it. + +## 27A. Engineering Client Portal + +External clients are not internal organization members. + +Use shared authentication identities where practical, but create a separate authorization boundary. + +```text +User + │ + ├── Internal Membership + │ ↓ + │ Organization Staff Access + │ + └── Client Portal Account + ↓ + Engineering Client Contact + ↓ + Project Access Grants +``` + +Suggested tables: + +```text +engineering_client_portal_accounts +engineering_client_portal_project_grants +engineering_project_document_publications +engineering_client_review_requests +``` + +### Portal Account + +Suggested fields: + +```text +id +organization_id +user_id +engineering_client_contact_id + +status + +invited_by_user_id +invited_at +accepted_at + +revoked_at +revoked_by_user_id +``` + +Portal accounts are not placed in `memberships`. + +### Project Grant + +Suggested fields: + +```text +id +organization_id +portal_account_id +project_id + +access_profile + +granted_by_user_id +granted_at +expires_at +revoked_at +``` + +Initial access capabilities may include: + +```text +project.status.read +project.documents.read_published +project.comments.create +project.files.submit +client_review.respond +``` + +The access model may later normalize capabilities into a grant table if simple profiles become insufficient. + +### Separate Frontend + +Recommended: + +```text +apps/ +├── engineering-web/ +└── engineering-client-portal/ +``` + +The internal engineering frontend and external portal do not share authorization assumptions. + +### Client Acceptance Is Not Engineering Approval + +Never represent client acceptance with: + +```text +engineering.designs.approve +``` + +Professional engineering approval is reserved for qualified internal/authorized professionals. + +Client-facing review should use separate concepts such as: + +```text +engineering.client_reviews.request +engineering.client_reviews.respond +engineering.client_reviews.accept +engineering.client_reviews.request_changes +``` + +Example: + +```http +POST /api/v1/engineering/client-review-requests/{reviewId}/accept +POST /api/v1/engineering/client-review-requests/{reviewId}/request-changes +``` + +A client acceptance may be commercially meaningful without being a professional engineering approval. + +### Portal Security Rules + +1. portal access is deny-by-default +2. every portal request remains organization-scoped +3. portal users only access explicitly granted projects +4. project membership does not apply to portal users +5. internal RBAC roles do not automatically apply to portal users +6. portal account revocation is immediate +7. portal grants may expire +8. sensitive document access requires explicit publication +9. portal activity is audited according to organization policy +10. professional approval endpoints are never exposed through portal grants + +--- + +## 27B. External Document Publication + +A document being linked to an engineering project does **not** make it externally visible. + +Use: + +```text +engineering_project_document_publications +``` + +Suggested fields: + +```text +id +organization_id + +project_document_link_id + +audience_type +portal_account_id nullable +client_id nullable + +published_by_user_id +published_at + +expires_at +revoked_at +revoked_by_user_id +``` + +Possible audiences: + +```text +all_active_client_portal_accounts_for_project +specific_portal_account +specific_client_contact +``` + +External download checks: + +```text +authenticated portal user ++ +active portal account ++ +active project grant ++ +active document publication ++ +publication not expired/revoked ++ +document classification allows publication ++ +download permission +``` + +This prevents an internal project document from appearing in the client portal merely because it is linked to the project. + +## 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 +``` + +--- + +## 32A. Engineering Batch Operations + +Batch operations are useful for repetitive engineering workflows, but they must not bypass per-resource authorization or domain rules. + +Examples: + +```http +POST /api/v1/engineering/tasks/batch-assign +POST /api/v1/engineering/tasks/batch-complete + +POST /api/v1/engineering/time-entries/batch-submit +``` + +### Batch Execution Modes + +Every batch command explicitly defines one of: + +```text +atomic +partial +``` + +Atomic: + +```text +all resources succeed +or +entire operation fails +``` + +Partial: + +```text +each resource is evaluated independently +successful items commit +failed items return individual errors +``` + +Do not leave this behavior implicit. + +Example request: + +```json +{ + "taskIds": [ + "task_1", + "task_2", + "task_3" + ], + "assigneeUserId": "user_123", + "mode": "partial" +} +``` + +Example response: + +```json +{ + "data": { + "succeeded": [ + "task_1", + "task_2" + ], + "failed": [ + { + "id": "task_3", + "code": "RESOURCE_INVALID_STATE" + } + ] + } +} +``` + +### Authorization + +Each resource is evaluated for: + +```text +tenant +permission +scope +resource access +state validity +credential policy where applicable +``` + +Never authorize the first item and assume the remaining batch is equivalent. + +### Synchronous vs Asynchronous + +Small batches may execute synchronously. + +Large batches become jobs: + +```http +202 Accepted +``` + +with: + +```text +jobId +``` + +The synchronous/asynchronous threshold is configuration based on: + +```text +batch size +operation cost +database load +side effects +product tier +``` + +Financial or regulated batch actions require stricter idempotency and audit rules than ordinary task updates. + +--- + +## 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 +``` + +Suggested states: + +```text +draft +under_review +changes_requested +approved +rejected +cancelled +withdrawn +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}/cancel +POST /api/v1/engineering/designs/{designId}/withdraw +POST /api/v1/engineering/designs/{designId}/supersede + +POST /api/v1/engineering/designs/{designId}/assign +POST /api/v1/engineering/designs/{designId}/unassign + +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 +``` + +### Assignment Model + +Use: + +```text +engineering_design_assignments +``` + +Possible assignment roles: + +```text +owner +designer +reviewer +approver +checker +``` + +Suggested fields: + +```text +id +organization_id +design_id +user_id +assignment_role +notes +assigned_by_user_id +assigned_at +unassigned_at +``` + +Assignment does not automatically grant platform permission. Both RBAC and resource policy still apply. + +### Design State Machine + +```text +draft + ├── submit-review ───────────────► under_review + └── cancel ──────────────────────► cancelled + +under_review + ├── request-changes ─────────────► changes_requested + ├── approve ─────────────────────► approved + ├── reject ──────────────────────► rejected + └── withdraw ────────────────────► withdrawn + +changes_requested + ├── submit-review ───────────────► under_review + └── withdraw ────────────────────► withdrawn + +rejected + └── revise ──────────────────────► draft + +approved + └── supersede ───────────────────► superseded +``` + +Use `cancelled` for work stopped before formal review. + +Use `withdrawn` for work intentionally removed after review workflow has started. + +Approval requires: + +```text +permission ++ +project access ++ +appropriate assignment/policy ++ +valid professional qualification ++ +valid design state ++ +organization approval policy +``` + +Approval, rejection, withdrawal, and supersession are audited. + +Approval is idempotent. + +Do not approve by PATCHing `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 +outcome + +scheduled_at +started_at +performed_at +cancelled_at + +summary + +created_at +updated_at +version +``` + +Lifecycle status: + +```text +draft +scheduled +in_progress +completed +cancelled +``` + +Outcome is separate: + +```text +passed +passed_with_observations +followup_required +failed +``` + +This distinction matters. + +An inspection can be fully completed and still require corrective work. + +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 + +POST /api/v1/engineering/inspections/{inspectionId}/followups +GET /api/v1/engineering/inspections/{inspectionId}/followups +``` + +A follow-up may be: + +```text +corrective task +new inspection +or both +``` + +Do not encode all follow-up workflow into the original inspection's lifecycle state. + +Inspection completion: + +1. validate inspector and project access +2. validate required fields +3. validate findings +4. calculate or confirm outcome +5. complete inspection +6. create corrective work/follow-up records when required +7. audit +8. write outbox event +9. notify appropriate participants + +Completion is idempotent. + +## 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 +``` + +--- + +## 38A. Engineering Project Budgets + +A single `budget_minor` column is sufficient only for a very early project total. + +When budget management enters scope, introduce: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries +``` + +### Budget + +Suggested fields: + +```text +id +organization_id +project_id + +name +currency_code +status + +approved_by_user_id +approved_at + +created_at +updated_at +version +``` + +### Budget Item + +Suggested fields: + +```text +id +organization_id +budget_id + +category +description + +allocated_amount_minor + +created_at +updated_at +``` + +Do not casually store mutable: + +```text +spent_amount_minor +committed_amount_minor +``` + +as independent sources of truth if those values are derived from time entries, expenses, purchase commitments, or invoices. + +Prefer: + +```text +authoritative cost/commitment records + ↓ +derived budget projections +``` + +If denormalized totals are needed for performance, update them transactionally and reconcile them. + +Potential REST: + +```http +GET /api/v1/engineering/projects/{projectId}/budgets +POST /api/v1/engineering/projects/{projectId}/budgets +GET /api/v1/engineering/budgets/{budgetId} +PATCH /api/v1/engineering/budgets/{budgetId} + +POST /api/v1/engineering/budgets/{budgetId}/approve +GET /api/v1/engineering/budgets/{budgetId}/items +POST /api/v1/engineering/budgets/{budgetId}/items +``` + +Budget approval is an explicit command. + +--- + +## 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 +document_categories +retention_policies +``` + +Binary data: + +```text +S3-compatible object storage +``` + +### Document + +Suggested fields: + +```text +id +organization_id + +name +category_id + +classification + +retention_policy_id + +current_version_id + +created_by_user_id +created_at +updated_at +``` + +Classification examples: + +```text +public +internal +confidential +restricted +regulated +``` + +Avoid a single `is_confidential` boolean as the long-term security model. + +### Document Version + +Suggested fields: + +```text +id +organization_id +document_id + +version_number + +storage_key + +mime_type +size_bytes + +content_hash +hash_algorithm + +uploaded_by_user_id +created_at +``` + +The authoritative checksum belongs on the version because each binary revision has different content. + +Optional document-level metadata may include: + +```text +current_version_id +current_version_number +``` + +but should not replace version-level integrity data. + +### Metadata + +Use JSONB only for genuinely extensible metadata that does not deserve stable relational columns. + +Examples: + +```text +CAD-specific extraction results +scanner metadata +non-authoritative document properties +``` + +Do not place access control, retention state, ownership, or lifecycle rules inside arbitrary metadata JSON. + +### Document Categories + +Suggested fields: + +```text +id +organization_id +profession nullable +name +parent_category_id +created_at +``` + +If `profession` is nullable and shared categories must remain unique, PostgreSQL uniqueness must explicitly handle nulls. + +Options include: + +```text +UNIQUE NULLS NOT DISTINCT +``` + +where supported, or separate partial unique indexes for: + +```text +profession IS NULL +profession IS NOT NULL +``` + +Do not rely on a plain nullable composite unique constraint and assume NULL behaves like a normal value. + +### Upload Security + +Validate: + +```text +declared MIME +extension +magic bytes/content signature +file size +malware scan +organization quota +classification policy +``` + +A renamed executable is not a PDF merely because the filename developed ambition. + +## 52. Document Upload Flow + +Small and ordinary file uploads: + +```text +Frontend + ↓ +Request upload authorization + ↓ +Backend validates tenant + permission + upload policy + ↓ +Create pending document/version + ↓ +Return signed upload URL + ↓ +Frontend uploads directly to object storage + ↓ +Backend finalizes + ↓ +verify checksum/type/size + ↓ +malware/security scan + ↓ +classification + retention + ↓ +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 +``` + +### Very Large Engineering Files + +Large CAD/BIM/model files use native object-storage multipart upload. + +The API orchestrates authorization and signed part URLs. + +It does **not** proxy gigabytes of file content through application servers. + +Flow: + +```text +Frontend + ↓ +POST /documents/multipart-uploads + ↓ +Backend authorizes +and initializes object-storage multipart upload + ↓ +Frontend requests signed part URLs + ↓ +Frontend uploads parts directly to object storage + ↓ +Frontend reports completed parts + ↓ +POST /documents/{id}/multipart-upload/complete + ↓ +Backend finalizes object + ↓ +verify object metadata/checksum + ↓ +malware/security scan + ↓ +mark document version available +``` + +Possible REST: + +```http +POST /api/v1/documents/multipart-uploads + +POST /api/v1/documents/{documentId}/multipart-upload/parts +POST /api/v1/documents/{documentId}/multipart-upload/complete + +DELETE /api/v1/documents/{documentId}/multipart-upload +``` + +The `/parts` endpoint returns signed upload URLs and part metadata. + +It does not carry binary chunks. + +### Multipart Upload State + +Track: + +```text +upload_id +organization_id +document_id +document_version_id +object_storage_upload_id +status +created_at +expires_at +completed_at +aborted_at +``` + +States: + +```text +initiated +uploading +completing +completed +aborted +expired +``` + +Cleanup workers abort abandoned multipart uploads. + +### File Policy + +Use configurable policy: + +```text +max_file_size_bytes +allowed_file_classes +organization_storage_quota_bytes +profession_overrides +plan/tier overrides +multipart_threshold_bytes +``` + +Exact file-size and quota values are product/configuration decisions. + +Validation includes: + +```text +declared MIME +extension +content signature / magic bytes +file size +checksum +quota +classification +malware scan +``` + +## 53. Profession-Specific Document Links + +Use explicit relationship tables. + +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 +``` + +### Engineering Project Documents + +Suggested link fields: + +```text +id +organization_id +project_id +document_id + +category +classification_override nullable + +linked_by_user_id +linked_at +unlinked_at +``` + +REST: + +```http +GET /api/v1/engineering/projects/{projectId}/documents +POST /api/v1/engineering/projects/{projectId}/documents + +DELETE /api/v1/engineering/project-documents/{documentLinkId} +``` + +Link deletion may preserve historical linkage through `unlinked_at` when required. + +Example response: + +```json +{ + "data": [ + { + "documentLinkId": "projdoc_123", + "category": "calculations", + "document": { + "id": "doc_456", + "name": "structural_calculations.pdf", + "classification": "confidential", + "currentVersion": 2, + "mimeType": "application/pdf", + "sizeBytes": 2457600 + } + } + ] +} +``` + +Explicit link resources give stronger referential integrity than generic polymorphic foreign keys. + +## 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 +``` + +Transaction: + +```text +BEGIN + +business change +audit event +outbox event + +COMMIT +``` + +The outbox is **at-least-once delivery**, not magically exactly-once. + +Worker claim example: + +```sql +SELECT id +FROM outbox_events +WHERE processed_at IS NULL + AND dead_lettered_at IS NULL + AND available_at <= now() +ORDER BY occurred_at +FOR UPDATE SKIP LOCKED +LIMIT 100; +``` + +Worker responsibilities: + +1. claim committed event +2. process consumer action +3. mark processed on success +4. increment attempts on failure +5. schedule retry with backoff +6. dead-letter after policy threshold +7. emit metrics +8. preserve replay/debug metadata + +### Critical Failure Case + +A worker may: + +```text +perform external side effect + ↓ +crash + ↓ +fail to mark event processed + ↓ +event is retried +``` + +Therefore every external consumer must support idempotency. + +Examples: + +```text +payment provider command → provider idempotency key +webhook delivery → delivery/event ID +email notification → dedupe key if duplicate mail is unacceptable +search indexing → upsert by entity/version +``` + +`FOR UPDATE SKIP LOCKED` prevents concurrent claims. It does **not** prevent duplicate side effects after a crash. + +Workers may be awakened by queue notifications, but must still poll durable outbox state so lost wake-ups do not strand events. + +## 57A. Webhooks and External Integrations + +Webhooks are a shared platform capability, not profession-specific transport code. + +Configuration REST: + +```http +GET /api/v1/webhooks +POST /api/v1/webhooks +GET /api/v1/webhooks/{webhookId} +PATCH /api/v1/webhooks/{webhookId} +DELETE /api/v1/webhooks/{webhookId} + +POST /api/v1/webhooks/{webhookId}/test +POST /api/v1/webhooks/{webhookId}/rotate-secret +``` + +Delivery REST: + +```http +GET /api/v1/webhook-deliveries +GET /api/v1/webhook-deliveries/{deliveryId} +POST /api/v1/webhook-deliveries/{deliveryId}/retry +``` + +Suggested tables: + +```text +webhooks +webhook_event_subscriptions +webhook_deliveries +``` + +Webhook fields: + +```text +id +organization_id +url +status +secret_ciphertext or signing_key_reference +created_by_user_id +created_at +updated_at +``` + +Do not return a secret hash to the client. + +### Secret Handling + +If using symmetric HMAC signing: + +```text +generate secret + ↓ +show plaintext once + ↓ +encrypt using KMS/key-management system + ↓ +store ciphertext + ↓ +decrypt only for signing +``` + +A one-way hash alone is insufficient because the server must possess the signing material. + +Alternative: + +```text +asymmetric signing ++ +published verification key +``` + +### Delivery Model + +Each delivery records: + +```text +id +organization_id +webhook_id +event_id + +attempt_number +request_timestamp +response_status +response_summary + +delivered_at +failed_at +next_attempt_at +``` + +Webhook workers require: + +```text +timeouts +retry with backoff +dead-letter/failure state +request signing +event IDs +idempotency guidance for consumers +delivery history +manual replay +``` + +Events should include stable identifiers so consumers can deduplicate. + +Example: + +```json +{ + "id": "evt_123", + "type": "engineering.design.approved", + "organizationId": "org_456", + "occurredAt": "2026-08-26T12:00:00Z", + "data": { + "designId": "design_789" + } +} +``` + +--- + +## 58. Background Jobs + +Workers handle: + +```text +Email +SMS +Notifications + +PDF/report generation + +File security scanning +Document processing + +Imports +Exports +Bulk updates + +Webhook delivery +Search indexing + +Large data operations +``` + +Architecture: + +```text +API + ↓ +Queue + ↓ +Worker +``` + +### Async Job Resource + +Use a shared job model for long-running user-requested operations. + +Suggested table: + +```text +jobs +``` + +Fields: + +```text +id +organization_id +requested_by_user_id + +job_type +status + +input_reference +result_reference + +progress_percent + +created_at +started_at +completed_at +failed_at + +error_code +error_summary +``` + +States: + +```text +queued +running +completed +failed +cancelled +``` + +REST: + +```http +GET /api/v1/jobs/{jobId} +GET /api/v1/jobs/{jobId}/result +POST /api/v1/jobs/{jobId}/cancel +``` + +### Import / Export + +Do not create asynchronous side effects with `GET`. + +Engineering examples: + +```http +POST /api/v1/engineering/project-imports +POST /api/v1/engineering/project-exports + +POST /api/v1/engineering/time-entry-imports +POST /api/v1/engineering/time-entry-exports +``` + +Response: + +```http +202 Accepted +``` + +```json +{ + "data": { + "jobId": "job_123", + "status": "queued" + } +} +``` + +Initial formats may include: + +```text +CSV +JSON +``` + +Import requirements: + +```text +validation report +row-level errors +all-or-partial mode explicitly defined +idempotency strategy +audit event +job result artifact +``` + +Export requirements: + +```text +authorization applied before generation +signed result URL +expiration +audit where data sensitivity requires it +``` + +## 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 +Argon2id or equivalent strong password hashing +short-lived access tokens +refresh-token rotation +refresh-token reuse detection +server-side session revocation + +rate limiting +anti-automation controls + +RBAC +resource policies +credential-aware authorization +tenant isolation + +input validation +SQL injection protection + +signed object-storage URLs +file-content validation +malware scanning + +audit trails +secret management +encryption at rest + +dependency scanning +container/image scanning +security headers + +request/correlation IDs +backup and restore testing +``` + +### Rate Limiting + +Model policy rather than baking arbitrary numbers into architecture. + +Example: + +```typescript +interface RateLimitRule { + routePattern: string; + method: string; + windowSeconds: number; + maxRequests: number; + scope: 'user' | 'organization' | 'ip' | 'email' | 'session'; +} +``` + +Policy classes: + +```text +authentication +password recovery +general API +search +upload authorization +report generation +webhooks/integrations +clinical record reads +``` + +Rate-limit values are configuration derived from: + +```text +security testing +load testing +observed traffic +customer tier +endpoint cost +abuse risk +``` + +Do not grant normal tenant roles blanket rate-limit bypass. + +Administrative exceptions, if any, require explicit trusted-system policy. + +Return: + +```http +429 Too Many Requests +Retry-After: ... +``` + +Error: + +```text +RATE_LIMIT_EXCEEDED +``` + +### Secrets + +Use managed secrets/key management where possible. + +Never put real secrets in source-controlled examples. + +Prefer JWT asymmetric signing or managed signing keys with rotation capability. + +## 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 +``` + +### Core Metrics + +API: + +```text +api_requests_total +api_errors_total +api_request_duration_seconds +``` + +Authentication: + +```text +auth_login_attempts_total +auth_token_refresh_total +auth_refresh_reuse_detections_total +auth_sessions_revoked_total +``` + +Authorization/security: + +```text +cross_tenant_access_attempts_total +tenant_isolation_invariant_failures_total +authorization_denials_total +credential_policy_denials_total +rate_limit_events_total +``` + +Important distinction: + +```text +cross_tenant_access_attempt += +request attempted another tenant's resource +``` + +This may be a stale link, mistake, or attack. + +```text +tenant_isolation_invariant_failure += +our system nearly or actually created/returned cross-tenant data +``` + +That is a high-severity internal correctness/security incident. + +Outbox/jobs/webhooks: + +```text +outbox_events_pending +outbox_events_failed_total +outbox_processing_duration_seconds + +jobs_queued +jobs_failed_total +job_duration_seconds + +webhook_delivery_attempts_total +webhook_delivery_failures_total +webhook_delivery_latency_seconds +``` + +Database: + +```text +db_pool_active +db_pool_waiting +db_query_duration_seconds +db_transaction_duration_seconds +``` + +Business metrics may include: + +```text +engineering_projects_created_total +engineering_designs_approved_total +engineering_inspections_completed_total +invoices_issued_total +``` + +Avoid patient-specific or sensitive identifiers in metric labels. + +### Alerts + +Examples: + +```text +refresh token reuse detected +tenant isolation invariant failure +outbox backlog exceeds SLO +webhook failure spike +database pool saturation +error-rate spike +latency regression +backup failure +malware scanner unavailable +``` + +Thresholds are calibrated from real environments rather than copied from a review document. + +### SLOs + +Define by endpoint class. + +Interactive CRUD, reports, file orchestration, and background jobs should not share one arbitrary latency target. + +## 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 +``` + +### Property-Based Tests + +Use property-based testing for high-value domain state machines. + +Candidates: + +```text +engineering design lifecycle +engineering inspection lifecycle +invoice lifecycle +payment state transitions +membership/role invariants +``` + +Correct properties: + +```text +every successful transition ends in a valid state + +every forbidden transition is rejected + +terminal states reject prohibited actions + +required invariants survive every valid transition + +transition sequences never bypass required approval/credential rules +``` + +Do not assert that every random state/action pair succeeds. Many are supposed to fail. + +### Integration Tests + +Test: + +```text +repositories +tenant-aware foreign keys +PostgreSQL constraints +transactions +outbox persistence +idempotency persistence +cache invalidation +job persistence +webhook delivery persistence +``` + +### API Tests + +Every important endpoint covers: + +```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 creation +outbox creation +``` + +### Outbox Reliability / Chaos Tests + +Test: + +```text +worker crash before side effect +worker crash after side effect but before marking processed +two workers competing for same row +temporary dependency outage +retry/backoff behavior +dead-letter behavior +consumer idempotency +lost worker wake-up +replay +``` + +The dangerous scenario is: + +```text +external side effect succeeds +worker dies +event retries +``` + +Tests must prove the consumer does not create an unacceptable duplicate. + +### Tenant Security Tests + +Test both: + +```text +external cross-tenant access attempts +``` + +and: + +```text +internal cross-tenant data invariant failures +``` + +These are different classes of failure. + +### Performance Tests + +Create realistic profiles: + +```text +interactive reads +interactive writes +search +dashboard read models +reporting +file upload orchestration +outbox processing +webhook bursts +notification bursts +``` + +Measure: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +``` + +Set production SLO gates only after a realistic baseline exists. + +### Coverage + +Track code coverage. + +Do not treat a single percentage such as `90%` as proof of quality. + +Critical-path expectations are stronger: + +```text +all tenant-isolation paths tested +all financial commands tested +all regulated commands tested +all state transitions tested +all critical authorization policies tested +``` + +## 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 +session/token model +idempotency strategy +error taxonomy +OpenAPI skeleton +engineering state machines +migration conventions +threat model +initial ADRs +risk register +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +auth +sessions +refresh-token families +token rotation/revocation + +users +organizations +organization professions + +membership invitations +memberships +roles +permissions +authorization + +audit +outbox + +request context +idempotency +rate limiting +observability +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering clients +engineering client contacts +client archive/restore +``` + +### Phase 3: Engineering Projects + +Build: + +```text +projects +project members +project phases +activation/close/archive +``` + +### Phase 4: Work and Site Management + +Build: + +```text +tasks +task batch operations +sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +versions +categories +classification +retention references +signed uploads +multipart uploads +content verification +malware scanning +engineering document links +``` + +### Phase 6: Engineering Designs + +Build: + +```text +designs +assignments +versions +reviews +cancel/withdraw semantics +credential-aware approval +audit +outbox +idempotency +``` + +### Phase 7: Engineering Inspections + +Build: + +```text +inspection lifecycle +inspection outcome +findings +corrective work +follow-up inspections +attachments +audit +outbox +idempotency +``` + +### Phase 8: Time, Budgets, and Billing + +Build: + +```text +time entries +batch timesheet submission +project budgets when required +invoices +payments +financial idempotency +reconciliation +``` + +### Phase 9: Notifications, Jobs, and Webhooks + +Build: + +```text +notifications +email +async jobs +imports/exports +webhooks +delivery/retry +dead-letter handling +``` + +### Phase 10: Reporting and Search + +Build: + +```text +project status +overdue work +inspection status +billable time +revenue +outstanding invoices +dashboard read models +``` + +### Phase 11: Engineering Client Portal + +Build: + +```text +portal account invitations +external project grants +published project documents +client review/acceptance workflow +portal audit +portal-specific frontend +``` + +Do not expose professional approval actions to client portal accounts. + +### Phase 12: Legal Vertical + +Validate shared core against: + +```text +matters +cases +conflicts +deadlines +retainers +restricted access / ethical walls +``` + +### Phase 13: Healthcare Readiness and Vertical + +Before implementation: + +```text +healthcare threat model +privacy review +jurisdiction analysis +scope-of-practice policy +record signing/amendment model +retention model +audit requirements +``` + +### Estimation Rule + +These are dependency-ordered milestones. + +They are not calendar promises. + +Calendar estimates require: + +```text +team size +frontend/UX scope +cloud decisions +third-party providers +security requirements +QA capacity +domain-expert availability +``` + +## 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 uses UUIDv7. + +Supported implementation choices: + +```text +PostgreSQL 18+: + use native uuidv7() if database-generated identifiers are desired + +Earlier PostgreSQL: + generate UUIDv7 in the application or use a controlled extension +``` + +Database columns remain PostgreSQL `UUID`. + +The rule is consistency, not ideological loyalty to one generation layer. + +Do not silently fall back to UUIDv4 while documenting UUIDv7. + +### Production Migration Rules + +Use expand/contract: + +```text +1. add backward-compatible schema +2. deploy code supporting old + new schema +3. backfill/migrate +4. switch reads/writes +5. observe +6. remove obsolete schema later +``` + +For destructive changes: + +```text +backup/restore plan +compatibility window +production-like dry run +explicit approval +post-migration verification +``` + +Do not assume a destructive database migration can always be reversed by a simple down migration. + +Never use automatic ORM schema synchronization in production. + +## 91A. Architecture Decision Records + +v4 stops treating technology suggestions as automatically settled architecture. + +Create ADRs before implementation locks in: + +```text +ADR-001 Backend Framework +ADR-002 SQL / ORM / Query Layer +ADR-003 Queue Implementation +ADR-004 PostgreSQL Minimum Version +ADR-005 Error Format / RFC 9457 Compatibility +ADR-006 Rate-Limit Header Convention +ADR-007 Webhook Signing Strategy +ADR-008 Object Storage Provider / Multipart Strategy +``` + +Each ADR should include: + +```text +context +decision +alternatives considered +tradeoffs +security impact +operational impact +migration/exit path +date +status +``` + +The architecture currently fixes capabilities and boundaries. + +It does not require a framework merely because a review document described it positively. + +--- + +## 92. Technology Recommendation + +The following are preferred candidates, not all final decisions. + +### Fixed Platform Choices + +```text +API style: REST +Contract: OpenAPI 3.1 +Primary language: TypeScript +Primary database: PostgreSQL +Architecture: Modular Monolith +Observability standard: OpenTelemetry +Object storage model: S3-compatible +Container model: Docker/OCI +``` + +### ADR-Gated Choices + +Backend framework candidates: + +```text +NestJS +Fastify-centered custom application structure +``` + +SQL / persistence candidates: + +```text +Drizzle +Kysely +Prisma +direct SQL for specialized queries +``` + +Queue candidates: + +```text +BullMQ / Redis +managed cloud queue +``` + +PostgreSQL baseline: + +```text +PostgreSQL 18+ +``` + +is attractive because of native UUIDv7 and current capabilities, but the minimum supported version must be confirmed against: + +```text +hosting provider availability +operations policy +extension requirements +upgrade policy +support lifecycle +``` + +Do not claim one ORM is categorically "faster" or "better" without workload-specific evidence. + +The selected stack should preserve: + +```text +transaction control +explicit SQL visibility +tenant-safe query design +migration control +observability +testability +``` + +## 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 API contract. +4. GraphQL is not part of v1. +5. Start as one modular monolith backend. +6. Each profession has its own frontend. +7. Each profession owns its domain tables and state machines. +8. Shared modules provide infrastructure, not forced domain abstractions. +9. Every tenant-owned row contains `organization_id`. +10. Tenant-scoped requests require explicit `X-Organization-Id`. +11. The API never silently selects an organization. +12. Tenant boundaries are enforced in queries and database constraints. +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 commands validate authoritative credential state. +17. Sessions and refresh tokens are separate resources. +18. Refresh tokens rotate within families and support reuse detection. +19. UUIDv7 is the identifier standard. +20. PostgreSQL 18 native UUIDv7 may be used when PostgreSQL 18+ is selected. +21. Important domain transitions use explicit REST command endpoints. +22. High-risk commands use durable idempotency. +23. Redis may accelerate idempotency but is not authoritative for financial/regulated commands. +24. Profession-specific state transitions are explicitly modeled and tested. +25. Design cancellation and post-review withdrawal are distinct when needed. +26. Inspection lifecycle and outcome are separate dimensions. +27. Follow-up inspection work is linked work, not overloaded lifecycle state. +28. Files live in object storage. +29. Large files use native object-storage multipart uploads. +30. Application servers do not proxy multi-gigabyte file chunks. +31. Document checksum is version-level authoritative data. +32. Document classification is multi-level. +33. File upload policy is configurable. +34. Upload validation includes content signature, size, quota, checksum, and malware scanning. +35. Explicit document-link tables are preferred over generic polymorphic links. +36. Project document linkage does not imply client-portal publication. +37. External publication requires an explicit publication record. +38. Client portal identities are not ordinary internal memberships. +39. Client portal permissions are separate from internal RBAC assumptions. +40. Client acceptance/review is not professional engineering approval. +41. Professional design approval is never granted through a client portal role. +42. Small batch commands define atomic or partial semantics explicitly. +43. Large batch operations become asynchronous jobs. +44. Every batch item receives tenant/authorization/domain validation. +45. Domain events use a transactional outbox. +46. Outbox semantics are at-least-once. +47. External side-effect consumers are idempotent. +48. Webhooks are shared platform infrastructure with retry, replay, delivery history, and signing. +49. HMAC webhook signing material is securely recoverable, normally encrypted with managed keys. +50. Async imports/exports/reports use job resources and return `202 Accepted`. +51. `GET` endpoints do not create export jobs. +52. Engineering clients support multiple contacts. +53. Engineering budgets use dedicated tables when budget management enters scope. +54. Derived financial totals do not become uncontrolled duplicate truth. +55. PostgreSQL is the authoritative transactional datastore. +56. Redis is an acceleration and coordination layer. +57. Search starts in PostgreSQL. +58. External search/read replicas/materialized views require measured need. +59. API collections use cursor pagination. +60. Important mutable resources use optimistic concurrency. +61. Database entities are not serialized directly as public API contracts. +62. Errors use stable codes. +63. Rate-limited responses use 429 and Retry-After. +64. Additional rate-limit headers are implementation/API-contract decisions, not frozen legacy header names. +65. Important and regulated actions are audited. +66. Sensitive healthcare reads are audited where policy requires. +67. Signed clinical records use sign/amend/version workflows. +68. Prescribing authority is jurisdiction and scope-of-practice driven. +69. Production migrations follow expand/contract. +70. Destructive schema changes are not assumed trivially reversible. +71. Secrets are managed outside source control. +72. Rate limits are policy/configuration calibrated by evidence. +73. CI validates types, tests, OpenAPI, migrations, and security scans. +74. Property-based tests are used for high-value state machines. +75. Outbox/job/webhook reliability is tested under failure and concurrency. +76. Internal tenant-isolation invariant failures and external cross-tenant attempts are separate signals. +77. Critical-path tests matter more than vanity coverage percentages. +78. Performance objectives are provisional until measured. +79. Architecture risks are maintained in a living register. +80. Framework/ORM/queue choices require ADRs. +81. Engineering is the first implemented product vertical. +82. The engineering client portal follows internal Engineering MVP foundations. +83. Legal follows after engineering validates shared assumptions. +84. Healthcare requires explicit security/privacy/jurisdiction readiness work. +85. Architecture documentation never equates "designed for" with "certified/compliant". +86. v4 is the final broad architecture baseline unless a foundational assumption is invalidated. + +## 95. Required Design Artifacts + +Maintain: + +```text +01_PROJECT_ARCHITECTURE.md +02_DATABASE_CONVENTIONS.md +03_AUTHORIZATION_MODEL.md +04_AUTH_SESSION_MODEL.md + +05_ENGINEERING_DOMAIN.md +06_ENGINEERING_DATABASE_SCHEMA.md +07_ENGINEERING_STATE_MACHINES.md + +08_API_CONVENTIONS.md +09_ENGINEERING_API_SPEC.md +10_OPENAPI.yaml + +11_FRONTEND_ARCHITECTURE.md +12_CLIENT_PORTAL_SECURITY_MODEL.md + +13_DOCUMENT_SECURITY_MODEL.md +14_LARGE_FILE_UPLOAD_MODEL.md + +15_WEBHOOK_INTEGRATION_MODEL.md +16_ASYNC_JOB_MODEL.md + +17_SECURITY_MODEL.md +18_DEPLOYMENT_ARCHITECTURE.md +19_OBSERVABILITY_MODEL.md +20_TESTING_STRATEGY.md + +21_ARCHITECTURE_DECISION_RECORDS/ +22_RISK_REGISTER.md +23_MVP_BACKLOG.md +``` + +Important ADRs: + +```text +backend framework +persistence/query layer +queue implementation +PostgreSQL minimum version +error format +rate-limit headers +webhook signing +object-storage provider +``` + +## 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 need efficient tenant scoping. + +Baseline: + +```text +(organization_id, id) +``` + +Common list access often benefits from: + +```text +(organization_id, created_at) +``` + +Query-specific examples: + +```text +(organization_id, status) +(organization_id, client_id) +(organization_id, project_id) +(organization_id, assigned_to_user_id) +``` + +### Rules + +1. every index corresponds to a known query, ordering, or constraint +2. column order follows real predicates +3. validate with `EXPLAIN (ANALYZE, BUFFERS)` +4. include production-like cardinality in testing +5. measure write amplification +6. do not index every field +7. introduce trigram/full-text indexes only for actual search requirements + +Potential later tools: + +```text +covering indexes +materialized views +read replicas +table partitioning +external search +``` + +These are evidence-driven scaling mechanisms, not baseline dependencies. + +### Document Category Uniqueness + +If a nullable field such as profession participates in uniqueness: + +```text +organization_id +profession nullable +name +``` + +do not assume plain uniqueness treats NULL as one shared value. + +Use PostgreSQL-supported null-aware uniqueness or partial unique indexes according to the selected PostgreSQL version. + +--- + +## 97B.## 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. + +--- + +## 97D. Provisional Performance Objectives + +Performance numbers in architecture are starting hypotheses, not guarantees. + +Initial engineering objectives may begin with: + +```text +Interactive read: + target p95 <= 500 ms + +Interactive mutation: + target p95 <= 750 ms + +Simple list/search: + target p95 <= 800 ms + +Upload authorization: + target p95 <= 300 ms + +Background outbox pickup: + target <= 5 seconds under normal operating conditions +``` + +These are revised after realistic testing. + +Track: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +outbox lag +``` + +Different endpoint classes receive different SLOs. + +Do not use file-transfer completion time as an API SLO when bytes travel directly between client and object storage. + +--- + +## 97E. Risk Register + +Maintain a living risk register. + +Suggested structure: + +| Risk | Impact | Mitigation | Owner | Phase | Status | +|---|---|---|---|---|---| +| Cross-tenant data exposure | Critical | Tenant-aware FKs, scoped queries, security tests | Backend/Security | P0 | Open | +| Non-idempotent outbox side effect | Critical | Consumer dedupe, provider idempotency, chaos tests | Backend | P0 | Open | +| Migration failure | High | Expand/contract, dry runs, backups | Backend/Platform | P0 | Open | +| Engineering workflow mismatch | High | Domain expert validation | Product/Engineering SME | MVP | Open | +| Portal authorization leak | Critical | Separate external access model, publication grants | Backend/Security | Portal | Open | +| Webhook delivery instability | Medium | Retry, dead-letter, replay, metrics | Backend | Integrations | Open | +| Large upload abandonment | Medium | Multipart expiry and cleanup | Backend/Platform | Documents | Open | +| Documentation drift | Medium | OpenAPI validation, ADRs, CI | Engineering | Continuous | Open | + +Do not pretend likelihood labels are quantitative unless the team defines and uses a scoring method. + +--- + +## 97F. Architecture Change Governance + +v4 is the last broad platform-architecture revision before Engineering MVP implementation. + +New discoveries should normally become: + +```text +ADR +OpenAPI change +database migration +domain-state-machine update +security decision +backlog item +runbook +``` + +rather than a new full architecture rewrite. + +Reopen the broad architecture only when a discovery invalidates one of these foundational assumptions: + +```text +tenant model +profession separation +shared-core boundary +REST API model +data ownership +security trust boundary +deployment topology +database architecture +``` + +This prevents design review from becoming an infinite recursion problem. + +--- + +## 97G. Production Readiness Gates + +Architecture being coherent does not mean production is safe. + +Before production, require evidence in these categories. + +### Security + +```text +TLS configured +password hashing configured +refresh rotation/reuse detection tested +session revocation tested +tenant isolation tests passing +authorization/credential policies tested +rate limiting active +secrets managed outside source control +file security scanning active +security review completed +``` + +### Reliability + +```text +database backups automated +restore tested +object storage recovery strategy tested +outbox monitoring active +job queue monitoring active +webhook retry/dead-letter behavior tested +health checks configured +dependency failures tested +``` + +### Data Integrity + +```text +tenant-aware foreign keys present where required +financial invariants tested +migration tested on production-like data +idempotency tested for high-risk commands +optimistic concurrency tested +audit integrity tested +``` + +### Contract / API + +```text +OpenAPI validates +contract tests pass +error schema consistent +versioning rules documented +client SDK generation validated if used +``` + +### Performance + +```text +load test executed +realistic SLOs defined +database pool configured +key queries analyzed +outbox/job backlogs remain within SLO +``` + +### Critical Domain Coverage + +Rather than a magic overall coverage number, require explicit test coverage for: + +```text +tenant boundaries +design approval +inspection completion +invoice issue +payment/refund +membership privilege changes +clinical record signing/amendment when healthcare exists +prescribing authorization when healthcare exists +``` + +### Release Gate Principle + +No single metric such as: + +```text +90% test coverage +``` + +is sufficient evidence of production readiness. + +Quality gates are based on critical behavior, not vanity percentages. + +--- + +## 97. Final Design Position + +The platform is: + +```text +One Shared Platform + │ + ├── Shared Identity / Sessions + ├── Shared Security / Authorization + ├── Shared Documents / Multipart Uploads + ├── Shared Financial Core + ├── Shared Audit / Outbox + ├── Shared Jobs / Webhooks / Notifications + │ + ├── Engineering Internal Product + │ ├── Engineering Frontend + │ ├── Engineering REST APIs + │ ├── Engineering State Machines + │ └── Engineering Tables + │ + ├── Engineering Client Portal + │ ├── External Portal Frontend + │ ├── Portal Accounts + │ ├── Project Grants + │ ├── Published Documents + │ └── Client Review / Acceptance + │ + ├── Legal Product + │ ├── Legal Frontend + │ ├── Legal REST APIs + │ └── Legal Tables + │ + └── Healthcare Product + ├── Healthcare Frontend + ├── Healthcare REST APIs + ├── Healthcare Security Policies + └── Healthcare Tables +``` + +The system shares infrastructure where reuse is valuable while preserving profession-specific domain semantics and trust boundaries. + +v4 is the final broad architecture baseline for Engineering MVP implementation. + +From this point forward, architecture detail should primarily move into: + +```text +ADRs +OpenAPI +database schema/migrations +state-machine specifications +security policies +implementation backlog +runbooks +``` + +rather than repeatedly rewriting the entire architecture plan. + +This document does not itself prove: + +```text +regulatory compliance +production certification +security certification +performance at a specific scale +``` + +Those require implementation evidence, security review, domain validation, operational testing, restore testing, and measured production-like workloads. + + + +--- + +# v4 Changelog + +Compared with v3, v4 adds or changes: + +```text +✓ dedicated engineering client portal trust boundary +✓ portal accounts separated from organization memberships +✓ explicit project-level external access grants +✓ professional design approval separated from client acceptance +✓ explicit external document-publication model +✓ batch operations with atomic/partial semantics +✓ asynchronous escalation for large batches +✓ object-storage multipart upload orchestration +✓ no API proxying of multi-gigabyte chunks +✓ rate-limit response policy with Retry-After +✓ legacy X-RateLimit headers not frozen into the architecture +✓ framework/ORM/queue decisions moved into ADRs +✓ PostgreSQL minimum version moved into an ADR +✓ RFC 9457 error-format compatibility added as an ADR +✓ provisional performance objectives separated from production SLOs +✓ living risk register introduced +✓ architecture-change governance introduced +✓ v4 designated final broad architecture baseline +``` diff --git a/professional_management_platform_rest_plan_v4_1.md b/professional_management_platform_rest_plan_v4_1.md new file mode 100644 index 0000000..cbf5a66 --- /dev/null +++ b/professional_management_platform_rest_plan_v4_1.md @@ -0,0 +1,6642 @@ +# Professional Management Platform +## Full REST-First System Design Plan + +> **Revision:** v4.1 — Consistency and Implementation-Contract Cleanup +> **Status:** Locked broad architecture baseline with implementation-blocking contradictions resolved. Subsequent detail belongs in ADRs, OpenAPI, migrations, domain specifications, and backlog items. +> **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 + +### v4.1 Cleanup Notes + +v4.1 does not redesign the platform. It resolves contradictions and fills implementation contracts discovered during detailed review. + +Resolved: + +- raw UUIDv7 is now the serialized/API identifier format +- database columns remain UUID; prefixed strings are not public IDs +- all tenant-owned subresources carry direct `organization_id` +- design-version document cardinality is explicit and relational +- engineering time entries can be attributed to a specific work item +- project-level `budget_minor` is removed in favor of the dedicated budget model +- duplicate `legal_documents` ownership is removed +- batch custom-action paths use one documented convention +- membership invitations can pre-assign multiple roles +- missing design `revise` command is added +- inspection follow-ups now have a table and lifecycle +- change requests are moved out of the initial Engineering schema until specified +- service accounts and API keys are defined for machine access +- API JSON, query parameters, and path parameter names use camelCase; database columns use snake_case +- professional profiles support multiple professional credentials +- deletion/archival/revocation/unlink behavior is globally defined +- invoice-item fields are specified +- deferred healthcare placeholder tables receive minimum schemas or explicit deferral notes +- document upload and multipart DTOs are defined +- webhook subscription fields are defined +- `POST /auth/logout` is restored +- portal review-request and portal capability schemas are defined +- project-role, task-status, priority, and inspection-outcome values are defined +- document-category uniqueness has a version-independent fallback +- retention policy fields are defined +- pagination defaults are explicit +- `assigned` authorization scope has resource-specific resolution rules +- feature-flag behavior is clarified +- audit privacy minimization/anonymization strategy is documented +- outbox correlation and causation IDs are added +- CORS and web-security configuration is moved into a required ADR +- project `stage` duplication is removed; project phases remain authoritative +- phase reordering, site listing, appointment locations, and encounter reason fields are clarified +- jobs remain tenant-scoped through the standard organization header rather than path nesting + +--- +--- +--- +--- + +## 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: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +X-Request-Id: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff +Content-Type: application/json +``` + +### API Naming Convention + +Public API representation: + +```text +JSON properties: camelCase +query parameters: camelCase +path parameter names in documentation: camelCase +HTTP headers: conventional HTTP header casing +``` + +Database representation: + +```text +table names: snake_case +column names: snake_case +constraint/index names: snake_case +``` + +Example: + +```http +GET /api/v1/engineering/tasks?assignedToUserId=&createdAfter=2026-08-01T00:00:00Z +``` + +```json +{ + "assignedToUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "createdAt": "2026-08-26T12:00:00Z" +} +``` + +maps internally to columns such as: + +```text +assigned_to_user_id +created_at +``` + +### Organization Context + +`X-Organization-Id` is mandatory for every tenant-scoped endpoint. + +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: + +```yaml +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_mismatch: + status: 404 + code: RESOURCE_NOT_FOUND +``` + +### Idempotency + +Use: + +```http +Idempotency-Key: 8f7d6c5e-4b3a-4b1c-9d8e-7f6a5b4c3d2e +``` + +Required where duplicate execution can create material side effects. + +PostgreSQL is authoritative for critical idempotency records. + +Redis may accelerate lookup. + +### Batch Custom-Action Convention + +For collection-level custom commands use: + +```text +/{collection}/batch/{action} +``` + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete +POST /api/v1/engineering/time-entries/batch/submit +``` + +Do not mix `batch-assign`, colon-style custom methods, and `/batch/assign` in the same API. + +### Rate-Limit Responses + +```http +429 Too Many Requests +Retry-After: +``` + +Additional rate-limit metadata may be exposed according to the selected gateway/standard. + +Do not freeze legacy `X-RateLimit-*` names here. + +### Error Standard Decision + +The current error envelope remains: + +```json +{ + "error": { + "code": "RESOURCE_NOT_FOUND", + "message": "Resource not found.", + "details": {}, + "requestId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff" + } +} +``` + +ADR-005 decides whether OpenAPI v1 aligns this with RFC 9457 Problem Details. + +Do not silently change the envelope during implementation. + +## 9. Standard Response Format + +Single resource: + +```json +{ + "data": { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c6d", + "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. + +--- + +## 11A. Identifier Convention + +The serialized identifier standard is **raw UUIDv7**. + +Example: + +```text +0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +``` + +Database: + +```sql +id UUID PRIMARY KEY +``` + +API: + +```json +{ + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d" +} +``` + +Do not serialize IDs as: + +```text +org_ +user_ +project_ +``` + +unless a future ADR explicitly changes the public identifier contract. + +Human-friendly resource references use separate fields such as: + +```text +projectNumber +matterNumber +patientNumber +invoiceNumber +``` + +This separates machine identity from business/display references. + +UUID generation is decided by ADR-004: + +```text +PostgreSQL-native UUIDv7 when supported and selected +or +application-generated UUIDv7 +``` + +The API format is identical either way. + +--- + +## 12. Authentication + +Initial human authentication: + +```text +Email ++ +Password ++ +Short-Lived Access Token ++ +Opaque Refresh Token ++ +Server-Side Session +``` + +REST: + +```http +POST /api/v1/auth/register +POST /api/v1/auth/login +POST /api/v1/auth/logout + +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 +``` + +`POST /auth/logout` revokes the current session. + +`DELETE /auth/sessions/{sessionId}` allows a user to revoke a specific session, such as another device. + +### Access Token + +```yaml +format: JWT +lifetime: short-lived +signed: true +encrypted: false +claims: + - sub + - sessionId + - issuer + - audience + - issuedAt + - expiresAt +``` + +Organization context is not trusted from the token as authorization authority. + +### Sessions + +```text +sessions +├── id +├── user_id +├── device metadata +├── created_at +├── last_active_at +├── expires_at +├── revoked_at +└── revocation_reason +``` + +### Refresh Tokens + +```text +refresh_tokens +├── id +├── session_id +├── family_id +├── token_hash +├── issued_at +├── expires_at +├── rotated_at +├── replaced_by_token_id +├── revoked_at +└── revocation_reason +``` + +Constraints/indexes: + +```text +UNIQUE(token_hash) +INDEX(family_id) +INDEX(session_id) +``` + +`family_id` is not unique. + +### Refresh Reuse Detection + +Use of a previously rotated token triggers: + +```text +revoke token family +revoke affected session +security audit event +reauthentication +``` + +Policy may escalate to all-session revocation. + +Future human authentication: + +- MFA +- WebAuthn/passkeys +- OIDC/SSO +- enterprise identity providers + + +## 12A. Service Accounts and API Keys + +Machine-to-machine access is separate from human sessions. + +Use: + +```text +service_accounts +api_keys +service_account_roles +``` + +### Service Account + +Suggested fields: + +```text +id +organization_id +name +description +status +created_by_user_id +created_at +updated_at +revoked_at +``` + +### API Key + +Suggested fields: + +```text +id +organization_id +service_account_id + +key_prefix +secret_hash + +created_at +expires_at +last_used_at +revoked_at +revocation_reason +``` + +Raw API-key secrets are shown only once. + +Store only a secure hash of the secret. + +`key_prefix` is safe display material for identifying a key in administration screens. + +### Authorization + +Service accounts use explicit organization-scoped permissions, preferably through: + +```text +service_account_roles +``` + +with the same registered permission vocabulary used by RBAC. + +They do not become fake human memberships. + +### Audit + +Audit actors support: + +```text +actor_type = user +actor_type = service_account +actor_type = system +``` + +Machine authentication is required when public/integration API access is implemented; it does not block the earliest internal Engineering UI slice. + +--- + +## 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. + +Tables: + +```text +membership_invitations +membership_invitation_roles +``` + +`membership_invitations`: + +```text +id +organization_id +email +invited_by_user_id +expires_at +accepted_at +revoked_at +created_at +``` + +`membership_invitation_roles`: + +```text +organization_id +invitation_id +role_id +created_at +``` + +Use tenant-aware foreign keys so invitation roles cannot reference another organization's role. + +Flow: + +```text +Invitation + Intended Roles + ↓ + Accepted + ↓ + User + ↓ + Membership + ↓ + Membership Roles +``` + +At acceptance: + +1. validate invitation token and expiry +2. validate invited email/account policy +3. create membership +4. copy valid intended roles to membership-role assignments +5. mark invitation accepted +6. audit +7. emit outbox event + +If an intended role was revoked/deleted before acceptance, acceptance fails safely or drops that role according to explicit organization policy. + +## 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 +``` + +Example: + +```text +Engineer: +engineering.projects.read = assigned + +Principal Engineer: +engineering.projects.read = organization +``` + +`assigned` is not magic. Each resource policy defines how assignment is resolved. + +### Engineering Project + +Assigned when: + +```text +engineering_project_members.user_id = ctx.userId +AND engineering_project_members.left_at IS NULL +``` + +or when the user is the active project manager, if project-manager assignment is modeled separately. + +### Engineering Task + +Assigned when: + +```text +engineering_tasks.assigned_to_user_id = ctx.userId +``` + +For tasks linked to a project, parent-project access may also be required. + +### Engineering Design + +Assigned when an active row exists in: + +```text +engineering_design_assignments +``` + +for the user and an allowed assignment role. + +### Engineering Inspection + +Assigned when: + +```text +engineering_inspections.inspector_user_id = ctx.userId +``` + +or an explicit inspection assignment exists if the model later supports multiple inspectors. + +### Derived Client Access + +An assigned professional may access a client only through a policy that derives access from authorized projects. + +Project assignment must not automatically grant access to every project belonging to that client. + +Future scopes may include: + +```text +owned +team +department +restricted +``` + +Do not add them before a real workflow requires them. + +## 21. Professional Credentials + +Professional identity and credentials are separate from RBAC. + +Use: + +```text +professional_profiles +professional_credentials +``` + +### Professional Profile + +One organization/user/profession relationship. + +Suggested fields: + +```text +id +organization_id +user_id +profession +title +status +created_at +updated_at +``` + +### Professional Credential + +One profile may hold many credentials. + +Suggested fields: + +```text +id +organization_id +professional_profile_id + +credential_type +credential_number +issuing_authority +jurisdiction +discipline + +status +valid_from +expires_at + +verified_at +verified_by_user_id + +created_at +updated_at +``` + +Examples: + +```text +professional engineering license in jurisdiction A +professional engineering license in jurisdiction B +specialty certification +medical license +controlled-substance prescribing registration where applicable +``` + +Credential policy evaluates the set of active credentials rather than one `primary_license_number`. + +High-risk actions such as design approval, record signing, or prescribing use authoritative or revocation-aware credential state. + +Prescribing remains jurisdiction/scope-of-practice policy, not a hard-coded profession test. + +## 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. + +--- + +## 21A. Deletion, Archival, Revocation, and Unlink Policy + +`DELETE` does not have one universal persistence meaning. + +Use four lifecycle behaviors. + +### Archive / Domain Inactivation + +For business records whose history matters: + +```text +engineering clients +engineering projects +legal matters +healthcare patients +documents where retention requires history +``` + +Typical fields: + +```text +status +archived_at +archived_by_user_id +``` + +Restore is permitted only when domain, retention, and organization policy allow it. + +### Revoke + +For access/security resources: + +```text +sessions +refresh tokens +API keys +membership invitations +portal grants +webhook credentials +``` + +Use: + +```text +revoked_at +revoked_by +revocation_reason +``` + +### Temporal Unlink + +For relationship records where the historical relationship matters: + +```text +project documents +project members +design assignments +portal document publications +``` + +Use: + +```text +unlinked_at +left_at +unassigned_at +revoked_at +``` + +rather than deleting historical evidence. + +### Hard Delete + +Reserved for genuinely disposable or never-committed data, such as: + +```text +expired pending upload artifacts +failed temporary staging objects +unreferenced draft configuration where audit/retention does not require history +``` + +Hard deletion of financial, professional, audit, signed clinical, or issued business records is forbidden unless an explicit retention/privacy policy defines the operation. + +Every resource specification must declare its lifecycle behavior. + +--- + +# Engineering Domain + +## 26. Engineering Tables + +Initial Engineering MVP tables: + +```text +engineering_clients +engineering_client_contacts + +engineering_projects +engineering_project_members +engineering_project_phases +engineering_sites +engineering_tasks + +engineering_designs +engineering_design_assignments +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews + +engineering_inspections +engineering_inspection_findings +engineering_inspection_followups + +engineering_specifications + +engineering_time_entries +``` + +Later Engineering extensions: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries + +engineering_change_requests +``` + +`engineering_change_requests` is not part of the initial schema until its lifecycle, relationships, and REST contract are specified. + +## 27. Engineering Clients + +Suggested core client fields: + +```text +id +organization_id +client_type +display_name +legal_name +status +created_at +updated_at +version +``` + +Do not permanently squeeze all contacts into one `email`, one `phone`, and one `contact_name`. + +Engineering customers commonly have multiple: + +```text +technical contacts +billing contacts +executive contacts +site contacts +contract contacts +``` + +Use: + +```text +engineering_client_contacts +``` + +Suggested contact fields: + +```text +id +organization_id +client_id + +name +title +department + +email +phone + +contact_type +is_primary + +created_at +updated_at +``` + +Client 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 +``` + +Contact REST: + +```http +GET /api/v1/engineering/clients/{clientId}/contacts +POST /api/v1/engineering/clients/{clientId}/contacts +PATCH /api/v1/engineering/clients/{clientId}/contacts/{contactId} +DELETE /api/v1/engineering/clients/{clientId}/contacts/{contactId} +``` + +Delete may be implemented as archival when contact history matters. + +Client restore is allowed only when organization policy and retention rules permit it. + +## 27A. Engineering Client Portal + +External clients are not internal organization members. + +Use shared authentication identities where practical, but create a separate authorization boundary. + +```text +User + │ + ├── Internal Membership + │ ↓ + │ Organization Staff Access + │ + └── Client Portal Account + ↓ + Engineering Client Contact + ↓ + Project Access Grants +``` + +Suggested tables: + +```text +engineering_client_portal_accounts +engineering_client_portal_project_grants +engineering_project_document_publications +engineering_client_review_requests +``` + +### Portal Account + +Suggested fields: + +```text +id +organization_id +user_id +engineering_client_contact_id + +status + +invited_by_user_id +invited_at +accepted_at + +revoked_at +revoked_by_user_id +``` + +Portal accounts are not placed in `memberships`. + +### Project Grant + +Suggested fields: + +```text +id +organization_id +portal_account_id +project_id + +access_profile + +granted_by_user_id +granted_at +expires_at +revoked_at +``` + +Initial access capabilities may include: + +```text +project.status.read +project.documents.read_published +project.comments.create +project.files.submit +client_review.respond +``` + +The access model may later normalize capabilities into a grant table if simple profiles become insufficient. + +### Separate Frontend + +Recommended: + +```text +apps/ +├── engineering-web/ +└── engineering-client-portal/ +``` + +The internal engineering frontend and external portal do not share authorization assumptions. + +### Client Acceptance Is Not Engineering Approval + +Never represent client acceptance with: + +```text +engineering.designs.approve +``` + +Professional engineering approval is reserved for qualified internal/authorized professionals. + +Client-facing review should use separate concepts such as: + +```text +engineering.client_reviews.request +engineering.client_reviews.respond +engineering.client_reviews.accept +engineering.client_reviews.request_changes +``` + +Example: + +```http +POST /api/v1/engineering/client-review-requests/{reviewId}/accept +POST /api/v1/engineering/client-review-requests/{reviewId}/request-changes +``` + +A client acceptance may be commercially meaningful without being a professional engineering approval. + +### Portal Security Rules + +1. portal access is deny-by-default +2. every portal request remains organization-scoped +3. portal users only access explicitly granted projects +4. project membership does not apply to portal users +5. internal RBAC roles do not automatically apply to portal users +6. portal account revocation is immediate +7. portal grants may expire +8. sensitive document access requires explicit publication +9. portal activity is audited according to organization policy +10. professional approval endpoints are never exposed through portal grants + +--- + +## 27B. External Document Publication + +A document being linked to an engineering project does **not** make it externally visible. + +Use: + +```text +engineering_project_document_publications +``` + +Suggested fields: + +```text +id +organization_id + +project_document_link_id + +audience_type +portal_account_id nullable +client_id nullable + +published_by_user_id +published_at + +expires_at +revoked_at +revoked_by_user_id +``` + +Possible audiences: + +```text +all_active_client_portal_accounts_for_project +specific_portal_account +specific_client_contact +``` + +External download checks: + +```text +authenticated portal user ++ +active portal account ++ +active project grant ++ +active document publication ++ +publication not expired/revoked ++ +document classification allows publication ++ +download permission +``` + +This prevents an internal project document from appearing in the client portal merely because it is linked to the project. + +## 28. Engineering Projects + +Suggested fields: + +```text +id +organization_id +client_id + +project_number +name +description +discipline + +status + +project_manager_user_id + +start_date +expected_completion_date +completed_date + +created_at +updated_at +version +``` + +`stage` is removed from the project row because project phases are the authoritative workflow decomposition. + +If the frontend needs a "current stage", derive it from the active/current project phase or maintain an explicitly documented `current_phase_id` pointer. + +Project `budget_minor` is also removed. + +Detailed project budgets belong to the dedicated budget model. + +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 reads: + +```http +GET /api/v1/engineering/projects/{projectId}/summary +GET /api/v1/engineering/projects/{projectId}/timeline +GET /api/v1/engineering/projects/{projectId}/budget +``` + +The budget endpoint reads from the budget module when that module exists. + +## 29. Engineering Project Members + +Suggested fields: + +```text +id +organization_id +project_id +user_id +project_role +joined_at +left_at +``` + +Initial project-role vocabulary: + +```text +project_manager +engineer +designer +reviewer +inspector +viewer +contractor +``` + +Project role describes participation in one project. + +It is not a substitute for RBAC permission. + +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} +``` + +`DELETE` means end participation by setting `left_at`, not erase historical participation. + +## 30. Engineering Project Phases + +Suggested fields: + +```text +id +organization_id +project_id +name +sequence +status +start_date +end_date +created_at +updated_at +version +``` + +Typical initial statuses: + +```text +planned +active +completed +cancelled +``` + +Example 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 +POST /api/v1/engineering/projects/{projectId}/phases/reorder +``` + +Reorder request: + +```json +{ + "projectVersion": 12, + "orderedPhaseIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b301", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b302" + ] +} +``` + +Reordering is transactional. + +Sequences remain unique within a project after commit. + +## 31. Engineering Sites + +Suggested fields: + +```text +id +organization_id +project_id +name +address +latitude +longitude +created_at +updated_at +``` + +REST: + +```http +GET /api/v1/engineering/sites +GET /api/v1/engineering/sites/{siteId} + +POST /api/v1/engineering/projects/{projectId}/sites +GET /api/v1/engineering/projects/{projectId}/sites + +PATCH /api/v1/engineering/sites/{siteId} +``` + +Global site listing is still tenant-scoped through `X-Organization-Id`. + +## 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 +``` + +Statuses: + +```text +todo +in_progress +completed +cancelled +``` + +Priorities: + +```text +low +medium +high +urgent +``` + +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 +``` + +## 32A. Engineering Batch Operations + +Batch operations are useful for repetitive engineering workflows, but they must not bypass per-resource authorization or domain rules. + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete + +POST /api/v1/engineering/time-entries/batch/submit +``` + +### Batch Execution Modes + +Every batch command explicitly defines one of: + +```text +atomic +partial +``` + +Atomic: + +```text +all resources succeed +or +entire operation fails +``` + +Partial: + +```text +each resource is evaluated independently +successful items commit +failed items return individual errors +``` + +Do not leave this behavior implicit. + +Example request: + +```json +{ + "taskIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83" + ], + "assigneeUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "mode": "partial" +} +``` + +Example response: + +```json +{ + "data": { + "succeeded": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82" + ], + "failed": [ + { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83", + "code": "RESOURCE_INVALID_STATE" + } + ] + } +} +``` + +### Authorization + +Each resource is evaluated for: + +```text +tenant +permission +scope +resource access +state validity +credential policy where applicable +``` + +Never authorize the first item and assume the remaining batch is equivalent. + +### Synchronous vs Asynchronous + +Small batches may execute synchronously. + +Large batches become jobs: + +```http +202 Accepted +``` + +with: + +```text +jobId +``` + +The synchronous/asynchronous threshold is configuration based on: + +```text +batch size +operation cost +database load +side effects +product tier +``` + +Financial or regulated batch actions require stricter idempotency and audit rules than ordinary task updates. + +--- + +## 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 +cancelled +withdrawn +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}/revise +POST /api/v1/engineering/designs/{designId}/cancel +POST /api/v1/engineering/designs/{designId}/withdraw +POST /api/v1/engineering/designs/{designId}/supersede + +POST /api/v1/engineering/designs/{designId}/assign +POST /api/v1/engineering/designs/{designId}/unassign + +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 +``` + +State machine: + +```text +draft + ├── submit-review ─────────────► under_review + └── cancel ────────────────────► cancelled + +under_review + ├── request-changes ───────────► changes_requested + ├── approve ───────────────────► approved + ├── reject ────────────────────► rejected + └── withdraw ──────────────────► withdrawn + +changes_requested + ├── submit-review ─────────────► under_review + └── withdraw ──────────────────► withdrawn + +rejected + └── revise ────────────────────► draft + +approved + └── supersede ─────────────────► superseded +``` + +Approval remains credential-aware, audited, and idempotent. + +## 34. Design Versions and Reviews + +A design version is a logical professional revision. + +It may have multiple document files. + +Use: + +```text +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews +``` + +### Design Version + +```text +id +organization_id +design_id +version_number +created_by_user_id +created_at +``` + +Unique: + +```text +(organization_id, design_id, version_number) +``` + +### Design Version Documents + +```text +id +organization_id +design_version_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +Possible `document_role` values: + +```text +primary_drawing +calculation +supporting_document +specification +attachment +``` + +A design version therefore supports one or many documents without putting `document_id` directly on the version. + +### Design Review + +```text +id +organization_id +design_id +design_version_id +reviewer_user_id +status +comments +reviewed_at +created_at +``` + +Statuses: + +```text +pending +approved +changes_requested +rejected +``` + +All three tables are tenant-owned and carry direct `organization_id`. + +## 35. Engineering Inspections + +Inspection fields: + +```text +id +organization_id +project_id +site_id + +inspection_type +inspector_user_id + +status +outcome + +scheduled_at +started_at +performed_at +cancelled_at + +summary + +created_at +updated_at +version +``` + +Lifecycle: + +```text +draft +scheduled +in_progress +completed +cancelled +``` + +Outcome: + +```text +passed +passed_with_observations +followup_required +failed +``` + +`inspection_type` is an application/domain registry rather than a PostgreSQL enum. + +Initial common keys may include: + +```text +structural +mechanical +electrical +safety +final +``` + +Organizations/modules may add supported types through controlled configuration later. + +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 + +GET /api/v1/engineering/inspections/{inspectionId}/followups +POST /api/v1/engineering/inspections/{inspectionId}/followups +``` + +Inspection completion may create follow-up records. + +Lifecycle and outcome remain separate. + +## 36. Inspection Findings + +`engineering_inspection_findings`: + +```text +id +organization_id +inspection_id + +severity +description +status + +resolved_at +resolved_by_user_id + +created_at +updated_at +version +``` + +Severity: + +```text +observation +minor +major +critical +``` + +Status: + +```text +open +in_progress +resolved +accepted_risk +``` + +REST: + +```http +POST /api/v1/engineering/inspections/{inspectionId}/findings +PATCH /api/v1/engineering/inspection-findings/{findingId} +POST /api/v1/engineering/inspection-findings/{findingId}/resolve +``` + +`organization_id` is direct even though tenant ownership is also derivable through the inspection. + +### Follow-Up Resource + +Use: + +```text +engineering_inspection_followups +``` + +Fields: + +```text +id +organization_id +inspection_id + +followup_type + +linked_task_id nullable +linked_inspection_id nullable + +status + +created_by_user_id +created_at +completed_at +cancelled_at +``` + +`followup_type`: + +```text +corrective_task +followup_inspection +both +``` + +`status`: + +```text +open +in_progress +completed +cancelled +``` + +Tenant-safe foreign keys apply to the original inspection and any linked task/inspection. + +## 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 + +**Deferred from the initial Engineering schema.** + +Change requests are a valid future engineering capability, but v4.1 does not create the table until these are specified: + +```text +relationship to project +relationship to design/specification +request origin +impact analysis +cost/schedule effects +review workflow +approval authority +state machine +document links +REST commands +audit requirements +``` + +Future candidate: + +```text +engineering_change_requests +``` + +This belongs in the Engineering extension backlog rather than a half-defined initial migration. + +## 38A. Engineering Project Budgets + +A single `budget_minor` column is sufficient only for a very early project total. + +When budget management enters scope, introduce: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries +``` + +### Budget + +Suggested fields: + +```text +id +organization_id +project_id + +name +currency_code +status + +approved_by_user_id +approved_at + +created_at +updated_at +version +``` + +### Budget Item + +Suggested fields: + +```text +id +organization_id +budget_id + +category +description + +allocated_amount_minor + +created_at +updated_at +``` + +Do not casually store mutable: + +```text +spent_amount_minor +committed_amount_minor +``` + +as independent sources of truth if those values are derived from time entries, expenses, purchase commitments, or invoices. + +Prefer: + +```text +authoritative cost/commitment records + ↓ +derived budget projections +``` + +If denormalized totals are needed for performance, update them transactionally and reconcile them. + +Potential REST: + +```http +GET /api/v1/engineering/projects/{projectId}/budgets +POST /api/v1/engineering/projects/{projectId}/budgets +GET /api/v1/engineering/budgets/{budgetId} +PATCH /api/v1/engineering/budgets/{budgetId} + +POST /api/v1/engineering/budgets/{budgetId}/approve +GET /api/v1/engineering/budgets/{budgetId}/items +POST /api/v1/engineering/budgets/{budgetId}/items +``` + +Budget approval is an explicit command. + +--- + +## 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 + +phase_id nullable +task_id nullable +design_id nullable +inspection_id nullable + +created_at +updated_at +version +``` + +The project is always required. + +A time entry may also identify one primary work item. + +Database check: + +```text +at most one of: +phase_id +task_id +design_id +inspection_id +``` + +Each optional foreign key is tenant-aware: + +```text +(organization_id, task_id) +→ engineering_tasks(organization_id, id) +``` + +and similarly for phase, design, and inspection. + +This preserves relational integrity instead of using an unconstrained polymorphic `reference_type/reference_id`. + +REST: + +```http +POST /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries/{timeEntryId} +PATCH /api/v1/engineering/time-entries/{timeEntryId} + +POST /api/v1/engineering/time-entries/batch/submit +``` + +Duration is integer minutes. + +## 40. Legal Tables + +Initial legal-domain tables: + +```text +legal_clients +legal_matters +legal_matter_members +legal_cases +legal_case_parties +legal_courts +legal_hearings +legal_deadlines +legal_time_entries +legal_retainers +legal_conflict_checks +legal_conflict_parties +legal_conflict_matches +``` + +There is no separate `legal_documents` ownership table. + +Documents remain shared infrastructure: + +```text +documents +document_versions +``` + +Legal relationships use: + +```text +legal_matter_documents +legal_case_documents +``` + +REST namespace: + +```text +/api/v1/legal +``` + +Legal remains a later vertical. + +## 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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cbd", + "status": "pending_review", + "potentialConflicts": [ + { + "type": "possible_direct_adversity", + "partyName": "Acme Corporation", + "existingMatterId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2ccd", + "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 + +Healthcare remains a later vertical. + +Minimum planned tables: + +```text +healthcare_patients +healthcare_patient_contacts +healthcare_patient_addresses + +healthcare_practitioners +healthcare_locations +healthcare_rooms + +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 +``` + +All tenant-owned tables carry direct `organization_id`. + +Detailed healthcare interoperability, terminology, and jurisdiction rules require healthcare-specific design before implementation. + +## 46. Healthcare Patients + +Core patient: + +```text +id +organization_id +patient_number + +first_name +middle_name +last_name +date_of_birth + +administrative_gender nullable +sex_at_birth nullable +gender_identity nullable + +status + +created_at +updated_at +version +``` + +Exact demographic terminology and allowed values are finalized in the healthcare-domain specification. + +Do not make every field mandatory merely because it exists. + +### Patient Contact + +`healthcare_patient_contacts`: + +```text +id +organization_id +patient_id + +contact_type +value +is_primary + +created_at +updated_at +``` + +### Patient Address + +`healthcare_patient_addresses`: + +```text +id +organization_id +patient_id + +address_type +line_1 +line_2 +city +region +postal_code +country_code + +is_primary + +created_at +updated_at +``` + +Sensitive subresources remain permission-controlled. + +## 47. Healthcare Practitioners + +Suggested fields: + +```text +id +organization_id +user_id +professional_profile_id + +specialty +status + +created_at +updated_at +``` + +Professional licenses are not duplicated here. + +Multiple licenses/credentials live in: + +```text +professional_credentials +``` + +## 48. Healthcare Appointments + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id + +location_id nullable +room_id nullable + +appointment_type + +starts_at +ends_at + +status +reason + +created_at +updated_at +version +``` + +Planned supporting tables: + +`healthcare_locations`: + +```text +id +organization_id +name +address fields +timezone +status +``` + +`healthcare_rooms`: + +```text +id +organization_id +location_id +name +status +``` + +Exact scheduling rules are deferred to the healthcare vertical. + +## 49. Healthcare Encounters + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id +appointment_id nullable + +encounter_type + +reason_for_visit nullable + +started_at +ended_at + +status + +created_at +updated_at +version +``` + +Do not add a generic free-form `notes` field as a substitute for clinical records. + +Clinical narrative belongs in governed clinical-record structures. + +## 50. Clinical Records + +Use: + +```text +healthcare_clinical_records +healthcare_clinical_record_versions +healthcare_clinical_record_amendments +``` + +### Clinical Record + +```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 +``` + +### Clinical Record Version + +```text +id +organization_id +record_id +version_number + +content_reference or governed content payload +created_by_practitioner_id +created_at +``` + +### Clinical Record Amendment + +```text +id +organization_id +record_id +source_version_id +result_version_id + +amended_by_practitioner_id + +amendment_type +amendment_reason + +created_at +``` + +Possible amendment types: + +```text +correction +addendum +clarification +``` + +Signed/finalized history is preserved. + +REST: + +```http +POST /api/v1/healthcare/encounters/{encounterId}/clinical-records + +GET /api/v1/healthcare/clinical-records/{recordId} +PATCH /api/v1/healthcare/clinical-records/{recordId} +# Draft/editable only. + +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 +``` + +## 51. Documents + +Shared document infrastructure: + +```text +documents +document_versions +document_categories +retention_policies +``` + +Binary data lives in S3-compatible object storage. + +### Document + +```text +id +organization_id +name +category_id +classification +retention_policy_id +current_version_id +created_by_user_id +created_at +updated_at +``` + +Classification: + +```text +public +internal +confidential +restricted +regulated +``` + +### Document Version + +```text +id +organization_id +document_id +version_number +storage_key +mime_type +size_bytes +content_hash +hash_algorithm +uploaded_by_user_id +created_at +``` + +Checksum is version-level authoritative data. + +### Document Category + +```text +id +organization_id +profession nullable +name +parent_category_id +created_at +``` + +Uniqueness requirement: + +```text +shared category: + unique organization_id + name where profession IS NULL + +profession category: + unique organization_id + profession + name where profession IS NOT NULL +``` + +Implementation options: + +```text +PostgreSQL null-aware unique constraint when supported +or +two partial unique indexes +``` + +The partial-index fallback does not depend on selecting PostgreSQL 18. + +### Retention Policy + +```text +id +organization_id + +name +profession nullable +classification nullable + +retention_period_days nullable +action + +created_at +updated_at +``` + +Initial actions: + +```text +review +archive +delete_when_legally_permitted +retain_indefinitely +``` + +A retention policy describes configured behavior. + +Actual deletion remains subject to domain, contractual, privacy, and jurisdiction requirements. + +### Metadata + +JSONB is allowed only for genuinely extensible, non-authoritative metadata. + +Do not put authorization, lifecycle, retention state, or ownership into arbitrary JSON. + +## 52. Document Upload Flow + +### Standard Upload + +Request: + +```http +POST /api/v1/documents/upload-url +``` + +```json +{ + "name": "structural-calculations.pdf", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/pdf", + "sizeBytes": 2457600, + "contentHash": "sha256:..." +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d01", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "uploadUrl": "https://object-storage.example/...", + "expiresAt": "2026-08-26T13:00:00Z" + } +} +``` + +The frontend uploads directly to object storage. + +Finalize: + +```http +POST /api/v1/documents/{documentId}/complete-upload +``` + +```json +{ + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "contentHash": "sha256:..." +} +``` + +### Multipart Initialization + +```http +POST /api/v1/documents/multipart-uploads +``` + +Request: + +```json +{ + "name": "building-model.bin", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/octet-stream", + "sizeBytes": 2147483648, + "contentHash": null +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d10", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d11", + "uploadId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d12", + "recommendedPartSizeBytes": 67108864, + "expiresAt": "2026-08-27T12:00:00Z" + } +} +``` + +### Request Signed Part URLs + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/parts +``` + +```json +{ + "partNumbers": [1, 2, 3, 4] +} +``` + +Response: + +```json +{ + "data": [ + { + "partNumber": 1, + "uploadUrl": "https://object-storage.example/..." + } + ] +} +``` + +Binary parts go directly to object storage. + +### Complete Multipart Upload + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/complete +``` + +```json +{ + "parts": [ + { + "partNumber": 1, + "etag": "..." + } + ], + "contentHash": "sha256:..." +} +``` + +Abort: + +```http +DELETE /api/v1/documents/{documentId}/multipart-uploads/{uploadId} +``` + +Upload state: + +```text +initiated +uploading +completing +completed +aborted +expired +``` + +Workers clean up abandoned multipart uploads. + +Upload policy validates: + +```text +declared MIME +extension +content signature +size +checksum +quota +classification +malware status +``` + +## 53. Profession-Specific Document Links + +Use explicit relationship tables. + +Engineering: + +```text +engineering_project_documents +engineering_design_version_documents +engineering_inspection_documents +``` + +Legal: + +```text +legal_matter_documents +legal_case_documents +``` + +Healthcare: + +```text +healthcare_patient_documents +healthcare_encounter_documents +``` + +`engineering_design_version_documents` is authoritative for files belonging to a specific design revision. + +Do not also maintain an ambiguous `engineering_design_documents` relation to the unversioned design unless a later requirement introduces a separate clearly named supporting-document relationship. + +### Project Documents + +```text +engineering_project_documents +├── id +├── organization_id +├── project_id +├── document_id +├── category +├── linked_by_user_id +├── linked_at +└── unlinked_at +``` + +REST: + +```http +GET /api/v1/engineering/projects/{projectId}/documents +POST /api/v1/engineering/projects/{projectId}/documents +DELETE /api/v1/engineering/project-documents/{documentLinkId} +``` + +`DELETE` temporally unlinks the relation when history must be preserved. + +## 54. Billing + +Shared financial core: + +```text +invoices +invoice_items +payments +``` + +### Invoice + +Core fields include: + +```text +id +organization_id +client/reference context +invoice_number +status +currency_code +subtotal_minor +tax_total_minor +total_minor +issued_at +due_at +paid_at +created_at +updated_at +version +``` + +### Invoice Item + +```text +id +organization_id +invoice_id + +description + +quantity +unit_price_minor +total_amount_minor + +position + +created_at +updated_at +``` + +`quantity` uses fixed-precision numeric semantics, not floating point. + +Money uses integer minor units. + +The invoice determines currency; invoice items do not independently choose a different currency unless multi-currency invoicing is intentionally designed later. + +### Profession-Specific Source Links + +The shared billing module does not use unconstrained: + +```text +reference_type +reference_id +``` + +to profession-owned tables. + +Profession modules create explicit links, for example: + +```text +engineering_invoice_item_time_entries +├── organization_id +├── invoice_item_id +└── time_entry_id +``` + +This preserves the rule that shared core does not depend on profession-table internals. + +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 + +Use: + +```text +audit_events +``` + +Suggested fields: + +```text +id +organization_id + +actor_type +actor_user_id nullable +actor_service_account_id nullable + +action + +resource_type +resource_id + +request_id +correlation_id + +ip_address +user_agent + +metadata + +occurred_at +``` + +Audit records are append-only from normal application workflows. + +### Mandatory Examples + +Engineering: + +```text +engineering.projects.create +engineering.projects.close +engineering.designs.approve +engineering.inspections.complete +``` + +Legal: + +```text +legal.matters.create +legal.matters.close +legal.conflicts.approve +``` + +Healthcare: + +```text +healthcare.records.read +healthcare.records.write +healthcare.records.sign +healthcare.records.amend +``` + +### Privacy / Erasure Handling + +Append-only audit does not mean "store unlimited personal data forever." + +Audit metadata must be minimized at write time. + +Where privacy, contractual, or retention obligations require removal of personally identifying material, use a governed privacy process such as: + +```text +pseudonymize actor references +null/remove nonessential PII fields +replace identifiers with irreversible privacy references where appropriate +retain the security/business event itself when permitted/required +``` + +The exact action depends on jurisdiction and retention policy and must be reviewed before healthcare/legal production. + +Do not place passwords, tokens, full clinical content, secret keys, or unnecessary payment data in audit metadata. + +REST: + +```http +GET /api/v1/audit-events +``` + +No public mutation endpoints. + +## 57. Domain Events and Transactional Outbox + +Use: + +```text +outbox_events +``` + +Fields: + +```text +id +organization_id nullable for truly global events + +event_type +aggregate_type +aggregate_id + +payload + +request_id nullable +correlation_id +causation_id nullable + +occurred_at +available_at +processed_at + +attempt_count +last_error +dead_lettered_at +``` + +`correlation_id` groups one logical workflow across requests/jobs/events. + +`causation_id` identifies the event/command that directly caused this event when applicable. + +Transaction: + +```text +BEGIN +business change +audit event +outbox event +COMMIT +``` + +Delivery semantics are at-least-once. + +Worker claim uses row locking such as: + +```sql +SELECT id +FROM outbox_events +WHERE processed_at IS NULL + AND dead_lettered_at IS NULL + AND available_at <= now() +ORDER BY occurred_at +FOR UPDATE SKIP LOCKED +LIMIT 100; +``` + +Every external side-effect consumer must be idempotent. + +`FOR UPDATE SKIP LOCKED` prevents simultaneous claiming; it does not prevent duplicate side effects after a worker crash. + +## 57A. Webhooks and External Integrations + +Shared tables: + +```text +webhooks +webhook_event_subscriptions +webhook_deliveries +``` + +### Webhook + +```text +id +organization_id +url +status +secret_ciphertext or signing_key_reference +created_by_user_id +created_at +updated_at +``` + +### Subscription + +```text +id +organization_id +webhook_id +event_type +created_at +``` + +Unique: + +```text +(organization_id, webhook_id, event_type) +``` + +Only registered externally publishable event types may be subscribed. + +### Delivery + +```text +id +organization_id +webhook_id +event_id + +attempt_number +request_timestamp +response_status +response_summary + +delivered_at +failed_at +next_attempt_at +``` + +Configuration REST: + +```http +GET /api/v1/webhooks +POST /api/v1/webhooks +GET /api/v1/webhooks/{webhookId} +PATCH /api/v1/webhooks/{webhookId} +DELETE /api/v1/webhooks/{webhookId} + +POST /api/v1/webhooks/{webhookId}/test +POST /api/v1/webhooks/{webhookId}/rotate-secret +``` + +Delivery REST: + +```http +GET /api/v1/webhook-deliveries +GET /api/v1/webhook-deliveries/{deliveryId} +POST /api/v1/webhook-deliveries/{deliveryId}/retry +``` + +If HMAC signing is used, signing material is encrypted/recoverable with managed key protection. + +A one-way secret hash is insufficient for outbound HMAC signing. + +Webhook consumers deduplicate using stable event IDs. + +## 58. Background Jobs + +Workers handle: + +```text +notifications +reports/PDFs +file scanning +document processing +imports +exports +bulk operations +webhooks +search indexing +large data operations +``` + +Use shared tenant-owned: + +```text +jobs +``` + +Fields: + +```text +id +organization_id +requested_by_user_id + +job_type +status + +input_reference +result_reference +progress_percent + +created_at +started_at +completed_at +failed_at + +error_code +error_summary +``` + +States: + +```text +queued +running +completed +failed +cancelled +``` + +REST: + +```http +GET /api/v1/jobs/{jobId} +GET /api/v1/jobs/{jobId}/result +POST /api/v1/jobs/{jobId}/cancel +``` + +These endpoints are tenant-scoped through the standard: + +```http +X-Organization-Id +``` + +They do not need `/organizations/{id}/jobs` because the platform already chose header-based tenant context. + +Large import/export operations return: + +```http +202 Accepted +``` + +with a job ID. + +## 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. + +Defaults: + +```text +default limit = 25 +maximum limit = 100 +offset pagination = not supported +``` + +Example: + +```http +GET /api/v1/engineering/projects?limit=25 +``` + +Response: + +```json +{ + "data": [], + "meta": { + "pagination": { + "nextCursor": null, + "hasMore": false + } + } +} +``` + +Rules: + +```text +cursor is opaque +sort order must be deterministic +cursor encodes/represents the selected sort position +unsupported limits return validation errors rather than silent huge responses +``` + +## 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=0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d +``` + +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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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/reuse detection +server-side session revocation + +rate limiting +anti-automation controls + +RBAC +resource policies +credential-aware authorization +tenant isolation + +input validation +SQL injection protection + +signed object-storage URLs +file-content validation +malware scanning + +audit trails +secret management +encryption at rest + +dependency/image scanning + +request/correlation IDs +backup and restore testing +``` + +### Web Security / CORS + +ADR-009 defines environment-specific web security. + +Baseline requirements: + +```text +explicit CORS allowlist +no wildcard credentialed CORS +allowed methods/headers documented +preflight behavior tested +HSTS at the edge for production HTTPS +X-Content-Type-Options: nosniff +secure cookie attributes when cookies are used +CSP on browser frontends +frame-ancestor/clickjacking policy on frontends +referrer policy appropriate to the frontend +``` + +Security headers belong at the appropriate application/CDN/gateway layer. + +### Rate Limiting + +Policies are endpoint-specific and configurable. + +Return: + +```http +429 Too Many Requests +Retry-After: ... +``` + +### Secrets + +Production secrets live outside source control, preferably in managed secret/key systems. + +JWT signing keys support rotation. + +## 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 +``` + +### Core Metrics + +API: + +```text +api_requests_total +api_errors_total +api_request_duration_seconds +``` + +Authentication: + +```text +auth_login_attempts_total +auth_token_refresh_total +auth_refresh_reuse_detections_total +auth_sessions_revoked_total +``` + +Authorization/security: + +```text +cross_tenant_access_attempts_total +tenant_isolation_invariant_failures_total +authorization_denials_total +credential_policy_denials_total +rate_limit_events_total +``` + +Important distinction: + +```text +cross_tenant_access_attempt += +request attempted another tenant's resource +``` + +This may be a stale link, mistake, or attack. + +```text +tenant_isolation_invariant_failure += +our system nearly or actually created/returned cross-tenant data +``` + +That is a high-severity internal correctness/security incident. + +Outbox/jobs/webhooks: + +```text +outbox_events_pending +outbox_events_failed_total +outbox_processing_duration_seconds + +jobs_queued +jobs_failed_total +job_duration_seconds + +webhook_delivery_attempts_total +webhook_delivery_failures_total +webhook_delivery_latency_seconds +``` + +Database: + +```text +db_pool_active +db_pool_waiting +db_query_duration_seconds +db_transaction_duration_seconds +``` + +Business metrics may include: + +```text +engineering_projects_created_total +engineering_designs_approved_total +engineering_inspections_completed_total +invoices_issued_total +``` + +Avoid patient-specific or sensitive identifiers in metric labels. + +### Alerts + +Examples: + +```text +refresh token reuse detected +tenant isolation invariant failure +outbox backlog exceeds SLO +webhook failure spike +database pool saturation +error-rate spike +latency regression +backup failure +malware scanner unavailable +``` + +Thresholds are calibrated from real environments rather than copied from a review document. + +### SLOs + +Define by endpoint class. + +Interactive CRUD, reports, file orchestration, and background jobs should not share one arbitrary latency target. + +## 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 +``` + +### Property-Based Tests + +Use property-based testing for high-value domain state machines. + +Candidates: + +```text +engineering design lifecycle +engineering inspection lifecycle +invoice lifecycle +payment state transitions +membership/role invariants +``` + +Correct properties: + +```text +every successful transition ends in a valid state + +every forbidden transition is rejected + +terminal states reject prohibited actions + +required invariants survive every valid transition + +transition sequences never bypass required approval/credential rules +``` + +Do not assert that every random state/action pair succeeds. Many are supposed to fail. + +### Integration Tests + +Test: + +```text +repositories +tenant-aware foreign keys +PostgreSQL constraints +transactions +outbox persistence +idempotency persistence +cache invalidation +job persistence +webhook delivery persistence +``` + +### API Tests + +Every important endpoint covers: + +```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 creation +outbox creation +``` + +### Outbox Reliability / Chaos Tests + +Test: + +```text +worker crash before side effect +worker crash after side effect but before marking processed +two workers competing for same row +temporary dependency outage +retry/backoff behavior +dead-letter behavior +consumer idempotency +lost worker wake-up +replay +``` + +The dangerous scenario is: + +```text +external side effect succeeds +worker dies +event retries +``` + +Tests must prove the consumer does not create an unacceptable duplicate. + +### Tenant Security Tests + +Test both: + +```text +external cross-tenant access attempts +``` + +and: + +```text +internal cross-tenant data invariant failures +``` + +These are different classes of failure. + +### Performance Tests + +Create realistic profiles: + +```text +interactive reads +interactive writes +search +dashboard read models +reporting +file upload orchestration +outbox processing +webhook bursts +notification bursts +``` + +Measure: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +``` + +Set production SLO gates only after a realistic baseline exists. + +### Coverage + +Track code coverage. + +Do not treat a single percentage such as `90%` as proof of quality. + +Critical-path expectations are stronger: + +```text +all tenant-isolation paths tested +all financial commands tested +all regulated commands tested +all state transitions tested +all critical authorization policies tested +``` + +## 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 +session/token model +idempotency strategy +error taxonomy +OpenAPI skeleton +engineering state machines +migration conventions +threat model +initial ADRs +risk register +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +auth +sessions +refresh-token families +token rotation/revocation + +users +organizations +organization professions + +membership invitations +memberships +roles +permissions +authorization + +audit +outbox + +request context +idempotency +rate limiting +observability +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering clients +engineering client contacts +client archive/restore +``` + +### Phase 3: Engineering Projects + +Build: + +```text +projects +project members +project phases +activation/close/archive +``` + +### Phase 4: Work and Site Management + +Build: + +```text +tasks +task batch operations +sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +versions +categories +classification +retention references +signed uploads +multipart uploads +content verification +malware scanning +engineering document links +``` + +### Phase 6: Engineering Designs + +Build: + +```text +designs +assignments +versions +reviews +cancel/withdraw semantics +credential-aware approval +audit +outbox +idempotency +``` + +### Phase 7: Engineering Inspections + +Build: + +```text +inspection lifecycle +inspection outcome +findings +corrective work +follow-up inspections +attachments +audit +outbox +idempotency +``` + +### Phase 8: Time, Budgets, and Billing + +Build: + +```text +time entries +batch timesheet submission +project budgets when required +invoices +payments +financial idempotency +reconciliation +``` + +### Phase 9: Notifications, Jobs, and Webhooks + +Build: + +```text +notifications +email +async jobs +imports/exports +webhooks +delivery/retry +dead-letter handling +``` + +### Phase 10: Reporting and Search + +Build: + +```text +project status +overdue work +inspection status +billable time +revenue +outstanding invoices +dashboard read models +``` + +### Phase 11: Engineering Client Portal + +Build: + +```text +portal account invitations +external project grants +published project documents +client review/acceptance workflow +portal audit +portal-specific frontend +``` + +Do not expose professional approval actions to client portal accounts. + +### Phase 12: Legal Vertical + +Validate shared core against: + +```text +matters +cases +conflicts +deadlines +retainers +restricted access / ethical walls +``` + +### Phase 13: Healthcare Readiness and Vertical + +Before implementation: + +```text +healthcare threat model +privacy review +jurisdiction analysis +scope-of-practice policy +record signing/amendment model +retention model +audit requirements +``` + +### Estimation Rule + +These are dependency-ordered milestones. + +They are not calendar promises. + +Calendar estimates require: + +```text +team size +frontend/UX scope +cloud decisions +third-party providers +security requirements +QA capacity +domain-expert availability +``` + +## 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 uses UUIDv7. + +Supported implementation choices: + +```text +PostgreSQL 18+: + use native uuidv7() if database-generated identifiers are desired + +Earlier PostgreSQL: + generate UUIDv7 in the application or use a controlled extension +``` + +Database columns remain PostgreSQL `UUID`. + +The rule is consistency, not ideological loyalty to one generation layer. + +Do not silently fall back to UUIDv4 while documenting UUIDv7. + +### Production Migration Rules + +Use expand/contract: + +```text +1. add backward-compatible schema +2. deploy code supporting old + new schema +3. backfill/migrate +4. switch reads/writes +5. observe +6. remove obsolete schema later +``` + +For destructive changes: + +```text +backup/restore plan +compatibility window +production-like dry run +explicit approval +post-migration verification +``` + +Do not assume a destructive database migration can always be reversed by a simple down migration. + +Never use automatic ORM schema synchronization in production. + +## 91A. Architecture Decision Records + +v4 stops treating technology suggestions as automatically settled architecture. + +Create ADRs before implementation locks in: + +```text +ADR-001 Backend Framework +ADR-002 SQL / ORM / Query Layer +ADR-003 Queue Implementation +ADR-004 PostgreSQL Minimum Version +ADR-005 Error Format / RFC 9457 Compatibility +ADR-006 Rate-Limit Header Convention +ADR-007 Webhook Signing Strategy +ADR-008 Object Storage Provider / Multipart Strategy +ADR-009 Web Security / CORS / Browser Headers +ADR-010 Machine Authentication / API Key Policy +``` + +Each ADR should include: + +```text +context +decision +alternatives considered +tradeoffs +security impact +operational impact +migration/exit path +date +status +``` + +The architecture currently fixes capabilities and boundaries. + +It does not require a framework merely because a review document described it positively. + +--- + +## 92. Technology Recommendation + +The following are preferred candidates, not all final decisions. + +### Fixed Platform Choices + +```text +API style: REST +Contract: OpenAPI 3.1 +Primary language: TypeScript +Primary database: PostgreSQL +Architecture: Modular Monolith +Observability standard: OpenTelemetry +Object storage model: S3-compatible +Container model: Docker/OCI +``` + +### ADR-Gated Choices + +Backend framework candidates: + +```text +NestJS +Fastify-centered custom application structure +``` + +SQL / persistence candidates: + +```text +Drizzle +Kysely +Prisma +direct SQL for specialized queries +``` + +Queue candidates: + +```text +BullMQ / Redis +managed cloud queue +``` + +PostgreSQL baseline: + +```text +PostgreSQL 18+ +``` + +is attractive because of native UUIDv7 and current capabilities, but the minimum supported version must be confirmed against: + +```text +hosting provider availability +operations policy +extension requirements +upgrade policy +support lifecycle +``` + +Do not claim one ORM is categorically "faster" or "better" without workload-specific evidence. + +The selected stack should preserve: + +```text +transaction control +explicit SQL visibility +tenant-safe query design +migration control +observability +testability +``` + +## 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 API contract. +4. GraphQL is not part of v1. +5. Start as one modular monolith backend. +6. Each profession has its own frontend. +7. Each profession owns its domain tables and state machines. +8. Shared modules provide infrastructure, not forced domain abstractions. +9. Public serialized IDs are raw UUIDv7. +10. Database ID columns use PostgreSQL UUID. +11. Human-readable business references are separate from resource IDs. +12. Every tenant-owned row carries direct `organization_id`. +13. Tenant-scoped requests require explicit `X-Organization-Id`. +14. Tenant boundaries are enforced in queries and database constraints. +15. Cross-tenant resources appear nonexistent. +16. API JSON/query parameter names use camelCase; DB identifiers use snake_case. +17. Authorization is server-side and deny-by-default. +18. `assigned` scope is defined per resource policy, never inferred generically. +19. Roles and professional credentials are separate. +20. A professional profile may own multiple credentials. +21. Sessions and refresh tokens are separate resources. +22. Refresh tokens rotate within families and support reuse detection. +23. Machine identities use service accounts/API keys, not fake human memberships. +24. Important domain transitions use explicit REST command endpoints. +25. High-risk commands use durable idempotency. +26. Batch custom actions use `/{collection}/batch/{action}`. +27. Every batch defines atomic or partial semantics. +28. Every batch item receives independent authorization/domain validation. +29. Large batches become asynchronous jobs. +30. Project phases are authoritative; duplicated project `stage` is not stored. +31. Project budgets use the dedicated budget model; project `budget_minor` is not authoritative. +32. Engineering time entries may attribute time to one explicit primary work item using tenant-safe FKs. +33. Design versions and design-version document links have explicit one-to-many cardinality. +34. All design/review/version/finding/follow-up subresources carry `organization_id`. +35. Inspection lifecycle and inspection outcome are separate. +36. Inspection follow-ups are explicit resources. +37. Engineering change requests remain deferred until fully specified. +38. Shared documents own document records; profession modules own link tables. +39. Legal does not duplicate shared document ownership. +40. Large files use object-storage multipart uploads. +41. Application servers do not proxy multi-gigabyte chunks. +42. Document checksums belong to document versions. +43. Document classification is multi-level. +44. Document retention is explicit policy. +45. Document category uniqueness must work for nullable profession values on the selected PostgreSQL version. +46. Project document linkage does not imply client-portal publication. +47. External publication requires explicit publication records. +48. Client portal accounts are not internal memberships. +49. Client acceptance is not professional engineering approval. +50. Domain events use a transactional outbox. +51. Outbox delivery is at-least-once. +52. Outbox events carry correlation/causation identifiers. +53. External side-effect consumers are idempotent. +54. Webhook subscriptions and deliveries are tenant-owned. +55. HMAC signing secrets are securely recoverable/encrypted, not only hashed. +56. Jobs are tenant-scoped by the standard organization header. +57. PostgreSQL is the authoritative transactional datastore. +58. Redis is acceleration/coordination, not critical source of truth. +59. Search starts with PostgreSQL. +60. Collections use cursor pagination, default 25 and max 100. +61. Important mutable resources use optimistic concurrency. +62. Database entities are not serialized directly. +63. Errors use stable codes. +64. `429` responses use `Retry-After`; exact quota headers are an API decision. +65. Business records use explicit archive/revoke/unlink/hard-delete lifecycle policies. +66. Financial/professional/audit records are not casually hard-deleted. +67. Audit metadata is minimized and supports governed privacy transformation when required. +68. Important/regulated actions are audited. +69. Signed clinical records use sign/amend/version workflows. +70. Prescribing authority remains jurisdiction/scope-of-practice policy. +71. Production migrations use expand/contract. +72. Destructive changes are not assumed trivially reversible. +73. Secrets remain outside source control. +74. CORS and browser security policy are explicit ADR/configuration. +75. Rate limits are calibrated by evidence. +76. CI validates types, tests, OpenAPI, migrations, and security checks. +77. Property-based tests cover high-value state machines. +78. Outbox/job/webhook reliability is tested under failure/concurrency. +79. Critical-path tests matter more than vanity coverage percentages. +80. Framework/ORM/queue/PostgreSQL-minimum choices require ADRs. +81. Engineering is the first vertical. +82. Client portal follows internal Engineering MVP foundations. +83. Legal follows after Engineering validates shared assumptions. +84. Healthcare requires dedicated privacy/security/domain design before implementation. +85. Architecture documentation never equates "designed for" with "certified/compliant". + +## 95. Required Design Artifacts + +Maintain: + +```text +01_PROJECT_ARCHITECTURE.md +02_DATABASE_CONVENTIONS.md +03_AUTHORIZATION_MODEL.md +04_AUTH_SESSION_MODEL.md + +05_ENGINEERING_DOMAIN.md +06_ENGINEERING_DATABASE_SCHEMA.md +07_ENGINEERING_STATE_MACHINES.md + +08_API_CONVENTIONS.md +09_ENGINEERING_API_SPEC.md +10_OPENAPI.yaml + +11_FRONTEND_ARCHITECTURE.md +12_CLIENT_PORTAL_SECURITY_MODEL.md + +13_DOCUMENT_SECURITY_MODEL.md +14_LARGE_FILE_UPLOAD_MODEL.md + +15_WEBHOOK_INTEGRATION_MODEL.md +16_ASYNC_JOB_MODEL.md + +17_SECURITY_MODEL.md +18_DEPLOYMENT_ARCHITECTURE.md +19_OBSERVABILITY_MODEL.md +20_TESTING_STRATEGY.md + +21_ARCHITECTURE_DECISION_RECORDS/ +22_RISK_REGISTER.md +23_MVP_BACKLOG.md +``` + +Important ADRs: + +```text +backend framework +persistence/query layer +queue implementation +PostgreSQL minimum version +error format +rate-limit headers +webhook signing +object-storage provider +``` + +## 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 need efficient tenant scoping. + +Baseline: + +```text +(organization_id, id) +``` + +Common list access often benefits from: + +```text +(organization_id, created_at) +``` + +Query-specific examples: + +```text +(organization_id, status) +(organization_id, client_id) +(organization_id, project_id) +(organization_id, assigned_to_user_id) +``` + +### Rules + +1. every index corresponds to a known query, ordering, or constraint +2. column order follows real predicates +3. validate with `EXPLAIN (ANALYZE, BUFFERS)` +4. include production-like cardinality in testing +5. measure write amplification +6. do not index every field +7. introduce trigram/full-text indexes only for actual search requirements + +Potential later tools: + +```text +covering indexes +materialized views +read replicas +table partitioning +external search +``` + +These are evidence-driven scaling mechanisms, not baseline dependencies. + +### Document Category Uniqueness + +If a nullable field such as profession participates in uniqueness: + +```text +organization_id +profession nullable +name +``` + +do not assume plain uniqueness treats NULL as one shared value. + +Use PostgreSQL-supported null-aware uniqueness or partial unique indexes according to the selected PostgreSQL version. + +--- + +## 97B.## 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. + + +### Feature Flags + +Feature flags used for deployment safety are operational configuration, not automatically a business database table. + +Initial implementation may use: + +```text +environment/config-service flags +``` + +for global rollout and kill switches. + +If per-organization feature rollout is later required, introduce an explicit tenant-owned model such as: + +```text +organization_feature_flags +``` + +through an ADR/migration. + +Do not overload `organization_professions` with unrelated product experiments. + + +### 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. + +--- + +## 97D. Provisional Performance Objectives + +Performance numbers in architecture are starting hypotheses, not guarantees. + +Initial engineering objectives may begin with: + +```text +Interactive read: + target p95 <= 500 ms + +Interactive mutation: + target p95 <= 750 ms + +Simple list/search: + target p95 <= 800 ms + +Upload authorization: + target p95 <= 300 ms + +Background outbox pickup: + target <= 5 seconds under normal operating conditions +``` + +These are revised after realistic testing. + +Track: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +outbox lag +``` + +Different endpoint classes receive different SLOs. + +Do not use file-transfer completion time as an API SLO when bytes travel directly between client and object storage. + +--- + +## 97E. Risk Register + +Maintain a living risk register. + +Suggested structure: + +| Risk | Impact | Mitigation | Owner | Phase | Status | +|---|---|---|---|---|---| +| Cross-tenant data exposure | Critical | Tenant-aware FKs, scoped queries, security tests | Backend/Security | P0 | Open | +| Non-idempotent outbox side effect | Critical | Consumer dedupe, provider idempotency, chaos tests | Backend | P0 | Open | +| Migration failure | High | Expand/contract, dry runs, backups | Backend/Platform | P0 | Open | +| Engineering workflow mismatch | High | Domain expert validation | Product/Engineering SME | MVP | Open | +| Portal authorization leak | Critical | Separate external access model, publication grants | Backend/Security | Portal | Open | +| Webhook delivery instability | Medium | Retry, dead-letter, replay, metrics | Backend | Integrations | Open | +| Large upload abandonment | Medium | Multipart expiry and cleanup | Backend/Platform | Documents | Open | +| Documentation drift | Medium | OpenAPI validation, ADRs, CI | Engineering | Continuous | Open | + +Do not pretend likelihood labels are quantitative unless the team defines and uses a scoring method. + +--- + +## 97F. Architecture Change Governance + +v4 is the last broad platform-architecture revision before Engineering MVP implementation. + +New discoveries should normally become: + +```text +ADR +OpenAPI change +database migration +domain-state-machine update +security decision +backlog item +runbook +``` + +rather than a new full architecture rewrite. + +Reopen the broad architecture only when a discovery invalidates one of these foundational assumptions: + +```text +tenant model +profession separation +shared-core boundary +REST API model +data ownership +security trust boundary +deployment topology +database architecture +``` + +This prevents design review from becoming an infinite recursion problem. + +--- + +## 97G. Production Readiness Gates + +Architecture being coherent does not mean production is safe. + +Before production, require evidence in these categories. + +### Security + +```text +TLS configured +password hashing configured +refresh rotation/reuse detection tested +session revocation tested +tenant isolation tests passing +authorization/credential policies tested +rate limiting active +secrets managed outside source control +file security scanning active +security review completed +``` + +### Reliability + +```text +database backups automated +restore tested +object storage recovery strategy tested +outbox monitoring active +job queue monitoring active +webhook retry/dead-letter behavior tested +health checks configured +dependency failures tested +``` + +### Data Integrity + +```text +tenant-aware foreign keys present where required +financial invariants tested +migration tested on production-like data +idempotency tested for high-risk commands +optimistic concurrency tested +audit integrity tested +``` + +### Contract / API + +```text +OpenAPI validates +contract tests pass +error schema consistent +versioning rules documented +client SDK generation validated if used +``` + +### Performance + +```text +load test executed +realistic SLOs defined +database pool configured +key queries analyzed +outbox/job backlogs remain within SLO +``` + +### Critical Domain Coverage + +Rather than a magic overall coverage number, require explicit test coverage for: + +```text +tenant boundaries +design approval +inspection completion +invoice issue +payment/refund +membership privilege changes +clinical record signing/amendment when healthcare exists +prescribing authorization when healthcare exists +``` + +### Release Gate Principle + +No single metric such as: + +```text +90% test coverage +``` + +is sufficient evidence of production readiness. + +Quality gates are based on critical behavior, not vanity percentages. + +--- + +## 97. Final Design Position + +The platform is: + +```text +One Shared Platform + │ + ├── Shared Identity / Sessions + ├── Shared Security / Authorization + ├── Shared Documents / Multipart Uploads + ├── Shared Financial Core + ├── Shared Audit / Outbox + ├── Shared Jobs / Webhooks / Notifications + │ + ├── Engineering Internal Product + │ ├── Engineering Frontend + │ ├── Engineering REST APIs + │ ├── Engineering State Machines + │ └── Engineering Tables + │ + ├── Engineering Client Portal + │ ├── External Portal Frontend + │ ├── Portal Accounts + │ ├── Project Grants + │ ├── Published Documents + │ └── Client Review / Acceptance + │ + ├── Legal Product + │ ├── Legal Frontend + │ ├── Legal REST APIs + │ └── Legal Tables + │ + └── Healthcare Product + ├── Healthcare Frontend + ├── Healthcare REST APIs + ├── Healthcare Security Policies + └── Healthcare Tables +``` + +The system shares infrastructure where reuse is valuable while preserving profession-specific domain semantics and trust boundaries. + +v4 is the final broad architecture baseline for Engineering MVP implementation. + +From this point forward, architecture detail should primarily move into: + +```text +ADRs +OpenAPI +database schema/migrations +state-machine specifications +security policies +implementation backlog +runbooks +``` + +rather than repeatedly rewriting the entire architecture plan. + +This document does not itself prove: + +```text +regulatory compliance +production certification +security certification +performance at a specific scale +``` + +Those require implementation evidence, security review, domain validation, operational testing, restore testing, and measured production-like workloads. + + + + +--- + +# v4.1 Changelog + +v4.1 resolves implementation-contract issues without changing the core architecture. + +```text +✓ raw UUIDv7 API ID contract +✓ camelCase API / snake_case database naming convention +✓ direct organization_id on tenant subresources +✓ invitation role assignments +✓ service accounts and hashed API keys +✓ multiple professional credentials per profile +✓ global archive/revoke/unlink/hard-delete policy +✓ project stage duplication removed +✓ project budget_minor removed +✓ project phase reorder command +✓ global engineering site listing +✓ task status and priority vocabularies +✓ design revise endpoint +✓ design-version many-document cardinality +✓ design review/version tenant keys +✓ inspection finding tenant keys +✓ explicit inspection follow-up table +✓ change requests deferred until fully specified +✓ time-entry work-item attribution +✓ legal_documents duplication removed +✓ healthcare placeholder schemas clarified +✓ invoice-item schema defined +✓ document retention-policy schema +✓ version-independent document-category uniqueness fallback +✓ standard upload DTO +✓ multipart-init/parts/complete DTOs +✓ webhook subscription schema +✓ logout endpoint +✓ assigned-scope resolution rules +✓ audit privacy transformation strategy +✓ outbox correlation and causation IDs +✓ CORS/browser-security ADR +✓ feature-flag strategy clarified +✓ jobs confirmed tenant-scoped via X-Organization-Id +``` + +The next artifacts should be implementation-specific: + +```text +ADRs +Engineering OpenAPI +Engineering database migrations +Engineering state-machine spec +Engineering MVP backlog +``` diff --git a/professional_management_platform_rest_plan_v4_2.md b/professional_management_platform_rest_plan_v4_2.md new file mode 100644 index 0000000..ad16410 --- /dev/null +++ b/professional_management_platform_rest_plan_v4_2.md @@ -0,0 +1,6773 @@ +# Professional Management Platform +## Full REST-First System Design Plan + +> **Revision:** v4.1 — Consistency and Implementation-Contract Cleanup +> **Status:** Locked broad architecture baseline with implementation-blocking contradictions resolved. Subsequent detail belongs in ADRs, OpenAPI, migrations, domain specifications, and backlog items. +> **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 + +### v4.1 Cleanup Notes + +v4.1 does not redesign the platform. It resolves contradictions and fills implementation contracts discovered during detailed review. + +Resolved: + +- raw UUIDv7 is now the serialized/API identifier format +- database columns remain UUID; prefixed strings are not public IDs +- all tenant-owned subresources carry direct `organization_id` +- design-version document cardinality is explicit and relational +- engineering time entries can be attributed to a specific work item +- time-entry work-item links are constrained to the time entry's project +- engineering specifications use explicit many-document link records +- project-level `budget_minor` is removed in favor of the dedicated budget model +- duplicate `legal_documents` ownership is removed +- legal matter/case document-link schemas are defined +- batch custom-action paths use one documented convention +- membership invitations can pre-assign multiple roles +- missing design `revise` command is added +- inspection follow-ups now have a table and lifecycle +- change requests are moved out of the initial Engineering schema until specified +- service accounts and API keys are defined for machine access +- service-account role assignments have an explicit relational schema +- API JSON, query parameters, and path parameter names use camelCase; database columns use snake_case +- professional profiles support multiple professional credentials +- deletion/archival/revocation/unlink behavior is globally defined +- invoice-item fields are specified +- deferred healthcare placeholder tables receive minimum schemas or explicit deferral notes +- document upload and multipart DTOs are defined +- webhook subscription fields are defined +- `POST /auth/logout` is restored +- portal review-request and portal capability schemas are defined +- project-role, task-status, priority, and inspection-outcome values are defined +- document-category uniqueness has a version-independent fallback +- retention policy fields are defined +- retention-period null semantics are explicit +- pagination defaults are explicit +- `assigned` authorization scope has resource-specific resolution rules +- feature-flag behavior is clarified +- audit privacy minimization/anonymization strategy is documented +- outbox correlation and causation IDs are added +- webhook delivery event references and job reference envelopes are defined +- CORS and web-security configuration is moved into a required ADR +- project `stage` duplication is removed; project phases remain authoritative +- phase reordering, site listing, appointment locations, and encounter reason fields are clarified +- jobs remain tenant-scoped through the standard organization header rather than path nesting + +--- +--- +--- +--- + +## 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: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +X-Request-Id: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff +Content-Type: application/json +``` + +### API Naming Convention + +Public API representation: + +```text +JSON properties: camelCase +query parameters: camelCase +path parameter names in documentation: camelCase +HTTP headers: conventional HTTP header casing +``` + +Database representation: + +```text +table names: snake_case +column names: snake_case +constraint/index names: snake_case +``` + +Example: + +```http +GET /api/v1/engineering/tasks?assignedToUserId=&createdAfter=2026-08-01T00:00:00Z +``` + +```json +{ + "assignedToUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "createdAt": "2026-08-26T12:00:00Z" +} +``` + +maps internally to columns such as: + +```text +assigned_to_user_id +created_at +``` + +### Organization Context + +`X-Organization-Id` is mandatory for every tenant-scoped endpoint. + +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: + +```yaml +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_mismatch: + status: 404 + code: RESOURCE_NOT_FOUND +``` + +### Idempotency + +Use: + +```http +Idempotency-Key: 8f7d6c5e-4b3a-4b1c-9d8e-7f6a5b4c3d2e +``` + +Required where duplicate execution can create material side effects. + +PostgreSQL is authoritative for critical idempotency records. + +Redis may accelerate lookup. + +### Batch Custom-Action Convention + +For collection-level custom commands use: + +```text +/{collection}/batch/{action} +``` + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete +POST /api/v1/engineering/time-entries/batch/submit +``` + +Do not mix `batch-assign`, colon-style custom methods, and `/batch/assign` in the same API. + +### Rate-Limit Responses + +```http +429 Too Many Requests +Retry-After: +``` + +Additional rate-limit metadata may be exposed according to the selected gateway/standard. + +Do not freeze legacy `X-RateLimit-*` names here. + +### Error Standard Decision + +The current error envelope remains: + +```json +{ + "error": { + "code": "RESOURCE_NOT_FOUND", + "message": "Resource not found.", + "details": {}, + "requestId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff" + } +} +``` + +ADR-005 decides whether OpenAPI v1 aligns this with RFC 9457 Problem Details. + +Do not silently change the envelope during implementation. + +## 9. Standard Response Format + +Single resource: + +```json +{ + "data": { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c6d", + "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. + +--- + +## 11A. Identifier Convention + +The serialized identifier standard is **raw UUIDv7**. + +Example: + +```text +0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +``` + +Database: + +```sql +id UUID PRIMARY KEY +``` + +API: + +```json +{ + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d" +} +``` + +Do not serialize IDs as: + +```text +org_ +user_ +project_ +``` + +unless a future ADR explicitly changes the public identifier contract. + +Human-friendly resource references use separate fields such as: + +```text +projectNumber +matterNumber +patientNumber +invoiceNumber +``` + +This separates machine identity from business/display references. + +UUID generation is decided by ADR-004: + +```text +PostgreSQL-native UUIDv7 when supported and selected +or +application-generated UUIDv7 +``` + +The API format is identical either way. + +--- + +## 12. Authentication + +Initial human authentication: + +```text +Email ++ +Password ++ +Short-Lived Access Token ++ +Opaque Refresh Token ++ +Server-Side Session +``` + +REST: + +```http +POST /api/v1/auth/register +POST /api/v1/auth/login +POST /api/v1/auth/logout + +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 +``` + +`POST /auth/logout` revokes the current session. + +`DELETE /auth/sessions/{sessionId}` allows a user to revoke a specific session, such as another device. + +### Access Token + +```yaml +format: JWT +lifetime: short-lived +signed: true +encrypted: false +claims: + - sub + - sessionId + - issuer + - audience + - issuedAt + - expiresAt +``` + +Organization context is not trusted from the token as authorization authority. + +### Sessions + +```text +sessions +├── id +├── user_id +├── device metadata +├── created_at +├── last_active_at +├── expires_at +├── revoked_at +└── revocation_reason +``` + +### Refresh Tokens + +```text +refresh_tokens +├── id +├── session_id +├── family_id +├── token_hash +├── issued_at +├── expires_at +├── rotated_at +├── replaced_by_token_id +├── revoked_at +└── revocation_reason +``` + +Constraints/indexes: + +```text +UNIQUE(token_hash) +INDEX(family_id) +INDEX(session_id) +``` + +`family_id` is not unique. + +### Refresh Reuse Detection + +Use of a previously rotated token triggers: + +```text +revoke token family +revoke affected session +security audit event +reauthentication +``` + +Policy may escalate to all-session revocation. + +Future human authentication: + +- MFA +- WebAuthn/passkeys +- OIDC/SSO +- enterprise identity providers + + +## 12A. Service Accounts and API Keys + +Machine-to-machine access is separate from human sessions. + +Use: + +```text +service_accounts +api_keys +service_account_roles +``` + +### Service Account + +Suggested fields: + +```text +id +organization_id +name +description +status +created_by_user_id +created_at +updated_at +revoked_at +``` + +### API Key + +Suggested fields: + +```text +id +organization_id +service_account_id + +key_prefix +secret_hash + +created_at +expires_at +last_used_at +revoked_at +revocation_reason +``` + +Raw API-key secrets are shown only once. + +Store only a secure hash of the secret. + +`key_prefix` is safe display material for identifying a key in administration screens. + +### Service Account Role + +`service_account_roles` uses the same organization-scoped role registry as human RBAC assignments. + +Suggested fields: + +```text +id +organization_id +service_account_id +role_id +created_at +``` + +Unique: + +```text +(organization_id, service_account_id, role_id) +``` + +Tenant-safe foreign keys require the service account and role to belong to the same organization as the assignment. + +### Authorization + +Service accounts use explicit organization-scoped permissions, preferably through: + +```text +service_account_roles +``` + +with the same registered permission vocabulary used by RBAC. + +They do not become fake human memberships. + +### Audit + +Audit actors support: + +```text +actor_type = user +actor_type = service_account +actor_type = system +``` + +Machine authentication is required when public/integration API access is implemented; it does not block the earliest internal Engineering UI slice. + +--- + +## 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. + +Tables: + +```text +membership_invitations +membership_invitation_roles +``` + +`membership_invitations`: + +```text +id +organization_id +email +invited_by_user_id +expires_at +accepted_at +revoked_at +created_at +``` + +`membership_invitation_roles`: + +```text +organization_id +invitation_id +role_id +created_at +``` + +Use tenant-aware foreign keys so invitation roles cannot reference another organization's role. + +Flow: + +```text +Invitation + Intended Roles + ↓ + Accepted + ↓ + User + ↓ + Membership + ↓ + Membership Roles +``` + +At acceptance: + +1. validate invitation token and expiry +2. validate invited email/account policy +3. create membership +4. copy valid intended roles to membership-role assignments +5. mark invitation accepted +6. audit +7. emit outbox event + +If an intended role was revoked/deleted before acceptance, acceptance fails safely or drops that role according to explicit organization policy. + +## 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 +``` + +Example: + +```text +Engineer: +engineering.projects.read = assigned + +Principal Engineer: +engineering.projects.read = organization +``` + +`assigned` is not magic. Each resource policy defines how assignment is resolved. + +### Engineering Project + +Assigned when: + +```text +engineering_project_members.user_id = ctx.userId +AND engineering_project_members.left_at IS NULL +``` + +or when the user is the active project manager, if project-manager assignment is modeled separately. + +### Engineering Task + +Assigned when: + +```text +engineering_tasks.assigned_to_user_id = ctx.userId +``` + +For tasks linked to a project, parent-project access may also be required. + +### Engineering Design + +Assigned when an active row exists in: + +```text +engineering_design_assignments +``` + +for the user and an allowed assignment role. + +### Engineering Inspection + +Assigned when: + +```text +engineering_inspections.inspector_user_id = ctx.userId +``` + +or an explicit inspection assignment exists if the model later supports multiple inspectors. + +### Derived Client Access + +An assigned professional may access a client only through a policy that derives access from authorized projects. + +Project assignment must not automatically grant access to every project belonging to that client. + +Future scopes may include: + +```text +owned +team +department +restricted +``` + +Do not add them before a real workflow requires them. + +## 21. Professional Credentials + +Professional identity and credentials are separate from RBAC. + +Use: + +```text +professional_profiles +professional_credentials +``` + +### Professional Profile + +One organization/user/profession relationship. + +Suggested fields: + +```text +id +organization_id +user_id +profession +title +status +created_at +updated_at +``` + +### Professional Credential + +One profile may hold many credentials. + +Suggested fields: + +```text +id +organization_id +professional_profile_id + +credential_type +credential_number +issuing_authority +jurisdiction +discipline + +status +valid_from +expires_at + +verified_at +verified_by_user_id + +created_at +updated_at +``` + +Examples: + +```text +professional engineering license in jurisdiction A +professional engineering license in jurisdiction B +specialty certification +medical license +controlled-substance prescribing registration where applicable +``` + +Credential policy evaluates the set of active credentials rather than one `primary_license_number`. + +High-risk actions such as design approval, record signing, or prescribing use authoritative or revocation-aware credential state. + +Prescribing remains jurisdiction/scope-of-practice policy, not a hard-coded profession test. + +## 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. + +--- + +## 21A. Deletion, Archival, Revocation, and Unlink Policy + +`DELETE` does not have one universal persistence meaning. + +Use four lifecycle behaviors. + +### Archive / Domain Inactivation + +For business records whose history matters: + +```text +engineering clients +engineering projects +legal matters +healthcare patients +documents where retention requires history +``` + +Typical fields: + +```text +status +archived_at +archived_by_user_id +``` + +Restore is permitted only when domain, retention, and organization policy allow it. + +### Revoke + +For access/security resources: + +```text +sessions +refresh tokens +API keys +membership invitations +portal grants +webhook credentials +``` + +Use: + +```text +revoked_at +revoked_by +revocation_reason +``` + +### Temporal Unlink + +For relationship records where the historical relationship matters: + +```text +project documents +project members +design assignments +portal document publications +``` + +Use: + +```text +unlinked_at +left_at +unassigned_at +revoked_at +``` + +rather than deleting historical evidence. + +### Hard Delete + +Reserved for genuinely disposable or never-committed data, such as: + +```text +expired pending upload artifacts +failed temporary staging objects +unreferenced draft configuration where audit/retention does not require history +``` + +Hard deletion of financial, professional, audit, signed clinical, or issued business records is forbidden unless an explicit retention/privacy policy defines the operation. + +Every resource specification must declare its lifecycle behavior. + +--- + +# Engineering Domain + +## 26. Engineering Tables + +Initial Engineering MVP tables: + +```text +engineering_clients +engineering_client_contacts + +engineering_projects +engineering_project_members +engineering_project_phases +engineering_sites +engineering_tasks + +engineering_designs +engineering_design_assignments +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews + +engineering_inspections +engineering_inspection_findings +engineering_inspection_followups + +engineering_specifications +engineering_specification_documents + +engineering_time_entries +``` + +Later Engineering extensions: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries + +engineering_change_requests +``` + +`engineering_change_requests` is not part of the initial schema until its lifecycle, relationships, and REST contract are specified. + +## 27. Engineering Clients + +Suggested core client fields: + +```text +id +organization_id +client_type +display_name +legal_name +status +created_at +updated_at +version +``` + +Do not permanently squeeze all contacts into one `email`, one `phone`, and one `contact_name`. + +Engineering customers commonly have multiple: + +```text +technical contacts +billing contacts +executive contacts +site contacts +contract contacts +``` + +Use: + +```text +engineering_client_contacts +``` + +Suggested contact fields: + +```text +id +organization_id +client_id + +name +title +department + +email +phone + +contact_type +is_primary + +created_at +updated_at +``` + +Client 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 +``` + +Contact REST: + +```http +GET /api/v1/engineering/clients/{clientId}/contacts +POST /api/v1/engineering/clients/{clientId}/contacts +PATCH /api/v1/engineering/clients/{clientId}/contacts/{contactId} +DELETE /api/v1/engineering/clients/{clientId}/contacts/{contactId} +``` + +Delete may be implemented as archival when contact history matters. + +Client restore is allowed only when organization policy and retention rules permit it. + +## 27A. Engineering Client Portal + +External clients are not internal organization members. + +Use shared authentication identities where practical, but create a separate authorization boundary. + +```text +User + │ + ├── Internal Membership + │ ↓ + │ Organization Staff Access + │ + └── Client Portal Account + ↓ + Engineering Client Contact + ↓ + Project Access Grants +``` + +Suggested tables: + +```text +engineering_client_portal_accounts +engineering_client_portal_project_grants +engineering_project_document_publications +engineering_client_review_requests +``` + +### Portal Account + +Suggested fields: + +```text +id +organization_id +user_id +engineering_client_contact_id + +status + +invited_by_user_id +invited_at +accepted_at + +revoked_at +revoked_by_user_id +``` + +Portal accounts are not placed in `memberships`. + +### Project Grant + +Suggested fields: + +```text +id +organization_id +portal_account_id +project_id + +access_profile + +granted_by_user_id +granted_at +expires_at +revoked_at +``` + +Initial access capabilities may include: + +```text +project.status.read +project.documents.read_published +project.comments.create +project.files.submit +client_review.respond +``` + +The access model may later normalize capabilities into a grant table if simple profiles become insufficient. + +### Separate Frontend + +Recommended: + +```text +apps/ +├── engineering-web/ +└── engineering-client-portal/ +``` + +The internal engineering frontend and external portal do not share authorization assumptions. + +### Client Acceptance Is Not Engineering Approval + +Never represent client acceptance with: + +```text +engineering.designs.approve +``` + +Professional engineering approval is reserved for qualified internal/authorized professionals. + +Client-facing review should use separate concepts such as: + +```text +engineering.client_reviews.request +engineering.client_reviews.respond +engineering.client_reviews.accept +engineering.client_reviews.request_changes +``` + +Example: + +```http +POST /api/v1/engineering/client-review-requests/{reviewId}/accept +POST /api/v1/engineering/client-review-requests/{reviewId}/request-changes +``` + +A client acceptance may be commercially meaningful without being a professional engineering approval. + +### Portal Security Rules + +1. portal access is deny-by-default +2. every portal request remains organization-scoped +3. portal users only access explicitly granted projects +4. project membership does not apply to portal users +5. internal RBAC roles do not automatically apply to portal users +6. portal account revocation is immediate +7. portal grants may expire +8. sensitive document access requires explicit publication +9. portal activity is audited according to organization policy +10. professional approval endpoints are never exposed through portal grants + +--- + +## 27B. External Document Publication + +A document being linked to an engineering project does **not** make it externally visible. + +Use: + +```text +engineering_project_document_publications +``` + +Suggested fields: + +```text +id +organization_id + +project_document_link_id + +audience_type +portal_account_id nullable +client_id nullable + +published_by_user_id +published_at + +expires_at +revoked_at +revoked_by_user_id +``` + +Possible audiences: + +```text +all_active_client_portal_accounts_for_project +specific_portal_account +specific_client_contact +``` + +External download checks: + +```text +authenticated portal user ++ +active portal account ++ +active project grant ++ +active document publication ++ +publication not expired/revoked ++ +document classification allows publication ++ +download permission +``` + +This prevents an internal project document from appearing in the client portal merely because it is linked to the project. + +## 28. Engineering Projects + +Suggested fields: + +```text +id +organization_id +client_id + +project_number +name +description +discipline + +status + +project_manager_user_id + +start_date +expected_completion_date +completed_date + +created_at +updated_at +version +``` + +`stage` is removed from the project row because project phases are the authoritative workflow decomposition. + +If the frontend needs a "current stage", derive it from the active/current project phase or maintain an explicitly documented `current_phase_id` pointer. + +Project `budget_minor` is also removed. + +Detailed project budgets belong to the dedicated budget model. + +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 reads: + +```http +GET /api/v1/engineering/projects/{projectId}/summary +GET /api/v1/engineering/projects/{projectId}/timeline +GET /api/v1/engineering/projects/{projectId}/budget +``` + +The budget endpoint reads from the budget module when that module exists. + +## 29. Engineering Project Members + +Suggested fields: + +```text +id +organization_id +project_id +user_id +project_role +joined_at +left_at +``` + +Initial project-role vocabulary: + +```text +project_manager +engineer +designer +reviewer +inspector +viewer +contractor +``` + +Project role describes participation in one project. + +It is not a substitute for RBAC permission. + +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} +``` + +`DELETE` means end participation by setting `left_at`, not erase historical participation. + +## 30. Engineering Project Phases + +Suggested fields: + +```text +id +organization_id +project_id +name +sequence +status +start_date +end_date +created_at +updated_at +version +``` + +Typical initial statuses: + +```text +planned +active +completed +cancelled +``` + +Example 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 +POST /api/v1/engineering/projects/{projectId}/phases/reorder +``` + +Reorder request: + +```json +{ + "projectVersion": 12, + "orderedPhaseIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b301", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b302" + ] +} +``` + +Reordering is transactional. + +Sequences remain unique within a project after commit. + +## 31. Engineering Sites + +Suggested fields: + +```text +id +organization_id +project_id +name +address +latitude +longitude +created_at +updated_at +``` + +REST: + +```http +GET /api/v1/engineering/sites +GET /api/v1/engineering/sites/{siteId} + +POST /api/v1/engineering/projects/{projectId}/sites +GET /api/v1/engineering/projects/{projectId}/sites + +PATCH /api/v1/engineering/sites/{siteId} +``` + +Global site listing is still tenant-scoped through `X-Organization-Id`. + +## 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 +``` + +Statuses: + +```text +todo +in_progress +completed +cancelled +``` + +Priorities: + +```text +low +medium +high +urgent +``` + +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 +``` + +## 32A. Engineering Batch Operations + +Batch operations are useful for repetitive engineering workflows, but they must not bypass per-resource authorization or domain rules. + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete + +POST /api/v1/engineering/time-entries/batch/submit +``` + +### Batch Execution Modes + +Every batch command explicitly defines one of: + +```text +atomic +partial +``` + +Atomic: + +```text +all resources succeed +or +entire operation fails +``` + +Partial: + +```text +each resource is evaluated independently +successful items commit +failed items return individual errors +``` + +Do not leave this behavior implicit. + +Example request: + +```json +{ + "taskIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83" + ], + "assigneeUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "mode": "partial" +} +``` + +Example response: + +```json +{ + "data": { + "succeeded": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82" + ], + "failed": [ + { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83", + "code": "RESOURCE_INVALID_STATE" + } + ] + } +} +``` + +### Authorization + +Each resource is evaluated for: + +```text +tenant +permission +scope +resource access +state validity +credential policy where applicable +``` + +Never authorize the first item and assume the remaining batch is equivalent. + +### Synchronous vs Asynchronous + +Small batches may execute synchronously. + +Large batches become jobs: + +```http +202 Accepted +``` + +with: + +```text +jobId +``` + +The synchronous/asynchronous threshold is configuration based on: + +```text +batch size +operation cost +database load +side effects +product tier +``` + +Financial or regulated batch actions require stricter idempotency and audit rules than ordinary task updates. + +--- + +## 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 +cancelled +withdrawn +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}/revise +POST /api/v1/engineering/designs/{designId}/cancel +POST /api/v1/engineering/designs/{designId}/withdraw +POST /api/v1/engineering/designs/{designId}/supersede + +POST /api/v1/engineering/designs/{designId}/assign +POST /api/v1/engineering/designs/{designId}/unassign + +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 +``` + +State machine: + +```text +draft + ├── submit-review ─────────────► under_review + └── cancel ────────────────────► cancelled + +under_review + ├── request-changes ───────────► changes_requested + ├── approve ───────────────────► approved + ├── reject ────────────────────► rejected + └── withdraw ──────────────────► withdrawn + +changes_requested + ├── submit-review ─────────────► under_review + └── withdraw ──────────────────► withdrawn + +rejected + └── revise ────────────────────► draft + +approved + └── supersede ─────────────────► superseded +``` + +Approval remains credential-aware, audited, and idempotent. + +Designs do not use generic archive/restore endpoints. Their professional lifecycle terminates through explicit state-machine outcomes such as `cancelled`, `withdrawn`, and `superseded`. Terminal designs remain queryable and auditable and are not hard-deleted through ordinary workflows. + +## 34. Design Versions and Reviews + +A design version is a logical professional revision. + +It may have multiple document files. + +Use: + +```text +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews +``` + +### Design Version + +```text +id +organization_id +design_id +version_number +created_by_user_id +created_at +``` + +Unique: + +```text +(organization_id, design_id, version_number) +``` + +### Design Version Documents + +```text +id +organization_id +design_version_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +Possible `document_role` values: + +```text +primary_drawing +calculation +supporting_document +specification +attachment +``` + +A design version therefore supports one or many documents without putting `document_id` directly on the version. + +### Design Review + +```text +id +organization_id +design_id +design_version_id +reviewer_user_id +status +comments +reviewed_at +created_at +``` + +Statuses: + +```text +pending +approved +changes_requested +rejected +``` + +All three tables are tenant-owned and carry direct `organization_id`. + +## 35. Engineering Inspections + +Inspection fields: + +```text +id +organization_id +project_id +site_id + +inspection_type +inspector_user_id + +status +outcome + +scheduled_at +started_at +performed_at +cancelled_at + +summary + +created_at +updated_at +version +``` + +Lifecycle: + +```text +draft +scheduled +in_progress +completed +cancelled +``` + +Outcome: + +```text +passed +passed_with_observations +followup_required +failed +``` + +`inspection_type` is an application/domain registry rather than a PostgreSQL enum. + +Initial common keys may include: + +```text +structural +mechanical +electrical +safety +final +``` + +Organizations/modules may add supported types through controlled configuration later. + +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 + +GET /api/v1/engineering/inspections/{inspectionId}/followups +POST /api/v1/engineering/inspections/{inspectionId}/followups +``` + +Inspection completion may create follow-up records. + +Lifecycle and outcome remain separate. + +## 36. Inspection Findings + +`engineering_inspection_findings`: + +```text +id +organization_id +inspection_id + +severity +description +status + +resolved_at +resolved_by_user_id + +created_at +updated_at +version +``` + +Severity: + +```text +observation +minor +major +critical +``` + +Status: + +```text +open +in_progress +resolved +accepted_risk +``` + +REST: + +```http +POST /api/v1/engineering/inspections/{inspectionId}/findings +PATCH /api/v1/engineering/inspection-findings/{findingId} +POST /api/v1/engineering/inspection-findings/{findingId}/resolve +``` + +`organization_id` is direct even though tenant ownership is also derivable through the inspection. + +### Follow-Up Resource + +Use: + +```text +engineering_inspection_followups +``` + +Fields: + +```text +id +organization_id +inspection_id + +followup_type + +linked_task_id nullable +linked_inspection_id nullable + +status + +created_by_user_id +created_at +completed_at +cancelled_at +``` + +`followup_type`: + +```text +corrective_task +followup_inspection +both +``` + +`status`: + +```text +open +in_progress +completed +cancelled +``` + +Tenant-safe foreign keys apply to the original inspection and any linked task/inspection. + +## 37. Engineering Specifications + +Use: + +```text +engineering_specifications +engineering_specification_documents +``` + +Suggested specification fields: + +```text +id +organization_id +project_id +specification_number +title +version +status +created_at +updated_at +``` + +Status values: + +```text +draft +active +superseded +archived +``` + +Specification document links: + +```text +id +organization_id +specification_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +A specification may therefore have one or many current or historical document links. `document_role` is an application registry with initial values such as `primary`, `attachment`, and `supporting_document`. Tenant-safe foreign keys apply to both the specification and shared document. + +--- + +## 38. Engineering Change Requests + +**Deferred from the initial Engineering schema.** + +Change requests are a valid future engineering capability, but v4.1 does not create the table until these are specified: + +```text +relationship to project +relationship to design/specification +request origin +impact analysis +cost/schedule effects +review workflow +approval authority +state machine +document links +REST commands +audit requirements +``` + +Future candidate: + +```text +engineering_change_requests +``` + +This belongs in the Engineering extension backlog rather than a half-defined initial migration. + +## 38A. Engineering Project Budgets + +A single `budget_minor` column is sufficient only for a very early project total. + +When budget management enters scope, introduce: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries +``` + +### Budget + +Suggested fields: + +```text +id +organization_id +project_id + +name +currency_code +status + +approved_by_user_id +approved_at + +created_at +updated_at +version +``` + +### Budget Item + +Suggested fields: + +```text +id +organization_id +budget_id + +category +description + +allocated_amount_minor + +created_at +updated_at +``` + +Do not casually store mutable: + +```text +spent_amount_minor +committed_amount_minor +``` + +as independent sources of truth if those values are derived from time entries, expenses, purchase commitments, or invoices. + +Prefer: + +```text +authoritative cost/commitment records + ↓ +derived budget projections +``` + +If denormalized totals are needed for performance, update them transactionally and reconcile them. + +Potential REST: + +```http +GET /api/v1/engineering/projects/{projectId}/budgets +POST /api/v1/engineering/projects/{projectId}/budgets +GET /api/v1/engineering/budgets/{budgetId} +PATCH /api/v1/engineering/budgets/{budgetId} + +POST /api/v1/engineering/budgets/{budgetId}/approve +GET /api/v1/engineering/budgets/{budgetId}/items +POST /api/v1/engineering/budgets/{budgetId}/items +``` + +Budget approval is an explicit command. + +--- + +## 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 + +phase_id nullable +task_id nullable +design_id nullable +inspection_id nullable + +created_at +updated_at +version +``` + +The project is always required. + +A time entry may also identify one primary work item. + +Database check: + +```text +at most one of: +phase_id +task_id +design_id +inspection_id +``` + +Each optional foreign key is tenant- and project-aware. For example: + +```text +(organization_id, project_id, task_id) +→ engineering_tasks(organization_id, project_id, id) +``` + +and similarly for phase, design, and inspection. Supporting unique constraints on `(organization_id, project_id, id)` are required on each target table. + +This is a database-enforced invariant, not only an application validation rule: whenever an optional work-item ID is present, that work item must belong to the same organization and `project_id` as the time entry. + +This preserves relational integrity instead of using an unconstrained polymorphic `reference_type/reference_id`. + +REST: + +```http +POST /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries/{timeEntryId} +PATCH /api/v1/engineering/time-entries/{timeEntryId} + +POST /api/v1/engineering/time-entries/batch/submit +``` + +Duration is integer minutes. + +## 40. Legal Tables + +Initial legal-domain tables: + +```text +legal_clients +legal_matters +legal_matter_members +legal_cases +legal_case_parties +legal_courts +legal_hearings +legal_deadlines +legal_time_entries +legal_retainers +legal_conflict_checks +legal_conflict_parties +legal_conflict_matches +legal_matter_documents +legal_case_documents +``` + +There is no separate `legal_documents` ownership table. + +Documents remain shared infrastructure: + +```text +documents +document_versions +``` + +Legal relationships use: + +```text +legal_matter_documents +legal_case_documents +``` + +`legal_matter_documents` fields: + +```text +id +organization_id +matter_id +document_id +linked_by_user_id +linked_at +unlinked_at +``` + +`legal_case_documents` fields: + +```text +id +organization_id +case_id +document_id +linked_by_user_id +linked_at +unlinked_at +``` + +Both tables use tenant-safe foreign keys to their Legal parent and the shared `documents` table. `unlinked_at` preserves link history without deleting the shared document. + +REST namespace: + +```text +/api/v1/legal +``` + +Legal remains a later vertical. + +## 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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cbd", + "status": "pending_review", + "potentialConflicts": [ + { + "type": "possible_direct_adversity", + "partyName": "Acme Corporation", + "existingMatterId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2ccd", + "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 + +Healthcare remains a later vertical. + +Minimum planned tables: + +```text +healthcare_patients +healthcare_patient_contacts +healthcare_patient_addresses + +healthcare_practitioners +healthcare_locations +healthcare_rooms + +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 +``` + +All tenant-owned tables carry direct `organization_id`. + +Detailed healthcare interoperability, terminology, and jurisdiction rules require healthcare-specific design before implementation. + +## 46. Healthcare Patients + +Core patient: + +```text +id +organization_id +patient_number + +first_name +middle_name +last_name +date_of_birth + +administrative_gender nullable +sex_at_birth nullable +gender_identity nullable + +status + +created_at +updated_at +version +``` + +Exact demographic terminology and allowed values are finalized in the healthcare-domain specification. + +Do not make every field mandatory merely because it exists. + +### Patient Contact + +`healthcare_patient_contacts`: + +```text +id +organization_id +patient_id + +contact_type +value +is_primary + +created_at +updated_at +``` + +### Patient Address + +`healthcare_patient_addresses`: + +```text +id +organization_id +patient_id + +address_type +line_1 +line_2 +city +region +postal_code +country_code + +is_primary + +created_at +updated_at +``` + +Sensitive subresources remain permission-controlled. + +## 47. Healthcare Practitioners + +Suggested fields: + +```text +id +organization_id +user_id +professional_profile_id + +specialty +status + +created_at +updated_at +``` + +Professional licenses are not duplicated here. + +Multiple licenses/credentials live in: + +```text +professional_credentials +``` + +## 48. Healthcare Appointments + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id + +location_id nullable +room_id nullable + +appointment_type + +starts_at +ends_at + +status +reason + +created_at +updated_at +version +``` + +Planned supporting tables: + +`healthcare_locations`: + +```text +id +organization_id +name +address fields +timezone +status +``` + +`healthcare_rooms`: + +```text +id +organization_id +location_id +name +status +``` + +Exact scheduling rules are deferred to the healthcare vertical. + +## 49. Healthcare Encounters + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id +appointment_id nullable + +encounter_type + +reason_for_visit nullable + +started_at +ended_at + +status + +created_at +updated_at +version +``` + +Do not add a generic free-form `notes` field as a substitute for clinical records. + +Clinical narrative belongs in governed clinical-record structures. + +## 50. Clinical Records + +Use: + +```text +healthcare_clinical_records +healthcare_clinical_record_versions +healthcare_clinical_record_amendments +``` + +### Clinical Record + +```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 +``` + +### Clinical Record Version + +```text +id +organization_id +record_id +version_number + +content_reference or governed content payload +created_by_practitioner_id +created_at +``` + +### Clinical Record Amendment + +```text +id +organization_id +record_id +source_version_id +result_version_id + +amended_by_practitioner_id + +amendment_type +amendment_reason + +created_at +``` + +Possible amendment types: + +```text +correction +addendum +clarification +``` + +Signed/finalized history is preserved. + +REST: + +```http +POST /api/v1/healthcare/encounters/{encounterId}/clinical-records + +GET /api/v1/healthcare/clinical-records/{recordId} +PATCH /api/v1/healthcare/clinical-records/{recordId} +# Draft/editable only. + +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 +``` + +## 51. Documents + +Shared document infrastructure: + +```text +documents +document_versions +document_categories +retention_policies +``` + +Binary data lives in S3-compatible object storage. + +### Document + +```text +id +organization_id +name +category_id +classification +retention_policy_id +current_version_id +created_by_user_id +created_at +updated_at +``` + +Classification: + +```text +public +internal +confidential +restricted +regulated +``` + +### Document Version + +```text +id +organization_id +document_id +version_number +storage_key +mime_type +size_bytes +content_hash +hash_algorithm +uploaded_by_user_id +created_at +``` + +Checksum is version-level authoritative data. + +### Document Category + +```text +id +organization_id +profession nullable +name +parent_category_id +created_at +``` + +Uniqueness requirement: + +```text +shared category: + unique organization_id + name where profession IS NULL + +profession category: + unique organization_id + profession + name where profession IS NOT NULL +``` + +Implementation options: + +```text +PostgreSQL null-aware unique constraint when supported +or +two partial unique indexes +``` + +The partial-index fallback does not depend on selecting PostgreSQL 18. + +### Retention Policy + +```text +id +organization_id + +name +profession nullable +classification nullable + +retention_period_days nullable +action + +created_at +updated_at +``` + +Initial actions: + +```text +review +archive +delete_when_legally_permitted +retain_indefinitely +``` + +`retention_period_days` has one meaning only: + +```text +action = retain_indefinitely + → retention_period_days MUST be null + +all other actions + → retention_period_days MUST be a positive integer +``` + +Null does not mean inherit, unconfigured, or unknown. Policy inheritance or an unconfigured state must be represented outside a persisted retention-policy row and specified separately before implementation. + +A retention policy describes configured behavior. + +Actual deletion remains subject to domain, contractual, privacy, and jurisdiction requirements. + +### Metadata + +JSONB is allowed only for genuinely extensible, non-authoritative metadata. + +Do not put authorization, lifecycle, retention state, or ownership into arbitrary JSON. + +## 52. Document Upload Flow + +### Standard Upload + +Request: + +```http +POST /api/v1/documents/upload-url +``` + +```json +{ + "name": "structural-calculations.pdf", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/pdf", + "sizeBytes": 2457600, + "contentHash": "sha256:..." +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d01", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "uploadUrl": "https://object-storage.example/...", + "expiresAt": "2026-08-26T13:00:00Z" + } +} +``` + +The frontend uploads directly to object storage. + +Finalize: + +```http +POST /api/v1/documents/{documentId}/complete-upload +``` + +```json +{ + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "contentHash": "sha256:..." +} +``` + +### Multipart Initialization + +```http +POST /api/v1/documents/multipart-uploads +``` + +Request: + +```json +{ + "name": "building-model.bin", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/octet-stream", + "sizeBytes": 2147483648, + "contentHash": null +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d10", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d11", + "uploadId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d12", + "recommendedPartSizeBytes": 67108864, + "expiresAt": "2026-08-27T12:00:00Z" + } +} +``` + +### Request Signed Part URLs + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/parts +``` + +```json +{ + "partNumbers": [1, 2, 3, 4] +} +``` + +Response: + +```json +{ + "data": [ + { + "partNumber": 1, + "uploadUrl": "https://object-storage.example/..." + } + ] +} +``` + +Binary parts go directly to object storage. + +### Complete Multipart Upload + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/complete +``` + +```json +{ + "parts": [ + { + "partNumber": 1, + "etag": "..." + } + ], + "contentHash": "sha256:..." +} +``` + +Abort: + +```http +DELETE /api/v1/documents/{documentId}/multipart-uploads/{uploadId} +``` + +Upload state: + +```text +initiated +uploading +completing +completed +aborted +expired +``` + +Workers clean up abandoned multipart uploads. + +Upload policy validates: + +```text +declared MIME +extension +content signature +size +checksum +quota +classification +malware status +``` + +## 53. Profession-Specific Document Links + +Use explicit relationship tables. + +Engineering: + +```text +engineering_project_documents +engineering_design_version_documents +engineering_inspection_documents +``` + +Legal: + +```text +legal_matter_documents +legal_case_documents +``` + +Healthcare: + +```text +healthcare_patient_documents +healthcare_encounter_documents +``` + +`engineering_design_version_documents` is authoritative for files belonging to a specific design revision. + +Do not also maintain an ambiguous `engineering_design_documents` relation to the unversioned design unless a later requirement introduces a separate clearly named supporting-document relationship. + +### Project Documents + +```text +engineering_project_documents +├── id +├── organization_id +├── project_id +├── document_id +├── category +├── linked_by_user_id +├── linked_at +└── unlinked_at +``` + +REST: + +```http +GET /api/v1/engineering/projects/{projectId}/documents +POST /api/v1/engineering/projects/{projectId}/documents +DELETE /api/v1/engineering/project-documents/{documentLinkId} +``` + +`DELETE` temporally unlinks the relation when history must be preserved. + +## 54. Billing + +Shared financial core: + +```text +invoices +invoice_items +payments +``` + +### Invoice + +Core fields include: + +```text +id +organization_id +client/reference context +invoice_number +status +currency_code +subtotal_minor +tax_total_minor +total_minor +issued_at +due_at +paid_at +created_at +updated_at +version +``` + +### Invoice Item + +```text +id +organization_id +invoice_id + +description + +quantity +unit_price_minor +total_amount_minor + +position + +created_at +updated_at +``` + +`quantity` uses fixed-precision numeric semantics, not floating point. + +Money uses integer minor units. + +The invoice determines currency; invoice items do not independently choose a different currency unless multi-currency invoicing is intentionally designed later. + +### Profession-Specific Source Links + +The shared billing module does not use unconstrained: + +```text +reference_type +reference_id +``` + +to profession-owned tables. + +Profession modules create explicit links, for example: + +```text +engineering_invoice_item_time_entries +├── organization_id +├── invoice_item_id +└── time_entry_id +``` + +This preserves the rule that shared core does not depend on profession-table internals. + +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 + +Use: + +```text +audit_events +``` + +Suggested fields: + +```text +id +organization_id + +actor_type +actor_user_id nullable +actor_service_account_id nullable + +action + +resource_type +resource_id + +request_id +correlation_id + +ip_address +user_agent + +metadata + +occurred_at +``` + +Audit records are append-only from normal application workflows. + +### Mandatory Examples + +Engineering: + +```text +engineering.projects.create +engineering.projects.close +engineering.designs.approve +engineering.inspections.complete +``` + +Legal: + +```text +legal.matters.create +legal.matters.close +legal.conflicts.approve +``` + +Healthcare: + +```text +healthcare.records.read +healthcare.records.write +healthcare.records.sign +healthcare.records.amend +``` + +### Privacy / Erasure Handling + +Append-only audit does not mean "store unlimited personal data forever." + +Audit metadata must be minimized at write time. + +Where privacy, contractual, or retention obligations require removal of personally identifying material, use a governed privacy process such as: + +```text +pseudonymize actor references +null/remove nonessential PII fields +replace identifiers with irreversible privacy references where appropriate +retain the security/business event itself when permitted/required +``` + +The exact action depends on jurisdiction and retention policy and must be reviewed before healthcare/legal production. + +Do not place passwords, tokens, full clinical content, secret keys, or unnecessary payment data in audit metadata. + +REST: + +```http +GET /api/v1/audit-events +``` + +No public mutation endpoints. + +## 57. Domain Events and Transactional Outbox + +Use: + +```text +outbox_events +``` + +Fields: + +```text +id +organization_id nullable for truly global events + +event_type +aggregate_type +aggregate_id + +payload + +request_id nullable +correlation_id +causation_id nullable + +occurred_at +available_at +processed_at + +attempt_count +last_error +dead_lettered_at +``` + +`correlation_id` groups one logical workflow across requests/jobs/events. + +`causation_id` identifies the event/command that directly caused this event when applicable. + +Transaction: + +```text +BEGIN +business change +audit event +outbox event +COMMIT +``` + +Delivery semantics are at-least-once. + +Worker claim uses row locking such as: + +```sql +SELECT id +FROM outbox_events +WHERE processed_at IS NULL + AND dead_lettered_at IS NULL + AND available_at <= now() +ORDER BY occurred_at +FOR UPDATE SKIP LOCKED +LIMIT 100; +``` + +Every external side-effect consumer must be idempotent. + +`FOR UPDATE SKIP LOCKED` prevents simultaneous claiming; it does not prevent duplicate side effects after a worker crash. + +## 57A. Webhooks and External Integrations + +Shared tables: + +```text +webhooks +webhook_event_subscriptions +webhook_deliveries +``` + +### Webhook + +```text +id +organization_id +url +status +secret_ciphertext or signing_key_reference +created_by_user_id +created_at +updated_at +``` + +### Subscription + +```text +id +organization_id +webhook_id +event_type +created_at +``` + +Unique: + +```text +(organization_id, webhook_id, event_type) +``` + +Only registered externally publishable event types may be subscribed. + +### Delivery + +```text +id +organization_id +webhook_id +event_id + +attempt_number +request_timestamp +response_status +response_summary + +delivered_at +failed_at +next_attempt_at +``` + +`event_id` references `outbox_events.id`. Because webhook deliveries are tenant-owned, only publishable outbox events with the same non-null `organization_id` may be delivered: + +```text +(organization_id, event_id) +→ outbox_events(organization_id, id) +``` + +The webhook publisher allowlists externally publishable `event_type` values before creating delivery records. The stable outbox event ID is also the consumer deduplication key. + +Configuration REST: + +```http +GET /api/v1/webhooks +POST /api/v1/webhooks +GET /api/v1/webhooks/{webhookId} +PATCH /api/v1/webhooks/{webhookId} +DELETE /api/v1/webhooks/{webhookId} + +POST /api/v1/webhooks/{webhookId}/test +POST /api/v1/webhooks/{webhookId}/rotate-secret +``` + +Delivery REST: + +```http +GET /api/v1/webhook-deliveries +GET /api/v1/webhook-deliveries/{deliveryId} +POST /api/v1/webhook-deliveries/{deliveryId}/retry +``` + +If HMAC signing is used, signing material is encrypted/recoverable with managed key protection. + +A one-way secret hash is insufficient for outbound HMAC signing. + +Webhook consumers deduplicate using stable event IDs. + +## 58. Background Jobs + +Workers handle: + +```text +notifications +reports/PDFs +file scanning +document processing +imports +exports +bulk operations +webhooks +search indexing +large data operations +``` + +Use shared tenant-owned: + +```text +jobs +``` + +Fields: + +```text +id +organization_id +requested_by_user_id + +job_type +status + +input_reference +result_reference +progress_percent + +created_at +started_at +completed_at +failed_at + +error_code +error_summary +``` + +`input_reference` and `result_reference` are nullable typed JSONB reference envelopes, not arbitrary blobs or public URLs. Their schema is registered per `job_type`. + +Allowed reference kinds initially include: + +```text +document_version +object_storage_key +query_snapshot +job +``` + +Object-storage references contain internal storage keys; APIs generate time-limited signed URLs when access is authorized. Resource IDs inside an envelope are validated for tenant ownership when the job is created. Large inputs and outputs live in documents or object storage rather than inside the job row. + +States: + +```text +queued +running +completed +failed +cancelled +``` + +REST: + +```http +GET /api/v1/jobs/{jobId} +GET /api/v1/jobs/{jobId}/result +POST /api/v1/jobs/{jobId}/cancel +``` + +These endpoints are tenant-scoped through the standard: + +```http +X-Organization-Id +``` + +They do not need `/organizations/{id}/jobs` because the platform already chose header-based tenant context. + +Large import/export operations return: + +```http +202 Accepted +``` + +with a job ID. + +## 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. + +Defaults: + +```text +default limit = 25 +maximum limit = 100 +offset pagination = not supported +``` + +Example: + +```http +GET /api/v1/engineering/projects?limit=25 +``` + +Response: + +```json +{ + "data": [], + "meta": { + "pagination": { + "nextCursor": null, + "hasMore": false + } + } +} +``` + +Rules: + +```text +cursor is opaque +sort order must be deterministic +cursor encodes/represents the selected sort position +unsupported limits return validation errors rather than silent huge responses +``` + +## 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=0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d +``` + +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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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/reuse detection +server-side session revocation + +rate limiting +anti-automation controls + +RBAC +resource policies +credential-aware authorization +tenant isolation + +input validation +SQL injection protection + +signed object-storage URLs +file-content validation +malware scanning + +audit trails +secret management +encryption at rest + +dependency/image scanning + +request/correlation IDs +backup and restore testing +``` + +### Web Security / CORS + +ADR-009 defines environment-specific web security. + +Baseline requirements: + +```text +explicit CORS allowlist +no wildcard credentialed CORS +allowed methods/headers documented +preflight behavior tested +HSTS at the edge for production HTTPS +X-Content-Type-Options: nosniff +secure cookie attributes when cookies are used +CSP on browser frontends +frame-ancestor/clickjacking policy on frontends +referrer policy appropriate to the frontend +``` + +Security headers belong at the appropriate application/CDN/gateway layer. + +### Rate Limiting + +Policies are endpoint-specific and configurable. + +Return: + +```http +429 Too Many Requests +Retry-After: ... +``` + +### Secrets + +Production secrets live outside source control, preferably in managed secret/key systems. + +JWT signing keys support rotation. + +## 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 +``` + +### Core Metrics + +API: + +```text +api_requests_total +api_errors_total +api_request_duration_seconds +``` + +Authentication: + +```text +auth_login_attempts_total +auth_token_refresh_total +auth_refresh_reuse_detections_total +auth_sessions_revoked_total +``` + +Authorization/security: + +```text +cross_tenant_access_attempts_total +tenant_isolation_invariant_failures_total +authorization_denials_total +credential_policy_denials_total +rate_limit_events_total +``` + +Important distinction: + +```text +cross_tenant_access_attempt += +request attempted another tenant's resource +``` + +This may be a stale link, mistake, or attack. + +```text +tenant_isolation_invariant_failure += +our system nearly or actually created/returned cross-tenant data +``` + +That is a high-severity internal correctness/security incident. + +Outbox/jobs/webhooks: + +```text +outbox_events_pending +outbox_events_failed_total +outbox_processing_duration_seconds + +jobs_queued +jobs_failed_total +job_duration_seconds + +webhook_delivery_attempts_total +webhook_delivery_failures_total +webhook_delivery_latency_seconds +``` + +Database: + +```text +db_pool_active +db_pool_waiting +db_query_duration_seconds +db_transaction_duration_seconds +``` + +Business metrics may include: + +```text +engineering_projects_created_total +engineering_designs_approved_total +engineering_inspections_completed_total +invoices_issued_total +``` + +Avoid patient-specific or sensitive identifiers in metric labels. + +### Alerts + +Examples: + +```text +refresh token reuse detected +tenant isolation invariant failure +outbox backlog exceeds SLO +webhook failure spike +database pool saturation +error-rate spike +latency regression +backup failure +malware scanner unavailable +``` + +Thresholds are calibrated from real environments rather than copied from a review document. + +### SLOs + +Define by endpoint class. + +Interactive CRUD, reports, file orchestration, and background jobs should not share one arbitrary latency target. + +## 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 +``` + +### Property-Based Tests + +Use property-based testing for high-value domain state machines. + +Candidates: + +```text +engineering design lifecycle +engineering inspection lifecycle +invoice lifecycle +payment state transitions +membership/role invariants +``` + +Correct properties: + +```text +every successful transition ends in a valid state + +every forbidden transition is rejected + +terminal states reject prohibited actions + +required invariants survive every valid transition + +transition sequences never bypass required approval/credential rules +``` + +Do not assert that every random state/action pair succeeds. Many are supposed to fail. + +### Integration Tests + +Test: + +```text +repositories +tenant-aware foreign keys +PostgreSQL constraints +transactions +outbox persistence +idempotency persistence +cache invalidation +job persistence +webhook delivery persistence +``` + +### API Tests + +Every important endpoint covers: + +```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 creation +outbox creation +``` + +### Outbox Reliability / Chaos Tests + +Test: + +```text +worker crash before side effect +worker crash after side effect but before marking processed +two workers competing for same row +temporary dependency outage +retry/backoff behavior +dead-letter behavior +consumer idempotency +lost worker wake-up +replay +``` + +The dangerous scenario is: + +```text +external side effect succeeds +worker dies +event retries +``` + +Tests must prove the consumer does not create an unacceptable duplicate. + +### Tenant Security Tests + +Test both: + +```text +external cross-tenant access attempts +``` + +and: + +```text +internal cross-tenant data invariant failures +``` + +These are different classes of failure. + +### Performance Tests + +Create realistic profiles: + +```text +interactive reads +interactive writes +search +dashboard read models +reporting +file upload orchestration +outbox processing +webhook bursts +notification bursts +``` + +Measure: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +``` + +Set production SLO gates only after a realistic baseline exists. + +### Coverage + +Track code coverage. + +Do not treat a single percentage such as `90%` as proof of quality. + +Critical-path expectations are stronger: + +```text +all tenant-isolation paths tested +all financial commands tested +all regulated commands tested +all state transitions tested +all critical authorization policies tested +``` + +## 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 +session/token model +idempotency strategy +error taxonomy +OpenAPI skeleton +engineering state machines +migration conventions +threat model +initial ADRs +risk register +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +auth +sessions +refresh-token families +token rotation/revocation + +users +organizations +organization professions + +membership invitations +memberships +roles +permissions +authorization + +audit +outbox + +request context +idempotency +rate limiting +observability +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering clients +engineering client contacts +client archive/restore +``` + +### Phase 3: Engineering Projects + +Build: + +```text +projects +project members +project phases +activation/close/archive +``` + +### Phase 4: Work and Site Management + +Build: + +```text +tasks +task batch operations +sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +versions +categories +classification +retention references +signed uploads +multipart uploads +content verification +malware scanning +engineering document links +``` + +### Phase 6: Engineering Designs + +Build: + +```text +designs +assignments +versions +reviews +cancel/withdraw semantics +credential-aware approval +audit +outbox +idempotency +``` + +### Phase 7: Engineering Inspections + +Build: + +```text +inspection lifecycle +inspection outcome +findings +corrective work +follow-up inspections +attachments +audit +outbox +idempotency +``` + +### Phase 8: Time, Budgets, and Billing + +Build: + +```text +time entries +batch timesheet submission +project budgets when required +invoices +payments +financial idempotency +reconciliation +``` + +### Phase 9: Notifications, Jobs, and Webhooks + +Build: + +```text +notifications +email +async jobs +imports/exports +webhooks +delivery/retry +dead-letter handling +``` + +### Phase 10: Reporting and Search + +Build: + +```text +project status +overdue work +inspection status +billable time +revenue +outstanding invoices +dashboard read models +``` + +### Phase 11: Engineering Client Portal + +Build: + +```text +portal account invitations +external project grants +published project documents +client review/acceptance workflow +portal audit +portal-specific frontend +``` + +Do not expose professional approval actions to client portal accounts. + +### Phase 12: Legal Vertical + +Validate shared core against: + +```text +matters +cases +conflicts +deadlines +retainers +restricted access / ethical walls +``` + +### Phase 13: Healthcare Readiness and Vertical + +Before implementation: + +```text +healthcare threat model +privacy review +jurisdiction analysis +scope-of-practice policy +record signing/amendment model +retention model +audit requirements +``` + +### Estimation Rule + +These are dependency-ordered milestones. + +They are not calendar promises. + +Calendar estimates require: + +```text +team size +frontend/UX scope +cloud decisions +third-party providers +security requirements +QA capacity +domain-expert availability +``` + +## 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 uses UUIDv7. + +Supported implementation choices: + +```text +PostgreSQL 18+: + use native uuidv7() if database-generated identifiers are desired + +Earlier PostgreSQL: + generate UUIDv7 in the application or use a controlled extension +``` + +Database columns remain PostgreSQL `UUID`. + +The rule is consistency, not ideological loyalty to one generation layer. + +Do not silently fall back to UUIDv4 while documenting UUIDv7. + +### Production Migration Rules + +Use expand/contract: + +```text +1. add backward-compatible schema +2. deploy code supporting old + new schema +3. backfill/migrate +4. switch reads/writes +5. observe +6. remove obsolete schema later +``` + +For destructive changes: + +```text +backup/restore plan +compatibility window +production-like dry run +explicit approval +post-migration verification +``` + +Do not assume a destructive database migration can always be reversed by a simple down migration. + +Never use automatic ORM schema synchronization in production. + +## 91A. Architecture Decision Records + +v4 stops treating technology suggestions as automatically settled architecture. + +Create ADRs before implementation locks in: + +```text +ADR-001 Backend Framework +ADR-002 SQL / ORM / Query Layer +ADR-003 Queue Implementation +ADR-004 PostgreSQL Minimum Version +ADR-005 Error Format / RFC 9457 Compatibility +ADR-006 Rate-Limit Header Convention +ADR-007 Webhook Signing Strategy +ADR-008 Object Storage Provider / Multipart Strategy +ADR-009 Web Security / CORS / Browser Headers +ADR-010 Machine Authentication / API Key Policy +``` + +Each ADR should include: + +```text +context +decision +alternatives considered +tradeoffs +security impact +operational impact +migration/exit path +date +status +``` + +The architecture currently fixes capabilities and boundaries. + +It does not require a framework merely because a review document described it positively. + +--- + +## 92. Technology Recommendation + +The following are preferred candidates, not all final decisions. + +### Fixed Platform Choices + +```text +API style: REST +Contract: OpenAPI 3.1 +Primary language: TypeScript +Primary database: PostgreSQL +Architecture: Modular Monolith +Observability standard: OpenTelemetry +Object storage model: S3-compatible +Container model: Docker/OCI +``` + +### ADR-Gated Choices + +Backend framework candidates: + +```text +NestJS +Fastify-centered custom application structure +``` + +SQL / persistence candidates: + +```text +Drizzle +Kysely +Prisma +direct SQL for specialized queries +``` + +Queue candidates: + +```text +BullMQ / Redis +managed cloud queue +``` + +PostgreSQL baseline: + +```text +PostgreSQL 18+ +``` + +is attractive because of native UUIDv7 and current capabilities, but the minimum supported version must be confirmed against: + +```text +hosting provider availability +operations policy +extension requirements +upgrade policy +support lifecycle +``` + +Do not claim one ORM is categorically "faster" or "better" without workload-specific evidence. + +The selected stack should preserve: + +```text +transaction control +explicit SQL visibility +tenant-safe query design +migration control +observability +testability +``` + +## 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 API contract. +4. GraphQL is not part of v1. +5. Start as one modular monolith backend. +6. Each profession has its own frontend. +7. Each profession owns its domain tables and state machines. +8. Shared modules provide infrastructure, not forced domain abstractions. +9. Public serialized IDs are raw UUIDv7. +10. Database ID columns use PostgreSQL UUID. +11. Human-readable business references are separate from resource IDs. +12. Every tenant-owned row carries direct `organization_id`. +13. Tenant-scoped requests require explicit `X-Organization-Id`. +14. Tenant boundaries are enforced in queries and database constraints. +15. Cross-tenant resources appear nonexistent. +16. API JSON/query parameter names use camelCase; DB identifiers use snake_case. +17. Authorization is server-side and deny-by-default. +18. `assigned` scope is defined per resource policy, never inferred generically. +19. Roles and professional credentials are separate. +20. A professional profile may own multiple credentials. +21. Sessions and refresh tokens are separate resources. +22. Refresh tokens rotate within families and support reuse detection. +23. Machine identities use service accounts/API keys, not fake human memberships. +24. Important domain transitions use explicit REST command endpoints. +25. High-risk commands use durable idempotency. +26. Batch custom actions use `/{collection}/batch/{action}`. +27. Every batch defines atomic or partial semantics. +28. Every batch item receives independent authorization/domain validation. +29. Large batches become asynchronous jobs. +30. Project phases are authoritative; duplicated project `stage` is not stored. +31. Project budgets use the dedicated budget model; project `budget_minor` is not authoritative. +32. Engineering time entries may attribute time to one explicit primary work item using tenant- and project-consistent composite foreign keys. +33. Design versions and engineering specifications use explicit document-link tables with one-to-many cardinality. +34. All design/review/version/finding/follow-up subresources carry `organization_id`. +35. Inspection lifecycle and inspection outcome are separate. +36. Inspection follow-ups are explicit resources. +37. Engineering change requests remain deferred until fully specified. +38. Shared documents own document records; profession modules own link tables. +39. Legal does not duplicate shared document ownership. +40. Large files use object-storage multipart uploads. +41. Application servers do not proxy multi-gigabyte chunks. +42. Document checksums belong to document versions. +43. Document classification is multi-level. +44. Document retention is explicit policy. +45. Document category uniqueness must work for nullable profession values on the selected PostgreSQL version. +46. Project document linkage does not imply client-portal publication. +47. External publication requires explicit publication records. +48. Client portal accounts are not internal memberships. +49. Client acceptance is not professional engineering approval. +50. Domain events use a transactional outbox. +51. Outbox delivery is at-least-once. +52. Outbox events carry correlation/causation identifiers. +53. External side-effect consumers are idempotent. +54. Webhook subscriptions and deliveries are tenant-owned. +55. HMAC signing secrets are securely recoverable/encrypted, not only hashed. +56. Jobs are tenant-scoped by the standard organization header. +57. PostgreSQL is the authoritative transactional datastore. +58. Redis is acceleration/coordination, not critical source of truth. +59. Search starts with PostgreSQL. +60. Collections use cursor pagination, default 25 and max 100. +61. Important mutable resources use optimistic concurrency. +62. Database entities are not serialized directly. +63. Errors use stable codes. +64. `429` responses use `Retry-After`; exact quota headers are an API decision. +65. Business records use explicit archive/revoke/unlink/hard-delete lifecycle policies. +66. Financial/professional/audit records are not casually hard-deleted. +67. Audit metadata is minimized and supports governed privacy transformation when required. +68. Important/regulated actions are audited. +69. Signed clinical records use sign/amend/version workflows. +70. Prescribing authority remains jurisdiction/scope-of-practice policy. +71. Production migrations use expand/contract. +72. Destructive changes are not assumed trivially reversible. +73. Secrets remain outside source control. +74. CORS and browser security policy are explicit ADR/configuration. +75. Rate limits are calibrated by evidence. +76. CI validates types, tests, OpenAPI, migrations, and security checks. +77. Property-based tests cover high-value state machines. +78. Outbox/job/webhook reliability is tested under failure/concurrency. +79. Critical-path tests matter more than vanity coverage percentages. +80. Framework/ORM/queue/PostgreSQL-minimum choices require ADRs. +81. Engineering is the first vertical. +82. Client portal follows internal Engineering MVP foundations. +83. Legal follows after Engineering validates shared assumptions. +84. Healthcare requires dedicated privacy/security/domain design before implementation. +85. Architecture documentation never equates "designed for" with "certified/compliant". + +## 95. Required Design Artifacts + +Maintain: + +```text +01_PROJECT_ARCHITECTURE.md +02_DATABASE_CONVENTIONS.md +03_AUTHORIZATION_MODEL.md +04_AUTH_SESSION_MODEL.md + +05_ENGINEERING_DOMAIN.md +06_ENGINEERING_DATABASE_SCHEMA.md +07_ENGINEERING_STATE_MACHINES.md + +08_API_CONVENTIONS.md +09_ENGINEERING_API_SPEC.md +10_OPENAPI.yaml + +11_FRONTEND_ARCHITECTURE.md +12_CLIENT_PORTAL_SECURITY_MODEL.md + +13_DOCUMENT_SECURITY_MODEL.md +14_LARGE_FILE_UPLOAD_MODEL.md + +15_WEBHOOK_INTEGRATION_MODEL.md +16_ASYNC_JOB_MODEL.md + +17_SECURITY_MODEL.md +18_DEPLOYMENT_ARCHITECTURE.md +19_OBSERVABILITY_MODEL.md +20_TESTING_STRATEGY.md + +21_ARCHITECTURE_DECISION_RECORDS/ +22_RISK_REGISTER.md +23_MVP_BACKLOG.md +``` + +Important ADRs: + +```text +backend framework +persistence/query layer +queue implementation +PostgreSQL minimum version +error format +rate-limit headers +webhook signing +object-storage provider +``` + +## 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 need efficient tenant scoping. + +Baseline: + +```text +(organization_id, id) +``` + +Common list access often benefits from: + +```text +(organization_id, created_at) +``` + +Query-specific examples: + +```text +(organization_id, status) +(organization_id, client_id) +(organization_id, project_id) +(organization_id, assigned_to_user_id) +``` + +### Rules + +1. every index corresponds to a known query, ordering, or constraint +2. column order follows real predicates +3. validate with `EXPLAIN (ANALYZE, BUFFERS)` +4. include production-like cardinality in testing +5. measure write amplification +6. do not index every field +7. introduce trigram/full-text indexes only for actual search requirements + +Potential later tools: + +```text +covering indexes +materialized views +read replicas +table partitioning +external search +``` + +These are evidence-driven scaling mechanisms, not baseline dependencies. + +### Document Category Uniqueness + +If a nullable field such as profession participates in uniqueness: + +```text +organization_id +profession nullable +name +``` + +do not assume plain uniqueness treats NULL as one shared value. + +Use PostgreSQL-supported null-aware uniqueness or partial unique indexes according to the selected PostgreSQL version. + +--- + +## 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. + + +### Feature Flags + +Feature flags used for deployment safety are operational configuration, not automatically a business database table. + +Initial implementation may use: + +```text +environment/config-service flags +``` + +for global rollout and kill switches. + +If per-organization feature rollout is later required, introduce an explicit tenant-owned model such as: + +```text +organization_feature_flags +``` + +through an ADR/migration. + +Do not overload `organization_professions` with unrelated product experiments. + + +### 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. + +--- + +## 97D. Provisional Performance Objectives + +Performance numbers in architecture are starting hypotheses, not guarantees. + +Initial engineering objectives may begin with: + +```text +Interactive read: + target p95 <= 500 ms + +Interactive mutation: + target p95 <= 750 ms + +Simple list/search: + target p95 <= 800 ms + +Upload authorization: + target p95 <= 300 ms + +Background outbox pickup: + target <= 5 seconds under normal operating conditions +``` + +These are revised after realistic testing. + +Track: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +outbox lag +``` + +Different endpoint classes receive different SLOs. + +Do not use file-transfer completion time as an API SLO when bytes travel directly between client and object storage. + +--- + +## 97E. Risk Register + +Maintain a living risk register. + +Suggested structure: + +| Risk | Impact | Mitigation | Owner | Phase | Status | +|---|---|---|---|---|---| +| Cross-tenant data exposure | Critical | Tenant-aware FKs, scoped queries, security tests | Backend/Security | P0 | Open | +| Non-idempotent outbox side effect | Critical | Consumer dedupe, provider idempotency, chaos tests | Backend | P0 | Open | +| Migration failure | High | Expand/contract, dry runs, backups | Backend/Platform | P0 | Open | +| Engineering workflow mismatch | High | Domain expert validation | Product/Engineering SME | MVP | Open | +| Portal authorization leak | Critical | Separate external access model, publication grants | Backend/Security | Portal | Open | +| Webhook delivery instability | Medium | Retry, dead-letter, replay, metrics | Backend | Integrations | Open | +| Large upload abandonment | Medium | Multipart expiry and cleanup | Backend/Platform | Documents | Open | +| Documentation drift | Medium | OpenAPI validation, ADRs, CI | Engineering | Continuous | Open | + +Do not pretend likelihood labels are quantitative unless the team defines and uses a scoring method. + +--- + +## 97F. Architecture Change Governance + +v4 is the last broad platform-architecture revision before Engineering MVP implementation. + +New discoveries should normally become: + +```text +ADR +OpenAPI change +database migration +domain-state-machine update +security decision +backlog item +runbook +``` + +rather than a new full architecture rewrite. + +Reopen the broad architecture only when a discovery invalidates one of these foundational assumptions: + +```text +tenant model +profession separation +shared-core boundary +REST API model +data ownership +security trust boundary +deployment topology +database architecture +``` + +This prevents design review from becoming an infinite recursion problem. + +--- + +## 97G. Production Readiness Gates + +Architecture being coherent does not mean production is safe. + +Before production, require evidence in these categories. + +### Security + +```text +TLS configured +password hashing configured +refresh rotation/reuse detection tested +session revocation tested +tenant isolation tests passing +authorization/credential policies tested +rate limiting active +secrets managed outside source control +file security scanning active +security review completed +``` + +### Reliability + +```text +database backups automated +restore tested +object storage recovery strategy tested +outbox monitoring active +job queue monitoring active +webhook retry/dead-letter behavior tested +health checks configured +dependency failures tested +``` + +### Data Integrity + +```text +tenant-aware foreign keys present where required +financial invariants tested +migration tested on production-like data +idempotency tested for high-risk commands +optimistic concurrency tested +audit integrity tested +``` + +### Contract / API + +```text +OpenAPI validates +contract tests pass +error schema consistent +versioning rules documented +client SDK generation validated if used +``` + +### Performance + +```text +load test executed +realistic SLOs defined +database pool configured +key queries analyzed +outbox/job backlogs remain within SLO +``` + +### Critical Domain Coverage + +Rather than a magic overall coverage number, require explicit test coverage for: + +```text +tenant boundaries +design approval +inspection completion +invoice issue +payment/refund +membership privilege changes +clinical record signing/amendment when healthcare exists +prescribing authorization when healthcare exists +``` + +### Release Gate Principle + +No single metric such as: + +```text +90% test coverage +``` + +is sufficient evidence of production readiness. + +Quality gates are based on critical behavior, not vanity percentages. + +--- + +## 97. Final Design Position + +The platform is: + +```text +One Shared Platform + │ + ├── Shared Identity / Sessions + ├── Shared Security / Authorization + ├── Shared Documents / Multipart Uploads + ├── Shared Financial Core + ├── Shared Audit / Outbox + ├── Shared Jobs / Webhooks / Notifications + │ + ├── Engineering Internal Product + │ ├── Engineering Frontend + │ ├── Engineering REST APIs + │ ├── Engineering State Machines + │ └── Engineering Tables + │ + ├── Engineering Client Portal + │ ├── External Portal Frontend + │ ├── Portal Accounts + │ ├── Project Grants + │ ├── Published Documents + │ └── Client Review / Acceptance + │ + ├── Legal Product + │ ├── Legal Frontend + │ ├── Legal REST APIs + │ └── Legal Tables + │ + └── Healthcare Product + ├── Healthcare Frontend + ├── Healthcare REST APIs + ├── Healthcare Security Policies + └── Healthcare Tables +``` + +The system shares infrastructure where reuse is valuable while preserving profession-specific domain semantics and trust boundaries. + +v4 is the final broad architecture baseline for Engineering MVP implementation. + +From this point forward, architecture detail should primarily move into: + +```text +ADRs +OpenAPI +database schema/migrations +state-machine specifications +security policies +implementation backlog +runbooks +``` + +rather than repeatedly rewriting the entire architecture plan. + +This document does not itself prove: + +```text +regulatory compliance +production certification +security certification +performance at a specific scale +``` + +Those require implementation evidence, security review, domain validation, operational testing, restore testing, and measured production-like workloads. + + + + +--- + +# v4.1 Changelog + +v4.1 resolves implementation-contract issues without changing the core architecture. + +```text +✓ raw UUIDv7 API ID contract +✓ camelCase API / snake_case database naming convention +✓ direct organization_id on tenant subresources +✓ invitation role assignments +✓ service accounts and hashed API keys +✓ multiple professional credentials per profile +✓ global archive/revoke/unlink/hard-delete policy +✓ project stage duplication removed +✓ project budget_minor removed +✓ project phase reorder command +✓ global engineering site listing +✓ task status and priority vocabularies +✓ design revise endpoint +✓ design-version many-document cardinality +✓ design review/version tenant keys +✓ inspection finding tenant keys +✓ explicit inspection follow-up table +✓ change requests deferred until fully specified +✓ time-entry work-item attribution +✓ time-entry project/work-item consistency constraints +✓ specification many-document cardinality and status values +✓ legal_documents duplication removed +✓ legal matter/case document-link schemas +✓ healthcare placeholder schemas clarified +✓ invoice-item schema defined +✓ document retention-policy schema +✓ explicit retention-period null semantics +✓ version-independent document-category uniqueness fallback +✓ standard upload DTO +✓ multipart-init/parts/complete DTOs +✓ webhook subscription schema +✓ webhook delivery references outbox events +✓ typed job input/result references +✓ logout endpoint +✓ assigned-scope resolution rules +✓ audit privacy transformation strategy +✓ outbox correlation and causation IDs +✓ CORS/browser-security ADR +✓ feature-flag strategy clarified +✓ jobs confirmed tenant-scoped via X-Organization-Id +``` + +The next artifacts should be implementation-specific: + +```text +ADRs +Engineering OpenAPI +Engineering database migrations +Engineering state-machine spec +Engineering MVP backlog +``` diff --git a/professional_management_platform_rest_plan_v4_3.md b/professional_management_platform_rest_plan_v4_3.md new file mode 100644 index 0000000..ad16410 --- /dev/null +++ b/professional_management_platform_rest_plan_v4_3.md @@ -0,0 +1,6773 @@ +# Professional Management Platform +## Full REST-First System Design Plan + +> **Revision:** v4.1 — Consistency and Implementation-Contract Cleanup +> **Status:** Locked broad architecture baseline with implementation-blocking contradictions resolved. Subsequent detail belongs in ADRs, OpenAPI, migrations, domain specifications, and backlog items. +> **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 + +### v4.1 Cleanup Notes + +v4.1 does not redesign the platform. It resolves contradictions and fills implementation contracts discovered during detailed review. + +Resolved: + +- raw UUIDv7 is now the serialized/API identifier format +- database columns remain UUID; prefixed strings are not public IDs +- all tenant-owned subresources carry direct `organization_id` +- design-version document cardinality is explicit and relational +- engineering time entries can be attributed to a specific work item +- time-entry work-item links are constrained to the time entry's project +- engineering specifications use explicit many-document link records +- project-level `budget_minor` is removed in favor of the dedicated budget model +- duplicate `legal_documents` ownership is removed +- legal matter/case document-link schemas are defined +- batch custom-action paths use one documented convention +- membership invitations can pre-assign multiple roles +- missing design `revise` command is added +- inspection follow-ups now have a table and lifecycle +- change requests are moved out of the initial Engineering schema until specified +- service accounts and API keys are defined for machine access +- service-account role assignments have an explicit relational schema +- API JSON, query parameters, and path parameter names use camelCase; database columns use snake_case +- professional profiles support multiple professional credentials +- deletion/archival/revocation/unlink behavior is globally defined +- invoice-item fields are specified +- deferred healthcare placeholder tables receive minimum schemas or explicit deferral notes +- document upload and multipart DTOs are defined +- webhook subscription fields are defined +- `POST /auth/logout` is restored +- portal review-request and portal capability schemas are defined +- project-role, task-status, priority, and inspection-outcome values are defined +- document-category uniqueness has a version-independent fallback +- retention policy fields are defined +- retention-period null semantics are explicit +- pagination defaults are explicit +- `assigned` authorization scope has resource-specific resolution rules +- feature-flag behavior is clarified +- audit privacy minimization/anonymization strategy is documented +- outbox correlation and causation IDs are added +- webhook delivery event references and job reference envelopes are defined +- CORS and web-security configuration is moved into a required ADR +- project `stage` duplication is removed; project phases remain authoritative +- phase reordering, site listing, appointment locations, and encounter reason fields are clarified +- jobs remain tenant-scoped through the standard organization header rather than path nesting + +--- +--- +--- +--- + +## 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: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +X-Request-Id: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff +Content-Type: application/json +``` + +### API Naming Convention + +Public API representation: + +```text +JSON properties: camelCase +query parameters: camelCase +path parameter names in documentation: camelCase +HTTP headers: conventional HTTP header casing +``` + +Database representation: + +```text +table names: snake_case +column names: snake_case +constraint/index names: snake_case +``` + +Example: + +```http +GET /api/v1/engineering/tasks?assignedToUserId=&createdAfter=2026-08-01T00:00:00Z +``` + +```json +{ + "assignedToUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "createdAt": "2026-08-26T12:00:00Z" +} +``` + +maps internally to columns such as: + +```text +assigned_to_user_id +created_at +``` + +### Organization Context + +`X-Organization-Id` is mandatory for every tenant-scoped endpoint. + +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: + +```yaml +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_mismatch: + status: 404 + code: RESOURCE_NOT_FOUND +``` + +### Idempotency + +Use: + +```http +Idempotency-Key: 8f7d6c5e-4b3a-4b1c-9d8e-7f6a5b4c3d2e +``` + +Required where duplicate execution can create material side effects. + +PostgreSQL is authoritative for critical idempotency records. + +Redis may accelerate lookup. + +### Batch Custom-Action Convention + +For collection-level custom commands use: + +```text +/{collection}/batch/{action} +``` + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete +POST /api/v1/engineering/time-entries/batch/submit +``` + +Do not mix `batch-assign`, colon-style custom methods, and `/batch/assign` in the same API. + +### Rate-Limit Responses + +```http +429 Too Many Requests +Retry-After: +``` + +Additional rate-limit metadata may be exposed according to the selected gateway/standard. + +Do not freeze legacy `X-RateLimit-*` names here. + +### Error Standard Decision + +The current error envelope remains: + +```json +{ + "error": { + "code": "RESOURCE_NOT_FOUND", + "message": "Resource not found.", + "details": {}, + "requestId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff" + } +} +``` + +ADR-005 decides whether OpenAPI v1 aligns this with RFC 9457 Problem Details. + +Do not silently change the envelope during implementation. + +## 9. Standard Response Format + +Single resource: + +```json +{ + "data": { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c6d", + "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. + +--- + +## 11A. Identifier Convention + +The serialized identifier standard is **raw UUIDv7**. + +Example: + +```text +0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +``` + +Database: + +```sql +id UUID PRIMARY KEY +``` + +API: + +```json +{ + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d" +} +``` + +Do not serialize IDs as: + +```text +org_ +user_ +project_ +``` + +unless a future ADR explicitly changes the public identifier contract. + +Human-friendly resource references use separate fields such as: + +```text +projectNumber +matterNumber +patientNumber +invoiceNumber +``` + +This separates machine identity from business/display references. + +UUID generation is decided by ADR-004: + +```text +PostgreSQL-native UUIDv7 when supported and selected +or +application-generated UUIDv7 +``` + +The API format is identical either way. + +--- + +## 12. Authentication + +Initial human authentication: + +```text +Email ++ +Password ++ +Short-Lived Access Token ++ +Opaque Refresh Token ++ +Server-Side Session +``` + +REST: + +```http +POST /api/v1/auth/register +POST /api/v1/auth/login +POST /api/v1/auth/logout + +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 +``` + +`POST /auth/logout` revokes the current session. + +`DELETE /auth/sessions/{sessionId}` allows a user to revoke a specific session, such as another device. + +### Access Token + +```yaml +format: JWT +lifetime: short-lived +signed: true +encrypted: false +claims: + - sub + - sessionId + - issuer + - audience + - issuedAt + - expiresAt +``` + +Organization context is not trusted from the token as authorization authority. + +### Sessions + +```text +sessions +├── id +├── user_id +├── device metadata +├── created_at +├── last_active_at +├── expires_at +├── revoked_at +└── revocation_reason +``` + +### Refresh Tokens + +```text +refresh_tokens +├── id +├── session_id +├── family_id +├── token_hash +├── issued_at +├── expires_at +├── rotated_at +├── replaced_by_token_id +├── revoked_at +└── revocation_reason +``` + +Constraints/indexes: + +```text +UNIQUE(token_hash) +INDEX(family_id) +INDEX(session_id) +``` + +`family_id` is not unique. + +### Refresh Reuse Detection + +Use of a previously rotated token triggers: + +```text +revoke token family +revoke affected session +security audit event +reauthentication +``` + +Policy may escalate to all-session revocation. + +Future human authentication: + +- MFA +- WebAuthn/passkeys +- OIDC/SSO +- enterprise identity providers + + +## 12A. Service Accounts and API Keys + +Machine-to-machine access is separate from human sessions. + +Use: + +```text +service_accounts +api_keys +service_account_roles +``` + +### Service Account + +Suggested fields: + +```text +id +organization_id +name +description +status +created_by_user_id +created_at +updated_at +revoked_at +``` + +### API Key + +Suggested fields: + +```text +id +organization_id +service_account_id + +key_prefix +secret_hash + +created_at +expires_at +last_used_at +revoked_at +revocation_reason +``` + +Raw API-key secrets are shown only once. + +Store only a secure hash of the secret. + +`key_prefix` is safe display material for identifying a key in administration screens. + +### Service Account Role + +`service_account_roles` uses the same organization-scoped role registry as human RBAC assignments. + +Suggested fields: + +```text +id +organization_id +service_account_id +role_id +created_at +``` + +Unique: + +```text +(organization_id, service_account_id, role_id) +``` + +Tenant-safe foreign keys require the service account and role to belong to the same organization as the assignment. + +### Authorization + +Service accounts use explicit organization-scoped permissions, preferably through: + +```text +service_account_roles +``` + +with the same registered permission vocabulary used by RBAC. + +They do not become fake human memberships. + +### Audit + +Audit actors support: + +```text +actor_type = user +actor_type = service_account +actor_type = system +``` + +Machine authentication is required when public/integration API access is implemented; it does not block the earliest internal Engineering UI slice. + +--- + +## 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. + +Tables: + +```text +membership_invitations +membership_invitation_roles +``` + +`membership_invitations`: + +```text +id +organization_id +email +invited_by_user_id +expires_at +accepted_at +revoked_at +created_at +``` + +`membership_invitation_roles`: + +```text +organization_id +invitation_id +role_id +created_at +``` + +Use tenant-aware foreign keys so invitation roles cannot reference another organization's role. + +Flow: + +```text +Invitation + Intended Roles + ↓ + Accepted + ↓ + User + ↓ + Membership + ↓ + Membership Roles +``` + +At acceptance: + +1. validate invitation token and expiry +2. validate invited email/account policy +3. create membership +4. copy valid intended roles to membership-role assignments +5. mark invitation accepted +6. audit +7. emit outbox event + +If an intended role was revoked/deleted before acceptance, acceptance fails safely or drops that role according to explicit organization policy. + +## 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 +``` + +Example: + +```text +Engineer: +engineering.projects.read = assigned + +Principal Engineer: +engineering.projects.read = organization +``` + +`assigned` is not magic. Each resource policy defines how assignment is resolved. + +### Engineering Project + +Assigned when: + +```text +engineering_project_members.user_id = ctx.userId +AND engineering_project_members.left_at IS NULL +``` + +or when the user is the active project manager, if project-manager assignment is modeled separately. + +### Engineering Task + +Assigned when: + +```text +engineering_tasks.assigned_to_user_id = ctx.userId +``` + +For tasks linked to a project, parent-project access may also be required. + +### Engineering Design + +Assigned when an active row exists in: + +```text +engineering_design_assignments +``` + +for the user and an allowed assignment role. + +### Engineering Inspection + +Assigned when: + +```text +engineering_inspections.inspector_user_id = ctx.userId +``` + +or an explicit inspection assignment exists if the model later supports multiple inspectors. + +### Derived Client Access + +An assigned professional may access a client only through a policy that derives access from authorized projects. + +Project assignment must not automatically grant access to every project belonging to that client. + +Future scopes may include: + +```text +owned +team +department +restricted +``` + +Do not add them before a real workflow requires them. + +## 21. Professional Credentials + +Professional identity and credentials are separate from RBAC. + +Use: + +```text +professional_profiles +professional_credentials +``` + +### Professional Profile + +One organization/user/profession relationship. + +Suggested fields: + +```text +id +organization_id +user_id +profession +title +status +created_at +updated_at +``` + +### Professional Credential + +One profile may hold many credentials. + +Suggested fields: + +```text +id +organization_id +professional_profile_id + +credential_type +credential_number +issuing_authority +jurisdiction +discipline + +status +valid_from +expires_at + +verified_at +verified_by_user_id + +created_at +updated_at +``` + +Examples: + +```text +professional engineering license in jurisdiction A +professional engineering license in jurisdiction B +specialty certification +medical license +controlled-substance prescribing registration where applicable +``` + +Credential policy evaluates the set of active credentials rather than one `primary_license_number`. + +High-risk actions such as design approval, record signing, or prescribing use authoritative or revocation-aware credential state. + +Prescribing remains jurisdiction/scope-of-practice policy, not a hard-coded profession test. + +## 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. + +--- + +## 21A. Deletion, Archival, Revocation, and Unlink Policy + +`DELETE` does not have one universal persistence meaning. + +Use four lifecycle behaviors. + +### Archive / Domain Inactivation + +For business records whose history matters: + +```text +engineering clients +engineering projects +legal matters +healthcare patients +documents where retention requires history +``` + +Typical fields: + +```text +status +archived_at +archived_by_user_id +``` + +Restore is permitted only when domain, retention, and organization policy allow it. + +### Revoke + +For access/security resources: + +```text +sessions +refresh tokens +API keys +membership invitations +portal grants +webhook credentials +``` + +Use: + +```text +revoked_at +revoked_by +revocation_reason +``` + +### Temporal Unlink + +For relationship records where the historical relationship matters: + +```text +project documents +project members +design assignments +portal document publications +``` + +Use: + +```text +unlinked_at +left_at +unassigned_at +revoked_at +``` + +rather than deleting historical evidence. + +### Hard Delete + +Reserved for genuinely disposable or never-committed data, such as: + +```text +expired pending upload artifacts +failed temporary staging objects +unreferenced draft configuration where audit/retention does not require history +``` + +Hard deletion of financial, professional, audit, signed clinical, or issued business records is forbidden unless an explicit retention/privacy policy defines the operation. + +Every resource specification must declare its lifecycle behavior. + +--- + +# Engineering Domain + +## 26. Engineering Tables + +Initial Engineering MVP tables: + +```text +engineering_clients +engineering_client_contacts + +engineering_projects +engineering_project_members +engineering_project_phases +engineering_sites +engineering_tasks + +engineering_designs +engineering_design_assignments +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews + +engineering_inspections +engineering_inspection_findings +engineering_inspection_followups + +engineering_specifications +engineering_specification_documents + +engineering_time_entries +``` + +Later Engineering extensions: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries + +engineering_change_requests +``` + +`engineering_change_requests` is not part of the initial schema until its lifecycle, relationships, and REST contract are specified. + +## 27. Engineering Clients + +Suggested core client fields: + +```text +id +organization_id +client_type +display_name +legal_name +status +created_at +updated_at +version +``` + +Do not permanently squeeze all contacts into one `email`, one `phone`, and one `contact_name`. + +Engineering customers commonly have multiple: + +```text +technical contacts +billing contacts +executive contacts +site contacts +contract contacts +``` + +Use: + +```text +engineering_client_contacts +``` + +Suggested contact fields: + +```text +id +organization_id +client_id + +name +title +department + +email +phone + +contact_type +is_primary + +created_at +updated_at +``` + +Client 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 +``` + +Contact REST: + +```http +GET /api/v1/engineering/clients/{clientId}/contacts +POST /api/v1/engineering/clients/{clientId}/contacts +PATCH /api/v1/engineering/clients/{clientId}/contacts/{contactId} +DELETE /api/v1/engineering/clients/{clientId}/contacts/{contactId} +``` + +Delete may be implemented as archival when contact history matters. + +Client restore is allowed only when organization policy and retention rules permit it. + +## 27A. Engineering Client Portal + +External clients are not internal organization members. + +Use shared authentication identities where practical, but create a separate authorization boundary. + +```text +User + │ + ├── Internal Membership + │ ↓ + │ Organization Staff Access + │ + └── Client Portal Account + ↓ + Engineering Client Contact + ↓ + Project Access Grants +``` + +Suggested tables: + +```text +engineering_client_portal_accounts +engineering_client_portal_project_grants +engineering_project_document_publications +engineering_client_review_requests +``` + +### Portal Account + +Suggested fields: + +```text +id +organization_id +user_id +engineering_client_contact_id + +status + +invited_by_user_id +invited_at +accepted_at + +revoked_at +revoked_by_user_id +``` + +Portal accounts are not placed in `memberships`. + +### Project Grant + +Suggested fields: + +```text +id +organization_id +portal_account_id +project_id + +access_profile + +granted_by_user_id +granted_at +expires_at +revoked_at +``` + +Initial access capabilities may include: + +```text +project.status.read +project.documents.read_published +project.comments.create +project.files.submit +client_review.respond +``` + +The access model may later normalize capabilities into a grant table if simple profiles become insufficient. + +### Separate Frontend + +Recommended: + +```text +apps/ +├── engineering-web/ +└── engineering-client-portal/ +``` + +The internal engineering frontend and external portal do not share authorization assumptions. + +### Client Acceptance Is Not Engineering Approval + +Never represent client acceptance with: + +```text +engineering.designs.approve +``` + +Professional engineering approval is reserved for qualified internal/authorized professionals. + +Client-facing review should use separate concepts such as: + +```text +engineering.client_reviews.request +engineering.client_reviews.respond +engineering.client_reviews.accept +engineering.client_reviews.request_changes +``` + +Example: + +```http +POST /api/v1/engineering/client-review-requests/{reviewId}/accept +POST /api/v1/engineering/client-review-requests/{reviewId}/request-changes +``` + +A client acceptance may be commercially meaningful without being a professional engineering approval. + +### Portal Security Rules + +1. portal access is deny-by-default +2. every portal request remains organization-scoped +3. portal users only access explicitly granted projects +4. project membership does not apply to portal users +5. internal RBAC roles do not automatically apply to portal users +6. portal account revocation is immediate +7. portal grants may expire +8. sensitive document access requires explicit publication +9. portal activity is audited according to organization policy +10. professional approval endpoints are never exposed through portal grants + +--- + +## 27B. External Document Publication + +A document being linked to an engineering project does **not** make it externally visible. + +Use: + +```text +engineering_project_document_publications +``` + +Suggested fields: + +```text +id +organization_id + +project_document_link_id + +audience_type +portal_account_id nullable +client_id nullable + +published_by_user_id +published_at + +expires_at +revoked_at +revoked_by_user_id +``` + +Possible audiences: + +```text +all_active_client_portal_accounts_for_project +specific_portal_account +specific_client_contact +``` + +External download checks: + +```text +authenticated portal user ++ +active portal account ++ +active project grant ++ +active document publication ++ +publication not expired/revoked ++ +document classification allows publication ++ +download permission +``` + +This prevents an internal project document from appearing in the client portal merely because it is linked to the project. + +## 28. Engineering Projects + +Suggested fields: + +```text +id +organization_id +client_id + +project_number +name +description +discipline + +status + +project_manager_user_id + +start_date +expected_completion_date +completed_date + +created_at +updated_at +version +``` + +`stage` is removed from the project row because project phases are the authoritative workflow decomposition. + +If the frontend needs a "current stage", derive it from the active/current project phase or maintain an explicitly documented `current_phase_id` pointer. + +Project `budget_minor` is also removed. + +Detailed project budgets belong to the dedicated budget model. + +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 reads: + +```http +GET /api/v1/engineering/projects/{projectId}/summary +GET /api/v1/engineering/projects/{projectId}/timeline +GET /api/v1/engineering/projects/{projectId}/budget +``` + +The budget endpoint reads from the budget module when that module exists. + +## 29. Engineering Project Members + +Suggested fields: + +```text +id +organization_id +project_id +user_id +project_role +joined_at +left_at +``` + +Initial project-role vocabulary: + +```text +project_manager +engineer +designer +reviewer +inspector +viewer +contractor +``` + +Project role describes participation in one project. + +It is not a substitute for RBAC permission. + +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} +``` + +`DELETE` means end participation by setting `left_at`, not erase historical participation. + +## 30. Engineering Project Phases + +Suggested fields: + +```text +id +organization_id +project_id +name +sequence +status +start_date +end_date +created_at +updated_at +version +``` + +Typical initial statuses: + +```text +planned +active +completed +cancelled +``` + +Example 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 +POST /api/v1/engineering/projects/{projectId}/phases/reorder +``` + +Reorder request: + +```json +{ + "projectVersion": 12, + "orderedPhaseIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b301", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b302" + ] +} +``` + +Reordering is transactional. + +Sequences remain unique within a project after commit. + +## 31. Engineering Sites + +Suggested fields: + +```text +id +organization_id +project_id +name +address +latitude +longitude +created_at +updated_at +``` + +REST: + +```http +GET /api/v1/engineering/sites +GET /api/v1/engineering/sites/{siteId} + +POST /api/v1/engineering/projects/{projectId}/sites +GET /api/v1/engineering/projects/{projectId}/sites + +PATCH /api/v1/engineering/sites/{siteId} +``` + +Global site listing is still tenant-scoped through `X-Organization-Id`. + +## 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 +``` + +Statuses: + +```text +todo +in_progress +completed +cancelled +``` + +Priorities: + +```text +low +medium +high +urgent +``` + +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 +``` + +## 32A. Engineering Batch Operations + +Batch operations are useful for repetitive engineering workflows, but they must not bypass per-resource authorization or domain rules. + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete + +POST /api/v1/engineering/time-entries/batch/submit +``` + +### Batch Execution Modes + +Every batch command explicitly defines one of: + +```text +atomic +partial +``` + +Atomic: + +```text +all resources succeed +or +entire operation fails +``` + +Partial: + +```text +each resource is evaluated independently +successful items commit +failed items return individual errors +``` + +Do not leave this behavior implicit. + +Example request: + +```json +{ + "taskIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83" + ], + "assigneeUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "mode": "partial" +} +``` + +Example response: + +```json +{ + "data": { + "succeeded": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82" + ], + "failed": [ + { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83", + "code": "RESOURCE_INVALID_STATE" + } + ] + } +} +``` + +### Authorization + +Each resource is evaluated for: + +```text +tenant +permission +scope +resource access +state validity +credential policy where applicable +``` + +Never authorize the first item and assume the remaining batch is equivalent. + +### Synchronous vs Asynchronous + +Small batches may execute synchronously. + +Large batches become jobs: + +```http +202 Accepted +``` + +with: + +```text +jobId +``` + +The synchronous/asynchronous threshold is configuration based on: + +```text +batch size +operation cost +database load +side effects +product tier +``` + +Financial or regulated batch actions require stricter idempotency and audit rules than ordinary task updates. + +--- + +## 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 +cancelled +withdrawn +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}/revise +POST /api/v1/engineering/designs/{designId}/cancel +POST /api/v1/engineering/designs/{designId}/withdraw +POST /api/v1/engineering/designs/{designId}/supersede + +POST /api/v1/engineering/designs/{designId}/assign +POST /api/v1/engineering/designs/{designId}/unassign + +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 +``` + +State machine: + +```text +draft + ├── submit-review ─────────────► under_review + └── cancel ────────────────────► cancelled + +under_review + ├── request-changes ───────────► changes_requested + ├── approve ───────────────────► approved + ├── reject ────────────────────► rejected + └── withdraw ──────────────────► withdrawn + +changes_requested + ├── submit-review ─────────────► under_review + └── withdraw ──────────────────► withdrawn + +rejected + └── revise ────────────────────► draft + +approved + └── supersede ─────────────────► superseded +``` + +Approval remains credential-aware, audited, and idempotent. + +Designs do not use generic archive/restore endpoints. Their professional lifecycle terminates through explicit state-machine outcomes such as `cancelled`, `withdrawn`, and `superseded`. Terminal designs remain queryable and auditable and are not hard-deleted through ordinary workflows. + +## 34. Design Versions and Reviews + +A design version is a logical professional revision. + +It may have multiple document files. + +Use: + +```text +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews +``` + +### Design Version + +```text +id +organization_id +design_id +version_number +created_by_user_id +created_at +``` + +Unique: + +```text +(organization_id, design_id, version_number) +``` + +### Design Version Documents + +```text +id +organization_id +design_version_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +Possible `document_role` values: + +```text +primary_drawing +calculation +supporting_document +specification +attachment +``` + +A design version therefore supports one or many documents without putting `document_id` directly on the version. + +### Design Review + +```text +id +organization_id +design_id +design_version_id +reviewer_user_id +status +comments +reviewed_at +created_at +``` + +Statuses: + +```text +pending +approved +changes_requested +rejected +``` + +All three tables are tenant-owned and carry direct `organization_id`. + +## 35. Engineering Inspections + +Inspection fields: + +```text +id +organization_id +project_id +site_id + +inspection_type +inspector_user_id + +status +outcome + +scheduled_at +started_at +performed_at +cancelled_at + +summary + +created_at +updated_at +version +``` + +Lifecycle: + +```text +draft +scheduled +in_progress +completed +cancelled +``` + +Outcome: + +```text +passed +passed_with_observations +followup_required +failed +``` + +`inspection_type` is an application/domain registry rather than a PostgreSQL enum. + +Initial common keys may include: + +```text +structural +mechanical +electrical +safety +final +``` + +Organizations/modules may add supported types through controlled configuration later. + +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 + +GET /api/v1/engineering/inspections/{inspectionId}/followups +POST /api/v1/engineering/inspections/{inspectionId}/followups +``` + +Inspection completion may create follow-up records. + +Lifecycle and outcome remain separate. + +## 36. Inspection Findings + +`engineering_inspection_findings`: + +```text +id +organization_id +inspection_id + +severity +description +status + +resolved_at +resolved_by_user_id + +created_at +updated_at +version +``` + +Severity: + +```text +observation +minor +major +critical +``` + +Status: + +```text +open +in_progress +resolved +accepted_risk +``` + +REST: + +```http +POST /api/v1/engineering/inspections/{inspectionId}/findings +PATCH /api/v1/engineering/inspection-findings/{findingId} +POST /api/v1/engineering/inspection-findings/{findingId}/resolve +``` + +`organization_id` is direct even though tenant ownership is also derivable through the inspection. + +### Follow-Up Resource + +Use: + +```text +engineering_inspection_followups +``` + +Fields: + +```text +id +organization_id +inspection_id + +followup_type + +linked_task_id nullable +linked_inspection_id nullable + +status + +created_by_user_id +created_at +completed_at +cancelled_at +``` + +`followup_type`: + +```text +corrective_task +followup_inspection +both +``` + +`status`: + +```text +open +in_progress +completed +cancelled +``` + +Tenant-safe foreign keys apply to the original inspection and any linked task/inspection. + +## 37. Engineering Specifications + +Use: + +```text +engineering_specifications +engineering_specification_documents +``` + +Suggested specification fields: + +```text +id +organization_id +project_id +specification_number +title +version +status +created_at +updated_at +``` + +Status values: + +```text +draft +active +superseded +archived +``` + +Specification document links: + +```text +id +organization_id +specification_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +A specification may therefore have one or many current or historical document links. `document_role` is an application registry with initial values such as `primary`, `attachment`, and `supporting_document`. Tenant-safe foreign keys apply to both the specification and shared document. + +--- + +## 38. Engineering Change Requests + +**Deferred from the initial Engineering schema.** + +Change requests are a valid future engineering capability, but v4.1 does not create the table until these are specified: + +```text +relationship to project +relationship to design/specification +request origin +impact analysis +cost/schedule effects +review workflow +approval authority +state machine +document links +REST commands +audit requirements +``` + +Future candidate: + +```text +engineering_change_requests +``` + +This belongs in the Engineering extension backlog rather than a half-defined initial migration. + +## 38A. Engineering Project Budgets + +A single `budget_minor` column is sufficient only for a very early project total. + +When budget management enters scope, introduce: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries +``` + +### Budget + +Suggested fields: + +```text +id +organization_id +project_id + +name +currency_code +status + +approved_by_user_id +approved_at + +created_at +updated_at +version +``` + +### Budget Item + +Suggested fields: + +```text +id +organization_id +budget_id + +category +description + +allocated_amount_minor + +created_at +updated_at +``` + +Do not casually store mutable: + +```text +spent_amount_minor +committed_amount_minor +``` + +as independent sources of truth if those values are derived from time entries, expenses, purchase commitments, or invoices. + +Prefer: + +```text +authoritative cost/commitment records + ↓ +derived budget projections +``` + +If denormalized totals are needed for performance, update them transactionally and reconcile them. + +Potential REST: + +```http +GET /api/v1/engineering/projects/{projectId}/budgets +POST /api/v1/engineering/projects/{projectId}/budgets +GET /api/v1/engineering/budgets/{budgetId} +PATCH /api/v1/engineering/budgets/{budgetId} + +POST /api/v1/engineering/budgets/{budgetId}/approve +GET /api/v1/engineering/budgets/{budgetId}/items +POST /api/v1/engineering/budgets/{budgetId}/items +``` + +Budget approval is an explicit command. + +--- + +## 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 + +phase_id nullable +task_id nullable +design_id nullable +inspection_id nullable + +created_at +updated_at +version +``` + +The project is always required. + +A time entry may also identify one primary work item. + +Database check: + +```text +at most one of: +phase_id +task_id +design_id +inspection_id +``` + +Each optional foreign key is tenant- and project-aware. For example: + +```text +(organization_id, project_id, task_id) +→ engineering_tasks(organization_id, project_id, id) +``` + +and similarly for phase, design, and inspection. Supporting unique constraints on `(organization_id, project_id, id)` are required on each target table. + +This is a database-enforced invariant, not only an application validation rule: whenever an optional work-item ID is present, that work item must belong to the same organization and `project_id` as the time entry. + +This preserves relational integrity instead of using an unconstrained polymorphic `reference_type/reference_id`. + +REST: + +```http +POST /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries/{timeEntryId} +PATCH /api/v1/engineering/time-entries/{timeEntryId} + +POST /api/v1/engineering/time-entries/batch/submit +``` + +Duration is integer minutes. + +## 40. Legal Tables + +Initial legal-domain tables: + +```text +legal_clients +legal_matters +legal_matter_members +legal_cases +legal_case_parties +legal_courts +legal_hearings +legal_deadlines +legal_time_entries +legal_retainers +legal_conflict_checks +legal_conflict_parties +legal_conflict_matches +legal_matter_documents +legal_case_documents +``` + +There is no separate `legal_documents` ownership table. + +Documents remain shared infrastructure: + +```text +documents +document_versions +``` + +Legal relationships use: + +```text +legal_matter_documents +legal_case_documents +``` + +`legal_matter_documents` fields: + +```text +id +organization_id +matter_id +document_id +linked_by_user_id +linked_at +unlinked_at +``` + +`legal_case_documents` fields: + +```text +id +organization_id +case_id +document_id +linked_by_user_id +linked_at +unlinked_at +``` + +Both tables use tenant-safe foreign keys to their Legal parent and the shared `documents` table. `unlinked_at` preserves link history without deleting the shared document. + +REST namespace: + +```text +/api/v1/legal +``` + +Legal remains a later vertical. + +## 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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cbd", + "status": "pending_review", + "potentialConflicts": [ + { + "type": "possible_direct_adversity", + "partyName": "Acme Corporation", + "existingMatterId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2ccd", + "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 + +Healthcare remains a later vertical. + +Minimum planned tables: + +```text +healthcare_patients +healthcare_patient_contacts +healthcare_patient_addresses + +healthcare_practitioners +healthcare_locations +healthcare_rooms + +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 +``` + +All tenant-owned tables carry direct `organization_id`. + +Detailed healthcare interoperability, terminology, and jurisdiction rules require healthcare-specific design before implementation. + +## 46. Healthcare Patients + +Core patient: + +```text +id +organization_id +patient_number + +first_name +middle_name +last_name +date_of_birth + +administrative_gender nullable +sex_at_birth nullable +gender_identity nullable + +status + +created_at +updated_at +version +``` + +Exact demographic terminology and allowed values are finalized in the healthcare-domain specification. + +Do not make every field mandatory merely because it exists. + +### Patient Contact + +`healthcare_patient_contacts`: + +```text +id +organization_id +patient_id + +contact_type +value +is_primary + +created_at +updated_at +``` + +### Patient Address + +`healthcare_patient_addresses`: + +```text +id +organization_id +patient_id + +address_type +line_1 +line_2 +city +region +postal_code +country_code + +is_primary + +created_at +updated_at +``` + +Sensitive subresources remain permission-controlled. + +## 47. Healthcare Practitioners + +Suggested fields: + +```text +id +organization_id +user_id +professional_profile_id + +specialty +status + +created_at +updated_at +``` + +Professional licenses are not duplicated here. + +Multiple licenses/credentials live in: + +```text +professional_credentials +``` + +## 48. Healthcare Appointments + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id + +location_id nullable +room_id nullable + +appointment_type + +starts_at +ends_at + +status +reason + +created_at +updated_at +version +``` + +Planned supporting tables: + +`healthcare_locations`: + +```text +id +organization_id +name +address fields +timezone +status +``` + +`healthcare_rooms`: + +```text +id +organization_id +location_id +name +status +``` + +Exact scheduling rules are deferred to the healthcare vertical. + +## 49. Healthcare Encounters + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id +appointment_id nullable + +encounter_type + +reason_for_visit nullable + +started_at +ended_at + +status + +created_at +updated_at +version +``` + +Do not add a generic free-form `notes` field as a substitute for clinical records. + +Clinical narrative belongs in governed clinical-record structures. + +## 50. Clinical Records + +Use: + +```text +healthcare_clinical_records +healthcare_clinical_record_versions +healthcare_clinical_record_amendments +``` + +### Clinical Record + +```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 +``` + +### Clinical Record Version + +```text +id +organization_id +record_id +version_number + +content_reference or governed content payload +created_by_practitioner_id +created_at +``` + +### Clinical Record Amendment + +```text +id +organization_id +record_id +source_version_id +result_version_id + +amended_by_practitioner_id + +amendment_type +amendment_reason + +created_at +``` + +Possible amendment types: + +```text +correction +addendum +clarification +``` + +Signed/finalized history is preserved. + +REST: + +```http +POST /api/v1/healthcare/encounters/{encounterId}/clinical-records + +GET /api/v1/healthcare/clinical-records/{recordId} +PATCH /api/v1/healthcare/clinical-records/{recordId} +# Draft/editable only. + +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 +``` + +## 51. Documents + +Shared document infrastructure: + +```text +documents +document_versions +document_categories +retention_policies +``` + +Binary data lives in S3-compatible object storage. + +### Document + +```text +id +organization_id +name +category_id +classification +retention_policy_id +current_version_id +created_by_user_id +created_at +updated_at +``` + +Classification: + +```text +public +internal +confidential +restricted +regulated +``` + +### Document Version + +```text +id +organization_id +document_id +version_number +storage_key +mime_type +size_bytes +content_hash +hash_algorithm +uploaded_by_user_id +created_at +``` + +Checksum is version-level authoritative data. + +### Document Category + +```text +id +organization_id +profession nullable +name +parent_category_id +created_at +``` + +Uniqueness requirement: + +```text +shared category: + unique organization_id + name where profession IS NULL + +profession category: + unique organization_id + profession + name where profession IS NOT NULL +``` + +Implementation options: + +```text +PostgreSQL null-aware unique constraint when supported +or +two partial unique indexes +``` + +The partial-index fallback does not depend on selecting PostgreSQL 18. + +### Retention Policy + +```text +id +organization_id + +name +profession nullable +classification nullable + +retention_period_days nullable +action + +created_at +updated_at +``` + +Initial actions: + +```text +review +archive +delete_when_legally_permitted +retain_indefinitely +``` + +`retention_period_days` has one meaning only: + +```text +action = retain_indefinitely + → retention_period_days MUST be null + +all other actions + → retention_period_days MUST be a positive integer +``` + +Null does not mean inherit, unconfigured, or unknown. Policy inheritance or an unconfigured state must be represented outside a persisted retention-policy row and specified separately before implementation. + +A retention policy describes configured behavior. + +Actual deletion remains subject to domain, contractual, privacy, and jurisdiction requirements. + +### Metadata + +JSONB is allowed only for genuinely extensible, non-authoritative metadata. + +Do not put authorization, lifecycle, retention state, or ownership into arbitrary JSON. + +## 52. Document Upload Flow + +### Standard Upload + +Request: + +```http +POST /api/v1/documents/upload-url +``` + +```json +{ + "name": "structural-calculations.pdf", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/pdf", + "sizeBytes": 2457600, + "contentHash": "sha256:..." +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d01", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "uploadUrl": "https://object-storage.example/...", + "expiresAt": "2026-08-26T13:00:00Z" + } +} +``` + +The frontend uploads directly to object storage. + +Finalize: + +```http +POST /api/v1/documents/{documentId}/complete-upload +``` + +```json +{ + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "contentHash": "sha256:..." +} +``` + +### Multipart Initialization + +```http +POST /api/v1/documents/multipart-uploads +``` + +Request: + +```json +{ + "name": "building-model.bin", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/octet-stream", + "sizeBytes": 2147483648, + "contentHash": null +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d10", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d11", + "uploadId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d12", + "recommendedPartSizeBytes": 67108864, + "expiresAt": "2026-08-27T12:00:00Z" + } +} +``` + +### Request Signed Part URLs + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/parts +``` + +```json +{ + "partNumbers": [1, 2, 3, 4] +} +``` + +Response: + +```json +{ + "data": [ + { + "partNumber": 1, + "uploadUrl": "https://object-storage.example/..." + } + ] +} +``` + +Binary parts go directly to object storage. + +### Complete Multipart Upload + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/complete +``` + +```json +{ + "parts": [ + { + "partNumber": 1, + "etag": "..." + } + ], + "contentHash": "sha256:..." +} +``` + +Abort: + +```http +DELETE /api/v1/documents/{documentId}/multipart-uploads/{uploadId} +``` + +Upload state: + +```text +initiated +uploading +completing +completed +aborted +expired +``` + +Workers clean up abandoned multipart uploads. + +Upload policy validates: + +```text +declared MIME +extension +content signature +size +checksum +quota +classification +malware status +``` + +## 53. Profession-Specific Document Links + +Use explicit relationship tables. + +Engineering: + +```text +engineering_project_documents +engineering_design_version_documents +engineering_inspection_documents +``` + +Legal: + +```text +legal_matter_documents +legal_case_documents +``` + +Healthcare: + +```text +healthcare_patient_documents +healthcare_encounter_documents +``` + +`engineering_design_version_documents` is authoritative for files belonging to a specific design revision. + +Do not also maintain an ambiguous `engineering_design_documents` relation to the unversioned design unless a later requirement introduces a separate clearly named supporting-document relationship. + +### Project Documents + +```text +engineering_project_documents +├── id +├── organization_id +├── project_id +├── document_id +├── category +├── linked_by_user_id +├── linked_at +└── unlinked_at +``` + +REST: + +```http +GET /api/v1/engineering/projects/{projectId}/documents +POST /api/v1/engineering/projects/{projectId}/documents +DELETE /api/v1/engineering/project-documents/{documentLinkId} +``` + +`DELETE` temporally unlinks the relation when history must be preserved. + +## 54. Billing + +Shared financial core: + +```text +invoices +invoice_items +payments +``` + +### Invoice + +Core fields include: + +```text +id +organization_id +client/reference context +invoice_number +status +currency_code +subtotal_minor +tax_total_minor +total_minor +issued_at +due_at +paid_at +created_at +updated_at +version +``` + +### Invoice Item + +```text +id +organization_id +invoice_id + +description + +quantity +unit_price_minor +total_amount_minor + +position + +created_at +updated_at +``` + +`quantity` uses fixed-precision numeric semantics, not floating point. + +Money uses integer minor units. + +The invoice determines currency; invoice items do not independently choose a different currency unless multi-currency invoicing is intentionally designed later. + +### Profession-Specific Source Links + +The shared billing module does not use unconstrained: + +```text +reference_type +reference_id +``` + +to profession-owned tables. + +Profession modules create explicit links, for example: + +```text +engineering_invoice_item_time_entries +├── organization_id +├── invoice_item_id +└── time_entry_id +``` + +This preserves the rule that shared core does not depend on profession-table internals. + +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 + +Use: + +```text +audit_events +``` + +Suggested fields: + +```text +id +organization_id + +actor_type +actor_user_id nullable +actor_service_account_id nullable + +action + +resource_type +resource_id + +request_id +correlation_id + +ip_address +user_agent + +metadata + +occurred_at +``` + +Audit records are append-only from normal application workflows. + +### Mandatory Examples + +Engineering: + +```text +engineering.projects.create +engineering.projects.close +engineering.designs.approve +engineering.inspections.complete +``` + +Legal: + +```text +legal.matters.create +legal.matters.close +legal.conflicts.approve +``` + +Healthcare: + +```text +healthcare.records.read +healthcare.records.write +healthcare.records.sign +healthcare.records.amend +``` + +### Privacy / Erasure Handling + +Append-only audit does not mean "store unlimited personal data forever." + +Audit metadata must be minimized at write time. + +Where privacy, contractual, or retention obligations require removal of personally identifying material, use a governed privacy process such as: + +```text +pseudonymize actor references +null/remove nonessential PII fields +replace identifiers with irreversible privacy references where appropriate +retain the security/business event itself when permitted/required +``` + +The exact action depends on jurisdiction and retention policy and must be reviewed before healthcare/legal production. + +Do not place passwords, tokens, full clinical content, secret keys, or unnecessary payment data in audit metadata. + +REST: + +```http +GET /api/v1/audit-events +``` + +No public mutation endpoints. + +## 57. Domain Events and Transactional Outbox + +Use: + +```text +outbox_events +``` + +Fields: + +```text +id +organization_id nullable for truly global events + +event_type +aggregate_type +aggregate_id + +payload + +request_id nullable +correlation_id +causation_id nullable + +occurred_at +available_at +processed_at + +attempt_count +last_error +dead_lettered_at +``` + +`correlation_id` groups one logical workflow across requests/jobs/events. + +`causation_id` identifies the event/command that directly caused this event when applicable. + +Transaction: + +```text +BEGIN +business change +audit event +outbox event +COMMIT +``` + +Delivery semantics are at-least-once. + +Worker claim uses row locking such as: + +```sql +SELECT id +FROM outbox_events +WHERE processed_at IS NULL + AND dead_lettered_at IS NULL + AND available_at <= now() +ORDER BY occurred_at +FOR UPDATE SKIP LOCKED +LIMIT 100; +``` + +Every external side-effect consumer must be idempotent. + +`FOR UPDATE SKIP LOCKED` prevents simultaneous claiming; it does not prevent duplicate side effects after a worker crash. + +## 57A. Webhooks and External Integrations + +Shared tables: + +```text +webhooks +webhook_event_subscriptions +webhook_deliveries +``` + +### Webhook + +```text +id +organization_id +url +status +secret_ciphertext or signing_key_reference +created_by_user_id +created_at +updated_at +``` + +### Subscription + +```text +id +organization_id +webhook_id +event_type +created_at +``` + +Unique: + +```text +(organization_id, webhook_id, event_type) +``` + +Only registered externally publishable event types may be subscribed. + +### Delivery + +```text +id +organization_id +webhook_id +event_id + +attempt_number +request_timestamp +response_status +response_summary + +delivered_at +failed_at +next_attempt_at +``` + +`event_id` references `outbox_events.id`. Because webhook deliveries are tenant-owned, only publishable outbox events with the same non-null `organization_id` may be delivered: + +```text +(organization_id, event_id) +→ outbox_events(organization_id, id) +``` + +The webhook publisher allowlists externally publishable `event_type` values before creating delivery records. The stable outbox event ID is also the consumer deduplication key. + +Configuration REST: + +```http +GET /api/v1/webhooks +POST /api/v1/webhooks +GET /api/v1/webhooks/{webhookId} +PATCH /api/v1/webhooks/{webhookId} +DELETE /api/v1/webhooks/{webhookId} + +POST /api/v1/webhooks/{webhookId}/test +POST /api/v1/webhooks/{webhookId}/rotate-secret +``` + +Delivery REST: + +```http +GET /api/v1/webhook-deliveries +GET /api/v1/webhook-deliveries/{deliveryId} +POST /api/v1/webhook-deliveries/{deliveryId}/retry +``` + +If HMAC signing is used, signing material is encrypted/recoverable with managed key protection. + +A one-way secret hash is insufficient for outbound HMAC signing. + +Webhook consumers deduplicate using stable event IDs. + +## 58. Background Jobs + +Workers handle: + +```text +notifications +reports/PDFs +file scanning +document processing +imports +exports +bulk operations +webhooks +search indexing +large data operations +``` + +Use shared tenant-owned: + +```text +jobs +``` + +Fields: + +```text +id +organization_id +requested_by_user_id + +job_type +status + +input_reference +result_reference +progress_percent + +created_at +started_at +completed_at +failed_at + +error_code +error_summary +``` + +`input_reference` and `result_reference` are nullable typed JSONB reference envelopes, not arbitrary blobs or public URLs. Their schema is registered per `job_type`. + +Allowed reference kinds initially include: + +```text +document_version +object_storage_key +query_snapshot +job +``` + +Object-storage references contain internal storage keys; APIs generate time-limited signed URLs when access is authorized. Resource IDs inside an envelope are validated for tenant ownership when the job is created. Large inputs and outputs live in documents or object storage rather than inside the job row. + +States: + +```text +queued +running +completed +failed +cancelled +``` + +REST: + +```http +GET /api/v1/jobs/{jobId} +GET /api/v1/jobs/{jobId}/result +POST /api/v1/jobs/{jobId}/cancel +``` + +These endpoints are tenant-scoped through the standard: + +```http +X-Organization-Id +``` + +They do not need `/organizations/{id}/jobs` because the platform already chose header-based tenant context. + +Large import/export operations return: + +```http +202 Accepted +``` + +with a job ID. + +## 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. + +Defaults: + +```text +default limit = 25 +maximum limit = 100 +offset pagination = not supported +``` + +Example: + +```http +GET /api/v1/engineering/projects?limit=25 +``` + +Response: + +```json +{ + "data": [], + "meta": { + "pagination": { + "nextCursor": null, + "hasMore": false + } + } +} +``` + +Rules: + +```text +cursor is opaque +sort order must be deterministic +cursor encodes/represents the selected sort position +unsupported limits return validation errors rather than silent huge responses +``` + +## 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=0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d +``` + +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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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/reuse detection +server-side session revocation + +rate limiting +anti-automation controls + +RBAC +resource policies +credential-aware authorization +tenant isolation + +input validation +SQL injection protection + +signed object-storage URLs +file-content validation +malware scanning + +audit trails +secret management +encryption at rest + +dependency/image scanning + +request/correlation IDs +backup and restore testing +``` + +### Web Security / CORS + +ADR-009 defines environment-specific web security. + +Baseline requirements: + +```text +explicit CORS allowlist +no wildcard credentialed CORS +allowed methods/headers documented +preflight behavior tested +HSTS at the edge for production HTTPS +X-Content-Type-Options: nosniff +secure cookie attributes when cookies are used +CSP on browser frontends +frame-ancestor/clickjacking policy on frontends +referrer policy appropriate to the frontend +``` + +Security headers belong at the appropriate application/CDN/gateway layer. + +### Rate Limiting + +Policies are endpoint-specific and configurable. + +Return: + +```http +429 Too Many Requests +Retry-After: ... +``` + +### Secrets + +Production secrets live outside source control, preferably in managed secret/key systems. + +JWT signing keys support rotation. + +## 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 +``` + +### Core Metrics + +API: + +```text +api_requests_total +api_errors_total +api_request_duration_seconds +``` + +Authentication: + +```text +auth_login_attempts_total +auth_token_refresh_total +auth_refresh_reuse_detections_total +auth_sessions_revoked_total +``` + +Authorization/security: + +```text +cross_tenant_access_attempts_total +tenant_isolation_invariant_failures_total +authorization_denials_total +credential_policy_denials_total +rate_limit_events_total +``` + +Important distinction: + +```text +cross_tenant_access_attempt += +request attempted another tenant's resource +``` + +This may be a stale link, mistake, or attack. + +```text +tenant_isolation_invariant_failure += +our system nearly or actually created/returned cross-tenant data +``` + +That is a high-severity internal correctness/security incident. + +Outbox/jobs/webhooks: + +```text +outbox_events_pending +outbox_events_failed_total +outbox_processing_duration_seconds + +jobs_queued +jobs_failed_total +job_duration_seconds + +webhook_delivery_attempts_total +webhook_delivery_failures_total +webhook_delivery_latency_seconds +``` + +Database: + +```text +db_pool_active +db_pool_waiting +db_query_duration_seconds +db_transaction_duration_seconds +``` + +Business metrics may include: + +```text +engineering_projects_created_total +engineering_designs_approved_total +engineering_inspections_completed_total +invoices_issued_total +``` + +Avoid patient-specific or sensitive identifiers in metric labels. + +### Alerts + +Examples: + +```text +refresh token reuse detected +tenant isolation invariant failure +outbox backlog exceeds SLO +webhook failure spike +database pool saturation +error-rate spike +latency regression +backup failure +malware scanner unavailable +``` + +Thresholds are calibrated from real environments rather than copied from a review document. + +### SLOs + +Define by endpoint class. + +Interactive CRUD, reports, file orchestration, and background jobs should not share one arbitrary latency target. + +## 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 +``` + +### Property-Based Tests + +Use property-based testing for high-value domain state machines. + +Candidates: + +```text +engineering design lifecycle +engineering inspection lifecycle +invoice lifecycle +payment state transitions +membership/role invariants +``` + +Correct properties: + +```text +every successful transition ends in a valid state + +every forbidden transition is rejected + +terminal states reject prohibited actions + +required invariants survive every valid transition + +transition sequences never bypass required approval/credential rules +``` + +Do not assert that every random state/action pair succeeds. Many are supposed to fail. + +### Integration Tests + +Test: + +```text +repositories +tenant-aware foreign keys +PostgreSQL constraints +transactions +outbox persistence +idempotency persistence +cache invalidation +job persistence +webhook delivery persistence +``` + +### API Tests + +Every important endpoint covers: + +```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 creation +outbox creation +``` + +### Outbox Reliability / Chaos Tests + +Test: + +```text +worker crash before side effect +worker crash after side effect but before marking processed +two workers competing for same row +temporary dependency outage +retry/backoff behavior +dead-letter behavior +consumer idempotency +lost worker wake-up +replay +``` + +The dangerous scenario is: + +```text +external side effect succeeds +worker dies +event retries +``` + +Tests must prove the consumer does not create an unacceptable duplicate. + +### Tenant Security Tests + +Test both: + +```text +external cross-tenant access attempts +``` + +and: + +```text +internal cross-tenant data invariant failures +``` + +These are different classes of failure. + +### Performance Tests + +Create realistic profiles: + +```text +interactive reads +interactive writes +search +dashboard read models +reporting +file upload orchestration +outbox processing +webhook bursts +notification bursts +``` + +Measure: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +``` + +Set production SLO gates only after a realistic baseline exists. + +### Coverage + +Track code coverage. + +Do not treat a single percentage such as `90%` as proof of quality. + +Critical-path expectations are stronger: + +```text +all tenant-isolation paths tested +all financial commands tested +all regulated commands tested +all state transitions tested +all critical authorization policies tested +``` + +## 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 +session/token model +idempotency strategy +error taxonomy +OpenAPI skeleton +engineering state machines +migration conventions +threat model +initial ADRs +risk register +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +auth +sessions +refresh-token families +token rotation/revocation + +users +organizations +organization professions + +membership invitations +memberships +roles +permissions +authorization + +audit +outbox + +request context +idempotency +rate limiting +observability +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering clients +engineering client contacts +client archive/restore +``` + +### Phase 3: Engineering Projects + +Build: + +```text +projects +project members +project phases +activation/close/archive +``` + +### Phase 4: Work and Site Management + +Build: + +```text +tasks +task batch operations +sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +versions +categories +classification +retention references +signed uploads +multipart uploads +content verification +malware scanning +engineering document links +``` + +### Phase 6: Engineering Designs + +Build: + +```text +designs +assignments +versions +reviews +cancel/withdraw semantics +credential-aware approval +audit +outbox +idempotency +``` + +### Phase 7: Engineering Inspections + +Build: + +```text +inspection lifecycle +inspection outcome +findings +corrective work +follow-up inspections +attachments +audit +outbox +idempotency +``` + +### Phase 8: Time, Budgets, and Billing + +Build: + +```text +time entries +batch timesheet submission +project budgets when required +invoices +payments +financial idempotency +reconciliation +``` + +### Phase 9: Notifications, Jobs, and Webhooks + +Build: + +```text +notifications +email +async jobs +imports/exports +webhooks +delivery/retry +dead-letter handling +``` + +### Phase 10: Reporting and Search + +Build: + +```text +project status +overdue work +inspection status +billable time +revenue +outstanding invoices +dashboard read models +``` + +### Phase 11: Engineering Client Portal + +Build: + +```text +portal account invitations +external project grants +published project documents +client review/acceptance workflow +portal audit +portal-specific frontend +``` + +Do not expose professional approval actions to client portal accounts. + +### Phase 12: Legal Vertical + +Validate shared core against: + +```text +matters +cases +conflicts +deadlines +retainers +restricted access / ethical walls +``` + +### Phase 13: Healthcare Readiness and Vertical + +Before implementation: + +```text +healthcare threat model +privacy review +jurisdiction analysis +scope-of-practice policy +record signing/amendment model +retention model +audit requirements +``` + +### Estimation Rule + +These are dependency-ordered milestones. + +They are not calendar promises. + +Calendar estimates require: + +```text +team size +frontend/UX scope +cloud decisions +third-party providers +security requirements +QA capacity +domain-expert availability +``` + +## 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 uses UUIDv7. + +Supported implementation choices: + +```text +PostgreSQL 18+: + use native uuidv7() if database-generated identifiers are desired + +Earlier PostgreSQL: + generate UUIDv7 in the application or use a controlled extension +``` + +Database columns remain PostgreSQL `UUID`. + +The rule is consistency, not ideological loyalty to one generation layer. + +Do not silently fall back to UUIDv4 while documenting UUIDv7. + +### Production Migration Rules + +Use expand/contract: + +```text +1. add backward-compatible schema +2. deploy code supporting old + new schema +3. backfill/migrate +4. switch reads/writes +5. observe +6. remove obsolete schema later +``` + +For destructive changes: + +```text +backup/restore plan +compatibility window +production-like dry run +explicit approval +post-migration verification +``` + +Do not assume a destructive database migration can always be reversed by a simple down migration. + +Never use automatic ORM schema synchronization in production. + +## 91A. Architecture Decision Records + +v4 stops treating technology suggestions as automatically settled architecture. + +Create ADRs before implementation locks in: + +```text +ADR-001 Backend Framework +ADR-002 SQL / ORM / Query Layer +ADR-003 Queue Implementation +ADR-004 PostgreSQL Minimum Version +ADR-005 Error Format / RFC 9457 Compatibility +ADR-006 Rate-Limit Header Convention +ADR-007 Webhook Signing Strategy +ADR-008 Object Storage Provider / Multipart Strategy +ADR-009 Web Security / CORS / Browser Headers +ADR-010 Machine Authentication / API Key Policy +``` + +Each ADR should include: + +```text +context +decision +alternatives considered +tradeoffs +security impact +operational impact +migration/exit path +date +status +``` + +The architecture currently fixes capabilities and boundaries. + +It does not require a framework merely because a review document described it positively. + +--- + +## 92. Technology Recommendation + +The following are preferred candidates, not all final decisions. + +### Fixed Platform Choices + +```text +API style: REST +Contract: OpenAPI 3.1 +Primary language: TypeScript +Primary database: PostgreSQL +Architecture: Modular Monolith +Observability standard: OpenTelemetry +Object storage model: S3-compatible +Container model: Docker/OCI +``` + +### ADR-Gated Choices + +Backend framework candidates: + +```text +NestJS +Fastify-centered custom application structure +``` + +SQL / persistence candidates: + +```text +Drizzle +Kysely +Prisma +direct SQL for specialized queries +``` + +Queue candidates: + +```text +BullMQ / Redis +managed cloud queue +``` + +PostgreSQL baseline: + +```text +PostgreSQL 18+ +``` + +is attractive because of native UUIDv7 and current capabilities, but the minimum supported version must be confirmed against: + +```text +hosting provider availability +operations policy +extension requirements +upgrade policy +support lifecycle +``` + +Do not claim one ORM is categorically "faster" or "better" without workload-specific evidence. + +The selected stack should preserve: + +```text +transaction control +explicit SQL visibility +tenant-safe query design +migration control +observability +testability +``` + +## 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 API contract. +4. GraphQL is not part of v1. +5. Start as one modular monolith backend. +6. Each profession has its own frontend. +7. Each profession owns its domain tables and state machines. +8. Shared modules provide infrastructure, not forced domain abstractions. +9. Public serialized IDs are raw UUIDv7. +10. Database ID columns use PostgreSQL UUID. +11. Human-readable business references are separate from resource IDs. +12. Every tenant-owned row carries direct `organization_id`. +13. Tenant-scoped requests require explicit `X-Organization-Id`. +14. Tenant boundaries are enforced in queries and database constraints. +15. Cross-tenant resources appear nonexistent. +16. API JSON/query parameter names use camelCase; DB identifiers use snake_case. +17. Authorization is server-side and deny-by-default. +18. `assigned` scope is defined per resource policy, never inferred generically. +19. Roles and professional credentials are separate. +20. A professional profile may own multiple credentials. +21. Sessions and refresh tokens are separate resources. +22. Refresh tokens rotate within families and support reuse detection. +23. Machine identities use service accounts/API keys, not fake human memberships. +24. Important domain transitions use explicit REST command endpoints. +25. High-risk commands use durable idempotency. +26. Batch custom actions use `/{collection}/batch/{action}`. +27. Every batch defines atomic or partial semantics. +28. Every batch item receives independent authorization/domain validation. +29. Large batches become asynchronous jobs. +30. Project phases are authoritative; duplicated project `stage` is not stored. +31. Project budgets use the dedicated budget model; project `budget_minor` is not authoritative. +32. Engineering time entries may attribute time to one explicit primary work item using tenant- and project-consistent composite foreign keys. +33. Design versions and engineering specifications use explicit document-link tables with one-to-many cardinality. +34. All design/review/version/finding/follow-up subresources carry `organization_id`. +35. Inspection lifecycle and inspection outcome are separate. +36. Inspection follow-ups are explicit resources. +37. Engineering change requests remain deferred until fully specified. +38. Shared documents own document records; profession modules own link tables. +39. Legal does not duplicate shared document ownership. +40. Large files use object-storage multipart uploads. +41. Application servers do not proxy multi-gigabyte chunks. +42. Document checksums belong to document versions. +43. Document classification is multi-level. +44. Document retention is explicit policy. +45. Document category uniqueness must work for nullable profession values on the selected PostgreSQL version. +46. Project document linkage does not imply client-portal publication. +47. External publication requires explicit publication records. +48. Client portal accounts are not internal memberships. +49. Client acceptance is not professional engineering approval. +50. Domain events use a transactional outbox. +51. Outbox delivery is at-least-once. +52. Outbox events carry correlation/causation identifiers. +53. External side-effect consumers are idempotent. +54. Webhook subscriptions and deliveries are tenant-owned. +55. HMAC signing secrets are securely recoverable/encrypted, not only hashed. +56. Jobs are tenant-scoped by the standard organization header. +57. PostgreSQL is the authoritative transactional datastore. +58. Redis is acceleration/coordination, not critical source of truth. +59. Search starts with PostgreSQL. +60. Collections use cursor pagination, default 25 and max 100. +61. Important mutable resources use optimistic concurrency. +62. Database entities are not serialized directly. +63. Errors use stable codes. +64. `429` responses use `Retry-After`; exact quota headers are an API decision. +65. Business records use explicit archive/revoke/unlink/hard-delete lifecycle policies. +66. Financial/professional/audit records are not casually hard-deleted. +67. Audit metadata is minimized and supports governed privacy transformation when required. +68. Important/regulated actions are audited. +69. Signed clinical records use sign/amend/version workflows. +70. Prescribing authority remains jurisdiction/scope-of-practice policy. +71. Production migrations use expand/contract. +72. Destructive changes are not assumed trivially reversible. +73. Secrets remain outside source control. +74. CORS and browser security policy are explicit ADR/configuration. +75. Rate limits are calibrated by evidence. +76. CI validates types, tests, OpenAPI, migrations, and security checks. +77. Property-based tests cover high-value state machines. +78. Outbox/job/webhook reliability is tested under failure/concurrency. +79. Critical-path tests matter more than vanity coverage percentages. +80. Framework/ORM/queue/PostgreSQL-minimum choices require ADRs. +81. Engineering is the first vertical. +82. Client portal follows internal Engineering MVP foundations. +83. Legal follows after Engineering validates shared assumptions. +84. Healthcare requires dedicated privacy/security/domain design before implementation. +85. Architecture documentation never equates "designed for" with "certified/compliant". + +## 95. Required Design Artifacts + +Maintain: + +```text +01_PROJECT_ARCHITECTURE.md +02_DATABASE_CONVENTIONS.md +03_AUTHORIZATION_MODEL.md +04_AUTH_SESSION_MODEL.md + +05_ENGINEERING_DOMAIN.md +06_ENGINEERING_DATABASE_SCHEMA.md +07_ENGINEERING_STATE_MACHINES.md + +08_API_CONVENTIONS.md +09_ENGINEERING_API_SPEC.md +10_OPENAPI.yaml + +11_FRONTEND_ARCHITECTURE.md +12_CLIENT_PORTAL_SECURITY_MODEL.md + +13_DOCUMENT_SECURITY_MODEL.md +14_LARGE_FILE_UPLOAD_MODEL.md + +15_WEBHOOK_INTEGRATION_MODEL.md +16_ASYNC_JOB_MODEL.md + +17_SECURITY_MODEL.md +18_DEPLOYMENT_ARCHITECTURE.md +19_OBSERVABILITY_MODEL.md +20_TESTING_STRATEGY.md + +21_ARCHITECTURE_DECISION_RECORDS/ +22_RISK_REGISTER.md +23_MVP_BACKLOG.md +``` + +Important ADRs: + +```text +backend framework +persistence/query layer +queue implementation +PostgreSQL minimum version +error format +rate-limit headers +webhook signing +object-storage provider +``` + +## 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 need efficient tenant scoping. + +Baseline: + +```text +(organization_id, id) +``` + +Common list access often benefits from: + +```text +(organization_id, created_at) +``` + +Query-specific examples: + +```text +(organization_id, status) +(organization_id, client_id) +(organization_id, project_id) +(organization_id, assigned_to_user_id) +``` + +### Rules + +1. every index corresponds to a known query, ordering, or constraint +2. column order follows real predicates +3. validate with `EXPLAIN (ANALYZE, BUFFERS)` +4. include production-like cardinality in testing +5. measure write amplification +6. do not index every field +7. introduce trigram/full-text indexes only for actual search requirements + +Potential later tools: + +```text +covering indexes +materialized views +read replicas +table partitioning +external search +``` + +These are evidence-driven scaling mechanisms, not baseline dependencies. + +### Document Category Uniqueness + +If a nullable field such as profession participates in uniqueness: + +```text +organization_id +profession nullable +name +``` + +do not assume plain uniqueness treats NULL as one shared value. + +Use PostgreSQL-supported null-aware uniqueness or partial unique indexes according to the selected PostgreSQL version. + +--- + +## 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. + + +### Feature Flags + +Feature flags used for deployment safety are operational configuration, not automatically a business database table. + +Initial implementation may use: + +```text +environment/config-service flags +``` + +for global rollout and kill switches. + +If per-organization feature rollout is later required, introduce an explicit tenant-owned model such as: + +```text +organization_feature_flags +``` + +through an ADR/migration. + +Do not overload `organization_professions` with unrelated product experiments. + + +### 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. + +--- + +## 97D. Provisional Performance Objectives + +Performance numbers in architecture are starting hypotheses, not guarantees. + +Initial engineering objectives may begin with: + +```text +Interactive read: + target p95 <= 500 ms + +Interactive mutation: + target p95 <= 750 ms + +Simple list/search: + target p95 <= 800 ms + +Upload authorization: + target p95 <= 300 ms + +Background outbox pickup: + target <= 5 seconds under normal operating conditions +``` + +These are revised after realistic testing. + +Track: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +outbox lag +``` + +Different endpoint classes receive different SLOs. + +Do not use file-transfer completion time as an API SLO when bytes travel directly between client and object storage. + +--- + +## 97E. Risk Register + +Maintain a living risk register. + +Suggested structure: + +| Risk | Impact | Mitigation | Owner | Phase | Status | +|---|---|---|---|---|---| +| Cross-tenant data exposure | Critical | Tenant-aware FKs, scoped queries, security tests | Backend/Security | P0 | Open | +| Non-idempotent outbox side effect | Critical | Consumer dedupe, provider idempotency, chaos tests | Backend | P0 | Open | +| Migration failure | High | Expand/contract, dry runs, backups | Backend/Platform | P0 | Open | +| Engineering workflow mismatch | High | Domain expert validation | Product/Engineering SME | MVP | Open | +| Portal authorization leak | Critical | Separate external access model, publication grants | Backend/Security | Portal | Open | +| Webhook delivery instability | Medium | Retry, dead-letter, replay, metrics | Backend | Integrations | Open | +| Large upload abandonment | Medium | Multipart expiry and cleanup | Backend/Platform | Documents | Open | +| Documentation drift | Medium | OpenAPI validation, ADRs, CI | Engineering | Continuous | Open | + +Do not pretend likelihood labels are quantitative unless the team defines and uses a scoring method. + +--- + +## 97F. Architecture Change Governance + +v4 is the last broad platform-architecture revision before Engineering MVP implementation. + +New discoveries should normally become: + +```text +ADR +OpenAPI change +database migration +domain-state-machine update +security decision +backlog item +runbook +``` + +rather than a new full architecture rewrite. + +Reopen the broad architecture only when a discovery invalidates one of these foundational assumptions: + +```text +tenant model +profession separation +shared-core boundary +REST API model +data ownership +security trust boundary +deployment topology +database architecture +``` + +This prevents design review from becoming an infinite recursion problem. + +--- + +## 97G. Production Readiness Gates + +Architecture being coherent does not mean production is safe. + +Before production, require evidence in these categories. + +### Security + +```text +TLS configured +password hashing configured +refresh rotation/reuse detection tested +session revocation tested +tenant isolation tests passing +authorization/credential policies tested +rate limiting active +secrets managed outside source control +file security scanning active +security review completed +``` + +### Reliability + +```text +database backups automated +restore tested +object storage recovery strategy tested +outbox monitoring active +job queue monitoring active +webhook retry/dead-letter behavior tested +health checks configured +dependency failures tested +``` + +### Data Integrity + +```text +tenant-aware foreign keys present where required +financial invariants tested +migration tested on production-like data +idempotency tested for high-risk commands +optimistic concurrency tested +audit integrity tested +``` + +### Contract / API + +```text +OpenAPI validates +contract tests pass +error schema consistent +versioning rules documented +client SDK generation validated if used +``` + +### Performance + +```text +load test executed +realistic SLOs defined +database pool configured +key queries analyzed +outbox/job backlogs remain within SLO +``` + +### Critical Domain Coverage + +Rather than a magic overall coverage number, require explicit test coverage for: + +```text +tenant boundaries +design approval +inspection completion +invoice issue +payment/refund +membership privilege changes +clinical record signing/amendment when healthcare exists +prescribing authorization when healthcare exists +``` + +### Release Gate Principle + +No single metric such as: + +```text +90% test coverage +``` + +is sufficient evidence of production readiness. + +Quality gates are based on critical behavior, not vanity percentages. + +--- + +## 97. Final Design Position + +The platform is: + +```text +One Shared Platform + │ + ├── Shared Identity / Sessions + ├── Shared Security / Authorization + ├── Shared Documents / Multipart Uploads + ├── Shared Financial Core + ├── Shared Audit / Outbox + ├── Shared Jobs / Webhooks / Notifications + │ + ├── Engineering Internal Product + │ ├── Engineering Frontend + │ ├── Engineering REST APIs + │ ├── Engineering State Machines + │ └── Engineering Tables + │ + ├── Engineering Client Portal + │ ├── External Portal Frontend + │ ├── Portal Accounts + │ ├── Project Grants + │ ├── Published Documents + │ └── Client Review / Acceptance + │ + ├── Legal Product + │ ├── Legal Frontend + │ ├── Legal REST APIs + │ └── Legal Tables + │ + └── Healthcare Product + ├── Healthcare Frontend + ├── Healthcare REST APIs + ├── Healthcare Security Policies + └── Healthcare Tables +``` + +The system shares infrastructure where reuse is valuable while preserving profession-specific domain semantics and trust boundaries. + +v4 is the final broad architecture baseline for Engineering MVP implementation. + +From this point forward, architecture detail should primarily move into: + +```text +ADRs +OpenAPI +database schema/migrations +state-machine specifications +security policies +implementation backlog +runbooks +``` + +rather than repeatedly rewriting the entire architecture plan. + +This document does not itself prove: + +```text +regulatory compliance +production certification +security certification +performance at a specific scale +``` + +Those require implementation evidence, security review, domain validation, operational testing, restore testing, and measured production-like workloads. + + + + +--- + +# v4.1 Changelog + +v4.1 resolves implementation-contract issues without changing the core architecture. + +```text +✓ raw UUIDv7 API ID contract +✓ camelCase API / snake_case database naming convention +✓ direct organization_id on tenant subresources +✓ invitation role assignments +✓ service accounts and hashed API keys +✓ multiple professional credentials per profile +✓ global archive/revoke/unlink/hard-delete policy +✓ project stage duplication removed +✓ project budget_minor removed +✓ project phase reorder command +✓ global engineering site listing +✓ task status and priority vocabularies +✓ design revise endpoint +✓ design-version many-document cardinality +✓ design review/version tenant keys +✓ inspection finding tenant keys +✓ explicit inspection follow-up table +✓ change requests deferred until fully specified +✓ time-entry work-item attribution +✓ time-entry project/work-item consistency constraints +✓ specification many-document cardinality and status values +✓ legal_documents duplication removed +✓ legal matter/case document-link schemas +✓ healthcare placeholder schemas clarified +✓ invoice-item schema defined +✓ document retention-policy schema +✓ explicit retention-period null semantics +✓ version-independent document-category uniqueness fallback +✓ standard upload DTO +✓ multipart-init/parts/complete DTOs +✓ webhook subscription schema +✓ webhook delivery references outbox events +✓ typed job input/result references +✓ logout endpoint +✓ assigned-scope resolution rules +✓ audit privacy transformation strategy +✓ outbox correlation and causation IDs +✓ CORS/browser-security ADR +✓ feature-flag strategy clarified +✓ jobs confirmed tenant-scoped via X-Organization-Id +``` + +The next artifacts should be implementation-specific: + +```text +ADRs +Engineering OpenAPI +Engineering database migrations +Engineering state-machine spec +Engineering MVP backlog +``` diff --git a/professional_management_platform_rest_plan_v4_5.md b/professional_management_platform_rest_plan_v4_5.md new file mode 100644 index 0000000..104dfb0 --- /dev/null +++ b/professional_management_platform_rest_plan_v4_5.md @@ -0,0 +1,7236 @@ +# Professional Management Platform +## Full REST-First System Design Plan + +> **Revision:** v4.1 — Consistency and Implementation-Contract Cleanup +> **Status:** Locked broad architecture baseline with implementation-blocking contradictions resolved. Subsequent detail belongs in ADRs, OpenAPI, migrations, domain specifications, and backlog items. +> **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 + +### v4.1 Cleanup Notes + +v4.1 does not redesign the platform. It resolves contradictions and fills implementation contracts discovered during detailed review. + +Resolved: + +- raw UUIDv7 is now the serialized/API identifier format +- database columns remain UUID; prefixed strings are not public IDs +- all tenant-owned subresources carry direct `organization_id` +- design-version document cardinality is explicit and relational +- engineering time entries can be attributed to a specific work item +- time-entry work-item links are constrained to the time entry's project +- engineering specifications use explicit many-document link records +- project-level `budget_minor` is removed in favor of the dedicated budget model +- duplicate `legal_documents` ownership is removed +- legal matter/case document-link schemas are defined +- batch custom-action paths use one documented convention +- membership invitations can pre-assign multiple roles +- missing design `revise` command is added +- inspection follow-ups now have a table and lifecycle +- change requests are moved out of the initial Engineering schema until specified +- service accounts and API keys are defined for machine access +- service-account role assignments have an explicit relational schema +- design assignments, portal review requests, inspection documents, payments, and refunds have explicit schemas +- shared billing accounts replace vague or polymorphic invoice references +- resource status and type vocabularies required by migrations/OpenAPI are defined +- API JSON, query parameters, and path parameter names use camelCase; database columns use snake_case +- professional profiles support multiple professional credentials +- deletion/archival/revocation/unlink behavior is globally defined +- invoice-item fields are specified +- deferred healthcare placeholder tables receive minimum schemas or explicit deferral notes +- document upload and multipart DTOs are defined +- webhook subscription fields are defined +- `POST /auth/logout` is restored +- portal review-request and portal capability schemas are defined +- project-role, task-status, priority, and inspection-outcome values are defined +- document-category uniqueness has a version-independent fallback +- retention policy fields are defined +- retention-period null semantics are explicit +- pagination defaults are explicit +- `assigned` authorization scope has resource-specific resolution rules +- feature-flag behavior is clarified +- audit privacy minimization/anonymization strategy is documented +- outbox correlation and causation IDs are added +- webhook delivery event references and job reference envelopes are defined +- CORS and web-security configuration is moved into a required ADR +- project `stage` duplication is removed; project phases remain authoritative +- phase reordering, site listing, appointment locations, and encounter reason fields are clarified +- jobs remain tenant-scoped through the standard organization header rather than path nesting +- job types use a registered handler-and-schema vocabulary + +--- +--- +--- +--- + +## 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: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +X-Request-Id: 0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff +Content-Type: application/json +``` + +### API Naming Convention + +Public API representation: + +```text +JSON properties: camelCase +query parameters: camelCase +path parameter names in documentation: camelCase +HTTP headers: conventional HTTP header casing +``` + +Database representation: + +```text +table names: snake_case +column names: snake_case +constraint/index names: snake_case +``` + +Example: + +```http +GET /api/v1/engineering/tasks?assignedToUserId=&createdAfter=2026-08-01T00:00:00Z +``` + +```json +{ + "assignedToUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "createdAt": "2026-08-26T12:00:00Z" +} +``` + +maps internally to columns such as: + +```text +assigned_to_user_id +created_at +``` + +### Organization Context + +`X-Organization-Id` is mandatory for every tenant-scoped endpoint. + +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: + +```yaml +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_mismatch: + status: 404 + code: RESOURCE_NOT_FOUND +``` + +### Idempotency + +Use: + +```http +Idempotency-Key: 8f7d6c5e-4b3a-4b1c-9d8e-7f6a5b4c3d2e +``` + +Required where duplicate execution can create material side effects. + +PostgreSQL is authoritative for critical idempotency records. + +Redis may accelerate lookup. + +### Batch Custom-Action Convention + +For collection-level custom commands use: + +```text +/{collection}/batch/{action} +``` + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete +POST /api/v1/engineering/time-entries/batch/submit +``` + +Do not mix `batch-assign`, colon-style custom methods, and `/batch/assign` in the same API. + +### Rate-Limit Responses + +```http +429 Too Many Requests +Retry-After: +``` + +Additional rate-limit metadata may be exposed according to the selected gateway/standard. + +Do not freeze legacy `X-RateLimit-*` names here. + +### Error Standard Decision + +The current error envelope remains: + +```json +{ + "error": { + "code": "RESOURCE_NOT_FOUND", + "message": "Resource not found.", + "details": {}, + "requestId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cff" + } +} +``` + +ADR-005 decides whether OpenAPI v1 aligns this with RFC 9457 Problem Details. + +Do not silently change the envelope during implementation. + +## 9. Standard Response Format + +Single resource: + +```json +{ + "data": { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c6d", + "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. + +--- + +## 11A. Identifier Convention + +The serialized identifier standard is **raw UUIDv7**. + +Example: + +```text +0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d +``` + +Database: + +```sql +id UUID PRIMARY KEY +``` + +API: + +```json +{ + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c1d" +} +``` + +Do not serialize IDs as: + +```text +org_ +user_ +project_ +``` + +unless a future ADR explicitly changes the public identifier contract. + +Human-friendly resource references use separate fields such as: + +```text +projectNumber +matterNumber +patientNumber +invoiceNumber +``` + +This separates machine identity from business/display references. + +UUID generation is decided by ADR-004: + +```text +PostgreSQL-native UUIDv7 when supported and selected +or +application-generated UUIDv7 +``` + +The API format is identical either way. + +--- + +## 12. Authentication + +Initial human authentication: + +```text +Email ++ +Password ++ +Short-Lived Access Token ++ +Opaque Refresh Token ++ +Server-Side Session +``` + +REST: + +```http +POST /api/v1/auth/register +POST /api/v1/auth/login +POST /api/v1/auth/logout + +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 +``` + +`POST /auth/logout` revokes the current session. + +`DELETE /auth/sessions/{sessionId}` allows a user to revoke a specific session, such as another device. + +### Access Token + +```yaml +format: JWT +lifetime: short-lived +signed: true +encrypted: false +claims: + - sub + - sessionId + - issuer + - audience + - issuedAt + - expiresAt +``` + +Organization context is not trusted from the token as authorization authority. + +### Sessions + +```text +sessions +├── id +├── user_id +├── device metadata +├── created_at +├── last_active_at +├── expires_at +├── revoked_at +└── revocation_reason +``` + +### Refresh Tokens + +```text +refresh_tokens +├── id +├── session_id +├── family_id +├── token_hash +├── issued_at +├── expires_at +├── rotated_at +├── replaced_by_token_id +├── revoked_at +└── revocation_reason +``` + +Constraints/indexes: + +```text +UNIQUE(token_hash) +INDEX(family_id) +INDEX(session_id) +``` + +`family_id` is not unique. + +### Refresh Reuse Detection + +Use of a previously rotated token triggers: + +```text +revoke token family +revoke affected session +security audit event +reauthentication +``` + +Policy may escalate to all-session revocation. + +Future human authentication: + +- MFA +- WebAuthn/passkeys +- OIDC/SSO +- enterprise identity providers + + +## 12A. Service Accounts and API Keys + +Machine-to-machine access is separate from human sessions. + +Use: + +```text +service_accounts +api_keys +service_account_roles +``` + +### Service Account + +Suggested fields: + +```text +id +organization_id +name +description +status +created_by_user_id +created_at +updated_at +revoked_at +``` + +Service-account status values: + +```text +active +revoked +``` + +### API Key + +Suggested fields: + +```text +id +organization_id +service_account_id + +key_prefix +secret_hash + +created_at +expires_at +last_used_at +revoked_at +revocation_reason +``` + +Raw API-key secrets are shown only once. + +Store only a secure hash of the secret. + +`key_prefix` is safe display material for identifying a key in administration screens. + +### Service Account Role + +`service_account_roles` uses the same organization-scoped role registry as human RBAC assignments. + +Suggested fields: + +```text +id +organization_id +service_account_id +role_id +created_at +``` + +Unique: + +```text +(organization_id, service_account_id, role_id) +``` + +Tenant-safe foreign keys require the service account and role to belong to the same organization as the assignment. + +### Authorization + +Service accounts use explicit organization-scoped permissions, preferably through: + +```text +service_account_roles +``` + +with the same registered permission vocabulary used by RBAC. + +They do not become fake human memberships. + +### Audit + +Audit actors support: + +```text +actor_type = user +actor_type = service_account +actor_type = system +``` + +Machine authentication is required when public/integration API access is implemented; it does not block the earliest internal Engineering UI slice. + +--- + +## 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 +``` + +Organization status values: + +```text +active +suspended +pending_deletion +``` + +--- + +## 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 +``` + +User status values: + +```text +active +inactive +pending_verification +``` + +Membership status values: + +```text +active +inactive +pending +``` + +--- + +## 17. Membership Invitations + +Keep invitations separate from memberships. + +Tables: + +```text +membership_invitations +membership_invitation_roles +``` + +`membership_invitations`: + +```text +id +organization_id +email +invited_by_user_id +expires_at +accepted_at +revoked_at +created_at +``` + +`membership_invitation_roles`: + +```text +organization_id +invitation_id +role_id +created_at +``` + +Use tenant-aware foreign keys so invitation roles cannot reference another organization's role. + +Flow: + +```text +Invitation + Intended Roles + ↓ + Accepted + ↓ + User + ↓ + Membership + ↓ + Membership Roles +``` + +At acceptance: + +1. validate invitation token and expiry +2. validate invited email/account policy +3. create membership +4. copy valid intended roles to membership-role assignments +5. mark invitation accepted +6. audit +7. emit outbox event + +If an intended role was revoked/deleted before acceptance, acceptance fails safely or drops that role according to explicit organization policy. + +## 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 +``` + +Example: + +```text +Engineer: +engineering.projects.read = assigned + +Principal Engineer: +engineering.projects.read = organization +``` + +`assigned` is not magic. Each resource policy defines how assignment is resolved. + +### Engineering Project + +Assigned when: + +```text +engineering_project_members.user_id = ctx.userId +AND engineering_project_members.left_at IS NULL +``` + +or when the user is the active project manager, if project-manager assignment is modeled separately. + +### Engineering Task + +Assigned when: + +```text +engineering_tasks.assigned_to_user_id = ctx.userId +``` + +For tasks linked to a project, parent-project access may also be required. + +### Engineering Design + +Assigned when an active row exists in: + +```text +engineering_design_assignments +``` + +for the user and an allowed assignment role. + +### Engineering Inspection + +Assigned when: + +```text +engineering_inspections.inspector_user_id = ctx.userId +``` + +or an explicit inspection assignment exists if the model later supports multiple inspectors. + +### Derived Client Access + +An assigned professional may access a client only through a policy that derives access from authorized projects. + +Project assignment must not automatically grant access to every project belonging to that client. + +Future scopes may include: + +```text +owned +team +department +restricted +``` + +Do not add them before a real workflow requires them. + +## 21. Professional Credentials + +Professional identity and credentials are separate from RBAC. + +Use: + +```text +professional_profiles +professional_credentials +``` + +### Professional Profile + +One organization/user/profession relationship. + +Suggested fields: + +```text +id +organization_id +user_id +profession +title +status +created_at +updated_at +``` + +Professional-profile status values: + +```text +active +suspended +inactive +``` + +Credential expiry is represented by credential status and `expires_at`; a profile itself does not become `expired` merely because one credential expires. + +### Professional Credential + +One profile may hold many credentials. + +Suggested fields: + +```text +id +organization_id +professional_profile_id + +credential_type +credential_number +issuing_authority +jurisdiction +discipline + +status +valid_from +expires_at + +verified_at +verified_by_user_id + +created_at +updated_at +``` + +Professional-credential status values: + +```text +pending_verification +active +suspended +expired +revoked +``` + +Examples: + +```text +professional engineering license in jurisdiction A +professional engineering license in jurisdiction B +specialty certification +medical license +controlled-substance prescribing registration where applicable +``` + +Credential policy evaluates the set of active credentials rather than one `primary_license_number`. + +High-risk actions such as design approval, record signing, or prescribing use authoritative or revocation-aware credential state. + +Prescribing remains jurisdiction/scope-of-practice policy, not a hard-coded profession test. + +## 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 +service_accounts +api_keys +service_account_roles + +memberships +membership_invitations + +roles +permissions +role_permissions +membership_roles + +professional_profiles +professional_credentials + +documents +document_versions +document_categories +retention_policies + +billing_accounts +invoices +invoice_items +payments +payment_refunds + +notifications +notification_deliveries + +audit_events +outbox_events + +webhooks +webhook_event_subscriptions +webhook_deliveries +jobs +``` + +--- + +## 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. + +--- + +## 21A. Deletion, Archival, Revocation, and Unlink Policy + +`DELETE` does not have one universal persistence meaning. + +Use four lifecycle behaviors. + +### Archive / Domain Inactivation + +For business records whose history matters: + +```text +engineering clients +engineering projects +legal matters +healthcare patients +documents where retention requires history +``` + +Typical fields: + +```text +status +archived_at +archived_by_user_id +``` + +Restore is permitted only when domain, retention, and organization policy allow it. + +### Revoke + +For access/security resources: + +```text +sessions +refresh tokens +API keys +membership invitations +portal grants +webhook credentials +``` + +Use: + +```text +revoked_at +revoked_by +revocation_reason +``` + +### Temporal Unlink + +For relationship records where the historical relationship matters: + +```text +project documents +project members +design assignments +portal document publications +``` + +Use: + +```text +unlinked_at +left_at +unassigned_at +revoked_at +``` + +rather than deleting historical evidence. + +### Hard Delete + +Reserved for genuinely disposable or never-committed data, such as: + +```text +expired pending upload artifacts +failed temporary staging objects +unreferenced draft configuration where audit/retention does not require history +``` + +Hard deletion of financial, professional, audit, signed clinical, or issued business records is forbidden unless an explicit retention/privacy policy defines the operation. + +Every resource specification must declare its lifecycle behavior. + +--- + +# Engineering Domain + +## 26. Engineering Tables + +Initial Engineering MVP tables: + +```text +engineering_clients +engineering_client_contacts + +engineering_projects +engineering_project_members +engineering_project_phases +engineering_sites +engineering_tasks + +engineering_designs +engineering_design_assignments +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews + +engineering_inspections +engineering_inspection_findings +engineering_inspection_followups +engineering_inspection_documents + +engineering_specifications +engineering_specification_documents + +engineering_time_entries +engineering_client_billing_accounts +engineering_invoice_projects +engineering_invoice_item_time_entries +``` + +Later Engineering extensions: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries + +engineering_change_requests +``` + +`engineering_change_requests` is not part of the initial schema until its lifecycle, relationships, and REST contract are specified. + +## 27. Engineering Clients + +Suggested core client fields: + +```text +id +organization_id +client_type +display_name +legal_name +status +created_at +updated_at +version +``` + +Initial `client_type` values: + +```text +corporate +government +individual +``` + +Engineering-client status values: + +```text +active +archived +``` + +Do not permanently squeeze all contacts into one `email`, one `phone`, and one `contact_name`. + +Engineering customers commonly have multiple: + +```text +technical contacts +billing contacts +executive contacts +site contacts +contract contacts +``` + +Use: + +```text +engineering_client_contacts +``` + +Suggested contact fields: + +```text +id +organization_id +client_id + +name +title +department + +email +phone + +contact_type +is_primary + +created_at +updated_at +``` + +Client 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 +``` + +Contact REST: + +```http +GET /api/v1/engineering/clients/{clientId}/contacts +POST /api/v1/engineering/clients/{clientId}/contacts +PATCH /api/v1/engineering/clients/{clientId}/contacts/{contactId} +DELETE /api/v1/engineering/clients/{clientId}/contacts/{contactId} +``` + +Delete may be implemented as archival when contact history matters. + +Client restore is allowed only when organization policy and retention rules permit it. + +## 27A. Engineering Client Portal + +External clients are not internal organization members. + +Use shared authentication identities where practical, but create a separate authorization boundary. + +```text +User + │ + ├── Internal Membership + │ ↓ + │ Organization Staff Access + │ + └── Client Portal Account + ↓ + Engineering Client Contact + ↓ + Project Access Grants +``` + +Suggested tables: + +```text +engineering_client_portal_accounts +engineering_client_portal_project_grants +engineering_project_document_publications +engineering_client_review_requests +``` + +### Portal Account + +Suggested fields: + +```text +id +organization_id +user_id +engineering_client_contact_id + +status + +invited_by_user_id +invited_at +accepted_at + +revoked_at +revoked_by_user_id +``` + +Portal-account status values: + +```text +invited +active +expired +revoked +``` + +Portal accounts are not placed in `memberships`. + +### Project Grant + +Suggested fields: + +```text +id +organization_id +portal_account_id +project_id + +access_profile + +granted_by_user_id +granted_at +expires_at +revoked_at +``` + +Initial `access_profile` values and capabilities: + +```text +viewer + project.status.read + project.documents.read_published + +contributor + all viewer capabilities + project.comments.create + project.files.submit + +reviewer + all contributor capabilities + client_review.respond +``` + +Capabilities are assigned through the three profiles above in v1; callers cannot submit an arbitrary capability list. + +The access model may later normalize capabilities into a grant table if simple profiles become insufficient. + +### Client Review Request + +`engineering_client_review_requests` fields: + +```text +id +organization_id +project_id +design_id nullable +portal_account_id + +requested_by_user_id +status +response nullable +response_notes nullable + +requested_at +responded_at nullable +created_at +updated_at +version +``` + +Status values: + +```text +pending +responded +withdrawn +expired +``` + +Response values: + +```text +accepted +changes_requested +declined +``` + +Only a portal account with an active grant for the same project and the `client_review.respond` capability may respond. A response sets `status = responded`, `response`, and `responded_at` atomically. Client responses never perform professional engineering approval. + +### Separate Frontend + +Recommended: + +```text +apps/ +├── engineering-web/ +└── engineering-client-portal/ +``` + +The internal engineering frontend and external portal do not share authorization assumptions. + +### Client Acceptance Is Not Engineering Approval + +Never represent client acceptance with: + +```text +engineering.designs.approve +``` + +Professional engineering approval is reserved for qualified internal/authorized professionals. + +Client-facing review should use separate concepts such as: + +```text +engineering.client_reviews.request +engineering.client_reviews.respond +engineering.client_reviews.accept +engineering.client_reviews.request_changes +``` + +Example: + +```http +POST /api/v1/engineering/client-review-requests/{reviewId}/accept +POST /api/v1/engineering/client-review-requests/{reviewId}/request-changes +``` + +A client acceptance may be commercially meaningful without being a professional engineering approval. + +### Portal Security Rules + +1. portal access is deny-by-default +2. every portal request remains organization-scoped +3. portal users only access explicitly granted projects +4. project membership does not apply to portal users +5. internal RBAC roles do not automatically apply to portal users +6. portal account revocation is immediate +7. portal grants may expire +8. sensitive document access requires explicit publication +9. portal activity is audited according to organization policy +10. professional approval endpoints are never exposed through portal grants + +--- + +## 27B. External Document Publication + +A document being linked to an engineering project does **not** make it externally visible. + +Use: + +```text +engineering_project_document_publications +``` + +Suggested fields: + +```text +id +organization_id + +project_document_link_id + +audience_type +portal_account_id nullable +client_id nullable + +published_by_user_id +published_at + +expires_at +revoked_at +revoked_by_user_id +``` + +Possible audiences: + +```text +all_active_client_portal_accounts_for_project +specific_portal_account +specific_client_contact +``` + +External download checks: + +```text +authenticated portal user ++ +active portal account ++ +active project grant ++ +active document publication ++ +publication not expired/revoked ++ +document classification allows publication ++ +download permission +``` + +This prevents an internal project document from appearing in the client portal merely because it is linked to the project. + +## 28. Engineering Projects + +Suggested fields: + +```text +id +organization_id +client_id + +project_number +name +description +discipline + +status + +project_manager_user_id + +start_date +expected_completion_date +completed_date + +created_at +updated_at +version +``` + +`stage` is removed from the project row because project phases are the authoritative workflow decomposition. + +Engineering-project status values: + +```text +draft +active +closed +archived +``` + +If the frontend needs a "current stage", derive it from the ordered phase records. `engineering_projects` does not store `current_phase_id` in v1; adding that denormalized pointer would require a later migration plus transactional reconciliation rules. + +Project `budget_minor` is also removed. + +Detailed project budgets belong to the dedicated budget model. + +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 reads: + +```http +GET /api/v1/engineering/projects/{projectId}/summary +GET /api/v1/engineering/projects/{projectId}/timeline +GET /api/v1/engineering/projects/{projectId}/budget +``` + +The budget endpoint reads from the budget module when that module exists. + +## 29. Engineering Project Members + +Suggested fields: + +```text +id +organization_id +project_id +user_id +project_role +joined_at +left_at +``` + +Initial project-role vocabulary: + +```text +project_manager +engineer +designer +reviewer +inspector +viewer +contractor +``` + +Project role describes participation in one project. + +It is not a substitute for RBAC permission. + +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} +``` + +`DELETE` means end participation by setting `left_at`, not erase historical participation. + +`PATCH` may change only `project_role` in v1. `joined_at` is server-assigned and immutable; `left_at` is set only by `DELETE`. Rejoining uses `POST` to create a new temporal membership record, and a partial unique index permits at most one active row per `(organization_id, project_id, user_id)` where `left_at IS NULL`. + +## 30. Engineering Project Phases + +Suggested fields: + +```text +id +organization_id +project_id +name +sequence +status +start_date +end_date +created_at +updated_at +version +``` + +Typical initial statuses: + +```text +planned +active +completed +cancelled +``` + +Example 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 +POST /api/v1/engineering/projects/{projectId}/phases/reorder +``` + +Reorder request: + +```json +{ + "projectVersion": 12, + "orderedPhaseIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b301", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b302" + ] +} +``` + +Reordering is transactional. + +Sequences remain unique within a project after commit. + +## 31. Engineering Sites + +Suggested fields: + +```text +id +organization_id +project_id +name +address +latitude +longitude +created_at +updated_at +``` + +REST: + +```http +GET /api/v1/engineering/sites +GET /api/v1/engineering/sites/{siteId} + +POST /api/v1/engineering/projects/{projectId}/sites +GET /api/v1/engineering/projects/{projectId}/sites + +PATCH /api/v1/engineering/sites/{siteId} +``` + +Global site listing is still tenant-scoped through `X-Organization-Id`. + +## 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 +``` + +Statuses: + +```text +todo +in_progress +completed +cancelled +``` + +Priorities: + +```text +low +medium +high +urgent +``` + +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 +``` + +## 32A. Engineering Batch Operations + +Batch operations are useful for repetitive engineering workflows, but they must not bypass per-resource authorization or domain rules. + +Examples: + +```http +POST /api/v1/engineering/tasks/batch/assign +POST /api/v1/engineering/tasks/batch/complete + +POST /api/v1/engineering/time-entries/batch/submit +``` + +### Batch Execution Modes + +Every batch command explicitly defines one of: + +```text +atomic +partial +``` + +Atomic: + +```text +all resources succeed +or +entire operation fails +``` + +Partial: + +```text +each resource is evaluated independently +successful items commit +failed items return individual errors +``` + +Do not leave this behavior implicit. + +Example request: + +```json +{ + "taskIds": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83" + ], + "assigneeUserId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d", + "mode": "partial" +} +``` + +Example response: + +```json +{ + "data": { + "succeeded": [ + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c81", + "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c82" + ], + "failed": [ + { + "id": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c83", + "code": "RESOURCE_INVALID_STATE" + } + ] + } +} +``` + +### Authorization + +Each resource is evaluated for: + +```text +tenant +permission +scope +resource access +state validity +credential policy where applicable +``` + +Never authorize the first item and assume the remaining batch is equivalent. + +### Synchronous vs Asynchronous + +Small batches may execute synchronously. + +Large batches become jobs: + +```http +202 Accepted +``` + +with: + +```text +jobId +``` + +The synchronous/asynchronous threshold is configuration based on: + +```text +batch size +operation cost +database load +side effects +product tier +``` + +Financial or regulated batch actions require stricter idempotency and audit rules than ordinary task updates. + +--- + +## 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 +cancelled +withdrawn +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}/revise +POST /api/v1/engineering/designs/{designId}/cancel +POST /api/v1/engineering/designs/{designId}/withdraw +POST /api/v1/engineering/designs/{designId}/supersede + +POST /api/v1/engineering/designs/{designId}/assign +POST /api/v1/engineering/designs/{designId}/unassign + +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 Assignment + +`engineering_design_assignments` fields: + +```text +id +organization_id +design_id +user_id +assignment_role +notes nullable +assigned_by_user_id +assigned_at +unassigned_at nullable +``` + +Initial assignment-role values: + +```text +owner +preparer +reviewer +contributor +``` + +`approver` is not an assignment role: approval authority is credential- and policy-driven, and the actual approver is recorded by the approval transition. + +Active assignments are unique by `(organization_id, design_id, user_id, assignment_role)` where `unassigned_at IS NULL`. `POST /assign` accepts `userId`, `assignmentRole`, and optional `notes`. `POST /unassign` accepts `assignmentId` and sets `unassigned_at`; it never hard-deletes the assignment. The design's primary `owner_user_id` and `prepared_by_user_id`, when set, must correspond to active `owner` and `preparer` assignments respectively. + +Assignment listing: + +```http +GET /api/v1/engineering/designs/{designId}/assignments +``` + +State machine: + +```text +draft + ├── submit-review ─────────────► under_review + └── cancel ────────────────────► cancelled + +under_review + ├── request-changes ───────────► changes_requested + ├── approve ───────────────────► approved + ├── reject ────────────────────► rejected + └── withdraw ──────────────────► withdrawn + +changes_requested + ├── submit-review ─────────────► under_review + └── withdraw ──────────────────► withdrawn + +rejected + └── revise ────────────────────► draft + +approved + └── supersede ─────────────────► superseded +``` + +Approval remains credential-aware, audited, and idempotent. + +Designs do not use generic archive/restore endpoints. Their professional lifecycle terminates through explicit state-machine outcomes such as `cancelled`, `withdrawn`, and `superseded`. Terminal designs remain queryable and auditable and are not hard-deleted through ordinary workflows. + +## 34. Design Versions and Reviews + +A design version is a logical professional revision. + +It may have multiple document files. + +Use: + +```text +engineering_design_versions +engineering_design_version_documents +engineering_design_reviews +``` + +### Design Version + +```text +id +organization_id +design_id +version_number +created_by_user_id +created_at +``` + +Unique: + +```text +(organization_id, design_id, version_number) +``` + +### Design Version Documents + +```text +id +organization_id +design_version_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +Possible `document_role` values: + +```text +primary_drawing +calculation +supporting_document +specification +attachment +``` + +A design version therefore supports one or many documents without putting `document_id` directly on the version. + +### Design Review + +```text +id +organization_id +design_id +design_version_id +reviewer_user_id +status +comments +reviewed_at +created_at +``` + +Statuses: + +```text +pending +approved +changes_requested +rejected +``` + +All three tables are tenant-owned and carry direct `organization_id`. + +## 35. Engineering Inspections + +Inspection fields: + +```text +id +organization_id +project_id +site_id + +inspection_type +inspector_user_id + +status +outcome + +scheduled_at +started_at +performed_at +cancelled_at + +summary + +created_at +updated_at +version +``` + +Lifecycle: + +```text +draft +scheduled +in_progress +completed +cancelled +``` + +Outcome: + +```text +passed +passed_with_observations +followup_required +failed +``` + +`inspection_type` is an application/domain registry rather than a PostgreSQL enum. + +Initial common keys may include: + +```text +structural +mechanical +electrical +safety +final +``` + +Organizations/modules may add supported types through controlled configuration later. + +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 + +GET /api/v1/engineering/inspections/{inspectionId}/followups +POST /api/v1/engineering/inspections/{inspectionId}/followups +``` + +Inspection completion may create follow-up records. + +Lifecycle and outcome remain separate. + +## 36. Inspection Findings + +`engineering_inspection_findings`: + +```text +id +organization_id +inspection_id + +severity +description +status + +resolved_at +resolved_by_user_id + +created_at +updated_at +version +``` + +Severity: + +```text +observation +minor +major +critical +``` + +Status: + +```text +open +in_progress +resolved +accepted_risk +``` + +REST: + +```http +POST /api/v1/engineering/inspections/{inspectionId}/findings +PATCH /api/v1/engineering/inspection-findings/{findingId} +POST /api/v1/engineering/inspection-findings/{findingId}/resolve +``` + +`organization_id` is direct even though tenant ownership is also derivable through the inspection. + +### Follow-Up Resource + +Use: + +```text +engineering_inspection_followups +``` + +Fields: + +```text +id +organization_id +inspection_id + +followup_type + +linked_task_id nullable +linked_inspection_id nullable + +status + +created_by_user_id +created_at +completed_at +cancelled_at +``` + +`followup_type`: + +```text +corrective_task +followup_inspection +both +``` + +`status`: + +```text +open +in_progress +completed +cancelled +``` + +Tenant-safe foreign keys apply to the original inspection and any linked task/inspection. + +## 37. Engineering Specifications + +Use: + +```text +engineering_specifications +engineering_specification_documents +``` + +Suggested specification fields: + +```text +id +organization_id +project_id +specification_number +title +version +status +superseded_by_specification_id nullable +archived_from_status nullable +archived_at nullable +archived_by_user_id nullable +created_at +updated_at +``` + +Status values: + +```text +draft +active +superseded +archived +``` + +Specification document links: + +```text +id +organization_id +specification_id +document_id +document_role +linked_by_user_id +linked_at +unlinked_at +``` + +A specification may therefore have one or many current or historical document links. `document_role` is an application registry with initial values such as `primary`, `attachment`, and `supporting_document`. Tenant-safe foreign keys apply to both the specification and shared document. + +The specification-document `document_role` registry is distinct from the design-version document-role registry in §34. Identical column names do not imply one shared vocabulary. + +Specification REST: + +```http +GET /api/v1/engineering/projects/{projectId}/specifications +POST /api/v1/engineering/projects/{projectId}/specifications + +GET /api/v1/engineering/specifications/{specificationId} +PATCH /api/v1/engineering/specifications/{specificationId} + +POST /api/v1/engineering/specifications/{specificationId}/activate +POST /api/v1/engineering/specifications/{specificationId}/supersede +POST /api/v1/engineering/specifications/{specificationId}/archive +POST /api/v1/engineering/specifications/{specificationId}/restore + +GET /api/v1/engineering/specifications/{specificationId}/documents +POST /api/v1/engineering/specifications/{specificationId}/documents +DELETE /api/v1/engineering/specification-documents/{documentLinkId} +``` + +Lifecycle rules: + +```text +draft → activate → active +draft → archive → archived +active → supersede → superseded +active → archive → archived +archived → restore → archived_from_status +superseded → terminal +``` + +Archive stores the prior `draft` or `active` value in `archived_from_status`; restore clears the archive fields and returns to that value. Supersede requires `supersededBySpecificationId`, linking a same-project replacement specification, and is audited and idempotent. + +--- + +## 38. Engineering Change Requests + +**Deferred from the initial Engineering schema.** + +Change requests are a valid future engineering capability, but v4.1 does not create the table until these are specified: + +```text +relationship to project +relationship to design/specification +request origin +impact analysis +cost/schedule effects +review workflow +approval authority +state machine +document links +REST commands +audit requirements +``` + +Future candidate: + +```text +engineering_change_requests +``` + +This belongs in the Engineering extension backlog rather than a half-defined initial migration. + +## 38A. Engineering Project Budgets + +A single `budget_minor` column is sufficient only for a very early project total. + +When budget management enters scope, introduce: + +```text +engineering_project_budgets +engineering_project_budget_items +engineering_project_commitments +engineering_project_cost_entries +``` + +### Budget + +Suggested fields: + +```text +id +organization_id +project_id + +name +currency_code +status + +approved_by_user_id +approved_at + +created_at +updated_at +version +``` + +### Budget Item + +Suggested fields: + +```text +id +organization_id +budget_id + +category +description + +allocated_amount_minor + +created_at +updated_at +``` + +Do not casually store mutable: + +```text +spent_amount_minor +committed_amount_minor +``` + +as independent sources of truth if those values are derived from time entries, expenses, purchase commitments, or invoices. + +Prefer: + +```text +authoritative cost/commitment records + ↓ +derived budget projections +``` + +If denormalized totals are needed for performance, update them transactionally and reconcile them. + +Potential REST: + +```http +GET /api/v1/engineering/projects/{projectId}/budgets +POST /api/v1/engineering/projects/{projectId}/budgets +GET /api/v1/engineering/budgets/{budgetId} +PATCH /api/v1/engineering/budgets/{budgetId} + +POST /api/v1/engineering/budgets/{budgetId}/approve +GET /api/v1/engineering/budgets/{budgetId}/items +POST /api/v1/engineering/budgets/{budgetId}/items +``` + +Budget approval is an explicit command. + +--- + +## 39. Engineering Time Entries + +Suggested fields: + +```text +id +organization_id +project_id +user_id + +work_date +duration_minutes +description + +billable +billing_rate_minor nullable +currency_code nullable + +phase_id nullable +task_id nullable +design_id nullable +inspection_id nullable + +created_at +updated_at +version +``` + +The project is always required. + +A time entry may also identify one primary work item. + +Database check: + +```text +at most one of: +phase_id +task_id +design_id +inspection_id +``` + +Each optional foreign key is tenant- and project-aware. For example: + +```text +(organization_id, project_id, task_id) +→ engineering_tasks(organization_id, project_id, id) +``` + +and similarly for phase, design, and inspection. Supporting unique constraints on `(organization_id, project_id, id)` are required on each target table. + +This is a database-enforced invariant, not only an application validation rule: whenever an optional work-item ID is present, that work item must belong to the same organization and `project_id` as the time entry. + +This preserves relational integrity instead of using an unconstrained polymorphic `reference_type/reference_id`. + +REST: + +```http +POST /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries +GET /api/v1/engineering/time-entries/{timeEntryId} +PATCH /api/v1/engineering/time-entries/{timeEntryId} + +POST /api/v1/engineering/time-entries/batch/submit +``` + +Duration is integer minutes. + +Billing snapshot constraint: + +```text +billable = true + → billing_rate_minor MUST be greater than zero + → currency_code MUST be non-null + +billable = false + → billing_rate_minor MUST be null + → currency_code MUST be null +``` + +The rate and currency are captured on the time entry so later billing-rate changes do not rewrite historical work. + +## 40. Legal Tables + +Initial legal-domain tables: + +```text +legal_clients +legal_matters +legal_matter_members +legal_cases +legal_case_parties +legal_courts +legal_hearings +legal_deadlines +legal_time_entries +legal_retainers +legal_conflict_checks +legal_conflict_parties +legal_conflict_matches +legal_matter_documents +legal_case_documents +legal_client_billing_accounts +legal_invoice_matters +``` + +There is no separate `legal_documents` ownership table. + +Documents remain shared infrastructure: + +```text +documents +document_versions +``` + +Legal relationships use: + +```text +legal_matter_documents +legal_case_documents +``` + +`legal_matter_documents` fields: + +```text +id +organization_id +matter_id +document_id +linked_by_user_id +linked_at +unlinked_at +``` + +`legal_case_documents` fields: + +```text +id +organization_id +case_id +document_id +linked_by_user_id +linked_at +unlinked_at +``` + +Both tables use tenant-safe foreign keys to their Legal parent and the shared `documents` table. `unlinked_at` preserves link history without deleting the shared document. + +REST namespace: + +```text +/api/v1/legal +``` + +Legal remains a later vertical. + +## 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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2cbd", + "status": "pending_review", + "potentialConflicts": [ + { + "type": "possible_direct_adversity", + "partyName": "Acme Corporation", + "existingMatterId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2ccd", + "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 + +Healthcare remains a later vertical. + +Minimum planned tables: + +```text +healthcare_patients +healthcare_patient_contacts +healthcare_patient_addresses + +healthcare_practitioners +healthcare_locations +healthcare_rooms + +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 +``` + +All tenant-owned tables carry direct `organization_id`. + +Detailed healthcare interoperability, terminology, and jurisdiction rules require healthcare-specific design before implementation. + +## 46. Healthcare Patients + +Core patient: + +```text +id +organization_id +patient_number + +first_name +middle_name +last_name +date_of_birth + +administrative_gender nullable +sex_at_birth nullable +gender_identity nullable + +status + +created_at +updated_at +version +``` + +Exact demographic terminology and allowed values are finalized in the healthcare-domain specification. + +Do not make every field mandatory merely because it exists. + +### Patient Contact + +`healthcare_patient_contacts`: + +```text +id +organization_id +patient_id + +contact_type +value +is_primary + +created_at +updated_at +``` + +### Patient Address + +`healthcare_patient_addresses`: + +```text +id +organization_id +patient_id + +address_type +line_1 +line_2 +city +region +postal_code +country_code + +is_primary + +created_at +updated_at +``` + +Sensitive subresources remain permission-controlled. + +## 47. Healthcare Practitioners + +Suggested fields: + +```text +id +organization_id +user_id +professional_profile_id + +specialty +status + +created_at +updated_at +``` + +Professional licenses are not duplicated here. + +Multiple licenses/credentials live in: + +```text +professional_credentials +``` + +## 48. Healthcare Appointments + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id + +location_id nullable +room_id nullable + +appointment_type + +starts_at +ends_at + +status +reason + +created_at +updated_at +version +``` + +Planned supporting tables: + +`healthcare_locations`: + +```text +id +organization_id +name +address fields +timezone +status +``` + +`healthcare_rooms`: + +```text +id +organization_id +location_id +name +status +``` + +Exact scheduling rules are deferred to the healthcare vertical. + +## 49. Healthcare Encounters + +Suggested fields: + +```text +id +organization_id + +patient_id +practitioner_id +appointment_id nullable + +encounter_type + +reason_for_visit nullable + +started_at +ended_at + +status + +created_at +updated_at +version +``` + +Do not add a generic free-form `notes` field as a substitute for clinical records. + +Clinical narrative belongs in governed clinical-record structures. + +## 50. Clinical Records + +Use: + +```text +healthcare_clinical_records +healthcare_clinical_record_versions +healthcare_clinical_record_amendments +``` + +### Clinical Record + +```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 +``` + +### Clinical Record Version + +```text +id +organization_id +record_id +version_number + +content_reference or governed content payload +created_by_practitioner_id +created_at +``` + +### Clinical Record Amendment + +```text +id +organization_id +record_id +source_version_id +result_version_id + +amended_by_practitioner_id + +amendment_type +amendment_reason + +created_at +``` + +Possible amendment types: + +```text +correction +addendum +clarification +``` + +Signed/finalized history is preserved. + +REST: + +```http +POST /api/v1/healthcare/encounters/{encounterId}/clinical-records + +GET /api/v1/healthcare/clinical-records/{recordId} +PATCH /api/v1/healthcare/clinical-records/{recordId} +# Draft/editable only. + +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 +``` + +## 51. Documents + +Shared document infrastructure: + +```text +documents +document_versions +document_categories +retention_policies +``` + +Binary data lives in S3-compatible object storage. + +### Document + +```text +id +organization_id +name +category_id +classification +retention_policy_id +current_version_id +created_by_user_id +created_at +updated_at +``` + +Classification: + +```text +public +internal +confidential +restricted +regulated +``` + +### Document Version + +```text +id +organization_id +document_id +version_number +storage_key +mime_type +size_bytes +content_hash +hash_algorithm +uploaded_by_user_id +created_at +``` + +Checksum is version-level authoritative data. + +### Document Category + +```text +id +organization_id +profession nullable +name +parent_category_id +created_at +``` + +Uniqueness requirement: + +```text +shared category: + unique organization_id + name where profession IS NULL + +profession category: + unique organization_id + profession + name where profession IS NOT NULL +``` + +Implementation options: + +```text +PostgreSQL null-aware unique constraint when supported +or +two partial unique indexes +``` + +The partial-index fallback does not depend on selecting PostgreSQL 18. + +### Retention Policy + +```text +id +organization_id + +name +profession nullable +classification nullable + +retention_period_days nullable +action + +created_at +updated_at +``` + +Initial actions: + +```text +review +archive +delete_when_legally_permitted +retain_indefinitely +``` + +`retention_period_days` has one meaning only: + +```text +action = retain_indefinitely + → retention_period_days MUST be null + +all other actions + → retention_period_days MUST be a positive integer +``` + +Null does not mean inherit, unconfigured, or unknown. Policy inheritance or an unconfigured state must be represented outside a persisted retention-policy row and specified separately before implementation. + +A retention policy describes configured behavior. + +Actual deletion remains subject to domain, contractual, privacy, and jurisdiction requirements. + +### Metadata + +JSONB is allowed only for genuinely extensible, non-authoritative metadata. + +Do not put authorization, lifecycle, retention state, or ownership into arbitrary JSON. + +## 52. Document Upload Flow + +### Standard Upload + +Request: + +```http +POST /api/v1/documents/upload-url +``` + +```json +{ + "name": "structural-calculations.pdf", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/pdf", + "sizeBytes": 2457600, + "contentHash": "sha256:..." +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d01", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "uploadUrl": "https://object-storage.example/...", + "expiresAt": "2026-08-26T13:00:00Z" + } +} +``` + +The frontend uploads directly to object storage. + +Finalize: + +```http +POST /api/v1/documents/{documentId}/complete-upload +``` + +```json +{ + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d02", + "contentHash": "sha256:..." +} +``` + +### Multipart Initialization + +```http +POST /api/v1/documents/multipart-uploads +``` + +Request: + +```json +{ + "name": "building-model.bin", + "categoryId": null, + "classification": "confidential", + "mimeType": "application/octet-stream", + "sizeBytes": 2147483648, + "contentHash": null +} +``` + +Response: + +```json +{ + "data": { + "documentId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d10", + "documentVersionId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d11", + "uploadId": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2d12", + "recommendedPartSizeBytes": 67108864, + "expiresAt": "2026-08-27T12:00:00Z" + } +} +``` + +### Request Signed Part URLs + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/parts +``` + +```json +{ + "partNumbers": [1, 2, 3, 4] +} +``` + +Response: + +```json +{ + "data": [ + { + "partNumber": 1, + "uploadUrl": "https://object-storage.example/..." + } + ] +} +``` + +Binary parts go directly to object storage. + +### Complete Multipart Upload + +```http +POST /api/v1/documents/{documentId}/multipart-uploads/{uploadId}/complete +``` + +```json +{ + "parts": [ + { + "partNumber": 1, + "etag": "..." + } + ], + "contentHash": "sha256:..." +} +``` + +Abort: + +```http +DELETE /api/v1/documents/{documentId}/multipart-uploads/{uploadId} +``` + +Upload state: + +```text +initiated +uploading +completing +completed +aborted +expired +``` + +Workers clean up abandoned multipart uploads. + +Upload policy validates: + +```text +declared MIME +extension +content signature +size +checksum +quota +classification +malware status +``` + +## 53. Profession-Specific Document Links + +Use explicit relationship tables. + +Engineering: + +```text +engineering_project_documents +engineering_design_version_documents +engineering_inspection_documents +``` + +Legal: + +```text +legal_matter_documents +legal_case_documents +``` + +Healthcare: + +```text +healthcare_patient_documents +healthcare_encounter_documents +``` + +`engineering_design_version_documents` is authoritative for files belonging to a specific design revision. + +Do not also maintain an ambiguous `engineering_design_documents` relation to the unversioned design unless a later requirement introduces a separate clearly named supporting-document relationship. + +### Project Documents + +```text +engineering_project_documents +├── id +├── organization_id +├── project_id +├── document_id +├── category +├── linked_by_user_id +├── linked_at +└── unlinked_at +``` + +REST: + +```http +GET /api/v1/engineering/projects/{projectId}/documents +POST /api/v1/engineering/projects/{projectId}/documents +DELETE /api/v1/engineering/project-documents/{documentLinkId} +``` + +`DELETE` temporally unlinks the relation when history must be preserved. + +### Inspection Documents + +`engineering_inspection_documents` fields: + +```text +id +organization_id +inspection_id +document_id +category +linked_by_user_id +linked_at +unlinked_at nullable +``` + +Both the inspection and document references use tenant-safe foreign keys. Active links are unique by `(organization_id, inspection_id, document_id)` where `unlinked_at IS NULL`. + +REST: + +```http +GET /api/v1/engineering/inspections/{inspectionId}/documents +POST /api/v1/engineering/inspections/{inspectionId}/documents +DELETE /api/v1/engineering/inspection-documents/{documentLinkId} +``` + +`DELETE` sets `unlinked_at`; it does not delete the shared document or erase inspection history. + +## 54. Billing + +Shared financial core: + +```text +billing_accounts +invoices +invoice_items +payments +payment_refunds +``` + +### Billing Account + +Invoices reference a shared bill-to identity rather than an unconstrained profession-owned resource. + +`billing_accounts` fields: + +```text +id +organization_id +display_name +legal_name nullable +billing_email nullable +billing_address nullable +status +created_at +updated_at +``` + +Billing-account status values: + +```text +active +inactive +``` + +Profession modules own explicit links from their parties to billing accounts. Initial link shapes are: + +```text +engineering_client_billing_accounts +├── id +├── organization_id +├── client_id +├── billing_account_id +├── linked_at +└── unlinked_at nullable + +legal_client_billing_accounts +├── id +├── organization_id +├── client_id +├── billing_account_id +├── linked_at +└── unlinked_at nullable +``` + +Each reference is tenant-safe. Engineering v1 permits one active billing-account link per client where `unlinked_at IS NULL`; later verticals may define stricter payer rules. Matter, project, encounter, and time-entry provenance remains in profession-owned invoice or invoice-item link tables. Shared billing therefore never depends on profession table internals. + +Billing-account REST: + +```http +GET /api/v1/billing-accounts +POST /api/v1/billing-accounts +GET /api/v1/billing-accounts/{billingAccountId} +PATCH /api/v1/billing-accounts/{billingAccountId} +``` + +### Invoice + +Core fields include: + +```text +id +organization_id +billing_account_id + +bill_to_name +bill_to_email nullable +bill_to_address_snapshot nullable + +invoice_number +status +currency_code +subtotal_minor +tax_total_minor +total_minor +issued_at +due_at +paid_at +created_at +updated_at +version +``` + +Invoice status values: + +```text +draft +issued +partially_paid +paid +overdue +void +``` + +The bill-to fields are immutable snapshots once the invoice is issued. Updating a billing account later does not rewrite an issued invoice. + +`(organization_id, billing_account_id)` uses a tenant-safe foreign key to `billing_accounts(organization_id, id)`. + +### Invoice Item + +```text +id +organization_id +invoice_id + +description + +quantity +unit_price_minor +total_amount_minor + +position + +created_at +updated_at +``` + +`quantity` uses fixed-precision numeric semantics, not floating point. + +Money uses integer minor units. + +The invoice determines currency; invoice items do not independently choose a different currency unless multi-currency invoicing is intentionally designed later. + +### Profession-Specific Source Links + +The shared billing module does not use unconstrained: + +```text +reference_type +reference_id +``` + +to profession-owned tables. + +Profession modules create explicit links, for example: + +```text +engineering_invoice_item_time_entries +├── organization_id +├── invoice_item_id +└── time_entry_id +``` + +This preserves the rule that shared core does not depend on profession-table internals. + +Invoice-level work context also uses explicit profession-owned links, for example: + +```text +engineering_invoice_projects +├── id +├── organization_id +├── invoice_id +├── project_id +└── linked_at + +legal_invoice_matters +├── id +├── organization_id +├── invoice_id +├── matter_id +└── linked_at +``` + +Healthcare invoice context is deferred to the healthcare billing design. The shared invoice table does not contain `reference_type` or `reference_id`. + +### Payment + +`payments` fields: + +```text +id +organization_id +invoice_id +amount_minor +currency_code +payment_method +status +transaction_reference nullable +paid_at nullable +created_at +updated_at +``` + +Payment status values: + +```text +pending +succeeded +failed +partially_refunded +refunded +voided +``` + +`payment_method` is an application registry with initial values `bank_transfer`, `card`, `check`, `cash`, and `other`. `amount_minor` must be positive, and `currency_code` must equal the invoice currency. + +### Payment Refund + +Refunds are separate records so partial or repeated refunds remain auditable. + +`payment_refunds` fields: + +```text +id +organization_id +payment_id +amount_minor +status +transaction_reference nullable +reason nullable +requested_by_user_id +created_at +refunded_at nullable +``` + +Refund status values: + +```text +pending +succeeded +failed +``` + +The sum of successful refunds may not exceed the successful payment amount. Payment and refund commands are transactional, idempotent, and append audit/outbox records. + +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 + +Use: + +```text +audit_events +``` + +Suggested fields: + +```text +id +organization_id + +actor_type +actor_user_id nullable +actor_service_account_id nullable + +action + +resource_type +resource_id + +request_id +correlation_id + +ip_address +user_agent + +metadata + +occurred_at +``` + +Audit records are append-only from normal application workflows. + +### Mandatory Examples + +Engineering: + +```text +engineering.projects.create +engineering.projects.close +engineering.designs.approve +engineering.inspections.complete +``` + +Legal: + +```text +legal.matters.create +legal.matters.close +legal.conflicts.approve +``` + +Healthcare: + +```text +healthcare.records.read +healthcare.records.write +healthcare.records.sign +healthcare.records.amend +``` + +### Privacy / Erasure Handling + +Append-only audit does not mean "store unlimited personal data forever." + +Audit metadata must be minimized at write time. + +Where privacy, contractual, or retention obligations require removal of personally identifying material, use a governed privacy process such as: + +```text +pseudonymize actor references +null/remove nonessential PII fields +replace identifiers with irreversible privacy references where appropriate +retain the security/business event itself when permitted/required +``` + +The exact action depends on jurisdiction and retention policy and must be reviewed before healthcare/legal production. + +Do not place passwords, tokens, full clinical content, secret keys, or unnecessary payment data in audit metadata. + +REST: + +```http +GET /api/v1/audit-events +``` + +No public mutation endpoints. + +## 57. Domain Events and Transactional Outbox + +Use: + +```text +outbox_events +``` + +Fields: + +```text +id +organization_id nullable for truly global events + +event_type +aggregate_type +aggregate_id + +payload + +request_id nullable +correlation_id +causation_id nullable + +occurred_at +available_at +processed_at + +attempt_count +last_error +dead_lettered_at +``` + +`correlation_id` groups one logical workflow across requests/jobs/events. + +`causation_id` identifies the event/command that directly caused this event when applicable. + +Transaction: + +```text +BEGIN +business change +audit event +outbox event +COMMIT +``` + +Delivery semantics are at-least-once. + +Worker claim uses row locking such as: + +```sql +SELECT id +FROM outbox_events +WHERE processed_at IS NULL + AND dead_lettered_at IS NULL + AND available_at <= now() +ORDER BY occurred_at +FOR UPDATE SKIP LOCKED +LIMIT 100; +``` + +Every external side-effect consumer must be idempotent. + +`FOR UPDATE SKIP LOCKED` prevents simultaneous claiming; it does not prevent duplicate side effects after a worker crash. + +## 57A. Webhooks and External Integrations + +Shared tables: + +```text +webhooks +webhook_event_subscriptions +webhook_deliveries +``` + +### Webhook + +```text +id +organization_id +url +status +secret_ciphertext or signing_key_reference +created_by_user_id +created_at +updated_at +``` + +Webhook status values: + +```text +active +paused +disabled +``` + +### Subscription + +```text +id +organization_id +webhook_id +event_type +created_at +``` + +Unique: + +```text +(organization_id, webhook_id, event_type) +``` + +Only registered externally publishable event types may be subscribed. + +### Delivery + +```text +id +organization_id +webhook_id +event_id + +attempt_number +request_timestamp +response_status +response_summary + +delivered_at +failed_at +next_attempt_at +``` + +`event_id` references `outbox_events.id`. Because webhook deliveries are tenant-owned, only publishable outbox events with the same non-null `organization_id` may be delivered: + +```text +(organization_id, event_id) +→ outbox_events(organization_id, id) +``` + +The webhook publisher allowlists externally publishable `event_type` values before creating delivery records. The stable outbox event ID is also the consumer deduplication key. + +Configuration REST: + +```http +GET /api/v1/webhooks +POST /api/v1/webhooks +GET /api/v1/webhooks/{webhookId} +PATCH /api/v1/webhooks/{webhookId} +DELETE /api/v1/webhooks/{webhookId} + +POST /api/v1/webhooks/{webhookId}/test +POST /api/v1/webhooks/{webhookId}/rotate-secret +``` + +Delivery REST: + +```http +GET /api/v1/webhook-deliveries +GET /api/v1/webhook-deliveries/{deliveryId} +POST /api/v1/webhook-deliveries/{deliveryId}/retry +``` + +If HMAC signing is used, signing material is encrypted/recoverable with managed key protection. + +A one-way secret hash is insufficient for outbound HMAC signing. + +Webhook consumers deduplicate using stable event IDs. + +## 58. Background Jobs + +Workers handle: + +```text +notifications +reports/PDFs +file scanning +document processing +imports +exports +bulk operations +webhooks +search indexing +large data operations +``` + +Use shared tenant-owned: + +```text +jobs +``` + +Fields: + +```text +id +organization_id +requested_by_user_id + +job_type +status + +input_reference +result_reference +progress_percent + +created_at +started_at +completed_at +failed_at + +error_code +error_summary +``` + +Initial `job_type` values: + +```text +project_export +time_entry_import +report_generation +bulk_operation +``` + +`job_type` is an application registry, not a client-defined free-form value or a PostgreSQL enum. Each registered type defines its handler, input-reference schema, result-reference schema, authorization policy, retry policy, and idempotency behavior. Unknown job types are rejected before a job row is created. + +`input_reference` and `result_reference` are nullable typed JSONB reference envelopes, not arbitrary blobs or public URLs. Their schema is registered per `job_type`. + +Allowed reference kinds initially include: + +```text +document_version +object_storage_key +query_snapshot +job +``` + +Object-storage references contain internal storage keys; APIs generate time-limited signed URLs when access is authorized. Resource IDs inside an envelope are validated for tenant ownership when the job is created. Large inputs and outputs live in documents or object storage rather than inside the job row. + +States: + +```text +queued +running +completed +failed +cancelled +``` + +REST: + +```http +GET /api/v1/jobs/{jobId} +GET /api/v1/jobs/{jobId}/result +POST /api/v1/jobs/{jobId}/cancel +``` + +These endpoints are tenant-scoped through the standard: + +```http +X-Organization-Id +``` + +They do not need `/organizations/{id}/jobs` because the platform already chose header-based tenant context. + +Large import/export operations return: + +```http +202 Accepted +``` + +with a job ID. + +## 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. + +Defaults: + +```text +default limit = 25 +maximum limit = 100 +offset pagination = not supported +``` + +Example: + +```http +GET /api/v1/engineering/projects?limit=25 +``` + +Response: + +```json +{ + "data": [], + "meta": { + "pagination": { + "nextCursor": null, + "hasMore": false + } + } +} +``` + +Rules: + +```text +cursor is opaque +sort order must be deterministic +cursor encodes/represents the selected sort position +unsupported limits return validation errors rather than silent huge responses +``` + +## 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=0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c3d +``` + +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": "0193c0a0-7c1e-7b3a-8c4d-6e5f4a3b2c5d", + "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/reuse detection +server-side session revocation + +rate limiting +anti-automation controls + +RBAC +resource policies +credential-aware authorization +tenant isolation + +input validation +SQL injection protection + +signed object-storage URLs +file-content validation +malware scanning + +audit trails +secret management +encryption at rest + +dependency/image scanning + +request/correlation IDs +backup and restore testing +``` + +### Web Security / CORS + +ADR-009 defines environment-specific web security. + +Baseline requirements: + +```text +explicit CORS allowlist +no wildcard credentialed CORS +allowed methods/headers documented +preflight behavior tested +HSTS at the edge for production HTTPS +X-Content-Type-Options: nosniff +secure cookie attributes when cookies are used +CSP on browser frontends +frame-ancestor/clickjacking policy on frontends +referrer policy appropriate to the frontend +``` + +Security headers belong at the appropriate application/CDN/gateway layer. + +### Rate Limiting + +Policies are endpoint-specific and configurable. + +Return: + +```http +429 Too Many Requests +Retry-After: ... +``` + +### Secrets + +Production secrets live outside source control, preferably in managed secret/key systems. + +JWT signing keys support rotation. + +## 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 +``` + +### Core Metrics + +API: + +```text +api_requests_total +api_errors_total +api_request_duration_seconds +``` + +Authentication: + +```text +auth_login_attempts_total +auth_token_refresh_total +auth_refresh_reuse_detections_total +auth_sessions_revoked_total +``` + +Authorization/security: + +```text +cross_tenant_access_attempts_total +tenant_isolation_invariant_failures_total +authorization_denials_total +credential_policy_denials_total +rate_limit_events_total +``` + +Important distinction: + +```text +cross_tenant_access_attempt += +request attempted another tenant's resource +``` + +This may be a stale link, mistake, or attack. + +```text +tenant_isolation_invariant_failure += +our system nearly or actually created/returned cross-tenant data +``` + +That is a high-severity internal correctness/security incident. + +Outbox/jobs/webhooks: + +```text +outbox_events_pending +outbox_events_failed_total +outbox_processing_duration_seconds + +jobs_queued +jobs_failed_total +job_duration_seconds + +webhook_delivery_attempts_total +webhook_delivery_failures_total +webhook_delivery_latency_seconds +``` + +Database: + +```text +db_pool_active +db_pool_waiting +db_query_duration_seconds +db_transaction_duration_seconds +``` + +Business metrics may include: + +```text +engineering_projects_created_total +engineering_designs_approved_total +engineering_inspections_completed_total +invoices_issued_total +``` + +Avoid patient-specific or sensitive identifiers in metric labels. + +### Alerts + +Examples: + +```text +refresh token reuse detected +tenant isolation invariant failure +outbox backlog exceeds SLO +webhook failure spike +database pool saturation +error-rate spike +latency regression +backup failure +malware scanner unavailable +``` + +Thresholds are calibrated from real environments rather than copied from a review document. + +### SLOs + +Define by endpoint class. + +Interactive CRUD, reports, file orchestration, and background jobs should not share one arbitrary latency target. + +## 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 +``` + +### Property-Based Tests + +Use property-based testing for high-value domain state machines. + +Candidates: + +```text +engineering design lifecycle +engineering inspection lifecycle +invoice lifecycle +payment state transitions +membership/role invariants +``` + +Correct properties: + +```text +every successful transition ends in a valid state + +every forbidden transition is rejected + +terminal states reject prohibited actions + +required invariants survive every valid transition + +transition sequences never bypass required approval/credential rules +``` + +Do not assert that every random state/action pair succeeds. Many are supposed to fail. + +### Integration Tests + +Test: + +```text +repositories +tenant-aware foreign keys +PostgreSQL constraints +transactions +outbox persistence +idempotency persistence +cache invalidation +job persistence +webhook delivery persistence +``` + +### API Tests + +Every important endpoint covers: + +```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 creation +outbox creation +``` + +### Outbox Reliability / Chaos Tests + +Test: + +```text +worker crash before side effect +worker crash after side effect but before marking processed +two workers competing for same row +temporary dependency outage +retry/backoff behavior +dead-letter behavior +consumer idempotency +lost worker wake-up +replay +``` + +The dangerous scenario is: + +```text +external side effect succeeds +worker dies +event retries +``` + +Tests must prove the consumer does not create an unacceptable duplicate. + +### Tenant Security Tests + +Test both: + +```text +external cross-tenant access attempts +``` + +and: + +```text +internal cross-tenant data invariant failures +``` + +These are different classes of failure. + +### Performance Tests + +Create realistic profiles: + +```text +interactive reads +interactive writes +search +dashboard read models +reporting +file upload orchestration +outbox processing +webhook bursts +notification bursts +``` + +Measure: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +``` + +Set production SLO gates only after a realistic baseline exists. + +### Coverage + +Track code coverage. + +Do not treat a single percentage such as `90%` as proof of quality. + +Critical-path expectations are stronger: + +```text +all tenant-isolation paths tested +all financial commands tested +all regulated commands tested +all state transitions tested +all critical authorization policies tested +``` + +## 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 +session/token model +idempotency strategy +error taxonomy +OpenAPI skeleton +engineering state machines +migration conventions +threat model +initial ADRs +risk register +``` + +### Phase 1: Shared Platform Core + +Build: + +```text +auth +sessions +refresh-token families +token rotation/revocation + +users +organizations +organization professions + +membership invitations +memberships +roles +permissions +authorization + +audit +outbox + +request context +idempotency +rate limiting +observability +``` + +### Phase 2: Engineering CRM + +Build: + +```text +engineering clients +engineering client contacts +client archive/restore +``` + +### Phase 3: Engineering Projects + +Build: + +```text +projects +project members +project phases +activation/close/archive +``` + +### Phase 4: Work and Site Management + +Build: + +```text +tasks +task batch operations +sites +``` + +### Phase 5: Documents + +Build: + +```text +documents +versions +categories +classification +retention references +signed uploads +multipart uploads +content verification +malware scanning +engineering document links +``` + +### Phase 6: Engineering Designs + +Build: + +```text +designs +assignments +versions +reviews +cancel/withdraw semantics +credential-aware approval +audit +outbox +idempotency +``` + +### Phase 7: Engineering Inspections + +Build: + +```text +inspection lifecycle +inspection outcome +findings +corrective work +follow-up inspections +attachments +audit +outbox +idempotency +``` + +### Phase 8: Time, Budgets, and Billing + +Build: + +```text +time entries +batch timesheet submission +project budgets when required +invoices +payments +financial idempotency +reconciliation +``` + +### Phase 9: Notifications, Jobs, and Webhooks + +Build: + +```text +notifications +email +async jobs +imports/exports +webhooks +delivery/retry +dead-letter handling +``` + +### Phase 10: Reporting and Search + +Build: + +```text +project status +overdue work +inspection status +billable time +revenue +outstanding invoices +dashboard read models +``` + +### Phase 11: Engineering Client Portal + +Build: + +```text +portal account invitations +external project grants +published project documents +client review/acceptance workflow +portal audit +portal-specific frontend +``` + +Do not expose professional approval actions to client portal accounts. + +### Phase 12: Legal Vertical + +Validate shared core against: + +```text +matters +cases +conflicts +deadlines +retainers +restricted access / ethical walls +``` + +### Phase 13: Healthcare Readiness and Vertical + +Before implementation: + +```text +healthcare threat model +privacy review +jurisdiction analysis +scope-of-practice policy +record signing/amendment model +retention model +audit requirements +``` + +### Estimation Rule + +These are dependency-ordered milestones. + +They are not calendar promises. + +Calendar estimates require: + +```text +team size +frontend/UX scope +cloud decisions +third-party providers +security requirements +QA capacity +domain-expert availability +``` + +## 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 uses UUIDv7. + +Supported implementation choices: + +```text +PostgreSQL 18+: + use native uuidv7() if database-generated identifiers are desired + +Earlier PostgreSQL: + generate UUIDv7 in the application or use a controlled extension +``` + +Database columns remain PostgreSQL `UUID`. + +The rule is consistency, not ideological loyalty to one generation layer. + +Do not silently fall back to UUIDv4 while documenting UUIDv7. + +### Production Migration Rules + +Use expand/contract: + +```text +1. add backward-compatible schema +2. deploy code supporting old + new schema +3. backfill/migrate +4. switch reads/writes +5. observe +6. remove obsolete schema later +``` + +For destructive changes: + +```text +backup/restore plan +compatibility window +production-like dry run +explicit approval +post-migration verification +``` + +Do not assume a destructive database migration can always be reversed by a simple down migration. + +Never use automatic ORM schema synchronization in production. + +## 91A. Architecture Decision Records + +v4 stops treating technology suggestions as automatically settled architecture. + +Create ADRs before implementation locks in: + +```text +ADR-001 Backend Framework +ADR-002 SQL / ORM / Query Layer +ADR-003 Queue Implementation +ADR-004 PostgreSQL Minimum Version +ADR-005 Error Format / RFC 9457 Compatibility +ADR-006 Rate-Limit Header Convention +ADR-007 Webhook Signing Strategy +ADR-008 Object Storage Provider / Multipart Strategy +ADR-009 Web Security / CORS / Browser Headers +ADR-010 Machine Authentication / API Key Policy +``` + +Each ADR should include: + +```text +context +decision +alternatives considered +tradeoffs +security impact +operational impact +migration/exit path +date +status +``` + +The architecture currently fixes capabilities and boundaries. + +It does not require a framework merely because a review document described it positively. + +--- + +## 92. Technology Recommendation + +The following are preferred candidates, not all final decisions. + +### Fixed Platform Choices + +```text +API style: REST +Contract: OpenAPI 3.1 +Primary language: TypeScript +Primary database: PostgreSQL +Architecture: Modular Monolith +Observability standard: OpenTelemetry +Object storage model: S3-compatible +Container model: Docker/OCI +``` + +### ADR-Gated Choices + +Backend framework candidates: + +```text +NestJS +Fastify-centered custom application structure +``` + +SQL / persistence candidates: + +```text +Drizzle +Kysely +Prisma +direct SQL for specialized queries +``` + +Queue candidates: + +```text +BullMQ / Redis +managed cloud queue +``` + +PostgreSQL baseline: + +```text +PostgreSQL 18+ +``` + +is attractive because of native UUIDv7 and current capabilities, but the minimum supported version must be confirmed against: + +```text +hosting provider availability +operations policy +extension requirements +upgrade policy +support lifecycle +``` + +Do not claim one ORM is categorically "faster" or "better" without workload-specific evidence. + +The selected stack should preserve: + +```text +transaction control +explicit SQL visibility +tenant-safe query design +migration control +observability +testability +``` + +## 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 API contract. +4. GraphQL is not part of v1. +5. Start as one modular monolith backend. +6. Each profession has its own frontend. +7. Each profession owns its domain tables and state machines. +8. Shared modules provide infrastructure, not forced domain abstractions. +9. Public serialized IDs are raw UUIDv7. +10. Database ID columns use PostgreSQL UUID. +11. Human-readable business references are separate from resource IDs. +12. Every tenant-owned row carries direct `organization_id`. +13. Tenant-scoped requests require explicit `X-Organization-Id`. +14. Tenant boundaries are enforced in queries and database constraints. +15. Cross-tenant resources appear nonexistent. +16. API JSON/query parameter names use camelCase; DB identifiers use snake_case. +17. Authorization is server-side and deny-by-default. +18. `assigned` scope is defined per resource policy, never inferred generically. +19. Roles and professional credentials are separate. +20. A professional profile may own multiple credentials. +21. Sessions and refresh tokens are separate resources. +22. Refresh tokens rotate within families and support reuse detection. +23. Machine identities use service accounts/API keys, not fake human memberships. +24. Important domain transitions use explicit REST command endpoints. +25. High-risk commands use durable idempotency. +26. Batch custom actions use `/{collection}/batch/{action}`. +27. Every batch defines atomic or partial semantics. +28. Every batch item receives independent authorization/domain validation. +29. Large batches become asynchronous jobs. +30. Project phases are authoritative; duplicated project `stage` and `current_phase_id` are not stored in v1. +31. Project budgets use the dedicated budget model and project `budget_minor` is not authoritative; shared invoices reference `billing_accounts` and never unconstrained polymorphic profession resources. +32. Engineering time entries may attribute time to one explicit primary work item using tenant- and project-consistent composite foreign keys. +33. Design versions and engineering specifications use explicit document-link tables with one-to-many cardinality and separate role registries. +34. All design/assignment/review/version/inspection-document/finding/follow-up subresources carry `organization_id`. +35. Inspection lifecycle and inspection outcome are separate. +36. Inspection follow-ups are explicit resources. +37. Engineering change requests remain deferred until fully specified. +38. Shared documents own document records; profession modules own link tables. +39. Legal does not duplicate shared document ownership. +40. Large files use object-storage multipart uploads. +41. Application servers do not proxy multi-gigabyte chunks. +42. Document checksums belong to document versions. +43. Document classification is multi-level. +44. Document retention is explicit policy. +45. Document category uniqueness must work for nullable profession values on the selected PostgreSQL version. +46. Project document linkage does not imply client-portal publication. +47. External publication requires explicit publication records. +48. Client portal accounts are not internal memberships. +49. Client acceptance is not professional engineering approval. +50. Domain events use a transactional outbox. +51. Outbox delivery is at-least-once. +52. Outbox events carry correlation/causation identifiers. +53. External side-effect consumers are idempotent. +54. Webhook subscriptions and deliveries are tenant-owned. +55. HMAC signing secrets are securely recoverable/encrypted, not only hashed. +56. Jobs are tenant-scoped by the standard organization header, and every `job_type` is registered with schemas, authorization, retry, and idempotency behavior. +57. PostgreSQL is the authoritative transactional datastore. +58. Redis is acceleration/coordination, not critical source of truth. +59. Search starts with PostgreSQL. +60. Collections use cursor pagination, default 25 and max 100. +61. Important mutable resources use optimistic concurrency. +62. Database entities are not serialized directly. +63. Errors use stable codes. +64. `429` responses use `Retry-After`; exact quota headers are an API decision. +65. Business records use explicit archive/revoke/unlink/hard-delete lifecycle policies. +66. Financial/professional/audit records are not casually hard-deleted. +67. Audit metadata is minimized and supports governed privacy transformation when required. +68. Important/regulated actions are audited. +69. Signed clinical records use sign/amend/version workflows. +70. Prescribing authority remains jurisdiction/scope-of-practice policy. +71. Production migrations use expand/contract. +72. Destructive changes are not assumed trivially reversible. +73. Secrets remain outside source control. +74. CORS and browser security policy are explicit ADR/configuration. +75. Rate limits are calibrated by evidence. +76. CI validates types, tests, OpenAPI, migrations, and security checks. +77. Property-based tests cover high-value state machines. +78. Outbox/job/webhook reliability is tested under failure/concurrency. +79. Critical-path tests matter more than vanity coverage percentages. +80. Framework/ORM/queue/PostgreSQL-minimum choices require ADRs. +81. Engineering is the first vertical. +82. Client portal follows internal Engineering MVP foundations. +83. Legal follows after Engineering validates shared assumptions. +84. Healthcare requires dedicated privacy/security/domain design before implementation. +85. Architecture documentation never equates "designed for" with "certified/compliant". + +## 95. Required Design Artifacts + +Maintain: + +```text +01_PROJECT_ARCHITECTURE.md +02_DATABASE_CONVENTIONS.md +03_AUTHORIZATION_MODEL.md +04_AUTH_SESSION_MODEL.md + +05_ENGINEERING_DOMAIN.md +06_ENGINEERING_DATABASE_SCHEMA.md +07_ENGINEERING_STATE_MACHINES.md + +08_API_CONVENTIONS.md +09_ENGINEERING_API_SPEC.md +10_OPENAPI.yaml + +11_FRONTEND_ARCHITECTURE.md +12_CLIENT_PORTAL_SECURITY_MODEL.md + +13_DOCUMENT_SECURITY_MODEL.md +14_LARGE_FILE_UPLOAD_MODEL.md + +15_WEBHOOK_INTEGRATION_MODEL.md +16_ASYNC_JOB_MODEL.md + +17_SECURITY_MODEL.md +18_DEPLOYMENT_ARCHITECTURE.md +19_OBSERVABILITY_MODEL.md +20_TESTING_STRATEGY.md + +21_ARCHITECTURE_DECISION_RECORDS/ +22_RISK_REGISTER.md +23_MVP_BACKLOG.md +``` + +Important ADRs: + +```text +backend framework +persistence/query layer +queue implementation +PostgreSQL minimum version +error format +rate-limit headers +webhook signing +object-storage provider +``` + +## 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 need efficient tenant scoping. + +Baseline: + +```text +(organization_id, id) +``` + +Common list access often benefits from: + +```text +(organization_id, created_at) +``` + +Query-specific examples: + +```text +(organization_id, status) +(organization_id, client_id) +(organization_id, project_id) +(organization_id, assigned_to_user_id) +``` + +### Rules + +1. every index corresponds to a known query, ordering, or constraint +2. column order follows real predicates +3. validate with `EXPLAIN (ANALYZE, BUFFERS)` +4. include production-like cardinality in testing +5. measure write amplification +6. do not index every field +7. introduce trigram/full-text indexes only for actual search requirements + +Potential later tools: + +```text +covering indexes +materialized views +read replicas +table partitioning +external search +``` + +These are evidence-driven scaling mechanisms, not baseline dependencies. + +### Document Category Uniqueness + +If a nullable field such as profession participates in uniqueness: + +```text +organization_id +profession nullable +name +``` + +do not assume plain uniqueness treats NULL as one shared value. + +Use PostgreSQL-supported null-aware uniqueness or partial unique indexes according to the selected PostgreSQL version. + +--- + +## 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. + + +### Feature Flags + +Feature flags used for deployment safety are operational configuration, not automatically a business database table. + +Initial implementation may use: + +```text +environment/config-service flags +``` + +for global rollout and kill switches. + +If per-organization feature rollout is later required, introduce an explicit tenant-owned model such as: + +```text +organization_feature_flags +``` + +through an ADR/migration. + +Do not overload `organization_professions` with unrelated product experiments. + + +### 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. + +--- + +## 97D. Provisional Performance Objectives + +Performance numbers in architecture are starting hypotheses, not guarantees. + +Initial engineering objectives may begin with: + +```text +Interactive read: + target p95 <= 500 ms + +Interactive mutation: + target p95 <= 750 ms + +Simple list/search: + target p95 <= 800 ms + +Upload authorization: + target p95 <= 300 ms + +Background outbox pickup: + target <= 5 seconds under normal operating conditions +``` + +These are revised after realistic testing. + +Track: + +```text +p50 +p95 +p99 +throughput +error rate +database saturation +queue backlog +outbox lag +``` + +Different endpoint classes receive different SLOs. + +Do not use file-transfer completion time as an API SLO when bytes travel directly between client and object storage. + +--- + +## 97E. Risk Register + +Maintain a living risk register. + +Suggested structure: + +| Risk | Impact | Mitigation | Owner | Phase | Status | +|---|---|---|---|---|---| +| Cross-tenant data exposure | Critical | Tenant-aware FKs, scoped queries, security tests | Backend/Security | P0 | Open | +| Non-idempotent outbox side effect | Critical | Consumer dedupe, provider idempotency, chaos tests | Backend | P0 | Open | +| Migration failure | High | Expand/contract, dry runs, backups | Backend/Platform | P0 | Open | +| Engineering workflow mismatch | High | Domain expert validation | Product/Engineering SME | MVP | Open | +| Portal authorization leak | Critical | Separate external access model, publication grants | Backend/Security | Portal | Open | +| Webhook delivery instability | Medium | Retry, dead-letter, replay, metrics | Backend | Integrations | Open | +| Large upload abandonment | Medium | Multipart expiry and cleanup | Backend/Platform | Documents | Open | +| Documentation drift | Medium | OpenAPI validation, ADRs, CI | Engineering | Continuous | Open | + +Do not pretend likelihood labels are quantitative unless the team defines and uses a scoring method. + +--- + +## 97F. Architecture Change Governance + +v4 is the last broad platform-architecture revision before Engineering MVP implementation. + +New discoveries should normally become: + +```text +ADR +OpenAPI change +database migration +domain-state-machine update +security decision +backlog item +runbook +``` + +rather than a new full architecture rewrite. + +Reopen the broad architecture only when a discovery invalidates one of these foundational assumptions: + +```text +tenant model +profession separation +shared-core boundary +REST API model +data ownership +security trust boundary +deployment topology +database architecture +``` + +This prevents design review from becoming an infinite recursion problem. + +--- + +## 97G. Production Readiness Gates + +Architecture being coherent does not mean production is safe. + +Before production, require evidence in these categories. + +### Security + +```text +TLS configured +password hashing configured +refresh rotation/reuse detection tested +session revocation tested +tenant isolation tests passing +authorization/credential policies tested +rate limiting active +secrets managed outside source control +file security scanning active +security review completed +``` + +### Reliability + +```text +database backups automated +restore tested +object storage recovery strategy tested +outbox monitoring active +job queue monitoring active +webhook retry/dead-letter behavior tested +health checks configured +dependency failures tested +``` + +### Data Integrity + +```text +tenant-aware foreign keys present where required +financial invariants tested +migration tested on production-like data +idempotency tested for high-risk commands +optimistic concurrency tested +audit integrity tested +``` + +### Contract / API + +```text +OpenAPI validates +contract tests pass +error schema consistent +versioning rules documented +client SDK generation validated if used +``` + +### Performance + +```text +load test executed +realistic SLOs defined +database pool configured +key queries analyzed +outbox/job backlogs remain within SLO +``` + +### Critical Domain Coverage + +Rather than a magic overall coverage number, require explicit test coverage for: + +```text +tenant boundaries +design approval +inspection completion +invoice issue +payment/refund +membership privilege changes +clinical record signing/amendment when healthcare exists +prescribing authorization when healthcare exists +``` + +### Release Gate Principle + +No single metric such as: + +```text +90% test coverage +``` + +is sufficient evidence of production readiness. + +Quality gates are based on critical behavior, not vanity percentages. + +--- + +## 97. Final Design Position + +The platform is: + +```text +One Shared Platform + │ + ├── Shared Identity / Sessions + ├── Shared Security / Authorization + ├── Shared Documents / Multipart Uploads + ├── Shared Financial Core + ├── Shared Audit / Outbox + ├── Shared Jobs / Webhooks / Notifications + │ + ├── Engineering Internal Product + │ ├── Engineering Frontend + │ ├── Engineering REST APIs + │ ├── Engineering State Machines + │ └── Engineering Tables + │ + ├── Engineering Client Portal + │ ├── External Portal Frontend + │ ├── Portal Accounts + │ ├── Project Grants + │ ├── Published Documents + │ └── Client Review / Acceptance + │ + ├── Legal Product + │ ├── Legal Frontend + │ ├── Legal REST APIs + │ └── Legal Tables + │ + └── Healthcare Product + ├── Healthcare Frontend + ├── Healthcare REST APIs + ├── Healthcare Security Policies + └── Healthcare Tables +``` + +The system shares infrastructure where reuse is valuable while preserving profession-specific domain semantics and trust boundaries. + +v4 is the final broad architecture baseline for Engineering MVP implementation. + +From this point forward, architecture detail should primarily move into: + +```text +ADRs +OpenAPI +database schema/migrations +state-machine specifications +security policies +implementation backlog +runbooks +``` + +rather than repeatedly rewriting the entire architecture plan. + +This document does not itself prove: + +```text +regulatory compliance +production certification +security certification +performance at a specific scale +``` + +Those require implementation evidence, security review, domain validation, operational testing, restore testing, and measured production-like workloads. + + + + +--- + +# v4.1 Changelog + +v4.1 resolves implementation-contract issues without changing the core architecture. + +```text +✓ raw UUIDv7 API ID contract +✓ camelCase API / snake_case database naming convention +✓ direct organization_id on tenant subresources +✓ invitation role assignments +✓ service accounts and hashed API keys +✓ multiple professional credentials per profile +✓ global archive/revoke/unlink/hard-delete policy +✓ project stage duplication removed +✓ project budget_minor removed +✓ project phase reorder command +✓ global engineering site listing +✓ task status and priority vocabularies +✓ design revise endpoint +✓ design-assignment schema and temporal unassignment +✓ design-version many-document cardinality +✓ design review/version tenant keys +✓ inspection finding tenant keys +✓ explicit inspection follow-up table +✓ inspection-document link schema and REST +✓ change requests deferred until fully specified +✓ time-entry work-item attribution +✓ time-entry project/work-item consistency constraints +✓ specification many-document cardinality and status values +✓ specification lifecycle commands and document REST +✓ legal_documents duplication removed +✓ legal matter/case document-link schemas +✓ healthcare placeholder schemas clarified +✓ invoice-item schema defined +✓ shared billing-account invoice reference +✓ payment and refund schemas +✓ document retention-policy schema +✓ explicit retention-period null semantics +✓ version-independent document-category uniqueness fallback +✓ standard upload DTO +✓ multipart-init/parts/complete DTOs +✓ webhook subscription schema +✓ webhook status vocabulary +✓ webhook delivery references outbox events +✓ typed job input/result references +✓ registered job-type vocabulary +✓ organization, user, membership, profile, service-account, invoice, and client vocabularies +✓ portal access profiles and client-review-request schema +✓ project-member PATCH contract +✓ derived project phase; no current_phase_id in v1 +✓ time-entry billing snapshot constraint +✓ logout endpoint +✓ assigned-scope resolution rules +✓ audit privacy transformation strategy +✓ outbox correlation and causation IDs +✓ CORS/browser-security ADR +✓ feature-flag strategy clarified +✓ jobs confirmed tenant-scoped via X-Organization-Id +``` + +The next artifacts should be implementation-specific: + +```text +ADRs +Engineering OpenAPI +Engineering database migrations +Engineering state-machine spec +Engineering MVP backlog +```