Skip to content

Chaverim ALPR Platform - Architecture Summary

This document provides a comprehensive overview of the Chaverim ALPR Platform architecture, consolidating design decisions from all component-specific documents.

Document Status: Living Document Last Updated: 2025-12-29 Related Documents: See individual architecture docs in this directory for detailed specifications.


Table of Contents

  1. System Overview
  2. Component Architecture
  3. Data Flow
  4. Data Model
  5. Deployment Architecture
  6. Security Architecture
  7. Integration Points
  8. Key Design Decisions

1. System Overview

1.1 Platform Description

The Chaverim ALPR Platform is a distributed license plate recognition system designed for community safety monitoring. It enables Chaverim of Rockland (a non-profit community watch organization) to:

  • Monitor neighborhood streets for suspicious vehicles
  • Investigate incidents by searching historical plate sightings
  • Track vehicle movement patterns across multiple locations
  • Provide organized evidence to law enforcement
  • Alert volunteers when watched plates are detected

1.2 Key Stakeholders

Stakeholder Role Key Interactions
Operators Active monitoring via web dashboard View live feed, search plates, respond to alerts
Administrators System configuration and management Manage users, collectors, watchlists, API keys
Field Volunteers On-site patrol and response Receive mobile alerts, investigate sightings
Law Enforcement Evidence consumers Request/receive evidence packages
Edge Sites Physical camera locations Capture detections, buffer events, upload data

1.3 System Context Diagram

C4Context title System Context - Chaverim ALPR Platform Person(operator, "Operator", "Monitors dashboard, searches plates, responds to alerts") Person(admin, "Administrator", "Manages system configuration, users, and collectors") Person(volunteer, "Field Volunteer", "Receives alerts, investigates incidents") Person(le, "Law Enforcement", "Receives evidence packages") System(alpr, "Chaverim ALPR Platform", "Distributed license plate recognition for community safety") System_Ext(cameras, "ALPR Cameras", "Hikvision, Unifi Protect cameras with built-in plate recognition") System_Ext(telegram, "Telegram", "External messaging platform for alerts") System_Ext(osm, "OpenStreetMap", "Map tiles and geocoding") Rel(operator, alpr, "Uses", "HTTPS/WebSocket") Rel(admin, alpr, "Configures", "HTTPS") Rel(volunteer, alpr, "Receives alerts", "Telegram/Web") Rel(le, alpr, "Receives evidence", "Export packages") Rel(cameras, alpr, "Sends detections", "ISAPI/Protect API") Rel(alpr, telegram, "Sends alerts", "Bot API") Rel(alpr, osm, "Fetches maps", "HTTPS")

1.4 Primary Use Cases

  1. Plate Search - Find all sightings of a specific plate number with timeline and map visualization
  2. Live Monitoring - Real-time detection feed with instant watchlist alerts
  3. Watchlist Management - Create and manage lists of plates of interest
  4. Incident Investigation - Reconstruct vehicle routes, find co-traveling vehicles
  5. Evidence Export - Generate chain-of-custody packages for law enforcement
  6. Collector Management - Provision, monitor, and configure edge devices

2. Component Architecture

2.1 High-Level Component Diagram

graph TB subgraph "Edge Site (Per Location)" subgraph "Raspberry Pi" HA[Hikvision Adapter] UA[Unifi Adapter] FA[Future Adapters] EB[Detection Buffer<br/>SQLite + WAL] LU[Local UI<br/>Flask + HTMX] HC[HTTP Client<br/>httpx async] end CAM1[Camera 1] CAM2[Camera 2] end subgraph "Central Server" subgraph "Application Layer" API[FastAPI<br/>REST + WebSocket] AE[Alert Engine<br/>Async Worker] WS[WebSocket Manager] TW[Telegram Worker] end subgraph "Data Layer" PG[(PostgreSQL 17<br/>Events, Users, Config)] MIO[(MinIO<br/>S3-Compatible<br/>Images)] AQ[Alert Queue<br/>PostgreSQL Table] end subgraph "Web UI" UI[HTMX + Alpine.js<br/>Tailwind CSS<br/>Jinja2 Templates] LF[Leaflet.js<br/>Map Visualization] end end CAM1 -->|ISAPI| HA CAM2 -->|Protect API| UA HA --> EB UA --> EB EB --> HC HC -->|HTTPS + API Key| API API --> PG API --> MIO API --> AQ AQ --> AE AE --> WS AE --> TW UI --> API UI --> LF style EB fill:#f9f,stroke:#333 style PG fill:#69b,stroke:#333 style MIO fill:#9b6,stroke:#333

