# Architecture

c-care is a modular Django monolith backed exclusively by PostgreSQL/psycopg.
`apps.commercial` owns service quotations, immutable presented revisions and
customer decision evidence. It introduces an approval gate only after explicit
customer-pay responsibility, preserving unclassified quotation-free technical
workflows. It does not move inventory or introduce payments. See
[service quotation](SERVICE_QUOTATION.md) for its monetary, scope and lock rules.
Phase 3C.2 adds immutable final service invoices and audited allocations connecting
actual consumed parts to approved quotation lines, with explicit performed-service
confirmation. Billing preserves payer value, uses the existing case lock, and
does not require invoicing retroactively for frozen handover workflows. See
[service invoice](SERVICE_INVOICE.md) for reconciliation and issuance rules.
`config` owns composition, settings, entry points, and application health.
`apps.accounts` owns the custom User, introduced before initial migrations.
`apps.organization` owns Company, Region, ServiceCenter, and Department master
data and user organizational assignments (a swappable user FK keeps accounts
independent). Assignments represent placement, not permissions; see
[assignments](ASSIGNMENTS.md). Its app-local abstract record shares fields and validation across these four
models. Django templates and standard admin remain sufficient. See
[organization domain](ORGANIZATION.md) for constraints and integrity boundaries.

`apps.access` owns global business roles, native Django permission memberships and
scoped user role assignments. It depends on organization; explicit synchronous
organization lifecycle hooks preserve one-way imports. Its permission query is an
unscoped inventory. The separate [authorization engine](AUTHORIZATION.md) combines
permission and scope from the same valid role-assignment path, using explicit
organization adapters for point decisions and SQL queryset filtering. See [RBAC](RBAC.md)
for role/lifecycle ownership. Native Django authentication remains unchanged.

`apps.catalog` owns global Brand, ProductCategory, ProductModel and ProductVariant
master data, with validated ownership and explicit lifecycle services. It has no
company scope or physical-device/inventory fields; see [catalog](CATALOG.md).
The frozen organizational authorization adapters are unchanged.

`apps.service_catalog` owns ServiceCategory, ComplaintSymptom, FaultDiagnosis,
RootCause and RepairAction as separate global vocabularies, with explicit product
category applicability. These are definitions, not job-level findings or repair
execution; see [service taxonomy](SERVICE_TAXONOMY.md).

`apps.parts` owns global PartCategory and SparePart masters, explicit serialization
policy, and retained model-wide or exact-variant compatibility with the catalog.
Model-only selection excludes variant-restricted parts; variant selection includes
its model-wide and exact-variant mappings. Transactional services and signed Admin
revisions protect configuration, while SQL queries enforce current active-state
eligibility. RepairAction remains independent. No physical stock, inventory
transaction, repair consumption or operational inventory authorization is introduced;
see [service parts](SERVICE_PARTS.md).

`apps.inventory` owns company-scoped locations, physical serialized part units
and immutable stock movements/ledger entries. StockPosition is a quantity-free
lock anchor; balances are SQL sums of the ledger. Operational commands reuse the
existing Company/ServiceCenter authorization targets and dependency-first locks.
The approved integration guard permanently locks a SparePart's serialization
policy after its first unit or posted movement, while drafts alone do not lock it.
See [inventory ledger](INVENTORY_LEDGER.md) for the Phase 3B.2 checkpoint.

`apps.customers` owns company-scoped Customer business identities, separate from
login users. Transactional company-scoped numbering, validated mutation services
and active-company query filtering preserve ownership without extending frozen
organization lifecycle or authorization adapters. See [customers](CUSTOMERS.md).
CustomerAddress and CustomerContact hold protected customer-owned address and
additional-contact records. Customer-coordinated services manage lifecycle and
explicit address/per-contact-type primaries; quick Customer phone/email fields
remain independent. Customer business access integration remains future work;
explicit service presenter relationships now live in `apps.service`.

`apps.devices` owns physical Device units and permanently reserved identifier
history, separate from commercial catalog definitions and Customer identity.
Registration/current corrections use catalog identification policy under compatible
locks. Separate DevicePurchaseEvidence and DeviceWarrantyCoverage records hold
reviewed acquisition facts and explicit coverage periods with retained coverage
history. They do not approve repair claims or establish Customer ownership.
CustomerDeviceRelationship separately records immutable OWNER periods, with
transactional assignment/end/transfer and permanent company affinity derived from
Customer history. PostgreSQL uniqueness and range exclusion protect the timeline.
Device has no cached owner/company. Recorded owner is not purchase evidence, a
warranty-holder assumption, service presenter or service requester; future service
transactions must capture their own actors. See [devices](DEVICES.md).

