-
-
Notifications
You must be signed in to change notification settings - Fork 0
Areas
Built (the Master Data Areas epic). A first-class, hierarchical Area entity in master-data, plus the location
areaIdlink and the area-scoped mobile-work it enables (per-operator reservation of count lines and replenishment tasks).
An area is a named, nestable region of a warehouse used to scope operator work: a building, a level, an aisle range, a zone. Areas are owned by master-data and are first-class catalog objects (create, edit, archive), exactly like SKUs, locations or storage blocks.
- An area belongs to a warehouse and may nest inside another area via
parentAreaId, so areas form a tree (a level contains aisles, an aisle contains zones, …). New tablearea(FlywayV19). - A location carries an optional
areaId(location.area_id), so a location belongs to at most one area. An area's effective scope is itself plus every descendant area beneath it. - Guards: a parent area must be in the same warehouse (cross-warehouse parenting is rejected), and the parent chain may not form a cycle (an area cannot be its own ancestor). Both are validated on create and update.
- There is no persistent operator → area binding. An operator chooses (or scans) their area on the
handheld; the chosen
areaIdlives only in the running process instance's data object.
RBAC-gated like the rest of master-data CRUD; see contracts/openapi/master-data.yaml.
| Method / path | Purpose |
|---|---|
GET /api/master-data/areas?warehouseId=&parentAreaId= |
List areas. Omit parentAreaId for top-level areas; supply it for the direct children of an area. |
POST /api/master-data/areas |
Create an area (name/code, warehouse, optional parentAreaId). |
GET /api/master-data/areas/{id} |
Read one area. |
PUT /api/master-data/areas/{id} |
Edit an area (rename, re-parent within guards). |
DELETE /api/master-data/areas/{id} |
Soft archive the area. |
GET /api/master-data/areas/{id}/location-ids?recursive=true |
Resolve the area to the set of location UUIDs in its subtree. A recursive CTE walks the area tree from {id} down and returns every location whose area_id is anywhere in that subtree. With recursive=false it returns only the area's own directly-assigned locations. |
GET /api/master-data/areas/resolve?warehouseId=&ref= |
Resolve an area by reference (code) for handheld scan/verify → {found, areaId, areaCode, …}. By design a 200 found:false on a miss (never 404). Backs the process-designer area verify kind. |
The location-ids?recursive=true call is the primitive everything else builds on: an operator
picks an area, and a service reserves only work whose location is inside that subtree.
Two services consume the area subtree to hand operators only their area's work, one piece at a time, with a per-operator reservation so two people in the same area never grab the same item.
-
POST /api/counting/lines/claim-next {warehouseId, areaId, instanceId}atomically reserves the next PENDING count line whose location is inside the area subtree (resolved viaGET /api/master-data/areas/{id}/location-ids?recursive=true, identity forwarded), using PostgresFOR UPDATE SKIP LOCKEDso concurrent operators never claim the same line. Returns{found, countTaskId, lineId, locationId, skuId, expectedQty, uomCode, countType}or{found:false}. -
POST /api/counting/lines/release {instanceId}frees every not-yet-started reservation held by the instance (idempotent; returns{freed}). - The first recorded count stamps
started_at, making the line immune to release and to the sweeper. - Schema:
count_linegainsreserved_by/reserved_at/reserved_by_instance/started_at(V6). A ShedLock sweeper reclaims stale reservations (TTLopenwcs.counting.reservation-ttl, default 15m).
-
POST /api/slotting/replenishment/claim-next {warehouseId, areaId, instanceId}reserves the next PLANNED replenishment (collection) task whose destination pick face (to_location_id) is inside the area subtree, EMERGENCY priority first, sameFOR UPDATE SKIP LOCKEDguarantee. Returns{found, taskId, skuId, fromLocationId, toLocationId, qty, uomId, priority}. -
POST /api/slotting/replenishment/release {instanceId}frees not-yet-started reservations. -
started_atis stamped on dispatch; the sweeper TTL isopenwcs.slotting.reservation-ttl(default 15m). Schema:replenishment_taskgains the same four reservation columns (V8).
-
Reserved:
claim-nexthands the operator the next line/task for their instance. -
Firm claim: once the first count or move is posted,
started_atis set; a started item is never released or swept. -
Freed: by an explicit release (a
work.releasestep on the flow's exit branch, see the Mobile Process Designer) or by the TTL sweeper if the app is closed / crashes, so an abandoned reservation never wedges an item forever.
The handheld side of this (the stockcheck.next, replenishment.next and work.release curated tasks,
the area verify kind, and the seeded stock-check-by-area reference process) is documented on the
Mobile Process Designer page.
In the Master data section the UI gains an Areas tab with an AreaDialog for creating and
editing nested areas (the parent select excludes the area itself and its descendants, so the tree
stays acyclic), and the Locations screen gains an Area select so a location can be filed under
an area.
area and location.area_id live in the master_data schema. Counting and slotting reference the
resolved location UUIDs by value (no cross-schema foreign keys); they call master-data over HTTP with
the operator's forwarded identity to resolve an area to its location-ids. See Architecture and
Services.
openWCS — open-source Warehouse Control System · summarized from build.md & docs/AS-BUILT.md (the repo docs are authoritative).
Design
Flows
- Areas
- Inbound and Inventory
- Slotting and Replenishment
- Goods-to-Person Stations
- Outbound Flow
- Equipment Integration
- Transport Overview
- Process Designer
- Mobile Process Designer
- Hardware Visualisation
- Host Integration
Reporting & Dashboards
Operations