Create wiki page 'Database Schema'
123
Database-Schema.md
Normal file
123
Database-Schema.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Database Schema
|
||||
|
||||
PostgreSQL. UUIDs as primary keys to prevent enumeration and ease future federation. All timestamps include timezone (`TIMESTAMPTZ`).
|
||||
|
||||
## ERD (simplified)
|
||||
|
||||
```
|
||||
users ──< thoughts ──< thought_tags >── tags
|
||||
│
|
||||
├──< follows
|
||||
├──< top_friends
|
||||
└──< api_keys
|
||||
```
|
||||
|
||||
## Tables
|
||||
|
||||
### `users`
|
||||
|
||||
Stores user account and profile data.
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `id` | UUID | PK, DEFAULT gen_random_uuid() | Unique user identifier |
|
||||
| `username` | VARCHAR(32) | NOT NULL, UNIQUE | User handle |
|
||||
| `email` | VARCHAR(255) | NOT NULL, UNIQUE | Email address |
|
||||
| `password_hash` | TEXT | NOT NULL | Argon2 or bcrypt hash |
|
||||
| `display_name` | VARCHAR(50) | NULL | Public display name |
|
||||
| `bio` | VARCHAR(160) | NULL | Public biography |
|
||||
| `avatar_url` | TEXT | NULL | URL to avatar image |
|
||||
| `header_url` | TEXT | NULL | URL to header/banner image |
|
||||
| `custom_css` | TEXT | NULL | Custom profile CSS (sanitized) |
|
||||
| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | Account creation time |
|
||||
| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | Last profile update |
|
||||
|
||||
---
|
||||
|
||||
### `thoughts`
|
||||
|
||||
Stores the content of each post.
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `id` | UUID | PK, DEFAULT gen_random_uuid() | Unique thought identifier |
|
||||
| `user_id` | UUID | NOT NULL, FK → users(id) | Author |
|
||||
| `content` | VARCHAR(128) | NOT NULL | Post text |
|
||||
| `reply_to` | UUID | NULL, FK → thoughts(id) | Parent thought (if reply) |
|
||||
| `visibility` | ENUM | NOT NULL, DEFAULT 'public' | `public`, `followers`, `private` |
|
||||
| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | Post timestamp |
|
||||
|
||||
---
|
||||
|
||||
### `follows`
|
||||
|
||||
Join table for the follower/following relationship.
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `follower_id` | UUID | NOT NULL, FK → users(id) | User who follows |
|
||||
| `following_id` | UUID | NOT NULL, FK → users(id) | User being followed |
|
||||
| | | PK (follower_id, following_id) | Prevents duplicate follows |
|
||||
|
||||
---
|
||||
|
||||
### `top_friends`
|
||||
|
||||
Ordered "Top Friends" list per user (up to 8 entries).
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `user_id` | UUID | NOT NULL, FK → users(id) | Owner of the list |
|
||||
| `friend_id` | UUID | NOT NULL, FK → users(id) | Friend being displayed |
|
||||
| `position` | SMALLINT | NOT NULL | Display order (1–8) |
|
||||
| | | PK (user_id, friend_id) | No duplicates |
|
||||
| | | UNIQUE (user_id, position) | No duplicate positions |
|
||||
|
||||
---
|
||||
|
||||
### `tags`
|
||||
|
||||
Unique hashtag names.
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `id` | SERIAL | PK | Tag identifier |
|
||||
| `name` | VARCHAR(50) | NOT NULL, UNIQUE | Tag name (e.g. `welcome`) |
|
||||
|
||||
---
|
||||
|
||||
### `thought_tags`
|
||||
|
||||
Many-to-many join between thoughts and tags.
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `thought_id` | UUID | NOT NULL, FK → thoughts(id) | The thought |
|
||||
| `tag_id` | INTEGER | NOT NULL, FK → tags(id) | The tag |
|
||||
| | | PK (thought_id, tag_id) | No duplicate tags per post |
|
||||
|
||||
---
|
||||
|
||||
### `api_keys`
|
||||
|
||||
Hashed API keys for third-party access.
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|---|---|---|---|
|
||||
| `id` | UUID | PK, DEFAULT gen_random_uuid() | Key identifier |
|
||||
| `user_id` | UUID | NOT NULL, FK → users(id) | Owning user |
|
||||
| `key_hash` | TEXT | NOT NULL, UNIQUE | Hashed key value |
|
||||
| `name` | VARCHAR(50) | NOT NULL | User-provided label |
|
||||
| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | Creation timestamp |
|
||||
|
||||
## Migrations
|
||||
|
||||
Migrations are managed by **SeaORM** in the `thoughts-backend/migration/` crate.
|
||||
|
||||
```bash
|
||||
# Run pending migrations
|
||||
cd thoughts-backend
|
||||
cargo run -p migration
|
||||
```
|
||||
|
||||
Migration files follow the naming pattern `m{YYYYMMDD}_{HHMMSS}_{description}.rs`.
|
||||
Reference in New Issue
Block a user