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.

┌──────────────────────────────────────────────────────────────────┐
│                        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/)

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:

modules/<feature>/
├── __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

Client                   FastAPI                  Supabase Auth
  │                        │                           │
  │  POST /api/auth/signup  │                           │
  │────────────────────────►│                           │
  │                        │  auth.sign_up()           │
  │                        │──────────────────────────►│
  │                        │◄──────────────────────────│
  │                        │  upsert profiles row       │
  │                        │  create_access_token()    │
  │◄────────────────────────│                           │
  │  TokenResponse (JWT)    │                           │

Google OAuth — Web

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)

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

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.