Supply Chain & Parts, Vehicle Operations and Production — Product Specification
Supply Chain & Parts, Vehicle Operations and Production — Product Specification
Section titled “Supply Chain & Parts, Vehicle Operations and Production — Product Specification”1. Overview
Section titled “1. Overview”Rechaj runs procurement and inventory across two internally owned systems: Atlas, the operational system of record where the flow originates and where inventory lives, and Polaris, which holds requisitions, orders, and amounts (a ticketing and expense surface). Today the two systems are stitched together by hand, and the day-to-day inventory job runs on paper and spreadsheets.
This specification defines the improved procurement-and-inventory flow end to end — Needed → Requested → Ordered → Shipped → Delivered → Used, plus the return path for delivered-but-unused stock and the facility request path that draws on it — and the digital surfaces that replace the manual process. It spans three units. Supply Chain & Parts buys and holds: the Inventory Manager and the Procurement Manager. Production and Vehicle Operations draw on that stock at their own facilities: the Production Manager and Production Inventory Manager, and the Retrofit Station Manager and Retrofit Station Inventory Manager. Six persona flows in all. The Inventory Manager surface is the fully designed reference implementation; the facility flows are built alongside it.
Problem statement
Section titled “Problem statement”- Order records are duplicated by hand. Every order is entered once in Atlas and again in Polaris, with the Procurement Manager copying the record across.
- Stock figures cannot be trusted. The confirmed root cause is a bug: items marked as received do not decrement (for issues) or populate (for arrivals) the on-hand count. This — not a cross-system sync gap — is the real stock-integrity problem.
- The process is manual and reactive. The Inventory Manager counts stock by hand every day, notices low stock by eye, and emails Procurement rather than triggering a request in the system.
- The catalog blocks work. Items not migrated from the legacy Sortly app cannot be added, so recipients cannot retrieve delivered goods.
- Labelling is ad hoc, dependent on one person’s judgment, with no controlled vocabulary, no unit of measure, and no serialized-vs-consumable distinction.
- Orders are rigid. They cannot be edited after creation, cannot carry supporting documents, cannot take a $0 cost, and are limited to air/sea shipment.
- There is no return path for delivered-but-unused stock, no home for faulty parts pulled during maintenance, and no consumption/usage logging at all.
- Cross-team demand is invisible. Production and Retrofit draw on the same consumable stock with no visible prioritization; a request for 10 rolls of tape was filled with 4 with no recorded reason.
- Dashboards exist for all four personas but are empty.
2. Goals & Success Metrics
Section titled “2. Goals & Success Metrics”| Goal | Success metric |
|---|---|
| Eliminate manual order duplication | Zero manually duplicated order records between Atlas and Polaris |
| Stock data can be trusted | On-hand counts move correctly on every receive, issue, transfer, and return; physical counts reconcile to system within tolerance |
| Full lifecycle visibility | Any stage of Needed → Used is viewable by the relevant person without asking anyone directly |
| Faster cycle time | Measurable reduction in average time-in-stage against a documented baseline |
| Reporting trusted across audiences | Finance, leadership, and inventory/procurement reports need no caveats |
3. Personas & Module Access
Section titled “3. Personas & Module Access”Six primary personas. Each lands on their Dashboard on login.
3.1 Inventory Manager
Section titled “3.1 Inventory Manager”Owns stock levels, labelling, and the receiving/returns desk for the warehouse (see §4 terminology). Identifies low stock and triggers requests to Procurement.
Navigation (built surface): Dashboard · Targets · Items · Item Categories · Batches · Requests · Delivery notes · Receiving · Production output · Returns · Investigations · Send feedback. Usage & reorder points is an inner page under Items, not a nav item; Notifications and Settings are reached from the topbar. Their inventory nav is labelled Inventory (they steward the whole store), not “My Inventory”. The Inventory Manager receives items from Procurement and owns batch creation, and is where finished production output is received into stock.
3.2 Procurement Manager
Section titled “3.2 Procurement Manager”Creates and manages orders, vendor relationships, the Atlas↔Polaris requisition handoff, dispatch of received goods to the warehouse, and the resolution of quarantined stock.
Navigation, six sidebar groups in this order: Overview (Dashboard) · Purchasing (Requests, Orders, Requisitions) · Receiving (Shipments, shown with a small grey “(inbound)” beside the label, and My Inventory) · Logistics (Delivery notes, shown with “(outbound)” beside the label, Vendors, Logistics contractors (§25)) · Exceptions (Quarantine, Variance cases (§24), Vendor returns) · Reports (Insights). The hint sits on the same line as the label, at 11.5px, weight 400, in the muted text colour. “Waybill” is not a module name anywhere in the Procurement UI. Procurement does not hold a Batches surface — batch records belong to the Inventory Manager, who receives from Procurement (§3.1, §7.4). The dashboard is the landing view and hosts a read-only Stock snapshot mirrored from Inventory (with a Location/warehouse column + filter — no central warehouse, §4). Requisitions is a read-only mirror of the requisitions raised in Polaris. My Inventory is Procurement’s own custody stock — goods received from vendors that have not yet been accepted by the warehouses. Only Requests carries a sidebar count badge, and it counts requests at Requested.
Dashboard. Four KPI tiles: Open requests (requests at Requested only · “Awaiting Procurement”), Urgent requests (requests at Requested marked high or urgent · “Marked high or urgent”), Orders in transit (orders at Shipped · “A shipment is in transit”) and Avg vendor lead time, shown to one decimal (“2.3 d”) and measured from date ordered to date delivered, per order (“Ordered to delivered, per order”). Below them, the Order lifecycle strip: Requests (at Requested) · Requisitions (pending in Polaris) · Ordered (orders at Ordered) · Shipped (shipments in transit; opens Shipments) · Delivered (delivery notes in transit or partially delivered; opens Delivery notes) · Used (serialized units consumed in the last 7 days). Each of the first five opens its register and shows a second muted line, “N in total”, under its meta line. Used opens nothing and does not react to hover.
Status tiles on every register. Requests, Orders, Requisitions and Shipments each lead with a row of clickable status tiles. All comes first and clears the status filter; clicking a status tile filters the table to that status, and clicking it again clears it. A tile counts the records passing the page’s other filters, so it says what clicking it will show.
| Register | Tiles (sub-line) |
|---|---|
| Requests | All (“Every request”) · Requested (“With Procurement”) · Ordered (“With the vendor”) · Delivery note issued (“With the carrier”) · Received (“With Inventory”) |
| Orders | All (“Every order”) · Draft (“Not sent”) · Requisition pending (“Sent to Polaris”) · Requisition approved (“Ready to ship”) · Ordered |
| Requisitions | All (“Every requisition”) · Pending approval · Approved · Rejected |
| Shipments | All (“Every shipment”) · In transit · Partially received · Delivered |
On the Requests queue the Requested by column shows the actual requester’s name with their team as a small badge beneath it. Teams are core’s TeamGroup: Production facility, Retrofit station, Telematics, Maintenance, Inventory, Delivery, Unclassified. The team is the floor requester’s: for a transfer the Inventory Manager escalated to Procurement, it is the floor person behind the transfer, not the Inventory Manager. On Requisitions, the Raised against cell puts the kind (Goods or Logistics) on its own line under the reference. A field row that shows a value with a qualifier or an action (“Road · Local”, “PDN-0007 · View”, a date and who recorded it) keeps an 8px gap between them, and on the vendor form each Contact channels Channel / Detail pair takes the full row width so a whole email address is visible.
Quarantine surface (Procurement-owned resolution): the queue of units the warehouse rejected on arrival or confirmed faulty on return. KPI row (awaiting release, returned to vendor, scrapped). The table stays scannable — Item, Vendor, Category, Qty, Source (receipt or return), Reported, Status, Return status — with the long reason, batch id, serials, and all history moved into a detail view opened on row click. Each row’s vendor is derived from its receipt id (receipt → vendor), so the trail from quarantine → receipt → vendor is unambiguous. Procurement releases an item one of two ways — Return to vendor or Scrap — each requiring a resolution note stamped to the audit trail. Accepting units into stock is not a Procurement action (that is Inventory’s call). On a return, the vendor return reference is system-generated and the return status shows on the table as it advances.
3.3 Production Manager
Section titled “3.3 Production Manager”Requests inventory for production; runs work orders and assembly at the Sango facility (the production/retrofit site — distinct from the Sango warehouse; see §4). System access tier is labelled “Forge Manager”; the person’s title is Production Manager.
Navigation: Dashboard · Targets · My Inventory · Work Orders · Assembly Procedures · My Facility · Category approvals · Investigations · Send feedback.
They no longer approve their team’s inventory requests. That gate moved to the Production Inventory Manager (§3.5, FR-TP4). This console reads the outcome: a team request sits at With inventory until the gate moves it, the With the inventory manager KPI counts what is still there, and the request detail names who it is waiting on. There is no Approve or Decline control and no approvals log.
3.4 Retrofit Station Manager
Section titled “3.4 Retrofit Station Manager”Requests inventory for retrofit work at the Sango facility. Within a facility roster this role appears as “Retrofit Station Manager”. Shares the Production Manager’s structural needs.
Navigation: Dashboard · Targets · My Inventory · Work Orders · Assembly Procedures · My Facility · Category approvals · Rider (under Rider Management) · Investigations · Send feedback.
They no longer approve their team’s inventory requests, on the same terms as §3.3; the gate is the Retrofit Station Inventory Manager’s (§3.6).
3.5 Production Inventory Manager
Section titled “3.5 Production Inventory Manager”Stewards the Production pool at the Sango facility: the shared team stock the Forge floor app draws on (Forge Floor App PRD §7.10, FR-FS1 to FR-FS9). Personal custody no longer exists on the floor — stock is received into the pool, the BOM gate reads the pool and a step draws from the pool — so the pool itself needs an owner. This is that owner, and they sit between the floor, which raises requests, and the warehouse, which fulfils them.
Navigation, two sidebar groups: Pool (Dashboard, Stock, Ledger, Returns, Recovery) · Supply (Requests, BOM forecast). Stock, Returns, Requests and BOM forecast carry a sidebar count; the count reads red when it is critical, waiting on a decision, or already past its order-by date.
They do not plan work orders or author procedures (§3.3), and they do not hold the catalog, receive from vendors or run batches and delivery notes (§3.1). They raise requests on the warehouse; the warehouse goes to Procurement.
3.6 Retrofit Station Inventory Manager
Section titled “3.6 Retrofit Station Inventory Manager”The same console against the Retrofit pool at the Sango facility, the second of the two team pools. The station fits kits rather than building them, so its bill of materials draws what Production made, and the forecast reads those lines as a production turnaround rather than a vendor lead time (FR-TP9). Its recovery stream is the chassis rather than the bench: every conversion gives up a petrol engine, a fuel tank and an exhaust (FR-TP13).
Navigation: identical to §3.5.
3.7 Supporting roles (planned, not yet built)
Section titled “3.7 Supporting roles (planned, not yet built)”Surfaced by the requisition/return workflow and the team hierarchy; scoped for a later phase:
| Role | Where it appears | Responsibility |
|---|---|---|
| Store Officer | “Issued By” / “Received By (Store)” on the requisition form | Issue items against approved requests, log faulty returns, produce delivery notes |
| Line Manager | Team hierarchy | View every request submitted by their team |
| Department Head / Maintenance-Technical Officer | Authorization signatures | Approve requisitions and faulty-return dispositions |
4. Terminology
Section titled “4. Terminology”- Warehouse — the inventory store at a location (the Inventory Manager’s domain, the supplier of stock). There is no central warehouse — each location has its own warehouse (Sango, Ikeja, Ibadan, Abuja warehouses). A warehouse and a facility can share a site name (Sango warehouse vs Sango facility) but are distinct entities.
- Sango facility — the production / retrofit site, run by the Production Manager and the Retrofit Station Manager. It requests stock from its warehouse, builds against work orders, and pushes stock back.
- Facility — the single requester type: the sites that raise requests and receive stock on delivery notes. Production/retrofit facilities and swap locations are all facilities (the term is facility, not “cluster”).
- Location tie (applies across all four personas). Every request carries a location, and that location determines its warehouse: a production or retrofit request from Sango routes to the Sango warehouse, an Ikeja request to the Ikeja warehouse, and so on — there is no central pool. Procurement’s delivery notes split by that location (one leg per warehouse); the Inventory Manager sees the requests tied to its location(s); and the requester + location travel to Polaris on the requisition. Location data is sourced from the Polaris database.
- Unit of measure — the canonical units are pcs · each · roll · metre · litre. The singular form is the unit token; count phrases pluralise (e.g. “3 rolls”, “10 metres”).
- Tracking — every item is either Serialized (a unique record, status and location per unit) or Consumable (counted in bulk).
- Atlas — operational system of record; owns all inventory and stock data.
- Polaris — holds requisitions, orders, and amounts only. It holds no inventory/stock data.
- Vendor — the external party a batch/receipt was ordered from and supplied by. The term vendor is used throughout (not “supplier”). A quarantined unit’s vendor is derived from the receipt it arrived on, never re-keyed.
- Quarantine — units held out of on-hand (never counted as available) for Procurement to resolve. Two sources: (1) units that arrived damaged or wrong from the vendor at receiving; (2) in-service items confirmed faulty on return from facilities/production/retrofit (including faults missed at receiving). Kept on record for the vendor-dispute trail until Procurement releases them back to stock, returns them to the vendor, or scraps them. A quarantined unit’s vendor is derived from its originating receipt. Faulty stock is the transient hold for a faulty return until the Inventory Manager confirms it and sends it to quarantine.
5. Information Architecture
Section titled “5. Information Architecture”All four persona surfaces run on the canonical Atlas web shell (1440, responsive down to mobile). Each lands on its Dashboard; breadcrumbs on every surface; a back affordance on every drill-down.
5.1 Inventory Manager
Section titled “5.1 Inventory Manager”The Inventory Manager surface is the fully built reference. Dashboard is the landing view and the first sidebar item.
| View | Purpose |
|---|---|
| Dashboard | KPI row (on-hand, low, critical, open requests to Procurement, pending returns). A days-of-cover table (On-hand / Assigned / ATP / Available / Burn·day / Days of cover, each column with a glossary tooltip and an “i” info icon). An Issuance window card showing the issuance timeslot the Inventory Manager sets, visible to requesters. Quick-action buttons that navigate to the correct pages, including a quick-link to Request from Procurement (on the Receiving page). An Export dashboard report button. |
| Items | Catalog stewardship. KPI row (catalog items, serialized, consumable, faulty held). Table shows a small item thumbnail beside the name, plus On-hand, ATP (beside On-hand, recalculated after receiving), category, tracking, UOM. New item and Edit item flows (see §7). A Thresholds button that opens Usage & reorder points. A Manual stock count action (cycle/physical count — see FR-C4). Row detail carries the item image and the quantity change history (audit log, CSV export). Column tooltips on this table. |
| Item Categories | Where Categories, Units of measure (UOM) and Item types are created and managed, plus new-category approval requests. Organised under tabs: Categories · Units of measure · Item types · Category requests (category requests live in their own tab, not stacked on the page). A category is a name + description, can be disabled (a disabled category, UOM or item type is hidden when creating an item). Each table shows an Item count column (how many catalog items use that category / unit / type). |
| Batches | Every batch received from vendors, each carrying its serialized units — an Inventory-Manager surface (Procurement holds no batches; amounts are hidden). List columns: Batch number, Item, Category, Qty received, Delivery, Date created. KPI row (total batches, delivered, in transit, quantity received). The Inventory Manager can log a received batch directly via a searchable item picker (selecting an item fills its category) plus qty, delivery status and received-from, with a system-generated B-YYMMDD-######## number. Opening a batch shows batch information and a batch items table (serial number, item, item type, location, custodian, status, transfer status); the custodian of each received unit, and the batch’s Received-by / Received-at, populate from the user who accepted the batch (and the location tied to them). The Inventory Manager confirms receipt here — per item or for the whole batch — which populates on-hand stock; used by faulty returns and traceability. |
transfers (view slug) → Requests |
Warehouse → facilities; serves facility requests. The page is named for what it holds — the requests coming in from facilities — not for the movement that answers them, which is the delivery note. Intro copy: “Facilities raise requests, a delivery note is issued, and the requests are fulfilled.” Fulfilling is the act that moves stock: it reduces on-hand, populates assigned, and lands the movement on the item’s movement history naming who fulfilled it and the request it went against; the delivery note prefilled from the request is the document the issued stock travels on. KPI row + a table of incoming facility requests with Fulfil, Reject (reason required), and Partial fulfilment (issue fewer than requested, with a reason) actions. Fulfil shows the request details, lets the user set the quantity fulfilled, then prompts to create a delivery note prefilled from the request. Reviewing a request does not fulfil it — fulfilling does: the fulfilment marks the request Fulfilled, and the row then shows the number of the delivery note raised from it. Reason and other long fields live in the request detail, not the table. Bulk fulfil several items from the same facility into a single delivery note. |
| Delivery notes | The inter-facility delivery-note surface (plural): new + history + detail. Line items are chosen from the catalog via a picker (not free text). Recent-note rows are clickable to a detail view with a Print action. Each note carries a Delivery status: In transit once issued, becoming Delivered (with date + time) when the requester accepts — that acceptance step is owned by a facility-side screen, so in this Inventory surface a note stays In transit. A note raised from a fulfil records the request id(s) it fulfils; a note issued directly (standalone) needs no request tie. |
| Receiving | What the warehouse receives from Procurement (vendor supply). Tables grouped under tabs: Request from procurement · Receive from procurement · Request variance · Quarantine. A quick-link in the page header opens Production output (finished kits are received there, not on a Receiving sub-tab). Summary KPI cards show pending receipts, arriving today, awaiting request, short/over this week, and in quarantine (the KPI jumps to the Quarantine tab). |
| Production output | A dedicated surface (own nav item) for finished-goods batches from closed work orders. Closing a work order creates a batch here automatically; the Inventory Manager then accepts the receipt into warehouse stock (Pending → Received), which restocks the kit’s on-hand in Items so a requester (e.g. the Retrofit Manager) can then request it. The output is serialized: units are serialized on the line when they pass QA, and those serials carry through on receipt — Inventory mints no new serials here (contrast the procurement/raw-material path, where the warehouse assigns serials). KPI row (to receive, units built this week, received this week). A quick-link back to Receiving sits in the header. |
| Returns | One view (labelled Returns) holding both return paths, separate from Requests. Delivered-but-unused restock — including facility push-backs of good stock — where accepting a return increments on-hand, and faulty-component returns (kept in a separate faulty stock count, never counted as available). Received by and the received date/time are auto-populated (the acting Inventory user and the completion timestamp), not typed. See §7. |
| Usage & reorder points | Cross-facility usage/consumption trend per item, with data-suggested reorder points. Applying a suggested reorder point updates the item’s thresholds. Filters + visible dates. |
| Notifications | Notification center: low/critical threshold alerts, incoming receipt notifications from Procurement (items to be received), returns, and other important events. Threshold alerts support multi-select + a bulk “Request from Procurement” action (per-line quantity editable); a per-row request is also available. |
Receiving tabs — detail
Section titled “Receiving tabs — detail”The Receiving page carries three tabs: Requests to procurement (the request log — a row appears when a request is raised and runs Pending → Received as the goods land, which is the same record throughout, so it is named for the request rather than the receipt), Request variance and Quarantine. There is no separate low-stock tab: raising a request from Procurement is a button on the page head and on the dashboard.
- Request from procurement — hosts the single and bulk request action. The request box opens a form where the user selects items (via a dropdown selector), sets quantities, a note, and an urgency. Quantity is editable per line.
- Receive from procurement — receipts with Pending → Received status. Pending populates from requests already sent to Procurement. Opening a receipt shows what was sent, takes the quantity received and an optional Dimension (cm), captures an image of what was received (viewable in the receipt detail), and verifies to populate the stock count — whether or not received quantity matches expected. Bulk receive presents the same per-item fields (quantity received, optional dimension, verify) for each selected receipt.
- Request variance — receiving-against-expectation table (expected vs received, short/over visibility). Carries a date filter and a variance filter. No row action.
- Quarantine — units sent to quarantine at receiving (damaged/wrong on arrival). Read-only for the Inventory Manager: columns are Item, Qty, From receipt, Reason, Reported, Photo (the receipt damage photo, click to enlarge), Status (Awaiting Procurement). The Inventory Manager can see quarantined stock but cannot release it — resolution is a Procurement responsibility (see §3.2 and §7.4).
5.2 Facility flows — Production Manager & Retrofit Station Manager
Section titled “5.2 Facility flows — Production Manager & Retrofit Station Manager”Both managers run full facility flows on the same shell. Navigation: My Inventory · Dashboard · My Facility · Work Orders · Assembly Procedures · Category approvals (the Retrofit Station Manager also carries Rider).
| View | Purpose |
|---|---|
| My Inventory | The facility’s own stock, under tabs Inventory · Requests · Outgoing · Incoming. Inventory lists on-hand facility stock with each item’s reorder point surfacing Low / Critical and a one-tap Request. Requests tracks items requested from the warehouse through their status. Outgoing holds stock the facility pushes out — back to Inventory (feeding Inventory Returns) or to a team member (an issue that draws down facility stock). Incoming holds stock issued to the facility that is In transit on a delivery note until the facility Accepts it into stock. |
| Dashboard | The landing view: facility KPIs, low/critical stock, open requests, work-order status. |
| My Facility | The facility record, under Overview (the facility’s profile and stock summary) and Team (its members, who raise requests the Manager approves). |
| Work Orders | The build queue. Building against a work order draws down facility stock; closing a work order creates a finished-goods batch in Inventory’s Production output surface (a Serialized finished-good, serialized on the line at QA — those serials carry through on receipt). A request may optionally link a work order, which prefills its bill of materials — but requesting is not locked to a work order. |
| Assembly Procedures | The reference assembly steps / bills of materials the facility builds against. An item can carry several named procedures, each Active at once and each under its own version history (e.g. the standard retrofit and the KAAG retrofit, §7.11a). |
| Rider (Retrofit only) | Rider management, under Rider Management. |
6. Lifecycle
Section titled “6. Lifecycle”Needed → Requested → Ordered → Shipped → Delivered → Used └──→ Unused / Returned| Stage | Behavior |
|---|---|
| Needed | Stock crosses a low/critical threshold; the Inventory Manager is alerted in-app and by email — a low line at once, a critical one in the next bundled critical alert (FR-U4) — and triggers a request to Procurement from within the system. Serialized items are requested on demand by name/type. |
| Requested | A formal requisition is created once, carrying urgency, and routed for approval. |
| Ordered | The requisition converts to a vendor Order — or, for BOM-driven material needs, to a Procurement Order (BOM + quantity + optional financing) that generates the underlying vendor Order(s). The order record exists in both Atlas and Polaris without manual re-entry. |
| Shipped | A shipment notice is logged with method (air / sea / road). |
| Delivered | Receipt is confirmed at the warehouse against what was sent; quantity received (and optional dimension) is recorded and verified; an image of what was received is captured; the stock count is populated. |
| Used | Consumption is logged when Production or Retrofit accept receipt of requested items against a work order — accepting receipt is the consumption event. This feeds burn/day and data-driven reorder points. |
| Unused / Returned | Delivered-but-unused stock is returned to the warehouse; accepting a good return increments on-hand. Faulty components follow the faulty path into a separate count. |
6.1 Facility request path
Section titled “6.1 Facility request path”The chain above supplies the warehouse from vendors. A parallel lifecycle governs how a facility draws stock from the warehouse:
(team member) Pending approval → Requested → Pending → Accepted │ ├──→ Rejected └──→ Declined └──→ Partially fulfilled| Stage | Behavior |
|---|---|
| Pending approval | A facility team member raises a request (mandatory reason/purpose and date required). It waits on the facility Manager, who approves it — or Declines with a reason. A request the Manager raises directly skips this step. |
| Requested | The approved request reaches the warehouse (Inventory’s Requests). |
| Pending | Inventory is fulfilling it; a delivery note carries the issued stock In transit. |
| Accepted | The facility Accepts the delivery in Incoming, moving the stock into facility inventory (the acceptance that logs consumption). |
| Rejected / Partially fulfilled | Inventory may Reject (reason required) or issue fewer than requested as a Partial fulfilment (with a reason). |
On the Inventory side the same request reads Open → Fulfilled / Partially fulfilled / Rejected (per-persona framing of one record).
7. Functional Requirements
Section titled “7. Functional Requirements”7.1 Requesting & ordering
Section titled “7.1 Requesting & ordering”| ID | Requirement |
|---|---|
| FR-R1 | The Inventory Manager can directly trigger a request to Procurement for a specific item when stock is low or critical; Procurement converts it into an order. No email or external channel. |
| FR-R2 | A multi-item request box lets the user select items via a dropdown selector, set a quantity per line, a note, and an urgency. Quantity is editable per line. Bulk request across several low-stock items in one action. |
| FR-R3 | An order is pushed to Polaris as its own requisition — one requisition per order, never summed together. Atlas’s itemized lines (item, quantity, unit price) roll up into Polaris’s Amount field, and the order carries a short description auto-generated from its line items (e.g. 10× Buck converter, 5× AC charger) so the requisition reads clearly. A line priced at zero is left out of the description: it came with another line or free of charge, so it is not what the requisition is for, and it stays on the order so it can be received (e.g. 900 enclosures at ₦10,000 arriving with EVA foams at ₦0 read 900× Enclosure). An order where every line is zero, such as a vendor replacement, lists them all. Send to Polaris (single from the order, or bulk over selected drafts) opens a summary confirmation first. Sync to Polaris is idempotent — each order keeps one requisition reference (PLR-REQ-####) assigned once, so re-syncing never creates a duplicate; a later sync pulls the Polaris-side outcome (approval or rejection). Non-inventory Polaris requisitions (lump-sum expenses) stay Polaris-only. |
| FR-R4 | $0 may be entered as a unit price. |
| FR-R5 | An order is editable only while its requisition is not yet approved (Draft or Requisition pending reopen the order form and update the same record in place). Once the requisition is approved the order locks. There is no separate amendment/version flow; instead every order carries an audit trail — actor, time and action across create, edit, send, sync, approve, reject, ship and deliver. Discarding a draft deletes it and releases its tied requests. |
| FR-R6 | Invoices and supporting documents can be attached to an order. |
| FR-R7 | The Procurement Manager can enter a product name directly during order creation even if it is not yet in the catalog, capturing at minimum name, unit of measure, and estimated quantity/price. Ad-hoc entries are flagged for the Inventory Manager to promote into the catalog or merge with an existing item. |
| FR-R8 | Every order carries an urgency level. When a requisition is approved or rejected in Polaris, the Procurement Manager receives an email and in-app notification. |
| FR-R9 | An order is single-vendor and single-currency (NGN/USD/CAD/AED) but may carry many item lines (add/remove), each optionally tied to a Request ID. The form shows a per-line total and one order total; the vendor is auto-suggested from the item’s preferred source (changeable). Invoices and images can be attached (multiple). |
| FR-R9a | An order’s value carries what is taken off it and what is added to it. Creating or editing an order takes a discount amount and a logistics amount, both optional, and the order total recalculates as it is typed: lines, less the discount, plus logistics. That calculated total is the figure raised into Polaris as the requisition value, not the line subtotal. The order detail carries an order value block showing the subtotal, the discount taken off, the logistics added, and the total, so the number sent for approval can be read against its parts. |
| FR-R9b | A discount is a fact about the vendor. The vendor record carries the discounts that vendor has given: which orders, how much, and the running total, so a vendor’s actual concession history is on the vendor rather than scattered across orders. |
| FR-R10 | Requests are Inventory-owned — the Procurement Manager does not raise them. An order is created from an existing request through an Accept and create order action (single or bulk) that ties each line to its source request and advances those requests (Requested → Ordered). The request queue shows a Request status; it carries no required-by or inline action column. |
| FR-R11 | An order has one unified Status (stage and requisition status merged): Draft → Requisition pending → Requisition rejected / Requisition approved → Ordered → Shipped → Partially received → Delivered. A rejected requisition (reason + notification) reopens for edit and can be re-sent. Once approved, the order can create a shipment; from there the status follows the shipment. |
| FR-R12 | A Notifications center (opened from the dashboard and the topbar bell, no sidebar entry) groups: threshold alerts auto-raised from Inventory’s thresholds, reaching Inventory and Procurement both — a low line as its own alert, in-app and email, and critical lines in the bundled critical alert of FR-U4 — new requests, and Polaris requisition outcomes — approvals and rejections only (statuses that don’t change automatically are not notified here). Requisition rows link straight into Polaris. Filterable by category; mark-all-read clears the bell indicator. |
| FR-R13 | Vendor management. A vendor carries name, location, address and country, multiple contact channels (add/remove; at least one populated), onboarding documents, preferred items, and lead-time history. There is no vendor status field. The scorecard is computed, not entered — on-time % from deliveries within the promised lead time, defect rate from the vendor’s returns — and recomputes live. The order form warns when a selected vendor has no onboarding documents on file. Create and edit share one dialog (full parity). |
| FR-R14 | Vendor returns / RMA. A return raises a tracked RMA with a system reference, followed from Claim raised → Awaiting pickup → Picked up → Credit received / Replacement shipped → Closed, recording the credit-note or replacement reference. RMAs are raised from Quarantine (Return to vendor) or created manually on the Vendor returns page. |
| FR-R15 | Shipment (vendor → procurement) · per-item incremental receipt. Once a requisition is approved, the Procurement Manager creates a shipment, which stamps the order date, moves it to Ordered and starts tracking. The shipment detail (cards laid side by side, action at the bottom) captures carrier / transport details (mode-aware vehicle/vessel/flight + waybill/AWB/B-L reference, carrier, driver) and shows the tied requests. Advancing the delivery status to Partially received (or Delivered) reveals a per-item receipt table — Item · Destination · Requested · Received so far · Receive now (capped at the outstanding). Recording a receipt raises a delivery note for exactly the items received (FR-R16) and sets the shipment Partially received, or Delivered once every item is fully received; Delivered receives all outstanding at once. A shipment may be received incrementally over several receipts, tying to several delivery notes (shown on the shipment detail). One confirmation message per receipt. |
| FR-R16 | Delivery note (procurement → the requesting warehouses). Renamed from “waybill”. A delivery note is auto-raised from a shipment receipt (FR-R15) for the items received, tied to their requests, with Inventory notified in-app + email; the tied requests flip to Delivery note issued. There is no central warehouse (§4) — each request routes to the warehouse at its location, so the note is created already split into one leg per destination warehouse, each leg a separate list row (DN-####-<WH>). A leg carries its own vehicle + logistics (a note may use a different vehicle per warehouse; logistics and vehicle type are required to dispatch, the plate is optional), its item lines (qty requested vs qty purchased/sent), and its own delivery status. Per-leg status: Pending dispatch → In transit → Partially delivered → Delivered — procurement assigns the vehicle and dispatches each leg when its goods are ready (legs dispatch independently); a leg is Partially delivered when only some of its items are accepted, Delivered when all are, and accepted items carry a received date. Acceptance is the Inventory side’s (Procurement has no accept control here); it closes the tied requests as Received. |
| FR-R17 | Insights. The Reports group’s one page, headed Insights, with tabs Requests · Items bought · Spend · Cycle time. The tabs share one row with the active tab’s controls, right-aligned: the Requests tab carries Filter and Export; Items bought carries a period select, Filter and Export; Spend and Cycle time carry the note “No currency or date filter” and Export. Requests: tiles Requests (“Raised in this scope”), Most requested item (the item’s name; “N requests · X% of all”) and Warehouses (“Receiving these requests”); a Requests by team table (Team · Requests · Share bar), then side by side Most requested items (Item · Requests · Teams, listing who asked for it, e.g. “Retrofit station 5 · Production facility 3” · Quantity) and Requests by warehouse (Warehouse · Requests · Share bar). The tab filters by request stage, urgency, raised from and raised to, and each table has its own search. The team is the actual floor requester’s TeamGroup (§3.2). Items bought: what Procurement bought over a period, from every order line sent to a vendor (drafts, discarded and rejected orders do not count), dated by the order date. Period presets This month · Last 3 months · Last 6 months (the default) · This year · All time, or a custom range from the filter. Tiles Items bought (“Across N orders”), Most often bought (the item on the most orders, with its quantity) and Bought at no charge (items on a line priced at zero). The Items bought table lists Item · Category · Qty bought (in the item’s own unit, noting how many came at no charge) · Orders · Last bought · Spent (per currency, never converted), most bought first, with search and filters for category, location, vendor and currency. A line’s location is the warehouse it was bought for: the warehouse of the request it was raised from, else the order’s destination warehouse. A zero-priced line counts toward the quantity and adds nothing to spend. A row opens the item’s record (FR-IP5) on the same period and location. Spend: tiles Committed spend, Purchase orders and Spend on logistics, then Spend by category and Spend by vendor (with on-time %) side by side, then Spend on logistics by haulier, then Spend by item: Item · Category · Spent · Share (of that currency’s spend) · Qty bought · Orders, one row per item per currency, most spent first, with its own search, location and currency filters and period (default Last 6 months); zero-priced lines are not on it. A row opens the item’s record on that period and location. Figures are shown as recorded in each order’s own currency; there is no currency switch, and only Spend by item takes a period. Cycle time: the Cycle time by stage table, whose subtitle carries the request → order average (“Median days per stage · request → order averages 2.3 d”). There is no Vendors tab. Every breakdown exports to CSV. Finance-side sourcing/RFQ, budgets, invoicing/AP, contracts and landed cost remain Polaris-side and out of scope here. |
| FR-R18 | Requisitions surface (read-only). A Requisitions sidebar page mirrors the requisitions raised in Polaris from this persona’s orders: Requisition (PLR-REQ-####) · Raised against · Vendor, with the Location (inventory warehouse) on its own line beneath · Requester · Amount · Raised · Status (Pending approval / Approved / Rejected), led by the status tiles in §3.2. Raised against names the order or delivery note with the kind (Goods or Logistics) on its own line beneath it. No manager action here (approvals happen in Polaris). A row appears when an order is sent to Polaris and gains its ref on sync; the dead “Polaris Requisitions” quick-link from Orders now routes here. |
| FR-R19 | Requester + inventory location travel to Polaris. Beyond Description + Amount + Currency + Urgency (FR-R3), each requisition carries the requester and the inventory location (the warehouse at the request’s location, derived from the tied request), shown on the order detail and the send-to-Polaris summary. |
| FR-R20 | Procurement custody (“My Inventory”). Goods received from a vendor sit in Procurement custody — awaiting dispatch → in transit → cleared (when the destination warehouse accepts) — until forwarded on delivery notes. Item-level table (Item · Category · Source · Vendor · Destination warehouse · In custody · Awaiting dispatch · In transit · Quarantined) with a warehouse filter; no cost shown. The one action is Flag quarantine (quantity + required reason) for damaged/wrong arrivals, which raises a Quarantine record. Delivery notes are raised from the shipment (FR-R16), not here. |
| FR-R21 | Currency is a filter, not just a column. Every Procurement surface that carries a money amount is filterable by currency (NGN / USD / CAD / AED) alongside its other facets: Orders, Requisitions and Vendor returns each carry a Currency column and a currency .filt-select, and each amount is rendered in its own row’s symbol (₦ / $ / CA$ / AED). The order detail states the order currency. Insights carries no currency switch: spend is shown as recorded (FR-R17). Surfaces that deliberately carry no cost (My Inventory custody, delivery notes) gain neither. |
| FR-R22 | A request carries the unit, the location and the requester. When Inventory raises a request to Procurement it sends each line’s unit of measure (from the catalog item), the requesting location and the requester. The unit does not take a column — it rides beside the quantity on the Requests queue, on the request detail and on every order line raised from that request (“10 rolls”, “600 m”), so a buyer orders in the right unit without a column spent on it. A count phrase pluralises (§4); the unit token stays singular wherever it is a field value. A request line that does not resolve to a catalog item has no unit and cannot be sent. |
| — | Goods receipt + three-way match (PO ↔ GRN ↔ invoice) was considered but is deferred. Receiving into stock is Inventory’s (it feeds the dashboard Stock snapshot); Procurement’s chain ends at the delivery note to the warehouses. |
Requests are reconciled by Inventory. Inbound requests arrive already de-duplicated from Inventory (the original requester is preserved), so there is no cross-team conflict-resolution step on the Procurement side — Procurement accepts a request and creates the tied order. Every order is tied to requests — there is no standalone “New order” action and no ad-hoc order (orders are created only via Accept & create order from the Requests queue). FR-R7 (ad-hoc free-text entry) is superseded by the catalog item picker; BOM-driven Procurement Orders are out of scope for this persona.
Dashboard presentation note: on the Procurement Manager dashboard the lifecycle pipeline’s first two cells are labelled Requests (inbound, from Inventory) and Requisitions (in Polaris). This is a dashboard label only — the canonical lifecycle vocabulary Needed · Requested · Ordered · Shipped · Delivered · Used (§ below) is unchanged.
7.2 Catalog & labelling
Section titled “7.2 Catalog & labelling”| ID | Requirement |
|---|---|
| FR-C1 | A controlled category vocabulary (dropdown, not free text) is stewarded by the Inventory Manager. Categories, Units of measure and Item types are created and managed on the Item Categories page. A category is a name + description and can be disabled; disabled categories and UOMs are hidden when creating an item. |
| FR-C2 | Each catalog item defines a Unit of measure (UOM). |
| FR-C3 | Each item has a Tracking attribute (Serialized / Consumable). Serialized items carry a unique record with status and location per unit and support scannable serialized tags so the contents of a delivered box can be verified against the order. A serialized item has one serial number (one per item, never a list) — captured as a single field on create/edit and surfaced on the Items table and item detail; consumables show none. Type is a separate classification field (e.g. Retrofit kit). |
| FR-C4 | Items supports a manual stock count (cycle/physical count): record the counted quantity per item, show system-vs-counted variance, and apply the count to adjust on-hand — writing an entry to the quantity-change audit log. |
| FR-C5 | Item image: a new item requires a picture upload (deletable) and a required description. Images can be captured from a mobile camera for field use. Items and individual line entries (e.g. a photo of a delivered part or a fault) can carry images. |
| FR-C6 | The Item Categories and Units-of-measure tables each show an Item count column (how many catalog items use that category / unit). |
| FR-C11 | An item is one record, read three ways. The item opens as a single page carrying Overview, Serials and Movement history rather than separate screens. Serials lists only the units on hand — a unit fitted to a keke, out with a team or in Procurement’s quarantine is not stock, and where it went is what the movement history is for — with search, a condition filter and export. |
| FR-C12 | Movement history is what inventory issued out, against the request it was issued for. It reads: the team it went to, their location, the quantity requested, the quantity given, the date and time it was fulfilled, who fulfilled it, and the request reference. It carries filters including a date range, a search and an export, and it is seeded. Because many people touch one part, a movement opens its own page, not a dialog, and that page carries what happened next — the units and serials issued, and where each one moved on to: fitted, swapped, charged, built into a kit, returned, or pushed to another team. |
| FR-C7 | Item names are composed, not free-typed. A name is formed from Describe it + Item type + (Key specs) + optional Version. Setting a Version makes How it differs required (the note distinguishing this version from the base item). The formed name is what appears in the catalog; the parts are stored separately so the name is consistent across everyone who adds items. |
| FR-C8 | Item type is a governed picklist. The ~101 item types are curated in type management; the 1,000+ items built from them are free. Each type may carry search-only aliases (e.g. a search for “loom” finds Harness) that match in search but never appear in the formed name. New types are added deliberately in type management, never inline on the item form. Group / Category is unchanged (the controlled category vocabulary of FR-C1). |
| FR-C8a | Item types are managed from their own tab. The Item Categories page carries an Item types tab beside Categories and Units of measure, where the Inventory Manager adds a type, edits one and disables one. The list carries search — matching a type’s own name or one of its aliases — a status filter and export, and shows each type’s aliases and the count of items named with it. A disabled type stays on the items already named with it and is hidden when a new name is composed. |
| FR-C8b | Renaming a type renames the items built from it. The type is a part of the composed name (FR-C7), so renaming it composes the name of every item that uses it again from that item’s stored parts. Before the rename is saved, the form states how many items it will rename. |
| FR-C8c | A type in use cannot be deleted. Deletion is available only for a type no item is named with. For one in use, the refusal reads where it is used — the items named with that type, each openable in the catalog — and offers disable instead. |
| FR-C9 | Live duplicate check. As a name is composed, the formed name is matched against the catalog and any exact or near duplicate is surfaced before the item is saved. |
| FR-C10 | Required fields carry a red asterisk across every persona’s forms. |
7.3 Item create & edit
Section titled “7.3 Item create & edit”| ID | Requirement |
|---|---|
| FR-I1 | New item composes the name from Describe it + Item type + (Key specs) + optional Version (with How it differs required when a Version is set), and captures a required picture (deletable), a required description, category, tracking, and UOM. A live duplicate check runs against the formed name (FR-C7–FR-C9). No reason field on create. |
| FR-I2 | Edit item allows editing the description, an editable quantity with a required reason, and low and critical threshold fields. Applying a consumption-suggested reorder point updates the thresholds automatically. |
| FR-I3 | Create and edit both show a confirmation pop-up summarizing the change before it is committed. |
| FR-I4 | The Items table shows a small thumbnail beside the name, On-hand, and ATP (beside On-hand). Type is shown in the item detail view, not the table. |
7.4 Receiving
Section titled “7.4 Receiving”| ID | Requirement |
|---|---|
| FR-V1 | Receiving handles what the warehouse receives from Procurement. Statuses: Pending (populated from requests already sent to Procurement) → Received (after verify, regardless of quantity match). |
| FR-V2 | Opening a receipt shows what was sent, takes the quantity received and an optional Dimension (cm), captures an image of what was received, and verifies to populate the stock count. The receipt detail provides a place to view that image. For a serialized item, the receipt also captures a serial number per unit — entered by type + Enter (removable chips) or CSV upload — validated against the quantity received before it commits (the item’s own warehouse serial). |
| FR-V3 | Receiving models expectation: every arrival records quantity expected vs quantity received so short/over deliveries are visible (Request variance table, with date and variance filters). |
| FR-V4 | Bulk receive: multiple receipts can be received at once; the bulk action presents the same per-item fields (quantity received, optional dimension, verify) as single receive. For serialized items, each line captures its own serials (type + Enter, or CSV), validated per line, and each serialized item is logged as its own separate batch. Bulk receive always creates new batches · receiving into an existing batch (FR-V6) is offered on single receive only. |
| FR-V5 | Marking an item received correctly populates/decrements the on-hand stock count. (This is the confirmed stock-integrity bug — see §11.) |
| FR-V5a | A received line says where the unit now is. Before the receipt an item reads Awaiting receipt; after it, In stock, or In quarantine where it was rejected on arrival. Onward movement from the warehouse reads Not transferred until it leaves, In transit while it is moving, and Held where something is holding it. |
| FR-V6 | Batches are an Inventory-Manager surface (Procurement holds no Batches page; amounts are hidden). A batch is created automatically on acceptance — from a Procurement receipt (serialized items) or from Production output — so there is no manual batch-logging and no separate confirm-receipt step: a batch exists only once accepted, so its units are already received and on-hand was populated at that acceptance. Each batch records a Source (Procurement / Production output) shown in the list and detail, its Category, and its serialized units. Batch KPIs are by source: Total batches · From procurement · From production output · Units received. System-generated B-YYMMDD-######## batch number. A serialized receipt creates a new batch by default, or is received into an existing receipt-less batch — a batch of the same item already at the receipt’s destination warehouse (a unit at the warehouse location, or in the custody of a user assigned to that warehouse) and tied to no receipt, shipment fulfilment or production work order. The Inventory Manager chooses Receive as · New batch / Existing batch on single receive (for a non-serialized item the first option reads On-hand · no batch). The choice always shows on single receive; when no candidate exists, Existing batch is disabled and the reason is stated (No receipt-less <item> batch in <warehouse>). Bulk receive does not offer it. And: (1) Quantity. The quantity received becomes the batch quantity: more than the batch holds adds units that await a serial; fewer removes units awaiting a serial first, then the newest unmoved unit. A unit that has moved (issued, transferred, fitted, or referenced by any other record) is never removed; any that remain above the quantity received are kept and listed on the batch as over by N. An arrival date is captured (defaulting to the batch’s created date); damaged/quarantine is not offered in this mode. (2) Serial checks, trim and case-insensitive, run before anything commits and name every serial: repeated in the file (with its rows · blocks), in use elsewhere (naming the other batch and its holder, or the battery pack / VCU / retrofit kit · blocks), already on this batch (skipped), new (accepted). Serials already on the batch plus the new ones may not exceed the quantity received (blocks, stating the numbers). (3) Partial serials. The receipt may be confirmed with fewer serials than units received; the receipt and the batch show progress (84 of 100 serials) and accept later uploads under the same checks until every unit carries one. (4) No second added-to-inventory event and no new batch number: the units already on the shelf were counted when the batch was minted, so on-hand moves only by the units added or removed, and every unit is repriced from the order line. (5) One reconciliation event per receipt on the batch, recording quantity before and after, units added and removed, serials attached, the moved units kept, the arrival date and the actor; the batch is then tied to the receipt and the order. (6) Non-serialized items are received into an existing batch as a batch-only resize: the same batch choice, facts, quantity and arrival date, but no serial upload or check; units added get system-generated serials (never pending); a shrink removes units at rest newest first; the receipt and order are linked, units at rest repriced and one reconciliation event written, and nothing is posted to the quantity ledger (no double count — on-hand does not move). (7) Production pool. A unit in the production pool that belongs to the receipt’s warehouse counts as in that warehouse (the batch stays a candidate) and counts as moved (never removed by a shrink; listed as over). (8) Batch-side entry. The record of a receipt-less batch offers Receive a delivery into this batch, listing the pending delivery-note receipts of the same item for that warehouse (receipt · DN · quantity expected · requested date), or No pending delivery for this item at <warehouse>; choosing one opens the same receive dialog with Existing batch and this batch pre-selected (GET /api/v2/inventory/batches/{uid}/candidate-receipts, the mirror of the receipt’s candidate batches). |
| FR-V7 | Component serials. A batch’s unit carries its own serial number plus any component serials captured for it, shown in a column named after the component (e.g. a Battery Pack unit shows SN + BMS ID); a unit may list several components. Component serials appear only on production-output batches — they were captured on the line at assembly QA and carry through, never captured at inventory — so procurement batches show the item’s own serial only. Faulty units can still be sent to Procurement’s quarantine from the batch. |
| FR-V8 | The batch-items table reads Serial Number · Component serial · Item · Category · Location · Custodian · Status · Transfer status. On-hand/ATP is populated at the receiving or production-acceptance step that creates the batch, not by a separate confirm action. |
| FR-V9 | Damaged/wrong on arrival → quarantine. When receiving a receipt, the Inventory Manager can record how many of the received units are damaged or wrong. Only the good units populate on-hand/ATP; the rest are held in quarantine, out of stock. A reason is required when any units are quarantined, and the receipt’s damage photo is retained for the vendor dispute. The split is validated (damaged cannot exceed received). Quarantine is captured on the single receive path; bulk receive stays the clean fast-path (no split). |
| FR-V10 | Quarantine is held, not deleted. Quarantined units never count toward on-hand, Available, or ATP, and remain on record for the vendor-dispute trail. The Inventory Manager has read-only visibility of quarantine; only Procurement can release it. |
| FR-V11 | Procurement resolves quarantine, choosing Accept into stock (adds the units to warehouse on-hand), Return to vendor, or Scrap — each with a required resolution note. On Return to vendor, the vendor return reference is system-generated (not typed) and the return is tracked through Awaiting pickup → Picked up → Credit received / Replacement shipped, with the current return status shown on the quarantine table as well as in the detail. Each quarantine record ties to its receipt, and the vendor is derived from that receipt id (not re-keyed). Long context (full reason, batch id, item serials, resolution, return tracking) lives in a detail view, keeping the table scannable. |
| FR-V12 | Production output receipt. Finished-goods output from production arrives on a dedicated Production output surface, not on a Receiving sub-tab. Closing a work order creates a production batch there automatically (Pending); the Inventory Manager accepts the receipt into warehouse stock, which restocks the kit’s on-hand in Items so it becomes requestable. The units are already serialized on the line at QA, so those production serials carry through and are recorded against stock on receipt — Inventory mints no new serials for production output (unlike the procurement/raw-material path, where the warehouse assigns serials). |
| FR-V13 | Accepting a batch stamps custodianship. When a batch’s units are received, each received unit’s custodian and the batch’s Received-by / Received-at populate from the user who accepted the batch and the location tied to that user (an unreceived unit has no custodian). |
7.5 Requests & delivery notes
Section titled “7.5 Requests & delivery notes”| ID | Requirement |
|---|---|
| FR-T1 | Requests (warehouse → facilities) lists incoming facility requests. Fulfil shows the request details, lets the user set the quantity fulfilled, then prompts to create a delivery note prefilled from the request. Fulfilling reduces on-hand and populates assigned — the decrement and the movement-history entry happen at fulfilment, naming who fulfilled it and the request it went against; the delivery note is the document the issued stock travels on, and issuing against it moves no stock. Fulfilment is capped at available on-hand — the review shows requested vs available per line, prefills the quantity at available, highlights any line pushed over, and blocks creating the delivery note until it is within stock. |
| FR-T2 | A Delivery Note is generated when stock leaves the warehouse for a facility (single or multiple items), capturing deliver-to (company/facility, contact name, phone, address), delivery number, date, line items (S/N, description, quantity), and logistics terms (logistics fulfilled by, vehicle type, vehicle plate no.). Line items are chosen from the catalog via a picker. |
| FR-T3 | Each delivery note is clickable to a detail view with a Print action. |
| FR-T4 | Bulk fulfil several items from the same facility into a single delivery note. |
| FR-T5 | Linked reference(s) + delivery status. The delivery note has a Linked reference(s) field where the user enters one or more ids — a request, a return, or any other module id — that this note fulfils. Each id must already exist in the system (issuing is blocked with an error on an unknown reference); several are comma-separated. A standalone note may leave it blank. When a request id is linked, the note is tied to that request — already marked Fulfilled at fulfilment — and the request’s row shows the tied note number; a note prefilled from a fulfil arrives with its request id already populated. Every note carries a Delivery status: In transit on issue, then Delivered with date + time when the requester accepts — that acceptance transition is owned by the facility-side Incoming screen (§5.2), so in this Inventory Manager surface a note remains In transit after issue. |
| FR-T6 | Reject & partial fulfilment. Against a facility request the Inventory Manager can, besides fulfilling in full, Reject it (a reason is required) or issue fewer than requested as a Partial fulfilment (also with a reason). The reason and other long fields live in the request detail, never the table. On the facility side the request reflects this as Rejected or Partially fulfilled (§6.1). |
7.6 Returns & faulty
Section titled “7.6 Returns & faulty”| ID | Requirement |
|---|---|
| FR-F1 | Delivered-but-unused stock has a defined return path, which also receives facility push-backs of good stock (§7.11). Accepting a good (non-faulty) return increments on-hand and populates the stock quantity. When accepting a return, the user inputs the actual number returned; Received by and the received date/time are auto-populated — the acting Inventory user and the completion timestamp — not typed. |
| FR-F2 | Faulty components returned from production/retrofit/facilities are logged with item, Type, description of fault, batch/lot no., quantity, returned-by, received-by (store), and remarks. The Inventory Manager verifies the fault and, on confirmation, sends the unit to Procurement’s Quarantine; it does not set the disposition (see FR-F3). Before accepting any return the user confirms the received condition (good/unused, damaged, faulty); only good, unused units go to on-hand. |
| FR-F3 | Faulty units are never counted as available. Accepting a return populates on-hand in the bucket the received condition names (FR-B10); faulty, damaged or incomplete items are held as faulty stock and carry a disposition (FR-B13): held for repair and accepted into Refurbished once fixed, or confirmed and sent to Procurement’s Quarantine. |
| FR-F3a | The Inventory Manager can select one or more open faulty returns and send them to Procurement’s Quarantine in a single action, adding a required inventory reason. Each quarantined faulty item then carries both reasons — the returner’s reason and the inventory reason — shown as distinct fields in the Procurement quarantine detail (damaged-on-arrival items carry a single reason). |
| FR-F4 | Return rows open a detail view that includes the returned-item image. The return reason lives in this detail (not as a table column). |
| FR-F5 | Returns and faulty share one view, separate from Requests. |
| FR-F6 | Retrieved-stock intake is one step, with no contents breakdown. A retrieval arrives as a consignment of catalog items, and because a kit or a bundle is itself a catalog item (§7.15) there is nothing to break down. The system shall capture warehouse custody and the condition it came back in in a single Receive return step. Condition is recorded in the bucket vocabulary (FR-B10) — one condition for the whole retrieval, because a kit or a bundle is one catalog item even though it is physically several parts. Used (the default — retrieved stock has been out), Refurbished and Unused restock every item on the retrieval into the bucket the condition names. Faulty carries the FR-B13 disposition: hold for repair (default), shown as Held for repair and counting as faulty until an explicit Accept repaired restocks the lot into Refurbished, or return to Procurement, which places every item in Procurement quarantine (FR-F3a trail). Discrepancy notes are required on a faulty retrieval, and both paths sit behind an explicit sign-off. There is no item-by-item classification screen, no contents view, and no keep-it-together-as-a-reusable-bundle outcome. Re-opening a closed retrieval shows the recorded outcome and notes, read-only. |
| FR-F7 | Serial capture on return. For serialized items, the specific serial number(s) returned shall be captured and reconciled against the serials originally issued/expected. A returned serial that does not match what was issued, or a missing expected serial, is flagged. With the item-by-item screen removed (FR-F6), the retrieval already carries its expected and returned serials, so this reconciliation is a check on the record rather than a manual per-line step. |
| FR-F8 | Chain of custody / anti-theft. Every return and retrieval records who returned it, who received it at the warehouse, and when — an auditable custody trail at each step. The system shall reconcile returned quantities and serials against what was issued/expected and flag any shortfall or mismatch, deterring theft on both sides (the returning party under-returning, and warehouse staff diverting retrieved stock). Acceptance requires an explicit verify/sign-off step; discrepancies cannot be silently accepted. |
| FR-F13 | Arrived is not accepted, and both desks say so in one vocabulary. Stock that has only turned up reads Awaiting acceptance and names no receiver, because custody has not passed. Accepting or declining is the moment it passes, and it stamps who took it and when — a different date from the day the stock came back, so the returner and the date it left them read in one column and the receiver and the moment of acceptance in another. Both desks then close into the same words: Restocked (with · flagged where a discrepancy was accepted), Held for repair, Sent to Procurement, Faulty stock, Scrapped, Declined. |
| FR-F14 | Whatever a row offers, its record offers. Opening a return or a retrieval must not mean closing it again to act on it: the record carries the same actions as the row it came from, so the stage logic has one source. Every row presents its actions the same way, through a row menu. |
| FR-F15 | The desk’s cards are its queue. Returns leads with awaiting acceptance (counted across both desks, so a card and the rows under it cannot disagree), how long the oldest one has waited, units restocked in the last seven days, and faulty held, which is never counted as available. The table’s own head and foot counts are read off the same rows. |
| FR-F9 | Location known at every point. A retrieved/returned item’s location and state are trackable through the whole path — in transit from the facility, received and closed in one step, held in faulty stock, and — once Procurement decides — returned-to-vendor / scrapped / repaired-and-restocked (or, for good units, on-hand). There is no pending-inspection or under-inspection state. |
| FR-F10 | A retrieval is received as what the station sent. Breaking a kit into the parts it is built from is the retrofit station’s act (FR-K7), not the warehouse’s. What arrives here is whatever was actually sent: a whole kit arrives as that kit — one catalog item, one condition, and only its own serial reconciled — and components stripped out of a kit arrive as individual items on the returns desk, where every other loose item comes back, each naming the kit it was taken out of. The retrievals table names the kit or bundle and how many items it is built from, for reading; the warehouse does not scan a kit’s parts because it is not receiving parts. |
| FR-F11 | A serial is captured in one field, however it is read. A delivery of forty units cannot be one input per unit. Both intake desks take a serial typed, read off a scanner, or lifted out of an uploaded CSV; each lands as a chip in a list that counts itself against what was issued or fulfilled, and any chip can be removed. Reconciliation is unchanged in substance: a unit that was issued and did not come back reads Not returned, and one that was never issued on that note reads Serial mismatch. Serials never appear in a list cell — there can be many of them — so the row names the record, the record holds the units, and the movement history follows where each one went. |
| FR-F12 | Inventory can decline a return or a retrieval. On both intake desks a pending row’s action column is a single three-dot (row actions) menu holding Accept and Decline, so neither action can be hit by a stray click; the receive dialog also carries Decline. Every decline path lands on one decline dialog (reference, item, sender, required reason). Declining refuses custody: nothing restocks, the stock stays the sender’s (their record resolves to Declined), and the reason — which is required — travels back on both records. |
7.7 Thresholds, usage & consumption
Section titled “7.7 Thresholds, usage & consumption”| ID | Requirement |
|---|---|
| FR-U1 | Low and critical thresholds are set per item (on Items, via edit) and managed alongside reorder points on the Usage & reorder points page. |
| FR-U2 | Item usage/consumption is logged at the point of use — when Production or Retrofit accept receipt of requested items against a work order, plus any direct issue at the warehouse. Consumption is cross-facility, not location-scoped. |
| FR-U3 | Usage/consumption-trend reports per item let reorder points be set from actual data rather than gut feel. |
| FR-U4 | Low goes out per item; critical goes out bundled, three days a week. A line reaching its low threshold raises its own notification, in-app and by email. A line at or below critical is not sent one by one: on Monday, Wednesday and Friday at 08:00 Africa/Lagos, each recipient gets one in-app notification and one email listing every line at or below its critical threshold, each with its on-hand, its threshold and a link to it. Nothing critical is sent on the other days. This holds for everyone who receives critical alerts: the Inventory Manager, Procurement (FR-U5), and each pool’s manager and inventory manager (FR-TP25). |
| FR-U5 | Procurement is copied on Inventory’s threshold alerts: a low line per item, in-app and by email, as the receiving warehouse’s Inventory Manager gets it, and critical lines in the same bundled alert (FR-U4). |
7.8 Cross-team demand
Section titled “7.8 Cross-team demand”| ID | Requirement |
|---|---|
| FR-X1 | Each request is automatically tagged with the submitter’s team/department (derived from their profile, not chosen manually), making cross-team demand for the same item visible at request time. |
| FR-X2 | The system detects and flags cross-team demand conflicts for the same item and surfaces the resolution/split reason to affected requesters. |
7.9 Requisition workflow & records
Section titled “7.9 Requisition workflow & records”| ID | Requirement |
|---|---|
| FR-W1 | Vendor contact details are stored as a flexible set of contact channels (phone, email, etc.), requiring at least one working channel rather than a fixed set. |
| FR-W2 | Multiple shipment methods are supported: air, sea, and road (road for local/domestic supplies). One order may travel on several of them. The method belongs to the shipment, not to the order, so an order split across two shipments carries a method each, and the delivery note’s legs (FR-R16) carry their own logistics and vehicle per destination. An order is never limited to one method. |
| FR-W3 | Vendor lead time is tracked per order/vendor. |
| FR-W4 | A per-item quantity change history (audit log) records every addition and deduction with a date-and-time stamp, actor, and reason, queryable and exportable (CSV) for month-end reconciliation. |
| FR-W5 | Line managers can view every request submitted by members of their team (role/hierarchy mapping reflected in Atlas permissions). |
| FR-W6 | Each request carries a stated reason/justification (Purpose / Job Reference), visible to the Inventory Manager and any approver. |
| FR-W7 | The Inventory Manager sets an Inventory Request window (an issuance timeslot for planning and request sorting), visible to the requester. The window is fully editable and may include weekend days. |
| FR-W8 | Each request shows the requester’s Location (drawn from the requester’s profile) alongside the requester name and team, on both the Procurement Requisitions surface and the Inventory Requests surface, so demand can be read by where it originates. |
7.10 Dashboards & platform-wide table behavior
Section titled “7.10 Dashboards & platform-wide table behavior”| ID | Requirement |
|---|---|
| FR-D1 | Role-based dashboards for all four personas, each populated and landing on login. |
| FR-D2 | Every list/table across all four persona surfaces provides filters (by status/stage, team, date range, category, urgency as applicable). Every record carries visible dates (requested, required, issued, received, returned), and date columns use date-prefixed titles (“Date returned”, “Date verified”). |
| FR-D3 | Every table supports pagination and its own export control. |
| FR-D4 | Lists support multi-select where a bulk action is meaningful (e.g. bulk request from Procurement, bulk fulfil, bulk receive). |
| FR-D5 | Summary KPI cards appear on the dashboard and the other inventory pages (items, receiving, returns, requests). |
| FR-D6 | Sidebar badges reflect the primary pending action per page: Requests = pending facility requests to fulfil, Receiving = pending receipts to receive, Production output = batches to receive, Returns = pending returns to accept. |
| FR-D8 | Every dashboard takes a period. A Today / This week / This month / Custom control sits above the KPI tiles and drives every measure that has a period, with the trend struck against the window of the same length immediately before. One series feeds them all — the tiles and any chart of the same measure are read off the same days, so a custom range needs no second set of figures and two numbers for one week cannot disagree. A point-in-time count takes no period: a backlog is whatever is sitting there now, and its subtext says what it counts rather than naming a window it does not honour. |
| FR-D7 | Facility floor-health metrics. The Retrofit Station Manager dashboard carries twelve signals across three rows of four, ordered by importance: did the work get out and did it hold up (conversions completed, behind schedule, 3-month breakdown rate, first-pass yield), then the work in hand (active conversion WOs, conversions queued, rework rate, open defects), then what explains the two above (on-time completion, units closed, material fill rate, kits to decide). The Production dashboard surfaces eight floor-health KPIs across two rows — output & delivery (Active WOs, Units closed today, On-time completion, Behind schedule) and quality & supply (First-pass yield — units passing QA with zero rework loops, superseding a plain QA-pass rate — Rework rate, Open defects, Material fill rate — requests filled in full) — over a units-closed trend and an active-WOs-by-stage breakdown. First-pass-yield/rework/on-time/fill-rate are the primary run-quality signals. |
7.11 Facility flows — requesting, consumption & push
Section titled “7.11 Facility flows — requesting, consumption & push”Requirements for the Production Manager and Retrofit Station Manager surfaces (§5.2).
| ID | Requirement |
|---|---|
| FR-M1 | Requesting from the warehouse. A facility request carries a mandatory Reason / purpose and Date required (the digitized Requisition Section A, §10.1). Requesting is not locked to a work order; an optional work-order link may prefill the request from that work order’s bill of materials. Items are chosen from the catalog, not free-typed. |
| FR-M2 | Approval gate. A request raised by a facility team member enters Pending approval and reaches the warehouse only after the facility Manager approves it (or Declines with a reason). A request the Manager raises directly skips approval (§6.1). This is the digitized Section D authorization (§10.1). |
| FR-M3 | Accepting incoming stock. Stock issued to the facility arrives on a delivery note that stays In transit in Incoming until the facility Accepts it — the acceptance moves it into facility inventory and is the logged consumption event (§7.7). |
| FR-M4 | Pushing stock out. A facility may push stock only two ways: back to Inventory — which feeds the Inventory Returns desk, capturing Condition and a Reason (§7.6) — or to a team member, an issue that draws down facility stock. There is no facility-to-facility push. |
| FR-M5 | Work orders & the kit loop. Building against a work order draws down facility stock (the per-unit bill of materials is committed when the work order is created). Closing a work order creates a finished-goods batch in Inventory’s Production output surface; Inventory accepts the receipt into warehouse stock, where a requester (e.g. the Retrofit Manager) can then request it. The output is Serialized on the line at QA, and those serials carry through to Inventory on receipt (FR-V12). |
| FR-M6 | Consumption & reorder. Building against work orders and issuing to team members both draw down facility stock. Each facility item has a reorder point that surfaces a Low / Critical state with a one-tap Request back to the warehouse. |
| FR-M7 | Work-order execution is split between Forge (floor app) and Atlas (web back-office). A work order can be created on either Atlas or Forge and populates both systems; Forge owns step completion, QA, close, serial issuance (on QA pass) and BMS-ID capture, while Atlas plans and monitors and its per-unit record is read-only. Parking a work order is a shared action — parking on Atlas pauses the same work order on Forge, and vice versa. |
| FR-M8 | Serials issue automatically on QA pass (every output is serialized). A manager may force-close remaining units for unforeseen circumstances (manager-only); because a force-close bypasses QA-pass issuance, it asks the manager whether to generate serials (off by default — units close without serials, to be issued later if they clear QA). A faulty return is linked to the item, not the production record. |
| FR-M9 | Serial capture is configured per component on the assembly procedure, generalizing the hard-coded BMS-ID capture (FR-M7): a procedure step’s bill-of-materials line can be flagged Capture serial — the operator inputs that component’s serial on the line, and the QA step confirms it even though QA steps carry no BOM. BMS is the seeded example (on the Battery Pack procedure); the unit’s captured-serial column and assembly record reflect whatever component(s) the procedure flags. Those captured component serials are what carry through to Inventory’s production-output batches (FR-V7). Creating a work order lists the components needed (have/need) once the procedure is chosen; the Team field was removed from work-order creation. |
| FR-M10 | The Work Orders table records who created each work order (a Created-by column). The create form is titled “New Forge work order” (the button keeps its plain name); its sub-line reads “Create a work order for the floor” (no hardcoded location, since location can change). |
| FR-M11 | Retrofit Station surfaces. The Rider view is a read-only rider-management list — Total riders / Active riders / Pending retrofits KPIs and a table of rider, license plate, status, onboarded-by, enabled and date onboarded. My Facility is an editable facility record: Overview (physical address, state, LGA, country, coordinates), plus Batteries and Users tabs, with Edit and Deactivate actions. |
| FR-M12 | Each assembly-procedure step carries an Instruction and Acceptance criteria (free text), alongside its checklist, BOM and assignees. Both show on the step card and are authored via an Edit instructions dialog (Step name · Instruction · Acceptance criteria); the instruction tells the operator what to do on the step and the acceptance criteria state what must be true for it to pass, surfaced on the procedure and on every work order that uses it. |
7.11a Assembly procedures — several active per item, each under version control
Section titled “7.11a Assembly procedures — several active per item, each under version control”One item can need more than one way of being built at the same time. The retrofit is the case that forces it: a rider who opted into KAAG gets the retrofit with the KAAG kit, every other rider gets the standard retrofit, and both run on the floor on the same day (Forge PRD FR-T11). So the procedure and the version are two different things: an item carries several procedures, and each procedure keeps its own version history. Before this, an item had a single version chain and “the current version” was assumed to be the only Active one — an assumption nothing enforced (an item can be found today with two Active versions, neither of which superseded the other).
| ID | Requirement |
|---|---|
| FR-M13 | A procedure is named, and its versions belong to it. An item carries one or more named assembly procedures (e.g. Retrofit · Standard, Retrofit · KAAG). Each procedure is a chain of versions, and each version is Draft / Active / Deprecated. The Assembly Procedures register lists one row per procedure, showing its current Active version (or its Draft when it has never been activated); the procedure’s detail page lists every version of that procedure, newest first, with who activated or retired each and when. A procedure’s name is unique within its item. |
| FR-M14 | Several procedures are active at once, one version each. Any number of an item’s procedures can be Active side by side, but each procedure has at most one Active version. Activating a version supersedes only its own procedure’s previous Active version: that version becomes Deprecated and records which version replaced it. Activating never touches another procedure on the same item — activating KAAG v2 leaves Standard v3 Active. Work orders and units already pinned to a superseded version keep running it to the end (FR-M18); only new work picks up the new version. Deprecate and Reactivate (the inverse) act on one version; Reactivate is refused while another version of the same procedure is Active, and is unaffected by the item’s other procedures. |
| FR-M15 | Editing an Active procedure creates its next version. An Active version is never changed in place. Edit on an Active version opens a Draft of the next version of the same procedure, copied from it — steps, BOM, checklists, instructions and acceptance criteria; step assignees are re-picked, as on any copy, because they are facility-scoped. The new version’s label is proposed as the next in sequence and stays editable; it is unique within the item. The Draft goes live only through Activate (with the existing activation gates), and on activation it supersedes the version it was made from (FR-M14). The previous version stays readable on the detail page for good. |
| FR-M16 | A procedure can be marked for KAAG riders. A procedure on a retrofit item can be marked “For KAAG opt-in riders”. It is the procedure Forge switches a unit onto when the rider bound to it has opted into KAAG (Forge PRD FR-T11); its bill of materials is the one that carries the KAAG kit. An item has at most one Active KAAG-marked procedure, and activating a second is refused naming the first. Because the switch happens the moment the rider is bound, a KAAG-marked version can only be activated when its first step binds the rider exactly as the standard procedure’s does — otherwise the unit would have nowhere to land. The mark is a property of the procedure, not of a version, so every version of a KAAG procedure is a KAAG version. |
| FR-M17 | New work order offers Active procedures, not the KAAG one. The New work order picker lists each Active procedure by name and version (e.g. Retrofit · Standard · v3). Deprecated and Draft versions are excluded, as before. A KAAG-marked procedure is not offered: a retrofit work order is raised on the standard procedure, and each unit that binds a KAAG rider is switched onto the KAAG procedure at binding. The manager never has to know in advance which riders opted in. |
| FR-M18 | A work order and each unit record what they were worked under. The work order records the procedure and version it was raised on. Each unit records the procedure and version it was actually worked under, which differs from the work order’s when a KAAG rider switched it. The work-order detail shows both — the procedure it was raised on and, where they differ, how many units ran on which (e.g. Standard v3 · 2 of 5 units on KAAG v1) — and each unit row carries its own procedure and version, with the KAAG Enabled badge on a switched unit. A version pinned by any work order or unit can be deprecated but is never deleted. |
7.12 New item requests (items not in the catalog)
Section titled “7.12 New item requests (items not in the catalog)”| ID | Requirement |
|---|---|
| FR-N1 | A Production Manager or Retrofit Station Manager can request an item the catalog does not hold, from the same place they request stock on their Atlas console (not the Forge floor app, which only ever requests catalog items). The request captures the item name, unit of measure, quantity needed, why it is needed, industry standard or spec (part number, rating or standard), location, need-by date, urgency and an optional photo. The name is built with the catalog name composer, not free-typed (FR-N1a). The requester and date requested are captured automatically. Every field except the photo is required. |
| FR-N1a | A requested item is named to the catalog standard at the point of request, using the same composer the Inventory Manager uses to create a catalog item: Item type (a controlled list, searchable by name or alias) · Describe it · Key specs · optionally Version + How it differs. The name forms live as [Describe] [Type] [Version] (Key specs, How it differs), and the same duplicate guardrail applies — an exact match blocks the request and offers the existing item, a similar name warns but allows it. So an approved request needs no renaming before it becomes a catalog item. |
| FR-N2 | The request goes to the requester’s line manager for approval — the Head of Production for a production request, the Head of Retrofit for a retrofit request. Their inbox shows the case in full: why it is needed, the industry standard, the location, the requester and their role, the unit and quantity, the photo, the need-by date and the urgency, plus the closest existing catalog items so a duplicate is visible. |
| FR-N3 | Statuses are Pending approval → Approved / Rejected. A rejection requires a reason, which the requester sees on the record. |
| FR-N4 | Approval does two things automatically and needs no second approval anywhere: the item is created in the catalog, and the quantity goes straight to Procurement as a request — the warehouse holds no stock of an item that did not exist until now, so there is nothing for it to fulfil. The request lands in Procurement’s queue marked as a new item (no vendor or price history), and Procurement buys it on the ordinary path. |
| FR-N4a | Inventory is notified on approval and sees the request on its Item requests tab, so it knows the incoming units are earmarked. The procurement to warehouse leg is unchanged (FR-R16): the goods arrive on a delivery note and are received as normal. Once received, the warehouse issues them to the original requester on a delivery note to that facility. Status runs Pending approval → Approved · with Procurement → Issue to requester → Issued, or Rejected. |
| FR-N5 | Inventory sees the outcome, not the decision. The Item requests tab on Item Categories lists approved requests with search plus status and location filters, and no approve or reject control. Each record carries the route: who approved it and when, the Procurement request reference, the date received, and the delivery note it was issued on. The one action is Issue to requester on a received record, which opens the delivery-note builder prefilled with the requester’s facility, the item and the quantity. Inventory’s other work on a created item is to finish its catalog record — thresholds, tracking and image — from the item’s normal edit path. |
| FR-N6 | A new-item request is distinguishable from an ordinary catalog request in the requester’s own list, and names the approver’s role while it is pending. |
| FR-N7 | Raising and viewing a new-item request is a page, not a dialog — the form on one side and the approval line alongside it, showing the route (requested → line manager → Procurement → Inventory issues it) with the current step marked. The same page serves the read-only view of an existing request, including a rejection reason. |
7.13 Inventory location transfers
Section titled “7.13 Inventory location transfers”| ID | Requirement |
|---|---|
| FR-T8 | An Inventory Manager can push stock from their own location to another inventory location, using the same push composer that sends stock to floor staff. The destination picker offers inventory locations (every warehouse except the current one) as well as floor staff. A location-to-location transfer shows from → to, requires the vehicle type and plate, caps each line at the quantity available at the sending location, carries each line’s unit, and captures received by at the destination. Dispatching removes the units from the sending location’s stock. |
| FR-T7 | The transfer is visible on both sides. Statuses run Pending dispatch → In transit → Received; the receiving location accepts it, which adds the units to that location’s stock and closes the transfer as Received. |
7.14 In-app feedback
Section titled “7.14 In-app feedback”| ID | Requirement |
|---|---|
| FR-F16 | Every persona surface reports a problem through one form. On the Atlas consoles that form is reached from two entry points, a Send feedback item in the sidebar and the same action in the topbar, because a topbar-only entry is too easy to miss. Both open the same centered dialog: Type (Bug / Improvement) · Impact (Blocking / Slows me down / Minor) · Where (the persona’s own pages, preselected to the page it was raised from) · Details · optional screenshot; all but the screenshot are required. On the Forge floor app the channel already exists as Profile → Tech support → Report a problem (name, email, what the problem is, urgency) — that sheet is extended with Type and Where rather than duplicated, and its Urgency (Low / Medium / High) is what carries impact. Two entry points into that one form are the same channel; a second, differently shaped reporting form on the same surface is not, and is not added. |
| FR-F17 | Submissions land on the Product Manager · Vehicle Operations console’s Tech feedback queue typed at source — type, impact and area travel with the note, alongside the sender’s name, role, email and the app. That queue filters by type, impact, status and date range, and triages each item through New → In progress → Resolved / Dismissed, emailing the sender on every action. |
7.15 Retrieved kits and bundles
Section titled “7.15 Retrieved kits and bundles”| ID | Requirement |
|---|---|
| FR-K1 | A kit and a bundle are catalog items, not containers of loose parts: Retrofit Kit (v1), Telemetry Bundle and Main Retrofit Harness (Bundle) sit in category Kits, are Serialized, and are counted in each. Wherever one is issued, retrieved or returned it is referenced as that item plus its serial, never re-typed. |
| FR-K2 | Retrieved stock covers kits as well as bundles. A retrieval (BND-####) is a consignment from a facility or the retrofit station, and each of its lines is a catalog item — a loose consumable, or a whole kit or bundle item. A serialized line reconciles the serial returned against the serial issued. The warehouse surface is Returned retrievals, filterable by source, which includes the retrofit station. |
| FR-K3 | Retrofit retrieval turns round on site. When a kit or bundle comes off a keke, the Retrofit Station Manager records the retrieval against the plate it came off and its rider, then takes one of two decisions: reassign it to another keke awaiting retrofit at that station, or return it to inventory. Most are reassigned the same day, which is why the decision sits on the retrieval record rather than waiting on a warehouse round trip. |
| FR-K3a | A reassignment names the keke it goes to. The destination is a searchable picker over the station’s waiting queue, and a plate the queue does not hold is refused with the error on the field — a reassignment is never recorded against a keke that is not waiting. There is no awaiting-decision and no awaiting-keke state: the decision and its destination are taken together. Outcomes are therefore Reassigned · Sent to inventory · Accepted by inventory (FR-J8), and a record nobody has ruled on yet carries Not yet decided (FR-J6). |
| FR-K4 | A faulty kit cannot be reassigned onto another keke — choosing it forces the decision to return to inventory. Condition claimed at retrieval is claimed in the bucket vocabulary — Unused, Refurbished, Used or Faulty (FR-J7) — and the warehouse confirms the received condition on intake (FR-F6). |
| FR-K5 | Returning a retrieval to inventory mints the retrieval reference the warehouse receives it under, so the station record and the warehouse record are the same reference. Reassigning it records the receiving plate and the date. The serial, the item and both plate fields are searchable pickers, and a value that is not on its list is rejected. A retrieval can only name a serial the system already holds in service — the register of serialized units maps a serial to the item it is and the keke it is fitted to, so choosing a serial fills the item, the plate and the rider rather than re-keying them. The register follows the outcome: a reassignment moves the serial to its new keke, a return to inventory takes it off the fleet. |
| FR-K7 | A kit comes off a keke as a kit and goes back out as parts. One condition and one destination for a whole kit is not what happens on the floor: the controller is fine and goes onto the next keke waiting, the BMS is faulty and is held for repair at the station, the harness goes back to the warehouse. Opening a retrieval therefore opens the items the kit is built from — the same composition the warehouse issues it as — each carrying its own serial (a component’s serial reads off the kit’s own, so the same kit always opens with the same units), its own condition, and its own destination: back to inventory, or held for repair here. A loose part is never refitted (FR-J3) — a keke takes a whole kit, not a component — and a part held for repair holds the rest of the kit with it (FR-P2), so the retrieval settles as one and the record follows what its parts did. A settled retrieval reads back as a record, not a form. |
| FR-K8 | What the station sends is what the warehouse gets. A kit sent back whole arrives on the warehouse’s retrievals desk as that kit; components stripped out of it arrive on the returns desk as individual items (FR-F10). The station’s split is never re-done at the warehouse. |
| FR-K6 | One serial, many lives. The same kit can be retrieved more than once. Each retrieval is its own record and the unit’s earlier retrievals and reassignments are shown on the record, so a serial appearing twice reads as a history rather than a conflict. This replaces the reassignment list that was being maintained by hand against the database. |
7.16 Investigations assigned by the PM
Section titled “7.16 Investigations assigned by the PM”| ID | Requirement |
|---|---|
| FR-G1 | The PM, Vehicle Operations raises investigations off their own analysis and assigns each to a named owner. Where the owner is the Inventory Manager, the investigation appears in this console under Investigations, and an assignment notification lands in this console’s own notifications naming the reference, who raised it and what it is — it is not left to be noticed. |
| FR-G2 | The register shows reference, subject, who raised it, severity, how long it has been running (flagged once it passes the period the PM set) and status, with search, status, severity and raised-date filters, a clear, and summary counts (active, not started, in progress, running long). |
| FR-G3 | A row opens the record: the scope, and an activity log naming who did what and when. The owner can start work, record a finding (each finding is logged and readable by the PM), and close it — which requires both a root cause and the action taken. |
| FR-G4 | The owner can export a findings pack from this console, not only from the PM console. |
| FR-G5 | Investigation actions only. An investigation never dispatches, resolves or signs off an operational record. |
7.17 Notification channels
Section titled “7.17 Notification channels”| ID | Requirement |
|---|---|
| FR-NC1 | Pumble mirrors the in-app and email notifications. Every event that raises an in-app and email notification for Inventory, Procurement, Production, Retrofit or the Head of Maintenance also posts to one shared Tricycle Hardware channel on Pumble. The message names the event and links to the record it concerns. |
| FR-NC2 | Push on Argo and Forge is the same inventory of events. Each app sends a device push for the events that already raise an in-app notification on it, so they reach the person with the app closed, and the push opens the record it is about. Push, in-app and email are one list of events, not three. |
8. Data Model
Section titled “8. Data Model”Atlas is the system of record for all of the below. Amounts and order references also sync to Polaris (§11).
Retrieval (kit or bundle off a keke)
Section titled “Retrieval (kit or bundle off a keke)”ref (BND-####) · item (catalog item) · serial · retrieved_from_plate · rider · date_retrieved · retrieved_by · condition (Unused / Refurbished / Used / Faulty, unset while Not yet decided) · outcome (Not yet decided / Reassigned / Sent to inventory / Accepted by inventory) · reassigned_to_plate · date_actioned · note · photo
Item request (not in the catalog)
Section titled “Item request (not in the catalog)”id · item_name · category · unit · quantity · why_needed · industry_standard · location · requester · requester_role · need_by · urgency · photo · date_requested · status (Pending approval / Approved / Rejected) · approver_role (Head of Production / Head of Retrofit) · decided_on · decided_by · reject_reason · created_item_id · raised_request_id
Location transfer (warehouse → warehouse)
Section titled “Location transfer (warehouse → warehouse)”ref · from_location · to_location · lines[] (item, quantity, unit) · vehicle_type · vehicle_plate · dispatched_on · received_by · received_on · status (Pending dispatch / In transit / Received)
Feedback submission
Section titled “Feedback submission”type (Bug / Improvement) · impact (Blocking / Slows me down / Minor) · area · details · screenshot · app · sender · sender_role · sender_email · submitted_on · status (New / In progress / Resolved / Dismissed) · reply
| Field | Notes |
|---|---|
| id, name, description | name is composed, not free-typed; description required |
| name_parts | {item_type, describe, key_specs, version, how_it_differs} — the parts the name is formed from (how_it_differs required when version set). Drives the live duplicate check |
| image | Required on create; deletable; multiple line images allowed |
| category_id → Category | Group / Category, from controlled vocabulary |
| uom_id → Unit of measure | pcs | each | roll | metre | litre |
| tracking | Serialized | Consumable |
| type_id → Item type | Governed picklist (~101 curated types) carrying aliases[] (search-only; never shown in the formed name). e.g. Retrofit kit |
| on_hand, assigned | Quantities; Available and ATP derived (§9) |
| low_threshold, critical_threshold | Reorder points |
| Relationships | 1 Category, 1 UOM; many Consumption events, Receipts, Returns, Threshold rows |
Assembly procedure (FR-M13 to FR-M18)
Section titled “Assembly procedure (FR-M13 to FR-M18)”| Field | Notes |
|---|---|
| item → Item | The item the procedure produces; an item has one or more procedures |
| name | Unique within the item (e.g. Retrofit · Standard, Retrofit · KAAG) |
| for_kaag_riders | Boolean. At most one Active procedure per item carries it; the Forge switch at rider binding resolves it |
| versions[] | Each: version label (unique within the item) · status (Draft / Active / Deprecated) · made_from (the version it was copied from) · superseded_by · activated by/at · deprecated by/at · steps (BOM, checklist, instruction, acceptance criteria, assignees). At most one Active version per procedure |
| Pinned by | Work order (procedure + version raised on) and unit (procedure + version worked under) |
Category
Section titled “Category”name, description, is_active (disabled → hidden at item creation), item_count (derived).
Unit of measure
Section titled “Unit of measure”name/symbol (pcs | each | roll | metre | litre), is_active, item_count (derived).
Item type
Section titled “Item type”name, aliases[] (search-only), is_active, item_count (derived). Curated in type management (~101 types); new types added deliberately there, never inline on the item form.
Threshold
Section titled “Threshold”item_id, low, critical. Updated automatically when a suggested reorder point is applied.
Request-to-Procurement
Section titled “Request-to-Procurement”requester (team auto-tagged), lines [{item_id, quantity, note}], urgency, purpose/job reference, created_at. Converts to Order.
Facility request (facility → warehouse)
Section titled “Facility request (facility → warehouse)”requester (team auto-tagged), raised_by, reason/purpose (required), date_required (required), work_order_ref (optional; prefills bill of materials), lines [{item_id, quantity}], approved_by (the facility Manager; null when the Manager raised it directly), status. Facility-side status Pending approval → Requested → Pending → Accepted with branches Declined / Rejected / Partially fulfilled; the same record reads Open → Fulfilled / Partially fulfilled / Rejected on the Inventory side (§6.1).
Order (vendor Order)
Section titled “Order (vendor Order)”id, vendor_id, currency, lines [{item_id, quantity, unit_price, request_id?}], total (auto-summed, single currency), shipment_method (air/sea/road), documents[], status (one unified lifecycle), urgency, requisition_ref (PLR-REQ-####, assigned once), description (auto from lines), audit[] ({actor, when, action}). Editable while Draft or Requisition pending; locks once approved. Syncs to Polaris as Description + Amount + Currency + Urgency + attachment — one requisition per order, never summed.
Delivery note (procurement → the requesting warehouses)
Section titled “Delivery note (procurement → the requesting warehouses)”Auto-raised from a shipment receipt (renamed from “waybill”). A note (DN-####) is split into one leg per destination warehouse (DN-####-<WH>), each a separate record: warehouse, request_ids[], line items [{item, requested_qty, purchased_qty (sent), uom, accepted?, received_date?}], vehicle {logistics, vehicle_type, plate} (per leg — different vehicles allowed; all required to dispatch), vendor_freight_ref, status (Pending dispatch → In transit → Partially delivered → Delivered). Legs dispatch independently once ready; dispatch notifies Inventory (in-app + email). Acceptance is Inventory-side, sets received_date per item and closes the tied requests as Received. Custody: received goods sit in Procurement custody (awaiting → in transit → cleared on acceptance).
Procurement Order
Section titled “Procurement Order”bom_id, quantity, debt_facility (optional). Generates vendor Order(s); traceable to them. Out of scope for the Procurement Manager persona in this iteration.
Receipt
Section titled “Receipt”order_ref, expected_qty, received_qty, dimension_cm (optional), image, status (Pending → Received), verified_by, verified_at. Verifying populates stock and moves expected supply into on-hand.
Transfer / Delivery note
Section titled “Transfer / Delivery note”Transfer: facility request → fulfilment (quantity_fulfilled, reduces on-hand, populates assigned), outcome (Fulfilled | Partially fulfilled | Rejected), reason (required on reject/partial). Delivery note: deliver_to {company/facility, contact_name, phone, address}, delivery_no, date, lines [{s_n, item_id (picker), quantity}], logistics {fulfilled_by, vehicle_type, plate_no}, linked_ids[] (must already exist; empty for standalone), delivery_status (In transit on issue → Delivered + accepted_at when the facility accepts in Incoming). Printable.
Return
Section titled “Return”item_id, actual_qty_returned, is_faulty, image, accepted_by, accepted_at. Good return → increments on-hand; faulty → routes to Faulty record.
Faulty record
Section titled “Faulty record”item_id, type, fault_description, batch_lot_no, quantity, returned_by, received_by (store), remarks/action_taken, disposition (Repair and restocked | Returned to vendor | Scrapped) — set by Procurement, not at logging. Held in a separate faulty count awaiting Procurement’s decision.
Quarantine record
Section titled “Quarantine record”item_id, receipt_id (vendor derived from this — not stored separately), batch_id, serials[], quantity, reason, photo, reported_at, status (Awaiting Procurement | Released to stock | Returned to vendor | Scrapped), resolution {outcome, note, resolved_at}, vendor_return {reference (system-generated), status: Awaiting pickup | Picked up | Credit received | Replacement shipped} (only when returned to vendor). Created at receiving when units are damaged/wrong; never counts toward on-hand/Available/ATP. Resolved by Procurement only; Accept into stock adds the quantity to on-hand.
Consumption event
Section titled “Consumption event”item_id, quantity, work_order_ref, occurred_at. Logged when Production/Retrofit accept receipt against a work order, or on direct warehouse issue. Cross-facility. Feeds burn/day.
Quantity change history (audit log)
Section titled “Quantity change history (audit log)”item_id, timestamp, delta, actor, reason. One row per addition/deduction, incl. manual stock-count adjustments. Exportable (CSV).
9. Glossary — Metrics
Section titled “9. Glossary — Metrics”Internal acronyms stay in the data model and this document; UI copy uses plain language (e.g. “Available”, never “ATP”).
| Term | Definition |
|---|---|
| On-hand | Physical units in the warehouse right now, before any commitments. |
| Assigned | On-hand units committed to work orders or approved requests, awaiting issue. |
| Available | Free to promise from current stock = On-hand − Assigned. |
| Expected supply | Quantity on open requests already sent to Procurement (inbound, not yet received). |
| ATP (Available to Promise) | On-hand + Expected supply. Forward-looking availability including inbound. Recalculates when items are received from Procurement (received units move from expected supply into on-hand). |
| Burn/day | Rolling 7-day average units consumed per day, from the consumption log. |
| Days of cover | Available ÷ Burn/day. Flags below the 5-day target. |
| Reorder point | Threshold at which a request should fire; set from usage data, applied to the item’s low/critical thresholds. |
| Consumption event | Logged when Production or Retrofit accept receipt of requested items against a work order (accepting receipt is the consumption), plus any direct warehouse issue. Cross-facility. |
| Pending / Received | Receiving statuses. Pending populates from requests sent to Procurement; Received is set after verify, regardless of quantity match. |
| Faulty stock | Units logged as faulty; counted separately, never counted as available. |
10. Digitized Source Artifacts
Section titled “10. Digitized Source Artifacts”The following manual artifacts are being digitized. Their fields are the source of the requirements above; sample content is retained as demo data.
10.1 Inventory Requisition & Return Form (paper)
Section titled “10.1 Inventory Requisition & Return Form (paper)”- Section A — Item Request: Item No., Description of Item, Quantity Requested, Purpose / Job Reference, Date Required. This is the request form — the digital facility request (§7.11, FR-M1) and the Inventory-to-Procurement request (§7.1) both carry these fields; Purpose / Job Reference is the mandatory request reason (FR-W6) and Date Required the mandatory date.
- Section B — Issued Items: Item No., Quantity Issued, Issued By. (Issuance / delivery-note trigger — FR-T1/FR-T2.)
- Section C — Faulty Component Return Record: Item No., Description of Faulty Component, Batch No., Returned By, Received By (Store), Remarks / Action Taken. (FR-F2.)
- Section D — Authorization: Department Head, Store Officer, Maintenance/Technical Officer — Name + Signature. This is the approval gate — digitized as the facility Manager’s approval of a team member’s request before it reaches the warehouse (§6.1, FR-M2).
10.2 Stock Received arrival log (spreadsheet)
Section titled “10.2 Stock Received arrival log (spreadsheet)”Each arrival logged as “ARRIVAL OF INVENTORY INTO THE WAREHOUSE <date>” with columns: S/N, Items, Dimension (cm), Quantity Received, Quantity Expected. This is the manual version of Receiving — the digital surface carries expected-vs-received per line, optional dimension, and the arrival date (FR-V1/FR-V3).
10.3 Inter-facility Delivery Note (paper, MocX-branded)
Section titled “10.3 Inter-facility Delivery Note (paper, MocX-branded)”Issued when items leave the warehouse for a facility. Fields: Deliver To (Company/Facility, Contact Name, Phone Number, Address), Delivery No., Date, line table (S/N, Description, Qty), Terms (Logistics fulfilled by, Vehicle Type, Plate No.), delivery_status (In transit | Delivered + accepted_at), linked_ids[] (tied request / return / other module ids that must already exist; empty for a standalone note). Reproduced digitally per FR-T2 / FR-T5.
11. Non-Functional Requirements & Constraints
Section titled “11. Non-Functional Requirements & Constraints”Accessibility & theming
Section titled “Accessibility & theming”| ID | Requirement |
|---|---|
| NFR-1 | UI supports light and dark themes, defaulting to system preference, with a manual override persisted per user. |
| NFR-2 | Status/flag indicators maintain WCAG AA contrast (4.5:1 minimum) in both themes — not simple inverted/dimmed variants. |
| NFR-3 | Color uses semantic design tokens (e.g. “surface”, “border”, “danger”), never hardcoded values. |
Navigation & information design
Section titled “Navigation & information design”| ID | Requirement |
|---|---|
| NFR-4 | Every persona lands on their Dashboard first; Dashboard is the first sidebar item. |
| NFR-5 | Every surface carries breadcrumbs, and every drill-down (detail view, dialog, sub-view) carries a back affordance. Navigation state is always visible and reversible. |
| NFR-6 | UI copy uses plain language: no internal requirement IDs, no internal acronyms (say “Available”, not “ATP”), and no meta-explanations of what changed. Surfaces read as a finished product. |
| NFR-7 | Reporting data is reliable enough for finance, leadership, and inventory audiences to use without caveats. |
Design-system canon (binding on all flows)
Section titled “Design-system canon (binding on all flows)”Follows the repo design handbook (CLAUDE.md, PATTERNS.md, DESIGN.md) verbatim:
- Canonical Atlas web shell at 1440, responsive down to mobile with no horizontal scroll — the sidebar collapses to a toggle,
.pstatKPI rows and card grids stack to one column, dialogs fit the screen, and wide tables scroll horizontally inside their.tscroll. .psegpill tabs,.tbl-cardtables,.pstatKPIs,.dlgcentered confirmations,toast().- Brand green
#01E46Fon#111text for primary buttons. - Outline icons only (
fill:none; stroke:currentColor), circular icon containers. - 4px spacing grid; 700 weight for display numerals only; no emoji; no em dashes (use
·). - Filters, visible dates, pagination, and export on every table; multi-select bulk actions where meaningful; image upload where noted; column tooltips on the dashboard days-of-cover and Items tables, each flagged with a small “i” info icon and positioned to stay fully on screen.
12. Dependencies & Assumptions
Section titled “12. Dependencies & Assumptions”- Atlas is the system of record. Polaris syncs to it, not the reverse.
- Polaris holds requisitions, orders, and amounts only — no inventory/stock data. Order records sync to Polaris (FR-R3), but there is no Atlas ↔ Polaris stock reconciliation, because there are no cross-system stock figures to reconcile. The real stock-integrity issue is the confirmed decrement/populate-on-receive bug (FR-V5), fixed internally.
- Both systems are internally owned, so integration is feasible without vendor negotiation. Atlas and Polaris API access and modification rights are available.
- The inventory store is the warehouse (Sango); delivery destinations are facilities.
- QA environment:
https://atlas-qa.rechaj.com. - Polaris requisition shape: Description, Amount, Currency, Urgency, optional Category, optional Vendor, and a required invoice/receipt attachment (PDF or image, ≤10MB each). Atlas’s itemized lines auto-sum into the single Amount; the receipt travels with the record either direction.
13. Out of Scope
Section titled “13. Out of Scope”- Visual/UI design specification for personas other than the Inventory Manager reference (handled per surface as they are built).
- Vendor pricing negotiation and contract terms.
- Migration of historical Sortly data beyond what is needed to unblock new-item creation.
- Facility-to-facility stock movement. A facility pushes stock only back to Inventory or to a team member (§7.11, FR-M4); there is no direct facility-to-facility transfer. (The facility request and push flows themselves are in scope — §5.2, §7.11 — and distinct from the Inventory Manager → Procurement trigger of FR-R1.)
- Direct/non-inventory Polaris requisitions (lump-sum expenses with no item list) — Polaris-only, no Atlas equivalent.
- The issue-blocking rule (blocking new issues against a job until faulty components are logged) — not required in the current phase.
- Work-order schedule performance (e.g. backlog and slip on active work orders) — a real operational concern, but separate from this flow.
14. Related Surfaces (for end-to-end demo)
Section titled “14. Related Surfaces (for end-to-end demo)”Persona surfaces link out to existing flows rather than re-implementing them, so a demo can move end to end:
- Polaris — Requisitions —
../../polaris/screens/dashboard.html: the amount-and-receipt requisition side of the sync. - Battery Identity Admin —
../flows/battery-identity-admin/index.html: serialized-battery custody/identity, adjacent to serialized tracking and scannable tags.
Cross-links live where they are contextual (inline actions), not as a standalone card on a primary surface.
15. Targets set by the PM
Section titled “15. Targets set by the PM”FR-Y1 — Visible on the dashboard. The Inventory Manager console carries a read-only Targets card showing the bands the PM, Vehicle Operations set: days of cover, critical items and open requests, each with the current value and the target.
FR-Y2 — The gap is stated. A measure past its target reads the size of the gap, coloured amber inside the PM’s amber band and red past it.
FR-Y3 — One definition of on target. The card uses the PM’s own band edges; the reorder and cover logic elsewhere in the console reads the same days-of-cover target rather than a separate number. A measure inside its band reads Healthy and one outside it reads Below target, in those words wherever the measure appears.
FR-Y4 — Read-only. Changing a band happens only in the PM’s console.
FR-Y5 — Countable at a glance. The card head states how many measures are off target.
16. Where targets live
Section titled “16. Where targets live”FR-Y6 — Its own page. Targets sits under Overview in the sidebar, beside the Dashboard.
FR-Y7 — The dashboard keeps a one-line strip. It states whether anything is off target and names the measure furthest through its band, and opens the Targets page.
FR-Y8 — The page shows the bands. Each measure is drawn against its red/amber/green bands with a marker at the current value, and the band edges are stated in words.
FR-Y9 — Changes are on the record. Every change the PM has made to a target is listed with what it was, what it became, who changed it and when.
FR-Y10 — A row opens the measure. Clicking a target row opens that measure, its bands and its change history.
17. Days of cover
Section titled “17. Days of cover”FR-Y11 — Counted, not averaged. The Targets card holds Parts below cover: how many items sit under the PM’s per-item days-of-cover rule. A median across parts is not used as a target, because it hides the items closest to running out.
FR-Y12 — The rule is named. The row states the rule that produced the count.
FR-Y13 — A reorder point says where its number came from. A point calculated from consumption reads From data; one on an item with too little history to calculate from reads Collecting data and is not presented as a figure the store can act on.
18. Requesting an item that does not exist
Section titled “18. Requesting an item that does not exist”FR-Z1 — Only for what is not in the catalog. The request form matches the composed item name against the catalog as it is typed. An exact match blocks the request: Send for approval is disabled and the submit path refuses it, so an existing item can never enter the approval queue.
FR-Z2 — The existing item is offered instead. A blocked request shows which item it matched and opens that item directly.
FR-Z3 — A near match warns but does not block. A similar name asks the requester to confirm it is a different item.
FR-Z4 — The form states its purpose before it is filled. It says it is for an item not already in the catalog, and names the line manager who must approve a new one before Procurement can buy it.
19. A retrieved kit carries its own history
Section titled “19. A retrieved kit carries its own history”FR-Z5 — Every movement is written against the serial. Retrieval, reassignment, return and being held for reassignment each append to that serial’s trail, so the unit shows every keke it has been fitted to.
FR-Z6 — A keke is named with its rider. Each trail entry and the reassignment row give the plate and the rider’s name together.
FR-Z7 — The trail is visible where the unit is. The retrieval detail shows the serial’s own history, newest first, with who recorded each movement and when.
20. Voiding a request
Section titled “20. Voiding a request”FR-Z8 — Only before a decision. A request can be voided while its status is pending. Once approved or rejected the decision stands and voiding is not offered.
FR-Z9 — Confirmed, with what is at stake. The confirm names the request and item, the quantity, who was waiting on it and when it was raised, and states that the item is never created and that it cannot be undone.
FR-Z10 — The approver is told. Voiding removes the request from the approval queue and notifies the line manager it was withdrawn.
FR-Z11 — It is on the record. The request keeps a Voided status, the date, and the person who voided it; the approval line reads Withdrawn before approval against them.
FR-Z12 — The list agrees with the record. The row, its badge and the status filter all carry the voided state, so counts never disagree with the request.
FR-Z13 — The trail names the signed-in user. Who performed a retrieval or reassignment is read from the signed-in identity, with their role, not written into the logger.
21. How many levels a new item must clear
Section titled “21. How many levels a new item must clear”FR-Z14 — Who signs is the org chart, not a choice. The approvers of a new-item request are the people above the requester on the reporting line. Neither the requester nor the approver picks them.
FR-Z15 — The PM sets the depth. For each business unit the PM sets how many levels a new item must clear: the line manager only, up to the VP, or all the way to the CEO. It is set on the PM’s Inventory page, on the New items tab beside the request queue it governs, and applies to every request from that unit.
FR-Z16 — The chain is derived and shown in order. The approval line renders one step per required level, naming the role and the person, in the order they sign. Changing the depth changes the number of steps; changing a reporting line changes who they are.
FR-Z17 — The requester sees the cost before filing. The line above the form states how many levels the item needs and names the chain.
FR-Z18 — The chain travels with the record. A submitted request keeps the chain it was sent through, so a later change of policy does not rewrite its history.
22. The cost of getting a delivery to the warehouse
Section titled “22. The cost of getting a delivery to the warehouse”Goods are bought on a purchase order. Moving them to the warehouse is a separate cost, paid to whoever carried them, and it does not belong on the order for the goods.
FR-L1 — Raised where the cost arises. The Procurement Manager raises a logistics requisition from the delivery note leg it is a cost of, not from a blank form. The leg supplies the delivery note, the destination and the goods being carried; only the amount has to be entered.
FR-L2 — One per destination. A delivery note going to three warehouses is three legs, three hauliers, three vehicles and three prices, so it is three requisitions. A cost is never spread across destinations, because no leg would then carry its own true figure.
FR-L3 — The haulier is the vendor being paid. The requisition names the party carrying the leg, defaulted from that leg’s dispatch record, with Procurement as the requester and the destination warehouse as the location.
FR-L4 — It joins the same queue. A logistics requisition is raised into Polaris exactly as a goods requisition is, at Pending approval, and is approved there. There is no second approval path.
FR-L5 — The list carries both kinds without a second table. The requisitions list names what each was raised against — a purchase order or a delivery note — with the kind on the same cell, and filters by goods, logistics, or both.
FR-L6 — A leg states its cost once raised. The leg shows the requisition, its amount, the haulier and its approval status, and does not offer to raise a second one. A leg carrying none reads Not raised, so a leg with no cost against it is visibly a leg nobody has costed rather than a leg that was free.
FR-L7 — Raising commits the haulier. Naming a haulier on a requisition records them on the leg, so the requisition and the dispatch record cannot disagree about who carried it.
FR-L8 — Freight is counted in spend. The Insights Spend tab carries logistics as its own measure: a total for getting deliveries to the warehouses, and a breakdown by haulier with the number of deliveries each carried. It is computed from the logistics requisitions raised, so raising one moves the figure.
FR-L9 — Goods and freight are separate lines. A purchase order and a haulage bill are not the same commitment, so committed spend on goods and spend on logistics are never summed into one number or mixed into the goods categories.
FR-L11 — Raised with a requisition’s own details. A logistics requisition carries what any requisition carries: a description, the requester, an urgency, the party being paid and the amount. The description is composed from the leg it is raised on — what the cost covers, the destination, the delivery note and the number of lines — and stops composing once it is edited.
FR-L12 — Every requisition says what it is for. The requisitions list shows each one’s description beneath its reference. A goods requisition takes it from the lines of the order it was raised against; where no order is held on the console, the description is left empty rather than invented.
FR-L10 — One base, one rate. Requisitions raised in another currency are normalised to the base currency at the rate the page states, so the currency switcher converts freight and goods together and the two can be compared.
23. Stock condition buckets
Section titled “23. Stock condition buckets”FR-B1 — One item, one name. Stock for an item is held in condition buckets — New, Refurbished, Used — and the condition is never a separate catalog item and never part of the item’s name.
FR-B2 — Every bucket is stock. On-hand, ATP, days of cover and the reorder-threshold alerts run on the total across buckets. A refurbished unit is usable stock and is counted as such.
FR-B3 — Faulty is not a bucket. Faulty, damaged and incomplete units are held separately and never count as available.
FR-B4 — Composition is visible. The items table shows the buckets as quantity columns alongside on-hand, and the item record repeats the breakdown with each bucket’s share.
FR-B5 — The requester never picks a condition. A facility requests an item and a quantity. There is no condition field at request time and no additional step.
FR-B6 — The manager assigns per bucket. Fulfilment shows the requested quantity and what each bucket holds, and takes a quantity per bucket. A line may be split across buckets, taken entirely from one, or issued short.
FR-B7 — A bucket cannot over-issue. Each entry is capped by what that bucket holds, because that is where the stock is; the line’s issued figure is the sum of its buckets, never typed.
FR-B8 — A shortfall stays outstanding. Issuing less than requested leaves the remainder outstanding on the request and still requires the partial-fulfilment reason.
FR-B9 — The split is on the record, both sides. A fulfilled request states what it was issued
from — issued: 2 new, 1 refurbished — to the requester and the inventory manager, and the
movement history logs the same words.
FR-B10 — A return is received in the bucket vocabulary. The conditions offered at acceptance are exactly the buckets — Unused restocks to New, Refurbished to Refurbished, Used to Used — so a return cannot be described in words the stock model does not hold. Retrieved and reassigned units go to the retrieved queue; faulty, damaged and incomplete go to returns and never become available.
FR-B11 — A serialized unit carries its own condition, and the buckets are the rollup of those units.
FR-B13 — A faulty return carries a disposition. Inventory chooses what happens next: return it to Procurement’s quarantine, or hold it for repair. A held unit counts as faulty — on the shelf, never available — until it is fixed, and accepting the repair restocks it into the Refurbished bucket with the movement on the record. The disposition applies to loose-stock returns and retrieved kits and bundles alike (FR-F6).
FR-B14 — The stages a return passes through are named. A return sent back to Procurement reads Sent to Procurement quarantine. A return held for repair reads Verifying fault while the fault is being confirmed, and lands on On-hand · refurbished once the repair is accepted, the movement recording that it was repaired and restocked as refurbished. A return that needs no repair reads Restocked, or Restocked · flagged where what arrived did not match what was sent.
FR-B12 — A stock count counts per condition. The physical count is taken one quantity per bucket, with faulty counted beside them because it sits on the same shelf without being stock. Every condition must be counted; on-hand reconciles as the sum of the counted buckets, faulty reconciles separately, and the movement history records the counted split. Nothing reads as a variance until every condition is in: the count then states Matches system, Over N or Short N against the system figure, with Faulty ±N carried beside it as its own number.
24. When a count disagrees with the delivery note
Section titled “24. When a count disagrees with the delivery note”A delivery note says what was sent. The warehouse counts what arrived. Any difference between the two is a variance case, opened automatically. There is no tolerance and no setting that decides whether a difference counts.
FR-S1 — The Inventory Manager counts, and only the Inventory Manager. The quantity received is entered when the Inventory Manager receives the delivery note leg. Procurement never records a count.
FR-S3 — Any difference raises a case on the spot. The moment the quantity received differs from the quantity sent, by any amount, verifying the receipt opens the case automatically and notifies the Procurement Manager and the person who raised the request, in-app and by email. Nobody opens a case by hand and nothing is configured to decide it. The notification carries the item, the expected and counted quantities, the variance, the delivery note leg, the vendor, the haulier, the vehicle and the destination warehouse, and opens the case.
FR-S4 — The case carries what an enquiry needs. Reference, delivery note leg, destination warehouse, vendor, vendor freight reference, haulier with vehicle and plate, who raised it and when, the photo taken at receipt, and a line per item stating quantity ordered, quantity sent, quantity received and the variance.
FR-S5 — A variance is valued at landed cost. The value is the actual unit cost, what the vendor charged plus that line’s share of getting the order here, times the quantity missing. The line states both figures so the difference between the two is visible.
FR-S6 — The leg states what was counted. A delivery note leg shows quantity received beside quantity sent, names the gap as short or over, and carries a variance state linking to the case.
FR-S8 — The investigation is a note, not a form. Chasing happens on the phone, by email and in person, over days, so the case keeps a running note, each entry stamped with who wrote it and the day and time. Nobody is assigned a case and nothing is due on a date; an open case states how long it has been open instead.
FR-S9 — Four outcomes, each landing where that claim already lives. Vendor short-shipped raises a credit or replacement on the vendor return path. Lost in carriage raises a deduction against that leg’s haulage. Warehouse count error triggers a recount and the adjustment that follows, with no claim on anybody. Unresolved writes it off.
FR-S10 — A case owed money stays open. Naming who it belongs to settles the argument, not the account. A case attributed to a vendor or a haulier stays open, carrying its outcome and its age, until the money is recorded. A recount or a write-off owes nothing and closes on the spot.
FR-S11 — Recovery follows the document it is owed on. A vendor claim settles when its return reaches credit received, against the credit note, or replacement shipped, against the shipment carrying the goods. A haulier deduction settles when the haulage requisition carrying it is approved. Anything settled another way is recorded by hand with the amount, the method, the document and the day. Part settlements are allowed and the case states the shortfall until it is whole. Until the settling document lands, the recovery reads Awaiting settlement rather than a figure the ledger has not seen.
FR-S12 — Writing off takes a reason. A write-off always names a reason and still records the vendor and the haulier, so a pattern accumulates against both. Every case is worked the same way whatever its value: there are no configured write-off or approval values, and Procurement has no variance setting.
FR-S13 — The shortfall is never re-ordered automatically. Backfilling asks who bears it: the vendor replaces it free of charge, and the order is raised at no cost with the value recorded as recovered; the vendor issues a credit instead, and the credit is the recovery with no order; or it is bought again at our cost. The request the leg served keeps the close it already has.
FR-S14 — The warehouse reads its cases, and does not work them. Inventory sees every case it raised with the counts, the value, the vendor, the haulier, the status and the outcome, and edits none of it. It supplies the count and the photo.
FR-S15 — The board reads in money. Open cases, value at risk on those still open, recovered, and written off.
25. The haulier that moved it
Section titled “25. The haulier that moved it”A delivery note leg is carried by somebody, and a name typed into a box cannot be asked anything afterwards, priced in advance, or held to a record.
FR-H1 — Contractors are a registry, beside the vendors. A logistics contractor holds its name, contact name, phone, email and status, the vehicles it runs with type, plate, driver name and driver phone, the warehouses it covers with a rate per route and the date last agreed, and its documents.
FR-H2 — A contractor has at least one vehicle. A contractor with no vehicle cannot be dispatched with, so one is required wherever a contractor is created or saved.
FR-H3 — A dispatch picks, it does not type. Logistics fulfilled by on a delivery note leg is a selection from the registry, and picking one fills the vehicle type, plate, driver name and phone, all still editable. A one-off haulier is still a typed name, and a new contractor can be added from the dispatch with only what a dispatch cannot do without: name, contact name, phone and one vehicle. The rest is completed on the contractor record.
FR-H4 — The driver number can be the contractor’s. Where the driver is the person already on the contractor, the leg reads that number off the registry rather than having it typed again, and keeps reading it while the contractor is changed.
FR-H5 — The rate card prices the requisition. Raising a logistics requisition reads the contractor’s rate for that destination and fills the amount. A route with no rate on file leaves the amount to be entered.
FR-H6 — A shipment names its haulier too. Carrier and transport details carry a logistics contractor beside the carrier, with its vehicle and driver, because the carrier who moved the freight and the haulier who moved it on the ground are not the same party.
FR-H7 — The record is computed, not typed. A contractor states the legs it hauled, the shipments it moved, the share of those legs that arrived short or over, the variance cases still open against it and what has been spent with it, all read off the board.
26. What a split kit becomes
Section titled “26. What a split kit becomes”A kit or bundle that comes off a keke whole is still a kit and can go straight onto the next one. Splitting it by item ends that, because the parts are loose stock the moment they are separated.
FR-J1 — Splitting is the station’s act. A retrieved kit is split at the retrofit station, never at the warehouse, and only into the items the kit is built from.
FR-J2 — A split item travels as a single return. Each part goes back to the warehouse as its own return, under its own condition, never as a kit or bundle retrieval. A mix of conditions across the items is normal and is carried per item.
FR-J3 — A split item cannot be refitted. Fitting a loose part to another keke is not offered. The only destination a split item has is the warehouse, and settling a split closes the retrieval as sent whatever mix of conditions the items carry.
FR-J4 — The kit it came out of travels with it. Every part names the kit it was stripped from, which is where the history of a split kit lives once the kit itself no longer exists.
FR-J5 — A reassignment is minted when the keke is received. Completing a retrieval on Kit retrieval opens the unit held against that plate on Kit reassignment, to settle. Confirming the arrival does not, and nothing is minted twice for the same unit.
27. Claimed, sent, accepted
Section titled “27. Claimed, sent, accepted”FR-J6 — A retrieval nobody has ruled on has no condition. Not yet decided means the condition and the outcome are both unset, and the screen states that rather than defaulting to a condition the record does not hold.
FR-J7 — A claim is made in the condition buckets. A retrieval and a return are claimed in the
words the warehouse stocks by, Unused, Refurbished, Used and Faulty (FR-B1), and never in a
good-or-faulty pair the warehouse cannot restock against.
FR-J8 — Sending is not returning. Stock that has left the station reads as sent and states that it is awaiting acceptance until the warehouse takes it, and only then as accepted. Custody transfers at acceptance, not at dispatch.
FR-J9 — The claim is editable until it is accepted. While the warehouse has not accepted it, the claimed condition can be corrected, per item on a split and on the kit itself where it went whole. Once accepted it is fixed, because the decision is then the warehouse’s.
28. Kit retrieval
Section titled “28. Kit retrieval”FR-Q1 — The list sits beside the riders. Kit retrieval is a .pseg tab beside Riders
on Rider management, because the riders and the retrievals raised against them are two
readings of the same people. Kit reassignment sits beside it, carrying what each kit did
once its keke arrived.
FR-Q2 — Three stages, and the counts are the filters. A retrieval reads Arrived, to confirm, then Arrival confirmed, then Retrieval completed. The KPI strip counts them as To confirm · Awaiting completion · Completed, and each count filters the table to its own stage.
FR-Q3 — Arrived is a claim, not a fact. Retrieval logistics approves the retrieval, sends it and marks it arrived. Arrived is that person’s claim, so the station manager confirms the keke is actually standing there before anything else can happen to it.
FR-Q4 — Only a confirmed retrieval can be completed, and the row menu offers only the step the record can take next.
FR-Q5 — Completing is what mints the kit reassignment (FR-J5). Confirming the arrival does
not, and nothing is minted twice for the same unit.
FR-Q6 — What the row carries. Rider with the phone under it · plate number · status · sent, with the retrieval-logistics person who dispatched it under it · 4-week efficiency, a 0 to 1 ratio held as the backend holds it and shown as a percentage, with any threshold written in the same unit · last update, the status with its date and who moved it · actions. Over them sit search, a status filter, a sent-date range, an export, and a reset that appears only once something is filtered.
FR-Q7 — The record’s trail is built from its own stamps. The retrieval record carries the retrieval, who sent it, the trigger, and a status trail assembled from the stamps themselves — generated, sent for retrieval, marked arrived, confirmed, completed — so the trail and the record cannot disagree.
FR-Q8 — The PM console mirrors it read-only. Product Manager · Vehicle Operations shows the same three stages and takes neither the confirmation nor the completion.
29. A unit inside a work order
Section titled “29. A unit inside a work order”FR-E1 — Five states, one vocabulary. A unit in a production or retrofit work order is Queued, In progress, Rework, Awaiting QA, or Closed · QA pass. No surface carries a sixth.
FR-E2 — The progress bar, the legend and the filter agree. The work-order Overview draws one progress track with a legend chip per state, the Units tab filters on the same five, and the KPI row jumps to the matching filter.
FR-E3 — QA is a state of the unit, not a separate queue. Awaiting QA is where a unit sits between its last build step and the QA decision, and a unit in Rework is one a QA gate failed, named with the gate and the reason on its assembly record. The decision itself is taken on the floor app; Atlas reads the state.
30. The Atlas · Polaris sync log
Section titled “30. The Atlas · Polaris sync log”FR-O1 — Every sync leaves a row. The Atlas · Polaris sync page carries a sync log with one row per record: record reference, direction, amount, status, date synced, and the action open on it.
FR-O2 — The row names its direction. A record Atlas raised and pushed reads Atlas → Polaris. A record that exists in Polaris with nothing behind it in Atlas reads Polaris only.
FR-O3 — Status is the sync’s own outcome. A pushed record reads Synced. A Polaris-only record reads No Atlas equivalent, which is a statement about the pair, not a failure of the push.
FR-O4 — The head states the standing position. With nothing outstanding the card reads All order records synced, so the page answers the question without the reader working through the rows.
31. Approvals, shelf life and what a requester can ask for again
Section titled “31. Approvals, shelf life and what a requester can ask for again”FR-A1 — An approval says whether anyone has looked. A category or new-item approval reads Pending while it waits, Approved or Rejected once decided, and Not reviewed where that approver’s step has not been reached. Not reviewed is not a decision and never stands in for one.
FR-A2 — Shelf life is stated on the item, not calculated by the reader. An item with an expiry reads In date, Expiring soon as it approaches the threshold, or Expired, and the date sits beside the word.
FR-A3 — A request already in flight cannot be raised twice. An item the requester has an open request against offers Already requested in place of the raise action, so the same need is not filed twice.
FR-A4 — Stock waiting to be collected says so. A fulfilled request that has not been collected reads Ready for pickup until the requester takes it.
32. A part on the bench holds the kit
Section titled “32. A part on the bench holds the kit”FR-P1 — Repair is a destination. Alongside reassigning the kit and returning it, a retrieval can be held for repair here: the whole kit, or single items when only some of them need work. Holding is chosen on the same decision as the others, not as an afterthought to it.
FR-P2 — A hold stops the whole retrieval. While any item is held for repair, nothing leaves — not the held part and not the parts beside it. A kit half-sent around a component still on the bench is a kit the warehouse can never reassemble and a keke that can never be fitted, so the retrieval waits as one.
FR-P3 — The record names what is held. A held retrieval reads Held for repair and states whether it is the whole kit or which items, with the day it was held and who held it.
FR-P4 — A repaired kit is decided again, as a kit. Marking it repaired puts the kit back on
the floor whole and returns it to the decision it was taken from: sent to inventory, or
reassigned onto another keke waiting at the station. The repaired parts carry
Refurbished, which is the bucket the warehouse restocks them into (FR-B13).
FR-P5 — The hold is on the serial’s trail. Holding and repairing both append to the unit’s own trail, naming what was held, so a kit that went to the bench twice reads as two events on one unit.
33. The team pool and its gate
Section titled “33. The team pool and its gate”Two shared team pools exist at each location, one for Production and one for Retrofit (Forge Floor App PRD §7.10). Each has a steward — §3.5 and §3.6 — and this section states what their console owes.
33.1 The pool is one set of movements
Section titled “33.1 The pool is one set of movements”| ID | Requirement |
|---|---|
| FR-TP1 | On-hand is derived, never stored twice. A pool line’s on-hand is its opening balance plus every movement against it. Burn per day, days of cover, the forecast shortfall and the write-off count are all computed from the same movements, so no two surfaces can state different numbers for the same fact. |
| FR-TP2 | The ledger is append-only. A movement is never edited or deleted; a correction is a new movement naming the one it corrects. Movements read in plain language — Received, Used on unit, Returned to warehouse, Written off, Reversed — never an internal state name. |
| FR-TP2a | The pool sets its own thresholds. Every line inherits the warehouse’s low and critical figures and can be set away from them per pool line (Forge Floor App PRD FR-FS8). The record states which figures are in force, what the warehouse sets, and who changed them and when; a line still on the inherited figures says so. |
| FR-TP2b | A threshold is set against the pool’s own rate, not guessed. Setting one shows what this pool draws per day, how long a replacement takes, and the quantity drawn while that replacement is in flight. A low point below that quantity is called out, because it cannot leave anyone time to order. Critical must sit below low, or the line can never read Low. |
| FR-TP2c | A line’s status is classified the way the estate classifies it. The figure classified is ATP — what the pool holds plus what the warehouse has fulfilled and the pool has not received yet — read against the line’s own two thresholds: at or under zero is Stock out, at or under critical is Critical, at or under low is Below target, otherwise Healthy. The pool sets the thresholds (FR-TP2a); the words and the arithmetic are the estate’s, not the console’s. |
| FR-TP2d | Days of cover is read off the schedule, not a trailing average. A line’s cover is the day the work already committed exhausts it, taken in due-date order; the fortnight’s draw rate stands in only when nothing scheduled draws it, and a line nothing has drawn says so rather than reading zero. Cover is stated beside the status, not folded into it. |
| FR-TP3 | The ledger answers three questions: per person, every item they drew with the work order and unit it went on; per work order, every item consumed and who drew it; per item, its whole movement history. Filterable by movement, item, person, work order and date window, with CSV export, which is a web feature. |
33.2 The gate
Section titled “33.2 The gate”| ID | Requirement |
|---|---|
| FR-TP4 | Every floor request passes one gate. A request raised on the floor reaches the warehouse only through the pool’s inventory manager. The requester’s line manager does not approve it (§3.3, §3.4) — one request, one gate. |
| FR-TP4a | A request is one surface. The gate, what was sent to the warehouse and what is on its way back are one path and belong on one page, as panels, not as separate destinations. The gate is the panel it opens on. |
| FR-TP5 | A decision is made against what the pool holds. Opening a request shows each line’s quantity beside the pool’s current on-hand for that item, and flags a line the pool cannot cover, so the steward can see whether the request is already satisfiable. |
| FR-TP6 | Approving moves the one record on; it does not mint a second. A request is REQ-#### from the moment the floor raises it to the moment the stock lands, as it is on the Production Manager console (§3.3). Its status carries it: With inventory at the gate, then Requested · Awaiting receipt · Fulfilled · Partially fulfilled, or Rejected by the warehouse, or Declined at the gate. The register shows its origin — approved from the floor, naming the requester and their role, or raised by the steward with no approval step. |
| FR-TP7 | Rejecting requires a reason, and that reason is what the requester reads. A rejection is refused without one. |
| FR-TP8 | A decision is kept as history. The approvals register is the full log, not just the queue: an actioned request stays with its outcome, who actioned it and when, and is never removed. Median time to decide is reported from it. |
| FR-TP8a | A fulfilled request is received where it is read. The Requests panel receives the whole request at once; the Incoming panel receives a line at a time, because that is the grain it lists. Receiving by either route writes the movement and raises on-hand for the whole team. |
| FR-TP8b | Receiving takes the quantity received and a serial per serialised unit, as the Inventory Manager’s receiving desk does (Forge Floor App PRD FR-FS4). One field per serialised line takes a scan, a typed serial on Enter, or a CSV of the packing list; captured serials show as removable chips with a running count, a serial the warehouse did not send is refused, and the receipt is blocked while any line is short. A quantity above what was fulfilled is refused, and a short receipt leaves the request Partially fulfilled. No lot or batch number is captured at the pool — a batch is the warehouse’s record of a production run, not something a pool keys at receipt. |
| FR-TP8c | A receipt states what was asked for as well as what turned up. A line the warehouse cut reads both its requested and its fulfilled quantity, and the received quantity defaults to what was actually sent, so a short shipment cannot be read as a complete one. |
| FR-TP8d | A quantity is entered in the unit it is counted in. A poured line steps in tenths; anything counted whole steps in ones and cannot be entered as a fraction. |
| FR-TP9 | The steward’s own request skips the gate. A request the inventory manager raises goes straight to the warehouse with no approval step, because the person raising it is the approver. Its origin reads “raised by me”. |
33.3 The forecast
Section titled “33.3 The forecast”The point of this surface is that a procurement request takes days to approve and weeks to deliver, so reading a shortfall on the day a work order opens is reading it far too late.
| ID | Requirement |
|---|---|
| FR-TP10 | Demand is built from work, not from history, and the committed work and the planned work are read separately rather than blended into one figure. A kit draws the sub-assembly it is built with, not that sub-assembly’s own parts, which are drawn by the work order that builds them. |
| FR-TP10a | Committed work is read per work order. A work order is raised from an assembly procedure and the procedure carries the per-unit bill of materials, so each open work order states its procedure and version, the units still to build, and every line multiplied out: per unit, needed, available, short. A work order that cannot run says so on its face. |
| FR-TP10b | Stock is allocated across the committed work orders in due-date order. Showing every work order the whole pool balance is how they all read covered while the line stops, so each one shows what is genuinely left for it after the work due before it. |
| FR-TP10c | Planned work reads as work orders too. The plan carries work orders that have not been raised yet, each built to an assembly procedure, so they are shown card for card like the committed ones — reference, procedure and version, units, due date, and the bill of materials exploded — with stock allocated among them in due-date order after the committed work has taken its share. A planned job still sitting there after its due date says so on its card. |
| FR-TP10c1 | A planned job is closed out by noting that its work order exists, not by raising one. The inventory manager does not raise work orders; the manager does, and the plan is how the pool hears what is coming. Noting one stops the plan counting that job’s bill of materials a second time, mints nothing, leaves the job in sight marked as raised, and can be undone. |
| FR-TP10d | What to order and by when is stated on the line that is short, not in a second list. The per-item roll-up across the planned work is the arithmetic behind the need-by and order-by dates and is what the export carries; it is not restated as a view, because every card already carries its own shortfall and its own way to act on it. |
| FR-TP10e | Every assembly procedure’s bill of materials is readable on its own, independent of any work order: its version, its step count, and each item it draws per unit against what the pool holds. |
| FR-TP11 | Planned demand is read against what the committed work leaves behind. Availability for planned work is the pool plus what is already incoming, less what the open work orders will draw. |
| FR-TP11a | The need-by date is where the demand actually bites. The jobs drawing an item are taken in due-date order and the demand accumulated; the date the running total passes what the pool can supply — on-hand plus what is already on its way — is the date the item is needed by. |
| FR-TP12 | Order-by is need-by minus lead time, and it is the column that matters. Lead time is stated as its parts: the days Procurement takes to approve plus the days the vendor takes to deliver. An order-by date in the past is shown as such, because that is the fact the steward has to act on. Status reads Covered · Order now · Order this week · Scheduled. |
| FR-TP13 | An item the estate builds is not a purchase. A line the Production line makes reads its lead time as a build here with its batch time, not a vendor lead. A station that takes a short kit to Procurement has gone to the wrong people, so the row has to say so. |
| FR-TP14 | The forecast answers a hypothetical. The steward can add N units of any assembly and the whole table recomputes, so “if we take this many more work orders, what will we need” is asked directly rather than inferred. |
| FR-TP15 | A shortfall is actionable from the card that is short. A work order or planned job reading short raises one warehouse request for exactly its gap, dated to the job’s due date and naming the job as the reason. |
33.4 Recycle
Section titled “33.4 Recycle”| ID | Requirement |
|---|---|
| FR-TP16 | One register, for material the floor cannot draw again. A leftover carries what is left of it — Offcut · Part-used · Packaging, or Strip-out for a part taken off a chassis — the work order it came off, who logged it, and what happens to it. Logging one off pool stock writes a movement against the item and is refused for a quantity the pool does not hold; a strip-out never sat in the pool, so it carries its own unit and writes no movement. |
| FR-TP16a | What the warehouse decides does not belong here. Damage, expiry and a QA failure send stock back on a return (§33.5), where the warehouse routes it — to repair, to Procurement, or to scrap. The pool’s register does not restate those outcomes or offer them as choices. |
| FR-TP17 | Leftovers are counted, not priced. This console does not carry what an item cost. The only money on the surface is a resale value where there is one, which is the point of the register: what can still be got back. |
| FR-TP18 | Anything still worth something is routed, not discarded. A leftover’s route is one of three: Held for resale · Re-used here · Scrapped. It runs Held until it leaves the bay the way its route said, when it is marked Cleared. What is still held, what that is worth, and the share kept out of scrap are all reported. |
| FR-TP19 | The retrofit station’s stream is the chassis. Parts stripped at conversion — the engine, the fuel tank, the exhaust — are leftovers, not pool stock: they never came from the warehouse and are never counted on a shelf. They are held against the work order that stripped them, and they are the largest holding on the page by value. |
33.5 Returns to the warehouse
Section titled “33.5 Returns to the warehouse”Stock also travels the other way, and until it could the ledger named a movement kind nothing was able to produce. The register is the Outgoing panel of the request page, beside the gate and what is coming in, because it is one leg of the same path (FR-TP4a).
| ID | Requirement |
|---|---|
| FR-TP20 | The pool can send stock back. A return names the item, the quantity, a condition of Unused or Faulty, and why it is going back. It leaves the pool the moment it is raised and writes a Returned to warehouse movement against the item. |
| FR-TP21 | A return is capped and evidenced. The quantity cannot exceed what the pool holds, the reason is required, and a faulty serialised line requires the serial of every unit before it commits. |
| FR-TP22 | The warehouse decides the outcome, and this surface only reads it. A return runs Awaiting acceptance and then whatever the Inventory Manager’s returns desk records — Restocked · Held for repair · Faulty stock · Sent to Procurement · Scrapped · Declined. The pool’s console proposes nothing new here. |
33.6 Notifications
Section titled “33.6 Notifications”| ID | Requirement |
|---|---|
| FR-TP23 | The centre is scoped to the pool and derived from it. It opens from the topbar bell, with no sidebar entry (as FR-R12), and is built from the pool’s own data rather than seeded beside it: floor requests waiting on a decision, lines at or below their critical threshold, forecast lines whose order-by date has passed, warehouse deliveries fulfilled and not yet received, returns the warehouse has not yet accepted, and recent write-offs. Entries group by day. Anything needing an action today is unread, and mark-all-read clears the bell indicator. |
| FR-TP24 | Two channels, carrying different loads. A low threshold alert and a passed order-by date are each sent on their own, in-app and by email (as FR-U4), because neither can wait for the next sign-in; a line at or below critical goes out in the bundled critical alert on Monday, Wednesday and Friday (FR-U4). Everything else in the centre is in-app only — a request waiting on a decision, a delivery to receive, a return not yet accepted, a write-off. Emailing all of it is how a person learns to ignore the ones that matter. |
| FR-TP25 | Each alert names its recipients. A threshold alert goes to the team’s manager and the pool’s inventory manager (Forge Floor App PRD FR-FS8), never to whoever last held the part. A passed order-by date goes to the pool’s inventory manager alone, because raising the request is that person’s decision. Neither is routed to the central warehouse, which sees the request when it arrives. |
| FR-TP26 | An alert repeats only when its cause changes. A line already alerted stays alerted without re-sending. It is sent again when it crosses a further threshold, when its order-by date moves because the planned work changed, or after the condition has cleared and returned. Duplicates within five minutes collapse into one. |
| FR-TP27 | An email says what to do, not that something happened. It names the pool, the item, the figure that tripped it and the action open to the reader, and links to the panel that performs it. The bundled critical alert is the one digest (FR-U4): it lists every line at or below critical, each with its on-hand, its threshold and a link to it. No digest stands in for a low threshold or a passed order-by alert. |
33.7 Surfaces
Section titled “33.7 Surfaces”34. The approval line on an item request
Section titled “34. The approval line on an item request”A request for stock is not always the requester’s to make on their own. Some of what the catalogue holds is expensive enough, or scarce enough, that the unit has to justify it; and a request for something the catalogue does not hold at all is a decision about what the estate stocks, not a withdrawal from it. Both take an approval first, and the approval is the requester’s own line manager.
| ID | Requirement |
|---|---|
| FR-AL1 | The approver is the requester’s line manager, never Inventory. Inventory fulfils a request; it does not authorise one made on it. The rung is set by the PM Vehicle Operations and the request goes to whoever sits above the raiser on it — so a request raised by a unit head goes a step further up, not back to the raiser. |
| FR-AL2 | Two kinds of request take the step. A request for an item the catalogue does not hold, and a request for one it does that Inventory has flagged. Everything else goes straight to the warehouse. |
| FR-AL3 | Inventory authors the flag, item by item. The catalogue record carries whether a request for that item needs a manager’s approval before the warehouse will fulfil it. Setting the flag is Inventory’s; giving the approval is not. |
| FR-AL4 | A request waiting on approval has not reached Inventory, is not counted as work the warehouse holds, and the surface that shows it names who it is waiting on rather than implying the warehouse has it. |
| FR-AL5 | Every request states which kind it is — new item or existing item — and can be filtered down to either. |
| FR-AL6 | Approving raises the request on Inventory, and where it is for an item the catalogue does not yet hold, the approval creates that item. The warehouse record and the catalogue record both exist the moment the approval is given, not when somebody retypes either, and the request names what it became. |
| FR-AL6a | A requester composes the catalogue name, never types one. The item type comes off a controlled list, with a descriptor, the key specs and a version where two items are otherwise identical; the name assembles in front of the person raising it. That, with the classification, the unit, the standard and a photograph, is the catalogue record the approval mints, which is why the composer asks for all of it. |
| FR-AL6b | The composer refuses a name that already exists, on the catalogue or on a request still waiting on a decision, and warns where a name is close to one of either without being the same. |
| FR-AL7 | Approving tells the requester, in-app and by email. They are the one waiting on it. Declining requires a reason, and the reason is what the requester and their manager read. |
| FR-AL8 | The decision is kept on the record with the approver’s name and the moment, and travels with the request: Inventory reads who approved it, and Procurement reads who approved it and the team it came from. |
| FR-AL9 | Every unit runs the same line. Production, Retrofit and Maintenance each raise, approve and route the same way; a unit’s own console is where its requests are approved. |
| FR-AL10 | Bay replenishment is a different line. A bay’s request for parts is approved by the Head of Maintenance, and is not an item request in the sense of this section. |
| FR-AL10a | A bay request naming a flagged item takes both approvals. The flag is about the item, not about who asked, so the Head of Maintenance approves it as always and it then goes to the line manager rather than to the warehouse. The record names both rungs and the part that put it on the second one. |
34.1 Where all of it lands
Section titled “34.1 Where all of it lands”| ID | Requirement |
|---|---|
| FR-AL11 | One desk gathers every unit’s requests once its own head has signed, so the estate’s purchases are decided against the whole picture rather than one unit at a time. It reads what waits on this desk, what is still with a unit head, and what has been approved or declined. |
| FR-AL12 | A request waiting there alerts in-app and by email (as FR-U4), because a held purchase stops whichever unit asked for it. An urgent request is distinguished from a normal one. |
| FR-AL13 | A decided request opens read-only. The record stays readable after the decision — what was asked, why, who signed it, what it became — rather than only being reachable while it is still actionable. |
| FR-AL14 | The approver is named on the row, not only on the record, as a person with their title: a title alone does not say who to ring. A queue of requests is read as a queue; opening each one to find out who authorised it is not reading it. |
| FR-AL14a | Most requests carry no approver, and the field is empty on those. Approval is the exception — a new item, or one Inventory has flagged — so a filled field is itself the statement that this request took a manager, and the record says plainly when none was required. |
| FR-AL14b | Procurement is copied on item-approval notifications, both when a request reaches the approving desk and when it is decided, because Procurement is who sources whatever is approved. |
| FR-AL15 | Asking for stock and asking for a new item are separate composers. The stock composer searches the catalogue and says so; a visible action beside it opens the new item composer. One field doing both jobs tells the requester about neither. |
| FR-AL14c | A request still awaiting a decision can be amended and voided by its raiser. Nothing has moved and nothing is committed while it waits, so the quantity is editable and the request can be withdrawn with a reason; a voided request stays on the list rather than disappearing. Every other field is locked, because changing what the item is after sending is a different request, and a decided record is read-only. |
| FR-AL14d | The same thing cannot be requested twice. A name already on the catalogue is a stock request, not a new item request; a name already waiting on a decision is the same request twice. Both are refused at send and the record or item they collide with is named. |
| FR-AL15a | The new item composer asks for what the catalogue record and sourcing both need: the composed name, category, unit, quantity, when it is needed, urgency, what fails today, the industry standard or part number, and a photograph. It does not send without the standard, because nobody can source a part from a name and a quantity. |
34.2 Who a purchase request belongs to
Section titled “34.2 Who a purchase request belongs to”| ID | Requirement |
|---|---|
| FR-AL16 | Procurement’s requests are raised by the warehouse, not by the floor. The floor asks Inventory; Inventory fulfils what it holds and raises the rest. The queue states that once rather than repeating one constant name down a column. |
| FR-AL17 | The floor people who wanted the item are named, with the team of each, because that is what tells a buyer whose work stops. |
| FR-AL18 | One purchase line can carry several of them. The warehouse batches the same item across teams, so the row states how many asked and the record names each one, their team and their share of the quantity. The shares add up to the line. |
35. What Procurement buys against
Section titled “35. What Procurement buys against”| ID | Requirement |
|---|---|
| FR-BM1 | Each business unit’s bill of materials is held on one page. What a unit needs to run, line by line, uploaded a unit at a time rather than inferred from whatever it happened to request that week. |
| FR-BM1a | The quantity is per rider. A line states what one rider’s build takes, so the order is that figure against the riders planned. Stating it per quarter means re-deriving it every time the plan moves. |
| FR-BM1e | An item several units run on is a line per unit, never one line summed, because the quantity and the reason differ by unit. The page groups by unit so each unit’s list reads as a block, and a line for an item another unit also runs says so. |
| FR-BM1b | A line can only name an item the system already holds. The sheet carries the business unit, the item and the quantity; the category, the tracking and the unit of measure are read off the catalogue, never typed, so a list cannot introduce an item nobody can order or disagree with the catalogue about what a thing is counted in. A row naming something not on the catalogue is skipped and named, not silently added. |
| FR-BM1c | The business unit is a team the system already holds, not free text. The unit filter is built from that list rather than from the lines present, so a unit with nothing on it yet still appears, and a sheet naming anything else is skipped and named the same way an unknown item is. Teams that hold and move stock rather than build against a rider do not run a bill of materials. |
| FR-BM1d | A sample sheet is downloadable, written out of those two lists: a row per business unit, spelled as the system spells it, against an item the catalogue holds. Neither the shape nor the names are guessed. |
| FR-BM2 | Every line can carry a note, and the note is the part a buyer cannot get from the item name: the substitute that is acceptable, the vendor who holds the mould, why the quantity is what it is. A line with nothing to add says so rather than reading empty. |
| FR-BM3 | The page filters by unit and by category, searches across the note as well as the item, and exports. |
| FR-BM4 | A delivery note can be printed from the surface that raised it, in the same action and the same words the warehouse already uses on its own copy. What prints is the note: not the navigation, not the page behind it, and not the controls that only work on a screen. |
| FR-BM4a | An exported file opens as what it is. Exports carry the estate’s separator and names with accents, so a CSV declares its encoding rather than leaving a spreadsheet to guess and open rider's as rider’s. |
| FR-BM5 | A stock count can say why. The reason is optional, because most counts are the routine cycle, and it reads on the item’s history beside the figure it moved. |
35.1 Insights breaks down one view at a time
Section titled “35.1 Insights breaks down one view at a time”| ID | Requirement |
|---|---|
| FR-BM6 | Requests are read in one breakdown, not three tables. The grouping is chosen in the card’s head — by item, by team, by warehouse — and a parent row opens into what it is made of: an item into the teams that asked for it, a team into the items it asked for. |
| FR-BM7 | A breakdown row carries the cadence, not just the count: how often the line is asked for, the usual gap between asks, and when it was last asked. |
| FR-BM8 | A pattern worth a second look is named. Oversized, Repeat while open, Split requests, Rising and Mostly urgent, filterable to any one of them or to anything flagged, with the flagged count stated. |
| FR-BM9 | Requested is set against used. Per team: what was asked of Procurement, what was asked of the warehouse, what the warehouse issued and what the floor actually put on a unit, with the share used stated and anything under half used flagged. That is where the leak shows. |
| FR-BM10 | The export follows the view on screen, so a file is of the breakdown that was being read rather than of everything at once. |
36. What a thing costs
Section titled “36. What a thing costs”Every surface here could say what was bought and none could say what it cost to buy it again. An order’s own detail prices its lines; nothing stated what the same item cost the last time, what anyone else charges for it, or what a rider’s worth of parts comes to. A buyer pricing a line had the figure in their head or on another page.
| ID | Requirement |
|---|---|
| FR-IP1 | A price is what an order committed to. A draft nobody sent, a requisition still pending and one the approver rejected set no price. Only an order that reached a vendor does, which is the same line the system draws when it counts purchase orders. A register that counted the rest would report prices nobody has agreed to pay. |
| FR-IP1a | A line at zero is a buy and not a price. An order line may legitimately charge nothing — a vendor replacing faulty stock, a free-replacement backfill — and the newest such line must never become the item’s cost: it would read zero against the item, zero per rider and a 100% fall, wiping a real price with a figure nobody paid. The price is the newest buy that charged something. The zero line stays on the purchase history, because it happened and the units are on the shelf, and reads No charge rather than a percentage; the comparison skips past it to the last buy that charged, so a free replacement between two orders does not break the chain. Vendor comparison is of charged buys only, since a zero would take the lowest every time. An item every one of whose buys was free reads Never charged — neither a price nor no history — and can be given a quoted cost like anything else without one. |
| FR-IP2 | Item pricing lists every catalogue item against what it costs: the unit cost the vendor last charged with its date, the cost per rider (what one rider takes of it, times that cost), and the change against the buy before, carrying the figure it was struck against. Tiles partition the catalogue into priced, risen, fallen and never bought, and each tile is the filter for what it counts. |
| FR-IP3 | The change is struck on the unit cost, never on the landed one. What a unit cost standing on the shelf includes its share of the order’s logistics, apportioned by the line’s share of that order’s value, so it moves with what else happened to be bought that day. Comparing two landed figures would report a shift in the freight ratio as a move in the vendor’s price. For the same reason the actual unit cost is not on the item sheet at all: it is a fact about an order line, and the order detail and the item’s purchase history state it there, beside the logistics share that produced it. |
| FR-IP4 | Two prices in different currencies do not compare. The system holds no exchange rate with an as-of date, so a percentage struck across a currency change would be invented. The row reads Currency changed and sends the reader to the history, where every buy is stated in the money it was bought in. Nothing anywhere on these surfaces is summed across currencies; a total that spans two states both. |
| FR-IP5 | An item’s own record holds its whole price history, narrowed by a location (the warehouses it was bought for) and a period (This month to All time, or the dates Insights opened it with; All time from Item pricing). Tiles Qty bought (in the item’s unit, across N orders) and Spent (per currency, with the average paid per unit) lead, then the unit cost and lowest unit cost, which stay the item’s own whatever the period. Bought per month draws a bar a month across the period, zero where nothing came in. The history lists every buy in the period newest first with the order, date, vendor, quantity, unit cost and actual unit cost, each line marked where it was priced as a lump and each stating what it did to the price against the buy before — the oldest reading First buy, and one in a different currency saying so rather than a percentage. with a total quantity row. Beside it, by vendor: every vendor it was bought from in the period, the currency, how many times, the quantity bought, and its last, lowest and highest unit cost, most bought first. Back returns to where the record was opened from. |
| FR-IP6 | The last unit cost shows at the point of ordering. Under the unit cost field on an order line: what was last paid, to whom and when, or that the item has never been bought. A buyer types against a known figure rather than from memory. |
| FR-IP7 | An item nobody has bought can be given a cost. A quoted unit cost, with the currency, who quoted it and a note, so a plan can be costed before the first purchase order. It is labelled Quoted in every cell it reaches, it never counts as a buy, and the first purchase order supersedes it. A quote that read like a price would make a plan costed off quotations indistinguishable from one costed off invoices. |
| FR-IP8 | Freight is priced on a load, not on a rider. A shipping rate names its load — a 20ft container, a 10t truck, an air pallet — what that load costs, and the rider kits it carries; the per-rider share is the division between them, printed rather than asserted, which is what shows a bigger load coming out cheaper per kit. The kit count is optional: a haulier quotes a load and a price, and how many kits fit is worked out later, so a rate can be on file before anyone has counted it. Such a rate cannot cost a rider and is offered nowhere that would need it to. The rates sit with the price list, because freight is a price. |
| FR-IP9 | The bill of materials costs a rider. Each line carries the item’s unit cost and what one rider’s worth of that line comes to, and the table’s foot totals whatever is on screen — so narrowing to one business unit totals that unit and leaving them all totals a whole rider’s build — with the shipping method chosen in the card head adding its per-rider share in its own currency. The foot names what it is missing and what of it is not a purchase (1 line quoted · 3 lines not priced): an item nobody has bought has no cost, and a total that treated it as free would read as the settled figure. |
| FR-IP10 | Inventory reads the unit cost and only reads it. Inventory does not buy, so it sets no price; it still has to know what a unit costs, because a stock adjustment, a write-off and a count variance are all worth money. The item record’s summary figures carry the current unit cost with the vendor and date it came from, labelled Quoted where that is what it is. No history, no landed cost, nothing editable. Procurement owns the price and its record. |
36.1 What the price is read from
Section titled “36.1 What the price is read from”A price is read off the order book rather than held on the catalogue item: the order line’s unit cost, its currency and quantity, against the order’s vendor and the day it went out. The landed figure is read from the one place that apportions an order’s freight and discount across its lines, so a unit cost read on the item and a unit cost read on the order cannot disagree. A vendor’s preferred-item record and the order book are the only inputs; nothing here needs a price field on the item itself, and nothing here writes one.
37. A keke that comes back inside its first three months
Section titled “37. A keke that comes back inside its first three months”A station hands a converted keke to a rider and then hears nothing. If the motor fails five weeks later the case is raised against maintenance, resolved at a bay and closed, and nothing of it ever reaches the station that built it. The floor’s own quality numbers stop at the door: first-pass yield and rework rate both measure the work before it leaves, and a station can hold both at ninety percent while sending out kekes that come back in a month.
| ID | Requirement |
|---|---|
| FR-EB1 | The measure is the failure rate, not its complement. The tile reads broke down within 3 months, not three months breakdown-free. A share of successes buries a rise inside a large number, where 94 to 91 reads as a good score slipping and 6 to 9 reads as half again as many kekes coming back. |
| FR-EB2 | The denominator is kekes whose three months have elapsed. One converted last week has not had its chance to fail and would only dilute the rate. Those still inside their window are counted and stated separately, with any that have already broken down named, so nothing with a known outcome is hidden. Where the register lists more rows than the rate counts, the difference is stated on the register rather than left to the reader. |
| FR-EB3 | The clock starts when the rider collects, and at Ready for pickup where no collection was recorded. A keke standing at the station is not in service and cannot break down in one. |
| FR-EB4 | Only what the conversion touched counts — motor, harness, VCU and battery wiring. A fault outside that set on the same keke rides the record for context and is never in the rate, and the record says which it is rather than dropping it. |
| FR-EB5 | A pattern is named only when there is one. A line above the register names a repeating component at three or more of the same, with the count and the total, and says nothing otherwise. The same fault twice over is a coincidence a manager should not be asked to act on. |
| FR-EB6 | The riders register flags the rider, reading Broke down N days after conversion. The flag appears only on a rider who has collected a converted keke, because a rider awaiting their first inspection cannot have broken down after a conversion. It rides the conversion cell rather than a column of its own. |
| FR-EB7 | An early breakdown opens as one keke’s timeline: the conversion step by step with who did each and when, the QA result, the collection, then the failure from field rescue with when, where and what the rider reported. The serials fitted at conversion sit beside it. |
| FR-EB8 | The maintenance record shows read-only — complaint, diagnosis, work done, parts removed and fitted with serials, who, dates, photos and outcome. The station reads it and writes nothing in it. Scope is narrow: only kekes converted at that station, only early breakdowns, only read. |
| FR-EB9 | A removed serial is matched to the one this station fitted. Where a part the bay took off carries a serial this station put on, the line says so on its face: fitted at conversion 1 Jun 2026, removed at Ikorodu bay 25 Jun 2026. Parts the station did not fit are marked as such, because a swap is only evidence about the conversion if the conversion fitted the thing swapped. |
| FR-EB10 | The cause is set once, by the station, after the bay closes. Four causes: Workmanship, Component, Rider use, Not conversion-related. While the case is open the record offers no action and reads Maintenance in progress, because a cause settled before the diagnosis is a guess entered as a fact. Setting a cause is the only thing this surface writes. |
| FR-EB11 | An early breakdown alerts in-app and by email when it happens (as FR-U4), because it is the one event on this surface the station cannot see for itself. A weekly summary email carries the rate, the new early breakdowns and the top repeating cause. |
| FR-EB12 | A Reports page holds the exports and the deeper cuts. Summary cards that read the filtered list rather than the register behind it, the register with search, a cause filter and export, and a grouping over the same filtered rows: by component, step, technician, batch and vendor. The export carries every column the grouping can cut by, so the same question can be asked off the page. |
| FR-EB13 | The maintenance consoles say how new the keke is. A Converted N days ago badge, red, on the case and on the tricycle work order in the Head of Maintenance console and on the work order in the Argo Maintenance Supervisor app. It stops at three months: past that the conversion is no longer the first thing to suspect, and a badge on every case would say nothing. A battery work order carries a pack rather than a plate and takes none. |
37.1 Which fault belongs to which step
Section titled “37.1 Which fault belongs to which step”A grouping by step and by technician is only worth reading if a fault maps to a step the same way every time it is counted. The mapping is held in one place and read by the register, the grouping and the export alike: motor and VCU to Motor and VCU, harness to Harness and wiring, battery wiring to Battery mount. The technician is whoever ran that step on that keke, not whoever closed the work order, so a grouping by technician names the hands that did the thing that failed.
38. What a rider’s parts come to, and by when they must be ordered
Section titled “38. What a rider’s parts come to, and by when they must be ordered”The bill of materials says what a rider takes (FR-BM1) and what one rider’s worth of it costs (FR-IP9). Neither answers the question Procurement actually has, which is what to buy for the next five hundred riders, how much of that is already covered, and which lines are late. A multiplication is not a budget: it ignores the stock that exists and the orders already placed, and it has no deadline in it.
| ID | Requirement |
|---|---|
| FR-BG1 | The budget is a tab on the bill of materials, not a page of its own, because it is the same lines read against a plan. |
| FR-BG2 | The plan is what a rider needs times the riders planned for. The rider count and the date needed by are the two inputs; everything else is derived. |
| FR-BG3 | A budget is the plan less what is already covered. Covered is stock available to promise plus quantity already with a vendor; what is left is what to buy, floored at zero and rounded up, since a line cannot be bought in fractions and an over-covered line is not a negative purchase. |
| FR-BG4 | Grouping is by item, not by bill-of-materials line. An item appearing on two units’ bills is one purchase, and netting its stock against each line separately counts the same stock twice. |
| FR-BG5 | The second output is a date. The order-by date is the date needed by, less that vendor’s lead time; a line already past it is the thing worth knowing today, and Past the order-by date is one of the filters. |
| FR-BG6 | One display currency is offered and never assumed. The default shows each line in the money it is bought in. Where a reader asks for a single currency, every converted figure carries the rate and the date it was read beneath it, quoted with the heavier unit as the base so a plan read in dollars still reads 1 USD = ₦1,500 rather than a long decimal. A converted total nobody can reproduce is worse than two totals. |
| FR-BG7 | The tiles read the lines on screen. Parts, Freight, Budget and Order now all follow the filters, the way the bill of materials’ foot does (FR-IP9); a tile reading the whole plan above a filtered table is a second, contradictory answer on one page. |
| FR-BG8 | Freight is not apportioned to a subset. It is quoted on a load of whole rider kits (FR-IP8), so under a filter the Freight tile says so rather than printing the whole plan’s freight beside one unit’s parts, which would read as that unit’s total. |
| FR-BG9 | A Budget tile exists only where one currency covers both halves. Parts in one currency and freight in another do not add, and the tile is absent rather than wrong. |
| FR-BG10 | The parts figure names the basket it could not price, as 12 of 15 items priced. An item nobody has bought has no cost (FR-IP7), and a total presented over three quarters of a basket with nothing said is worse than no total. |
39. What the keke runs on, and whether it is talking
Section titled “39. What the keke runs on, and whether it is talking”A station that converts a keke and then hears nothing from it had nowhere to ask why. The rider record named the rider and the plate and said nothing about the hardware fitted to it, so a silent keke was a phone call to telematics.
| ID | Requirement |
|---|---|
| FR-HW1 | The rider record carries a Hardware block: the VCU, the SIM mapped to that VCU, and the battery pack. |
| FR-HW2 | The VCU and the battery pack are the station’s to set. Each reads its serial with Remove when one is fitted and Assign when none is, and assignment offers only what this station holds free, so a unit already on another keke cannot be offered twice. |
| FR-HW3 | The SIM is read, never set. Attaching one is telematics bench prep — serial, then SIM, then firmware, then ping — done before the device reaches a station, so there is no Attach control here. What the station gets is the fact and who it sits with. |
| FR-HW4 | The words are the shipped contract’s. ConnectivitySim already models this, so the row reads its own states — DATA_ATTACHED, SMS_ONLY, OFFLINE, CAP_BLOCKED — rather than inventing a second vocabulary for one fact. Mapped means a SIM carrying this VCU’s serial. |
| FR-HW5 | Unmapped is a different problem from mapped and quiet, so they do not share a badge. No SIM mapped reads with Telematics · bench prep, because it is a bench job never done and nobody at the station can fix it. A mapped SIM that has stopped talking reads its state and how long since it last did. |
| FR-HW6 | Every row carries its as-of time. The whole thing is a synced snapshot and ConnectivitySummary.asOf is nullable, so the row says as of today 09:12, or that nothing has ever synced. Online with no as-of claims the SIM is talking when it means it was talking when the read model was last read. |
| FR-HW7 | The masked ICCID shows, because the contract offers iccidMasked and a station does not need the full number to raise a ticket. |
| FR-HW8 | The SIM hangs off the VCU, not the rider, which is what it does physically: assign a VCU and its SIM comes with it, remove the VCU and the SIM goes too, and the remove confirmation says so. Keyed to the rider, a rider would keep a SIM after losing the device it was mapped to. |