2.2 Central Server Components

Component Technology Responsibility
FastAPI Application FastAPI + Pydantic REST API, request validation, authentication
PostgreSQL PostgreSQL 17 Detection metadata, users, watchlists, configuration
MinIO MinIO (S3-compatible) Full scene and plate crop images
Alert Engine Async Python worker Watchlist matching, notification dispatch
WebSocket Manager FastAPI WebSocket Real-time client connections
Telegram Worker Async Python worker External notification delivery
Web UI HTMX + Alpine.js + Tailwind Mobile-responsive operator interface

2.3 Edge Collector Components

Component Technology Responsibility
Camera Adapters Python + httpx Vendor-specific protocol handling (ISAPI, Protect)
Detection Buffer SQLite + WAL mode 7-day local Detection storage for offline resilience
HTTP Client httpx async Batch uploads, heartbeats, command acknowledgments
Local UI Flask + HTMX Setup wizard, diagnostics, status display
Credential Store Fernet (AES-256) Device-bound encrypted camera credentials

2.4 Component Interaction Diagram

sequenceDiagram participant C as Camera participant E as Edge Collector participant A as Central API participant D as PostgreSQL participant S as MinIO participant W as Alert Worker participant U as Web UI Note over C,U: Normal Detection Flow C->>E: Plate Detection (ISAPI/Protect) E->>E: Buffer locally (SQLite) loop Every 5-30 seconds E->>A: POST /api/v1/detections/batch<br/>(multipart: detections + images) A->>D: Store Detection metadata A->>S: Store images A->>D: Enqueue for alert processing A->>E: 201 Created end W->>D: Poll alert queue W->>W: Match against watchlist cache alt Match Found W->>D: Create alert record W->>U: WebSocket push end

3. Data Flow

3.1 Detection Ingestion Flow

Detections flow from camera to central storage through a batched, resilient pipeline.

flowchart LR subgraph Edge["Edge Collector"] DET[Detection<br/>Received] --> NORM[Normalize<br/>Plate] NORM --> DEDUP[Deduplicate<br/>30s window] DEDUP --> BUF[Add to<br/>Buffer] BUF --> BATCH{Batch<br/>Trigger?} BATCH -->|Time: 5-30s| UPLOAD BATCH -->|Count: 50| UPLOAD BATCH -->|Size: 5MB| UPLOAD BATCH -->|No| BUF UPLOAD[Upload<br/>Batch] end subgraph Central["Central Server"] UPLOAD -->|HTTPS + API Key| VALIDATE[Validate<br/>API Key] VALIDATE --> STORE[Store to<br/>PostgreSQL] STORE --> IMAGE[Store Images<br/>to MinIO] IMAGE --> QUEUE[Enqueue for<br/>Alert Check] QUEUE --> RESP[Return<br/>201 Created] end subgraph Failure["Failure Handling"] UPLOAD -.->|Fail| BACKOFF[Exponential<br/>Backoff] BACKOFF -.-> BUF end

Batch Upload Configuration:

Parameter Default Description
batch_window_seconds 5-30s Time before forced flush (varies by camera type)
batch_max_detections 50 Detections per batch
batch_max_size_mb 5 Maximum payload size

See: Detection Batching for complete specification.

3.2 Alert Processing Flow

Alerts are processed asynchronously to avoid blocking detection ingestion during high-volume periods.

