System Architecture¶
Overview¶
graph TB
subgraph External
CIN7[Cin7 ERP<br/>Source of Truth]
end
subgraph Data Pipeline
AIRFLOW[Apache Airflow<br/>Nightly ETL]
end
subgraph Azure Cloud
DB[(Azure SQL Database<br/>cin7_purchase_orders_headers<br/>cin7_po_lines)]
API[Azure Functions<br/>Node.js API]
SWA[Azure Static Web Apps<br/>React Frontend]
end
subgraph Auth
AAD[Microsoft Entra ID<br/>Azure AD B2C]
end
CIN7 -->|SP-API / Export| AIRFLOW
AIRFLOW -->|MERGE Upsert| DB
DB --> API
API --> SWA
AAD -->|MSAL Auth| SWA
AAD -->|JWT Validation| API
Technology Stack¶
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | React + TypeScript + Tailwind CSS | User interface |
| API | Azure Functions (Node.js) | Backend REST API |
| Database | Azure SQL Database | Data storage |
| Auth | Microsoft Entra ID (Azure AD B2C) + MSAL | Authentication |
| Hosting | Azure Static Web Apps | Frontend + API hosting |
| Data Pipeline | Apache Airflow | Nightly Cin7 → SQL sync |
| Source Control | GitHub | Code repository |
Data Flow¶
Nightly Sync (Cin7 → Database)¶
- Airflow DAG triggers at scheduled time
- Extracts PO data from Cin7 via SP-API
- Transforms and loads into Azure SQL using MERGE upsert
- Only updates Cin7-sourced columns — preserves app-owned columns (vendor replies, status, etc.)
User Interactions (Browser → API → Database)¶
- User authenticates via MSAL → receives JWT token
- Frontend sends API requests with JWT in
X-User-Tokenheader - API validates token, extracts user role and vendor code
- API executes SQL queries with role-based filtering
- Response returned to frontend for rendering
Key Design Decisions¶
Dual-Column Pattern¶
Each editable field has two columns: the original Cin7 value and the vendor's reply value. Example: xfd (original) and vendor_reply_xfd (vendor edit). This preserves the source of truth while tracking changes.
State Machine Engine¶
All status transitions go through a single executeTransition() function that validates against the Ref_PO_Transitions table. This ensures no invalid status changes can occur.
Role-Based Access Control¶
Three roles (Vendor, PO_Manager, Admin) with hierarchy: Admin > PO_Manager > Vendor. Vendors are scoped to their own company's POs via billing_company filtering.