feat: implement auth, projects, and frontend foundation
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-17
|
||||
@@ -0,0 +1,3 @@
|
||||
# database-models
|
||||
|
||||
Implement SQLAlchemy models and Alembic migrations for all core entities
|
||||
@@ -0,0 +1,125 @@
|
||||
# Design: Database Models
|
||||
|
||||
## Technology Choices
|
||||
|
||||
- **SQLAlchemy 2.0**: Modern async ORM with type annotations
|
||||
- **asyncpg**: High-performance async PostgreSQL driver
|
||||
- **Alembic**: Database migration tool
|
||||
- **UUID**: All primary keys use UUID for distributed safety
|
||||
|
||||
## Architecture
|
||||
|
||||
### Base Model
|
||||
|
||||
All models inherit from a common base with:
|
||||
- `id`: UUID primary key (default=uuid4)
|
||||
- `created_at`: Timestamp
|
||||
- `updated_at`: Timestamp (auto-updated)
|
||||
|
||||
### Models
|
||||
|
||||
1. **User**
|
||||
- id: UUID PK
|
||||
- email: str, unique, indexed
|
||||
- name: str
|
||||
- authentik_id: str, unique (external auth reference)
|
||||
- avatar_url: str | None
|
||||
- created_at, updated_at
|
||||
|
||||
2. **Project**
|
||||
- id: UUID PK
|
||||
- name: str
|
||||
- description: str | None
|
||||
- owner_id: UUID → User
|
||||
- default_ssh_key_id: UUID → SSHKey | None
|
||||
- created_at, updated_at
|
||||
|
||||
3. **GitRepository**
|
||||
- id: UUID PK
|
||||
- name: str
|
||||
- path: str (filesystem path to bare repo)
|
||||
- project_id: UUID → Project
|
||||
- owner_id: UUID → User
|
||||
- is_mirror: bool
|
||||
- remote_url: str | None
|
||||
- last_push: datetime | None
|
||||
- created_at
|
||||
|
||||
4. **SSHKey**
|
||||
- id: UUID PK
|
||||
- name: str
|
||||
- public_key: str
|
||||
- private_key_encrypted: str (Fernet encrypted)
|
||||
- user_id: UUID → User
|
||||
- project_id: UUID → Project | None
|
||||
- created_at
|
||||
|
||||
5. **UserConfig**
|
||||
- id: UUID PK
|
||||
- user_id: UUID → User
|
||||
- config: JSONB (PostgreSQL native JSON)
|
||||
- created_at, updated_at
|
||||
|
||||
### Relationships
|
||||
|
||||
```
|
||||
User 1--N Project
|
||||
User 1--N SSHKey
|
||||
User 1--1 UserConfig
|
||||
Project 1--N GitRepository
|
||||
Project N--1 SSHKey (default_ssh_key)
|
||||
```
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
apps/api/
|
||||
├── src/
|
||||
│ ├── models/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base.py # DeclarativeBase + common columns
|
||||
│ │ ├── user.py
|
||||
│ │ ├── project.py
|
||||
│ │ ├── git_repository.py
|
||||
│ │ ├── ssh_key.py
|
||||
│ │ └── user_config.py
|
||||
│ ├── database.py # Async engine + session
|
||||
│ └── config.py # Settings with pydantic-settings
|
||||
├── alembic/
|
||||
│ ├── env.py
|
||||
│ ├── script.py.mako
|
||||
│ └── versions/
|
||||
│ └── 001_initial.py
|
||||
├── tests/
|
||||
│ └── test_models.py
|
||||
└── scripts/
|
||||
└── seed.py
|
||||
```
|
||||
|
||||
## Async Pattern
|
||||
|
||||
```python
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
engine = create_async_engine(DATABASE_URL)
|
||||
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession)
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
- Single initial migration creating all tables
|
||||
- Future migrations use `alembic revision --autogenerate`
|
||||
- Run with `make migrate` (docker compose exec api alembic upgrade head)
|
||||
|
||||
## Seed Data
|
||||
|
||||
- Create a test user with sample data
|
||||
- Run via `docker compose exec api python scripts/seed.py`
|
||||
|
||||
## Quality Gates
|
||||
|
||||
- pytest with async test support
|
||||
- mypy strict mode
|
||||
- ruff for linting
|
||||
- All models have type annotations
|
||||
@@ -0,0 +1,28 @@
|
||||
# Proposal: Database Models
|
||||
|
||||
## What
|
||||
|
||||
Implement SQLAlchemy 2.0 async models and Alembic migrations for all core entities in the Headquarter platform.
|
||||
|
||||
## Why
|
||||
|
||||
All other features (auth, git repos, projects, SSH keys, etc.) depend on a solid database foundation. We need models that:
|
||||
- Use SQLAlchemy 2.0 async style for performance
|
||||
- Support all entity relationships defined in the specs
|
||||
- Have proper migrations for schema versioning
|
||||
- Include seed data for development
|
||||
|
||||
## Scope
|
||||
|
||||
- User, Project, GitRepository, SSHKey, UserConfig models
|
||||
- Alembic setup with asyncpg support
|
||||
- Initial migration creating all tables
|
||||
- Database seeding script
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- All models defined with correct relationships
|
||||
- Initial migration runs successfully
|
||||
- `make migrate` works
|
||||
- Seed script creates test data
|
||||
- Quality gates pass (pytest, mypy, ruff)
|
||||
@@ -0,0 +1,64 @@
|
||||
# Tasks: Database Models
|
||||
|
||||
## Task 1: Create project structure and configuration
|
||||
- [x] Create `apps/api/src/models/__init__.py`
|
||||
- [x] Create `apps/api/src/config.py` with pydantic-settings for database URL
|
||||
- [x] Create `apps/api/src/database.py` with async engine and session
|
||||
|
||||
## Task 2: Create base model
|
||||
- [x] Create `apps/api/src/models/base.py` with DeclarativeBase
|
||||
- [x] Add UUID primary key mixin
|
||||
- [x] Add timestamp mixin (created_at, updated_at)
|
||||
|
||||
## Task 3: Create User model
|
||||
- [x] Create `apps/api/src/models/user.py`
|
||||
- [x] Define User with all fields from spec
|
||||
- [x] Add relationships to Project, SSHKey, UserConfig
|
||||
|
||||
## Task 4: Create Project model
|
||||
- [x] Create `apps/api/src/models/project.py`
|
||||
- [x] Define Project with all fields
|
||||
- [x] Add relationships to User, GitRepository, SSHKey
|
||||
|
||||
## Task 5: Create GitRepository model
|
||||
- [x] Create `apps/api/src/models/git_repository.py`
|
||||
- [x] Define GitRepository with all fields
|
||||
- [x] Add relationships to Project, User
|
||||
|
||||
## Task 6: Create SSHKey model
|
||||
- [x] Create `apps/api/src/models/ssh_key.py`
|
||||
- [x] Define SSHKey with all fields
|
||||
- [x] Add relationships to User, Project
|
||||
|
||||
## Task 7: Create UserConfig model
|
||||
- [x] Create `apps/api/src/models/user_config.py`
|
||||
- [x] Define UserConfig with JSONB config field
|
||||
- [x] Add relationship to User
|
||||
|
||||
## Task 8: Initialize Alembic
|
||||
- [x] Create Alembic scaffolding equivalent to `alembic init`
|
||||
- [x] Configure `alembic/env.py` for async
|
||||
- [x] Update `alembic.ini` with correct URL
|
||||
|
||||
## Task 9: Create initial migration
|
||||
- [x] Generate migration creating all tables
|
||||
- [x] Verify migration is correct
|
||||
|
||||
## Task 10: Create seed script
|
||||
- [x] Create `apps/api/src/scripts/seed.py`
|
||||
- [x] Add test user and sample data payload helper
|
||||
- [x] Make script runnable
|
||||
|
||||
## Task 11: Create tests
|
||||
- [x] Create `apps/api/tests/test_models.py`
|
||||
- [x] Test model creation and relationships
|
||||
- [x] Test async database operations
|
||||
|
||||
## Task 12: Run quality gates
|
||||
- [x] Run `pytest` - all tests pass
|
||||
- [x] Run `mypy .` - no type errors
|
||||
- [x] Run `ruff check .` - no lint errors
|
||||
|
||||
## Runtime Verification
|
||||
|
||||
- [x] Run migrations against a live PostgreSQL instance to verify end-to-end database execution.
|
||||
Reference in New Issue
Block a user