> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pcnaid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture Overview

> TexasVerified components, data boundaries, deployment shape, portals, and inventory rules.

# Architecture Overview

## Application shape

* **`apps/web`:** Next.js App Router application with marketing, member, auditor, administrator, public-certificate, and API routes. It is deployed to Cloudflare Workers with a configured fallback deployment path.
* **`packages/shared`:** shared domain types, tier and compliance rules, and helpers.
* **`packages/integrations`:** adapters for government data, document analysis, notifications, e-signature, and analytics.
* **Workers:** separate intake, OCR/notification consumer, scheduled sync, compliance-resource mirror, chat, and Wallet processes.
* **`infra/db/migrations`:** the PostgreSQL schema, row-level-security rules, views, and application functions.

The web worker binds R2 storage, OCR and notification queues, KV namespaces, a Durable Object namespace, a pooled PostgreSQL connection, and service bindings to the supporting workers. The intake worker persists inbound files and queues OCR; the pipeline consumer reads the stored object, performs processing, and records review-needed outcomes when confidence is insufficient.

## Three portals

TexasVerified has three strictly separate portals fanned out by server-resolved role:

| Portal | Audience | Entry |
| - | - | - |
| **Member portal** | Retailer organizations (owners/staff) | Main app login → `/dashboard` |
| **Auditor portal** | Government users plus named pilots | `/audit` (standalone) |
| **Staff/admin portal** | Pcnaid staff | `/admin` |

Role routing: `admin` → `/admin`, `auditor` → `/audit`, everyone else → retailer `/dashboard` (org-less accounts go to `/onboarding`).

## Authentication and tenancy

Interactive authentication uses Auth0 sessions. The session resolver reads role, organization, and location claims, then resolves the database user and memberships when the database is configured. Unauthenticated pages redirect to the Auth0 login entry point; API routes using `requireApiUser` return HTTP 401 instead.

Native mobile-capable routes accept an Auth0 API access token in `Authorization: Bearer`. The web Worker verifies its RS256 signature, issuer, audience, and lifetime before resolving the database-backed principal.

Roles in the database schema are `retailer_owner`, `retailer_staff`, `supplier`, `auditor`, and `admin`. Retailer pages require an organization; auditor-only users are routed to a standalone auditor console, and administrators are routed to the staff console.

PostgreSQL is the source of truth for tenant data. Core records include organizations, users and memberships, locations, drives and stored objects, OCR jobs, products and lots, COAs, permits, access requests, certificates, public-page settings, and billing records. Tenant tables enable row-level security, and the runtime query layer sets user, organization, and role context for database work.

## Location-first compliance model

Compliance, verification progress, certificates, and catalog data are location tabs rather than organization-wide summaries. This matches the data model: permits, evidence, inventory, certificate records, and auditor grants attach to a location.

Public verification has two implemented surfaces: a public member page at `/m/[certificateNumber]` and a public lookup route at `/api/verify/[certificateNumber]`. Private document access remains session- and authorization-scoped.

## Core flows

### Upload → Drive → OCR

1. A portal upload, email attachment, or MMS media object is hashed.
2. R2 key is content-addressed as `objects/sha256/<prefix>/<hash>`, so identical bytes reuse the same object.
3. `drive_items` links the object into the relevant Drive section.
4. Invoice, receipt, and COA sections enqueue OCR.
5. The pipeline consumer fetches the R2 object and calls Azure Document Intelligence, writes `ocr_jobs.extracted_json`, creates receiving records and invoice line items, and matches products.
6. COAs feed extracted text into lab result tables and open a review row to link the certificate to a product.

### Government status sync

The cron worker discovers DSHS rosters and Comptroller permit data. Status changes enqueue notification messages. TX Comptroller sales-and-use permits do not expire; DSHS retail-hemp registrations expire and are checked for current status.

### Auditor access and compliance review

Auditors request access via certificate number, URL, or QR code scan. Retailer owners approve or decline. Active grants open Compliance Tasks — a bilateral workspace with deadlines, checklists, threaded comments, and Drive-backed documents. RLS enforces scoped access: only the grant auditor and retailer participants see the task.

### Web ↔ iOS sync (push, not poll)

After every committed write, `app.note_org_change` appends affected org ids. The realtime worker's `OrgEvents` Durable Object sends a signal to open WebSocket connections, which trigger re-reads through normal authenticated paths.

## Offline master-inventory importer

A local verification importer runs against an offline Airtable snapshot. Its CLI accepts only `import` or `reconcile` plus `--snapshot <path>`. Before connecting it requires the explicit local-import guard, a loopback PostgreSQL host, and a dedicated local verification database.

The importer validates the snapshot, refuses an unsupported non-empty COA destination before opening a transaction, validates the manufacturer seam, upserts brands, plans product identities, writes products in one transaction under an advisory lock, and then reconciles the database against the source classification.

### Quarantine never folds into a merge

A non-blank GTIN is the primary product identity. Without a GTIN, the generated fallback uses the resolved brand ID, exact product name, and size. A legitimately brandless item has a known empty-brand component and still participates in collision detection.

If snapshot rows share an identity, or an incoming row collides with a different existing row, the importer assigns a specific quarantine reason. It does not merge the records. A GTIN-less row that links to a brand missing from the database has an indeterminate fallback identity: collision, identity, and quarantine comparisons that require that missing input are suppressed, while independently knowable damage remains reportable.

Reconciliation derives product metrics from one classification and exits non-zero when a hard mismatch remains. The test suite includes damaged states, combined failure dimensions, brandless duplicates, missing linked brands, identity mismatches, and quarantine false positives, misses, and reason mismatches. A successful run therefore represents both healthy-data correctness and visibility of tested damage.

> [!WARNING]
>
> The importer is not a production Airtable synchronization service. Manufacturer import and non-empty COA persistence are explicit unimplemented seams that fail instead of guessing a mapping or provenance key.

## Apple Wallet

Wallet passes mirror the live certificate with member number, retail location, verification level, status, COA coverage, and push updates on status change. The wallet worker returns HTTP 501 until real PassKit material is configured. Owners may customize pass layout and palette from Settings.

## Build and deployment

Root build orchestration uses Turbo:

```bash theme={null}
npm run build:packages
npm run typecheck
npm run build
```

Runtime deployment requires separately configured Auth0, PostgreSQL (with connection pooling), R2, queues, KV, Durable Objects, service bindings, and whichever external integrations are enabled.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.