# 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
