Pant0x's picture
Deploy Ain El Aql Backend to HF Spaces (no secrets)
f315c76
|
Raw
History Blame Contribute Delete
11.8 kB
# 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 <supabase_access_token>`
- 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 <barrier_token>`
- 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.