flowchart TB subgraph Ingestion["Fast Path (< 100ms)"] BATCH[Batch<br/>Received] --> STORE[Store<br/>Detections] STORE --> ENQUEUE[Enqueue<br/>Detection IDs] ENQUEUE --> RETURN[Return<br/>201] end subgraph AlertEngine["Background Processing"] POLL[Poll<br/>Queue] --> LOAD[Load<br/>Detection] LOAD --> LOOKUP{In Watchlist<br/>Cache?} LOOKUP -->|Yes| ALERT[Create<br/>Alert] LOOKUP -->|No| COMPLETE[Mark<br/>Complete] ALERT --> NOTIFY[Notify<br/>Subscribers] NOTIFY --> COMPLETE end subgraph Notification["Multi-Channel Delivery"] NOTIFY --> WS[WebSocket<br/>Push] NOTIFY --> TG[Telegram<br/>Bot] NOTIFY --> PUSH[Push Notify<br/>Future] end ENQUEUE -.-> POLL style Ingestion fill:#e8f5e9 style AlertEngine fill:#fff3e0

Performance Targets:

Metric Target
Ingestion latency < 100ms per batch
Alert latency 1-5 seconds after ingestion
Watchlist lookup O(1) via in-memory cache

See: Alert Engine for complete specification.

3.3 Configuration Push Flow

Configuration updates are delivered to edge collectors via heartbeat polling.

sequenceDiagram participant A as Admin UI participant C as Central Server participant E as Edge Collector A->>C: Update collector config C->>C: Increment config_version<br/>Store pending command loop Every 60 seconds E->>C: POST /api/v1/heartbeat<br/>{uptime, queue_depth, config_version} C->>C: Check for pending commands C->>E: {pending_commands: [{type: "config_update", ...}]} end E->>E: Apply configuration E->>C: POST /api/v1/commands/{id}/ack<br/>{status: "success"} C->>C: Mark command acknowledged

Heartbeat Payload:

{
  "uptime_seconds": 86400,
  "queue_depth": 150,
  "cameras_online": 2,
  "config_version": 5
}

4. Data Model

4.1 Core Entity Relationships

