# Ain El Aql Backend - Comprehensive Technical Documentation ## 1) Purpose and Scope This document is the single-source technical overview for the Ain El Aql backend. It covers: 1. System architecture 2. Authentication and authorization 3. Role model and access scope 4. Endpoint catalog and contracts 5. End-to-end data flow 6. Database model and relationships 7. Validation, errors, and operational behavior 8. Production readiness guidance Primary implementation file: - `API.py` Supporting documentation: - `docs/API_REFERENCE.md` - `docs/BACKEND_ARCHITECTURE.md` - `docs/ENVIRONMENT_VARIABLES.md` --- ## 2) System Architecture The backend is a FastAPI monolith that combines: 1. AI inference orchestration (local YOLO or remote model service) 2. Supabase-backed auth, profile, data persistence, and storage 3. Parking/session lifecycle and event feeds 4. Pricing and occupancy engines 5. Gate/payment decision logic ### Runtime Components 1. API framework: FastAPI 2. CV/ML runtime: OpenCV, NumPy, Ultralytics YOLO 3. Data/auth/storage backend: Supabase (Auth + PostgREST + Storage) 4. Payment provider: Paymob (optional) ### Inference Modes 1. `MODEL_INFERENCE_PROVIDER=local` - Inference executed in this service. 2. `MODEL_INFERENCE_PROVIDER=remote` - Backend calls external model runtime using `MODEL_SERVICE_URL`. --- ## 3) Authentication and Authorization The backend supports two authentication paths: 1. Supabase JWT bearer token 2. Barrier/device static token ### 3.1 Supabase Token Auth - Header: `Authorization: Bearer ` - Validation endpoint: Supabase `GET /auth/v1/user` - On successful verification: - backend derives user id/email - backend auto-creates a minimal `profiles` row when missing (best effort) Why auto-provision profile rows: - Prevent FK failures on writes referencing `profiles.id`. - Reduce silent persistence failures when auth users exist but profile rows do not. ### 3.2 Barrier/Device Token Auth - Header: `Authorization: Bearer ` - Token sources: - `BARRIER_API_TOKEN` (single token) - `BARRIER_API_TOKENS` (comma-separated tokens) - Comparison uses constant-time matching (`hmac.compare_digest`). - Returns synthetic auth context: - `id = BARRIER_SYNTHETIC_USER_ID` (default `barrier-device`) - `role = barrier` - `auth_type = barrier_token` Important: - Barrier auth is intended for machine integrations (camera/barrier clients). - Barrier auth is not a substitute for end-user mobile/web sessions. --- ## 4) Role Model and Access Scope Roles in runtime behavior: 1. `user` 2. `admin` 3. `security` 4. `developer` 5. `barrier` (synthetic API role) ### 4.1 Scope Rules 1. User scope: - Own records only 2. Staff scope (`admin`, `security`): - Global records - optional `for_user_id` filtering on feed/history endpoints 3. Barrier scope (`barrier`): - Global read scope for operational feeds/history and gate decision checks - Not treated as staff for privileged maintenance/payment confirmations 4. Developer scope (`developer`): - Access to developer endpoints (`/developer/*`) --- ## 5) Endpoint Catalog ### 5.1 Public/Utility 1. `GET /` 2. `GET /health` 3. `GET /supabase/health` 4. `GET /models` ### 5.2 Developer 1. `GET /developer/models` 2. `POST /developer/predict` ### 5.3 Authentication 1. `POST /auth/register` 2. `POST /auth/login` 3. `POST /auth/otp/request` 4. `POST /auth/otp/verify` 5. `POST /auth/forgot-password` 6. `POST /auth/reset-password/resolve-token` 7. `POST /auth/reset-password` 8. `GET /auth/reset-password-page` 9. `GET /auth/reset-password-bridge` ### 5.4 Profile and Vehicles 1. `PUT /profile/update` 2. `POST /vehicles/add` 3. `GET /vehicles/my` 4. `PUT /vehicles/{vehicle_id}` 5. `DELETE /vehicles/{vehicle_id}` 6. `POST /vehicles/verify` ### 5.5 Notifications 1. `POST /notifications/fcm-token` 2. `GET /notifications/my` ### 5.6 Inference and Model Runtime 1. `POST /predict` 2. `POST /model/infer` ### 5.7 Parking/Events/History 1. `GET /parking/locations` 2. `GET /parking/occupancy` 3. `GET /events/entered-cars` 4. `GET /events/leaving-cars-within-5-minutes` 5. `GET /events/new-cars` 6. `GET /events/left-cars` 7. `GET /events/inside-cars` 8. `GET /parking/history` ### 5.8 Payments and Gate 1. `POST /payments/paymob/create` 2. `POST /payments/paymob/webhook` 3. `POST /payments/manual/cash-confirm` 4. `POST /gate/decision` ### 5.9 Maintenance 1. `POST /admin/maintenance/weekly-refresh` --- ## 6) End-to-End Data Flow ## 6.1 Predict Request Flow (`POST /predict`) 1. Authenticate request (Supabase token or barrier token). 2. Validate optional inputs: - `event_type` in `{entry, exit, ocr_scan}` - `parking_location` pattern - `camera_source` pattern 3. Run inference pipeline (local or remote). 4. Build normalized plate payload. 5. Persist output to Supabase: - upload raw and processed images to storage buckets - resolve vehicle from OCR plate - resolve/create session depending on event type - create `car_events` row - optionally emit notification events 6. Compute and return: - `payment_status` - `pricing` - `gate_decision` - persistence metadata ## 6.2 Vehicle Resolution Logic The backend now matches OCR plates using both formats: 1. Arabic plate fields: `plate_letters_ar + plate_numbers_ar` 2. English plate fields: `plate_letters_en + plate_numbers_en` Matching order: 1. Owner-scoped lookup (when authenticated Supabase user id is available) 2. Global lookup fallback Effect: - Reduces false negatives where OCR returns one language format but not the other. ## 6.3 Session Lifecycle 1. `entry` - create or reuse open session 2. `exit` - use open session - if paid and within 5 minutes: close session (`status=exited`) - if paid but grace expired: keep open with `status=overstayed` - if unpaid: keep open (gate deny path) 3. `ocr_scan` - read context only, no session state transition ## 6.4 Unmatched Fallback Flow When a plate is detected but not linked to a registered vehicle/session: 1. Event is still stored in `car_events` (with nullable `vehicle_id`/`session_id`). 2. Backend builds inferred unmatched rows from entry/exit event streams by plate key. 3. Inferred rows are merged into: - `GET /parking/locations` - `GET /parking/occupancy` - `GET /events/inside-cars` - `GET /parking/history` Response markers for inferred rows: 1. `inferred_unmatched=true` 2. `plate` object (key/arabic/english) 3. `event_count` Occupancy responses also include source breakdown: 1. `inside_from_registered_sessions` 2. `inside_from_inferred_unmatched` --- ## 7) Database Model (Supabase) Core relational tables: 1. `profiles` - user identity/profile metadata - role and staff metadata 2. `vehicles` - vehicle registration and ownership 3. `parking_sessions` - parking lifecycle state 4. `car_events` - entry/exit/scan event stream 5. `payment_transactions` - payment ledger for paymob/manual cash Notifications and app links: 1. `notification_device_tokens` 2. `notification_events` 3. `app_links` ### Key Relationships 1. `profiles.id` -> `auth.users.id` 2. `vehicles.owner_id` -> `profiles.id` 3. `parking_sessions.vehicle_id` -> `vehicles.id` 4. `car_events.session_id` -> `parking_sessions.id` (nullable) 5. `car_events.vehicle_id` -> `vehicles.id` (nullable) ### Storage Buckets 1. `SUPABASE_RAW_BUCKET` (raw uploads) 2. `SUPABASE_PROCESSED_BUCKET` (split/admin images) --- ## 8) Security and Data Integrity ### 8.1 RLS and Role Design - Supabase RLS is enabled for core business tables. - Backend writes are performed via service role credentials. - Client-facing authorization is enforced in API layer by user role/scope. ### 8.2 Notification Event Hardening Current model: 1. Notification content is server-owned. 2. Authenticated users can read own notifications. 3. Authenticated users can only mark own notifications as read. 4. Client-side insert/delete/content edits are blocked. ### 8.3 Created-By FK Protection For persistence writes: - `created_by` is now populated only for Supabase-authenticated users. - Barrier-auth requests do not inject synthetic ids into FK-backed columns. This prevents FK violations and silent persistence drop scenarios. --- ## 9) Validation and Error Contract Common input validations: 1. Auth header format (`Bearer ...`) 2. `event_type` allowed values 3. parking location format 4. camera source format 5. file type and non-empty uploads 6. payment amount positive integer rules Common error statuses: 1. `400` invalid input 2. `401` auth missing/invalid/expired 3. `403` role or scope violation 4. `404` missing session/resource 5. `502` upstream integration failure 6. `503` missing critical configuration --- ## 10) Production Readiness Checklist ## 10.1 Required Environment 1. `SUPABASE_URL` 2. `SUPABASE_ANON_KEY` 3. `SUPABASE_SERVICE_ROLE_KEY` 4. `SUPABASE_ENFORCE_AUTH=true` (recommended) 5. model runtime config (`MODEL_INFERENCE_PROVIDER` + remote/local settings) Optional but recommended: 1. `PASSWORD_RESET_REDIRECT_URL` 2. `BARRIER_API_TOKEN` or `BARRIER_API_TOKENS` (if device auth is needed) 3. pricing/capacity config 4. paymob config if card payments enabled ## 10.2 Database Migration Baseline Ensure latest SQL is applied, including: 1. `supabase/04_auth_profile_vehicle_upgrade.sql` 2. `supabase/05_multi_vehicle_auth_notifications.sql` 3. `supabase/06_profile_name_parts_upgrade.sql` ## 10.3 Smoke Tests 1. `GET /health` 2. `GET /supabase/health` 3. Auth login/register flow 4. `POST /predict` (entry + exit) 5. `GET /parking/locations` 6. `GET /events/inside-cars` 7. `GET /parking/history` 8. Gate decision endpoint 9. Password reset flow (bridge + page + resolver) ## 10.4 Operational Guardrails 1. Rotate service secrets and barrier tokens regularly. 2. Keep `SUPABASE_SERVICE_ROLE_KEY` backend-only. 3. Monitor `response.supabase.saved` from `/predict` integrations. 4. Alert on repeated `saved=false` responses and 5xx spikes. --- ## 11) Troubleshooting Guide ### Symptom: feeds/history are empty Checks: 1. Confirm requests are authenticated and role scope is correct. 2. Verify `/predict` responses include `supabase.saved=true`. 3. Verify vehicle resolution fields (Arabic/English plate matching). 4. Confirm sessions are being created (`parking_sessions`) and linked to events. 5. If traffic is mostly unregistered, verify inferred rows are visible (`inferred_unmatched=true`). ### Symptom: barrier token rejected Checks: 1. Token present as Bearer token 2. `BARRIER_API_TOKEN` or `BARRIER_API_TOKENS` set in deployment env 3. No hidden whitespace in configured token ### Symptom: auth user exists but no data persists Checks: 1. Confirm `profiles` row exists for that auth user id. 2. Confirm Supabase service role key is valid and backend can write tables. 3. Inspect backend logs for persistence exceptions. --- ## 12) Notes on Backward Compatibility 1. Existing Supabase auth clients continue to work unchanged. 2. Barrier token support is additive. 3. Feed/history response shape is preserved. - Added optional inferred markers and source-breakdown fields. 4. Role checks remain strict for maintenance and payment confirmation endpoints. --- ## 13) Recommended Next Improvements 1. Add structured audit logs for auth path used (`supabase` vs `barrier`). 2. Add metrics counters for vehicle-match source (`arabic`, `english`, fallback). 3. Add integration tests for: - missing-profile auto-provision - barrier gate decision authorization - plate matching variants (Arabic-only, English-only, mixed) 4. Add a migration to introduce an explicit persistent `barrier` app role if database-level modeling is desired.