feat(auth): add DB-backed login, token management, and idempotent auth migration
This commit is contained in:
+55
-7
@@ -5,12 +5,13 @@
|
||||
This document defines the database schema in an AI-agent-friendly format.
|
||||
|
||||
- Source of truth: Alembic revisions in `migrations/versions`
|
||||
- Current baseline revision: `20260403_0004`
|
||||
- Current baseline revision: `20260403_0005`
|
||||
- Baseline files:
|
||||
- `migrations/versions/20260403_0001_initial_portfolio_schema.py`
|
||||
- `migrations/versions/20260403_0002_strategy_set_columns.py`
|
||||
- `migrations/versions/20260403_0003_portfolio_strategy_refs.py`
|
||||
- `migrations/versions/20260403_0004_users_table.py`
|
||||
- `migrations/versions/20260403_0005_auth_user_fields_and_tokens.py`
|
||||
|
||||
## 2. Scope
|
||||
|
||||
@@ -18,6 +19,7 @@ Schema objects covered by baseline revision:
|
||||
|
||||
- `strategy_sets`
|
||||
- `users`
|
||||
- `auth_tokens`
|
||||
- `portfolios`
|
||||
- `portfolio_ledger`
|
||||
- secondary indexes
|
||||
@@ -45,8 +47,12 @@ Columns:
|
||||
| id | Text | NO | - | Primary Key |
|
||||
| username | Text | NO | - | Unique username |
|
||||
| email | Text | YES | - | Unique when present |
|
||||
| permission | Text | NO | "read" | User permission level |
|
||||
| is_active | Boolean | NO | TRUE | Whether login is allowed |
|
||||
| password_hash | Text | YES | - | Scrypt password hash |
|
||||
| created_at | DateTime(timezone=True) | NO | NOW() | Creation timestamp |
|
||||
| updated_at | DateTime(timezone=True) | NO | NOW() | Last update timestamp |
|
||||
| last_login_at | DateTime(timezone=True) | YES | - | Last successful login timestamp |
|
||||
|
||||
Constraints:
|
||||
|
||||
@@ -54,7 +60,34 @@ Constraints:
|
||||
- Unique: `uq_users_username` on (`username`)
|
||||
- Unique: `uq_users_email` on (`email`)
|
||||
|
||||
### 4.2 strategy_sets
|
||||
### 4.2 auth_tokens
|
||||
|
||||
Purpose:
|
||||
|
||||
- Stores DB-issued session tokens and client tokens.
|
||||
|
||||
Columns:
|
||||
|
||||
| Column | Type | Null | Default | Constraints / Notes |
|
||||
|---|---|---|---|---|
|
||||
| id | Text | NO | - | Primary Key |
|
||||
| user_id | Text | NO | - | Logical user reference |
|
||||
| name | Text | NO | - | Human-readable token name |
|
||||
| token_prefix | Text | NO | - | Display prefix for issued token |
|
||||
| token_hash | Text | NO | - | Unique SHA-256 token hash |
|
||||
| permission | Text | NO | - | Effective token permission |
|
||||
| token_type | Text | NO | - | `session` or `client` |
|
||||
| expires_at | DateTime(timezone=True) | YES | - | Expiration time |
|
||||
| last_used_at | DateTime(timezone=True) | YES | - | Last successful use |
|
||||
| revoked_at | DateTime(timezone=True) | YES | - | Revocation time |
|
||||
| created_at | DateTime(timezone=True) | NO | NOW() | Creation timestamp |
|
||||
|
||||
Constraints:
|
||||
|
||||
- Primary key: `id`
|
||||
- Unique: `uq_auth_tokens_token_hash` on (`token_hash`)
|
||||
|
||||
### 4.3 strategy_sets
|
||||
|
||||
Purpose:
|
||||
|
||||
@@ -76,7 +109,7 @@ Constraints:
|
||||
- Unique: `uq_strategy_sets_name_config` on (`name`, `config`)
|
||||
- Unique: `uq_strategy_sets_nick` on (`nick`)
|
||||
|
||||
### 4.3 portfolios
|
||||
### 4.4 portfolios
|
||||
|
||||
Purpose:
|
||||
|
||||
@@ -84,7 +117,7 @@ Purpose:
|
||||
|
||||
Current baseline note:
|
||||
|
||||
- The columns below describe the currently migrated schema through revision `20260403_0004`.
|
||||
- The columns below describe the currently migrated schema through revision `20260403_0005`.
|
||||
|
||||
Columns:
|
||||
|
||||
@@ -114,7 +147,7 @@ Constraint notes:
|
||||
- `active_strategy_id` is a nullable logical reference to `strategy_sets.id`
|
||||
- `avabile_strategies` stores zero or more selectable strategy set IDs when present
|
||||
|
||||
### 4.4 portfolio_ledger
|
||||
### 4.5 portfolio_ledger
|
||||
|
||||
Purpose:
|
||||
|
||||
@@ -152,14 +185,28 @@ Constraints:
|
||||
- Unique: no
|
||||
- Intent: speed operational listing by recency.
|
||||
|
||||
### 5.2 idx_portfolio_ledger_portfolio_time
|
||||
### 5.2 idx_auth_tokens_user_created
|
||||
|
||||
- Table: `auth_tokens`
|
||||
- Columns/expressions: (`user_id`, `created_at`)
|
||||
- Unique: no
|
||||
- Intent: fetch current user's issued tokens efficiently.
|
||||
|
||||
### 5.3 idx_auth_tokens_hash_active
|
||||
|
||||
- Table: `auth_tokens`
|
||||
- Columns/expressions: (`token_hash`)
|
||||
- Unique: no
|
||||
- Intent: resolve bearer tokens efficiently.
|
||||
|
||||
### 5.4 idx_portfolio_ledger_portfolio_time
|
||||
|
||||
- Table: `portfolio_ledger`
|
||||
- Columns/expressions: (`portfolio_id`, `recorded_at DESC`)
|
||||
- Unique: no
|
||||
- Intent: fetch recent ledger entries per portfolio efficiently.
|
||||
|
||||
### 5.3 idx_portfolios_broker_status_updated
|
||||
### 5.5 idx_portfolios_broker_status_updated
|
||||
|
||||
- Table: `portfolios`
|
||||
- Columns/expressions: (`broker`, `status`, `updated_at DESC`)
|
||||
@@ -202,3 +249,4 @@ When schema changes:
|
||||
| 20260403_0002 | migrations/versions/20260403_0002_strategy_set_columns.py | Rename `strategy_name`->`name`, `strategy_config`->`config`, add unique `nick`, handle legacy unnamed unique constraint |
|
||||
| 20260403_0003 | migrations/versions/20260403_0003_portfolio_strategy_refs.py | Remove embedded portfolio strategy fields, add `active_strategy_id` and `avabile_strategies` |
|
||||
| 20260403_0004 | migrations/versions/20260403_0004_users_table.py | Add `users` table with unique username/email and created_at index |
|
||||
| 20260403_0005 | migrations/versions/20260403_0005_auth_user_fields_and_tokens.py | Add password/permission/login fields to `users` and create `auth_tokens` table |
|
||||
|
||||
Reference in New Issue
Block a user