Files
finance_bot/docs/ARCHITECTURE.md
2025-12-10 22:09:31 +09:00

636 lines
19 KiB
Markdown

# 🏗️ API-First Zero-Trust Architecture - Complete Guide
## 📋 Table of Contents
1. [Architecture Overview](#architecture-overview)
2. [Security Model](#security-model)
3. [Authentication Flows](#authentication-flows)
4. [RBAC & Permissions](#rbac--permissions)
5. [API Endpoints](#api-endpoints)
6. [Telegram Bot Integration](#telegram-bot-integration)
7. [Testing Strategy](#testing-strategy)
8. [Deployment](#deployment)
9. [Production Checklist](#production-checklist)
---
## 🏗️ Architecture Overview
### System Components
```
EXTERNAL CLIENTS (Web, Mobile, Bot)
API GATEWAY (FastAPI)
MIDDLEWARE STACK
├─ Security Headers
├─ Rate Limiting
├─ HMAC Verification
├─ JWT Authentication
├─ RBAC Authorization
└─ Request Logging
DOMAIN SERVICES
├─ AuthService
├─ TransactionService
├─ WalletService
├─ BudgetService
└─ NotificationService
REPOSITORY LAYER (SQLAlchemy)
DATABASE + REDIS + MESSAGE QUEUE
```
### Key Principles
| Principle | Implementation |
|-----------|-----------------|
| **Zero-Trust** | Every request requires JWT + HMAC verification |
| **Immutability** | No direct record deletion; use reversals + audit logs |
| **Isolation** | Family-level data isolation at service layer |
| **Observability** | Every action logged to event_log + access_log |
| **Stateless** | API calls don't depend on session state |
---
## 🔐 Security Model
### Token Types
#### 1. **Access Token (JWT)**
- **Purpose:** Authenticate API requests
- **Lifetime:** 15 minutes
- **Scope:** Contains family_ids user can access
- **Usage:**
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
#### 2. **Refresh Token**
- **Purpose:** Issue new access tokens without re-login
- **Lifetime:** 30 days
- **Usage:**
```
POST /api/v1/auth/refresh
{ "refresh_token": "..." }
```
#### 3. **Service Token**
- **Purpose:** Telegram bot → API communication
- **Lifetime:** 1 year
- **Scope:** "telegram_bot" service
- **Note:** Different from user tokens; issued separately
### HMAC Signature Verification
**Base String Format:**
```
METHOD:ENDPOINT:TIMESTAMP:BODY_HASH
POST:/api/v1/transactions:1702237800:a3f5d8c2e1b9...
```
**Headers Required:**
```
X-Signature: HMAC_SHA256(base_string, client_secret)
X-Timestamp: 1702237800
X-Client-Id: telegram_bot|web_frontend|ios_app
```
**Verification Steps:**
1. Check timestamp freshness (±30 seconds)
2. Reconstruct base_string
3. Compute HMAC with client secret
4. Compare with X-Signature
5. Check signature nonce (prevent replay)
**MVP Default:** HMAC disabled (`require_hmac_verification=false`)
### Encryption Strategy
| Data | Encryption | Notes |
|------|-----------|-------|
| Password Hash | bcrypt | Never store plain passwords |
| Phone Number | AES-256 | At rest, logged as masked |
| Notes/Descriptions | None (MVP) | Can add AES-256 for sensitive notes |
| Transit | HTTPS TLS 1.2+ | Enforced in production |
---
## 🔑 Authentication Flows
### User Login Flow
```
┌─────────────────────────────────────────────────────────┐
│ 1. User submits credentials │
│ POST /api/v1/auth/login │
│ { "email": "user@example.com", "password": "..." } │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 2. Server verifies password hash with bcrypt │
│ Load user → Load family_ids → Create tokens │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 3. Response │
│ { │
│ "access_token": "eyJhbGc...", │
│ "refresh_token": "eyJhbGc...", │
│ "user_id": 123, │
│ "expires_in": 900 │
│ } │
└─────────────────────────────────────────────────────────┘
```
### Telegram Binding Flow
```
┌─────────────────────────────────────────────────────────┐
│ STEP 1: User sends /start │
│ Bot chat_id: 12345 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STEP 2: Bot generates binding code │
│ POST /api/v1/auth/telegram/start │
│ Response: { "code": "ABC123XYZ...", "expires_in": 600 } │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STEP 3: Bot sends link to user │
│ "Click: https://app.com/auth/telegram?code=ABC123&... │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STEP 4: User clicks link │
│ (User must be logged in or create account) │
│ POST /api/v1/auth/telegram/confirm │
│ { "code": "ABC123", "chat_id": 12345 } │
│ Headers: Authorization: Bearer <user_jwt> │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STEP 5: Server creates TelegramIdentity record │
│ TelegramIdentity { │
│ user_id: 123, │
│ chat_id: 12345, │
│ verified_at: now │
│ } │
│ │
│ Generate JWT for bot usage │
│ Response: { "jwt_token": "..." } │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STEP 6: Bot stores JWT in Redis │
│ Redis key: chat_id:12345:jwt │
│ Redis key: chat_id:12345:jwt:exp │
│ TTL: 30 days │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ STEP 7: Bot can now make API calls │
│ POST /api/v1/transactions │
│ Authorization: Bearer <jwt_from_redis> │
│ X-Client-Id: telegram_bot │
│ X-Signature: HMAC_SHA256(...) │
│ X-Timestamp: unixtime │
└─────────────────────────────────────────────────────────┘
```
---
## 👥 RBAC & Permissions
### Role Hierarchy
```
OWNER (Full Control)
└─ Can manage everything
└─ Can approve/reject large transactions
└─ Can manage members
└─ Can delete family
ADULT
└─ Can create/edit transactions
└─ Can approve transactions (with owner)
└─ Can create budgets/goals
└─ Can invite members
MEMBER
└─ Can create/view own transactions
└─ Can view budgets/goals
└─ Can view shared reports
CHILD
└─ Can create/view limited transactions
└─ Can view their allowance
└─ Very restricted permissions
READ_ONLY
└─ Can view reports only
└─ Audit/observer role
```
### Permission Examples
| Action | Owner | Adult | Member | Child | Read-Only |
|--------|-------|-------|--------|-------|-----------|
| Create Transaction | ✓ | ✓ | ✓ | ✓ (limited) | ✗ |
| Edit Own Transaction | ✓ | ✓ | ✓ | ✗ | ✗ |
| Edit Any Transaction | ✓ | ✗ | ✗ | ✗ | ✗ |
| Delete Transaction | ✓ | ✗ | ✗ | ✗ | ✗ |
| Approve Transaction | ✓ | ✓ | ✗ | ✗ | ✗ |
| Create Budget | ✓ | ✓ | ✗ | ✗ | ✗ |
| Manage Members | ✓ | ✗ | ✗ | ✗ | ✗ |
| View Audit Log | ✓ | ✓ | ✓ | ✗ | ✓ |
| Delete Family | ✓ | ✗ | ✗ | ✗ | ✗ |
### RBAC Implementation
**In Code:**
```python
# Check permission
RBACEngine.check_permission(user_context, Permission.CREATE_TRANSACTION)
# Check family access
RBACEngine.check_family_access(user_context, family_id=1)
# Check resource ownership
RBACEngine.check_resource_ownership(user_context, owner_id=123)
```
**In Endpoint:**
```python
@router.post("/transactions")
async def create_transaction(
request: TransactionCreateRequest,
user_context: UserContext = Depends(get_user_context),
):
# Middleware already verified JWT
# RBAC middleware already checked family access
# Now just check specific permission
RBACEngine.check_permission(
user_context,
Permission.CREATE_TRANSACTION
)
# Proceed with business logic
...
```
---
## 📡 API Endpoints
### Authentication
| Method | Endpoint | Purpose |
|--------|----------|---------|
| POST | `/api/v1/auth/login` | User login |
| POST | `/api/v1/auth/refresh` | Refresh access token |
| POST | `/api/v1/auth/logout` | Revoke session |
| POST | `/api/v1/auth/telegram/start` | Generate binding code |
| POST | `/api/v1/auth/telegram/confirm` | Confirm Telegram binding |
### Transactions
| Method | Endpoint | Purpose | Auth |
|--------|----------|---------|------|
| POST | `/api/v1/transactions` | Create transaction | JWT + HMAC |
| GET | `/api/v1/transactions` | List transactions | JWT |
| GET | `/api/v1/transactions/{id}` | Get transaction | JWT |
| POST | `/api/v1/transactions/{id}/confirm` | Approve pending | JWT + HMAC |
| DELETE | `/api/v1/transactions/{id}` | Reverse transaction | JWT + HMAC |
### Wallets
| Method | Endpoint | Purpose |
|--------|----------|---------|
| POST | `/api/v1/wallets` | Create wallet |
| GET | `/api/v1/wallets` | List wallets |
| GET | `/api/v1/wallets/summary` | Balance summary |
| PUT | `/api/v1/wallets/{id}` | Update wallet |
### Budgets & Goals
| Method | Endpoint | Purpose |
|--------|----------|---------|
| POST | `/api/v1/budgets` | Create budget |
| GET | `/api/v1/budgets` | List budgets |
| POST | `/api/v1/goals` | Create goal |
| GET | `/api/v1/goals` | List goals |
### Events & Webhooks
| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/api/v1/events/stream/{family_id}` | WebSocket event stream |
| POST | `/api/v1/events/webhook/telegram-notification` | Send Telegram notification |
---
## 🤖 Telegram Bot Integration
### Bot Commands
```
/start - Begin account binding
/help - Show available commands
/balance - View wallet balances
/add - Add new transaction
/reports - View financial reports
```
### Bot API Communication Pattern
```python
# Get user JWT from Redis
jwt_token = redis.get(f"chat_id:{chat_id}:jwt")
# Make API request
async with aiohttp.ClientSession() as session:
async with session.post(
"https://api.example.com/api/v1/transactions",
headers={
"Authorization": f"Bearer {jwt_token}",
"X-Client-Id": "telegram_bot",
"X-Signature": hmac_signature,
"X-Timestamp": str(timestamp),
},
json=payload,
) as response:
result = await response.json()
```
### Event Handling
```
Bot listens to Redis Streams:
- transaction.created
- budget.alert
- goal.completed
- member.joined
Bot processes events → Sends Telegram messages
```
---
## 🧪 Testing Strategy
### Unit Tests
- JWT token generation/verification
- HMAC signature creation/verification
- RBAC permission checks
- Service business logic
### Integration Tests
- Full request → response cycles
- Authentication flows
- RBAC in middleware
- Database transactions
### Security Tests
- Invalid token rejection
- HMAC signature verification
- Timestamp freshness
- Signature replay prevention
- Family isolation
### Load Testing Example (k6)
```javascript
import http from 'k6/http';
import { check } from 'k6';
export let options = {
vus: 10,
duration: '30s',
};
export default function() {
let url = 'http://localhost:8000/api/v1/wallets';
let params = {
headers: {
'Authorization': `Bearer ${__ENV.JWT_TOKEN}`,
'X-Client-Id': 'k6_test',
},
};
let res = http.get(url, params);
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
}
```
---
## 🚀 Deployment
### Docker Compose (MVP)
```yaml
version: '3.9'
services:
api:
image: finance-bot:latest
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://...
- REDIS_URL=redis://redis:6379
- JWT_SECRET_KEY=...
- HMAC_SECRET_KEY=...
depends_on:
- postgres
- redis
networks:
- finance
bot:
image: finance-bot-bot:latest
environment:
- BOT_TOKEN=...
- API_BASE_URL=http://api:8000
- REDIS_URL=redis://redis:6379
depends_on:
- api
- redis
networks:
- finance
worker:
image: finance-bot-worker:latest
environment:
- REDIS_URL=redis://redis:6379
- DATABASE_URL=postgresql://...
depends_on:
- postgres
- redis
networks:
- finance
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: finance_db
POSTGRES_USER: trevor
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- finance
redis:
image: redis:7-alpine
networks:
- finance
volumes:
pgdata:
networks:
finance:
```
### Kubernetes Deployment (Future)
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
JWT_SECRET_KEY: <secret>
HMAC_SECRET_KEY: <secret>
DATABASE_URL: postgresql://postgres/finance_db
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 3
template:
spec:
containers:
- name: api
image: finance-bot:latest
ports:
- containerPort: 8000
envFrom:
- configMapRef:
name: api-config
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
```
---
## ✅ Production Checklist
### Security
- [ ] Change JWT_SECRET_KEY from default
- [ ] Change HMAC_SECRET_KEY from default
- [ ] Enable HTTPS/TLS (Nginx reverse proxy)
- [ ] Enable CORS only for approved origins
- [ ] Set require_hmac_verification=true
- [ ] Implement password hashing (bcrypt)
- [ ] Implement token blacklisting
- [ ] Add rate limiting (current: 100 req/min)
- [ ] Enable audit logging (EventLog)
- [ ] Encrypt sensitive data at rest
### Deployment
- [ ] Run migrations in production
- [ ] Set app_env="production"
- [ ] Disable debug mode
- [ ] Configure proper logging
- [ ] Set up monitoring/alerts
- [ ] Configure backup strategy
- [ ] Test failover procedures
- [ ] Document runbooks
### Testing
- [ ] Unit tests coverage > 80%
- [ ] Integration tests for critical flows
- [ ] Security testing (OWASP Top 10)
- [ ] Load testing (identify bottlenecks)
- [ ] Penetration testing
- [ ] API contract testing
### Operations
- [ ] Set up CI/CD pipeline
- [ ] Configure health check endpoints
- [ ] Set up application monitoring
- [ ] Configure database backups
- [ ] Document API in OpenAPI/Swagger
- [ ] Set up error tracking (Sentry)
- [ ] Implement graceful shutdown
---
## 📚 Additional Resources
### OpenAPI Specification
```bash
# Auto-generated from FastAPI
GET /docs # Swagger UI
GET /redoc # ReDoc documentation
GET /openapi.json # OpenAPI spec
```
### Architecture Decision Records (ADR)
- ADR-001: JWT + HMAC for authentication (not just JWT)
- ADR-002: Redis Streams for event bus (vs RabbitMQ)
- ADR-003: Compensation transactions for reversals
- ADR-004: Family-level isolation in all queries
### Performance Targets
- API response time: < 200ms (p95)
- Transaction creation: < 100ms
- List queries: < 500ms (for 1000 items)
- HMAC verification: < 5ms
- JWT verification: < 2ms
---
## 🔄 Roadmap (Post-MVP)
### Phase 2: Enhanced Features
- [ ] Web Frontend (React/Vue)
- [ ] Mobile App (React Native/Flutter)
- [ ] Advanced reporting (PDF export, charts)
- [ ] Recurring transactions
- [ ] Currency conversion
- [ ] Multi-family support
- [ ] User notifications preferences
### Phase 3: Enterprise Features
- [ ] Kubernetes deployment
- [ ] Multi-region failover
- [ ] Advanced RBAC (custom roles)
- [ ] Audit webhook integrations
- [ ] API rate limiting (per-user)
- [ ] Data export (GDPR compliance)
- [ ] SSO integration (OAuth2)
---
**Document Version:** 1.0
**Last Updated:** 2025-12-10
**Status:** MVP Complete