232 lines
5.6 KiB
Markdown
232 lines
5.6 KiB
Markdown
# Data Model
|
|
|
|
This document describes the data model for the dalex-todo-proto application using Mermaid diagrams.
|
|
|
|
## Entity Relationship Diagram
|
|
|
|
```mermaid
|
|
erDiagram
|
|
USER ||--o{ TODO : owns
|
|
|
|
USER {
|
|
string id PK "Keycloak User ID"
|
|
string username "From Keycloak"
|
|
string email "From Keycloak"
|
|
}
|
|
|
|
TODO {
|
|
int id PK "Auto-increment primary key"
|
|
string userId FK "Reference to User (Keycloak ID)"
|
|
string title "Todo title (required)"
|
|
string description "Optional description"
|
|
datetime createdAt "Creation timestamp"
|
|
datetime completedAt "Completion timestamp (nullable)"
|
|
boolean isCompleted "Completion status"
|
|
}
|
|
```
|
|
|
|
## Database Schema
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class Todo {
|
|
+int Id
|
|
+string UserId
|
|
+string Title
|
|
+string Description
|
|
+DateTime CreatedAt
|
|
+DateTime CompletedAt
|
|
+bool IsCompleted
|
|
+GetAge() TimeSpan
|
|
+IsOld() bool
|
|
}
|
|
|
|
class TodoDbContext {
|
|
+DbSet~Todo~ Todos
|
|
+OnModelCreating(ModelBuilder)
|
|
}
|
|
|
|
TodoDbContext --> Todo : manages
|
|
```
|
|
|
|
## Data Flow Architecture
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
subgraph Client ["Frontend (Vue 3)"]
|
|
UI[User Interface]
|
|
KC_CLIENT[Keycloak Client]
|
|
API_CLIENT[API Client]
|
|
end
|
|
|
|
subgraph Keycloak ["Keycloak Server"]
|
|
AUTH[Authentication]
|
|
TOKEN[JWT Token Service]
|
|
end
|
|
|
|
subgraph Backend ["ASP.NET Core Backend"]
|
|
JWT_VALIDATE[JWT Validation]
|
|
API[REST API Endpoints]
|
|
BL[Business Logic]
|
|
end
|
|
|
|
subgraph Database ["SQLite Database"]
|
|
DB[(Todos Table)]
|
|
end
|
|
|
|
UI --> KC_CLIENT
|
|
KC_CLIENT <--> AUTH
|
|
AUTH --> TOKEN
|
|
TOKEN --> API_CLIENT
|
|
|
|
API_CLIENT --> JWT_VALIDATE
|
|
JWT_VALIDATE --> API
|
|
API --> BL
|
|
BL <--> DB
|
|
|
|
style Client fill:#e1f5ff
|
|
style Keycloak fill:#fff4e1
|
|
style Backend fill:#e8f5e9
|
|
style Database fill:#f3e5f5
|
|
```
|
|
|
|
## Todo Entity Details
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Nullable | Description |
|
|
|-------|------|----------|-------------|
|
|
| `Id` | int | No | Primary key, auto-increment |
|
|
| `UserId` | string | No | Keycloak user identifier (from JWT token) |
|
|
| `Title` | string | No | Todo title/summary |
|
|
| `Description` | string | Yes | Optional detailed description |
|
|
| `CreatedAt` | DateTime | No | UTC timestamp when todo was created |
|
|
| `CompletedAt` | DateTime | Yes | UTC timestamp when todo was marked complete |
|
|
| `IsCompleted` | bool | No | Completion status flag |
|
|
|
|
### Indexes
|
|
|
|
- **Primary Key**: `Id`
|
|
- **Index**: `UserId` (for efficient user-specific queries)
|
|
|
|
### Constraints
|
|
|
|
- `UserId` is required (enforced at database and application level)
|
|
- `Title` is required (enforced at database and application level)
|
|
- `CreatedAt` is automatically set on creation
|
|
- `CompletedAt` is set when `IsCompleted` changes to `true`
|
|
- `CompletedAt` is cleared when `IsCompleted` changes to `false`
|
|
|
|
## API Data Transfer Objects (DTOs)
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class TodoCreateDto {
|
|
+string Title
|
|
+string Description
|
|
}
|
|
|
|
class TodoUpdateDto {
|
|
+string Title
|
|
+string Description
|
|
+bool? IsCompleted
|
|
}
|
|
|
|
class Todo {
|
|
+int Id
|
|
+string UserId
|
|
+string Title
|
|
+string Description
|
|
+DateTime CreatedAt
|
|
+DateTime CompletedAt
|
|
+bool IsCompleted
|
|
}
|
|
|
|
TodoCreateDto ..> Todo : creates
|
|
TodoUpdateDto ..> Todo : updates
|
|
```
|
|
|
|
## Business Rules
|
|
|
|
### Sorting Logic
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
START[Get Todos for User]
|
|
SPLIT{Group by Status}
|
|
|
|
INCOMPLETE[Incomplete Todos]
|
|
COMPLETE[Complete Todos]
|
|
|
|
SORT_INC[Sort by CreatedAt ASC<br/>Oldest first]
|
|
SORT_COM[Sort by CompletedAt DESC<br/>Newest first]
|
|
|
|
FILTER{Show Older?}
|
|
HIDE[Hide todos completed<br/>> 1 week ago]
|
|
SHOW[Show all]
|
|
|
|
COMBINE[Combine Lists]
|
|
RESULT[Return Sorted List]
|
|
|
|
START --> SPLIT
|
|
SPLIT --> INCOMPLETE
|
|
SPLIT --> COMPLETE
|
|
|
|
INCOMPLETE --> SORT_INC
|
|
COMPLETE --> SORT_COM
|
|
|
|
SORT_INC --> COMBINE
|
|
SORT_COM --> FILTER
|
|
|
|
FILTER -->|No| HIDE
|
|
FILTER -->|Yes| SHOW
|
|
|
|
HIDE --> COMBINE
|
|
SHOW --> COMBINE
|
|
|
|
COMBINE --> RESULT
|
|
```
|
|
|
|
### User Isolation
|
|
|
|
- Each user can only see their own todos
|
|
- `UserId` is extracted from JWT token (Keycloak `sub` or `NameIdentifier` claim)
|
|
- All queries are filtered by `UserId`
|
|
- No cross-user data access is possible
|
|
|
|
## Storage
|
|
|
|
### SQLite Database
|
|
|
|
- **File Location**: `/app/data/todos.db` (in Docker container)
|
|
- **Persistence**: Docker volume `todolist-proto_backend-data`
|
|
- **Schema Management**: Entity Framework Core with automatic migration on startup
|
|
- **Connection String**: `Data Source=/app/data/todos.db`
|
|
|
|
### Table Structure
|
|
|
|
```sql
|
|
CREATE TABLE "Todos" (
|
|
"Id" INTEGER NOT NULL CONSTRAINT "PK_Todos" PRIMARY KEY AUTOINCREMENT,
|
|
"UserId" TEXT NOT NULL,
|
|
"Title" TEXT NOT NULL,
|
|
"Description" TEXT NULL,
|
|
"CreatedAt" TEXT NOT NULL,
|
|
"CompletedAt" TEXT NULL,
|
|
"IsCompleted" INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE INDEX "IX_Todos_UserId" ON "Todos" ("UserId");
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
1. **Authentication**: All API endpoints require valid JWT token from Keycloak
|
|
2. **Authorization**: Users can only access their own todos (enforced by UserId filtering)
|
|
3. **Data Validation**:
|
|
- Title is required
|
|
- UserId is required
|
|
- All inputs are validated before database operations
|
|
4. **SQL Injection**: Protected by Entity Framework Core parameterized queries
|
|
5. **CORS**: Restricted to frontend origin only (`http://localhost:3030`)
|