`apps.service` owns ServiceCase intake/job cards with explicit Company, ServiceCenter,
presenting Customer and Device references. Per-center counters allocate job numbers;
complaints, condition/accessory records and immutable warranty snapshots retain intake
history. RECEIVED, ASSIGNED, DIAGNOSING, DIAGNOSED, REPAIRING, REPAIRED, QC_PENDING,
QC_IN_PROGRESS, QC_PASSED and CANCELLED are the states;
cancellation preserves children. Presenters
need not be recorded owners, and intake never assigns ownership or approves a repair
claim. Services enforce integrity under compatible locks; business authorization and
downstream workflows remain separate work. See [service intake](SERVICE_INTAKE.md).

Phase 3A.2 adds protected ServiceEngineerAssignment periods and explicit assign,
reassign/unassign services. Existing Users qualify through same-path organizational
scope and `service.handle_servicecase` permission; no Engineer identity or frozen
authorization adapter is introduced. Cancellation ends the current period atomically.
SQL operational queues exclude lost eligibility while Admin/history retain the
assignment for recovery. See [engineer assignment](ENGINEER_ASSIGNMENT.md).

Phase 3A.3 binds ServiceDiagnosticAssessment to the responsible assignment period
and records multiple FaultDiagnosis findings with optional RootCause. Unknown causes
remain NULL, including at completion. Technical writes require the current eligible
engineer; explicit abandonment/cancellation preserve history for recovery. Completed
assessments are immutable and assignments continue through DIAGNOSED. See
[engineer diagnosis](ENGINEER_DIAGNOSIS.md).

Phase 3A.4 adds protected repair attempts and explicit planned/performed RepairAction
rows. Successful completion reaches REPAIRED; unsuccessful completion or abandonment
returns to DIAGNOSED with immutable attempt history. Assignment remains current;
cancellation during repair abandons the attempt and ends the assignment atomically.
See [engineer repair](ENGINEER_REPAIR.md).

Phase 3A.5 adds independent QC attempts, a versioned service checklist and original
complaint verification. Same-path `service.perform_quality_control` duty cannot be
substituted by staff/superuser privileges, and engineers cannot QC their own repair.
PASS reaches QC_PASSED; FAIL preserves evidence and returns to DIAGNOSED for new
repair. See [quality control](QUALITY_CONTROL.md).

`base.py` holds shared settings. `development.py` reads DEBUG and allows loopback
hosts. `production.py` forces DEBUG off, requires an independent strong secret
and explicit hosts, redirects HTTP to HTTPS, and enables secure cookies and HSTS.
`manage.py` defaults to development; ASGI/WSGI default to production. Explicit
DJANGO_SETTINGS_MODULE always wins. Runserver inherits development from manage.py.

Production requires HTTPS, its own environment/secrets, a reviewed application
server, and separate static/media serving. No production server dependency or
deployment infrastructure is selected in Phase 1A. Configure trusted CSRF origins
only when required. Proxy SSL headers are intentionally not trusted by default;
declare exactly one trusted hop with DJANGO_TRUSTED_PROXY_HEADER only after
verifying that a trusted proxy strips client values. HSTS applies only to the
current host by default; subdomain and preload coverage are explicit operator
opt-ins because both are whole-domain commitments. Run
`python manage.py check --deploy --settings=config.settings.production` using
production configuration before deployment. Never deploy with the local `.env`.

Phase 5D separates the two monitoring concerns in `config`. `/health/` is
liveness only and touches no database, configuration or filesystem.
`/ready/` additionally performs one bounded read inside a transaction-local
statement timeout and returns HTTP 503 when the database is unusable. Neither
endpoint discloses a version, hostname, database name or exception. Project error
responses (400/403/404/500) are rendered from standalone templates that use no
context processor, URL reversing, static file or database access, because Django
renders `500.html` from an empty context. Production logging is console-only;
rotation and retention belong to the host. See
[production deployment](PRODUCTION_DEPLOYMENT.md) and
[operations runbook](OPERATIONS_RUNBOOK.md).

Future apps must remain domain-oriented with thin views. Complex transactional
workflows belong in explicit services. Enforce important invariants using database
constraints and application validation. Use transactions, locking, append-only
history, and reconciliation tests where domain requirements justify them.
Authorization must be enforced server-side; hidden buttons are not authorization.
Avoid circular dependencies, hard-coded roles, and generic utility dumping grounds.
Organization, assignments, RBAC, and scoped authorization are implemented.
Phase 3A.6 adds explicit service-center release, recipient/accessory handover and
terminal closure through [SERVICE_HANDOVER.md](SERVICE_HANDOVER.md). Delivery ends
the engineer assignment atomically and does not transfer Device ownership.
No inventory, general audit-log, API, or asynchronous processing is implemented.

See [ADR 0001](ADR/0001-foundation.md) for identifier and foundation decisions.

Phase 3C.3 adds immutable invoice-specific payments, allocations, receipts and
reversals in `apps.commercial`. Settlement is derived from CUSTOMER liability and
posted allocations. Handover rechecks settlement or an explicit scoped due-release
under the existing case lock; invoice-free workflows remain compatible. See
[service payments](SERVICE_PAYMENT.md) for APIs, lock order and financial boundaries.
