10 KiB
10 KiB
🚀 MVP Implementation Quick Start
Phase-by-Phase Implementation Guide
✅ Phase 1: Complete (Existing)
- Database schema with 10 tables
- Environment variable management
- Docker Compose setup
- API health endpoint
🔄 Phase 2: Security Foundation (THIS DELIVERABLE)
2.1 Database Migrations
# Run the new migration
cd /home/data/finance_bot
source .venv/bin/activate
alembic upgrade head
What it creates:
sessionstable (for refresh token tracking)telegram_identitiestable (Telegram user binding)event_logtable (audit trail)access_logtable (request logging)- Enhanced
transactions(with approval workflow) - Enhanced
family_members(RBAC)
2.2 Install Dependencies
pip install -r requirements.txt
Key additions:
PyJWT==2.8.1 # JWT token management
aiohttp==3.9.1 # Async HTTP client
python-multipart==0.0.6 # Form data parsing
redis==5.0.1 # Redis client
2.3 Update Configuration
# Add to .env
JWT_SECRET_KEY=your-super-secret-key-min-32-chars-here-please
HMAC_SECRET_KEY=your-hmac-secret-key-min-32-chars-please
REQUIRE_HMAC_VERIFICATION=false # Disabled in MVP
2.4 Verify API Starts
# Start FastAPI server
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# In another terminal, test
curl http://localhost:8000/health
# Response: {"status":"ok","environment":"development","version":"1.0.0"}
📋 Phase 3: API Endpoints (EXAMPLES)
3.1 Authentication Endpoints
Login:
POST /api/v1/auth/login
{
"email": "user@example.com",
"password": "password123"
}
Response 200:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user_id": 1,
"expires_in": 900
}
Telegram Binding (Start):
POST /api/v1/auth/telegram/start
{
"chat_id": 12345
}
Response 200:
{
"code": "ABC123XYZ...",
"expires_in": 600
}
Telegram Binding (Confirm):
POST /api/v1/auth/telegram/confirm
Authorization: Bearer <user_access_token>
{
"code": "ABC123XYZ...",
"chat_id": 12345,
"username": "john_doe",
"first_name": "John"
}
Response 200:
{
"success": true,
"user_id": 1,
"jwt_token": "eyJhbGc...",
"expires_at": "2024-01-09T12:30:00Z"
}
3.2 Transaction Endpoints
Create Transaction (Small Amount - Auto-executed):
POST /api/v1/transactions
Authorization: Bearer <jwt_token>
X-Client-Id: telegram_bot
X-Timestamp: 1702237800
X-Signature: <hmac_sha256>
{
"family_id": 1,
"from_wallet_id": 10,
"to_wallet_id": 11,
"amount": 50.00,
"category_id": 5,
"description": "Groceries"
}
Response 201:
{
"id": 100,
"status": "executed",
"amount": "50.00",
"confirmation_required": false,
"created_at": "2023-12-10T12:30:00Z"
}
Create Transaction (Large Amount - Requires Approval):
POST /api/v1/transactions
...
{
...
"amount": 600.00, # > threshold
}
Response 201:
{
"id": 101,
"status": "pending_approval",
"amount": "600.00",
"confirmation_required": true,
"created_at": "2023-12-10T12:30:00Z"
}
# Bot notifies owner in Telegram
Approve Transaction:
POST /api/v1/transactions/101/confirm
Authorization: Bearer <owner_jwt>
{
"confirmation_token": null
}
Response 200:
{
"id": 101,
"status": "executed",
"executed_at": "2023-12-10T12:35:00Z"
}
Reverse Transaction:
DELETE /api/v1/transactions/100
Authorization: Bearer <jwt>
{
"reason": "User requested refund"
}
Response 200:
{
"original_transaction_id": 100,
"reversal_transaction_id": 102,
"reversed_at": "2023-12-10T12:40:00Z"
}
3.3 Wallet Endpoints
List Wallets:
GET /api/v1/wallets?family_id=1
Authorization: Bearer <jwt>
Response 200:
{
"wallets": [
{
"id": 10,
"name": "Cash",
"balance": "150.00",
"type": "cash"
},
{
"id": 11,
"name": "Bank Account",
"balance": "1250.00",
"type": "bank"
}
]
}
🧪 Testing the MVP
1. Unit Tests
# Run security tests
pytest tests/test_security.py -v
# Run specific test
pytest tests/test_security.py::TestJWTManager::test_create_access_token -v
2. Integration Tests
# Start API server in background
python -m uvicorn app.main:app &
# Run full test suite
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=app --cov-report=html
3. Manual API Testing
Using curl:
# Get health
curl http://localhost:8000/health
# Create transaction (need valid JWT)
JWT_TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"pass"}' | jq -r '.access_token')
curl -X POST http://localhost:8000/api/v1/transactions \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "X-Client-Id: manual_test" \
-H "Content-Type: application/json" \
-d '{
"family_id": 1,
"from_wallet_id": 10,
"to_wallet_id": 11,
"amount": 50.00,
"category_id": 5,
"description": "Test transaction"
}'
Using Swagger UI:
http://localhost:8000/docs
- All endpoints documented with interactive testing
- Try endpoints directly from browser
Using Postman:
- Open Postman
- Create new request
- Set URL:
http://localhost:8000/api/v1/transactions - Set Method:
POST - Add Headers:
Authorization: Bearer <your_jwt>X-Client-Id: postman
- Set Body (JSON):
{ "family_id": 1, "from_wallet_id": 10, "to_wallet_id": 11, "amount": 50.00, "category_id": 5, "description": "Postman test" } - Send!
🤖 Telegram Bot Testing
1. Local Bot Testing
Create test bot:
- Open Telegram
- Chat with @BotFather
/newbot- Follow instructions
- Get BOT_TOKEN
Update .env:
BOT_TOKEN=<your_test_bot_token>
Run bot:
# Terminal 1: API server
python -m uvicorn app.main:app --reload
# Terminal 2: Bot client (polling)
# TODO: Implement bot polling in app/bot/worker.py
Test flow:
Your Telegram → /start
Bot → "Click link to bind: https://..."
You → Click link (authenticate)
API → Create TelegramIdentity
You → Bot says "Connected!"
You → /balance
Bot → Shows wallets via API call
📊 RBAC Testing
Test Permission Checking
# python -i
from app.security.rbac import RBACEngine, MemberRole, Permission, UserContext
# Create contexts for different roles
owner = UserContext(
user_id=1,
family_id=1,
role=MemberRole.OWNER,
permissions=RBACEngine.get_permissions(MemberRole.OWNER),
family_ids=[1],
)
member = UserContext(
user_id=2,
family_id=1,
role=MemberRole.MEMBER,
permissions=RBACEngine.get_permissions(MemberRole.MEMBER),
family_ids=[1],
)
# Test owner permissions
RBACEngine.has_permission(owner, Permission.DELETE_FAMILY) # True
RBACEngine.has_permission(member, Permission.DELETE_FAMILY) # False
# Test family access
RBACEngine.check_family_access(owner, 1) # OK
RBACEngine.check_family_access(member, 2, raise_exception=False) # False
🚀 Deployment Steps
Docker Compose Deployment
# Navigate to project
cd /home/data/finance_bot
# Build images
docker-compose build
# Start services
docker-compose up -d
# Run migrations
docker-compose exec migrations python -m alembic upgrade head
# Verify
docker-compose ps
curl http://localhost:8000/health
# Check logs
docker-compose logs -f api
docker-compose logs -f bot
Docker-Free Deployment
# Setup environment
source .venv/bin/activate
# Update .env
export $(cat .env | grep -v '#' | xargs)
# Start services (in separate terminals)
# Terminal 1: API
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000
# Terminal 2: Bot (polling)
# TODO: Implement in app/bot/worker.py
python -m app.bot.worker
# Terminal 3: Worker (event processing)
# TODO: Implement in app/workers/event_processor.py
python -m app.workers.event_processor
📈 Monitoring & Debugging
Enable Debug Logging
# In app/core/config.py
log_level: str = "DEBUG"
# In .env
LOG_LEVEL=DEBUG
View Event Log
# python -i
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.db.models import EventLog
engine = create_engine("postgresql://...")
Session = sessionmaker(bind=engine)
session = Session()
# Query recent events
events = session.query(EventLog).order_by(EventLog.created_at.desc()).limit(10)
for e in events:
print(f"{e.created_at} | {e.action} | {e.entity_type} #{e.entity_id} | Actor: {e.actor_id}")
View Access Log
from app.db.models import AccessLog
access = session.query(AccessLog).order_by(AccessLog.created_at.desc()).limit(10)
for a in access:
print(f"{a.created_at} | {a.method} {a.endpoint} | {a.status_code} | {a.user_id} | {a.ip_address}")
❌ Troubleshooting
Issue: "type already exists"
Solution:
# Drop conflicting type in PostgreSQL
docker exec finance_bot_postgres psql -U trevor -d finance_db -c \
"DROP TYPE IF EXISTS family_role CASCADE;"
# Re-run migration
docker-compose exec migrations python -m alembic downgrade -1
docker-compose exec migrations python -m alembic upgrade head
Issue: JWT token verification fails
Solution:
# Check token expiration
from app.security.jwt_manager import jwt_manager
token_payload = jwt_manager.decode_token(token) # Ignore signature
print(f"Expires at: {token_payload.get('exp')}")
print(f"Current time: {datetime.utcnow().timestamp()}")
Issue: HMAC signature mismatch
Solution:
- Verify base_string format:
METHOD:ENDPOINT:TIMESTAMP:BODY_HASH - Verify client_secret matches on both sides
- Check timestamp isn't too old (±30 seconds)
📚 Next Steps
To Complete MVP:
- ✅ Security foundation created
- ⏳ Add remaining endpoints (Wallets, Budgets, Goals, Reports)
- ⏳ Implement worker process (event consumer)
- ⏳ Implement Telegram bot webhook (instead of polling)
- ⏳ Add comprehensive tests
- ⏳ Generate API documentation
To Extend MVP:
- Web frontend (React)
- Mobile app (React Native)
- Advanced reporting
- Kubernetes deployment
- Multi-region setup
Document Version: 1.0
Last Updated: 2025-12-10
Next Review: 2025-12-24