ShopFloor - System Overview
System Overview
Section titled “System Overview”What this system is
Section titled “What this system is”CTLShopFloor is a hybrid Warehouse Management System (WMS) and Manufacturing Execution System (MES) for consumer-electronics refurbishment. A facility running this system receives used laptops, desktops, monitors, and similar devices, processes them through a sequence of inspection / cleaning / imaging / grading / packing stations, and either ships them out as refurbished sellable inventory or routes them to repair, harvesting, or scrap.
It is not a generic warehouse system — it knows about Windows licensing (DPK injection), hardware-spec capture, cosmetic vs. functional triage scoring, parts cannibalization, and per-tenant routing rules. It manages a unit from the moment its serial number is scanned at the receiving dock until the moment it leaves the building.
Who uses it
Section titled “Who uses it”| Role | Primary interaction |
|---|---|
| Receiving operators | Scan inbound pallets and units at the Dock station. |
| Triage technicians | Run the Cosmetic and Functional questionnaires at Triage. |
| Repair technicians | Diagnose and repair failed units at the Repair Center; consume parts from inventory. |
| Imaging technicians | Install Windows + capture hardware specs on a separate “Windows Test System.” |
| Floor operators | Move units through Cleaning, Grading, Kitting, Packing, QA, Pallet, and Finished Good stations via barcode scans. |
| Harvesting / Recovery operators | Cannibalize parts from BER units into inventory. |
| Buyers / Procurement | Create Purchase Orders for replacement parts; receipt them into inventory. |
| Customer service / Returns | Create RMAs for returned units (in-system or out-of-system). |
| Sales / Fulfillment | Watch outbound pallets close into FGI; reconcile via Fishbowl and Mercado Libre imports. |
| Operations management | Read reports (BER, BinLocation, FG, Fallout, Receiving Reconciliation, Settlement, Variance, etc.). |
| Admins | Configure projects, stations, routes, BOMs, tenants, permissions. |
| Partner systems | Push inbound orders via the external API. |
What business problem it solves
Section titled “What business problem it solves”The system answers, at every moment, three questions per unit:
- Where is this unit physically right now? (
WorkTracking.StationID) - What has been done to it? (
WorkTrackingOperations,RepairCenter,SystemInformation,KittingLog, the triage submissions, etc.) - What is its current sellable state and grade? (
GradingID,ErrorFlag,OutboundPalletID,UnitSoldDate, etc.)
And, at the aggregate level: how many units are at each station, how many failed at each step, what parts inventory is consumed, what the BER rate is per program, and what the per-project P&L looks like once acquisition cost is reconciled.
The lifecycle in one picture
Section titled “The lifecycle in one picture”Every StationType in the system belongs to exactly one of seven phases. Unit flow proceeds left-to-right through these phases, with branches into the “Outside-Process” lane for repair, BER, harvesting, and quarantine.
flowchart LR F[Forecast<br/>6] --> R[Receiving<br/>7] R --> W[WIP<br/>8] W --> P[Pre-FGI<br/>9] P --> FGI[FGI<br/>10] FGI --> Post[Post-FGI<br/>11]
W -.-> OP[Outside-Process<br/>12<br/>Repair, BER, Harvest, Quarantine] P -.-> OP OP -.-> WSee 02-unit-flow.md for the full station-by-station narrative.
Key external systems
Section titled “Key external systems”| External system | Direction | Purpose |
|---|---|---|
| Fishbowl (MySQL ERP) | Inbound (read-only) | Sales orders, inventory. Polled by Hangfire jobs and the always-on inventory sync. |
| Mercado Libre | Inbound | Marketplace sales orders. Polled daily. |
| HP PCB API | Inbound (read-only) | HP product catalog, tech specs, images by model. |
| BitRaser | Inbound (read-only) | Drive-erasure and verification reports. Polled daily; persisted to DriveEraseLog / DriveVerificationLog. |
| Channel Advisor temp file | Inbound | Channel-name enrichment for sales import reconciliation. |
| Windows Test System | Bidirectional (offline) | Off-floor station that installs Windows, injects DPKs, captures specs. Results uploaded back via WindowsTestResultsUpload. |
| Partner systems | Inbound | Push inbound orders into the facility via CTLShopFloor.Presentation.ExternalAPI (API key + Bearer auth). |
| Azure Blob Storage | Outbound | Stores 6-month tracking reports, BitRaser logs, image uploads, PDF labels. |
| MongoDB | Outbound | Receives Audit.NET entity-change records (auditLog.shopFloor collection). |
| Seq | Outbound | Centralized Serilog log aggregation. |
High-level architecture
Section titled “High-level architecture”flowchart TB subgraph Presentation WAPP[WebAPP<br/>MVC + Razor + Syncfusion EJ2] WAPI[WebAPI<br/>Internal admin API] EXTAPI[ExternalAPI<br/>Partner integration] end subgraph Services WASI[WebAppServicesImplementation<br/>~150 controller-services<br/>ServiceManager facade] WASC[WebAppServicesContracts<br/>Interfaces] end subgraph Infrastructure PERSIST[Persistance<br/>EF Core 9 + repositories<br/>RepositoryManager UoW] end subgraph Core DOMAIN[Domain<br/>~225 entities + enums] CONTRACTS[Core.Contracts<br/>Interfaces] SHARED[Core.Shared<br/>DTOs] end subgraph External SQL[(SQL Server<br/>Repository + Tenant)] FB[(MySQL<br/>Fishbowl)] MONGO[(MongoDB<br/>Audit)] BLOB[Azure Blob] HF[Hangfire<br/>SQL-backed] SEQ[Seq] end WAPP --> WASI WAPI --> WASI EXTAPI --> WASI WASI --> WASC WASI --> PERSIST PERSIST --> DOMAIN PERSIST --> SQL PERSIST --> FB WASI --> BLOB WASI --> MONGO WASI --> HF WAPP --> SEQFor the detailed wiring see 10-architecture.md.
Technology stack at a glance
Section titled “Technology stack at a glance”| Layer | Stack |
|---|---|
| Runtime | .NET 9.0, C# 12 with nullable reference types enabled |
| Web | ASP.NET Core 9 MVC + Razor + Syncfusion EJ2 grids/charts |
| ORM | Entity Framework Core 9 (SQL Server primary, Pomelo MySQL for Fishbowl) |
| Multi-tenancy | Finbuckle.MultiTenant 9 (header → session → route resolution) |
| Auth | ASP.NET Identity (cookies) + JWT Bearer + custom API Key |
| Background jobs | Hangfire (SQL-backed, ~18 active recurring jobs) |
| Logging | Serilog → Console + SQL ErrorLog table + Seq |
| Audit | Audit.NET → MongoDB |
| Testing | NUnit 4 + NSubstitute |
| Reporting / Excel | Syncfusion XlsIO |
Multi-tenant model
Section titled “Multi-tenant model”A single deployment serves multiple tenants (real ones in the system include “Mexicali” and “Dallas SL”). Tenant resolution happens via HTTP header tenant, falling back to session, then to route parameter _tenant_. All application entities are scoped by TenantId through Finbuckle’s global query filter, applied automatically on RepositoryDbContext.
Inside a tenant, work is further partitioned by Project — a customer program or business unit. Most entities carry a ProjectID and are scoped accordingly.
⚠️ Known smell: several pieces of business logic branch on hardcoded tenant names (Triage routing, sales-import facility mapping, HP COA report eligibility). See 20-refactor-findings.md.
Where to read next
Section titled “Where to read next”| If you want to… | Read |
|---|---|
| Understand what a single unit does, end to end | 02-unit-flow.md |
| Look up a domain term | 03-glossary.md |
| Understand how the code is wired | 10-architecture.md |
| Find an entity and its neighbors | 11-data-model.md |
| Look up what a particular station does | 12-station-catalog.md |
| Understand the route/scan engine | 13-workflow-engine.md |
| See what runs in the background | 14-jobs-and-integrations.md |
| See what to refactor first | 20-refactor-findings.md |