Store hub orchestrator: POS/MPOS <-> ApexEdge <-> HQ. Offline-first, contract-driven, with durable order submission and document generation.
- Overview
- Build and run
- Quality gates
- Manual testing: Local POS Simulator
- Testing
- Contracts
- Security and operations
- Crates
- Documentation
- Project policies
- License
git clone https://github.com/AncientiCe/apex-edge.git
cd apex-edge- Architecture diagrams: See docs/architecture/README.md for high-level mermaid diagrams (system context, bootstrap, routes, POS/document/outbox/sync flows, observability).
- Northbound: POS clients send cart/checkout commands; ApexEdge returns cart state or finalize result.
- Southbound: HQ syncs catalog, prices, promos, coupons, config; ApexEdge submits orders via durable outbox.
- Local-first: All transaction data (catalog, pricing, promos, coupons, config) is available on the hub so checkout does not require external calls.
- Documents: Receipt, merchant copy, kitchen chit, etc. are generated by ApexEdge and exposed for POS retrieval. The POS is responsible for printing.
Docker (OS-agnostic: Windows, Linux, macOS):
docker build -t apex-edge .
docker run -p 3000:3000 -v apex-edge-data:/data apex-edgeThe image stores the SQLite DB in /data; use -v apex-edge-data:/data (or any volume/path) to persist it. Override the DB path with -e APEX_EDGE_DB=/data/apex_edge.db if needed.
Local (Rust):
From the repo root, run the server. The database file is created automatically if it does not exist.
cargo run -p apex-edgeOr build and run the release binary:
cargo build --release
# Linux / macOS:
APEX_EDGE_DB=./apex_edge.db ./target/release/apex-edge
# Windows (PowerShell):
$env:APEX_EDGE_DB = ".\apex_edge.db"; .\target\release\apex-edge.exeOptional: set APEX_EDGE_DB to a path (relative or absolute). Default is apex_edge.db in the current working directory.
To quickly populate the local DB with plenty of demo categories, products, and customers:
# Linux / macOS
APEX_EDGE_SEED_DEMO=1 cargo run -p apex-edge
# Windows PowerShell
$env:APEX_EDGE_SEED_DEMO = "1"; cargo run -p apex-edgeOr pass a CLI flag:
cargo run -p apex-edge -- --seed-demoSeeded data is store-scoped to store_id = 00000000-0000-0000-0000-000000000000 and includes (at minimum):
-
8 categories
-
180 products with prices and descriptions
-
120 customers with codes and emails
-
6 promotions (coupons: SAVE10, FLAT5, VIP20; automatic: spend $20 get 5% off, Beverages 10% off, Buy 2+ Bakery get 15% off Bakery)
-
Health:
GET /health— liveness. -
Ready:
GET /ready— readiness (checks DB). -
POS:
POST /pos/command— envelope withversion,idempotency_key,store_id,register_id,payload(see contracts). -
Documents:
GET /documents/{id}andGET /orders/{order_id}/documents— fetch generated documents for local POS printing.
Before pushing or opening a PR, run the same checks as CI:
make checkThis runs (in order): cargo fmt --all -- --check, cargo clippy --workspace --all-targets --all-features -- -D warnings, cargo test --workspace --all-features, and cargo audit. Individual targets:
make fmt— check formatting (usemake fmt-fixto fix).make clippy— lint.make test— unit, integration, smoke, and full order-flow journey tests.make test-journey— run only the orchestrator journey tests (create cart → products, customer, promo, payment → finalize → document + HQ payload).make audit— dependency advisories.
Install cargo-audit if missing: cargo install cargo-audit (or make setup).
A local-only POS simulator frontend (Vite + React + TypeScript in frontend/) lets you drive the API from a browser for manual testing.
- Backend and frontend run as separate processes; the simulator talks to the API at a configurable base URL (default
http://localhost:3000). - For a full cart → order → documents flow, the backend database must have catalog items, price book entries, tax rules, and optionally customers and promotions (e.g. seed data as in
apex-edge/tests/orchestrator_journey.rsor your own fixtures).
-
Start the backend
- From the repo root:
cargo run -p apex-edge(orcargo build --releasethenAPEX_EDGE_DB=./apex_edge.db ./target/release/apex-edge). - Leave it running (default:
http://0.0.0.0:3000).
- From the repo root:
-
Start the frontend
cd frontend, thennpm install, thennpm run dev.- Open the URL shown (e.g.
http://localhost:5173) in a browser.
-
Configure connection
- In the simulator, set API base URL to
http://localhost:3000(or the host/port where the backend is listening). - Click Health then Ready.
- Pass: Health shows
ok, Ready showsready. - Fail: If you see an error or no response, check that the backend is running and CORS is enabled (backend uses
tower-httpCORS layer).
- In the simulator, set API base URL to
-
Run a POS journey
- Create cart: Click Create cart. Pass: Cart ID appears and state is
open. - Lookup product: Enter a SKU that exists in your DB (e.g. from seeded data), click Search products. Pass: At least one product appears. Select it, set quantity, click Add line. Pass: Cart state updates; line appears; total/subtotal reflect the item.
- Set customer (optional): Enter a customer code that exists, click Search customers. Select a customer, click Set customer. Pass: Cart shows customer.
- Checkout: Click Set tendering. Pass: State becomes
tendering. Enter an amount ≥ cart total (e.g.10.00), click Add payment. Pass: State becomespaid. Click Finalize order. Pass: Order ID and print job IDs appear; cart is cleared.
- Create cart: Click Create cart. Pass: Cart ID appears and state is
-
Validate documents
- After finalize, the Documents panel can use the shown Order ID. Click List documents. Pass: At least one document summary is returned (e.g. receipt).
- Click a document link to fetch its content. Pass: Document content (or error message) is shown.
-
Negative checks
- Search for an invalid SKU or customer code. Pass: UI shows empty list or error in event log; no crash.
- Send an unsupported command path if the UI exposes it. Pass: Backend error details appear in the event log.
Pass criteria (summary): Health and Ready return OK; you can create a cart, add a line (with a valid product), set tendering, add payment, and finalize; order ID and print job IDs are shown; listing and fetching documents for that order succeed; errors for invalid input are visible in the UI/event log.
- Unit / integration:
cargo test --workspace --all-features(ormake test). Covers all crates plus the apex-edge binary tests. - Smoke tests: In-process server tests in
apex-edge/tests/smoke_http.rshit/health,/ready, and a minimal POScreate_cartflow; they start the app on a random port and use an in-memory SQLite DB. - Full order flow (journey):
apex-edge/tests/orchestrator_journey.rsruns create cart → search/add product → search/add customer → add second product → assert 20% automatic promotion → receive payment → place order → generate document → assert document content and full HQ outbox payload. Run withmake test-journeyor as part ofmake test. - Release smoke: The
.github/workflows/smoke-release.ymljob builds the Docker image, runs the container, and asserts/health,/ready, andPOST /pos/command(create_cart) withcurl.
- POS <-> ApexEdge:
PosRequestEnvelope<PosCommand>,PosResponseEnvelope<T>,CartState,FinalizeResult. Seecrates/contractsand docs/contracts/. - ApexEdge -> HQ:
HqOrderSubmissionEnvelope(withsubmission_id,sequence_number,checksum). Idempotent ingest expected.
- Secrets: Use env or a secret store for DB path and HQ URL; no secrets in logs.
- Transport: In production use TLS (e.g. mTLS for HQ). Encryption at rest for DB is deployment-specific.
- Audit: Order finalization and HQ submission can be recorded via
apex_edge_storage::audit::record. - Observability: Structured logging (tracing); health/ready for DB. Prometheus metrics are exposed at
GET /metricswhen the app is started with the default binary (recorder installed). See Metrics for the catalog and usage. - Vulnerability reporting: See SECURITY.md.
Metrics are Prometheus-style (counters, histograms, gauges) with an apex_edge_ prefix and bounded label cardinality. Scrape GET /metrics (e.g. http://localhost:3000/metrics) and point Prometheus at this target.
| Family | Type | Labels | Description |
|---|---|---|---|
apex_edge_http_requests_total |
counter | method, route, status_class |
Total HTTP requests by route and outcome |
apex_edge_http_request_duration_seconds |
histogram | route |
Request latency by route |
apex_edge_http_requests_in_flight |
gauge | route |
In-flight requests by route |
apex_edge_pos_commands_total |
counter | operation, outcome |
POS commands (create_cart, add_line_item, finalize_order, etc.) by outcome |
apex_edge_pos_command_duration_seconds |
histogram | operation |
POS command handler duration |
apex_edge_document_operations_total |
counter | operation, outcome |
Document get/list by outcome (hit, not_found, error) |
apex_edge_document_operation_duration_seconds |
histogram | operation |
Document operation duration |
apex_edge_outbox_dispatch_attempts_total |
counter | outcome |
Outbox dispatch attempts (accepted, rejected, http_error, timeout) |
apex_edge_outbox_dispatch_duration_seconds |
histogram | — | HQ HTTP call duration |
apex_edge_outbox_dlq_total |
counter | — | Messages moved to dead-letter queue |
apex_edge_sync_ingest_batches_total |
counter | entity, outcome |
Sync ingest batches by entity and outcome |
apex_edge_sync_ingest_duration_seconds |
histogram | entity |
Sync batch processing duration |
apex_edge_db_operations_total |
counter | operation, outcome |
DB operations (get_document, fetch_pending_outbox, etc.) |
apex_edge_db_operation_duration_seconds |
histogram | operation |
DB operation duration |
Behavior ownership: Route/flow → owner (api/health, api/pos, api/documents, outbox/dispatcher, sync/ingest). DB and HQ call sites are instrumented in storage and outbox.
Usage: Configure Prometheus to scrape the ApexEdge instance (e.g. add to scrape_configs). Example alert seeds: high 5xx rate on apex_edge_http_requests_total, high latency on apex_edge_http_request_duration_seconds, non-zero apex_edge_outbox_dlq_total, or apex_edge_db_operations_total with outcome="error".
| Crate | Role |
|---|---|
apex-edge-contracts |
POS/HQ and sync data shapes, versioning |
apex-edge-domain |
Cart state machine, pricing/promo/coupon pipeline, order |
apex-edge-storage |
SQLite persistence, migrations, outbox, documents, audit, idempotency |
apex-edge-sync |
Async ingest with checkpoints and conflict policy |
apex-edge-outbox |
Durable outbox dispatcher (retry, backoff, DLQ) |
apex-edge-printing |
Document generation (render + persist for POS retrieval) |
apex-edge-metrics |
Prometheus metric names, labels, and recorder bootstrap |
apex-edge-api |
HTTP API (POS, health, ready, documents) |
apex-edge |
Binary entrypoint |
| Document | Description |
|---|---|
| Architecture | System context, bootstrap, routes, POS/outbox/sync/observability diagrams |
| Contracts | POS ↔ ApexEdge and ApexEdge → HQ message shapes |
| Runbook | Deployment, environment variables, health checks, troubleshooting, go/no-go checklist |
| Changelog | Release history |
| Policy | Description |
|---|---|
| Contributing | How to set up, develop, and submit changes |
| Security | How to report vulnerabilities privately |
| Code of Conduct | Community standards |
Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.