erDiagram COLLECTOR ||--o{ DETECTION : generates COLLECTOR ||--o{ CAMERA : has COLLECTOR ||--o{ API_KEY : authenticates_with DETECTION ||--o| DETECTION_IMAGE : has DETECTION ||--o{ LEGAL_HOLD : protected_by DETECTION ||--o{ ALERT : triggers USER ||--o{ WATCHLIST : creates USER ||--o{ ALERT_SUBSCRIPTION : subscribes_to USER ||--o{ TELEGRAM_LINK : links WATCHLIST ||--o{ WATCHLIST_ENTRY : contains WATCHLIST ||--o{ ALERT : generates WATCHLIST ||--o{ ALERT_SUBSCRIPTION : subscribed_via ALERT ||--o{ NOTIFICATION : delivers_via COLLECTOR { uuid id PK string site_name string site_address decimal gps_latitude decimal gps_longitude string status timestamp last_heartbeat_at int config_version } DETECTION { bigint id PK uuid collector_id FK uuid camera_id FK string plate_number string plate_normalized float confidence timestamp captured_at string direction char full_image_hash char crop_image_hash char record_hash } USER { uuid id PK string email string password_hash string role boolean is_active } WATCHLIST { uuid id PK uuid created_by FK string name string description boolean is_active } ALERT { bigint id PK bigint detection_id FK uuid watchlist_id FK timestamp created_at } LEGAL_HOLD { bigint id PK bigint detection_id FK string case_id string reason timestamp hold_until timestamp released_at timestamp created_at }

4.2 Key Tables

Table Purpose Retention
events Plate detection metadata 7 years
event_images Image paths and hashes 1 year (images), 7 years (metadata)
collectors Edge device registry Permanent
cameras Camera configuration per collector Permanent
api_keys Collector authentication Permanent (with audit)
users User accounts and roles Permanent
watchlists Plate lists of interest Permanent
watchlist_entries Individual plates in watchlists Permanent
alerts Watchlist match records 7 years
legal_holds Evidence preservation flags 7 years
audit_log All user actions 7 years

4.3 Data Retention Summary

Data Type Retention Storage Rationale
Detection metadata 7 years PostgreSQL Legal/investigation requirements
Full scene images 1 year MinIO Storage cost management
Plate crop images 1 year MinIO Storage cost management
Audit logs 7 years PostgreSQL Compliance
Alert history 7 years PostgreSQL Investigation records

See: Data Retention for tiered storage and lifecycle details.


5. Deployment Architecture

5.1 Deployment Overview

graph TB subgraph Internet["Internet"] USER[Web Browser] MOBILE[Mobile Device] end subgraph CentralInfra["Central Infrastructure (Docker Compose)"] LB[Reverse Proxy<br/>Nginx/Traefik] subgraph AppContainer["Application Container"] APP[FastAPI App<br/>+ Workers] end subgraph DataContainers["Data Containers"] PG[(PostgreSQL 17)] MINIO[(MinIO)] end end subgraph EdgeSites["Edge Sites (systemd)"] subgraph Site1["Site 1: Main St"] PI1[Raspberry Pi] CAM1A[Camera A] CAM1B[Camera B] end subgraph Site2["Site 2: Oak Ave"] PI2[Raspberry Pi] CAM2A[Camera A] end end USER -->|HTTPS| LB MOBILE -->|HTTPS| LB LB --> APP APP --> PG APP --> MINIO PI1 -->|HTTPS + API Key| LB PI2 -->|HTTPS + API Key| LB CAM1A -->|LAN| PI1 CAM1B -->|LAN| PI1 CAM2A -->|LAN| PI2

5.2 Central Server Deployment

Docker Compose Stack:

Service Image Resources Volumes
app Custom FastAPI 2 CPU, 4GB RAM Logs
db postgres:17 2 CPU, 4GB RAM Data, WAL
minio minio/minio 1 CPU, 2GB RAM Data (SSD + HDD tiers)
nginx nginx:alpine 0.5 CPU, 512MB RAM Certs, config

Network Topology:

graph LR subgraph DockerNetwork["Docker Network"] APP[app:8000] DB[db:5432] MINIO[minio:9000] NGINX[nginx:443] end subgraph External CLIENT[Clients] end CLIENT -->|443| NGINX NGINX -->|8000| APP APP -->|5432| DB APP -->|9000| MINIO

5.3 Edge Collector Deployment

Hardware Requirements:

Model RAM Max Cameras Max Events/min
Pi 4 (2GB) 2GB 4 ~50
Pi 4 (4GB) 4GB 8 ~100
Pi 5 (8GB) 8GB 16 ~200

Systemd Services:

Service Purpose Dependencies
chaverim-edge.service Main collector service Network online
chaverim-setup.service First-boot provisioning Runs until claimed
chaverim-watchdog.service Health monitoring Edge service

File System Layout:

/opt/chaverim-edge/
+-- bin/
|   +-- edge-collector
|   +-- setup-wizard
+-- config/
|   +-- base-config.yaml
|   +-- central.yaml
|   +-- local.yaml
|   +-- .credentials/
+-- data/
|   +-- events.db
+-- logs/

See: Edge Provisioning for complete deployment workflow.


6. Security Architecture

6.1 Authentication Model

graph TB subgraph UserAuth["User Authentication (JWT)"] LOGIN[Login Form] -->|Username/Password| VERIFY[Verify Credentials<br/>Argon2id] VERIFY -->|Valid| JWT[Issue JWT<br/>HTTP-only Cookie] JWT --> SESSION[Session Valid] end subgraph EdgeAuth["Edge Authentication (API Key)"] EDGE[Edge Collector] -->|X-API-Key Header| HASH[SHA-256 Hash] HASH --> LOOKUP[Database Lookup] LOOKUP -->|Valid + Active| COLLECTOR[Collector Identified] end subgraph RBAC["Role-Based Access Control"] SESSION --> ROLE{User Role?} ROLE -->|admin| ADMIN[Full Access] ROLE -->|operator| OPERATOR[Search + Alerts] ROLE -->|viewer| VIEWER[Read Only] end

6.2 Authentication Mechanisms

Authentication Type Method Token Lifetime Storage
User Login Argon2id password hash 24h JWT HTTP-only cookie
Edge Collector API Key (SHA-256) Until revoked Encrypted on device
Telegram Link One-time claim code 10 min Temporary table

6.3 Authorization (RBAC)

Role Permissions
admin Full system access, user management, collector provisioning, API key management
operator Search, view detections, manage personal watchlists, receive alerts
viewer View detections and alerts (read-only)

6.4 Data Protection

flowchart TB subgraph Transit["Encryption in Transit"] TLS[TLS 1.3] --> EDGE[Edge to Central] TLS --> WEB[Browser to Server] TLS --> API[API Calls] end subgraph Rest["Encryption at Rest"] DB[PostgreSQL] --> PGE[Column-level for PII] MINIO2[MinIO] --> SSE[Server-Side Encryption] EDGE2[Edge Credentials] --> FERNET[Fernet AES-256<br/>Device-Bound Key] end subgraph Integrity["Data Integrity"] HASH[Image Hashing] --> SHA256[SHA-256] CHAIN[Record Hash Chain] --> TAMPER[Tamper Evidence] WORM[WORM Protection] --> TRIGGER[Database Triggers] end

Key Security Controls:

Layer Control Implementation
Transport TLS 1.3 All external communication
API Keys Never stored plaintext SHA-256 hash only
Passwords Secure hashing Argon2id with salt
Images Integrity verification SHA-256 hash on ingest
Events WORM protection Database triggers block UPDATE/DELETE
Edge credentials Device-bound encryption Fernet + hardware ID

See: API Key Management and Data Integrity for complete specifications.

6.5 Security Diagram

graph TB subgraph External["External Boundary"] INTERNET((Internet)) end subgraph DMZ["DMZ / Edge Network"] LB[Load Balancer<br/>TLS Termination] end subgraph AppZone["Application Zone"] API[FastAPI<br/>JWT + API Key Auth] WORKERS[Background Workers] end subgraph DataZone["Data Zone"] PG[(PostgreSQL<br/>Role-based Access)] MINIO[(MinIO<br/>SSE Encryption)] end subgraph EdgeZone["Edge Sites (Isolated)"] PI[Raspberry Pi<br/>Encrypted Creds] CAM[Cameras<br/>LAN Only] end INTERNET -->|HTTPS 443| LB LB -->|Internal| API API --> PG API --> MINIO API --> WORKERS PI -->|HTTPS + API Key| LB CAM -->|LAN Only| PI style DataZone fill:#ffe0e0 style EdgeZone fill:#e0ffe0

7. Integration Points

7.1 Camera Vendor Integrations

Vendor Protocol Authentication Capabilities
Hikvision ISAPI (HTTP) Digest Auth Plate detections, images, vehicle metadata
Unifi Protect REST API Bearer Token detections via NVR, images
Future Vendors Pluggable adapters Vendor-specific Extensible adapter pattern

Hikvision ISAPI Integration:

# Event subscription
GET /ISAPI/Traffic/channels/1/vehicleDetect/subscription

# Event payload contains:
# - Plate number
# - Capture time
# - Confidence score
# - Full image (base64)
# - Plate crop (base64)
# - Vehicle type, color

7.2 Notification Integrations

Channel Protocol Use Case Phase
WebSocket WS/WSS Real-time web UI alerts POC
Telegram Bot Bot API Mobile alerts for field volunteers POC
Push Notifications FCM/APNs Native mobile app alerts Post-POC

Telegram Bot Integration:

sequenceDiagram participant U as User participant W as Web UI participant C as Central Server participant T as Telegram API participant D as User's Phone U->>W: Request Telegram link W->>C: Generate link code C->>W: Display code (expires 10 min) U->>T: /link ABC123 T->>C: Webhook: link command C->>C: Validate code, store chat_id C->>T: "Successfully linked!" T->>D: Confirmation message Note over C,T: When alert triggers... C->>T: Send alert message T->>D: Push notification

7.3 External System Integrations

System Purpose Integration Method
OpenStreetMap Map tiles, geocoding Leaflet.js client-side
Time Servers NTP sync (critical for edge) UDP 123
DNS Name resolution UDP 53

8. Key Design Decisions

8.1 Decision Summary Table

Decision Chosen Approach Alternative Rationale Document
Detection ingestion rate limiting Backpressure signaling Reject after X req/min Never lose evidence data Rate Limiting
Alert processing Async queue-based Synchronous on ingest Decouple from ingestion for scalability Alert Engine
Image upload format Multipart form-data Base64 in JSON 33% bandwidth savings Detection Batching
Watchlist matching In-memory cache Database query per detection O(1) lookups, 60s refresh Alert Engine
Edge-to-central auth API keys over TLS Mutual TLS (mTLS) Simpler ops, no cert management API Key Management
Edge provisioning Admin-provisioned claim codes Self-registration Security: admin controls device admission Edge Provisioning
detection data protection WORM (triggers + permissions) Soft delete Evidence integrity for law enforcement Data Integrity
Legal hold implementation Junction table Column on events Maintains WORM immutability Data Integrity
Image retention 1 year (tiered) Same as metadata (7 years) Storage cost management Data Retention
Search implementation PostgreSQL pg_trgm Elasticsearch Sufficient for expected scale, simpler stack Search
OCR-aware matching Normalized plate column Fuzzy search only Deterministic O(1) matching for common confusions Search
Mobile strategy (POC) Responsive web Native app Faster to market, web covers 90% use case CLAUDE.md
Edge credential storage Device-bound encryption Plaintext config SD card theft protection Edge Provisioning

8.2 Architecture Principles

Principle Description Example
Edge-First Design Assume unreliable networks 7-day local buffer, exponential backoff
Accept All Evidence Never reject legitimate detection data Backpressure over rate limiting
Defense in Depth Multiple layers of protection App + DB roles + triggers for WORM
Graceful Degradation System continues when components fail Edge operates offline, alerts continue if storage slow
Field-Friendly Non-technical volunteers can deploy QR code claim, no CLI required
Mobile-Responsive All UIs work on phones Tailwind breakpoints throughout
Explicit over Implicit Document everything This architecture doc, PRPs, decisions.md

8.3 Open Decisions

See open-decisions.md for detailed tracking of all pending decisions.

ID Decision Status Blocker Document
OD-001 Log aggregation platform 🟡 Pending Before Phase 8 Observability
OD-002 Backup target host 🟡 Pending Before Phase 7 Backup & DR
OD-003 Cloud backup (S3/Glacier) 🔴 Blocked Security approval Backup & DR
OD-004 MinIO replication strategy 🟡 Pending Post-POC Backup & DR

8.4 Performance Targets

Metric Target Measured At
Detection ingestion latency < 100ms per batch API response time
Alert processing latency 1-5 seconds Detection store to notification
Search response time < 500ms Exact plate lookup
Plate search (fuzzy) < 1 second pg_trgm similarity
WebSocket notification < 100ms Alert to client receive
Edge heartbeat 60 seconds Polling interval

8.5 Scalability Considerations

Deployment timeline and detection estimates: See CLAUDE.md - Deployment Scale for planned rollout (Month 1: 7 cameras, Month 6: 100 cameras) and per-camera detection rates.

Component Current Target Scaling Path
Detections per day 100,000 (100 cameras) Table partitioning, read replicas
Image storage ~10 GB/day MinIO tiered storage, lifecycle policies
Concurrent users 50 Multiple API instances behind load balancer
Alert queue depth 10,000 Multiple alert workers, Redis queue
Edge collectors 100 Horizontal API scaling

Appendix A: Technology Stack Summary

Central Server

Layer Technology Version
Runtime Python 3.13
Framework FastAPI Latest
ORM SQLAlchemy 2.0
Database PostgreSQL 17
Object Storage MinIO Latest
Web Frontend HTMX + Alpine.js + Tailwind CSS Latest
Maps Leaflet.js + OpenStreetMap Latest
Container Runtime Docker + Docker Compose Latest

Edge Collector

Layer Technology Version
Runtime Python 3.13
Local Web UI Flask + HTMX Latest
Local Database SQLite + WAL 3.x
HTTP Client httpx Latest
Process Manager systemd System
Encryption Fernet (cryptography) Latest

Appendix B: Document Cross-Reference

Topic Detailed Document
Detection batching and upload detection-batching.md
Alert engine and notifications alert-engine.md
Rate limiting and backpressure rate-limiting.md
Data retention and tiering data-retention.md
Evidence integrity and WORM data-integrity.md
Plate search and indexing search.md
API key lifecycle api-key-management.md
Edge device provisioning edge-provisioning.md
Camera adapter interface camera-adapters.md
Monorepo structure monorepo.md
Open architecture decisions open-decisions.md
Backup and disaster recovery backup-disaster-recovery.md
Logging and metrics observability.md
Project overview CLAUDE.md
Implementation patterns docs/prp/

Document Maintainer: Architecture Team Review Cycle: Update with each architectural decision