Work-Order Persistence¶
Summary of MongoDB persistence rules for:
POST /api/v1/inbound/work-orders(live writes)
The public format-validation endpoint POST /api/v1/inbound/work-orders/test does not use this persistence plan. See Inbound Work Orders.
API usage and examples: Inbound Work Orders.
Scope¶
The live endpoint validates then persists accepted projects to customer MongoDB collections:
projectsproductsmachines(read-only resolution)users(read-only resolution)
The test endpoint validates JSON/XML format and contract only. It never reads or writes business collections, never writes api_idempotency_records, and never writes api_request_archive.
Live endpoint idempotency (Idempotency-Key) and raw request archive are implemented. See Idempotency and Request Archive.
Tenant fields¶
Every request resolves a tenant from root company_id and organization_id using the same pair-and-fallback rules as outbound GET endpoints:
| Situation | Result |
|---|---|
| Both request values present | Use the request pair |
| Neither request value present | Use DEFAULT_COMPANY_ID and DEFAULT_ORGANIZATION_ID when both are configured |
| Exactly one request value present | Request rejected (TENANT_CONTEXT_INCOMPLETE) |
| Neither request nor configured defaults | Request rejected (TENANT_CONTEXT_REQUIRED) |
All lookups are scoped to the resolved tenant. The service never operates without a tenant filter.
Collection type differences¶
Existing schemas are preserved (no type migration in this release):
| Collection | company_id / organization_id |
|---|---|
projects |
ObjectID |
machines |
ObjectID |
products |
string |
users |
string |
Natural keys¶
| Entity | Key |
|---|---|
| Project | tenant + project_code |
| Production | production_code within a project document |
| Stage | production_stage_code within a production |
| Product | tenant + product_code |
| Machine | tenant + machine_code |
| Employee | tenant + username |
Product upsert¶
All product occurrences in the payload are upserted into products:
- Create when missing; keep
_idwhen updating - Update mutable fields:
product_name,category,unit,ideal_cycle_time - Do not change
product_code - Preserve existing
descriptionandimage_url quantitystays on embedded occurrences only- Same
product_codemay appear multiple times; master upsert can run once while occurrences keep distinct quantities
Project / production / stage merge¶
- New project when code is unknown; update when code and name match
- Same code with different name → skip project (
PROJECT_NAME_CONFLICT); do not modify the document - Unsent existing productions and stages are preserved
- Matched productions/stages update contract fields; operational fields (
production_stage_operation, files, status when not in contract) are preserved - New production stages default to integer
status: 0(BSON integer). Existing stage status values are never overwritten by the request - If all incoming stages for a production are skipped → production skipped (
ALL_STAGES_SKIPPED) - If all productions for a project are skipped → project skipped (
ALL_PRODUCTIONS_SKIPPED)
Shared processing plan¶
The live endpoint builds one deterministic ProcessingPlan after validation:
- Decode → normalize → contract validation
- Tenant ObjectID and duplicate checks
- Integration actor validation
- Project / product / machine / employee lookups (reads)
- Product create/update/unchanged preview
- Production and stage merge preview, including skip rules
Then live applies the plan with MongoDB writes.
The public test endpoint stops after decode/normalize/contract validation and does not build or apply a processing plan.
Test / live difference¶
A successful format test does not guarantee a later live request will succeed. Live processing still depends on database state, tenant resolution, actor configuration, and business rules.
Machine resolution¶
Machines catalog is read-only. Missing machine_code skips the entire stage (MACHINE_NOT_FOUND). Empty machines arrays are allowed. Canonical machine_name / machine_code come from MongoDB.
Employee resolution¶
Users catalog is read-only. Missing username skips only that assignment (EMPLOYEE_NOT_FOUND) and does not skip the stage. Password, email, phone, and role are never embedded.
Partial processing¶
Projects are processed independently. Response data.status:
success— all received projects processedpartial_success— at least one processed and one or more skipped- HTTP 409
NO_PROJECT_PROCESSED— none processed
Integration actor¶
INTEGRATION_ACTOR_USER_ID supplies audit ObjectIDs / hex strings for new and updated project/product audit fields. It must be the ObjectID of an existing active user in the same Users store used at runtime. A random ObjectID is invalid even if the hex format is correct. Known actor failures return HTTP 409 (INTEGRATION_ACTOR_USER_NOT_FOUND, INTEGRATION_ACTOR_USER_INACTIVE, INTEGRATION_ACTOR_TENANT_MISMATCH) instead of INTERNAL_ERROR. Responses never include the actor ObjectID. See Configuration and Error Codes.
Standalone MongoDB¶
No multi-document transactions. Project document writes are single-document atomic. Product upserts are independent; products may remain if a later project write fails.
Related HTTP codes¶
| Code | HTTP |
|---|---|
NO_PROJECT_PROCESSED |
409 |
INTEGRATION_ACTOR_USER_NOT_FOUND |
409 |
INTEGRATION_ACTOR_USER_INACTIVE |
409 |
INTEGRATION_ACTOR_TENANT_MISMATCH |
409 |
DATABASE_UNAVAILABLE |
503 |
INTERNAL_ERROR |
500 |