# Architecture Decision Records — 360lm

This directory captures architectural decisions for the 360lm platform (hub + all PWAs).

**Template:** `ADR-template.md`  
**Tool:** [adr-kit](https://github.com/rvdbreemen/adr-kit) (skills + agent installed in `.claude/`)  
**Agent:** `/adr-generator` — drafts a complete ADR from your inputs  
**Skill:** `/adr` — reference guide for ADR conventions  

## How to create an ADR

1. Run `/adr-generator` (or ask Claude to "create an ADR for...")
2. Provide: title, decision, context, 2+ alternatives, consequences
3. Agent writes `ADR-NNN-title.md` and updates this index
4. Review against the 4 gates (Completeness, Evidence, Clarity, Consistency)
5. Update Status to `Accepted` once gates pass

## Status legend

| Status | Meaning |
|---|---|
| Proposed | Under discussion, not yet in force |
| Accepted | Decision is in force — follow it |
| Superseded | Replaced by a newer ADR (link shown) |
| Deprecated | No longer applies, kept for history |

## Index

<!-- Add one line per ADR: ADR-NNN | Status | Title | Date -->

| ADR | Status | Title | Date |
|---|---|---|---|
| [ADR-001](ADR-001-hub-next-redirect-on-login.md) | Accepted | All PWAs Pass ?next= When Redirecting to Hub Login | 2026-06-25 |
| [ADR-002](ADR-002-safe-bottom-css-mandatory.md) | Accepted | Every PWA Must Link shared/safe-bottom.css | 2026-06-25 |
| [ADR-003](ADR-003-mobile-scroll-root-document.md) | Accepted | Long Lists Must Scroll the Root Document, Not a Nested Container | 2026-06-25 |
| [ADR-004](ADR-004-maps-google-primary-tomtom-fallback.md) | Accepted | Maps Strategy — Google Primary, TomTom for Traffic/Matrix/Truck + Auto-Failover | 2026-06-25 |
| [ADR-005](ADR-005-sw-cache-ver-string-bump.md) | Accepted | SW Cache Busting via CACHE_VER String, Not skipWaiting() | 2026-06-25 |
| [ADR-006](ADR-006-verify-pin-returns-table-array.md) | Accepted | verify_pin RPC Returns a TABLE Array, Not a Success Boolean | 2026-06-25 |
| [ADR-007](ADR-007-pg-trigger-security-definer.md) | Accepted | Trigger Functions Writing Privileged Tables Must Use SECURITY DEFINER | 2026-06-25 |
| [ADR-008](ADR-008-plpgsql-variable-conflict-use-column.md) | Accepted | PL/pgSQL RETURNS TABLE Functions Must Declare #variable_conflict use_column | 2026-06-25 |
| [ADR-009](ADR-009-each-pwa-owns-its-db-schema.md) | Accepted | Each PWA Owns a Dedicated PostgreSQL Schema | 2026-06-25 |
| [ADR-010](ADR-010-cross-schema-data-via-proxy-not-postgrest.md) | Accepted | Cross-Schema Data Access Goes Through the Proxy, Not PostgREST Directly | 2026-06-25 |
| [ADR-011](ADR-011-pin-based-auth-no-passwords.md) | Accepted | Employee Authentication Uses PIN, Not Passwords or OAuth | 2026-06-25 |
| [ADR-012](ADR-012-hub-as-sso-gateway.md) | Accepted | Hub PWA Is the Single SSO Gateway for All Employee-Facing PWAs | 2026-06-25 |
| [ADR-013](ADR-013-single-html-file-no-framework.md) | Accepted | Each PWA Is a Single Self-Contained HTML File — No Framework, No Build Pipeline | 2026-06-25 |
| [ADR-014](ADR-014-postgrest-as-api-layer.md) | Accepted | PostgREST Is the API Layer — No Custom REST Framework | 2026-06-25 |
| [ADR-015](ADR-015-dev-prod-two-stacks-same-vps.md) | Accepted | Dev and Prod Are Two Full Stacks on the Same VPS, Not Branches or Feature Flags | 2026-06-25 |
| [ADR-016](ADR-016-new-pwa-must-register-in-hub-registry.md) | Accepted | Every New PWA Must Register in hub.pwa_registry | 2026-06-25 |
| [ADR-017](ADR-017-traefik-docker-labels-for-routing.md) | Accepted | All Service Routing Uses Traefik + Docker Labels — No Nginx Config Files | 2026-06-25 |
| [ADR-018](ADR-018-client-auth-company-code-not-pin.md) | Accepted | External Client Authentication Uses Company Code + Access Code, Not Employee PIN | 2026-06-25 |
| [ADR-019](ADR-019-ocr-client-side-for-docs-server-side-for-photos.md) | Accepted | OCR Strategy — Client-Side Tesseract for Identity Docs, Server-Side Proxy for Bill Photos | 2026-06-25 |
| [ADR-020](ADR-020-offline-first-indexeddb-primary.md) | Accepted | Field PWAs Are Offline-First — IndexedDB Primary, Server Sync Secondary | 2026-06-25 |
| [ADR-021](ADR-021-sw-cache-first-network-fallback.md) | Accepted | Service Worker Uses Cache-First Strategy with Network Fallback | 2026-06-25 |
| [ADR-022](ADR-022-playwright-for-e2e-testing.md) | Accepted | Playwright Is the E2E Test Framework — One Spec File Per PWA | 2026-06-25 |
| [ADR-023](ADR-023-push-notifications-self-hosted-vapid.md) | Accepted | Push Notifications Use Self-Hosted VAPID Server, Not FCM or Third-Party | 2026-06-25 |
| [ADR-024](ADR-024-google-slides-via-gas-proxy.md) | Accepted | Google Slides/Sheets Integration Uses Google Apps Script via Self-Hosted Proxy | 2026-06-25 |
| [ADR-025](ADR-025-self-hosted-ollama-for-ai-inference.md) | Accepted | Self-Hosted Ollama Runs Alongside Cloud AI for Vision and Text Inference | 2026-06-25 |
| [ADR-026](ADR-026-cross-pwa-session-bridge-via-localstorage.md) | Accepted | Cross-PWA Session Handoff Uses Shared localStorage on Same Origin | 2026-06-25 |
| [ADR-027](ADR-027-leave-one-out-faceted-filtering.md) | Accepted | Multi-Dimension List Filtering Uses Leave-One-Out Faceted Availability | 2026-06-25 |
| [ADR-028](ADR-028-feature-ownership-follows-domain.md) | Accepted | Feature Ownership Follows Domain — Hub Is Navigation-Only | 2026-06-22 |
| [ADR-029](ADR-029-dual-write-offline-access-control.md) | Accepted | Employee Access Control Is Dual-Written to DB and hub-access.json | 2026-06-22 |
| [ADR-030](ADR-030-no-select-over-5-options.md) | Accepted | No &lt;select&gt; for More Than 5 Options — Use Searchable Type-Ahead or Chip-Grid | 2026-06-22 |
| [ADR-031](ADR-031-fullscreen-forms-not-modals.md) | Accepted | Complex Forms Use Full-Screen Overlays — Modals Only for Simple Confirmations | 2026-06-22 |
| [ADR-032](ADR-032-expense-employees-cross-schema-fk-anchor.md) | Accepted | expense.employees Is the Canonical Employee Identity Table — Cross-Schema FK Anchor | 2026-06-22 |
| [ADR-033](ADR-033-approval-rpc-atomic-impress-deduction.md) | Accepted | Expense Approval RPC Atomically Deducts Impress in One DB Transaction | 2026-06-22 |
| [ADR-034](ADR-034-hr-salary-cross-writes-finance-transactions.md) | Accepted | HR Salary Payment RPC Cross-Writes to finance.transactions | 2026-06-22 |
| [ADR-035](ADR-035-screenshot-deterrence-not-enforcement.md) | Accepted | Screenshot Protection Uses CSS/JS Deterrence — OS-Level Enforcement Not Available | 2026-06-22 |
| [ADR-036](ADR-036-custodian-payees-shared-cross-pwa.md) | Accepted | custodian.payees Is the Shared Payee Master Across All Payment-Facing PWAs | 2026-06-22 |
| [ADR-037](ADR-037-transaction-lines-soft-polymorphic-fk.md) | Accepted | transaction_lines Uses Soft Polymorphism — source_id Has No FK Constraint | 2026-06-22 |
| [ADR-038](ADR-038-capture-to-catalog-trigger.md) | Accepted | Vendor Catalog Is Auto-Populated by Trigger on Transaction Line Capture | 2026-06-22 |
| [ADR-039](ADR-039-two-mode-reactivation-custodian.md) | Accepted | Custodian Reactivation Offers Limited (Settlement-Only) and Full Mode | 2026-06-22 |
| [ADR-040](ADR-040-cross-schema-active-state-sync-trigger.md) | Accepted | Cross-Schema Active-State Sync Uses SECURITY DEFINER Trigger, Not Dual-Write | 2026-06-22 |
| [ADR-041](ADR-041-supersede-not-delete-for-engaged-recce.md) | Accepted | Replacing an Engaged Official Recce Record Uses Supersede Flow, Not Update-in-Place | 2026-06-22 |
| [ADR-042](ADR-042-rate-card-comparison-latest-not-lowest.md) | Accepted | Vendor Rate Card Comparison Baseline Is Latest by created_at, Not Lowest Price | 2026-06-22 |
| [ADR-043](ADR-043-sales-catalog-shared-product-master.md) | Accepted | sales.catalog Is the Shared Product Master — Vendor Management Links to It | 2026-06-22 |
| [ADR-044](ADR-044-finance-mini-pwa-family-not-monolith.md) | Accepted | Finance Is Implemented as a Family of Focused Mini-PWAs, Not a Monolith | 2026-06-22 |
| [ADR-045](ADR-045-edit-delete-via-approval-queue-or-admin-direct.md) | Accepted | Transaction Edit/Delete Uses Approval Queue for Non-Admins, Direct Apply for Admins | 2026-06-22 |
| [ADR-046](ADR-046-installation-campaigns-canonical-job-record.md) | Superseded | installation.campaigns Is the Canonical Job Record — sales.jobs Is Downstream | 2026-06-22 |
| [ADR-047](ADR-047-recce-client-visibility-per-brand-filter.md) | Accepted | Recce Client Visibility Is Filtered Per-Brand, Not Per-Counter | 2026-06-22 |
| [ADR-048](ADR-048-external-client-magic-link-not-hub-pin.md) | Accepted | External Client Portal Uses Email Magic-Link Auth — Not Hub PIN | 2026-06-22 |
| [ADR-049](ADR-049-recce-view-files-via-hmac-signed-proxy.md) | Accepted | Recce View Files Are Served via HMAC-Signed Proxy — Not Direct Traefik Serve | 2026-06-22 |
| [ADR-050](ADR-050-client-auth-tables-rpc-only-no-direct-grants.md) | Accepted | Client Auth Tables Have No Direct web_anon Grants — RPC-Only Access | 2026-06-22 |
| [ADR-051](ADR-051-learning-completion-threshold-based.md) | Accepted | Learning Completion Is Threshold-Based — 100% Scenes or 80% Watch Time (Scrub-Proof) | 2026-06-22 |
| [ADR-052](ADR-052-view-tracking-two-rpc-beacon.md) | Accepted | Learning View Tracking Uses Two-RPC Beacon (start_view / end_view) — Not Single Write | 2026-06-22 |
| [ADR-053](ADR-053-counter-brand-data-on-recce-submissions.md) | Accepted | Per-Brand Counter Data Lives on recce.submissions — Not on counters.counter | 2026-06-22 |
| [ADR-054](ADR-054-counter-sync-rpc-with-stores-json-fallback.md) | Accepted | Counter Sync Prefers my_visible_counters RPC, Falls Back to stores.json with Visible Warning | 2026-06-22 |
| [ADR-055](ADR-055-mail-outbox-external-poller-not-inline-smtp.md) | Accepted | Transactional Email Uses mail_outbox Table + External Poller — Not Inline SMTP | 2026-06-22 |
| [ADR-056](ADR-056-ai-handoff-via-prompt-not-live-api.md) | Accepted | AI-Assisted Features Use Prompt Copy-Paste Hand-Off — Not Live API Integration | 2026-06-22 |
| [ADR-057](ADR-057-statement-close-gated-on-zero-unmatched.md) | Accepted | Reconciliation Statement Cannot Be Closed Until All Lines Are Matched | 2026-06-22 |
| [ADR-058](ADR-058-cc-transactions-via-cross-schema-view-only.md) | Accepted | Credit Card PWA Reads vehicle.cc_transactions via View — Zero Writes to Vehicle Schema | 2026-06-22 |
| [ADR-059](ADR-059-tour-ai-dedicated-sidecar-proxy.md) | Accepted | Tour Planner AI Uses a Dedicated Sidecar Proxy — Not the Shared AI Finance Proxy | 2026-06-22 |
| [ADR-060](ADR-060-prod-deploy-rsync-allowlist-not-full-checkout.md) | Accepted | Production Promotion Uses rsync Allowlist — Not Full Git Checkout | 2026-06-22 |
| [ADR-061](ADR-061-dual-mode-lazy-search-eager-dashboard.md) | Accepted | Dual-Mode Search: Lazy Proxy Search + Eager Client-Side Dashboard for Bounded Datasets | 2026-06-25 |
| [ADR-062](ADR-062-live-ai-pipeline-contract.md) | Accepted | Live AI Pipeline Contract — Auth Chain, Fallback Order, Human-Review Gate, 503 Handling | 2026-06-25 |
| [ADR-063](ADR-063-ai-dev-toolchain.md) | Accepted | AI-Assisted Development Toolchain | 2026-06-26 |
| [ADR-064](ADR-064-video-tutorial-production-pipeline.md) | Accepted | Video Tutorial Production Pipeline — scripts.json → edge-tts → Playwright → ffmpeg | 2026-06-26 |
| [ADR-065](ADR-065-scene-guide-format.md) | Accepted | Scene Guide Tutorial Format — JSON Data Contract + Player | 2026-06-26 |
| [ADR-066](ADR-066-parallel-cli-session-coordination.md) | Accepted | Parallel CLI Session Coordination with Conflict Zone Locking | 2026-06-27 |
| [ADR-067](ADR-067-cross-pwa-change-safety-gate.md) | Accepted | Cross-PWA Change Safety Gate — Explicit Confirmation Before Shared Infrastructure Changes | 2026-06-27 |
| [ADR-068](ADR-068-vcc-pre-build-safety-checklist.md) | Accepted | VCC Pre-Build Safety Checklist — Mandatory Bug Prevention Standard | 2026-06-27 |
| [ADR-069](ADR-069-production-hotfix-protocol.md) | Accepted | Production Hotfix Protocol — Bugfix DB Template, Dev-Branch Fix, Deploy via Master | 2026-06-27 |
| [ADR-070](ADR-070-ist-timezone-enforcement.md) | Accepted | All User-Facing Timestamps Displayed in IST (UTC+5:30) | 2026-06-27 |
| [ADR-071](ADR-071-indian-number-formatting.md) | Accepted | Indian Number Formatting for All Monetary Amount Inputs | 2026-06-27 |
| [ADR-072](ADR-072-proof-image-capture-annotation.md) | Accepted | Proof Image Capture and Annotation Standard — Two-Phase Flow with Canvas Editor | 2026-06-27 |
| [ADR-073](ADR-073-traefik-label-conventions.md) | Accepted | Traefik Docker Label Conventions and Middleware Chaining | 2026-06-27 |
| [ADR-074](ADR-074-postgrest-accept-profile-header.md) | Accepted | PostgREST Multi-Schema Routing via Accept-Profile Header | 2026-06-27 |
| [ADR-075](ADR-075-rpc-error-response-format.md) | Accepted | Unified RPC Error Response Format and Client-Side Error Contract | 2026-06-27 |
| [ADR-076](ADR-076-mobile-first-viewport-standard.md) | Accepted | Mobile-First Viewport and Meta Tag Standard | 2026-06-27 |
| [ADR-077](ADR-077-openclaw-integration-schema-grants.md) | Accepted | OpenClaw Integration — Read-Only DB Role, Schema Grants, and Auth Layers | 2026-06-27 |
| [ADR-078](ADR-078-paperclip-isolation.md) | Accepted | Paperclip AI Platform Isolation — Separate DB Role, Zero lm360 Access, Independent Backups | 2026-06-27 |
| [ADR-079](ADR-079-shared-helper-governance.md) | Accepted | Shared Helper Governance — /shared/ Directory Structure, Adoption Policy, and Breaking Change Protocol | 2026-06-27 |
| [ADR-080](ADR-080-hub-session-registry-cross-schema-sync.md) | Accepted | Hub as Authoritative Session Registry — Cross-Schema Active-State Sync Architecture | 2026-06-27 |
| [ADR-081](ADR-081-safe-area-inset-rendering.md) | Accepted | Safe-Area Inset Rendering for Notched and Rounded-Corner Devices | 2026-06-27 |
| [ADR-082](ADR-082-dark-mode-theming-architecture.md) | Accepted | Dark Mode and Theming Architecture — Forced Light Mode for ERP PWAs, Dark UI for Standalone Apps | 2026-06-27 |
| [ADR-083](ADR-083-form-validation-strategy.md) | Accepted | Form Validation Strategy — Client-Side Feedback, Server-Side Enforcement | 2026-06-27 |
| [ADR-084](ADR-084-list-pagination-infinite-scroll.md) | Accepted | List Pagination and Infinite Scroll — When to Use Each, PostgREST Range Header Pattern | 2026-06-27 |
| [ADR-085](ADR-085-file-upload-patterns.md) | Accepted | File Upload Patterns — CSV Import, PDF Export, and Bulk Data Handling | 2026-06-27 |
| [ADR-086](ADR-086-isolated-pwa-architecture.md) | Accepted | Isolated PWA Architecture — When to Build Standalone Apps with Zero Cross-Access | 2026-06-27 |
| [ADR-087](ADR-087-push-notification-implementation-contract.md) | Accepted | Push Notification Implementation Contract — SW Handler, Subscription Payload, and Notification Format | 2026-06-27 |
| [ADR-088](ADR-088-indexeddb-schema-versioning.md) | Accepted | IndexedDB Schema Versioning and Safe Upgrade Protocol | 2026-06-27 |
| [ADR-089](ADR-089-bilingual-platform-architecture.md) | Accepted | Bilingual EN/HI Platform Architecture — DB-Backed Language Preference, t() Helper, and Adoption Checklist | 2026-06-27 |
| [ADR-090](ADR-090-font-size-accessibility-preference.md) | Accepted | Font Size Accessibility Preference — 5-Level Scaling, localStorage Persistence, Init-Time Application | 2026-06-27 |
| [ADR-091](ADR-091-inapp-tour-engine-contract.md) | Accepted | In-App Onboarding Tour Engine Contract — shared/tour.js Usage, Step Shape, and Dismissal Protocol | 2026-06-27 |
| [ADR-092](ADR-092-user-preference-cascading-fallback.md) | Proposed | User Preference Cascading Fallback — DB → localStorage → Hardcoded Default | 2026-06-27 |
| [ADR-093](ADR-093-zero-backend-standalone-pwa.md) | Accepted | Zero-Backend Standalone PWA — localStorage-Only State with Client-Side PIN Guard | 2026-06-29 |
| [ADR-094](ADR-094-google-oauth-token-lifecycle.md) | Accepted | Google OAuth Token Lifecycle — In-Memory Only, Email Hint Persisted for Silent Re-Auth | 2026-06-29 |
| [ADR-095](ADR-095-btl-addin-client-deck-contract.md) | Accepted | BTL Client Deck Contract — PowerPoint Add-in, Tagged Shape Naming, and 3-Path Extraction | 2026-07-01 |
| [ADR-096](ADR-096-excel-approval-form-one-time-tokens.md) | Accepted | Recce Excel Approval Form — One-Time Token Submission + DataValidation | 2026-07-01 |
| [ADR-097](ADR-097-blogsmith-ai-content-pipeline.md) | Accepted | Blogsmith AI Content Pipeline — Standalone PWA, Keyword to Published Article | 2026-07-01 |
| [ADR-098](ADR-098-native-client-branding-approval-flow.md) | Accepted | Native Web Page Is the Primary Client Branding Approval Channel — PPTX/Excel Are Fallbacks | 2026-07-01 |
| [ADR-099](ADR-099-context-efficient-devguide-architecture.md) | Accepted | DevGuide Is an Index + Skill + Topic Files, Not a Monolith | 2026-07-02 |
| [ADR-100](ADR-100-theme-v2-design-token-presets.md) | Accepted | Visual Design via shared/theme-v2.css Token Presets, Outside Ponytail Scope | 2026-07-02 |
| [ADR-101](ADR-101-svg-centric-print-pipeline.md) | Accepted | SVG Is the Working Format for Print Creatives; CorelDRAW Is Fallback Only | 2026-07-02 |
| [ADR-102](ADR-102-modern-cdr-conversion-requires-coreldraw.md) | Accepted | Modern CDR Conversion Must Originate From CorelDRAW; Cloud Only for Legacy | 2026-07-02 |
| [ADR-103](ADR-103-print-bridge-job-folder-contract.md) | Accepted | Print Bridge Runs Over a Syncthing Job Folder With a Self-Updating Watcher | 2026-07-02 |
| [ADR-104](ADR-104-cross-pwa-payment-handoff.md) | Accepted | Cross-PWA Payment Handoff — localStorage Bridge into a Prefilled Custodian Transfer | 2026-07-03 |
| [ADR-105](ADR-105-signed-jwt-for-proxy-and-native-auth.md) | Accepted | Hub Issues a Signed JWT Alongside the localStorage Session — For Proxy Services and Future Native Clients Only | 2026-07-03 |
| [ADR-106](ADR-106-cross-schema-access-is-grant-gated-not-rls.md) | Proposed | Cross-Schema Access Today Is Grant-Gated by Convention, Not Enforced by Views or RLS — Ratify Reads, Flag Owner-Bypassing Writes for Remediation | 2026-07-03 |
| [ADR-107](ADR-107-mdd-reverse-adr-checklist-not-passive-citation.md) | Accepted | `/mdd-reverse` ADR Verification Is an Active Per-Pattern Checklist, Not a Passive Citation Instruction — And Its Exemplars Must Model That | 2026-07-03 |
| [ADR-108](ADR-108-generic-authenticated-site-capture-and-analysis-service.md) | Accepted | A Generic, Permanent Authenticated-Site Capture & AI-Analysis Service (Codename: SiteCap) | 2026-07-03 |
| [ADR-109](ADR-109-videosmith-isolated-wrapper-around-internal-engine.md) | Accepted | VideoSmith — Isolated PWA Wrapping an Internal-Only Third-Party Engine, With the AI Chain Owned by the Wrapper | 2026-07-03 |
| [ADR-110](ADR-110-custodian-voucher-ad-hoc-charge-write.md) | Proposed | Custodian Voucher Booking Writes `creditcard.ad_hoc_charges` via SECURITY DEFINER RPC, Not Client-Side Fetch | 2026-07-09 |
| [ADR-111](ADR-111-unified-job-record-sales-jobs-canonical.md) | Accepted | Unified Job Record in sales.jobs (Supersedes ADR-046) | 2026-07-11 |
| [ADR-112](ADR-112-canonical-session-key-and-universal-logout.md) | Accepted | lm360-session Is the Single Canonical Session — Every PWA Mirrors To It on Login, and Every PWA Exposes an Always-Visible Logout | 2026-07-12 |
| [ADR-113](ADR-113-email-tel-format-validation-default.md) | Accepted | Email and Indian Mobile Inputs Validate Format by Default — Platform-Native Pattern + checkValidity, No Validation Library | 2026-07-12 |
| [ADR-114](ADR-114-google-ai-oauth-vertex-ai.md) | Accepted | Google AI Access Uses OAuth/ADC Service Identity via Vertex AI — Never Static Gemini API Keys | 2026-07-16 |
| [ADR-115](ADR-115-tailscale-mesh-admin-fallback.md) | Accepted | Tailscale Mesh Is the Standing Admin-Access Fallback When ISP Routing Breaks the Public Path | 2026-07-16 |
| [ADR-116](ADR-116-learning-hub-context-deep-linking.md) | Accepted | Learning Hub Context-Specific Deep-Linking from PWA Headers | 2026-07-16 |
| [ADR-117](ADR-117-courier-dispatch-via-external-aggregator-proxy.md) | Proposed | Courier Dispatch via a Dedicated External-Aggregator Proxy Service | 2026-07-27 |
| [ADR-118](ADR-118-courier-tracking-backbone-and-captcha-relay.md) | Proposed | Courier Tracking Backbone + Human-in-the-Loop CAPTCHA Relay | 2026-07-27 |
| [ADR-119](ADR-119-rule-driven-courier-auto-selection.md) | Proposed | Rule-Driven Courier Auto-Selection Mirroring Shiprocket Allocation | 2026-07-27 |
| [ADR-120](ADR-120-lifecycle-event-store-and-retention.md) | Proposed | Append-Only Shipment Lifecycle Event Store + Delete-Protected Final Record | 2026-07-27 |
| [ADR-121](ADR-121-dispatch-target-consolidation-into-counter-master.md) | Proposed | Dispatch-Target Consolidation into the Counter/Store Master via Tiered Matching | 2026-07-27 |
| [ADR-122](ADR-122-booking-point-abstraction.md) | Proposed | Booking-Point Abstraction for Multi-Account / Multi-Carrier Extensibility | 2026-07-27 |
| [ADR-123](ADR-123-dispatch-reporting-access-and-pii-model.md) | Proposed | Dispatch Reporting Access & PII Model — Internal MIS vs Client Report | 2026-07-27 |
| [ADR-124](ADR-124-playwright-first-for-pwa-visual-capture.md) | Accepted | Playwright Is the Default Tool for PWA Screenshot/Screencast Automation — Claude-in-Chrome Requires Explicit Approval | 2026-07-29 |
| [ADR-125](ADR-125-tour-job-many-to-many-and-tour-expense-pwa.md) | Proposed (revised) | Tours Link to Multiple Jobs via a True Many-to-Many Bridge Table (sales.tour_jobs); a New Tour Expense PWA Tracks Per-Tour Employee Allowances | 2026-08-01 |
| [ADR-126](ADR-126-effective-dated-many-to-many-bridges-and-unified-job-identity.md) | Proposed | Effective-Dated Many-to-Many Bridges Are the Platform Pattern for Entity-to-Job Associations; Job Identity Is Unified on sales.jobs | 2026-08-01 |
| [ADR-127](ADR-127-counter-job-effective-dated-junction.md) | Proposed | Counter-to-Job Is an Effective-Dated Many-to-Many Junction; installation.counters Is Rebuilt as That Bridge Over the counters.counter Master | 2026-08-01 |
| [ADR-128](ADR-128-shared-postgrest-role-model.md) | Proposed | PostgREST Access Rides on a Shared web_anon/authenticator Role Model — Per-PWA Postgres Roles Do Not Exist | 2026-08-01 |
| [ADR-129](ADR-129-per-job-attributable-pnl-view.md) | Proposed | Per-Job Attributable P&L via a sales.job_pnl View — Even-Split Tour-Cost Allocation, Agency-Margin Headline | 2026-08-01 |

---

*Last updated: 2026-07-29*
