generated from coulomb/repo-seed
361 lines
12 KiB
Markdown
361 lines
12 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
**DirektVermittlungDe (DVD)** is a document-centric communication platform between citizens and German authorities. It eliminates the "phone hunt" by:
|
|
1. Citizens upload a document or provide an *Aktenzeichen* (reference number)
|
|
2. The system auto-routes to the responsible unit
|
|
3. Opens an interaction thread for direct clarification
|
|
|
|
## Current Development Status
|
|
|
|
**⚠️ IMPORTANT**: This repository is currently in transition from prototype phase to main production codebase.
|
|
|
|
- **Current State**: Three prototype implementations (chatgpt5, geminiNbt3pro, grok4.1) in `/prototype-*` directories
|
|
- **Target State**: Unified production codebase in `/src` with TDD-driven development
|
|
- **Active Workplan**: See `docs/WORKPLAN_MainCodebase_Integration.md` for detailed migration plan
|
|
|
|
**When working on this codebase:**
|
|
- Check the workplan to understand which phase we're in
|
|
- Follow TDD practices: write tests first, then implementation
|
|
- Reference ADRs for architectural decisions (see below)
|
|
- New code goes in `/src`, not prototypes
|
|
|
|
## Repository Structure (Target State)
|
|
|
|
```
|
|
/
|
|
├── docs/
|
|
│ ├── architecture/
|
|
│ │ ├── adr/ # Individual ADR files (0001-*.md)
|
|
│ │ │ ├── 0001-split-payload-model.md
|
|
│ │ │ ├── 0002-stateless-authentication.md
|
|
│ │ │ └── ...
|
|
│ │ ├── architecture-overview.md
|
|
│ │ └── design-patterns.md
|
|
│ ├── api/
|
|
│ │ ├── openapi.yaml
|
|
│ │ └── api-scenarios.md
|
|
│ ├── development/
|
|
│ │ ├── testing-strategy.md
|
|
│ │ ├── agentic-coding-guide.md
|
|
│ │ └── setup-guide.md
|
|
│ └── WORKPLAN_MainCodebase_Integration.md
|
|
├── src/
|
|
│ ├── domain/ # Pure business logic (TDD tested)
|
|
│ ├── adapters/ # External integrations (mocked in tests)
|
|
│ ├── service/ # Application services (TDD tested)
|
|
│ ├── api/ # FastAPI routes (integration tested)
|
|
│ └── workers/ # Background jobs
|
|
├── tests/
|
|
│ ├── unit/ # TDD unit tests
|
|
│ ├── integration/ # Integration tests
|
|
│ └── fixtures/ # Test data and mocks
|
|
├── scripts/ # Utility scripts
|
|
├── prototype-*/ # ARCHIVED prototypes (reference only)
|
|
├── pyproject.toml # Dependencies & tool config
|
|
└── pytest.ini # Test configuration
|
|
```
|
|
|
|
## Development Commands
|
|
|
|
### Setup and Run (Main Codebase)
|
|
|
|
```bash
|
|
# Install dependencies (from repo root)
|
|
pip install -e ".[dev]"
|
|
|
|
# Initialize database metadata
|
|
python -m scripts.init_db
|
|
|
|
# Run development server
|
|
uvicorn src.main:app --reload
|
|
|
|
# View API docs
|
|
# http://localhost:8000/docs
|
|
```
|
|
|
|
### Testing (TDD Workflow)
|
|
|
|
```bash
|
|
# Run all tests
|
|
pytest
|
|
|
|
# Run with coverage report
|
|
pytest --cov=src --cov-report=html
|
|
|
|
# Run only unit tests
|
|
pytest tests/unit/
|
|
|
|
# Run only integration tests
|
|
pytest tests/integration/
|
|
|
|
# Run specific test file
|
|
pytest tests/unit/domain/test_document_metadata.py -v
|
|
|
|
# Watch mode (requires pytest-watch)
|
|
ptw
|
|
```
|
|
|
|
### Code Quality
|
|
|
|
```bash
|
|
# Lint and format with ruff
|
|
ruff check src/ tests/
|
|
ruff format src/ tests/
|
|
|
|
# Type checking with mypy
|
|
mypy src/
|
|
|
|
# Run pre-commit hooks manually
|
|
pre-commit run --all-files
|
|
```
|
|
|
|
## Key Architectural Patterns
|
|
|
|
### 1. Split-Payload Model (ADR-001)
|
|
|
|
**Critical**: Documents use a split design to enable both encryption and routing:
|
|
- **metadata** (plaintext JSON): authorityId, referenceNumber, docType, issuedAt
|
|
- **encryptedPayload** (encrypted blob): actual PDF/scan content
|
|
|
|
The backend can route based on metadata without decrypting the payload. This is the core architectural constraint.
|
|
|
|
When working with documents:
|
|
- NEVER attempt to decrypt `encryptedPayload` in the main service
|
|
- The backend treats encrypted content as opaque
|
|
- Routing logic operates only on metadata fields
|
|
|
|
### 2. Hybrid Concurrency Pattern (ADR-007)
|
|
|
|
Python's GIL requires careful concurrency handling:
|
|
- **I/O operations** (DB, network): Use native `async`/`await`
|
|
- **CPU operations** (crypto, PDF): Offload to `ProcessPoolExecutor`
|
|
|
|
Example pattern:
|
|
```python
|
|
cpu_pool = ProcessPoolExecutor(max_workers=4)
|
|
|
|
async def handler():
|
|
# I/O: async/await
|
|
data = await db.fetch()
|
|
|
|
# CPU: executor
|
|
loop = asyncio.get_running_loop()
|
|
result = await loop.run_in_executor(cpu_pool, heavy_function, data)
|
|
```
|
|
|
|
### 3. Cursor-Based Pagination (ADR-003)
|
|
|
|
For message threads, use cursor-based pagination (timestamp) instead of offset-based:
|
|
- Ensures consistent performance regardless of thread length
|
|
- Prevents duplicate/missing messages during real-time updates
|
|
- Target: <300ms response time (NFR-1)
|
|
|
|
### 4. Async Export Pattern (ADR-004)
|
|
|
|
Data exports use async request-reply:
|
|
1. POST `/exports` → 202 Accepted + jobId
|
|
2. Background worker processes via message queue
|
|
3. Client polls status endpoint or receives webhook
|
|
|
|
### 5. Stateless Authentication (ADR-002)
|
|
|
|
OAuth2/JWT with scopes:
|
|
- `citizen:write`: Document submission, thread creation
|
|
- `official:read`: View assigned cases
|
|
- `official:write`: Respond to inquiries
|
|
|
|
JWTs enable horizontal scaling without session affinity.
|
|
|
|
### 6. GDPR-Compliant Retention (ADR-006)
|
|
|
|
Documents have `retention_date` field:
|
|
- Default: `closedAt + gracePeriod`
|
|
- Personal archive: `null` or extended date
|
|
- Automated cleanup via TTL engine
|
|
|
|
## API Structure
|
|
|
|
The API follows document-centric REST hierarchy:
|
|
- `/documents` - Root envelope (FR-1: Document intake)
|
|
- `/documents/{id}/threads` - Sub-resource for communication (FR-3)
|
|
- `/threads/{threadId}/messages` - Message exchange
|
|
- `/exports` - Async data export for authority systems (FR-7)
|
|
|
|
## Critical Domain Models
|
|
|
|
Located in `src/domain/models.py` (target) or `prototype-chatgpt5/src/app/domain/models.py` (reference):
|
|
|
|
**Enums:**
|
|
- **ThreadType**: TEXT_CHAT, CALLBACK_REQUEST, APPOINTMENT
|
|
- **SenderRole**: CITIZEN, OFFICIAL, SYSTEM
|
|
- **ExportJobStatus**: QUEUED, RUNNING, COMPLETED, FAILED
|
|
|
|
**Core Models:**
|
|
- **DocumentMetadata**: authorityId, referenceNumber, docType, issuedAt
|
|
- Validation: authorityId (1-50 chars), referenceNumber required
|
|
- **DocumentCreateRequest**: metadata, encryptedPayload (base64)
|
|
- **DocumentCreatedResponse**: id, status, assignedUnit
|
|
- **ThreadCreateRequest**: type, initialMessage, preferredTimeSlot
|
|
- **MessageDto**: id, senderRole, content (encrypted), timestamp
|
|
|
|
## Performance Targets (NFR)
|
|
|
|
- Core operations: <300ms response time
|
|
- Document upload routing: <500ms
|
|
- Concurrent sessions: 10k+ per region
|
|
- Availability: ≥99.5%
|
|
|
|
## Security Constraints
|
|
|
|
- E2E encryption required for sensitive data (NFR-5)
|
|
- Backend cannot decrypt document payloads
|
|
- Least-privilege access via OAuth scopes (NFR-6)
|
|
- No PII in plaintext application logs
|
|
|
|
## TDD Development Workflow
|
|
|
|
**CRITICAL**: This project follows a strict Test-Driven Development approach.
|
|
|
|
### The Red-Green-Refactor Cycle
|
|
|
|
1. **RED**: Write a failing test that defines desired behavior
|
|
2. **GREEN**: Write minimal code to make the test pass
|
|
3. **REFACTOR**: Improve code while keeping tests green
|
|
|
|
### Example TDD Workflow
|
|
|
|
```python
|
|
# Step 1: Write failing test (tests/unit/domain/test_document_metadata.py)
|
|
def test_document_metadata_validates_authority_id():
|
|
with pytest.raises(ValidationError):
|
|
DocumentMetadata(
|
|
authorityId="", # Empty should fail
|
|
referenceNumber="123/456",
|
|
docType="NOTICE",
|
|
issuedAt=datetime.now()
|
|
)
|
|
|
|
# Step 2: Run test (it fails)
|
|
# $ pytest tests/unit/domain/test_document_metadata.py
|
|
|
|
# Step 3: Implement validation (src/domain/models.py)
|
|
class DocumentMetadata(BaseModel):
|
|
authorityId: str = Field(..., min_length=1, max_length=50)
|
|
# ... rest of fields
|
|
|
|
# Step 4: Run test again (it passes)
|
|
|
|
# Step 5: Refactor if needed, ensure tests still pass
|
|
```
|
|
|
|
### Agentic TDD Pattern
|
|
|
|
When asking Claude to implement features, use this pattern:
|
|
|
|
```
|
|
"Write a test for [feature] that verifies [specific behavior].
|
|
Use pytest and follow the pattern in tests/unit/[module]/.
|
|
Reference ADR-[number] for architectural constraints."
|
|
```
|
|
|
|
Example:
|
|
```
|
|
"Write a test for document routing that verifies documents with docType='NOTICE'
|
|
are routed to the NoticeTeam. Mock the routing adapter using the protocol defined
|
|
in src/adapters/protocols.py. Follow ADR-0001 split-payload constraints."
|
|
```
|
|
|
|
See `docs/development/agentic-coding-guide.md` for comprehensive examples.
|
|
|
|
## Documentation References
|
|
|
|
### Architecture & Decisions
|
|
- **Workplan**: `docs/WORKPLAN_MainCodebase_Integration.md` - Current migration plan
|
|
- **ADRs**: `docs/architecture/adr/` - Individual decision records
|
|
- `0001-split-payload-model.md` - Core constraint: metadata vs encrypted payload
|
|
- `0002-stateless-authentication.md` - OAuth2/JWT architecture
|
|
- `0003-cursor-based-pagination.md` - Performance-optimized pagination
|
|
- `0004-async-export-workflow.md` - Background job pattern
|
|
- `0005-rest-resource-structure.md` - API design hierarchy
|
|
- `0006-gdpr-retention-model.md` - Data lifecycle management
|
|
- `0007-hybrid-concurrency-pattern.md` - Python GIL mitigation
|
|
- `0008-agentic-tdd-workflow.md` - LLM-driven development process
|
|
- **Overview**: `docs/architecture/architecture-overview.md` - System design
|
|
- **Patterns**: `docs/architecture/design-patterns.md` - Common patterns
|
|
|
|
### API Documentation
|
|
- **OpenAPI**: `docs/api/openapi.yaml` - Full API specification
|
|
- **Scenarios**: `docs/api/api-scenarios.md` - Real-world usage examples
|
|
|
|
### Development Guides
|
|
- **Testing**: `docs/development/testing-strategy.md` - TDD practices
|
|
- **Agentic Coding**: `docs/development/agentic-coding-guide.md` - AI-assisted development
|
|
- **Setup**: `docs/development/setup-guide.md` - Environment setup
|
|
|
|
### Legacy (Prototypes)
|
|
- `prototype-chatgpt5/README.md` - Reference implementation (ARCHIVED)
|
|
- `docs/decisions.md` - Original ADRs (DEPRECATED, see /docs/architecture/adr/)
|
|
|
|
## Database Schema
|
|
|
|
Key tables (PostgreSQL):
|
|
- **documents**: id, reference_number, authority_id, status, storage_path, retention_date
|
|
- **threads**: id, document_id, type, assigned_official_id, last_activity_at
|
|
- **messages**: id, thread_id, sender_role, content_blob, created_at
|
|
|
|
Indexes:
|
|
- `idx_docs_authority` on documents(authority_id, status)
|
|
- `idx_msgs_thread_time` on messages(thread_id, created_at DESC)
|
|
|
|
## Technology Stack
|
|
|
|
- **Language**: Python 3.11+
|
|
- **Framework**: FastAPI + Uvicorn
|
|
- **ORM**: SQLAlchemy (async)
|
|
- **Database**: PostgreSQL 15+
|
|
- **Blob Storage**: S3-compatible (MinIO/AWS S3)
|
|
- **Task Queue**: ARQ (Redis-based, async) or Celery
|
|
- **Auth**: OAuth2/JWT (stateless)
|
|
- **Testing**: pytest + pytest-asyncio + pytest-cov
|
|
- **Linting**: ruff (fast, replaces flake8/isort/pyupgrade)
|
|
- **Type Checking**: mypy (strict mode)
|
|
- **CI/CD**: GitHub Actions
|
|
|
|
## Workplan & Phase Tracking
|
|
|
|
**Active Workplan**: `docs/WORKPLAN_MainCodebase_Integration.md`
|
|
|
|
### Current Phase Status
|
|
|
|
To check which phase we're in:
|
|
1. Open `docs/WORKPLAN_MainCodebase_Integration.md`
|
|
2. Look for checked `[x]` items in each phase section
|
|
3. Focus development on uncompleted `[ ]` items in the current phase
|
|
|
|
### How to Contribute
|
|
|
|
**Before implementing any feature:**
|
|
1. Check if it's in the current phase of the workplan
|
|
2. Read the relevant ADR(s) in `docs/architecture/adr/`
|
|
3. Write tests first (TDD approach)
|
|
4. Implement to make tests pass
|
|
5. Ensure all quality gates pass (pytest, mypy, ruff)
|
|
|
|
**When adding new architectural decisions:**
|
|
1. Create a new ADR file in `docs/architecture/adr/`
|
|
2. Use the template in `0000-template.md`
|
|
3. Number sequentially (next available number)
|
|
4. Update the ADR index in `docs/architecture/adr/README.md`
|
|
|
|
## Common Gotchas
|
|
|
|
1. **Stream large files**: Use `aiobotocore` to stream uploads to S3, don't load entire payloads into memory
|
|
2. **ProcessPoolExecutor**: CPU-heavy operations MUST be offloaded to avoid blocking the event loop
|
|
3. **Metadata separation**: The routing engine needs plaintext metadata - design API contracts accordingly
|
|
4. **Retention dates**: Always set `retention_date` on document creation for GDPR compliance
|
|
5. **Cursor pagination**: Use timestamp-based cursors for message history, not offset-based
|