bayan-api / docs /architecture /07-database-schema.md
youssefreda9's picture
docs: Complete Architecture Documentation (12 files) - 01-system-overview: High-level architecture diagram - 02-class-diagram: UML class diagram (Frontend + Backend) - 03-component-diagram: All modules and connections - 04-sequence-diagrams: 5 flows (Analysis, AutoComplete, Summarize, Save, Offline) - 05-dataflow-diagram: DFD Level 0 + Level 1 - 06-deployment-diagram: Docker + HF Spaces + CI/CD - 07-database-schema: ERD + RLS policies + triggers - 08-nlp-pipeline-diagram: Final NLP pipeline with all 5 models - 09-sync-engine-diagram: State machine + conflict resolution - 10-project-dependency-map: Full dependency graph - 11-production-architecture: Final production system diagram - 12-architecture-audit-report: Stats, risks, future expansion
9641a79
|
Raw
History Blame Contribute Delete
5.2 kB
# 07 — Database Schema Diagram
## Overview
BAYAN uses Supabase (PostgreSQL) with Row-Level Security (RLS). All tables enforce per-user data isolation via `auth.uid()`.
## Entity Relationship Diagram
```mermaid
erDiagram
AUTH_USERS {
uuid id PK
text email
boolean is_anonymous
jsonb raw_user_meta_data
jsonb raw_app_meta_data
timestamptz created_at
timestamptz updated_at
}
PROFILES {
uuid id PK "FK → auth.users(id)"
text display_name
text avatar_url
text auth_provider "anonymous | google"
timestamptz created_at
timestamptz updated_at
}
DOCUMENTS {
uuid id PK "gen_random_uuid()"
uuid user_id FK "→ auth.users(id)"
text title "Default: مستند جديد"
text content "HTML content"
timestamptz created_at
timestamptz updated_at
}
SUMMARIES {
uuid id PK "gen_random_uuid()"
uuid document_id FK "→ documents(id)"
uuid user_id FK "→ auth.users(id)"
text original_text
text summary_text
integer word_count
real compression_ratio
timestamptz created_at
}
SETTINGS {
uuid id PK "gen_random_uuid()"
uuid user_id FK "→ auth.users(id)"
jsonb preferences "theme, font, size, etc."
timestamptz created_at
timestamptz updated_at
}
AUTH_USERS ||--|| PROFILES : "auto-created on signup"
AUTH_USERS ||--o{ DOCUMENTS : "owns"
AUTH_USERS ||--o| SETTINGS : "has"
DOCUMENTS ||--o{ SUMMARIES : "has"
AUTH_USERS ||--o{ SUMMARIES : "owns"
```
## Table Details
### profiles
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| `id` | `uuid` | PK, FK → auth.users | User ID from Supabase Auth |
| `display_name` | `text` | nullable | Display name (from Google or "ضيف") |
| `avatar_url` | `text` | nullable | Google profile picture URL |
| `auth_provider` | `text` | NOT NULL, default 'anonymous' | `anonymous` or `google` |
| `created_at` | `timestamptz` | NOT NULL, default now() | Account creation time |
| `updated_at` | `timestamptz` | NOT NULL, default now() | Last profile update |
### documents
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| `id` | `uuid` | PK, default gen_random_uuid() | Document unique ID |
| `user_id` | `uuid` | FK → auth.users, NOT NULL | Owner |
| `title` | `text` | default 'مستند جديد' | Document title |
| `content` | `text` | nullable | HTML content from editor |
| `created_at` | `timestamptz` | NOT NULL, default now() | Creation time |
| `updated_at` | `timestamptz` | NOT NULL, default now() | Last save time |
### summaries
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| `id` | `uuid` | PK, default gen_random_uuid() | Summary unique ID |
| `document_id` | `uuid` | FK → documents(id) | Parent document |
| `user_id` | `uuid` | FK → auth.users, NOT NULL | Owner |
| `original_text` | `text` | NOT NULL | Source text that was summarized |
| `summary_text` | `text` | NOT NULL | Generated summary |
| `word_count` | `integer` | nullable | Summary word count |
| `compression_ratio` | `real` | nullable | Compression percentage |
| `created_at` | `timestamptz` | NOT NULL, default now() | Generation time |
### settings
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| `id` | `uuid` | PK, default gen_random_uuid() | Setting record ID |
| `user_id` | `uuid` | FK → auth.users, UNIQUE | Owner (one per user) |
| `preferences` | `jsonb` | NOT NULL, default '{}' | All user preferences |
| `created_at` | `timestamptz` | NOT NULL, default now() | Creation time |
| `updated_at` | `timestamptz` | NOT NULL, default now() | Last update time |
## Row Level Security (RLS) Policies
All tables have RLS enabled. Policies follow the pattern:
```sql
-- SELECT: Users can only read their own data
CREATE POLICY "select_own" ON table
FOR SELECT USING (auth.uid() = user_id);
-- INSERT: Users can only insert their own data
CREATE POLICY "insert_own" ON table
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- UPDATE: Users can only update their own data
CREATE POLICY "update_own" ON table
FOR UPDATE USING (auth.uid() = user_id);
-- DELETE: Users can only delete their own data
CREATE POLICY "delete_own" ON table
FOR DELETE USING (auth.uid() = user_id);
```
## Database Triggers
| Trigger | Event | Function | Purpose |
|---------|-------|----------|---------|
| `on_auth_user_created` | `AFTER INSERT ON auth.users` | `handle_new_user()` | Auto-create profile on signup |
| `on_auth_user_updated` | `AFTER UPDATE ON auth.users` | `handle_user_updated()` | Update profile when linking Google |
## Client-Side Storage (localStorage)
| Key | Type | Purpose |
|-----|------|---------|
| `bayan_editor_draft` | `string (HTML)` | Unsaved editor content |
| `bayan_dismissed_words` | `JSON array` | Words marked "keep as-is" |
| `bayan_word_goal` | `number` | Word count target |
| `bayan_theme` | `string` | "dark" or "light" |