Technical Architecture
Technical Architecture
Section titled “Technical Architecture”Tech Stack (Recommended)
Section titled “Tech Stack (Recommended)”┌──────────────────┐ ┌───────────────────┐ ┌──────────────┐│ Next.js 14 │────▶│ Express API │────▶│ PostgreSQL ││ (Frontend) │◀────│ (Backend) │◀────│ ││ App Router │ │ TypeScript/ESM │ └──────────────┘│ Tailwind CSS │ └────────┬──────────┘│ shadcn/ui │ │└──────────────────┘ ┌────────┴──────────┐ │ Redis + BullMQ │ │ (cache + jobs) │ └───────────────────┘Frontend — Next.js 14
Section titled “Frontend — Next.js 14”- App Router with server components for dashboard performance
- Tailwind CSS + shadcn/ui for consistent, professional UI
- React Query (TanStack Query) for API state management
- Recharts or Chart.js for dashboard visualizations
- React Table (TanStack Table) for sortable/filterable invoice lists
- React Hook Form + Zod for form validation
Backend — Express + TypeScript
Section titled “Backend — Express + TypeScript”- Express.js with TypeScript (ESM modules)
- Prisma ORM with PostgreSQL
- Zod for request validation
- JWT authentication with refresh tokens
- Role-based middleware for access control
Database — PostgreSQL
Section titled “Database — PostgreSQL”- Primary data store for all entities
- JSON columns for flexible fields (settings, attachments, metadata)
- Indexed for common query patterns (vendor lookups, date ranges, status filters)
Background Processing — Redis + BullMQ
Section titled “Background Processing — Redis + BullMQ”- Validation engine runs as background job for large invoices
- Report generation (PDF export) runs async
- Email notifications queued and sent in background
- Usage summary recalculation after invoice approval
File Storage
Section titled “File Storage”- S3-compatible storage (AWS S3 or MinIO)
- For invoice attachments, supporting documents, generated reports
PDF Generation
Section titled “PDF Generation”- @react-pdf/renderer or Puppeteer for report PDF export
Multi-Tenant Architecture
Section titled “Multi-Tenant Architecture”Approach: Shared Database, Row-Level Isolation
Section titled “Approach: Shared Database, Row-Level Isolation”All tenants share a single database. Every table includes an organizationId column. All queries are scoped.
Why this approach:
- Simpler to maintain than database-per-tenant
- Lower infrastructure cost for MVP
- Scales well up to ~1,000 tenants
- Can migrate to database-per-tenant later for enterprise clients
Implementation:
- Prisma middleware that automatically adds
organizationIdfilter to every query - API middleware that extracts
organizationIdfrom authenticated user’s JWT - Database-level row security policies as an additional safety layer (optional)
// Prisma middleware exampleprisma.$use(async (params, next) => { // Automatically scope all queries by organization if (params.args.where) { params.args.where.organizationId = currentOrganizationId; } return next(params);});Tenant Onboarding Flow
Section titled “Tenant Onboarding Flow”- Organization created with admin user
- Admin configures:
- Organization settings (currency, thresholds, notifications)
- Users and roles
- Vendors
- Contracts and rate cards
- System ready to process invoices
API Structure
Section titled “API Structure”Base URL Pattern
Section titled “Base URL Pattern”/api/v1/{resource}Endpoints
Section titled “Endpoints”Authentication
POST /api/v1/auth/register (create organization + admin)POST /api/v1/auth/loginPOST /api/v1/auth/refreshPOST /api/v1/auth/forgot-passwordPOST /api/v1/auth/reset-passwordOrganization
GET /api/v1/organizationPUT /api/v1/organizationGET /api/v1/organization/settingsPUT /api/v1/organization/settingsUsers
GET /api/v1/usersPOST /api/v1/usersGET /api/v1/users/:idPUT /api/v1/users/:idDELETE /api/v1/users/:idVendors
GET /api/v1/vendorsPOST /api/v1/vendorsGET /api/v1/vendors/:idPUT /api/v1/vendors/:idDELETE /api/v1/vendors/:idGET /api/v1/vendors/:id/invoicesGET /api/v1/vendors/:id/scorecardContracts
GET /api/v1/contractsPOST /api/v1/contractsGET /api/v1/contracts/:idPUT /api/v1/contracts/:idDELETE /api/v1/contracts/:idGET /api/v1/contracts/:id/rate-cardsPOST /api/v1/contracts/:id/rate-cardsPUT /api/v1/contracts/:id/rate-cards/:rateIdDELETE /api/v1/contracts/:id/rate-cards/:rateIdGET /api/v1/contracts/:id/expense-rulesPOST /api/v1/contracts/:id/expense-rulesPUT /api/v1/contracts/:id/expense-rules/:ruleIdDELETE /api/v1/contracts/:id/expense-rules/:ruleIdGET /api/v1/contracts/:id/utilizationInvoices
GET /api/v1/invoicesPOST /api/v1/invoicesGET /api/v1/invoices/:idPUT /api/v1/invoices/:idDELETE /api/v1/invoices/:idPOST /api/v1/invoices/:id/line-items (batch add)PUT /api/v1/invoices/:id/line-items/:itemIdDELETE /api/v1/invoices/:id/line-items/:itemIdPOST /api/v1/invoices/:id/validate (trigger validation)GET /api/v1/invoices/:id/findingsPOST /api/v1/invoices/:id/approvePOST /api/v1/invoices/:id/rejectPOST /api/v1/invoices/:id/queryGET /api/v1/invoices/:id/queriesPOST /api/v1/invoices/:id/queries/:queryId/respondFindings
GET /api/v1/findings (with filters)PUT /api/v1/findings/:id/acknowledgePUT /api/v1/findings/:id/resolvePUT /api/v1/findings/:id/waive (requires reason)Dashboard & Reports
GET /api/v1/dashboard/summaryGET /api/v1/dashboard/findings-by-typeGET /api/v1/dashboard/top-flagged-vendorsGET /api/v1/dashboard/savingsGET /api/v1/dashboard/trendsGET /api/v1/reports/monthly/:year/:monthGET /api/v1/reports/vendor-scorecard/:vendorIdPOST /api/v1/reports/export (generates PDF)Audit Trail
GET /api/v1/audit-log (with filters)Security Considerations
Section titled “Security Considerations”Authentication
Section titled “Authentication”- JWT with short-lived access tokens (15 min) and refresh tokens (7 days)
- Refresh token rotation (new refresh token on each use)
- Password hashing with bcrypt (cost factor 12)
Authorization
Section titled “Authorization”- Role-based access control enforced at API middleware level
- Approval thresholds enforced server-side (never trust client)
- Dual sign-off logic enforced server-side
Data Protection
Section titled “Data Protection”- All API communication over HTTPS
- Sensitive fields encrypted at rest (optional, for enterprise tier)
- Audit log is append-only (no updates, no deletes)
- Database backups (daily, retained 30 days minimum)
Multi-Tenant Security
Section titled “Multi-Tenant Security”- Organization ID extracted from JWT, never from client request
- Prisma middleware enforces tenant isolation on every query
- API tests verify tenant isolation (user from org A cannot access org B data)
MVP Build Phases
Section titled “MVP Build Phases”| Phase | Scope | Details |
|---|---|---|
| Phase 1 | Foundation | Project setup, Prisma schema, database, auth, multi-tenant middleware |
| Phase 2 | Vendor & Contracts | CRUD for vendors, contracts, rate cards, expense rules (API + UI) |
| Phase 3 | Invoice Capture | Invoice and line item CRUD, manual entry forms, CSV upload |
| Phase 4 | Validation Engine | All 14 checks, finding generation, risk scoring |
| Phase 5 | Review Workflow | Finding display, approve/reject/query flow, audit trail |
| Phase 6 | Dashboard | Executive dashboard, contract utilization, charts |
| Phase 7 | Reporting | Monthly report generation, PDF export, savings tracking |
| Phase 8 | Polish & Testing | E2E tests, tenant isolation tests, UI polish, performance |
Key Decisions (To Be Finalized)
Section titled “Key Decisions (To Be Finalized)”| # | Decision | Options | Status |
|---|---|---|---|
| 1 | Multi-tenant approach | Shared DB with row isolation (recommended) vs DB per tenant | Decided: Shared DB |
| 2 | Invoice input method (MVP) | Manual form only vs Manual + CSV upload vs Manual + CSV + PDF upload | Pending |
| 3 | Notification delivery | In-app only vs In-app + email | Pending |
| 4 | Vendor portal | No portal (email only) vs Basic portal for query responses | Pending |
| 5 | Currency support | Single currency (ZAR) vs Multi-currency | Pending |
| 6 | Hosting | Self-hosted VPS vs AWS/GCP vs Vercel + managed DB | Pending |
| 7 | Pricing model | Per-user vs Per-invoice volume vs Flat tiers | Pending |
| 8 | Domain / branding | Product name, domain | Pending |
Infrastructure (Production)
Section titled “Infrastructure (Production)”Recommended Setup (Cost-Effective)
Section titled “Recommended Setup (Cost-Effective)”┌─────────────────────────────────────────┐│ Vercel (Frontend) ││ - Next.js deployment ││ - Edge functions for auth ││ - CDN for static assets │├─────────────────────────────────────────┤│ Railway / Render (Backend) ││ - Express API ││ - Auto-scaling ││ - Managed Redis │├─────────────────────────────────────────┤│ Supabase / Neon (Database) ││ - Managed PostgreSQL ││ - Automated backups ││ - Connection pooling │├─────────────────────────────────────────┤│ AWS S3 (File Storage) ││ - Invoice attachments ││ - Generated reports │├─────────────────────────────────────────┤│ Resend / SendGrid (Email) ││ - Transactional emails ││ - Notification delivery │└─────────────────────────────────────────┘Alternative: Self-Hosted (Lower Cost, More Control)
Section titled “Alternative: Self-Hosted (Lower Cost, More Control)”- VPS (Hetzner / DigitalOcean) with Docker Compose
- Nginx reverse proxy
- PostgreSQL + Redis on same server (small scale)
- MinIO for S3-compatible storage