Engineering Specification — PavingOS
Version: MVP v1 (Authoritative)
Focus: Field reliability (offline), financial correctness, scalable estimating logic
1. Product & Architectural Goals
Primary Product Goals
Opinionated estimating built for paving (templates → assemblies → estimates).
Zero-reentry workflow: Estimate → Job → Actuals → Invoice.
Continuous feedback loop from job actuals back to estimating insights.
Foreman-first execution experience with minimal friction.
Day-1 Non-Negotiables
Minimum viable offline support for foremen:
View assigned jobs
Start / complete job
Log labor hours
Add notes
Capture photos
Sync later without data loss
Financial correctness
No floating-point currency math
Deterministic, auditable calculations
Multi-tenant, secure-by-default
Row Level Security everywhere
Strong auditability for financial actions
2. System Architecture
High-Level Stack
Frontend & API: Next.js (App Router) deployed on Vercel
Database: Supabase Postgres
Auth: Supabase Auth (magic link initially)
Storage: Supabase Storage (private buckets)
Offline: Service Worker + IndexedDB (event queue + photo staging)
Integrations: QuickBooks Online (OAuth2 + REST APIs)
Runtime Responsibilities
Vercel Edge
Session handling
Lightweight reads
Middleware (auth, rate limiting)
Vercel Serverless
Job/event ingestion
Estimate → Job transactions
Invoice creation
QBO OAuth + API calls
Supabase
Data integrity, RLS enforcement
Storage signing
Optional realtime subscriptions
3. Offline Strategy (Authoritative)
Philosophy
This is not a full local-first replica.
This is minimum viable offline, optimized for reliability and speed.
Client Behavior
Foreman actions are written first to IndexedDB.
Each action generates a job_event with a UUID client_event_id.
Photos are staged locally until upload succeeds.
Sync runs automatically when connectivity is detected.
Server Behavior
Events are appended idempotently.
Duplicate client_event_ids are ignored.
Derived summaries are recomputed server-side.
Why This Approach
Predictable
Auditable
Easy to reason about
Avoids premature sync-engine complexity
4. Authentication & Foreman PIN Security
Supabase Auth
Email magic link for all users.
Sessions managed server-side (@supabase/ssr).
Foreman PIN Gate (Required)
Field devices are shared. We add a local PIN lock.
Behavior
After initial login, foreman sets a 4–6 digit PIN.
App requires PIN to unlock cached jobs and offline UI.
PIN is required after:
App restart
Inactivity timeout
Ops/Owner can remotely reset or lock PINs.
Data Model
profiles
user_id (pk)
pin_hash text
pin_set_at timestamptz
pin_failed_attempts int
pin_locked_until timestamptz
Notes
PIN ≠ Auth token
PIN protects against casual misuse, not device compromise
IndexedDB encryption may be added later
5. Data Model (Postgres, Multi-Tenant)
Core Tenancy
All tables include org_id.
All access enforced via RLS.
orgs
id uuid pk
name text
timezone text
created_at
profiles
user_id uuid pk
full_name
phone
PIN fields (see above)
org_memberships
org_id
user_id
role enum (owner|ops|estimator|foreman)
status
Unique (org_id, user_id)
6. Financial Modeling (Critical)
Money Rules (Hard Requirements)
All currency stored as integer cents (bigint)
All percentages stored as basis points (int)
Quantities stored as numeric
No floats. Ever.
Estimating
estimate_templates
id
org_id
name
default_markup_bps
notes
archived_at
assemblies
id
org_id
template_id
name
kind (labor|equipment|materials|mobilization)
uom
default_qty numeric
default_unit_cost_cents bigint
production_rate numeric null
sort_order
estimates
id
org_id
customer_id
template_id null
status (draft|sent|approved|rejected)
subtotal_cents
markup_bps
total_cents
pricing_snapshot jsonb
job_site jsonb
assumptions text
created_by
estimate_line_items
id
estimate_id
assembly_id null
name
kind
qty numeric
unit_cost_cents
unit_price_cents
line_total_cents
sort_order
7. Jobs & Field Execution
jobs
id
org_id
estimate_id
status (ready|in_progress|completed|invoiced)
scheduled_date date
job_site jsonb
scope_snapshot jsonb
created_at
Event Log (Append-Only)
job_events
id uuid pk
org_id
job_id
client_event_id uuid
type enum
start
complete
note
labor_hours
equipment_usage
photo_add
photo_remove
adjustment
payload jsonb
created_by
device_ts
created_at
Unique (org_id, client_event_id)
Derived Data
job_actuals_summary
job_id pk
labor_hours numeric
equipment_hours numeric
notes_count
photos_count
last_event_at
job_variances
job_id pk
estimate_totals_cents jsonb
actual_totals_cents jsonb
variance_cents jsonb
signal enum (ok|warn|bad)
8. Invoicing & QuickBooks
invoices
id
org_id
job_id
status (draft|sent_to_qbo|paid|void)
line_items_snapshot jsonb
total_cents
qbo_invoice_id text
created_at
qbo_connections
org_id pk
realm_id
access_token encrypted
refresh_token encrypted
token_expires_at
scopes
connected_at
9. API Surface (Primary)
Core
POST /api/estimates
POST /api/estimates/:id/approve
POST /api/jobs/:id/events
POST /api/jobs/:id/events/batch
GET /api/jobs/:id
POST /api/invoices/from-job/:jobId
POST /api/invoices/:id/push-to-qbo
Foreman PIN
POST /api/foreman/pin/set
POST /api/foreman/pin/reset
POST /api/foreman/pin/lock
10. Storage
Bucket: job-photos (private)
Path: org/{org_id}/jobs/{job_id}/{uuid}.jpg
Upload via signed URLs
Read via short-TTL signed URLs only
11. Security & Integrity
RLS on every table
Server-derived org_id only
Idempotency enforced at DB level
Audit log for:
Estimate approval
Job completion
Invoice push
PIN resets
Rate limiting on:
Auth
Event ingestion
QBO endpoints
12. Testing & CI
Required Tests
Unit
Pricing math (decimal correctness)
Markup bps logic
Variance signals
Integration
Supabase migrations + RLS policies
Event idempotency
E2E
Estimate → Job
Offline job execution → sync → invoice
CI
Lint
Typecheck
Unit
Integration
E2E
Vercel Preview Deploys per PR
13. Explicit Non-Goals (MVP)
Full local-first replication
Multi-foreman concurrent editing conflict resolution
Automated template mutation
ERP integrations beyond QBO
14. Design & UX Governance
All user-facing functionality MUST comply with the
"PavingOS Design Contract (MVP)".
The Engineering Spec defines system behavior and constraints.
The Design Contract defines interaction rules, friction limits, and experience principles.
In cases of conflict:
Data integrity > UX polish
Field usability > office convenience
Design Contract > ad-hoc UI decisions