Spaces:
Running
Running
| # Data Model: Full-Stack Integration & UI Experience | |
| **Feature**: 002-fullstack-ui-integration | |
| **Date**: 2026-01-09 | |
| **Status**: Reference Only (No New Entities) | |
| ## Overview | |
| This feature does not introduce new data entities. It integrates and polishes existing functionality from Specs 1 (Task CRUD) and 2 (Authentication & API Security). This document references the existing data model for completeness. | |
| ## Existing Entities | |
| ### User (from Spec 2: Authentication & API Security) | |
| **Purpose**: Represents an authenticated user with task management capabilities | |
| **Attributes**: | |
| - `id` (integer, primary key): Unique identifier for the user | |
| - `email` (string, unique, required): User's email address for authentication | |
| - `name` (string, required): User's display name | |
| - `password_hash` (string, required): Bcrypt-hashed password (never exposed in API) | |
| - `created_at` (datetime, auto): Timestamp of account creation | |
| - `updated_at` (datetime, auto): Timestamp of last profile update | |
| **Relationships**: | |
| - One-to-Many with Task: A user can have multiple tasks | |
| **Validation Rules**: | |
| - Email must be valid RFC 5322 format | |
| - Email must be unique across all users | |
| - Password must be at least 8 characters with uppercase, lowercase, and number | |
| - Name must be 1-100 characters | |
| **Security**: | |
| - Password is hashed with bcrypt (cost factor 12) before storage | |
| - Password hash is never returned in API responses | |
| - User ID is extracted from JWT token for all authenticated requests | |
| **Database Table**: `users` | |
| **Indexes**: | |
| - Primary key on `id` | |
| - Unique index on `email` | |
| **Source**: `backend/src/models/user.py` | |
| --- | |
| ### Task (from Spec 1: Task CRUD) | |
| **Purpose**: Represents a todo item belonging to a specific user | |
| **Attributes**: | |
| - `id` (integer, primary key): Unique identifier for the task | |
| - `user_id` (integer, foreign key, required): Owner of the task (references User.id) | |
| - `title` (string, required): Task title (max 200 characters) | |
| - `description` (string, optional): Task description (max 1000 characters) | |
| - `completed` (boolean, default false): Completion status | |
| - `created_at` (datetime, auto): Timestamp of task creation | |
| - `updated_at` (datetime, auto): Timestamp of last task update | |
| **Relationships**: | |
| - Many-to-One with User: Each task belongs to exactly one user | |
| **Validation Rules**: | |
| - Title is required and must be 1-200 characters | |
| - Description is optional, max 1000 characters | |
| - Completed defaults to false | |
| - User ID must reference an existing user | |
| **Business Rules**: | |
| - Users can only access their own tasks (enforced by JWT authentication) | |
| - Tasks are automatically filtered by authenticated user_id in all queries | |
| - Deleting a user cascades to delete all their tasks | |
| **Database Table**: `tasks` | |
| **Indexes**: | |
| - Primary key on `id` | |
| - Index on `user_id` (for filtering by user) | |
| - Index on `completed` (for filtering by status) | |
| - Composite index on `(user_id, completed)` (for combined filtering) | |
| - Index on `created_at` (for sorting) | |
| **Source**: `backend/src/models/task.py` | |
| --- | |
| ### AuthSession (Frontend Only - from Spec 2) | |
| **Purpose**: Client-side session state for authenticated users | |
| **Attributes**: | |
| - `token` (string, nullable): JWT token from backend | |
| - `user` (object, nullable): User profile information | |
| - `id` (integer): User ID | |
| - `email` (string): User email | |
| - `name` (string): User display name | |
| **Storage**: Browser localStorage (key: `auth_session`) | |
| **Lifecycle**: | |
| - Created on successful signin (POST /api/auth/signin) | |
| - Persisted across page refreshes | |
| - Cleared on signout or 401 Unauthorized response | |
| - Expires when JWT token expires (7 days) | |
| **Security**: | |
| - Token is included in Authorization header for all API requests | |
| - Session is cleared on any authentication error | |
| - No sensitive data stored (password never stored client-side) | |
| **Source**: `frontend/src/lib/auth.ts` | |
| --- | |
| ## Entity Relationships | |
| ``` | |
| User (1) ----< (Many) Task | |
| | | |
| | JWT Token (stateless) | |
| | | |
| v | |
| AuthSession (Frontend) | |
| ``` | |
| **Relationship Details**: | |
| 1. **User → Task** (One-to-Many): | |
| - A user can have zero or more tasks | |
| - Each task belongs to exactly one user | |
| - Foreign key: `Task.user_id` references `User.id` | |
| - Cascade delete: Deleting a user deletes all their tasks | |
| 2. **User → AuthSession** (Stateless): | |
| - JWT token contains user_id and email | |
| - No server-side session storage | |
| - Frontend stores token and user profile in localStorage | |
| - Token is verified on every API request | |
| ## Data Flow | |
| ### Authentication Flow | |
| ``` | |
| 1. User signs up/signs in | |
| ↓ | |
| 2. Backend creates JWT token with user_id | |
| ↓ | |
| 3. Frontend stores token + user profile in AuthSession | |
| ↓ | |
| 4. Frontend includes token in Authorization header | |
| ↓ | |
| 5. Backend verifies token and extracts user_id | |
| ↓ | |
| 6. Backend filters all queries by user_id | |
| ``` | |
| ### Task Management Flow | |
| ``` | |
| 1. User creates/updates/deletes task | |
| ↓ | |
| 2. Frontend sends request with JWT token | |
| ↓ | |
| 3. Backend verifies token → extracts user_id | |
| ↓ | |
| 4. Backend performs operation (filtered by user_id) | |
| ↓ | |
| 5. Backend returns result | |
| ↓ | |
| 6. Frontend updates UI (optimistic or after response) | |
| ``` | |
| ## Data Isolation | |
| **Critical Security Requirement**: All task queries MUST be filtered by authenticated user_id | |
| **Implementation**: | |
| - JWT token contains user_id in 'sub' claim | |
| - `get_current_user()` dependency extracts user_id from token | |
| - All task endpoints use `current_user_id = Depends(get_current_user)` | |
| - SQLModel queries include `.where(Task.user_id == current_user_id)` | |
| **Verification**: | |
| - User A cannot access User B's tasks | |
| - API returns 404 (not 403) for unauthorized task access | |
| - No data leakage through error messages | |
| ## State Transitions | |
| ### Task State Transitions | |
| ``` | |
| [New Task] | |
| ↓ | |
| [Active] ←→ [Completed] | |
| ↓ | |
| [Deleted] | |
| ``` | |
| **Transitions**: | |
| - New → Active: Task created with `completed=false` | |
| - Active → Completed: User marks task as done (`completed=true`) | |
| - Completed → Active: User marks task as not done (`completed=false`) | |
| - Any → Deleted: User deletes task (hard delete from database) | |
| **No Soft Deletes**: Tasks are permanently deleted (no `deleted_at` field) | |
| ### User State Transitions | |
| ``` | |
| [New User] | |
| ↓ | |
| [Active] | |
| ↓ | |
| [Deleted] (future - not implemented) | |
| ``` | |
| **Current Implementation**: | |
| - New → Active: User signs up successfully | |
| - No user deletion implemented yet (out of scope) | |
| ## Schema Migrations | |
| **Existing Migrations**: | |
| 1. `001_initial.py`: Created users and tasks tables (Spec 1) | |
| 2. `002_add_user_password.py`: Added password_hash to users table (Spec 2) | |
| **No New Migrations Required**: This feature does not modify the database schema | |
| ## Data Validation | |
| ### Backend Validation (Pydantic Schemas) | |
| **User Validation** (`backend/src/schemas/auth.py`): | |
| - Email: RFC 5322 format validation | |
| - Password: Min 8 chars, uppercase, lowercase, number | |
| - Name: 1-100 characters | |
| **Task Validation** (`backend/src/schemas/task.py`): | |
| - Title: Required, 1-200 characters | |
| - Description: Optional, max 1000 characters | |
| - Completed: Boolean (defaults to false) | |
| ### Frontend Validation | |
| **Client-Side Validation**: | |
| - Email format validation (regex) | |
| - Password strength validation (min 8 chars, complexity) | |
| - Form field required/optional indicators | |
| - Inline error messages | |
| **Note**: Backend validation is authoritative - frontend validation is for UX only | |
| ## Performance Considerations | |
| **Indexes** (already implemented): | |
| - `users.email` (unique): Fast user lookup during signin | |
| - `tasks.user_id`: Fast filtering of user's tasks | |
| - `tasks.completed`: Fast filtering by completion status | |
| - `tasks.(user_id, completed)`: Fast combined filtering | |
| - `tasks.created_at`: Fast sorting by creation date | |
| **Query Patterns**: | |
| - Most common: Get all tasks for user (filtered by user_id) | |
| - Second most common: Get active/completed tasks for user | |
| - Sorting: By created_at or updated_at | |
| **No N+1 Queries**: All queries are direct (no nested loops) | |
| ## Summary | |
| This feature reuses the existing data model from Specs 1 and 2: | |
| - **User**: Authentication and ownership | |
| - **Task**: Todo items with user isolation | |
| - **AuthSession**: Frontend session state | |
| No new entities, relationships, or migrations are required. The focus is on UI integration and polish rather than data model changes. | |