.. _architecture: System Architecture =================== High-Level Overview ------------------- LinguaAI follows a **modular monolith** pattern on the backend, with a Flutter cross-platform frontend communicating via REST and WebSocket connections. .. code-block:: text ┌──────────────────────────────────────────────────────────────────┐ │ Flutter Client │ │ (iOS / Android / Web) │ │ │ │ AuthService ──► REST (HTTP/S) ──────────────────────────────┐ │ │ OCR Service (on-device) │ │ │ WebSocket client ──► wss://... ────────────────────────────┐ │ │ └────────────────────────────────────────────────────────────-─┼-┼──┘ │ │ ┌────────────────────────▼-▼──┐ │ FastAPI Backend │ │ │ │ /api/auth/* (auth module) │ │ /api/dictionary/* (dictionary) │ │ /api/flashcards/* (flashcards) │ │ /api/gamification/* (gamification)│ │ /api/lessons/* (lessons) │ │ /api/users/* (users) │ │ /api/learn/* (planned) │ │ /ws/speak (planned) │ │ │ │ core/security.py │ │ core/database.py │ └──────────────┬───────────────┘ │ ┌──────────────▼───────────────┐ │ Supabase │ │ │ │ auth.users (managed) │ │ public.profiles │ │ public.field_specific │ └──────────────────────────────┘ Backend Architecture -------------------- The backend is a **FastAPI modular monolith** — all feature modules live in a single process but are physically separated into their own directories under ``app/modules/``. Application Entry Point (``app/main.py``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Instantiates the FastAPI application with a title, description, and version. - Adds ``CORSMiddleware`` permitting all origins (tighten in production). - Registers all feature routers under the ``/api`` prefix. - Exposes: - ``GET /`` — Serves ``index.html`` (root welcome page). - ``GET /health`` — Database connectivity health check. Core Layer (``app/core/``) ~~~~~~~~~~~~~~~~~~~~~~~~~~ .. list-table:: :header-rows: 1 :widths: 25 75 * - File - Responsibility * - ``config.py`` - Reads ``.env`` with ``python-dotenv``; exposes JWT settings (HS256, 1440 min TTL) and Google OAuth URLs as module-level constants. * - ``database.py`` - Creates a single global ``supabase.Client`` instance at import time. All modules import this shared client. * - ``security.py`` - ``hash_password`` / ``verify_password`` (bcrypt), ``create_access_token`` / ``decode_access_token`` (PyJWT), ``get_current_user`` FastAPI dependency that validates Bearer tokens. * - ``logging_config.py`` - Rotating file handler (5 MB, 3 backups) + console handler. All modules use ``logging.getLogger(__name__)``. Module Layer (``app/modules/``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each module is self-contained and follows the same internal structure: .. code-block:: text modules// ├── __init__.py ├── router.py # FastAPI APIRouter with route definitions ├── service.py # Business logic (static/class methods) ├── schemas.py # Pydantic request/response models and enums └── models.py # ORM-like dataclasses + repository pattern **Key patterns:** - Protected routes use ``Depends(get_current_user)`` from ``core/security.py``. - The Supabase client is imported from ``core/database.py`` — one instance, shared. - Routes are ``async``; tests use ``asyncio_mode = strict``. - Business logic lives entirely in ``service.py``; routers are thin. Authentication Flow ------------------- Email / Password ~~~~~~~~~~~~~~~~ .. code-block:: text Client FastAPI Supabase Auth │ │ │ │ POST /api/auth/signup │ │ │────────────────────────►│ │ │ │ auth.sign_up() │ │ │──────────────────────────►│ │ │◄──────────────────────────│ │ │ upsert profiles row │ │ │ create_access_token() │ │◄────────────────────────│ │ │ TokenResponse (JWT) │ │ Google OAuth — Web ~~~~~~~~~~~~~~~~~~ .. code-block:: text Client FastAPI Google / Supabase │ │ │ │ POST /api/auth/google/url │ │────────────────────────►│ supabase.auth.get_url() │ │ │──────────────────────────►│ │◄────────────────────────│ { url } │ │ redirect browser │ │ │──────────────────────────────────────────────────►│ │◄──────────────────────────────────────────────────│ code │ POST /api/auth/google/callback (code) │ │────────────────────────►│ exchange_code() │ │ │──────────────────────────►│ │◄────────────────────────│ TokenResponse │ Google OAuth — Mobile (Native) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: text Flutter FastAPI Google │ │ │ │ google_sign_in SDK ───────────────────────────► │ │◄─────────────────────────────── id_token ─────────│ │ POST /api/auth/google/token (id_token) │ │────────────────────────►│ sign_in_with_id_token() │ │◄────────────────────────│ TokenResponse │ Token Lifecycle ~~~~~~~~~~~~~~~ - JWT tokens use HS256 and expire after **24 hours** (1440 minutes). - The client stores the access token and refresh token in ``SharedPreferences``. - ``POST /api/auth/refresh`` exchanges a refresh token for a new access token. - ``POST /api/auth/logout`` invalidates the session on the Supabase side. Real-time Pronunciation Scoring (Planned) ----------------------------------------- The ``speaking`` module will expose a WebSocket endpoint that: 1. Accepts a WebSocket connection authenticated by a query-parameter JWT. 2. Receives binary audio chunks streamed from the Flutter client. 3. Passes chunks to a Whisper (ASR) model for transcription. 4. Computes phoneme-level pronunciation scores via a HuggingFace model. 5. Streams JSON score payloads back to the client in real time. Security Considerations ----------------------- .. list-table:: :header-rows: 1 :widths: 30 70 * - Concern - Mitigation * - Password storage - bcrypt with salt; plain-text passwords never persisted. * - Token signing - HS256 JWT; secret must be at least 32 random characters. * - Database access - Supabase Row Level Security (RLS) restricts reads/writes per user. * - Service role key - Only used server-side; never sent to the Flutter client. * - CORS - Currently ``allow_origins=["*"]``; restrict to known origins in production. * - Logging - Tokens and passwords are never written to log files.