Data Model Architecture
Data Model Architecture
Section titled “Data Model Architecture”The foundation of this product. The data model must handle real-world contract complexity — tiered rates, role-based pricing, expense caps, cumulative tracking, and multi-tenant isolation.
Multi-Tenant Foundation
Section titled “Multi-Tenant Foundation”Every entity below lives under an Organization tenant. All queries are scoped by organizationId.
Organization├── id├── name├── slug (subdomain or URL identifier)├── plan (free | starter | professional | enterprise)├── maxUsers├── maxVendors├── settings (JSON — currency, thresholds, notification prefs)├── createdAt└── updatedAtUser├── id├── organizationId → Organization├── email├── name├── role (admin | senior_auditor | auditor | viewer)├── status (active | inactive)├── lastLoginAt├── createdAt└── updatedAtVendor
Section titled “Vendor”Vendor├── id├── organizationId → Organization├── name├── registrationNumber (tax/company registration)├── contactPerson├── email├── phone├── status (active | inactive | suspended)├── industry (legal | consulting | audit | IT | other)├── paymentTerms (net30 | net60 | net90 | other)├── createdAt└── updatedAtContract
Section titled “Contract”A vendor can have multiple contracts (different engagements, different periods).
Contract├── id├── organizationId → Organization├── vendorId → Vendor├── contractReference (internal reference number)├── title ("Legal Services 2026", "IT Support Q1-Q2")├── type (fixed_fee | hourly | retainer | milestone)├── status (draft | active | expired | terminated)├── startDate├── endDate├── totalCeiling (NTE amount for entire contract)├── monthlyCeiling (NTE per month, optional)├── currency├── autoRenew (boolean)├── notes├── createdAt└── updatedAtContract Rate Card
Section titled “Contract Rate Card”This is where most products fail. Rates are NOT simple — you need a rate card model that supports tiered rates, role-based pricing, and time-based escalations.
ContractRateCard├── id├── contractId → Contract├── serviceCategory ("litigation", "advisory", "development")├── roleLevel ("partner", "senior_associate", "junior", "paralegal")├── approvedRate (decimal)├── rateType (hourly | daily | fixed_per_deliverable)├── maxHoursPerMonth (optional)├── maxHoursTotal (optional, lifetime of contract)├── billingIncrement (6min | 15min | 30min | 1hr)├── effectiveFrom├── effectiveTo (supports annual rate escalations)└── notesWhat This Handles
Section titled “What This Handles”- Different rates per seniority level
- Different rates per service type
- Rate changes over time (annual escalations)
- Billing increment rules (law firms bill in 6-minute increments)
- Hour caps per period and lifetime
Contract Expense Rules
Section titled “Contract Expense Rules”Separate from service rates. Controls what expenses a vendor can claim and at what limits.
ContractExpenseRule├── id├── contractId → Contract├── expenseCategory ("travel", "printing", "courier", "software")├── allowed (boolean)├── maxPerInstance (optional)├── maxPerMonth (optional)├── maxTotal (optional)├── requiresPreApproval (boolean)├── markupAllowed (boolean)├── maxMarkupPercent (optional)└── notesReal-World Example
Section titled “Real-World Example”A law firm contract might specify:
- Travel expenses allowed up to R5,000/month, no markup
- Printing at cost, max R500/month
- All travel requires pre-approval
- Software licenses not claimable
Invoice
Section titled “Invoice”Multi-line item support is non-negotiable. Real invoices have dozens of line items.
Invoice├── id├── organizationId → Organization├── vendorId → Vendor├── contractId → Contract├── invoiceNumber (vendor's reference)├── invoiceDate├── receivedDate├── periodStart (billing period)├── periodEnd├── subtotal├── tax├── totalAmount├── currency├── status (pending | under_review | approved | rejected | queried | paid)├── submittedBy├── reviewedBy├── reviewedAt├── notes├── attachments (JSON array — file references)├── createdAt└── updatedAtInvoiceLineItem├── id├── invoiceId → Invoice├── lineNumber├── description├── serviceCategory├── roleLevel├── quantity (hours, days, units)├── rate├── amount (quantity x rate)├── itemType (service | expense | disbursement)├── expenseCategory (if itemType = expense)├── date (date service was rendered)└── notesValidation Findings
Section titled “Validation Findings”Each validation check produces a finding. Findings are the audit trail of what the engine detected.
ValidationFinding├── id├── invoiceId → Invoice├── lineItemId → InvoiceLineItem (nullable — some findings are invoice-level)├── ruleType (see Rule Types below)├── severity (low | medium | high | critical)├── expectedValue├── actualValue├── variance (amount of discrepancy)├── description (human-readable explanation)├── status (open | acknowledged | resolved | waived)├── resolvedBy├── resolvedAt├── resolution (explanation of how it was resolved)└── createdAtRule Types
Section titled “Rule Types”| Rule Type | Description |
|---|---|
rate_mismatch | Billed rate differs from approved rate card |
hours_exceeded_monthly | Hours exceed monthly cap for role/service |
hours_exceeded_total | Hours exceed lifetime cap for contract |
monthly_ceiling_breach | Total billing exceeds monthly NTE |
contract_ceiling_breach | Cumulative billing exceeds contract NTE |
expense_exceeded | Expense exceeds category cap |
unapproved_service | Service category not in contract |
unapproved_expense | Expense category not allowed |
duplicate_charge | Matches a previous invoice line item |
duplicate_invoice | Invoice number already submitted |
billing_increment_violation | Hours not billed in correct increments |
expired_contract | Invoice references an expired contract |
markup_violation | Expense markup exceeds allowed percentage |
arithmetic_error | Line item math doesn’t add up |
date_anomaly | Service dates outside billing period or on weekends |
pre_approval_missing | Expense requires pre-approval, none documented |
Contract Usage Summary
Section titled “Contract Usage Summary”Materialized/cached view for cumulative tracking. Powers both the validation engine and the dashboard.
ContractUsageSummary├── contractId → Contract├── period (month — e.g., "2026-03")├── totalBilled├── totalHoursByRole (JSON: {"partner": 45, "senior": 120})├── totalExpenses├── cumulativeBilledToDate├── cumulativeHoursToDate├── remainingCeiling└── lastUpdatedRecalculate after every invoice is processed.
Audit Log
Section titled “Audit Log”Immutable log of every action. Critical for compliance.
AuditLog├── id├── organizationId → Organization├── entityType (invoice | contract | vendor | finding)├── entityId├── action (created | updated | approved | rejected | queried | resolved | waived)├── performedBy → User├── previousState (JSON snapshot)├── newState (JSON snapshot)├── reason (optional — required for waivers and rejections)├── ipAddress└── timestampEntity Relationship Summary
Section titled “Entity Relationship Summary”Organization ├── Users (many) ├── Vendors (many) │ └── Contracts (many) │ ├── RateCards (many) │ ├── ExpenseRules (many) │ ├── UsageSummaries (many, per period) │ └── Invoices (many) │ ├── LineItems (many) │ └── Findings (many) └── AuditLog (many)