Database¶
LinguaAI uses PostgreSQL hosted on Supabase. The schema uses a hybrid approach: relational tables for structured data and JSONB columns (planned) for flexible AI output such as error logs and pronunciation feedback.
Migrations live in backend/supabase/migrations/.
Custom Types (Enums)¶
CREATE TYPE proficiency_level AS ENUM (
'Beginner',
'Elementary',
'Intermediate',
'Advanced',
'Fluent'
);
CREATE TYPE goal_enum AS ENUM (
'Travel & Tourism',
'Business & Work',
'Education',
'Daily Conversation',
'Culture & Entertainment',
'Family & Friends'
);
CREATE TYPE focus_area_enum AS ENUM (
'Speaking',
'Listening',
'Reading',
'Writing',
'Vocabulary',
'Grammar'
);
Tables¶
profiles¶
Stores user-facing profile data. The id column is a foreign key to
Supabase’s managed auth.users table.
Column |
Type |
Nullable |
Notes |
|---|---|---|---|
|
|
No |
Primary key; references |
|
|
No |
Unique |
|
|
No |
|
|
|
Yes |
|
|
|
No |
Default: |
|
|
Yes |
Array of selected learning goals |
|
|
Yes |
Array of selected focus areas |
|
|
Yes |
|
|
|
No |
Default: |
|
|
Yes |
Unique where not null |
|
|
No |
Default: |
|
|
Yes |
Indexes:
-- Enforced by UNIQUE constraint
profiles_email_key ON profiles (email);
-- Partial unique index (only when google_id is not null)
profiles_google_id_unique ON profiles (google_id)
WHERE google_id IS NOT NULL;
Row Level Security (RLS):
Operation |
Policy name |
Rule |
|---|---|---|
|
Public profiles are viewable |
Allow all ( |
|
Users can insert own profile |
|
|
Users can update own profile |
|
field_specific¶
A vocabulary dictionary table used to serve word definitions, examples, and difficulty metadata to the learning module.
Column |
Type |
Nullable |
Notes |
|---|---|---|---|
|
|
No |
Primary key, auto-increment |
|
|
No |
|
|
|
No |
|
|
|
Yes |
|
|
|
Yes |
e.g. |
|
|
No |
|
|
|
No |
Topic category (e.g. |
|
|
No |
Default: |
Indexes:
idx_dictionary_word ON field_specific (word);
idx_dictionary_category ON field_specific (category);
Database Triggers¶
handle_new_user¶
Automatically creates a profiles row whenever a new user registers via
Supabase Auth, preventing orphaned auth.users records.
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$
BEGIN
INSERT INTO public.profiles (id, email, full_name, avatar_url)
VALUES (
NEW.id,
NEW.email,
COALESCE(NEW.raw_user_meta_data->>'full_name', ''),
NEW.raw_user_meta_data->>'avatar_url'
);
RETURN NEW;
END;
$$;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
PostgreSQL Extensions¶
The following extensions are enabled on the Supabase project:
Extension |
Purpose |
|---|---|
|
UUID generation ( |
|
Cryptographic functions |
|
Automatic GraphQL API (Supabase feature) |
|
Query performance statistics |
|
Encrypted secret storage |
Planned Tables¶
The following tables are planned for future modules:
Table |
Purpose |
|---|---|
|
AI tutor conversation sessions |
|
Individual messages within a session |
|
Audio attempts with phoneme-level scores (JSONB) |
|
Spaced-repetition state per word per user |
|
Gamification XP ledger |
|
Badge definitions |
|
Badges earned by each user |