Spaces:
Sleeping
Sleeping
Iniital Commit
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .dockerignore +48 -0
- .env.example +0 -124
- .gitignore +14 -0
- .space +3 -0
- Dockerfile +8 -57
- README.md +80 -692
- alembic.ini +41 -0
- alembic/env.py +68 -0
- alembic/script.py.mako +24 -0
- docs/README.md +774 -0
- docs/agent/COMPREHENSIVE_BUILD_PLAN.md +2340 -0
- docs/dev/TEMPLATES_ARCHITECTURE.md +265 -0
- docs/dev/spec/DEVELOPMENT_CHECKLIST.md +329 -0
- docs/dev/spec/HUGGINGFACE_DEPLOYMENT.md +276 -0
- docs/dev/spec/PROJECT_STATUS.md +237 -0
- docs/dev/spec/PROJECT_STRUCTURE.txt +0 -0
- docs/dev/spec/QUICKSTART.md +180 -0
- docs/dev/spec/SCAFFOLDING_COMPLETE.md +292 -0
- docs/dev/spec/START_HERE.md +241 -0
- docs/huggingface/examples/Dockerfile +80 -0
- docs/huggingface/examples/requirements.txt +61 -0
- docs/prod/BACKEND_FEATURES.md +1821 -0
- docs/prod/CREDENTIALS_SETUP_GUIDE.md +734 -0
- docs/prod/TEST_TEMPLATES.md +234 -0
- docs/spec/USER_STORIES.md +1118 -0
- requirements-dev.txt +25 -0
- requirements.txt +29 -106
- scripts/seed_database.py +37 -0
- src/app/__init__.py +6 -0
- src/app/api/__init__.py +3 -0
- src/app/api/deps.py +57 -0
- src/app/api/v1/__init__.py +3 -0
- src/app/api/v1/analytics.py +8 -0
- src/app/api/v1/assignments.py +8 -0
- src/app/api/v1/auth.py +15 -0
- src/app/api/v1/customers.py +8 -0
- src/app/api/v1/documents.py +8 -0
- src/app/api/v1/expenses.py +8 -0
- src/app/api/v1/health.py +8 -0
- src/app/api/v1/incidents.py +8 -0
- src/app/api/v1/inventory.py +8 -0
- src/app/api/v1/media.py +8 -0
- src/app/api/v1/organizations.py +8 -0
- src/app/api/v1/pages.py +69 -0
- src/app/api/v1/payroll.py +8 -0
- src/app/api/v1/projects.py +8 -0
- src/app/api/v1/reports.py +8 -0
- src/app/api/v1/router.py +18 -0
- src/app/api/v1/sales_orders.py +8 -0
- src/app/api/v1/subscriptions.py +8 -0
.dockerignore
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
*.so
|
| 6 |
+
.Python
|
| 7 |
+
venv/
|
| 8 |
+
env/
|
| 9 |
+
ENV/
|
| 10 |
+
|
| 11 |
+
# Development files
|
| 12 |
+
.pre-commit-config.yaml
|
| 13 |
+
pytest.ini
|
| 14 |
+
requirements-dev.txt
|
| 15 |
+
docker-compose.yml
|
| 16 |
+
|
| 17 |
+
# Tests
|
| 18 |
+
tests/
|
| 19 |
+
.pytest_cache/
|
| 20 |
+
.coverage
|
| 21 |
+
htmlcov/
|
| 22 |
+
|
| 23 |
+
# Documentation
|
| 24 |
+
docs/
|
| 25 |
+
*.md
|
| 26 |
+
!README.md
|
| 27 |
+
|
| 28 |
+
# IDE
|
| 29 |
+
.vscode/
|
| 30 |
+
.idea/
|
| 31 |
+
*.swp
|
| 32 |
+
*.swo
|
| 33 |
+
|
| 34 |
+
# Git
|
| 35 |
+
.git/
|
| 36 |
+
.gitignore
|
| 37 |
+
|
| 38 |
+
# Environment
|
| 39 |
+
.env
|
| 40 |
+
.env.local
|
| 41 |
+
|
| 42 |
+
# Scripts
|
| 43 |
+
scripts/
|
| 44 |
+
|
| 45 |
+
# Build artifacts
|
| 46 |
+
*.egg-info/
|
| 47 |
+
dist/
|
| 48 |
+
build/
|
.env.example
CHANGED
|
@@ -23,127 +23,3 @@ ALGORITHM=HS256
|
|
| 23 |
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 24 |
REFRESH_TOKEN_EXPIRE_DAYS=7
|
| 25 |
|
| 26 |
-
# ============================================
|
| 27 |
-
# REDIS (CACHING & CELERY)
|
| 28 |
-
# ============================================
|
| 29 |
-
REDIS_URL=redis://localhost:6379/0
|
| 30 |
-
CACHE_TTL_SECONDS=300
|
| 31 |
-
|
| 32 |
-
# ============================================
|
| 33 |
-
# CELERY (BACKGROUND TASKS)
|
| 34 |
-
# ============================================
|
| 35 |
-
CELERY_BROKER_URL=redis://localhost:6379/0
|
| 36 |
-
CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
| 37 |
-
CELERY_TASK_ALWAYS_EAGER=False
|
| 38 |
-
|
| 39 |
-
# ============================================
|
| 40 |
-
# PAYMENT GATEWAYS
|
| 41 |
-
# ============================================
|
| 42 |
-
# M-Pesa (Safaricom)
|
| 43 |
-
MPESA_ENVIRONMENT=sandbox # or 'production'
|
| 44 |
-
MPESA_CONSUMER_KEY=your-mpesa-consumer-key
|
| 45 |
-
MPESA_CONSUMER_SECRET=your-mpesa-consumer-secret
|
| 46 |
-
MPESA_SHORTCODE=174379
|
| 47 |
-
MPESA_PASSKEY=your-mpesa-passkey
|
| 48 |
-
MPESA_CALLBACK_URL=https://your-domain.com/api/v1/webhooks/mpesa
|
| 49 |
-
|
| 50 |
-
# Bank API (if applicable)
|
| 51 |
-
BANK_API_URL=https://api.bank.com
|
| 52 |
-
BANK_API_KEY=your-bank-api-key
|
| 53 |
-
|
| 54 |
-
# ============================================
|
| 55 |
-
# GOOGLE MAPS API
|
| 56 |
-
# ============================================
|
| 57 |
-
GOOGLE_MAPS_API_KEY=your-google-maps-api-key
|
| 58 |
-
GOOGLE_MAPS_DISTANCE_MATRIX_ENABLED=True
|
| 59 |
-
|
| 60 |
-
# ============================================
|
| 61 |
-
# SMS PROVIDER (AFRICA'S TALKING)
|
| 62 |
-
# ============================================
|
| 63 |
-
AFRICASTALKING_USERNAME=your-username
|
| 64 |
-
AFRICASTALKING_API_KEY=your-api-key
|
| 65 |
-
AFRICASTALKING_SENDER_ID=SwiftOps
|
| 66 |
-
|
| 67 |
-
# ============================================
|
| 68 |
-
# EMAIL PROVIDER (SENDGRID)
|
| 69 |
-
# ============================================
|
| 70 |
-
SENDGRID_API_KEY=your-sendgrid-api-key
|
| 71 |
-
FROM_EMAIL=noreply@swiftops.com
|
| 72 |
-
FROM_NAME=SwiftOps Platform
|
| 73 |
-
|
| 74 |
-
# ============================================
|
| 75 |
-
# FILE STORAGE
|
| 76 |
-
# ============================================
|
| 77 |
-
STORAGE_PROVIDER=supabase # Options: 'supabase', 's3', 'local'
|
| 78 |
-
|
| 79 |
-
# Supabase Storage
|
| 80 |
-
SUPABASE_STORAGE_BUCKET=documents
|
| 81 |
-
|
| 82 |
-
# AWS S3 (if using S3)
|
| 83 |
-
AWS_ACCESS_KEY_ID=your-aws-access-key
|
| 84 |
-
AWS_SECRET_ACCESS_KEY=your-aws-secret-key
|
| 85 |
-
AWS_S3_BUCKET=swiftops-documents
|
| 86 |
-
AWS_REGION=us-east-1
|
| 87 |
-
|
| 88 |
-
# Local Storage (for development)
|
| 89 |
-
LOCAL_STORAGE_PATH=./uploads
|
| 90 |
-
|
| 91 |
-
# ============================================
|
| 92 |
-
# CORS CONFIGURATION
|
| 93 |
-
# ============================================
|
| 94 |
-
CORS_ORIGINS=http://localhost:3000,http://localhost:5173,https://your-frontend-domain.com
|
| 95 |
-
CORS_ALLOW_CREDENTIALS=True
|
| 96 |
-
|
| 97 |
-
# ============================================
|
| 98 |
-
# RATE LIMITING
|
| 99 |
-
# ============================================
|
| 100 |
-
RATE_LIMIT_ENABLED=True
|
| 101 |
-
RATE_LIMIT_PER_MINUTE=60
|
| 102 |
-
RATE_LIMIT_PER_HOUR=1000
|
| 103 |
-
|
| 104 |
-
# ============================================
|
| 105 |
-
# MONITORING & LOGGING
|
| 106 |
-
# ============================================
|
| 107 |
-
SENTRY_DSN=your-sentry-dsn-here
|
| 108 |
-
SENTRY_ENVIRONMENT=development
|
| 109 |
-
|
| 110 |
-
# ============================================
|
| 111 |
-
# FEATURE FLAGS
|
| 112 |
-
# ============================================
|
| 113 |
-
ENABLE_OFFLINE_MODE=True
|
| 114 |
-
ENABLE_AUTO_ASSIGNMENT=False
|
| 115 |
-
ENABLE_LOCATION_TRACKING=True
|
| 116 |
-
ENABLE_PAYMENT_GATEWAY=True
|
| 117 |
-
ENABLE_SMS_NOTIFICATIONS=True
|
| 118 |
-
ENABLE_EMAIL_NOTIFICATIONS=True
|
| 119 |
-
|
| 120 |
-
# ============================================
|
| 121 |
-
# BUSINESS RULES CONFIGURATION
|
| 122 |
-
# ============================================
|
| 123 |
-
# Ticket Assignment
|
| 124 |
-
MAX_SELF_ASSIGNED_TICKETS=3
|
| 125 |
-
AUTO_ASSIGNMENT_RADIUS_KM=50
|
| 126 |
-
|
| 127 |
-
# SLA Configuration (hours)
|
| 128 |
-
SLA_URGENT_HOURS=24
|
| 129 |
-
SLA_HIGH_HOURS=48
|
| 130 |
-
SLA_NORMAL_HOURS=72
|
| 131 |
-
SLA_LOW_DAYS=7
|
| 132 |
-
|
| 133 |
-
# Location Verification
|
| 134 |
-
ARRIVAL_VERIFICATION_RADIUS_METERS=100
|
| 135 |
-
MAX_TRAVEL_SPEED_KMH=120
|
| 136 |
-
|
| 137 |
-
# File Upload Limits
|
| 138 |
-
MAX_FILE_UPLOAD_MB=50
|
| 139 |
-
MAX_FILES_PER_TICKET=20
|
| 140 |
-
ALLOWED_FILE_TYPES=pdf,jpg,jpeg,png,doc,docx,xls,xlsx
|
| 141 |
-
|
| 142 |
-
# Payroll
|
| 143 |
-
PAYROLL_GENERATION_DAY=Friday
|
| 144 |
-
PAYROLL_GENERATION_HOUR=18
|
| 145 |
-
|
| 146 |
-
# ============================================
|
| 147 |
-
# TESTING
|
| 148 |
-
# ============================================
|
| 149 |
-
TEST_DATABASE_URL=postgresql://postgres:password@localhost:5432/swiftops_test
|
|
|
|
| 23 |
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 24 |
REFRESH_TOKEN_EXPIRE_DAYS=7
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
CHANGED
|
@@ -48,6 +48,7 @@ venv.bak/
|
|
| 48 |
# ============================================
|
| 49 |
# VSCode
|
| 50 |
.vscode/
|
|
|
|
| 51 |
*.code-workspace
|
| 52 |
|
| 53 |
# PyCharm
|
|
@@ -173,3 +174,16 @@ credentials/
|
|
| 173 |
# ============================================
|
| 174 |
poetry.lock
|
| 175 |
Pipfile.lock
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
# ============================================
|
| 49 |
# VSCode
|
| 50 |
.vscode/
|
| 51 |
+
.kiro/
|
| 52 |
*.code-workspace
|
| 53 |
|
| 54 |
# PyCharm
|
|
|
|
| 174 |
# ============================================
|
| 175 |
poetry.lock
|
| 176 |
Pipfile.lock
|
| 177 |
+
|
| 178 |
+
# ============================================
|
| 179 |
+
# Development Files (Not for HF Spaces)
|
| 180 |
+
# ============================================
|
| 181 |
+
# Keep these locally but don't deploy to Hugging Face
|
| 182 |
+
docker-compose.yml
|
| 183 |
+
.pre-commit-config.yaml
|
| 184 |
+
pytest.ini
|
| 185 |
+
|
| 186 |
+
# Optional: Uncomment to exclude from deployment
|
| 187 |
+
# requirements-dev.txt
|
| 188 |
+
# scripts/
|
| 189 |
+
# tests/
|
.space
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces Configuration
|
| 2 |
+
sdk: docker
|
| 3 |
+
app_port: 7860
|
Dockerfile
CHANGED
|
@@ -1,27 +1,13 @@
|
|
| 1 |
-
|
| 2 |
-
FROM python:3.11-slim as base
|
| 3 |
|
| 4 |
-
# Set environment variables
|
| 5 |
-
ENV PYTHONUNBUFFERED=1 \
|
| 6 |
-
PYTHONDONTWRITEBYTECODE=1 \
|
| 7 |
-
PIP_NO_CACHE_DIR=1 \
|
| 8 |
-
PIP_DISABLE_PIP_VERSION_CHECK=1
|
| 9 |
-
|
| 10 |
-
# Set work directory
|
| 11 |
WORKDIR /app
|
| 12 |
|
| 13 |
# Install system dependencies
|
| 14 |
RUN apt-get update && apt-get install -y \
|
| 15 |
gcc \
|
| 16 |
postgresql-client \
|
| 17 |
-
curl \
|
| 18 |
&& rm -rf /var/lib/apt/lists/*
|
| 19 |
|
| 20 |
-
# ============================================
|
| 21 |
-
# Development Stage
|
| 22 |
-
# ============================================
|
| 23 |
-
FROM base as development
|
| 24 |
-
|
| 25 |
# Copy requirements
|
| 26 |
COPY requirements.txt .
|
| 27 |
|
|
@@ -29,47 +15,12 @@ COPY requirements.txt .
|
|
| 29 |
RUN pip install --no-cache-dir -r requirements.txt
|
| 30 |
|
| 31 |
# Copy application code
|
| 32 |
-
COPY
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
EXPOSE 8000
|
| 36 |
-
|
| 37 |
-
# Default command (can be overridden in docker-compose)
|
| 38 |
-
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
| 39 |
-
|
| 40 |
-
# ============================================
|
| 41 |
-
# Production Stage
|
| 42 |
-
# ============================================
|
| 43 |
-
FROM base as production
|
| 44 |
-
|
| 45 |
-
# Copy requirements
|
| 46 |
-
COPY requirements.txt .
|
| 47 |
-
|
| 48 |
-
# Install Python dependencies (production only)
|
| 49 |
-
RUN pip install --no-cache-dir -r requirements.txt
|
| 50 |
-
|
| 51 |
-
# Create non-root user
|
| 52 |
-
RUN useradd -m -u 1000 appuser && \
|
| 53 |
-
chown -R appuser:appuser /app
|
| 54 |
-
|
| 55 |
-
# Copy application code
|
| 56 |
-
COPY --chown=appuser:appuser . .
|
| 57 |
-
|
| 58 |
-
# Switch to non-root user
|
| 59 |
-
USER appuser
|
| 60 |
-
|
| 61 |
-
# Expose port
|
| 62 |
-
EXPOSE 8000
|
| 63 |
|
| 64 |
-
#
|
| 65 |
-
|
| 66 |
-
CMD curl -f http://localhost:8000/health || exit 1
|
| 67 |
|
| 68 |
-
#
|
| 69 |
-
CMD
|
| 70 |
-
"--workers", "4", \
|
| 71 |
-
"--worker-class", "uvicorn.workers.UvicornWorker", \
|
| 72 |
-
"--bind", "0.0.0.0:8000", \
|
| 73 |
-
"--access-logfile", "-", \
|
| 74 |
-
"--error-logfile", "-", \
|
| 75 |
-
"--log-level", "info"]
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
|
|
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
# Install system dependencies
|
| 6 |
RUN apt-get update && apt-get install -y \
|
| 7 |
gcc \
|
| 8 |
postgresql-client \
|
|
|
|
| 9 |
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
# Copy requirements
|
| 12 |
COPY requirements.txt .
|
| 13 |
|
|
|
|
| 15 |
RUN pip install --no-cache-dir -r requirements.txt
|
| 16 |
|
| 17 |
# Copy application code
|
| 18 |
+
COPY src/ ./src/
|
| 19 |
+
COPY alembic/ ./alembic/
|
| 20 |
+
COPY alembic.ini .
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
+
# Expose port (Hugging Face Spaces uses port 7860 by default)
|
| 23 |
+
EXPOSE 7860
|
|
|
|
| 24 |
|
| 25 |
+
# Run database migrations and start application
|
| 26 |
+
CMD alembic upgrade head && uvicorn src.app.main:app --host 0.0.0.0 --port 7860
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -1,479 +1,31 @@
|
|
| 1 |
-
# SwiftOps Backend
|
| 2 |
-
|
| 3 |
-
**Field Service Management Platform - FastAPI Backend**
|
| 4 |
-
|
| 5 |
-
A scalable, production-ready FastAPI backend for managing field service operations including ticket management, payroll processing, inventory tracking, and financial workflows.
|
| 6 |
-
|
| 7 |
-
---
|
| 8 |
-
|
| 9 |
-
## 🏗️ Architecture Overview
|
| 10 |
-
|
| 11 |
-
```
|
| 12 |
-
backend/
|
| 13 |
-
├── app/
|
| 14 |
-
│ ├── __init__.py
|
| 15 |
-
│ ├── main.py # FastAPI application entry point
|
| 16 |
-
│ ├── config.py # Configuration management (env vars, settings)
|
| 17 |
-
│ │
|
| 18 |
-
│ ├── api/ # API Layer - HTTP endpoints
|
| 19 |
-
│ │ ├── __init__.py
|
| 20 |
-
│ │ ├── deps.py # Shared dependencies (auth, db session)
|
| 21 |
-
│ │ ├── v1/ # API version 1
|
| 22 |
-
│ │ │ ├── __init__.py
|
| 23 |
-
│ │ │ ├── router.py # Main router aggregator
|
| 24 |
-
│ │ │ ├── auth.py # Authentication endpoints
|
| 25 |
-
│ │ │ ├── users.py # User management
|
| 26 |
-
│ │ │ ├── projects.py # Project CRUD
|
| 27 |
-
│ │ │ ├── tickets.py # Ticket operations
|
| 28 |
-
│ │ │ ├── assignments.py # Ticket assignment logic
|
| 29 |
-
│ │ │ ├── payroll.py # Payroll generation & management
|
| 30 |
-
│ │ │ ├── inventory.py # Inventory tracking
|
| 31 |
-
│ │ │ ├── finance.py # Financial transactions
|
| 32 |
-
│ │ │ ├── customers.py # Customer management
|
| 33 |
-
│ │ │ ├── subscriptions.py # Subscription lifecycle
|
| 34 |
-
│ │ │ ├── incidents.py # Support incidents
|
| 35 |
-
│ │ │ ├── sales_orders.py # Sales order processing
|
| 36 |
-
│ │ │ ├── analytics.py # Dashboard & reporting
|
| 37 |
-
│ │ │ └── webhooks.py # Payment gateway webhooks
|
| 38 |
-
│ │ │
|
| 39 |
-
│ │ └── websockets/ # WebSocket endpoints
|
| 40 |
-
│ │ ├── __init__.py
|
| 41 |
-
│ │ ├── location.py # Real-time location tracking
|
| 42 |
-
│ │ └── notifications.py # Real-time notifications
|
| 43 |
-
│ │
|
| 44 |
-
│ ├── core/ # Core Business Logic
|
| 45 |
-
│ │ ├── __init__.py
|
| 46 |
-
│ │ ├── auth.py # JWT handling, password hashing
|
| 47 |
-
│ │ ├── security.py # RLS, permissions, RBAC
|
| 48 |
-
│ │ ├── exceptions.py # Custom exception classes
|
| 49 |
-
│ │ └── middleware.py # Custom middleware (logging, CORS)
|
| 50 |
-
│ │
|
| 51 |
-
│ ├── services/ # Business Logic Layer
|
| 52 |
-
│ │ ├── __init__.py
|
| 53 |
-
│ │ ├── ticket_service.py # Ticket lifecycle, assignment logic
|
| 54 |
-
│ │ ├── payroll_service.py # Payroll calculation, generation
|
| 55 |
-
│ │ ├── inventory_service.py # Inventory allocation, tracking
|
| 56 |
-
│ │ ├── finance_service.py # Transaction workflows, approvals
|
| 57 |
-
│ │ ├── sla_service.py # SLA calculation, monitoring
|
| 58 |
-
│ │ ├── location_service.py # GPS validation, distance calculation
|
| 59 |
-
│ │ ├── notification_service.py # Email, SMS, push notifications
|
| 60 |
-
│ │ ├── payment_service.py # Payment gateway integration
|
| 61 |
-
│ │ ├── subscription_service.py # Subscription activation, lifecycle
|
| 62 |
-
│ │ └── analytics_service.py # Metrics, dashboard data
|
| 63 |
-
│ │
|
| 64 |
-
│ ├── models/ # SQLAlchemy ORM Models
|
| 65 |
-
│ │ ├── __init__.py
|
| 66 |
-
│ │ ├── base.py # Base model with common fields
|
| 67 |
-
│ │ ├── user.py # User, UserFinancialAccounts
|
| 68 |
-
│ │ ├── organization.py # Clients, Contractors
|
| 69 |
-
│ │ ├── project.py # Projects, ProjectTeam, ProjectRoles
|
| 70 |
-
│ │ ├── ticket.py # Tickets, TicketAssignments, TicketStatusHistory
|
| 71 |
-
│ │ ├── customer.py # Customers, SalesOrders, Subscriptions
|
| 72 |
-
│ │ ├── incident.py # Incidents
|
| 73 |
-
│ │ ├── inventory.py # ProjectInventory, InventoryAssignments
|
| 74 |
-
│ │ ├── finance.py # ProjectFinance, UserPayroll, PaymentLogs
|
| 75 |
-
│ │ ├── timesheet.py # Timesheets
|
| 76 |
-
│ │ └── document.py # Documents
|
| 77 |
-
│ │
|
| 78 |
-
│ ├── schemas/ # Pydantic Schemas (Request/Response)
|
| 79 |
-
│ │ ├── __init__.py
|
| 80 |
-
│ │ ├── user.py # UserCreate, UserUpdate, UserResponse
|
| 81 |
-
│ │ ├── project.py # ProjectCreate, ProjectUpdate, ProjectResponse
|
| 82 |
-
│ │ ├── ticket.py # TicketCreate, TicketUpdate, TicketResponse
|
| 83 |
-
│ │ ├── payroll.py # PayrollCreate, PayrollCalculation
|
| 84 |
-
│ │ ├── inventory.py # InventoryAssignment, InventoryDistribution
|
| 85 |
-
│ │ ├── finance.py # TransactionCreate, TransactionApproval
|
| 86 |
-
│ │ └── common.py # Shared schemas (Pagination, Filters)
|
| 87 |
-
│ │
|
| 88 |
-
│ ├── repositories/ # Data Access Layer (Repository Pattern)
|
| 89 |
-
│ │ ├── __init__.py
|
| 90 |
-
│ │ ├── base.py # Base repository with CRUD operations
|
| 91 |
-
│ │ ├── user_repository.py # User-specific queries
|
| 92 |
-
│ │ ├── ticket_repository.py # Ticket-specific queries
|
| 93 |
-
│ │ ├── payroll_repository.py # Payroll-specific queries
|
| 94 |
-
│ │ └── finance_repository.py # Finance-specific queries
|
| 95 |
-
│ │
|
| 96 |
-
│ ├── tasks/ # Background Tasks (Celery)
|
| 97 |
-
│ │ ├── __init__.py
|
| 98 |
-
│ │ ├── celery_app.py # Celery configuration
|
| 99 |
-
│ │ ├── payroll_tasks.py # Weekly payroll generation
|
| 100 |
-
│ │ ├── sla_tasks.py # SLA monitoring, alerts
|
| 101 |
-
│ │ ├── notification_tasks.py # Send emails, SMS
|
| 102 |
-
│ │ ├── invoice_tasks.py # Generate contractor invoices
|
| 103 |
-
│ │ └── analytics_tasks.py # Pre-compute dashboard metrics
|
| 104 |
-
│ │
|
| 105 |
-
│ ├── integrations/ # External Service Integrations
|
| 106 |
-
│ │ ├── __init__.py
|
| 107 |
-
│ │ ├── supabase.py # Supabase client (Auth, Storage, Realtime)
|
| 108 |
-
│ │ ├── mpesa.py # M-Pesa payment gateway
|
| 109 |
-
│ │ ├── google_maps.py # Google Maps API (geocoding, distance)
|
| 110 |
-
│ │ ├── sms_provider.py # SMS gateway (Africa's Talking, Twilio)
|
| 111 |
-
│ │ ├── email_provider.py # Email service (SendGrid, AWS SES)
|
| 112 |
-
│ │ └── storage.py # File storage (Supabase Storage, S3)
|
| 113 |
-
│ │
|
| 114 |
-
│ ├── utils/ # Utility Functions
|
| 115 |
-
│ │ ├── __init__.py
|
| 116 |
-
│ │ ├── date_utils.py # Date/time helpers
|
| 117 |
-
│ │ ├── location_utils.py # GPS calculations, distance
|
| 118 |
-
│ │ ├── validation.py # Custom validators
|
| 119 |
-
│ │ ├── formatters.py # Data formatting helpers
|
| 120 |
-
│ │ └── constants.py # Application constants
|
| 121 |
-
│ │
|
| 122 |
-
│ └── db/ # Database Configuration
|
| 123 |
-
│ ├── __init__.py
|
| 124 |
-
│ ├── session.py # Database session management
|
| 125 |
-
│ ├── base.py # Base class for all models
|
| 126 |
-
│ └── migrations/ # Alembic migrations
|
| 127 |
-
│ └── versions/
|
| 128 |
-
│
|
| 129 |
-
├── tests/ # Test Suite
|
| 130 |
-
│ ├── __init__.py
|
| 131 |
-
│ ├── conftest.py # Pytest fixtures
|
| 132 |
-
│ ├── unit/ # Unit tests
|
| 133 |
-
│ │ ├── test_services/
|
| 134 |
-
│ │ ├── test_repositories/
|
| 135 |
-
│ │ └── test_utils/
|
| 136 |
-
│ ├── integration/ # Integration tests
|
| 137 |
-
│ │ ├── test_api/
|
| 138 |
-
│ │ └── test_tasks/
|
| 139 |
-
│ └── e2e/ # End-to-end tests
|
| 140 |
-
│
|
| 141 |
-
├── scripts/ # Utility Scripts
|
| 142 |
-
│ ├── seed_data.py # Seed database with test data
|
| 143 |
-
│ ├── generate_payroll.py # Manual payroll generation
|
| 144 |
-
│ └── migrate_data.py # Data migration scripts
|
| 145 |
-
│
|
| 146 |
-
├── .env.example # Environment variables template
|
| 147 |
-
├── .gitignore
|
| 148 |
-
├── requirements.txt # Python dependencies
|
| 149 |
-
├── pyproject.toml # Poetry configuration (alternative)
|
| 150 |
-
├── Dockerfile # Docker container definition
|
| 151 |
-
├── docker-compose.yml # Local development setup
|
| 152 |
-
└── README.md # This file
|
| 153 |
-
```
|
| 154 |
-
|
| 155 |
-
---
|
| 156 |
-
|
| 157 |
-
## 🎯 Core Functions & Responsibilities
|
| 158 |
-
|
| 159 |
-
### **1. Authentication & Authorization**
|
| 160 |
-
**Module**: `app/api/v1/auth.py`, `app/core/auth.py`, `app/core/security.py`
|
| 161 |
-
|
| 162 |
-
**Functions**:
|
| 163 |
-
- User login/logout (JWT token generation)
|
| 164 |
-
- Password reset flow
|
| 165 |
-
- Role-based access control (RBAC)
|
| 166 |
-
- Row-level security (RLS) enforcement
|
| 167 |
-
- Multi-tenancy isolation (client/contractor scoping)
|
| 168 |
-
|
| 169 |
-
**Supabase Integration**:
|
| 170 |
-
- Uses Supabase Auth for user authentication
|
| 171 |
-
- Validates JWT tokens from Supabase
|
| 172 |
-
- Syncs user roles with custom `Users` table
|
| 173 |
-
|
| 174 |
-
---
|
| 175 |
-
|
| 176 |
-
### **2. Ticket Management**
|
| 177 |
-
**Module**: `app/services/ticket_service.py`, `app/api/v1/tickets.py`
|
| 178 |
-
|
| 179 |
-
**Functions**:
|
| 180 |
-
- Create tickets from sales orders, incidents, or tasks
|
| 181 |
-
- Ticket assignment logic (manual, auto-assignment)
|
| 182 |
-
- Limit self-assignment to 3 tickets per agent
|
| 183 |
-
- Status transitions with validation
|
| 184 |
-
- SLA deadline calculation and monitoring
|
| 185 |
-
- GPS-based arrival verification
|
| 186 |
-
- Ticket completion workflow
|
| 187 |
-
|
| 188 |
-
**Business Rules**:
|
| 189 |
-
```python
|
| 190 |
-
# Example: Ticket Assignment Logic
|
| 191 |
-
def assign_ticket(ticket_id, user_id):
|
| 192 |
-
# 1. Check user has < 3 active assignments
|
| 193 |
-
# 2. Verify user is in project team
|
| 194 |
-
# 3. Check user's region matches ticket region
|
| 195 |
-
# 4. Create TicketAssignment record
|
| 196 |
-
# 5. Update ticket status to 'assigned'
|
| 197 |
-
# 6. Send notification to agent
|
| 198 |
-
# 7. Update SLA target date
|
| 199 |
-
```
|
| 200 |
-
|
| 201 |
-
---
|
| 202 |
-
|
| 203 |
-
### **3. Payroll Processing**
|
| 204 |
-
**Module**: `app/services/payroll_service.py`, `app/api/v1/payroll.py`
|
| 205 |
-
|
| 206 |
-
**Functions**:
|
| 207 |
-
- Weekly payroll generation (automated via Celery)
|
| 208 |
-
- Calculate earnings based on compensation type:
|
| 209 |
-
- Flat rate (fixed weekly amount)
|
| 210 |
-
- Commission (% of package price)
|
| 211 |
-
- Hybrid (base + commission)
|
| 212 |
-
- Hourly (based on timesheet hours)
|
| 213 |
-
- Apply deductions (advances, penalties)
|
| 214 |
-
- Generate payroll reports
|
| 215 |
-
- Mark payroll as paid with payment reference
|
| 216 |
-
|
| 217 |
-
**Business Rules**:
|
| 218 |
-
```python
|
| 219 |
-
# Example: Payroll Calculation
|
| 220 |
-
def calculate_payroll(user_id, project_id, period_start, period_end):
|
| 221 |
-
role = get_user_project_role(user_id, project_id)
|
| 222 |
-
tickets_closed = count_tickets_closed(user_id, period_start, period_end)
|
| 223 |
-
hours_worked = sum_timesheet_hours(user_id, period_start, period_end)
|
| 224 |
-
|
| 225 |
-
if role.compensation_type == 'flat_rate':
|
| 226 |
-
earnings = role.flat_rate_amount
|
| 227 |
-
elif role.compensation_type == 'commission':
|
| 228 |
-
earnings = sum_ticket_values(tickets) * role.commission_percentage
|
| 229 |
-
elif role.compensation_type == 'hybrid':
|
| 230 |
-
earnings = role.base_amount + (sum_ticket_values(tickets) * role.commission_percentage)
|
| 231 |
-
elif role.compensation_type == 'hourly':
|
| 232 |
-
earnings = hours_worked * role.hourly_rate
|
| 233 |
-
|
| 234 |
-
deductions = get_user_deductions(user_id, period_start, period_end)
|
| 235 |
-
total = earnings - deductions
|
| 236 |
-
|
| 237 |
-
return create_payroll_record(...)
|
| 238 |
-
```
|
| 239 |
-
|
| 240 |
-
---
|
| 241 |
-
|
| 242 |
-
### **4. Inventory Management**
|
| 243 |
-
**Module**: `app/services/inventory_service.py`, `app/api/v1/inventory.py`
|
| 244 |
-
|
| 245 |
-
**Functions**:
|
| 246 |
-
- Allocate inventory to regional hubs
|
| 247 |
-
- Issue equipment to field agents
|
| 248 |
-
- Track serial numbers and unit identifiers
|
| 249 |
-
- Prevent duplicate assignments (same serial issued twice)
|
| 250 |
-
- Handle returns (tools) and installations (equipment)
|
| 251 |
-
- Optimistic locking for concurrent updates
|
| 252 |
-
- Inventory reconciliation reports
|
| 253 |
-
|
| 254 |
-
**Business Rules**:
|
| 255 |
-
```python
|
| 256 |
-
# Example: Inventory Assignment
|
| 257 |
-
def assign_inventory_to_agent(distribution_id, user_id, unit_identifier):
|
| 258 |
-
# 1. Check unit_identifier not already assigned
|
| 259 |
-
# 2. Verify quantity_available > 0
|
| 260 |
-
# 3. Check user is in same region as distribution
|
| 261 |
-
# 4. Create InventoryAssignment record
|
| 262 |
-
# 5. Update distribution.quantity_issued
|
| 263 |
-
# 6. Use optimistic locking (version field)
|
| 264 |
-
```
|
| 265 |
|
| 266 |
---
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
- Link to entities (tickets, payroll, invoices)
|
| 275 |
-
- Payment gateway integration (M-Pesa, bank transfers)
|
| 276 |
-
- Transaction reconciliation
|
| 277 |
-
- Financial reporting and audit trails
|
| 278 |
-
|
| 279 |
-
**Business Rules**:
|
| 280 |
-
```python
|
| 281 |
-
# Example: Expense Approval Workflow
|
| 282 |
-
def approve_expense(expense_id, approver_id):
|
| 283 |
-
# 1. Check approver has 'dispatcher' or 'project_manager' role
|
| 284 |
-
# 2. Verify expense is in 'pending' status
|
| 285 |
-
# 3. Validate location_verified = TRUE (if required)
|
| 286 |
-
# 4. Update status to 'approved'
|
| 287 |
-
# 5. Create ProjectFinance record
|
| 288 |
-
# 6. Send notification to incurred_by_user
|
| 289 |
-
```
|
| 290 |
-
|
| 291 |
-
---
|
| 292 |
-
|
| 293 |
-
### **6. Location Tracking**
|
| 294 |
-
**Module**: `app/services/location_service.py`, `app/api/websockets/location.py`
|
| 295 |
-
|
| 296 |
-
**Functions**:
|
| 297 |
-
- Real-time GPS tracking via WebSocket
|
| 298 |
-
- Validate agent arrival at customer site
|
| 299 |
-
- Calculate distance between agent and customer
|
| 300 |
-
- Journey tracking (breadcrumb trail)
|
| 301 |
-
- Fraud detection (impossible travel speeds)
|
| 302 |
-
- Update user current location
|
| 303 |
-
|
| 304 |
-
**Business Rules**:
|
| 305 |
-
```python
|
| 306 |
-
# Example: Arrival Verification
|
| 307 |
-
def verify_arrival(ticket_id, agent_location):
|
| 308 |
-
ticket = get_ticket(ticket_id)
|
| 309 |
-
customer_location = get_customer_location(ticket.customer_id)
|
| 310 |
-
|
| 311 |
-
distance = calculate_distance(agent_location, customer_location)
|
| 312 |
-
|
| 313 |
-
if distance <= 100: # Within 100 meters
|
| 314 |
-
mark_arrived(ticket_id, agent_location, verified=True)
|
| 315 |
-
else:
|
| 316 |
-
mark_arrived(ticket_id, agent_location, verified=False)
|
| 317 |
-
```
|
| 318 |
-
|
| 319 |
-
---
|
| 320 |
-
|
| 321 |
-
### **7. SLA Monitoring**
|
| 322 |
-
**Module**: `app/services/sla_service.py`, `app/tasks/sla_tasks.py`
|
| 323 |
-
|
| 324 |
-
**Functions**:
|
| 325 |
-
- Calculate SLA deadlines based on priority
|
| 326 |
-
- Monitor tickets approaching deadline
|
| 327 |
-
- Send alerts to managers and agents
|
| 328 |
-
- Mark tickets as SLA violated
|
| 329 |
-
- Generate SLA compliance reports
|
| 330 |
-
|
| 331 |
-
**Background Task** (runs every hour):
|
| 332 |
-
```python
|
| 333 |
-
@celery_app.task
|
| 334 |
-
def monitor_sla_violations():
|
| 335 |
-
# 1. Find tickets with sla_target_date < now() and status != 'completed'
|
| 336 |
-
# 2. Mark sla_violated = TRUE
|
| 337 |
-
# 3. Send notifications to project managers
|
| 338 |
-
# 4. Log SLA violation event
|
| 339 |
-
```
|
| 340 |
-
|
| 341 |
-
---
|
| 342 |
-
|
| 343 |
-
### **8. Payment Gateway Integration**
|
| 344 |
-
**Module**: `app/services/payment_service.py`, `app/integrations/mpesa.py`
|
| 345 |
-
|
| 346 |
-
**Functions**:
|
| 347 |
-
- Initiate M-Pesa payments (B2C, B2B)
|
| 348 |
-
- Handle payment callbacks/webhooks
|
| 349 |
-
- Retry failed payments
|
| 350 |
-
- Log all payment attempts (PaymentLogs)
|
| 351 |
-
- Reconcile payments with transactions
|
| 352 |
-
|
| 353 |
-
**Webhook Handler**:
|
| 354 |
-
```python
|
| 355 |
-
@router.post("/webhooks/mpesa")
|
| 356 |
-
async def mpesa_callback(payload: dict):
|
| 357 |
-
# 1. Validate webhook signature
|
| 358 |
-
# 2. Parse payment result
|
| 359 |
-
# 3. Update ProjectFinance status
|
| 360 |
-
# 4. Create PaymentLog entry
|
| 361 |
-
# 5. Send notification to user
|
| 362 |
-
```
|
| 363 |
-
|
| 364 |
---
|
| 365 |
|
| 366 |
-
|
| 367 |
-
**Module**: `app/services/subscription_service.py`, `app/api/v1/subscriptions.py`
|
| 368 |
-
|
| 369 |
-
**Functions**:
|
| 370 |
-
- Activate subscriptions after installation
|
| 371 |
-
- Validate activation requirements (dynamic per project)
|
| 372 |
-
- Manage subscription lifecycle (active, suspended, cancelled)
|
| 373 |
-
- Link subscriptions to tickets and sales orders
|
| 374 |
-
|
| 375 |
-
**Business Rules**:
|
| 376 |
-
```python
|
| 377 |
-
# Example: Subscription Activation
|
| 378 |
-
def activate_subscription(subscription_id, activation_data):
|
| 379 |
-
subscription = get_subscription(subscription_id)
|
| 380 |
-
project = get_project(subscription.project_id)
|
| 381 |
-
|
| 382 |
-
# Validate dynamic activation requirements
|
| 383 |
-
for requirement in project.activation_requirements:
|
| 384 |
-
if requirement['required'] and requirement['field'] not in activation_data:
|
| 385 |
-
raise ValidationError(f"Missing required field: {requirement['label']}")
|
| 386 |
-
|
| 387 |
-
# Update subscription
|
| 388 |
-
subscription.status = 'active'
|
| 389 |
-
subscription.activation_date = date.today()
|
| 390 |
-
subscription.activation_details = activation_data
|
| 391 |
-
subscription.activated_by_user_id = current_user.id
|
| 392 |
-
```
|
| 393 |
-
|
| 394 |
-
---
|
| 395 |
-
|
| 396 |
-
### **10. Analytics & Reporting**
|
| 397 |
-
**Module**: `app/services/analytics_service.py`, `app/api/v1/analytics.py`
|
| 398 |
-
|
| 399 |
-
**Functions**:
|
| 400 |
-
- Dashboard metrics (tickets, revenue, SLA compliance)
|
| 401 |
-
- Agent performance reports
|
| 402 |
-
- Project financial summaries
|
| 403 |
-
- Inventory utilization reports
|
| 404 |
-
- Pre-computed aggregations (via Celery)
|
| 405 |
-
|
| 406 |
-
**Background Task** (runs daily):
|
| 407 |
-
```python
|
| 408 |
-
@celery_app.task
|
| 409 |
-
def compute_daily_metrics():
|
| 410 |
-
# 1. Calculate tickets closed per agent
|
| 411 |
-
# 2. Compute average completion time
|
| 412 |
-
# 3. Calculate SLA compliance rate
|
| 413 |
-
# 4. Store in cache (Redis)
|
| 414 |
-
```
|
| 415 |
-
|
| 416 |
-
---
|
| 417 |
-
|
| 418 |
-
## 🔗 Supabase Integration Points
|
| 419 |
-
|
| 420 |
-
### **1. Authentication**
|
| 421 |
-
```python
|
| 422 |
-
# app/integrations/supabase.py
|
| 423 |
-
from supabase import create_client
|
| 424 |
-
|
| 425 |
-
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 426 |
-
|
| 427 |
-
# Verify JWT token from frontend
|
| 428 |
-
def verify_token(token: str):
|
| 429 |
-
user = supabase.auth.get_user(token)
|
| 430 |
-
return user
|
| 431 |
-
```
|
| 432 |
-
|
| 433 |
-
### **2. Storage (File Uploads)**
|
| 434 |
-
```python
|
| 435 |
-
# Upload ticket photos, receipts
|
| 436 |
-
def upload_document(file, bucket="documents"):
|
| 437 |
-
path = f"{user_id}/{ticket_id}/{filename}"
|
| 438 |
-
supabase.storage.from_(bucket).upload(path, file)
|
| 439 |
-
return supabase.storage.from_(bucket).get_public_url(path)
|
| 440 |
-
```
|
| 441 |
|
| 442 |
-
##
|
| 443 |
-
```python
|
| 444 |
-
# Subscribe to ticket updates
|
| 445 |
-
supabase.realtime.channel('tickets')
|
| 446 |
-
.on('postgres_changes',
|
| 447 |
-
event='UPDATE',
|
| 448 |
-
schema='public',
|
| 449 |
-
table='Tickets',
|
| 450 |
-
callback=handle_ticket_update)
|
| 451 |
-
.subscribe()
|
| 452 |
-
```
|
| 453 |
|
| 454 |
-
###
|
| 455 |
-
```python
|
| 456 |
-
# Use Supabase client for simple queries (optional)
|
| 457 |
-
# For complex queries, use SQLAlchemy ORM
|
| 458 |
-
tickets = supabase.table('Tickets').select('*').eq('status', 'open').execute()
|
| 459 |
-
```
|
| 460 |
-
|
| 461 |
-
---
|
| 462 |
-
|
| 463 |
-
## 🚀 Getting Started
|
| 464 |
-
|
| 465 |
-
### **Prerequisites**
|
| 466 |
- Python 3.11+
|
| 467 |
-
- PostgreSQL 15+
|
| 468 |
-
- Redis
|
| 469 |
- Docker & Docker Compose (optional)
|
| 470 |
|
| 471 |
-
###
|
| 472 |
|
| 473 |
1. **Clone the repository**
|
| 474 |
```bash
|
| 475 |
-
git clone <
|
| 476 |
-
cd backend
|
| 477 |
```
|
| 478 |
|
| 479 |
2. **Create virtual environment**
|
|
@@ -490,7 +42,7 @@ pip install -r requirements.txt
|
|
| 490 |
4. **Set up environment variables**
|
| 491 |
```bash
|
| 492 |
cp .env.example .env
|
| 493 |
-
# Edit .env with your
|
| 494 |
```
|
| 495 |
|
| 496 |
5. **Run database migrations**
|
|
@@ -500,90 +52,38 @@ alembic upgrade head
|
|
| 500 |
|
| 501 |
6. **Start the development server**
|
| 502 |
```bash
|
| 503 |
-
uvicorn app.main:app --reload
|
| 504 |
-
```
|
| 505 |
-
|
| 506 |
-
7. **Start Celery worker** (in separate terminal)
|
| 507 |
-
```bash
|
| 508 |
-
celery -A app.tasks.celery_app worker --loglevel=info
|
| 509 |
```
|
| 510 |
|
| 511 |
-
|
| 512 |
-
```bash
|
| 513 |
-
celery -A app.tasks.celery_app beat --loglevel=info
|
| 514 |
-
```
|
| 515 |
|
| 516 |
-
|
| 517 |
|
| 518 |
-
##
|
| 519 |
|
| 520 |
```bash
|
| 521 |
-
# Start all services (API, Celery, Redis)
|
| 522 |
docker-compose up -d
|
| 523 |
-
|
| 524 |
-
# View logs
|
| 525 |
-
docker-compose logs -f api
|
| 526 |
-
|
| 527 |
-
# Stop services
|
| 528 |
-
docker-compose down
|
| 529 |
```
|
| 530 |
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
## 📝 Environment Variables
|
| 534 |
|
| 535 |
-
```bash
|
| 536 |
-
# .env.example
|
| 537 |
-
|
| 538 |
-
# Application
|
| 539 |
-
APP_NAME=SwiftOps API
|
| 540 |
-
APP_VERSION=1.0.0
|
| 541 |
-
DEBUG=True
|
| 542 |
-
ENVIRONMENT=development
|
| 543 |
-
|
| 544 |
-
# Database (Supabase PostgreSQL)
|
| 545 |
-
DATABASE_URL=postgresql://user:password@host:5432/dbname
|
| 546 |
-
SUPABASE_URL=https://your-project.supabase.co
|
| 547 |
-
SUPABASE_KEY=your-anon-key
|
| 548 |
-
SUPABASE_SERVICE_KEY=your-service-role-key
|
| 549 |
-
|
| 550 |
-
# JWT
|
| 551 |
-
SECRET_KEY=your-secret-key-here
|
| 552 |
-
ALGORITHM=HS256
|
| 553 |
-
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 554 |
-
|
| 555 |
-
# Redis
|
| 556 |
-
REDIS_URL=redis://localhost:6379/0
|
| 557 |
-
|
| 558 |
-
# Celery
|
| 559 |
-
CELERY_BROKER_URL=redis://localhost:6379/0
|
| 560 |
-
CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
| 561 |
-
|
| 562 |
-
# Payment Gateways
|
| 563 |
-
MPESA_CONSUMER_KEY=your-mpesa-key
|
| 564 |
-
MPESA_CONSUMER_SECRET=your-mpesa-secret
|
| 565 |
-
MPESA_SHORTCODE=174379
|
| 566 |
-
MPESA_PASSKEY=your-passkey
|
| 567 |
-
|
| 568 |
-
# Google Maps
|
| 569 |
-
GOOGLE_MAPS_API_KEY=your-google-maps-key
|
| 570 |
-
|
| 571 |
-
# SMS Provider (Africa's Talking)
|
| 572 |
-
AFRICASTALKING_USERNAME=your-username
|
| 573 |
-
AFRICASTALKING_API_KEY=your-api-key
|
| 574 |
-
|
| 575 |
-
# Email Provider (SendGrid)
|
| 576 |
-
SENDGRID_API_KEY=your-sendgrid-key
|
| 577 |
-
FROM_EMAIL=noreply@swiftops.com
|
| 578 |
-
|
| 579 |
-
# File Storage
|
| 580 |
-
STORAGE_PROVIDER=supabase # or 's3'
|
| 581 |
-
AWS_ACCESS_KEY_ID=your-aws-key
|
| 582 |
-
AWS_SECRET_ACCESS_KEY=your-aws-secret
|
| 583 |
-
AWS_S3_BUCKET=your-bucket-name
|
| 584 |
```
|
| 585 |
-
|
| 586 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 587 |
|
| 588 |
## 🧪 Testing
|
| 589 |
|
|
@@ -592,183 +92,71 @@ AWS_S3_BUCKET=your-bucket-name
|
|
| 592 |
pytest
|
| 593 |
|
| 594 |
# Run with coverage
|
| 595 |
-
pytest --cov=app --cov-report=html
|
| 596 |
|
| 597 |
# Run specific test file
|
| 598 |
-
pytest tests/unit/
|
| 599 |
-
|
| 600 |
-
# Run integration tests only
|
| 601 |
-
pytest tests/integration/
|
| 602 |
```
|
| 603 |
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
## 📚 API Documentation
|
| 607 |
|
| 608 |
-
|
| 609 |
-
-
|
| 610 |
-
-
|
| 611 |
-
-
|
| 612 |
|
| 613 |
-
|
| 614 |
-
|
| 615 |
-
## 🏛️ Design Patterns & Best Practices
|
| 616 |
-
|
| 617 |
-
### **1. Repository Pattern**
|
| 618 |
-
Separates data access logic from business logic.
|
| 619 |
-
|
| 620 |
-
```python
|
| 621 |
-
# app/repositories/ticket_repository.py
|
| 622 |
-
class TicketRepository:
|
| 623 |
-
def get_by_id(self, ticket_id: UUID) -> Ticket:
|
| 624 |
-
return db.query(Ticket).filter(Ticket.id == ticket_id).first()
|
| 625 |
-
|
| 626 |
-
def get_open_tickets(self, project_id: UUID) -> List[Ticket]:
|
| 627 |
-
return db.query(Ticket).filter(
|
| 628 |
-
Ticket.project_id == project_id,
|
| 629 |
-
Ticket.status == 'open',
|
| 630 |
-
Ticket.deleted_at.is_(None)
|
| 631 |
-
).all()
|
| 632 |
-
```
|
| 633 |
|
| 634 |
-
###
|
| 635 |
-
Encapsulates business logic.
|
| 636 |
-
|
| 637 |
-
```python
|
| 638 |
-
# app/services/ticket_service.py
|
| 639 |
-
class TicketService:
|
| 640 |
-
def __init__(self, ticket_repo: TicketRepository):
|
| 641 |
-
self.ticket_repo = ticket_repo
|
| 642 |
-
|
| 643 |
-
def assign_ticket(self, ticket_id: UUID, user_id: UUID):
|
| 644 |
-
# Business logic here
|
| 645 |
-
ticket = self.ticket_repo.get_by_id(ticket_id)
|
| 646 |
-
self._validate_assignment(ticket, user_id)
|
| 647 |
-
assignment = self._create_assignment(ticket, user_id)
|
| 648 |
-
self._send_notification(user_id, ticket)
|
| 649 |
-
return assignment
|
| 650 |
-
```
|
| 651 |
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
```python
|
| 656 |
-
# app/api/deps.py
|
| 657 |
-
def get_db():
|
| 658 |
-
db = SessionLocal()
|
| 659 |
-
try:
|
| 660 |
-
yield db
|
| 661 |
-
finally:
|
| 662 |
-
db.close()
|
| 663 |
-
|
| 664 |
-
def get_current_user(token: str = Depends(oauth2_scheme)):
|
| 665 |
-
# Validate token and return user
|
| 666 |
-
return user
|
| 667 |
-
|
| 668 |
-
# Usage in endpoint
|
| 669 |
-
@router.get("/tickets")
|
| 670 |
-
def get_tickets(
|
| 671 |
-
db: Session = Depends(get_db),
|
| 672 |
-
current_user: User = Depends(get_current_user)
|
| 673 |
-
):
|
| 674 |
-
return ticket_service.get_tickets(db, current_user)
|
| 675 |
-
```
|
| 676 |
|
| 677 |
-
#
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
```python
|
| 681 |
-
def update_inventory_distribution(distribution_id, updates, version):
|
| 682 |
-
distribution = db.query(ProjectInventoryDistribution).filter(
|
| 683 |
-
ProjectInventoryDistribution.id == distribution_id,
|
| 684 |
-
ProjectInventoryDistribution.version == version
|
| 685 |
-
).first()
|
| 686 |
-
|
| 687 |
-
if not distribution:
|
| 688 |
-
raise ConcurrentUpdateError("Record was modified by another user")
|
| 689 |
-
|
| 690 |
-
# Apply updates
|
| 691 |
-
distribution.quantity_issued += updates.quantity
|
| 692 |
-
distribution.version += 1
|
| 693 |
-
db.commit()
|
| 694 |
-
```
|
| 695 |
|
| 696 |
-
#
|
| 697 |
-
|
| 698 |
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
def get_active(self, model_class):
|
| 702 |
-
return db.query(model_class).filter(model_class.deleted_at.is_(None))
|
| 703 |
```
|
| 704 |
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
## 🔐 Security Considerations
|
| 708 |
-
|
| 709 |
-
1. **Row-Level Security (RLS)**
|
| 710 |
-
- Enforce tenant isolation at database level
|
| 711 |
-
- Use Supabase RLS policies
|
| 712 |
-
|
| 713 |
-
2. **API Rate Limiting**
|
| 714 |
-
- Implement rate limiting per client/user
|
| 715 |
-
- Use Redis for rate limit tracking
|
| 716 |
-
|
| 717 |
-
3. **Input Validation**
|
| 718 |
-
- Use Pydantic schemas for all inputs
|
| 719 |
-
- Validate file uploads (type, size)
|
| 720 |
-
|
| 721 |
-
4. **Audit Logging**
|
| 722 |
-
- Log all financial transactions
|
| 723 |
-
- Track who created/updated records
|
| 724 |
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
---
|
| 730 |
-
|
| 731 |
-
## 📈 Scalability Considerations
|
| 732 |
-
|
| 733 |
-
1. **Database Connection Pooling**
|
| 734 |
-
- Use SQLAlchemy connection pool
|
| 735 |
-
- Configure pool size based on load
|
| 736 |
-
|
| 737 |
-
2. **Caching Strategy**
|
| 738 |
-
- Cache frequently accessed data (Redis)
|
| 739 |
-
- Invalidate cache on updates
|
| 740 |
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
- Use task queues for async processing
|
| 744 |
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
|
| 749 |
-
|
| 750 |
-
- Use indexes effectively
|
| 751 |
-
- Monitor slow queries
|
| 752 |
-
- Consider read replicas for reporting
|
| 753 |
|
| 754 |
-
|
|
|
|
|
|
|
| 755 |
|
| 756 |
-
#
|
|
|
|
| 757 |
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
4. Update documentation
|
| 762 |
-
5. Submit pull request
|
| 763 |
|
| 764 |
-
|
| 765 |
|
| 766 |
-
|
| 767 |
|
| 768 |
-
|
| 769 |
|
| 770 |
-
-
|
| 771 |
|
| 772 |
-
##
|
| 773 |
|
| 774 |
-
|
|
|
|
| 1 |
+
# SwiftOps Backend
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
---
|
| 4 |
+
title: SwiftOps API
|
| 5 |
+
emoji: 🚀
|
| 6 |
+
colorFrom: blue
|
| 7 |
+
colorTo: green
|
| 8 |
+
sdk: docker
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
+
Field Service Management Platform for African Telecom
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
## 🚀 Quick Start
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
+
### Prerequisites
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
- Python 3.11+
|
| 19 |
+
- PostgreSQL 15+
|
| 20 |
+
- Redis 7+
|
| 21 |
- Docker & Docker Compose (optional)
|
| 22 |
|
| 23 |
+
### Installation
|
| 24 |
|
| 25 |
1. **Clone the repository**
|
| 26 |
```bash
|
| 27 |
+
git clone <repository-url>
|
| 28 |
+
cd swiftops-backend
|
| 29 |
```
|
| 30 |
|
| 31 |
2. **Create virtual environment**
|
|
|
|
| 42 |
4. **Set up environment variables**
|
| 43 |
```bash
|
| 44 |
cp .env.example .env
|
| 45 |
+
# Edit .env with your configuration
|
| 46 |
```
|
| 47 |
|
| 48 |
5. **Run database migrations**
|
|
|
|
| 52 |
|
| 53 |
6. **Start the development server**
|
| 54 |
```bash
|
| 55 |
+
uvicorn src.app.main:app --reload
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
```
|
| 57 |
|
| 58 |
+
The API will be available at `http://localhost:8000`
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
+
API Documentation: `http://localhost:8000/api/docs`
|
| 61 |
|
| 62 |
+
### Using Docker
|
| 63 |
|
| 64 |
```bash
|
|
|
|
| 65 |
docker-compose up -d
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
```
|
| 67 |
|
| 68 |
+
## 📁 Project Structure
|
|
|
|
|
|
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
```
|
| 71 |
+
swiftops-backend/
|
| 72 |
+
├── src/app/ # Application code
|
| 73 |
+
│ ├── api/ # API endpoints
|
| 74 |
+
│ ├── core/ # Core utilities
|
| 75 |
+
│ ├── models/ # Database models
|
| 76 |
+
│ ├── schemas/ # Pydantic schemas
|
| 77 |
+
│ ├── services/ # Business logic
|
| 78 |
+
│ ├── repositories/ # Data access
|
| 79 |
+
│ ├── tasks/ # Background tasks
|
| 80 |
+
│ ├── integrations/ # External services
|
| 81 |
+
│ └── utils/ # Utilities
|
| 82 |
+
├── tests/ # Test suite
|
| 83 |
+
├── alembic/ # Database migrations
|
| 84 |
+
├── docs/ # Documentation
|
| 85 |
+
└── scripts/ # Utility scripts
|
| 86 |
+
```
|
| 87 |
|
| 88 |
## 🧪 Testing
|
| 89 |
|
|
|
|
| 92 |
pytest
|
| 93 |
|
| 94 |
# Run with coverage
|
| 95 |
+
pytest --cov=src/app --cov-report=html
|
| 96 |
|
| 97 |
# Run specific test file
|
| 98 |
+
pytest tests/unit/services/test_ticket_service.py
|
|
|
|
|
|
|
|
|
|
| 99 |
```
|
| 100 |
|
| 101 |
+
## 📚 Documentation
|
|
|
|
|
|
|
| 102 |
|
| 103 |
+
- [API Documentation](http://localhost:8000/api/docs)
|
| 104 |
+
- [Database Schema](docs/schema/schema.sql)
|
| 105 |
+
- [Build Plan](docs/agent/COMPREHENSIVE_BUILD_PLAN.md)
|
| 106 |
+
- [Backend Features](docs/prod/BACKEND_FEATURES.md)
|
| 107 |
|
| 108 |
+
## 🔧 Development
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
+
### Code Quality
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
+
```bash
|
| 113 |
+
# Format code
|
| 114 |
+
black src/ tests/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
+
# Sort imports
|
| 117 |
+
isort src/ tests/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
|
| 119 |
+
# Lint code
|
| 120 |
+
flake8 src/ tests/
|
| 121 |
|
| 122 |
+
# Type checking
|
| 123 |
+
mypy src/
|
|
|
|
|
|
|
| 124 |
```
|
| 125 |
|
| 126 |
+
### Database Migrations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
+
```bash
|
| 129 |
+
# Create new migration
|
| 130 |
+
alembic revision --autogenerate -m "description"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
| 132 |
+
# Apply migrations
|
| 133 |
+
alembic upgrade head
|
|
|
|
| 134 |
|
| 135 |
+
# Rollback migration
|
| 136 |
+
alembic downgrade -1
|
| 137 |
+
```
|
| 138 |
|
| 139 |
+
### Background Tasks
|
|
|
|
|
|
|
|
|
|
| 140 |
|
| 141 |
+
```bash
|
| 142 |
+
# Start Celery worker
|
| 143 |
+
celery -A src.app.tasks.celery_app worker --loglevel=info
|
| 144 |
|
| 145 |
+
# Start Celery beat (scheduler)
|
| 146 |
+
celery -A src.app.tasks.celery_app beat --loglevel=info
|
| 147 |
|
| 148 |
+
# Monitor with Flower
|
| 149 |
+
celery -A src.app.tasks.celery_app flower
|
| 150 |
+
```
|
|
|
|
|
|
|
| 151 |
|
| 152 |
+
## 🚀 Deployment
|
| 153 |
|
| 154 |
+
See [Deployment Guide](docs/prod/DEPLOYMENT.md) for production deployment instructions.
|
| 155 |
|
| 156 |
+
## 📝 License
|
| 157 |
|
| 158 |
+
Proprietary - All rights reserved
|
| 159 |
|
| 160 |
+
## 👥 Team
|
| 161 |
|
| 162 |
+
SwiftOps Development Team
|
alembic.ini
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[alembic]
|
| 2 |
+
script_location = alembic
|
| 3 |
+
prepend_sys_path = .
|
| 4 |
+
version_path_separator = os
|
| 5 |
+
sqlalchemy.url = postgresql://swiftops:swiftops_dev@localhost:5432/swiftops_db
|
| 6 |
+
|
| 7 |
+
[post_write_hooks]
|
| 8 |
+
|
| 9 |
+
[loggers]
|
| 10 |
+
keys = root,sqlalchemy,alembic
|
| 11 |
+
|
| 12 |
+
[handlers]
|
| 13 |
+
keys = console
|
| 14 |
+
|
| 15 |
+
[formatters]
|
| 16 |
+
keys = generic
|
| 17 |
+
|
| 18 |
+
[logger_root]
|
| 19 |
+
level = WARN
|
| 20 |
+
handlers = console
|
| 21 |
+
qualname =
|
| 22 |
+
|
| 23 |
+
[logger_sqlalchemy]
|
| 24 |
+
level = WARN
|
| 25 |
+
handlers =
|
| 26 |
+
qualname = sqlalchemy.engine
|
| 27 |
+
|
| 28 |
+
[logger_alembic]
|
| 29 |
+
level = INFO
|
| 30 |
+
handlers =
|
| 31 |
+
qualname = alembic
|
| 32 |
+
|
| 33 |
+
[handler_console]
|
| 34 |
+
class = StreamHandler
|
| 35 |
+
args = (sys.stderr,)
|
| 36 |
+
level = NOTSET
|
| 37 |
+
formatter = generic
|
| 38 |
+
|
| 39 |
+
[formatter_generic]
|
| 40 |
+
format = %(levelname)-5.5s [%(name)s] %(message)s
|
| 41 |
+
datefmt = %H:%M:%S
|
alembic/env.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Alembic Environment Configuration
|
| 3 |
+
"""
|
| 4 |
+
from logging.config import fileConfig
|
| 5 |
+
from sqlalchemy import engine_from_config
|
| 6 |
+
from sqlalchemy import pool
|
| 7 |
+
from alembic import context
|
| 8 |
+
import sys
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
# Add src directory to path
|
| 12 |
+
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
| 13 |
+
|
| 14 |
+
from app.core.database import Base
|
| 15 |
+
from app.config import settings
|
| 16 |
+
|
| 17 |
+
# Import all models to ensure they're registered with Base
|
| 18 |
+
from app.models import user, organization, project, ticket, customer, incident, inventory, finance, timesheet, document, media, audit_log
|
| 19 |
+
|
| 20 |
+
# this is the Alembic Config object
|
| 21 |
+
config = context.config
|
| 22 |
+
|
| 23 |
+
# Interpret the config file for Python logging
|
| 24 |
+
if config.config_file_name is not None:
|
| 25 |
+
fileConfig(config.config_file_name)
|
| 26 |
+
|
| 27 |
+
# Set sqlalchemy.url from settings
|
| 28 |
+
config.set_main_option("sqlalchemy.url", settings.DATABASE_URL)
|
| 29 |
+
|
| 30 |
+
# add your model's MetaData object here for 'autogenerate' support
|
| 31 |
+
target_metadata = Base.metadata
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def run_migrations_offline() -> None:
|
| 35 |
+
"""Run migrations in 'offline' mode."""
|
| 36 |
+
url = config.get_main_option("sqlalchemy.url")
|
| 37 |
+
context.configure(
|
| 38 |
+
url=url,
|
| 39 |
+
target_metadata=target_metadata,
|
| 40 |
+
literal_binds=True,
|
| 41 |
+
dialect_opts={"paramstyle": "named"},
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
with context.begin_transaction():
|
| 45 |
+
context.run_migrations()
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def run_migrations_online() -> None:
|
| 49 |
+
"""Run migrations in 'online' mode."""
|
| 50 |
+
connectable = engine_from_config(
|
| 51 |
+
config.get_section(config.config_ini_section, {}),
|
| 52 |
+
prefix="sqlalchemy.",
|
| 53 |
+
poolclass=pool.NullPool,
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
with connectable.connect() as connection:
|
| 57 |
+
context.configure(
|
| 58 |
+
connection=connection, target_metadata=target_metadata
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
with context.begin_transaction():
|
| 62 |
+
context.run_migrations()
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
if context.is_offline_mode():
|
| 66 |
+
run_migrations_offline()
|
| 67 |
+
else:
|
| 68 |
+
run_migrations_online()
|
alembic/script.py.mako
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""${message}
|
| 2 |
+
|
| 3 |
+
Revision ID: ${up_revision}
|
| 4 |
+
Revises: ${down_revision | comma,n}
|
| 5 |
+
Create Date: ${create_date}
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from alembic import op
|
| 9 |
+
import sqlalchemy as sa
|
| 10 |
+
${imports if imports else ""}
|
| 11 |
+
|
| 12 |
+
# revision identifiers, used by Alembic.
|
| 13 |
+
revision = ${repr(up_revision)}
|
| 14 |
+
down_revision = ${repr(down_revision)}
|
| 15 |
+
branch_labels = ${repr(branch_labels)}
|
| 16 |
+
depends_on = ${repr(depends_on)}
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def upgrade() -> None:
|
| 20 |
+
${upgrades if upgrades else "pass"}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def downgrade() -> None:
|
| 24 |
+
${downgrades if downgrades else "pass"}
|
docs/README.md
ADDED
|
@@ -0,0 +1,774 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend API
|
| 2 |
+
|
| 3 |
+
**Field Service Management Platform - FastAPI Backend**
|
| 4 |
+
|
| 5 |
+
A scalable, production-ready FastAPI backend for managing field service operations including ticket management, payroll processing, inventory tracking, and financial workflows.
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## 🏗️ Architecture Overview
|
| 10 |
+
|
| 11 |
+
```
|
| 12 |
+
backend/
|
| 13 |
+
├── app/
|
| 14 |
+
│ ├── __init__.py
|
| 15 |
+
│ ├── main.py # FastAPI application entry point
|
| 16 |
+
│ ├── config.py # Configuration management (env vars, settings)
|
| 17 |
+
│ │
|
| 18 |
+
│ ├── api/ # API Layer - HTTP endpoints
|
| 19 |
+
│ │ ├── __init__.py
|
| 20 |
+
│ │ ├── deps.py # Shared dependencies (auth, db session)
|
| 21 |
+
│ │ ├── v1/ # API version 1
|
| 22 |
+
│ │ │ ├── __init__.py
|
| 23 |
+
│ │ │ ├── router.py # Main router aggregator
|
| 24 |
+
│ │ │ ├── auth.py # Authentication endpoints
|
| 25 |
+
│ │ │ ├── users.py # User management
|
| 26 |
+
│ │ │ ├── projects.py # Project CRUD
|
| 27 |
+
│ │ │ ├── tickets.py # Ticket operations
|
| 28 |
+
│ │ │ ├── assignments.py # Ticket assignment logic
|
| 29 |
+
│ │ │ ├── payroll.py # Payroll generation & management
|
| 30 |
+
│ │ │ ├── inventory.py # Inventory tracking
|
| 31 |
+
│ │ │ ├── finance.py # Financial transactions
|
| 32 |
+
│ │ │ ├── customers.py # Customer management
|
| 33 |
+
│ │ │ ├── subscriptions.py # Subscription lifecycle
|
| 34 |
+
│ │ │ ├── incidents.py # Support incidents
|
| 35 |
+
│ │ │ ├── sales_orders.py # Sales order processing
|
| 36 |
+
│ │ │ ├── analytics.py # Dashboard & reporting
|
| 37 |
+
│ │ │ └── webhooks.py # Payment gateway webhooks
|
| 38 |
+
│ │ │
|
| 39 |
+
│ │ └── websockets/ # WebSocket endpoints
|
| 40 |
+
│ │ ├── __init__.py
|
| 41 |
+
│ │ ├── location.py # Real-time location tracking
|
| 42 |
+
│ │ └── notifications.py # Real-time notifications
|
| 43 |
+
│ │
|
| 44 |
+
│ ├── core/ # Core Business Logic
|
| 45 |
+
│ │ ├── __init__.py
|
| 46 |
+
│ │ ├── auth.py # JWT handling, password hashing
|
| 47 |
+
│ │ ├── security.py # RLS, permissions, RBAC
|
| 48 |
+
│ │ ├── exceptions.py # Custom exception classes
|
| 49 |
+
│ │ └── middleware.py # Custom middleware (logging, CORS)
|
| 50 |
+
│ │
|
| 51 |
+
│ ├── services/ # Business Logic Layer
|
| 52 |
+
│ │ ├── __init__.py
|
| 53 |
+
│ │ ├── ticket_service.py # Ticket lifecycle, assignment logic
|
| 54 |
+
│ │ ├── payroll_service.py # Payroll calculation, generation
|
| 55 |
+
│ │ ├── inventory_service.py # Inventory allocation, tracking
|
| 56 |
+
│ │ ├── finance_service.py # Transaction workflows, approvals
|
| 57 |
+
│ │ ├── sla_service.py # SLA calculation, monitoring
|
| 58 |
+
│ │ ├── location_service.py # GPS validation, distance calculation
|
| 59 |
+
│ │ ├── notification_service.py # Email, SMS, push notifications
|
| 60 |
+
│ │ ├── payment_service.py # Payment gateway integration
|
| 61 |
+
│ │ ├── subscription_service.py # Subscription activation, lifecycle
|
| 62 |
+
│ │ └── analytics_service.py # Metrics, dashboard data
|
| 63 |
+
│ │
|
| 64 |
+
│ ├── models/ # SQLAlchemy ORM Models
|
| 65 |
+
│ │ ├── __init__.py
|
| 66 |
+
│ │ ├── base.py # Base model with common fields
|
| 67 |
+
│ │ ├── user.py # User, UserFinancialAccounts
|
| 68 |
+
│ │ ├── organization.py # Clients, Contractors
|
| 69 |
+
│ │ ├── project.py # Projects, ProjectTeam, ProjectRoles
|
| 70 |
+
│ │ ├── ticket.py # Tickets, TicketAssignments, TicketStatusHistory
|
| 71 |
+
│ │ ├── customer.py # Customers, SalesOrders, Subscriptions
|
| 72 |
+
│ │ ├── incident.py # Incidents
|
| 73 |
+
│ │ ├── inventory.py # ProjectInventory, InventoryAssignments
|
| 74 |
+
│ │ ├── finance.py # ProjectFinance, UserPayroll, PaymentLogs
|
| 75 |
+
│ │ ├── timesheet.py # Timesheets
|
| 76 |
+
│ │ └── document.py # Documents
|
| 77 |
+
│ │
|
| 78 |
+
│ ├── schemas/ # Pydantic Schemas (Request/Response)
|
| 79 |
+
│ │ ├── __init__.py
|
| 80 |
+
│ │ ├── user.py # UserCreate, UserUpdate, UserResponse
|
| 81 |
+
│ │ ├── project.py # ProjectCreate, ProjectUpdate, ProjectResponse
|
| 82 |
+
│ │ ├── ticket.py # TicketCreate, TicketUpdate, TicketResponse
|
| 83 |
+
│ │ ├── payroll.py # PayrollCreate, PayrollCalculation
|
| 84 |
+
│ │ ├── inventory.py # InventoryAssignment, InventoryDistribution
|
| 85 |
+
│ │ ├── finance.py # TransactionCreate, TransactionApproval
|
| 86 |
+
│ │ └── common.py # Shared schemas (Pagination, Filters)
|
| 87 |
+
│ │
|
| 88 |
+
│ ├── repositories/ # Data Access Layer (Repository Pattern)
|
| 89 |
+
│ │ ├── __init__.py
|
| 90 |
+
│ │ ├── base.py # Base repository with CRUD operations
|
| 91 |
+
│ │ ├── user_repository.py # User-specific queries
|
| 92 |
+
│ │ ├── ticket_repository.py # Ticket-specific queries
|
| 93 |
+
│ │ ├── payroll_repository.py # Payroll-specific queries
|
| 94 |
+
│ │ └── finance_repository.py # Finance-specific queries
|
| 95 |
+
│ │
|
| 96 |
+
│ ├── tasks/ # Background Tasks (Celery)
|
| 97 |
+
│ │ ├── __init__.py
|
| 98 |
+
│ │ ├── celery_app.py # Celery configuration
|
| 99 |
+
│ │ ├── payroll_tasks.py # Weekly payroll generation
|
| 100 |
+
│ │ ├── sla_tasks.py # SLA monitoring, alerts
|
| 101 |
+
│ │ ├── notification_tasks.py # Send emails, SMS
|
| 102 |
+
│ │ ├── invoice_tasks.py # Generate contractor invoices
|
| 103 |
+
│ │ └── analytics_tasks.py # Pre-compute dashboard metrics
|
| 104 |
+
│ │
|
| 105 |
+
│ ├── integrations/ # External Service Integrations
|
| 106 |
+
│ │ ├── __init__.py
|
| 107 |
+
│ │ ├── supabase.py # Supabase client (Auth, Storage, Realtime)
|
| 108 |
+
│ │ ├── mpesa.py # M-Pesa payment gateway
|
| 109 |
+
│ │ ├── google_maps.py # Google Maps API (geocoding, distance)
|
| 110 |
+
│ │ ├── sms_provider.py # SMS gateway (Africa's Talking, Twilio)
|
| 111 |
+
│ │ ├── email_provider.py # Email service (SendGrid, AWS SES)
|
| 112 |
+
│ │ └── storage.py # File storage (Supabase Storage, S3)
|
| 113 |
+
│ │
|
| 114 |
+
│ ├── utils/ # Utility Functions
|
| 115 |
+
│ │ ├── __init__.py
|
| 116 |
+
│ │ ├── date_utils.py # Date/time helpers
|
| 117 |
+
│ │ ├── location_utils.py # GPS calculations, distance
|
| 118 |
+
│ │ ├── validation.py # Custom validators
|
| 119 |
+
│ │ ├── formatters.py # Data formatting helpers
|
| 120 |
+
│ │ └── constants.py # Application constants
|
| 121 |
+
│ │
|
| 122 |
+
│ └── db/ # Database Configuration
|
| 123 |
+
│ ├── __init__.py
|
| 124 |
+
│ ├── session.py # Database session management
|
| 125 |
+
│ ├── base.py # Base class for all models
|
| 126 |
+
│ └── migrations/ # Alembic migrations
|
| 127 |
+
│ └── versions/
|
| 128 |
+
│
|
| 129 |
+
├── tests/ # Test Suite
|
| 130 |
+
│ ├── __init__.py
|
| 131 |
+
│ ├── conftest.py # Pytest fixtures
|
| 132 |
+
│ ├── unit/ # Unit tests
|
| 133 |
+
│ │ ├── test_services/
|
| 134 |
+
│ │ ├── test_repositories/
|
| 135 |
+
│ │ └── test_utils/
|
| 136 |
+
│ ├── integration/ # Integration tests
|
| 137 |
+
│ │ ├── test_api/
|
| 138 |
+
│ │ └── test_tasks/
|
| 139 |
+
│ └── e2e/ # End-to-end tests
|
| 140 |
+
│
|
| 141 |
+
├── scripts/ # Utility Scripts
|
| 142 |
+
│ ├── seed_data.py # Seed database with test data
|
| 143 |
+
│ ├── generate_payroll.py # Manual payroll generation
|
| 144 |
+
│ └── migrate_data.py # Data migration scripts
|
| 145 |
+
│
|
| 146 |
+
├── .env.example # Environment variables template
|
| 147 |
+
├── .gitignore
|
| 148 |
+
├── requirements.txt # Python dependencies
|
| 149 |
+
├── pyproject.toml # Poetry configuration (alternative)
|
| 150 |
+
├── Dockerfile # Docker container definition
|
| 151 |
+
├── docker-compose.yml # Local development setup
|
| 152 |
+
└── README.md # This file
|
| 153 |
+
```
|
| 154 |
+
|
| 155 |
+
---
|
| 156 |
+
|
| 157 |
+
## 🎯 Core Functions & Responsibilities
|
| 158 |
+
|
| 159 |
+
### **1. Authentication & Authorization**
|
| 160 |
+
**Module**: `app/api/v1/auth.py`, `app/core/auth.py`, `app/core/security.py`
|
| 161 |
+
|
| 162 |
+
**Functions**:
|
| 163 |
+
- User login/logout (JWT token generation)
|
| 164 |
+
- Password reset flow
|
| 165 |
+
- Role-based access control (RBAC)
|
| 166 |
+
- Row-level security (RLS) enforcement
|
| 167 |
+
- Multi-tenancy isolation (client/contractor scoping)
|
| 168 |
+
|
| 169 |
+
**Supabase Integration**:
|
| 170 |
+
- Uses Supabase Auth for user authentication
|
| 171 |
+
- Validates JWT tokens from Supabase
|
| 172 |
+
- Syncs user roles with custom `Users` table
|
| 173 |
+
|
| 174 |
+
---
|
| 175 |
+
|
| 176 |
+
### **2. Ticket Management**
|
| 177 |
+
**Module**: `app/services/ticket_service.py`, `app/api/v1/tickets.py`
|
| 178 |
+
|
| 179 |
+
**Functions**:
|
| 180 |
+
- Create tickets from sales orders, incidents, or tasks
|
| 181 |
+
- Ticket assignment logic (manual, auto-assignment)
|
| 182 |
+
- Limit self-assignment to 3 tickets per agent
|
| 183 |
+
- Status transitions with validation
|
| 184 |
+
- SLA deadline calculation and monitoring
|
| 185 |
+
- GPS-based arrival verification
|
| 186 |
+
- Ticket completion workflow
|
| 187 |
+
|
| 188 |
+
**Business Rules**:
|
| 189 |
+
```python
|
| 190 |
+
# Example: Ticket Assignment Logic
|
| 191 |
+
def assign_ticket(ticket_id, user_id):
|
| 192 |
+
# 1. Check user has < 3 active assignments
|
| 193 |
+
# 2. Verify user is in project team
|
| 194 |
+
# 3. Check user's region matches ticket region
|
| 195 |
+
# 4. Create TicketAssignment record
|
| 196 |
+
# 5. Update ticket status to 'assigned'
|
| 197 |
+
# 6. Send notification to agent
|
| 198 |
+
# 7. Update SLA target date
|
| 199 |
+
```
|
| 200 |
+
|
| 201 |
+
---
|
| 202 |
+
|
| 203 |
+
### **3. Payroll Processing**
|
| 204 |
+
**Module**: `app/services/payroll_service.py`, `app/api/v1/payroll.py`
|
| 205 |
+
|
| 206 |
+
**Functions**:
|
| 207 |
+
- Weekly payroll generation (automated via Celery)
|
| 208 |
+
- Calculate earnings based on compensation type:
|
| 209 |
+
- Flat rate (fixed weekly amount)
|
| 210 |
+
- Commission (% of package price)
|
| 211 |
+
- Hybrid (base + commission)
|
| 212 |
+
- Hourly (based on timesheet hours)
|
| 213 |
+
- Apply deductions (advances, penalties)
|
| 214 |
+
- Generate payroll reports
|
| 215 |
+
- Mark payroll as paid with payment reference
|
| 216 |
+
|
| 217 |
+
**Business Rules**:
|
| 218 |
+
```python
|
| 219 |
+
# Example: Payroll Calculation
|
| 220 |
+
def calculate_payroll(user_id, project_id, period_start, period_end):
|
| 221 |
+
role = get_user_project_role(user_id, project_id)
|
| 222 |
+
tickets_closed = count_tickets_closed(user_id, period_start, period_end)
|
| 223 |
+
hours_worked = sum_timesheet_hours(user_id, period_start, period_end)
|
| 224 |
+
|
| 225 |
+
if role.compensation_type == 'flat_rate':
|
| 226 |
+
earnings = role.flat_rate_amount
|
| 227 |
+
elif role.compensation_type == 'commission':
|
| 228 |
+
earnings = sum_ticket_values(tickets) * role.commission_percentage
|
| 229 |
+
elif role.compensation_type == 'hybrid':
|
| 230 |
+
earnings = role.base_amount + (sum_ticket_values(tickets) * role.commission_percentage)
|
| 231 |
+
elif role.compensation_type == 'hourly':
|
| 232 |
+
earnings = hours_worked * role.hourly_rate
|
| 233 |
+
|
| 234 |
+
deductions = get_user_deductions(user_id, period_start, period_end)
|
| 235 |
+
total = earnings - deductions
|
| 236 |
+
|
| 237 |
+
return create_payroll_record(...)
|
| 238 |
+
```
|
| 239 |
+
|
| 240 |
+
---
|
| 241 |
+
|
| 242 |
+
### **4. Inventory Management**
|
| 243 |
+
**Module**: `app/services/inventory_service.py`, `app/api/v1/inventory.py`
|
| 244 |
+
|
| 245 |
+
**Functions**:
|
| 246 |
+
- Allocate inventory to regional hubs
|
| 247 |
+
- Issue equipment to field agents
|
| 248 |
+
- Track serial numbers and unit identifiers
|
| 249 |
+
- Prevent duplicate assignments (same serial issued twice)
|
| 250 |
+
- Handle returns (tools) and installations (equipment)
|
| 251 |
+
- Optimistic locking for concurrent updates
|
| 252 |
+
- Inventory reconciliation reports
|
| 253 |
+
|
| 254 |
+
**Business Rules**:
|
| 255 |
+
```python
|
| 256 |
+
# Example: Inventory Assignment
|
| 257 |
+
def assign_inventory_to_agent(distribution_id, user_id, unit_identifier):
|
| 258 |
+
# 1. Check unit_identifier not already assigned
|
| 259 |
+
# 2. Verify quantity_available > 0
|
| 260 |
+
# 3. Check user is in same region as distribution
|
| 261 |
+
# 4. Create InventoryAssignment record
|
| 262 |
+
# 5. Update distribution.quantity_issued
|
| 263 |
+
# 6. Use optimistic locking (version field)
|
| 264 |
+
```
|
| 265 |
+
|
| 266 |
+
---
|
| 267 |
+
|
| 268 |
+
### **5. Financial Management**
|
| 269 |
+
**Module**: `app/services/finance_service.py`, `app/api/v1/finance.py`
|
| 270 |
+
|
| 271 |
+
**Functions**:
|
| 272 |
+
- Record project expenses (inflows/outflows)
|
| 273 |
+
- Approval workflow (pending → approved → paid)
|
| 274 |
+
- Link to entities (tickets, payroll, invoices)
|
| 275 |
+
- Payment gateway integration (M-Pesa, bank transfers)
|
| 276 |
+
- Transaction reconciliation
|
| 277 |
+
- Financial reporting and audit trails
|
| 278 |
+
|
| 279 |
+
**Business Rules**:
|
| 280 |
+
```python
|
| 281 |
+
# Example: Expense Approval Workflow
|
| 282 |
+
def approve_expense(expense_id, approver_id):
|
| 283 |
+
# 1. Check approver has 'dispatcher' or 'project_manager' role
|
| 284 |
+
# 2. Verify expense is in 'pending' status
|
| 285 |
+
# 3. Validate location_verified = TRUE (if required)
|
| 286 |
+
# 4. Update status to 'approved'
|
| 287 |
+
# 5. Create ProjectFinance record
|
| 288 |
+
# 6. Send notification to incurred_by_user
|
| 289 |
+
```
|
| 290 |
+
|
| 291 |
+
---
|
| 292 |
+
|
| 293 |
+
### **6. Location Tracking**
|
| 294 |
+
**Module**: `app/services/location_service.py`, `app/api/websockets/location.py`
|
| 295 |
+
|
| 296 |
+
**Functions**:
|
| 297 |
+
- Real-time GPS tracking via WebSocket
|
| 298 |
+
- Validate agent arrival at customer site
|
| 299 |
+
- Calculate distance between agent and customer
|
| 300 |
+
- Journey tracking (breadcrumb trail)
|
| 301 |
+
- Fraud detection (impossible travel speeds)
|
| 302 |
+
- Update user current location
|
| 303 |
+
|
| 304 |
+
**Business Rules**:
|
| 305 |
+
```python
|
| 306 |
+
# Example: Arrival Verification
|
| 307 |
+
def verify_arrival(ticket_id, agent_location):
|
| 308 |
+
ticket = get_ticket(ticket_id)
|
| 309 |
+
customer_location = get_customer_location(ticket.customer_id)
|
| 310 |
+
|
| 311 |
+
distance = calculate_distance(agent_location, customer_location)
|
| 312 |
+
|
| 313 |
+
if distance <= 100: # Within 100 meters
|
| 314 |
+
mark_arrived(ticket_id, agent_location, verified=True)
|
| 315 |
+
else:
|
| 316 |
+
mark_arrived(ticket_id, agent_location, verified=False)
|
| 317 |
+
```
|
| 318 |
+
|
| 319 |
+
---
|
| 320 |
+
|
| 321 |
+
### **7. SLA Monitoring**
|
| 322 |
+
**Module**: `app/services/sla_service.py`, `app/tasks/sla_tasks.py`
|
| 323 |
+
|
| 324 |
+
**Functions**:
|
| 325 |
+
- Calculate SLA deadlines based on priority
|
| 326 |
+
- Monitor tickets approaching deadline
|
| 327 |
+
- Send alerts to managers and agents
|
| 328 |
+
- Mark tickets as SLA violated
|
| 329 |
+
- Generate SLA compliance reports
|
| 330 |
+
|
| 331 |
+
**Background Task** (runs every hour):
|
| 332 |
+
```python
|
| 333 |
+
@celery_app.task
|
| 334 |
+
def monitor_sla_violations():
|
| 335 |
+
# 1. Find tickets with sla_target_date < now() and status != 'completed'
|
| 336 |
+
# 2. Mark sla_violated = TRUE
|
| 337 |
+
# 3. Send notifications to project managers
|
| 338 |
+
# 4. Log SLA violation event
|
| 339 |
+
```
|
| 340 |
+
|
| 341 |
+
---
|
| 342 |
+
|
| 343 |
+
### **8. Payment Gateway Integration**
|
| 344 |
+
**Module**: `app/services/payment_service.py`, `app/integrations/mpesa.py`
|
| 345 |
+
|
| 346 |
+
**Functions**:
|
| 347 |
+
- Initiate M-Pesa payments (B2C, B2B)
|
| 348 |
+
- Handle payment callbacks/webhooks
|
| 349 |
+
- Retry failed payments
|
| 350 |
+
- Log all payment attempts (PaymentLogs)
|
| 351 |
+
- Reconcile payments with transactions
|
| 352 |
+
|
| 353 |
+
**Webhook Handler**:
|
| 354 |
+
```python
|
| 355 |
+
@router.post("/webhooks/mpesa")
|
| 356 |
+
async def mpesa_callback(payload: dict):
|
| 357 |
+
# 1. Validate webhook signature
|
| 358 |
+
# 2. Parse payment result
|
| 359 |
+
# 3. Update ProjectFinance status
|
| 360 |
+
# 4. Create PaymentLog entry
|
| 361 |
+
# 5. Send notification to user
|
| 362 |
+
```
|
| 363 |
+
|
| 364 |
+
---
|
| 365 |
+
|
| 366 |
+
### **9. Subscription Management**
|
| 367 |
+
**Module**: `app/services/subscription_service.py`, `app/api/v1/subscriptions.py`
|
| 368 |
+
|
| 369 |
+
**Functions**:
|
| 370 |
+
- Activate subscriptions after installation
|
| 371 |
+
- Validate activation requirements (dynamic per project)
|
| 372 |
+
- Manage subscription lifecycle (active, suspended, cancelled)
|
| 373 |
+
- Link subscriptions to tickets and sales orders
|
| 374 |
+
|
| 375 |
+
**Business Rules**:
|
| 376 |
+
```python
|
| 377 |
+
# Example: Subscription Activation
|
| 378 |
+
def activate_subscription(subscription_id, activation_data):
|
| 379 |
+
subscription = get_subscription(subscription_id)
|
| 380 |
+
project = get_project(subscription.project_id)
|
| 381 |
+
|
| 382 |
+
# Validate dynamic activation requirements
|
| 383 |
+
for requirement in project.activation_requirements:
|
| 384 |
+
if requirement['required'] and requirement['field'] not in activation_data:
|
| 385 |
+
raise ValidationError(f"Missing required field: {requirement['label']}")
|
| 386 |
+
|
| 387 |
+
# Update subscription
|
| 388 |
+
subscription.status = 'active'
|
| 389 |
+
subscription.activation_date = date.today()
|
| 390 |
+
subscription.activation_details = activation_data
|
| 391 |
+
subscription.activated_by_user_id = current_user.id
|
| 392 |
+
```
|
| 393 |
+
|
| 394 |
+
---
|
| 395 |
+
|
| 396 |
+
### **10. Analytics & Reporting**
|
| 397 |
+
**Module**: `app/services/analytics_service.py`, `app/api/v1/analytics.py`
|
| 398 |
+
|
| 399 |
+
**Functions**:
|
| 400 |
+
- Dashboard metrics (tickets, revenue, SLA compliance)
|
| 401 |
+
- Agent performance reports
|
| 402 |
+
- Project financial summaries
|
| 403 |
+
- Inventory utilization reports
|
| 404 |
+
- Pre-computed aggregations (via Celery)
|
| 405 |
+
|
| 406 |
+
**Background Task** (runs daily):
|
| 407 |
+
```python
|
| 408 |
+
@celery_app.task
|
| 409 |
+
def compute_daily_metrics():
|
| 410 |
+
# 1. Calculate tickets closed per agent
|
| 411 |
+
# 2. Compute average completion time
|
| 412 |
+
# 3. Calculate SLA compliance rate
|
| 413 |
+
# 4. Store in cache (Redis)
|
| 414 |
+
```
|
| 415 |
+
|
| 416 |
+
---
|
| 417 |
+
|
| 418 |
+
## 🔗 Supabase Integration Points
|
| 419 |
+
|
| 420 |
+
### **1. Authentication**
|
| 421 |
+
```python
|
| 422 |
+
# app/integrations/supabase.py
|
| 423 |
+
from supabase import create_client
|
| 424 |
+
|
| 425 |
+
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 426 |
+
|
| 427 |
+
# Verify JWT token from frontend
|
| 428 |
+
def verify_token(token: str):
|
| 429 |
+
user = supabase.auth.get_user(token)
|
| 430 |
+
return user
|
| 431 |
+
```
|
| 432 |
+
|
| 433 |
+
### **2. Storage (File Uploads)**
|
| 434 |
+
```python
|
| 435 |
+
# Upload ticket photos, receipts
|
| 436 |
+
def upload_document(file, bucket="documents"):
|
| 437 |
+
path = f"{user_id}/{ticket_id}/{filename}"
|
| 438 |
+
supabase.storage.from_(bucket).upload(path, file)
|
| 439 |
+
return supabase.storage.from_(bucket).get_public_url(path)
|
| 440 |
+
```
|
| 441 |
+
|
| 442 |
+
### **3. Realtime (WebSocket)**
|
| 443 |
+
```python
|
| 444 |
+
# Subscribe to ticket updates
|
| 445 |
+
supabase.realtime.channel('tickets')
|
| 446 |
+
.on('postgres_changes',
|
| 447 |
+
event='UPDATE',
|
| 448 |
+
schema='public',
|
| 449 |
+
table='Tickets',
|
| 450 |
+
callback=handle_ticket_update)
|
| 451 |
+
.subscribe()
|
| 452 |
+
```
|
| 453 |
+
|
| 454 |
+
### **4. Database (Direct Queries)**
|
| 455 |
+
```python
|
| 456 |
+
# Use Supabase client for simple queries (optional)
|
| 457 |
+
# For complex queries, use SQLAlchemy ORM
|
| 458 |
+
tickets = supabase.table('Tickets').select('*').eq('status', 'open').execute()
|
| 459 |
+
```
|
| 460 |
+
|
| 461 |
+
---
|
| 462 |
+
|
| 463 |
+
## 🚀 Getting Started
|
| 464 |
+
|
| 465 |
+
### **Prerequisites**
|
| 466 |
+
- Python 3.11+
|
| 467 |
+
- PostgreSQL 15+ (Supabase)
|
| 468 |
+
- Redis (for caching and Celery)
|
| 469 |
+
- Docker & Docker Compose (optional)
|
| 470 |
+
|
| 471 |
+
### **Installation**
|
| 472 |
+
|
| 473 |
+
1. **Clone the repository**
|
| 474 |
+
```bash
|
| 475 |
+
git clone <repo-url>
|
| 476 |
+
cd backend
|
| 477 |
+
```
|
| 478 |
+
|
| 479 |
+
2. **Create virtual environment**
|
| 480 |
+
```bash
|
| 481 |
+
python -m venv venv
|
| 482 |
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
| 483 |
+
```
|
| 484 |
+
|
| 485 |
+
3. **Install dependencies**
|
| 486 |
+
```bash
|
| 487 |
+
pip install -r requirements.txt
|
| 488 |
+
```
|
| 489 |
+
|
| 490 |
+
4. **Set up environment variables**
|
| 491 |
+
```bash
|
| 492 |
+
cp .env.example .env
|
| 493 |
+
# Edit .env with your Supabase credentials
|
| 494 |
+
```
|
| 495 |
+
|
| 496 |
+
5. **Run database migrations**
|
| 497 |
+
```bash
|
| 498 |
+
alembic upgrade head
|
| 499 |
+
```
|
| 500 |
+
|
| 501 |
+
6. **Start the development server**
|
| 502 |
+
```bash
|
| 503 |
+
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
| 504 |
+
```
|
| 505 |
+
|
| 506 |
+
7. **Start Celery worker** (in separate terminal)
|
| 507 |
+
```bash
|
| 508 |
+
celery -A app.tasks.celery_app worker --loglevel=info
|
| 509 |
+
```
|
| 510 |
+
|
| 511 |
+
8. **Start Celery beat** (scheduler, in separate terminal)
|
| 512 |
+
```bash
|
| 513 |
+
celery -A app.tasks.celery_app beat --loglevel=info
|
| 514 |
+
```
|
| 515 |
+
|
| 516 |
+
---
|
| 517 |
+
|
| 518 |
+
## 🐳 Docker Setup
|
| 519 |
+
|
| 520 |
+
```bash
|
| 521 |
+
# Start all services (API, Celery, Redis)
|
| 522 |
+
docker-compose up -d
|
| 523 |
+
|
| 524 |
+
# View logs
|
| 525 |
+
docker-compose logs -f api
|
| 526 |
+
|
| 527 |
+
# Stop services
|
| 528 |
+
docker-compose down
|
| 529 |
+
```
|
| 530 |
+
|
| 531 |
+
---
|
| 532 |
+
|
| 533 |
+
## 📝 Environment Variables
|
| 534 |
+
|
| 535 |
+
```bash
|
| 536 |
+
# .env.example
|
| 537 |
+
|
| 538 |
+
# Application
|
| 539 |
+
APP_NAME=SwiftOps API
|
| 540 |
+
APP_VERSION=1.0.0
|
| 541 |
+
DEBUG=True
|
| 542 |
+
ENVIRONMENT=development
|
| 543 |
+
|
| 544 |
+
# Database (Supabase PostgreSQL)
|
| 545 |
+
DATABASE_URL=postgresql://user:password@host:5432/dbname
|
| 546 |
+
SUPABASE_URL=https://your-project.supabase.co
|
| 547 |
+
SUPABASE_KEY=your-anon-key
|
| 548 |
+
SUPABASE_SERVICE_KEY=your-service-role-key
|
| 549 |
+
|
| 550 |
+
# JWT
|
| 551 |
+
SECRET_KEY=your-secret-key-here
|
| 552 |
+
ALGORITHM=HS256
|
| 553 |
+
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 554 |
+
|
| 555 |
+
# Redis
|
| 556 |
+
REDIS_URL=redis://localhost:6379/0
|
| 557 |
+
|
| 558 |
+
# Celery
|
| 559 |
+
CELERY_BROKER_URL=redis://localhost:6379/0
|
| 560 |
+
CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
| 561 |
+
|
| 562 |
+
# Payment Gateways
|
| 563 |
+
MPESA_CONSUMER_KEY=your-mpesa-key
|
| 564 |
+
MPESA_CONSUMER_SECRET=your-mpesa-secret
|
| 565 |
+
MPESA_SHORTCODE=174379
|
| 566 |
+
MPESA_PASSKEY=your-passkey
|
| 567 |
+
|
| 568 |
+
# Google Maps
|
| 569 |
+
GOOGLE_MAPS_API_KEY=your-google-maps-key
|
| 570 |
+
|
| 571 |
+
# SMS Provider (Africa's Talking)
|
| 572 |
+
AFRICASTALKING_USERNAME=your-username
|
| 573 |
+
AFRICASTALKING_API_KEY=your-api-key
|
| 574 |
+
|
| 575 |
+
# Email Provider (SendGrid)
|
| 576 |
+
SENDGRID_API_KEY=your-sendgrid-key
|
| 577 |
+
FROM_EMAIL=noreply@swiftops.com
|
| 578 |
+
|
| 579 |
+
# File Storage
|
| 580 |
+
STORAGE_PROVIDER=supabase # or 's3'
|
| 581 |
+
AWS_ACCESS_KEY_ID=your-aws-key
|
| 582 |
+
AWS_SECRET_ACCESS_KEY=your-aws-secret
|
| 583 |
+
AWS_S3_BUCKET=your-bucket-name
|
| 584 |
+
```
|
| 585 |
+
|
| 586 |
+
---
|
| 587 |
+
|
| 588 |
+
## 🧪 Testing
|
| 589 |
+
|
| 590 |
+
```bash
|
| 591 |
+
# Run all tests
|
| 592 |
+
pytest
|
| 593 |
+
|
| 594 |
+
# Run with coverage
|
| 595 |
+
pytest --cov=app --cov-report=html
|
| 596 |
+
|
| 597 |
+
# Run specific test file
|
| 598 |
+
pytest tests/unit/test_services/test_payroll_service.py
|
| 599 |
+
|
| 600 |
+
# Run integration tests only
|
| 601 |
+
pytest tests/integration/
|
| 602 |
+
```
|
| 603 |
+
|
| 604 |
+
---
|
| 605 |
+
|
| 606 |
+
## 📚 API Documentation
|
| 607 |
+
|
| 608 |
+
Once the server is running, visit:
|
| 609 |
+
- **Swagger UI**: http://localhost:8000/docs
|
| 610 |
+
- **ReDoc**: http://localhost:8000/redoc
|
| 611 |
+
- **OpenAPI JSON**: http://localhost:8000/openapi.json
|
| 612 |
+
|
| 613 |
+
---
|
| 614 |
+
|
| 615 |
+
## 🏛️ Design Patterns & Best Practices
|
| 616 |
+
|
| 617 |
+
### **1. Repository Pattern**
|
| 618 |
+
Separates data access logic from business logic.
|
| 619 |
+
|
| 620 |
+
```python
|
| 621 |
+
# app/repositories/ticket_repository.py
|
| 622 |
+
class TicketRepository:
|
| 623 |
+
def get_by_id(self, ticket_id: UUID) -> Ticket:
|
| 624 |
+
return db.query(Ticket).filter(Ticket.id == ticket_id).first()
|
| 625 |
+
|
| 626 |
+
def get_open_tickets(self, project_id: UUID) -> List[Ticket]:
|
| 627 |
+
return db.query(Ticket).filter(
|
| 628 |
+
Ticket.project_id == project_id,
|
| 629 |
+
Ticket.status == 'open',
|
| 630 |
+
Ticket.deleted_at.is_(None)
|
| 631 |
+
).all()
|
| 632 |
+
```
|
| 633 |
+
|
| 634 |
+
### **2. Service Layer Pattern**
|
| 635 |
+
Encapsulates business logic.
|
| 636 |
+
|
| 637 |
+
```python
|
| 638 |
+
# app/services/ticket_service.py
|
| 639 |
+
class TicketService:
|
| 640 |
+
def __init__(self, ticket_repo: TicketRepository):
|
| 641 |
+
self.ticket_repo = ticket_repo
|
| 642 |
+
|
| 643 |
+
def assign_ticket(self, ticket_id: UUID, user_id: UUID):
|
| 644 |
+
# Business logic here
|
| 645 |
+
ticket = self.ticket_repo.get_by_id(ticket_id)
|
| 646 |
+
self._validate_assignment(ticket, user_id)
|
| 647 |
+
assignment = self._create_assignment(ticket, user_id)
|
| 648 |
+
self._send_notification(user_id, ticket)
|
| 649 |
+
return assignment
|
| 650 |
+
```
|
| 651 |
+
|
| 652 |
+
### **3. Dependency Injection**
|
| 653 |
+
Use FastAPI's dependency injection system.
|
| 654 |
+
|
| 655 |
+
```python
|
| 656 |
+
# app/api/deps.py
|
| 657 |
+
def get_db():
|
| 658 |
+
db = SessionLocal()
|
| 659 |
+
try:
|
| 660 |
+
yield db
|
| 661 |
+
finally:
|
| 662 |
+
db.close()
|
| 663 |
+
|
| 664 |
+
def get_current_user(token: str = Depends(oauth2_scheme)):
|
| 665 |
+
# Validate token and return user
|
| 666 |
+
return user
|
| 667 |
+
|
| 668 |
+
# Usage in endpoint
|
| 669 |
+
@router.get("/tickets")
|
| 670 |
+
def get_tickets(
|
| 671 |
+
db: Session = Depends(get_db),
|
| 672 |
+
current_user: User = Depends(get_current_user)
|
| 673 |
+
):
|
| 674 |
+
return ticket_service.get_tickets(db, current_user)
|
| 675 |
+
```
|
| 676 |
+
|
| 677 |
+
### **4. Optimistic Locking**
|
| 678 |
+
Prevent concurrent update conflicts.
|
| 679 |
+
|
| 680 |
+
```python
|
| 681 |
+
def update_inventory_distribution(distribution_id, updates, version):
|
| 682 |
+
distribution = db.query(ProjectInventoryDistribution).filter(
|
| 683 |
+
ProjectInventoryDistribution.id == distribution_id,
|
| 684 |
+
ProjectInventoryDistribution.version == version
|
| 685 |
+
).first()
|
| 686 |
+
|
| 687 |
+
if not distribution:
|
| 688 |
+
raise ConcurrentUpdateError("Record was modified by another user")
|
| 689 |
+
|
| 690 |
+
# Apply updates
|
| 691 |
+
distribution.quantity_issued += updates.quantity
|
| 692 |
+
distribution.version += 1
|
| 693 |
+
db.commit()
|
| 694 |
+
```
|
| 695 |
+
|
| 696 |
+
### **5. Soft Deletes**
|
| 697 |
+
Always filter out soft-deleted records.
|
| 698 |
+
|
| 699 |
+
```python
|
| 700 |
+
# Base repository method
|
| 701 |
+
def get_active(self, model_class):
|
| 702 |
+
return db.query(model_class).filter(model_class.deleted_at.is_(None))
|
| 703 |
+
```
|
| 704 |
+
|
| 705 |
+
---
|
| 706 |
+
|
| 707 |
+
## 🔐 Security Considerations
|
| 708 |
+
|
| 709 |
+
1. **Row-Level Security (RLS)**
|
| 710 |
+
- Enforce tenant isolation at database level
|
| 711 |
+
- Use Supabase RLS policies
|
| 712 |
+
|
| 713 |
+
2. **API Rate Limiting**
|
| 714 |
+
- Implement rate limiting per client/user
|
| 715 |
+
- Use Redis for rate limit tracking
|
| 716 |
+
|
| 717 |
+
3. **Input Validation**
|
| 718 |
+
- Use Pydantic schemas for all inputs
|
| 719 |
+
- Validate file uploads (type, size)
|
| 720 |
+
|
| 721 |
+
4. **Audit Logging**
|
| 722 |
+
- Log all financial transactions
|
| 723 |
+
- Track who created/updated records
|
| 724 |
+
|
| 725 |
+
5. **Secrets Management**
|
| 726 |
+
- Never commit secrets to git
|
| 727 |
+
- Use environment variables or secret managers
|
| 728 |
+
|
| 729 |
+
---
|
| 730 |
+
|
| 731 |
+
## 📈 Scalability Considerations
|
| 732 |
+
|
| 733 |
+
1. **Database Connection Pooling**
|
| 734 |
+
- Use SQLAlchemy connection pool
|
| 735 |
+
- Configure pool size based on load
|
| 736 |
+
|
| 737 |
+
2. **Caching Strategy**
|
| 738 |
+
- Cache frequently accessed data (Redis)
|
| 739 |
+
- Invalidate cache on updates
|
| 740 |
+
|
| 741 |
+
3. **Background Jobs**
|
| 742 |
+
- Offload heavy tasks to Celery
|
| 743 |
+
- Use task queues for async processing
|
| 744 |
+
|
| 745 |
+
4. **Horizontal Scaling**
|
| 746 |
+
- Stateless API design
|
| 747 |
+
- Load balance across multiple instances
|
| 748 |
+
|
| 749 |
+
5. **Database Optimization**
|
| 750 |
+
- Use indexes effectively
|
| 751 |
+
- Monitor slow queries
|
| 752 |
+
- Consider read replicas for reporting
|
| 753 |
+
|
| 754 |
+
---
|
| 755 |
+
|
| 756 |
+
## 🤝 Contributing
|
| 757 |
+
|
| 758 |
+
1. Create a feature branch
|
| 759 |
+
2. Write tests for new features
|
| 760 |
+
3. Follow PEP 8 style guide
|
| 761 |
+
4. Update documentation
|
| 762 |
+
5. Submit pull request
|
| 763 |
+
|
| 764 |
+
---
|
| 765 |
+
|
| 766 |
+
## 📄 License
|
| 767 |
+
|
| 768 |
+
[Your License Here]
|
| 769 |
+
|
| 770 |
+
---
|
| 771 |
+
|
| 772 |
+
## 📞 Support
|
| 773 |
+
|
| 774 |
+
For questions or issues, contact: [your-email@example.com]
|
docs/agent/COMPREHENSIVE_BUILD_PLAN.md
ADDED
|
@@ -0,0 +1,2340 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend - Comprehensive Build Plan
|
| 2 |
+
## Senior Developer's End-to-End Implementation Guide
|
| 3 |
+
|
| 4 |
+
**Version:** 1.0
|
| 5 |
+
**Created:** 2025-11-15
|
| 6 |
+
**Status:** Master Build Plan
|
| 7 |
+
**Approach:** Complete System Build (All-at-Once View)
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## 📋 Executive Summary
|
| 12 |
+
|
| 13 |
+
This document provides a complete, end-to-end build plan for the SwiftOps backend system. It's designed for a top 1% senior developer who needs to see the entire architecture, understand all components, and build a robust, maintainable system that a human can easily navigate and extend.
|
| 14 |
+
|
| 15 |
+
### Core Principles
|
| 16 |
+
1. **Clean Architecture** - Clear separation of concerns (API → Service → Repository → Model)
|
| 17 |
+
2. **Domain-Driven Design** - Business logic organized by domain boundaries
|
| 18 |
+
3. **SOLID Principles** - Single responsibility, dependency injection, interface segregation
|
| 19 |
+
4. **Maintainability First** - Code that's easy to read, understand, and modify
|
| 20 |
+
5. **Production-Ready** - Built for scale, monitoring, and operational excellence
|
| 21 |
+
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## 🏗️ Architecture Overview
|
| 25 |
+
|
| 26 |
+
### High-Level System Architecture
|
| 27 |
+
|
| 28 |
+
```
|
| 29 |
+
┌─────────────────────────────────────────────────────────────────┐
|
| 30 |
+
│ CLIENT LAYER │
|
| 31 |
+
│ (Web Dashboard, Mobile App, External APIs) │
|
| 32 |
+
└────────────────────────┬────────────────────────────────────────┘
|
| 33 |
+
│ HTTPS/REST
|
| 34 |
+
┌────────────────────────▼────────────────────────────────────────┐
|
| 35 |
+
│ API GATEWAY LAYER │
|
| 36 |
+
│ • Rate Limiting • Authentication • Request Validation │
|
| 37 |
+
│ • CORS • Compression • Logging │
|
| 38 |
+
└────────────────────────┬────────────────────────────────────────┘
|
| 39 |
+
│
|
| 40 |
+
┌────────────────────────▼────────────────────────────────────────┐
|
| 41 |
+
│ API ENDPOINTS LAYER │
|
| 42 |
+
│ (FastAPI Routers - Thin Controllers) │
|
| 43 |
+
│ • Input Validation (Pydantic) │
|
| 44 |
+
│ • Response Formatting │
|
| 45 |
+
│ • Error Handling │
|
| 46 |
+
└────────────────────────┬────────────────────────────────────────┘
|
| 47 |
+
│
|
| 48 |
+
┌────────────────────────▼────────────────────────────────────────┐
|
| 49 |
+
│ SERVICE LAYER │
|
| 50 |
+
│ (Business Logic - The Brain) │
|
| 51 |
+
│ • Domain Logic • Validation Rules • Orchestration │
|
| 52 |
+
│ • Transaction Management • Event Publishing │
|
| 53 |
+
└────────────────────────┬────────────────────────────────────────┘
|
| 54 |
+
│
|
| 55 |
+
┌────────────────────────▼────────────────────────────────────────┐
|
| 56 |
+
│ REPOSITORY LAYER │
|
| 57 |
+
│ (Data Access - Database Abstraction) │
|
| 58 |
+
│ • CRUD Operations • Query Building • Caching │
|
| 59 |
+
└────────────────────────┬────────────────────────────────────────┘
|
| 60 |
+
│
|
| 61 |
+
┌────────────────────────▼────────────────────────────────────────┐
|
| 62 |
+
│ DATABASE LAYER │
|
| 63 |
+
│ PostgreSQL (Supabase) - Single Source of Truth │
|
| 64 |
+
└─────────────────────────────────────────────────��────────────────┘
|
| 65 |
+
|
| 66 |
+
┌──────────────────────────────────────────────────────────────────┐
|
| 67 |
+
│ SUPPORTING SYSTEMS │
|
| 68 |
+
├──────────────────────────────────────────────────────────────────┤
|
| 69 |
+
│ • Redis (Caching, Sessions, Locks) │
|
| 70 |
+
│ • Celery (Background Jobs, Scheduled Tasks) │
|
| 71 |
+
│ • External APIs (M-Pesa, Cloudinary, Resend, Google Maps) │
|
| 72 |
+
│ • Monitoring (Sentry, Logs, Metrics) │
|
| 73 |
+
└──────────────────────────────────────────────────────────────────┘
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
---
|
| 77 |
+
|
| 78 |
+
## 📁 Complete Folder Structure
|
| 79 |
+
|
| 80 |
+
This is the **definitive** folder structure that ensures maintainability and clarity:
|
| 81 |
+
|
| 82 |
+
```
|
| 83 |
+
swiftops-backend/
|
| 84 |
+
│
|
| 85 |
+
├── src/ # Source code root
|
| 86 |
+
│ └── app/ # Main application package
|
| 87 |
+
│ │
|
| 88 |
+
│ ├── __init__.py # App package initialization
|
| 89 |
+
│ ├── main.py # FastAPI app entry point
|
| 90 |
+
│ ├── config.py # Configuration management
|
| 91 |
+
│ ├── dependencies.py # Global dependencies (DB, Auth)
|
| 92 |
+
│ │
|
| 93 |
+
│ ├── core/ # Core utilities (used everywhere)
|
| 94 |
+
│ │ ├── __init__.py
|
| 95 |
+
│ │ ├── auth.py # JWT, token management
|
| 96 |
+
│ │ ├── security.py # Password hashing, encryption
|
| 97 |
+
│ │ ├── permissions.py # RBAC permission definitions
|
| 98 |
+
│ │ ├── exceptions.py # Custom exception classes
|
| 99 |
+
│ │ ├── logging.py # Structured logging setup
|
| 100 |
+
│ │ └── database.py # Database session management
|
| 101 |
+
│ │
|
| 102 |
+
│ ├── middleware/ # HTTP middleware
|
| 103 |
+
│ │ ├── __init__.py
|
| 104 |
+
│ │ ├── authentication.py # Auth middleware
|
| 105 |
+
│ │ ├── rate_limiting.py # Rate limiter
|
| 106 |
+
│ │ ├── request_logging.py # Request/response logging
|
| 107 |
+
│ │ ├── error_handling.py # Global error handler
|
| 108 |
+
│ │ └── cors.py # CORS configuration
|
| 109 |
+
│ │
|
| 110 |
+
│ ├── api/ # API layer (HTTP endpoints)
|
| 111 |
+
│ │ ├── __init__.py
|
| 112 |
+
│ │ ├── deps.py # Route dependencies
|
| 113 |
+
│ │ │
|
| 114 |
+
│ │ └── v1/ # API version 1
|
| 115 |
+
│ │ ├── __init__.py
|
| 116 |
+
│ │ ├── router.py # Main router aggregator
|
| 117 |
+
│ │ │
|
| 118 |
+
│ │ ├── auth.py # Authentication endpoints
|
| 119 |
+
│ │ ├── users.py # User management
|
| 120 |
+
│ │ ├── organizations.py # Clients & Contractors
|
| 121 |
+
│ │ ├── projects.py # Project CRUD
|
| 122 |
+
│ │ ├── tickets.py # Ticket operations
|
| 123 |
+
│ │ ├── assignments.py # Ticket assignments
|
| 124 |
+
│ │ ├── customers.py # Customer management
|
| 125 |
+
│ │ ├── sales_orders.py # Sales order processing
|
| 126 |
+
│ │ ├── subscriptions.py # Subscription management
|
| 127 |
+
│ │ ├── incidents.py # Support incidents
|
| 128 |
+
│ │ ├── inventory.py # Inventory management
|
| 129 |
+
│ │ ├── expenses.py # Expense tracking
|
| 130 |
+
│ │ ├── payroll.py # Payroll management
|
| 131 |
+
│ │ ├── timesheets.py # Timesheet tracking
|
| 132 |
+
│ │ ├── documents.py # Document management
|
| 133 |
+
│ │ ├── media.py # Photo/file uploads
|
| 134 |
+
│ │ ├── reports.py # Report generation
|
| 135 |
+
│ │ ├── analytics.py # Analytics endpoints
|
| 136 |
+
│ │ ├── webhooks.py # External webhooks (M-Pesa)
|
| 137 |
+
│ │ └── health.py # Health check endpoints
|
| 138 |
+
│ │
|
| 139 |
+
│ ├── services/ # Business logic layer (THE BRAIN)
|
| 140 |
+
│ │ ├── __init__.py
|
| 141 |
+
│ │ │
|
| 142 |
+
│ │ ├── auth_service.py # Authentication logic
|
| 143 |
+
│ │ ├── user_service.py # User management logic
|
| 144 |
+
│ │ ├── organization_service.py # Client/Contractor logic
|
| 145 |
+
│ │ ├── project_service.py # Project management logic
|
| 146 |
+
│ │ ├── ticket_service.py # Ticket lifecycle logic
|
| 147 |
+
│ │ ├── assignment_service.py # Ticket assignment logic
|
| 148 |
+
│ │ ├── customer_service.py # Customer management logic
|
| 149 |
+
│ │ ├── sales_order_service.py # Sales order processing
|
| 150 |
+
│ │ ├── subscription_service.py # Subscription lifecycle
|
| 151 |
+
│ │ ├── incident_service.py # Incident management
|
| 152 |
+
│ │ ├── inventory_service.py # Inventory tracking
|
| 153 |
+
│ │ ├── expense_service.py # Expense management
|
| 154 |
+
│ │ ├── payroll_service.py # Payroll calculation
|
| 155 |
+
│ │ ├── timesheet_service.py # Timesheet management
|
| 156 |
+
│ │ ├── document_service.py # Document handling
|
| 157 |
+
│ │ ├── media_service.py # Photo/file management
|
| 158 |
+
│ │ ├── notification_service.py # Notification orchestration
|
| 159 |
+
│ │ ├── report_service.py # Report generation
|
| 160 |
+
│ │ ├── analytics_service.py # Analytics computation
|
| 161 |
+
│ │ ├── csv_import_service.py # CSV import logic
|
| 162 |
+
│ │ ├── csv_export_service.py # CSV export logic
|
| 163 |
+
│ │ ├── allocation_service.py # Agent allocation (V2)
|
| 164 |
+
│ │ ├── route_optimization_service.py # Route planning (V2)
|
| 165 |
+
│ │ └── otp_service.py # OTP generation/verification
|
| 166 |
+
│ │
|
| 167 |
+
│ ├── repositories/ # Data access layer
|
| 168 |
+
│ │ ├── __init__.py
|
| 169 |
+
│ │ ├── base_repository.py # Base repository with common methods
|
| 170 |
+
│ │ │
|
| 171 |
+
│ │ ├── user_repository.py
|
| 172 |
+
│ │ ├── organization_repository.py
|
| 173 |
+
│ │ ├── project_repository.py
|
| 174 |
+
│ │ ├── ticket_repository.py
|
| 175 |
+
│ │ ├── assignment_repository.py
|
| 176 |
+
│ │ ├── customer_repository.py
|
| 177 |
+
│ │ ├── sales_order_repository.py
|
| 178 |
+
│ │ ├── subscription_repository.py
|
| 179 |
+
│ │ ├── incident_repository.py
|
| 180 |
+
│ │ ├── inventory_repository.py
|
| 181 |
+
│ │ ├── expense_repository.py
|
| 182 |
+
│ │ ├── payroll_repository.py
|
| 183 |
+
│ │ ├── timesheet_repository.py
|
| 184 |
+
│ │ ├── document_repository.py
|
| 185 |
+
│ │ └── audit_log_repository.py
|
| 186 |
+
│ │
|
| 187 |
+
│ ├── models/ # SQLAlchemy ORM models
|
| 188 |
+
│ │ ├── __init__.py
|
| 189 |
+
│ │ ├── base.py # Base model with common fields
|
| 190 |
+
│ │ │
|
| 191 |
+
│ │ ├── user.py # Users, UserFinancialAccounts, UserAssetAssignments
|
| 192 |
+
│ │ ├── organization.py # Clients, Contractors
|
| 193 |
+
│ │ ├── project.py # Projects, ProjectTeam, ProjectRoles, ProjectRegions
|
| 194 |
+
│ │ ├── ticket.py # Tickets, TicketAssignments, TicketStatusHistory
|
| 195 |
+
│ │ ├── customer.py # Customers, SalesOrders, Subscriptions
|
| 196 |
+
│ │ ├── incident.py # Incidents
|
| 197 |
+
│ │ ├── inventory.py # ProjectInventory, InventoryAssignments
|
| 198 |
+
│ │ ├── finance.py # ProjectFinance, UserPayroll, PaymentLogs
|
| 199 |
+
│ │ ├── timesheet.py # Timesheets
|
| 200 |
+
│ │ ├── document.py # Documents, DocumentVersions
|
| 201 |
+
│ │ ├── media.py # MediaFiles
|
| 202 |
+
│ │ ├── audit_log.py # AuditLogs
|
| 203 |
+
│ │ └── enums.py # All ENUM types
|
| 204 |
+
│ │
|
| 205 |
+
│ ├── schemas/ # Pydantic schemas (request/response)
|
| 206 |
+
│ │ ├── __init__.py
|
| 207 |
+
│ │ ├── base.py # Base schemas
|
| 208 |
+
│ │ │
|
| 209 |
+
│ │ ├── auth.py # Login, Token, OTP schemas
|
| 210 |
+
│ │ ├── user.py # User CRUD schemas
|
| 211 |
+
│ │ ├── organization.py # Client/Contractor schemas
|
| 212 |
+
│ │ ├── project.py # Project schemas
|
| 213 |
+
│ │ ├── ticket.py # Ticket schemas
|
| 214 |
+
│ │ ├── assignment.py # Assignment schemas
|
| 215 |
+
│ │ ├── customer.py # Customer schemas
|
| 216 |
+
│ │ ├── sales_order.py # Sales order schemas
|
| 217 |
+
│ │ ├── subscription.py # Subscription schemas
|
| 218 |
+
│ │ ├── incident.py # Incident schemas
|
| 219 |
+
│ │ ├── inventory.py # Inventory schemas
|
| 220 |
+
│ │ ├── expense.py # Expense schemas
|
| 221 |
+
│ │ ├── payroll.py # Payroll schemas
|
| 222 |
+
│ │ ├── timesheet.py # Timesheet schemas
|
| 223 |
+
│ │ ├── document.py # Document schemas
|
| 224 |
+
│ │ ├── media.py # Media schemas
|
| 225 |
+
│ │ ├── report.py # Report schemas
|
| 226 |
+
│ │ └── common.py # Common schemas (pagination, filters)
|
| 227 |
+
│ │
|
| 228 |
+
│ ├── tasks/ # Celery background tasks
|
| 229 |
+
│ │ ├── __init__.py
|
| 230 |
+
│ │ ├── celery_app.py # Celery configuration
|
| 231 |
+
│ │ │
|
| 232 |
+
│ │ ├── notification_tasks.py # Email/SMS sending
|
| 233 |
+
│ │ ├── payroll_tasks.py # Payroll generation
|
| 234 |
+
│ │ ├── payment_tasks.py # Payment processing
|
| 235 |
+
│ │ ├── import_tasks.py # CSV import processing
|
| 236 |
+
│ │ ├── export_tasks.py # Report export generation
|
| 237 |
+
│ │ ├── analytics_tasks.py # Analytics computation
|
| 238 |
+
│ │ ├── sla_tasks.py # SLA monitoring
|
| 239 |
+
│ │ └── cleanup_tasks.py # Data cleanup
|
| 240 |
+
│ │
|
| 241 |
+
│ ├── integrations/ # External service integrations
|
| 242 |
+
│ │ ├── __init__.py
|
| 243 |
+
│ │ │
|
| 244 |
+
│ │ ├── supabase.py # Supabase client
|
| 245 |
+
│ │ ├── cloudinary.py # Cloudinary image uploads
|
| 246 |
+
│ │ ├── mpesa.py # M-Pesa payment gateway
|
| 247 |
+
│ │ ├── resend.py # Resend email service
|
| 248 |
+
│ │ ├── africastalking.py # Africa's Talking SMS (V2)
|
| 249 |
+
│ │ ├── google_maps.py # Google Maps API
|
| 250 |
+
│ │ └── sentry.py # Sentry error tracking
|
| 251 |
+
│ │
|
| 252 |
+
│ ├── utils/ # Utility functions
|
| 253 |
+
│ │ ├── __init__.py
|
| 254 |
+
│ │ │
|
| 255 |
+
│ │ ├── cache.py # Redis caching utilities
|
| 256 |
+
│ │ ├── encryption.py # Data encryption
|
| 257 |
+
│ │ ├── validators.py # Custom validators
|
| 258 |
+
│ │ ├── formatters.py # Data formatters
|
| 259 |
+
│ │ ├── pagination.py # Pagination helpers
|
| 260 |
+
│ │ ├── filters.py # Query filter builders
|
| 261 |
+
│ │ ├── date_utils.py # Date/time utilities
|
| 262 |
+
│ │ ├── phone_utils.py # Phone number validation
|
| 263 |
+
│ │ ├── location_utils.py # GPS/location utilities
|
| 264 |
+
│ │ ├── file_utils.py # File handling utilities
|
| 265 |
+
│ │ ├── csv_utils.py # CSV parsing utilities
|
| 266 |
+
│ │ └── distributed_lock.py # Redis distributed locks
|
| 267 |
+
│ │
|
| 268 |
+
│ └── constants/ # Application constants
|
| 269 |
+
│ ├── __init__.py
|
| 270 |
+
│ ├── roles.py # Role definitions
|
| 271 |
+
│ ├── permissions.py # Permission mappings
|
| 272 |
+
│ ├── status.py # Status constants
|
| 273 |
+
│ └── messages.py # User-facing messages
|
| 274 |
+
│
|
| 275 |
+
├── tests/ # Test suite
|
| 276 |
+
│ ├── __init__.py
|
| 277 |
+
│ ├── conftest.py # Pytest configuration
|
| 278 |
+
│ │
|
| 279 |
+
│ ├── unit/ # Unit tests
|
| 280 |
+
│ │ ├── services/
|
| 281 |
+
│ │ ├── repositories/
|
| 282 |
+
│ │ └── utils/
|
| 283 |
+
│ │
|
| 284 |
+
│ ├── integration/ # Integration tests
|
| 285 |
+
│ │ ├── api/
|
| 286 |
+
│ │ ├── database/
|
| 287 |
+
│ │ └── external_services/
|
| 288 |
+
│ │
|
| 289 |
+
│ └── fixtures/ # Test fixtures
|
| 290 |
+
│ ├── users.py
|
| 291 |
+
│ ├── projects.py
|
| 292 |
+
│ └── tickets.py
|
| 293 |
+
│
|
| 294 |
+
├── scripts/ # Utility scripts
|
| 295 |
+
│ ├── seed_database.py # Database seeding
|
| 296 |
+
│ ├── migrate_data.py # Data migration
|
| 297 |
+
│ ├── generate_test_data.py # Test data generation
|
| 298 |
+
│ └── backup_database.py # Database backup
|
| 299 |
+
│
|
| 300 |
+
├── alembic/ # Database migrations
|
| 301 |
+
│ ├── versions/ # Migration files
|
| 302 |
+
│ ├── env.py # Alembic environment
|
| 303 |
+
│ └── script.py.mako # Migration template
|
| 304 |
+
│
|
| 305 |
+
├── docs/ # Documentation
|
| 306 |
+
│ ├── agent/ # AI agent plans
|
| 307 |
+
│ ├── dev/ # Developer docs
|
| 308 |
+
│ ├── prod/ # Production docs
|
| 309 |
+
│ └── schema/ # Database schema
|
| 310 |
+
│
|
| 311 |
+
├── .env.example # Environment template
|
| 312 |
+
├── .env # Environment variables (gitignored)
|
| 313 |
+
├── .gitignore # Git ignore rules
|
| 314 |
+
├── requirements.txt # Python dependencies
|
| 315 |
+
├── requirements-dev.txt # Development dependencies
|
| 316 |
+
├── Dockerfile # Docker image definition
|
| 317 |
+
├── docker-compose.yml # Docker services
|
| 318 |
+
├── alembic.ini # Alembic configuration
|
| 319 |
+
├── pytest.ini # Pytest configuration
|
| 320 |
+
├── .pre-commit-config.yaml # Pre-commit hooks
|
| 321 |
+
└── README.md # Project documentation
|
| 322 |
+
```
|
| 323 |
+
|
| 324 |
+
---
|
| 325 |
+
|
| 326 |
+
## 🎯 Domain Boundaries & Component Organization
|
| 327 |
+
|
| 328 |
+
### Domain 1: Authentication & Authorization
|
| 329 |
+
**Purpose:** User identity, access control, security
|
| 330 |
+
**Components:**
|
| 331 |
+
- `core/auth.py` - JWT token management
|
| 332 |
+
- `core/security.py` - Password hashing, encryption
|
| 333 |
+
- `core/permissions.py` - RBAC definitions
|
| 334 |
+
- `services/auth_service.py` - Login, logout, token refresh
|
| 335 |
+
- `services/otp_service.py` - 2FA implementation
|
| 336 |
+
- `api/v1/auth.py` - Auth endpoints
|
| 337 |
+
|
| 338 |
+
**Key Responsibilities:**
|
| 339 |
+
- Validate Supabase JWT tokens
|
| 340 |
+
- Generate application JWT tokens
|
| 341 |
+
- Enforce role-based permissions
|
| 342 |
+
- Handle OTP generation/verification
|
| 343 |
+
- Manage user sessions
|
| 344 |
+
|
| 345 |
+
---
|
| 346 |
+
|
| 347 |
+
### Domain 2: User Management
|
| 348 |
+
**Purpose:** User profiles, preferences, financial accounts
|
| 349 |
+
**Components:**
|
| 350 |
+
- `models/user.py` - User, UserFinancialAccounts, UserAssetAssignments, UserPreferences
|
| 351 |
+
- `services/user_service.py` - User CRUD, profile management
|
| 352 |
+
- `repositories/user_repository.py` - User data access
|
| 353 |
+
- `api/v1/users.py` - User endpoints
|
| 354 |
+
|
| 355 |
+
**Key Responsibilities:**
|
| 356 |
+
- User onboarding and activation
|
| 357 |
+
- Profile management (health info, PPE sizes, emergency contacts)
|
| 358 |
+
- Financial account management (M-Pesa, bank accounts)
|
| 359 |
+
- Asset assignment tracking (tools, vehicles, equipment)
|
| 360 |
+
- User preferences (UI settings, notifications)
|
| 361 |
+
|
| 362 |
+
---
|
| 363 |
+
|
| 364 |
+
### Domain 3: Organization Management
|
| 365 |
+
**Purpose:** Clients, contractors, subcontractors
|
| 366 |
+
**Components:**
|
| 367 |
+
- `models/organization.py` - Clients, Contractors
|
| 368 |
+
- `services/organization_service.py` - Organization CRUD
|
| 369 |
+
- `repositories/organization_repository.py` - Organization data access
|
| 370 |
+
- `api/v1/organizations.py` - Organization endpoints
|
| 371 |
+
|
| 372 |
+
**Key Responsibilities:**
|
| 373 |
+
- Client management (telecom operators)
|
| 374 |
+
- Contractor management (field service providers)
|
| 375 |
+
- Organization activation/deactivation
|
| 376 |
+
- Competency tracking
|
| 377 |
+
- Billing plan management
|
| 378 |
+
|
| 379 |
+
---
|
| 380 |
+
|
| 381 |
+
### Domain 4: Project Management
|
| 382 |
+
**Purpose:** Projects, teams, roles, regions, subcontractors
|
| 383 |
+
**Components:**
|
| 384 |
+
- `models/project.py` - Projects, ProjectTeam, ProjectRoles, ProjectRegions, ProjectSubcontractors
|
| 385 |
+
- `services/project_service.py` - Project lifecycle management
|
| 386 |
+
- `repositories/project_repository.py` - Project data access
|
| 387 |
+
- `api/v1/projects.py` - Project endpoints
|
| 388 |
+
|
| 389 |
+
**Key Responsibilities:**
|
| 390 |
+
- Project creation and configuration
|
| 391 |
+
- Team assignment (main contractor + subcontractors)
|
| 392 |
+
- Regional hub management
|
| 393 |
+
- Role and compensation structure
|
| 394 |
+
- Project closure and archival
|
| 395 |
+
|
| 396 |
+
---
|
| 397 |
+
|
| 398 |
+
### Domain 5: Ticket Management
|
| 399 |
+
**Purpose:** Work orders, assignments, status tracking
|
| 400 |
+
**Components:**
|
| 401 |
+
- `models/ticket.py` - Tickets, TicketAssignments, TicketStatusHistory, TicketExpenses
|
| 402 |
+
- `services/ticket_service.py` - Ticket lifecycle
|
| 403 |
+
- `services/assignment_service.py` - Assignment logic
|
| 404 |
+
- `repositories/ticket_repository.py` - Ticket data access
|
| 405 |
+
- `api/v1/tickets.py` - Ticket endpoints
|
| 406 |
+
- `api/v1/assignments.py` - Assignment endpoints
|
| 407 |
+
|
| 408 |
+
**Key Responsibilities:**
|
| 409 |
+
- Ticket creation from sales orders, incidents, tasks
|
| 410 |
+
- Ticket assignment (manual, self-assignment, auto-allocation)
|
| 411 |
+
- Status transitions (open → assigned → in_progress → completed)
|
| 412 |
+
- SLA tracking and violation detection
|
| 413 |
+
- Expense logging and approval
|
| 414 |
+
- GPS verification and location tracking
|
| 415 |
+
|
| 416 |
+
---
|
| 417 |
+
|
| 418 |
+
### Domain 6: Customer & Sales
|
| 419 |
+
**Purpose:** Customers, sales orders, subscriptions
|
| 420 |
+
**Components:**
|
| 421 |
+
- `models/customer.py` - Customers, SalesOrders, Subscriptions
|
| 422 |
+
- `services/customer_service.py` - Customer management
|
| 423 |
+
- `services/sales_order_service.py` - Sales order processing
|
| 424 |
+
- `services/subscription_service.py` - Subscription lifecycle
|
| 425 |
+
- `repositories/customer_repository.py` - Customer data access
|
| 426 |
+
- `api/v1/customers.py` - Customer endpoints
|
| 427 |
+
- `api/v1/sales_orders.py` - Sales order endpoints
|
| 428 |
+
- `api/v1/subscriptions.py` - Subscription endpoints
|
| 429 |
+
|
| 430 |
+
**Key Responsibilities:**
|
| 431 |
+
- Customer deduplication (by phone number)
|
| 432 |
+
- Sales order CSV import
|
| 433 |
+
- Ticket generation from sales orders
|
| 434 |
+
- Subscription activation after installation
|
| 435 |
+
- Service address management
|
| 436 |
+
- Equipment tracking (ONT, IMEI, etc.)
|
| 437 |
+
|
| 438 |
+
---
|
| 439 |
+
|
| 440 |
+
### Domain 7: Support & Incidents
|
| 441 |
+
**Purpose:** Customer support requests, issue tracking
|
| 442 |
+
**Components:**
|
| 443 |
+
- `models/incident.py` - Incidents
|
| 444 |
+
- `services/incident_service.py` - Incident management
|
| 445 |
+
- `repositories/incident_repository.py` - Incident data access
|
| 446 |
+
- `api/v1/incidents.py` - Incident endpoints
|
| 447 |
+
|
| 448 |
+
**Key Responsibilities:**
|
| 449 |
+
- Incident creation from customer complaints
|
| 450 |
+
- Ticket generation from incidents
|
| 451 |
+
- Issue categorization (no_service, slow_speed, equipment_fault)
|
| 452 |
+
- Resolution tracking
|
| 453 |
+
- Customer communication
|
| 454 |
+
|
| 455 |
+
---
|
| 456 |
+
|
| 457 |
+
### Domain 8: Inventory Management
|
| 458 |
+
**Purpose:** Equipment, materials, stock tracking
|
| 459 |
+
**Components:**
|
| 460 |
+
- `models/inventory.py` - ProjectInventory, InventoryAssignments, InventoryTransactions
|
| 461 |
+
- `services/inventory_service.py` - Inventory operations
|
| 462 |
+
- `repositories/inventory_repository.py` - Inventory data access
|
| 463 |
+
- `api/v1/inventory.py` - Inventory endpoints
|
| 464 |
+
|
| 465 |
+
**Key Responsibilities:**
|
| 466 |
+
- Stock management by region
|
| 467 |
+
- Equipment issuance to field agents
|
| 468 |
+
- Return tracking
|
| 469 |
+
- Low stock alerts
|
| 470 |
+
- Inventory reconciliation
|
| 471 |
+
|
| 472 |
+
---
|
| 473 |
+
|
| 474 |
+
### Domain 9: Financial Management
|
| 475 |
+
**Purpose:** Expenses, payroll, payments
|
| 476 |
+
**Components:**
|
| 477 |
+
- `models/finance.py` - ProjectFinance, UserPayroll, PaymentLogs, TicketExpenses
|
| 478 |
+
- `services/expense_service.py` - Expense management
|
| 479 |
+
- `services/payroll_service.py` - Payroll calculation
|
| 480 |
+
- `services/payment_service.py` - Payment processing
|
| 481 |
+
- `repositories/expense_repository.py` - Expense data access
|
| 482 |
+
- `repositories/payroll_repository.py` - Payroll data access
|
| 483 |
+
- `api/v1/expenses.py` - Expense endpoints
|
| 484 |
+
- `api/v1/payroll.py` - Payroll endpoints
|
| 485 |
+
|
| 486 |
+
**Key Responsibilities:**
|
| 487 |
+
- Expense logging and approval
|
| 488 |
+
- Payroll calculation (weekly, commission-based)
|
| 489 |
+
- Payment processing (M-Pesa, bank transfer)
|
| 490 |
+
- Payment status tracking
|
| 491 |
+
- Financial reporting
|
| 492 |
+
|
| 493 |
+
---
|
| 494 |
+
|
| 495 |
+
### Domain 10: Timesheet & Attendance
|
| 496 |
+
**Purpose:** Worker presence, location tracking
|
| 497 |
+
**Components:**
|
| 498 |
+
- `models/timesheet.py` - Timesheets
|
| 499 |
+
- `services/timesheet_service.py` - Timesheet management
|
| 500 |
+
- `repositories/timesheet_repository.py` - Timesheet data access
|
| 501 |
+
- `api/v1/timesheets.py` - Timesheet endpoints
|
| 502 |
+
|
| 503 |
+
**Key Responsibilities:**
|
| 504 |
+
- Daily attendance tracking
|
| 505 |
+
- Check-in/check-out
|
| 506 |
+
- Leave management
|
| 507 |
+
- Hours worked calculation
|
| 508 |
+
- Location history aggregation
|
| 509 |
+
|
| 510 |
+
---
|
| 511 |
+
|
| 512 |
+
### Domain 11: Document Management
|
| 513 |
+
**Purpose:** File uploads, document versioning
|
| 514 |
+
**Components:**
|
| 515 |
+
- `models/document.py` - Documents, DocumentVersions
|
| 516 |
+
- `models/media.py` - MediaFiles
|
| 517 |
+
- `services/document_service.py` - Document handling
|
| 518 |
+
- `services/media_service.py` - Photo/file management
|
| 519 |
+
- `repositories/document_repository.py` - Document data access
|
| 520 |
+
- `api/v1/documents.py` - Document endpoints
|
| 521 |
+
- `api/v1/media.py` - Media endpoints
|
| 522 |
+
|
| 523 |
+
**Key Responsibilities:**
|
| 524 |
+
- File upload to Cloudinary
|
| 525 |
+
- Document versioning
|
| 526 |
+
- Photo management (before/after, receipts)
|
| 527 |
+
- EXIF data extraction
|
| 528 |
+
- File validation and security
|
| 529 |
+
|
| 530 |
+
---
|
| 531 |
+
|
| 532 |
+
### Domain 12: Communication & Notifications
|
| 533 |
+
**Purpose:** Email, SMS, push notifications
|
| 534 |
+
**Components:**
|
| 535 |
+
- `services/notification_service.py` - Notification orchestration
|
| 536 |
+
- `integrations/resend.py` - Email service
|
| 537 |
+
- `integrations/africastalking.py` - SMS service
|
| 538 |
+
- `tasks/notification_tasks.py` - Async notification sending
|
| 539 |
+
|
| 540 |
+
**Key Responsibilities:**
|
| 541 |
+
- Email sending (transactional, reports)
|
| 542 |
+
- SMS sending (OTP, alerts)
|
| 543 |
+
- Push notifications (mobile app)
|
| 544 |
+
- Notification preferences
|
| 545 |
+
- Delivery tracking
|
| 546 |
+
|
| 547 |
+
---
|
| 548 |
+
|
| 549 |
+
### Domain 13: Reporting & Analytics
|
| 550 |
+
**Purpose:** Data export, analytics, dashboards
|
| 551 |
+
**Components:**
|
| 552 |
+
- `services/report_service.py` - Report generation
|
| 553 |
+
- `services/analytics_service.py` - Analytics computation
|
| 554 |
+
- `services/csv_export_service.py` - CSV export
|
| 555 |
+
- `tasks/export_tasks.py` - Async export generation
|
| 556 |
+
- `api/v1/reports.py` - Report endpoints
|
| 557 |
+
- `api/v1/analytics.py` - Analytics endpoints
|
| 558 |
+
|
| 559 |
+
**Key Responsibilities:**
|
| 560 |
+
- CSV/Excel export
|
| 561 |
+
- Performance analytics
|
| 562 |
+
- SLA compliance reports
|
| 563 |
+
- Financial reports
|
| 564 |
+
- Dashboard metrics
|
| 565 |
+
|
| 566 |
+
---
|
| 567 |
+
|
| 568 |
+
### Domain 14: Background Processing
|
| 569 |
+
**Purpose:** Async tasks, scheduled jobs
|
| 570 |
+
**Components:**
|
| 571 |
+
- `tasks/celery_app.py` - Celery configuration
|
| 572 |
+
- `tasks/payroll_tasks.py` - Payroll generation
|
| 573 |
+
- `tasks/payment_tasks.py` - Payment processing
|
| 574 |
+
- `tasks/sla_tasks.py` - SLA monitoring
|
| 575 |
+
- `tasks/cleanup_tasks.py` - Data cleanup
|
| 576 |
+
|
| 577 |
+
**Key Responsibilities:**
|
| 578 |
+
- Weekly payroll generation
|
| 579 |
+
- Payment queue processing
|
| 580 |
+
- SLA violation detection
|
| 581 |
+
- Data archival
|
| 582 |
+
- Report generation
|
| 583 |
+
|
| 584 |
+
---
|
| 585 |
+
|
| 586 |
+
### Domain 15: External Integrations
|
| 587 |
+
**Purpose:** Third-party service integration
|
| 588 |
+
**Components:**
|
| 589 |
+
- `integrations/supabase.py` - Supabase client
|
| 590 |
+
- `integrations/cloudinary.py` - Image uploads
|
| 591 |
+
- `integrations/mpesa.py` - Payment gateway
|
| 592 |
+
- `integrations/google_maps.py` - Geocoding, routing
|
| 593 |
+
- `integrations/sentry.py` - Error tracking
|
| 594 |
+
|
| 595 |
+
**Key Responsibilities:**
|
| 596 |
+
- Supabase Auth integration
|
| 597 |
+
- Cloudinary image management
|
| 598 |
+
- M-Pesa payment processing
|
| 599 |
+
- Google Maps API calls
|
| 600 |
+
- Error tracking and monitoring
|
| 601 |
+
|
| 602 |
+
---
|
| 603 |
+
|
| 604 |
+
## 🔧 Implementation Patterns & Best Practices
|
| 605 |
+
|
| 606 |
+
### Pattern 1: Repository Pattern (Data Access Layer)
|
| 607 |
+
|
| 608 |
+
**Purpose:** Abstract database operations, enable testing, centralize queries
|
| 609 |
+
|
| 610 |
+
**Base Repository Template:**
|
| 611 |
+
```python
|
| 612 |
+
# app/repositories/base_repository.py
|
| 613 |
+
from typing import Generic, TypeVar, Type, Optional, List
|
| 614 |
+
from sqlalchemy.orm import Session
|
| 615 |
+
from sqlalchemy import select, update, delete
|
| 616 |
+
from app.models.base import Base
|
| 617 |
+
|
| 618 |
+
ModelType = TypeVar("ModelType", bound=Base)
|
| 619 |
+
|
| 620 |
+
class BaseRepository(Generic[ModelType]):
|
| 621 |
+
def __init__(self, model: Type[ModelType], db: Session):
|
| 622 |
+
self.model = model
|
| 623 |
+
self.db = db
|
| 624 |
+
|
| 625 |
+
def get_by_id(self, id: str) -> Optional[ModelType]:
|
| 626 |
+
"""Get single record by ID"""
|
| 627 |
+
return self.db.query(self.model).filter(
|
| 628 |
+
self.model.id == id,
|
| 629 |
+
self.model.deleted_at.is_(None)
|
| 630 |
+
).first()
|
| 631 |
+
|
| 632 |
+
def get_all(self, skip: int = 0, limit: int = 100) -> List[ModelType]:
|
| 633 |
+
"""Get all records with pagination"""
|
| 634 |
+
return self.db.query(self.model).filter(
|
| 635 |
+
self.model.deleted_at.is_(None)
|
| 636 |
+
).offset(skip).limit(limit).all()
|
| 637 |
+
|
| 638 |
+
def create(self, obj_in: dict) -> ModelType:
|
| 639 |
+
"""Create new record"""
|
| 640 |
+
db_obj = self.model(**obj_in)
|
| 641 |
+
self.db.add(db_obj)
|
| 642 |
+
self.db.commit()
|
| 643 |
+
self.db.refresh(db_obj)
|
| 644 |
+
return db_obj
|
| 645 |
+
|
| 646 |
+
def update(self, id: str, obj_in: dict) -> Optional[ModelType]:
|
| 647 |
+
"""Update existing record"""
|
| 648 |
+
db_obj = self.get_by_id(id)
|
| 649 |
+
if not db_obj:
|
| 650 |
+
return None
|
| 651 |
+
|
| 652 |
+
for field, value in obj_in.items():
|
| 653 |
+
setattr(db_obj, field, value)
|
| 654 |
+
|
| 655 |
+
self.db.commit()
|
| 656 |
+
self.db.refresh(db_obj)
|
| 657 |
+
return db_obj
|
| 658 |
+
|
| 659 |
+
def soft_delete(self, id: str) -> bool:
|
| 660 |
+
"""Soft delete record"""
|
| 661 |
+
db_obj = self.get_by_id(id)
|
| 662 |
+
if not db_obj:
|
| 663 |
+
return False
|
| 664 |
+
|
| 665 |
+
db_obj.deleted_at = datetime.utcnow()
|
| 666 |
+
self.db.commit()
|
| 667 |
+
return True
|
| 668 |
+
|
| 669 |
+
def apply_filters(self, query, filters: dict):
|
| 670 |
+
"""Apply dynamic filters to query"""
|
| 671 |
+
for key, value in filters.items():
|
| 672 |
+
if hasattr(self.model, key) and value is not None:
|
| 673 |
+
query = query.filter(getattr(self.model, key) == value)
|
| 674 |
+
return query
|
| 675 |
+
```
|
| 676 |
+
|
| 677 |
+
**Specific Repository Example:**
|
| 678 |
+
```python
|
| 679 |
+
# app/repositories/ticket_repository.py
|
| 680 |
+
from app.repositories.base_repository import BaseRepository
|
| 681 |
+
from app.models.ticket import Ticket
|
| 682 |
+
from sqlalchemy.orm import Session, joinedload
|
| 683 |
+
|
| 684 |
+
class TicketRepository(BaseRepository[Ticket]):
|
| 685 |
+
def __init__(self, db: Session):
|
| 686 |
+
super().__init__(Ticket, db)
|
| 687 |
+
|
| 688 |
+
def get_with_relations(self, ticket_id: str):
|
| 689 |
+
"""Get ticket with all related data (eager loading)"""
|
| 690 |
+
return self.db.query(Ticket).options(
|
| 691 |
+
joinedload(Ticket.customer),
|
| 692 |
+
joinedload(Ticket.project),
|
| 693 |
+
joinedload(Ticket.assignments),
|
| 694 |
+
joinedload(Ticket.expenses)
|
| 695 |
+
).filter(
|
| 696 |
+
Ticket.id == ticket_id,
|
| 697 |
+
Ticket.deleted_at.is_(None)
|
| 698 |
+
).first()
|
| 699 |
+
|
| 700 |
+
def get_by_project(self, project_id: str, status: Optional[str] = None):
|
| 701 |
+
"""Get tickets by project with optional status filter"""
|
| 702 |
+
query = self.db.query(Ticket).filter(
|
| 703 |
+
Ticket.project_id == project_id,
|
| 704 |
+
Ticket.deleted_at.is_(None)
|
| 705 |
+
)
|
| 706 |
+
|
| 707 |
+
if status:
|
| 708 |
+
query = query.filter(Ticket.status == status)
|
| 709 |
+
|
| 710 |
+
return query.all()
|
| 711 |
+
|
| 712 |
+
def get_overdue_tickets(self):
|
| 713 |
+
"""Get tickets past SLA deadline"""
|
| 714 |
+
return self.db.query(Ticket).filter(
|
| 715 |
+
Ticket.status.in_(['open', 'assigned', 'in_progress']),
|
| 716 |
+
Ticket.sla_target_date < datetime.utcnow(),
|
| 717 |
+
Ticket.deleted_at.is_(None)
|
| 718 |
+
).all()
|
| 719 |
+
```
|
| 720 |
+
|
| 721 |
+
---
|
| 722 |
+
|
| 723 |
+
### Pattern 2: Service Layer Pattern (Business Logic)
|
| 724 |
+
|
| 725 |
+
**Purpose:** Encapsulate business rules, orchestrate operations, manage transactions
|
| 726 |
+
|
| 727 |
+
**Service Template:**
|
| 728 |
+
```python
|
| 729 |
+
# app/services/ticket_service.py
|
| 730 |
+
from typing import Optional, List
|
| 731 |
+
from sqlalchemy.orm import Session
|
| 732 |
+
from app.repositories.ticket_repository import TicketRepository
|
| 733 |
+
from app.repositories.customer_repository import CustomerRepository
|
| 734 |
+
from app.schemas.ticket import TicketCreate, TicketUpdate, TicketResponse
|
| 735 |
+
from app.core.exceptions import NotFoundException, BusinessRuleException
|
| 736 |
+
from app.services.notification_service import NotificationService
|
| 737 |
+
|
| 738 |
+
class TicketService:
|
| 739 |
+
def __init__(self, db: Session):
|
| 740 |
+
self.db = db
|
| 741 |
+
self.ticket_repo = TicketRepository(db)
|
| 742 |
+
self.customer_repo = CustomerRepository(db)
|
| 743 |
+
self.notification_service = NotificationService(db)
|
| 744 |
+
|
| 745 |
+
def create_ticket(self, ticket_data: TicketCreate, created_by_id: str) -> TicketResponse:
|
| 746 |
+
"""
|
| 747 |
+
Create new ticket with business rule validation
|
| 748 |
+
|
| 749 |
+
Business Rules:
|
| 750 |
+
1. Customer must exist
|
| 751 |
+
2. Project must be active
|
| 752 |
+
3. No duplicate tickets for same source
|
| 753 |
+
4. Calculate SLA deadline based on priority
|
| 754 |
+
"""
|
| 755 |
+
# Validate customer exists
|
| 756 |
+
customer = self.customer_repo.get_by_id(ticket_data.customer_id)
|
| 757 |
+
if not customer:
|
| 758 |
+
raise NotFoundException("Customer not found")
|
| 759 |
+
|
| 760 |
+
# Check for duplicate tickets
|
| 761 |
+
existing = self.ticket_repo.get_by_source(
|
| 762 |
+
ticket_data.source,
|
| 763 |
+
ticket_data.source_id
|
| 764 |
+
)
|
| 765 |
+
if existing:
|
| 766 |
+
raise BusinessRuleException("Ticket already exists for this source")
|
| 767 |
+
|
| 768 |
+
# Calculate SLA deadline
|
| 769 |
+
sla_hours = self._get_sla_hours(ticket_data.priority)
|
| 770 |
+
sla_target_date = datetime.utcnow() + timedelta(hours=sla_hours)
|
| 771 |
+
|
| 772 |
+
# Create ticket
|
| 773 |
+
ticket_dict = ticket_data.dict()
|
| 774 |
+
ticket_dict['sla_target_date'] = sla_target_date
|
| 775 |
+
ticket_dict['created_by_user_id'] = created_by_id
|
| 776 |
+
|
| 777 |
+
ticket = self.ticket_repo.create(ticket_dict)
|
| 778 |
+
|
| 779 |
+
# Send notification (async)
|
| 780 |
+
self.notification_service.notify_ticket_created(ticket.id)
|
| 781 |
+
|
| 782 |
+
return TicketResponse.from_orm(ticket)
|
| 783 |
+
|
| 784 |
+
def assign_ticket(
|
| 785 |
+
self,
|
| 786 |
+
ticket_id: str,
|
| 787 |
+
agent_id: str,
|
| 788 |
+
assigned_by_id: str
|
| 789 |
+
) -> TicketResponse:
|
| 790 |
+
"""
|
| 791 |
+
Assign ticket to field agent
|
| 792 |
+
|
| 793 |
+
Business Rules:
|
| 794 |
+
1. Ticket must be in 'open' status
|
| 795 |
+
2. Agent must be active and in same project
|
| 796 |
+
3. Agent cannot have more than 3 active tickets
|
| 797 |
+
4. Record assignment history
|
| 798 |
+
"""
|
| 799 |
+
ticket = self.ticket_repo.get_by_id(ticket_id)
|
| 800 |
+
if not ticket:
|
| 801 |
+
raise NotFoundException("Ticket not found")
|
| 802 |
+
|
| 803 |
+
if ticket.status != 'open':
|
| 804 |
+
raise BusinessRuleException("Ticket must be in 'open' status to assign")
|
| 805 |
+
|
| 806 |
+
# Check agent workload
|
| 807 |
+
active_tickets = self.ticket_repo.get_active_tickets_for_agent(agent_id)
|
| 808 |
+
if len(active_tickets) >= 3:
|
| 809 |
+
raise BusinessRuleException("Agent already has 3 active tickets")
|
| 810 |
+
|
| 811 |
+
# Update ticket status
|
| 812 |
+
ticket = self.ticket_repo.update(ticket_id, {
|
| 813 |
+
'status': 'assigned',
|
| 814 |
+
'assigned_agent_id': agent_id
|
| 815 |
+
})
|
| 816 |
+
|
| 817 |
+
# Create assignment record
|
| 818 |
+
self._create_assignment_record(ticket_id, agent_id, assigned_by_id)
|
| 819 |
+
|
| 820 |
+
# Send notification to agent
|
| 821 |
+
self.notification_service.notify_ticket_assigned(ticket_id, agent_id)
|
| 822 |
+
|
| 823 |
+
return TicketResponse.from_orm(ticket)
|
| 824 |
+
|
| 825 |
+
def _get_sla_hours(self, priority: str) -> int:
|
| 826 |
+
"""Calculate SLA hours based on priority"""
|
| 827 |
+
sla_map = {
|
| 828 |
+
'urgent': 24,
|
| 829 |
+
'high': 48,
|
| 830 |
+
'normal': 72,
|
| 831 |
+
'low': 168 # 7 days
|
| 832 |
+
}
|
| 833 |
+
return sla_map.get(priority, 72)
|
| 834 |
+
```
|
| 835 |
+
|
| 836 |
+
---
|
| 837 |
+
|
| 838 |
+
### Pattern 3: API Endpoint Pattern (Thin Controllers)
|
| 839 |
+
|
| 840 |
+
**Purpose:** Handle HTTP concerns, validate input, format responses
|
| 841 |
+
|
| 842 |
+
**Endpoint Template:**
|
| 843 |
+
```python
|
| 844 |
+
# app/api/v1/tickets.py
|
| 845 |
+
from fastapi import APIRouter, Depends, HTTPException, status
|
| 846 |
+
from sqlalchemy.orm import Session
|
| 847 |
+
from typing import List
|
| 848 |
+
|
| 849 |
+
from app.api.deps import get_db, get_current_user
|
| 850 |
+
from app.schemas.ticket import TicketCreate, TicketUpdate, TicketResponse
|
| 851 |
+
from app.schemas.common import PaginatedResponse
|
| 852 |
+
from app.services.ticket_service import TicketService
|
| 853 |
+
from app.core.exceptions import NotFoundException, BusinessRuleException
|
| 854 |
+
from app.models.user import User
|
| 855 |
+
|
| 856 |
+
router = APIRouter(prefix="/tickets", tags=["tickets"])
|
| 857 |
+
|
| 858 |
+
@router.post("/", response_model=TicketResponse, status_code=status.HTTP_201_CREATED)
|
| 859 |
+
def create_ticket(
|
| 860 |
+
ticket_data: TicketCreate,
|
| 861 |
+
db: Session = Depends(get_db),
|
| 862 |
+
current_user: User = Depends(get_current_user)
|
| 863 |
+
):
|
| 864 |
+
"""
|
| 865 |
+
Create new ticket
|
| 866 |
+
|
| 867 |
+
Permissions: project_manager, dispatcher
|
| 868 |
+
"""
|
| 869 |
+
try:
|
| 870 |
+
service = TicketService(db)
|
| 871 |
+
return service.create_ticket(ticket_data, current_user.id)
|
| 872 |
+
except NotFoundException as e:
|
| 873 |
+
raise HTTPException(status_code=404, detail=str(e))
|
| 874 |
+
except BusinessRuleException as e:
|
| 875 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 876 |
+
|
| 877 |
+
@router.get("/{ticket_id}", response_model=TicketResponse)
|
| 878 |
+
def get_ticket(
|
| 879 |
+
ticket_id: str,
|
| 880 |
+
db: Session = Depends(get_db),
|
| 881 |
+
current_user: User = Depends(get_current_user)
|
| 882 |
+
):
|
| 883 |
+
"""Get ticket by ID"""
|
| 884 |
+
service = TicketService(db)
|
| 885 |
+
ticket = service.get_ticket(ticket_id)
|
| 886 |
+
|
| 887 |
+
if not ticket:
|
| 888 |
+
raise HTTPException(status_code=404, detail="Ticket not found")
|
| 889 |
+
|
| 890 |
+
return ticket
|
| 891 |
+
|
| 892 |
+
@router.get("/", response_model=PaginatedResponse[TicketResponse])
|
| 893 |
+
def list_tickets(
|
| 894 |
+
project_id: Optional[str] = None,
|
| 895 |
+
status: Optional[str] = None,
|
| 896 |
+
skip: int = 0,
|
| 897 |
+
limit: int = 100,
|
| 898 |
+
db: Session = Depends(get_db),
|
| 899 |
+
current_user: User = Depends(get_current_user)
|
| 900 |
+
):
|
| 901 |
+
"""
|
| 902 |
+
List tickets with filters
|
| 903 |
+
|
| 904 |
+
Filters:
|
| 905 |
+
- project_id: Filter by project
|
| 906 |
+
- status: Filter by status
|
| 907 |
+
- skip: Pagination offset
|
| 908 |
+
- limit: Page size
|
| 909 |
+
"""
|
| 910 |
+
service = TicketService(db)
|
| 911 |
+
tickets, total = service.list_tickets(
|
| 912 |
+
project_id=project_id,
|
| 913 |
+
status=status,
|
| 914 |
+
skip=skip,
|
| 915 |
+
limit=limit
|
| 916 |
+
)
|
| 917 |
+
|
| 918 |
+
return PaginatedResponse(
|
| 919 |
+
items=tickets,
|
| 920 |
+
total=total,
|
| 921 |
+
skip=skip,
|
| 922 |
+
limit=limit
|
| 923 |
+
)
|
| 924 |
+
|
| 925 |
+
@router.post("/{ticket_id}/assign", response_model=TicketResponse)
|
| 926 |
+
def assign_ticket(
|
| 927 |
+
ticket_id: str,
|
| 928 |
+
agent_id: str,
|
| 929 |
+
db: Session = Depends(get_db),
|
| 930 |
+
current_user: User = Depends(get_current_user)
|
| 931 |
+
):
|
| 932 |
+
"""
|
| 933 |
+
Assign ticket to field agent
|
| 934 |
+
|
| 935 |
+
Permissions: dispatcher, project_manager
|
| 936 |
+
"""
|
| 937 |
+
try:
|
| 938 |
+
service = TicketService(db)
|
| 939 |
+
return service.assign_ticket(ticket_id, agent_id, current_user.id)
|
| 940 |
+
except NotFoundException as e:
|
| 941 |
+
raise HTTPException(status_code=404, detail=str(e))
|
| 942 |
+
except BusinessRuleException as e:
|
| 943 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 944 |
+
```
|
| 945 |
+
|
| 946 |
+
---
|
| 947 |
+
|
| 948 |
+
### Pattern 4: Dependency Injection
|
| 949 |
+
|
| 950 |
+
**Purpose:** Manage dependencies, enable testing, improve maintainability
|
| 951 |
+
|
| 952 |
+
```python
|
| 953 |
+
# app/api/deps.py
|
| 954 |
+
from typing import Generator
|
| 955 |
+
from fastapi import Depends, HTTPException, status
|
| 956 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
| 957 |
+
from sqlalchemy.orm import Session
|
| 958 |
+
|
| 959 |
+
from app.core.database import SessionLocal
|
| 960 |
+
from app.core.auth import verify_token
|
| 961 |
+
from app.models.user import User
|
| 962 |
+
from app.repositories.user_repository import UserRepository
|
| 963 |
+
|
| 964 |
+
security = HTTPBearer()
|
| 965 |
+
|
| 966 |
+
def get_db() -> Generator:
|
| 967 |
+
"""Database session dependency"""
|
| 968 |
+
db = SessionLocal()
|
| 969 |
+
try:
|
| 970 |
+
yield db
|
| 971 |
+
finally:
|
| 972 |
+
db.close()
|
| 973 |
+
|
| 974 |
+
def get_current_user(
|
| 975 |
+
credentials: HTTPAuthorizationCredentials = Depends(security),
|
| 976 |
+
db: Session = Depends(get_db)
|
| 977 |
+
) -> User:
|
| 978 |
+
"""Get current authenticated user"""
|
| 979 |
+
token = credentials.credentials
|
| 980 |
+
|
| 981 |
+
try:
|
| 982 |
+
payload = verify_token(token)
|
| 983 |
+
user_id = payload.get("sub")
|
| 984 |
+
|
| 985 |
+
if not user_id:
|
| 986 |
+
raise HTTPException(
|
| 987 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 988 |
+
detail="Invalid authentication credentials"
|
| 989 |
+
)
|
| 990 |
+
|
| 991 |
+
user_repo = UserRepository(db)
|
| 992 |
+
user = user_repo.get_by_id(user_id)
|
| 993 |
+
|
| 994 |
+
if not user or not user.is_active:
|
| 995 |
+
raise HTTPException(
|
| 996 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 997 |
+
detail="User not found or inactive"
|
| 998 |
+
)
|
| 999 |
+
|
| 1000 |
+
return user
|
| 1001 |
+
|
| 1002 |
+
except Exception:
|
| 1003 |
+
raise HTTPException(
|
| 1004 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 1005 |
+
detail="Could not validate credentials"
|
| 1006 |
+
)
|
| 1007 |
+
|
| 1008 |
+
def require_role(*allowed_roles: str):
|
| 1009 |
+
"""Role-based access control decorator"""
|
| 1010 |
+
def role_checker(current_user: User = Depends(get_current_user)) -> User:
|
| 1011 |
+
if current_user.role not in allowed_roles:
|
| 1012 |
+
raise HTTPException(
|
| 1013 |
+
status_code=status.HTTP_403_FORBIDDEN,
|
| 1014 |
+
detail=f"Access denied. Required roles: {', '.join(allowed_roles)}"
|
| 1015 |
+
)
|
| 1016 |
+
return current_user
|
| 1017 |
+
return role_checker
|
| 1018 |
+
```
|
| 1019 |
+
|
| 1020 |
+
---
|
| 1021 |
+
|
| 1022 |
+
### Pattern 5: Error Handling
|
| 1023 |
+
|
| 1024 |
+
**Purpose:** Consistent error responses, proper logging
|
| 1025 |
+
|
| 1026 |
+
```python
|
| 1027 |
+
# app/core/exceptions.py
|
| 1028 |
+
class AppException(Exception):
|
| 1029 |
+
"""Base application exception"""
|
| 1030 |
+
def __init__(self, message: str, code: str = None):
|
| 1031 |
+
self.message = message
|
| 1032 |
+
self.code = code
|
| 1033 |
+
super().__init__(self.message)
|
| 1034 |
+
|
| 1035 |
+
class NotFoundException(AppException):
|
| 1036 |
+
"""Resource not found"""
|
| 1037 |
+
pass
|
| 1038 |
+
|
| 1039 |
+
class BusinessRuleException(AppException):
|
| 1040 |
+
"""Business rule violation"""
|
| 1041 |
+
pass
|
| 1042 |
+
|
| 1043 |
+
class ValidationException(AppException):
|
| 1044 |
+
"""Data validation error"""
|
| 1045 |
+
pass
|
| 1046 |
+
|
| 1047 |
+
class AuthenticationException(AppException):
|
| 1048 |
+
"""Authentication failure"""
|
| 1049 |
+
pass
|
| 1050 |
+
|
| 1051 |
+
class AuthorizationException(AppException):
|
| 1052 |
+
"""Authorization failure"""
|
| 1053 |
+
pass
|
| 1054 |
+
|
| 1055 |
+
# app/middleware/error_handling.py
|
| 1056 |
+
from fastapi import Request, status
|
| 1057 |
+
from fastapi.responses import JSONResponse
|
| 1058 |
+
from app.core.exceptions import (
|
| 1059 |
+
AppException,
|
| 1060 |
+
NotFoundException,
|
| 1061 |
+
BusinessRuleException,
|
| 1062 |
+
ValidationException
|
| 1063 |
+
)
|
| 1064 |
+
import logging
|
| 1065 |
+
|
| 1066 |
+
logger = logging.getLogger(__name__)
|
| 1067 |
+
|
| 1068 |
+
async def error_handler_middleware(request: Request, call_next):
|
| 1069 |
+
try:
|
| 1070 |
+
return await call_next(request)
|
| 1071 |
+
except NotFoundException as e:
|
| 1072 |
+
logger.warning(f"Not found: {e.message}")
|
| 1073 |
+
return JSONResponse(
|
| 1074 |
+
status_code=status.HTTP_404_NOT_FOUND,
|
| 1075 |
+
content={"detail": e.message, "code": e.code}
|
| 1076 |
+
)
|
| 1077 |
+
except BusinessRuleException as e:
|
| 1078 |
+
logger.warning(f"Business rule violation: {e.message}")
|
| 1079 |
+
return JSONResponse(
|
| 1080 |
+
status_code=status.HTTP_400_BAD_REQUEST,
|
| 1081 |
+
content={"detail": e.message, "code": e.code}
|
| 1082 |
+
)
|
| 1083 |
+
except ValidationException as e:
|
| 1084 |
+
logger.warning(f"Validation error: {e.message}")
|
| 1085 |
+
return JSONResponse(
|
| 1086 |
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
| 1087 |
+
content={"detail": e.message, "code": e.code}
|
| 1088 |
+
)
|
| 1089 |
+
except Exception as e:
|
| 1090 |
+
logger.error(f"Unhandled exception: {str(e)}", exc_info=True)
|
| 1091 |
+
return JSONResponse(
|
| 1092 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
| 1093 |
+
content={"detail": "Internal server error"}
|
| 1094 |
+
)
|
| 1095 |
+
```
|
| 1096 |
+
|
| 1097 |
+
---
|
| 1098 |
+
|
| 1099 |
+
### Pattern 6: Caching Strategy
|
| 1100 |
+
|
| 1101 |
+
**Purpose:** Improve performance, reduce database load
|
| 1102 |
+
|
| 1103 |
+
```python
|
| 1104 |
+
# app/utils/cache.py
|
| 1105 |
+
from typing import Optional, Any, Callable
|
| 1106 |
+
from functools import wraps
|
| 1107 |
+
import json
|
| 1108 |
+
import redis
|
| 1109 |
+
from app.config import settings
|
| 1110 |
+
|
| 1111 |
+
redis_client = redis.from_url(settings.REDIS_URL)
|
| 1112 |
+
|
| 1113 |
+
def cache_get(key: str) -> Optional[Any]:
|
| 1114 |
+
"""Get value from cache"""
|
| 1115 |
+
value = redis_client.get(key)
|
| 1116 |
+
return json.loads(value) if value else None
|
| 1117 |
+
|
| 1118 |
+
def cache_set(key: str, value: Any, ttl: int = 300):
|
| 1119 |
+
"""Set value in cache with TTL"""
|
| 1120 |
+
redis_client.setex(key, ttl, json.dumps(value))
|
| 1121 |
+
|
| 1122 |
+
def cache_delete(key: str):
|
| 1123 |
+
"""Delete key from cache"""
|
| 1124 |
+
redis_client.delete(key)
|
| 1125 |
+
|
| 1126 |
+
def cache_delete_pattern(pattern: str):
|
| 1127 |
+
"""Delete all keys matching pattern"""
|
| 1128 |
+
keys = redis_client.keys(pattern)
|
| 1129 |
+
if keys:
|
| 1130 |
+
redis_client.delete(*keys)
|
| 1131 |
+
|
| 1132 |
+
def cached(ttl: int = 300, key_prefix: str = ""):
|
| 1133 |
+
"""Decorator for caching function results"""
|
| 1134 |
+
def decorator(func: Callable):
|
| 1135 |
+
@wraps(func)
|
| 1136 |
+
def wrapper(*args, **kwargs):
|
| 1137 |
+
# Generate cache key
|
| 1138 |
+
cache_key = f"{key_prefix}:{func.__name__}:{str(args)}:{str(kwargs)}"
|
| 1139 |
+
|
| 1140 |
+
# Try to get from cache
|
| 1141 |
+
cached_value = cache_get(cache_key)
|
| 1142 |
+
if cached_value is not None:
|
| 1143 |
+
return cached_value
|
| 1144 |
+
|
| 1145 |
+
# Execute function
|
| 1146 |
+
result = func(*args, **kwargs)
|
| 1147 |
+
|
| 1148 |
+
# Store in cache
|
| 1149 |
+
cache_set(cache_key, result, ttl)
|
| 1150 |
+
|
| 1151 |
+
return result
|
| 1152 |
+
return wrapper
|
| 1153 |
+
return decorator
|
| 1154 |
+
|
| 1155 |
+
# Usage example
|
| 1156 |
+
@cached(ttl=300, key_prefix="dashboard")
|
| 1157 |
+
def get_dashboard_metrics(project_id: str):
|
| 1158 |
+
# Expensive database query
|
| 1159 |
+
return compute_metrics(project_id)
|
| 1160 |
+
```
|
| 1161 |
+
|
| 1162 |
+
---
|
| 1163 |
+
|
| 1164 |
+
### Pattern 7: Background Tasks (Celery)
|
| 1165 |
+
|
| 1166 |
+
**Purpose:** Async processing, scheduled jobs
|
| 1167 |
+
|
| 1168 |
+
```python
|
| 1169 |
+
# app/tasks/celery_app.py
|
| 1170 |
+
from celery import Celery
|
| 1171 |
+
from celery.schedules import crontab
|
| 1172 |
+
from app.config import settings
|
| 1173 |
+
|
| 1174 |
+
celery_app = Celery(
|
| 1175 |
+
"swiftops",
|
| 1176 |
+
broker=settings.CELERY_BROKER_URL,
|
| 1177 |
+
backend=settings.CELERY_RESULT_BACKEND
|
| 1178 |
+
)
|
| 1179 |
+
|
| 1180 |
+
celery_app.conf.update(
|
| 1181 |
+
task_serializer='json',
|
| 1182 |
+
accept_content=['json'],
|
| 1183 |
+
result_serializer='json',
|
| 1184 |
+
timezone='UTC',
|
| 1185 |
+
enable_utc=True,
|
| 1186 |
+
task_track_started=True,
|
| 1187 |
+
task_time_limit=30 * 60, # 30 minutes
|
| 1188 |
+
task_soft_time_limit=25 * 60, # 25 minutes
|
| 1189 |
+
)
|
| 1190 |
+
|
| 1191 |
+
# Task routing
|
| 1192 |
+
celery_app.conf.task_routes = {
|
| 1193 |
+
'app.tasks.notification_tasks.*': {'queue': 'high_priority'},
|
| 1194 |
+
'app.tasks.payment_tasks.*': {'queue': 'high_priority'},
|
| 1195 |
+
'app.tasks.report_tasks.*': {'queue': 'medium_priority'},
|
| 1196 |
+
'app.tasks.analytics_tasks.*': {'queue': 'low_priority'},
|
| 1197 |
+
}
|
| 1198 |
+
|
| 1199 |
+
# Scheduled tasks
|
| 1200 |
+
celery_app.conf.beat_schedule = {
|
| 1201 |
+
'generate-weekly-payroll': {
|
| 1202 |
+
'task': 'app.tasks.payroll_tasks.generate_weekly_payroll',
|
| 1203 |
+
'schedule': crontab(day_of_week=5, hour=18, minute=0),
|
| 1204 |
+
},
|
| 1205 |
+
'monitor-sla-violations': {
|
| 1206 |
+
'task': 'app.tasks.sla_tasks.check_sla_violations',
|
| 1207 |
+
'schedule': crontab(minute=0), # Every hour
|
| 1208 |
+
},
|
| 1209 |
+
'cleanup-old-exports': {
|
| 1210 |
+
'task': 'app.tasks.cleanup_tasks.cleanup_old_exports',
|
| 1211 |
+
'schedule': crontab(hour=2, minute=0), # 2 AM daily
|
| 1212 |
+
},
|
| 1213 |
+
}
|
| 1214 |
+
|
| 1215 |
+
# app/tasks/notification_tasks.py
|
| 1216 |
+
from app.tasks.celery_app import celery_app
|
| 1217 |
+
from app.integrations.resend import send_email
|
| 1218 |
+
from app.core.database import SessionLocal
|
| 1219 |
+
|
| 1220 |
+
@celery_app.task(bind=True, max_retries=3)
|
| 1221 |
+
def send_ticket_assignment_email(self, ticket_id: str, agent_id: str):
|
| 1222 |
+
"""Send email notification for ticket assignment"""
|
| 1223 |
+
try:
|
| 1224 |
+
db = SessionLocal()
|
| 1225 |
+
|
| 1226 |
+
# Get ticket and agent details
|
| 1227 |
+
ticket = db.query(Ticket).filter(Ticket.id == ticket_id).first()
|
| 1228 |
+
agent = db.query(User).filter(User.id == agent_id).first()
|
| 1229 |
+
|
| 1230 |
+
# Send email
|
| 1231 |
+
send_email(
|
| 1232 |
+
to=agent.email,
|
| 1233 |
+
subject=f"New Ticket Assigned: {ticket.ticket_name}",
|
| 1234 |
+
template="ticket_assignment",
|
| 1235 |
+
variables={
|
| 1236 |
+
"agent_name": agent.name,
|
| 1237 |
+
"ticket_id": ticket.id,
|
| 1238 |
+
"customer_name": ticket.customer.customer_name,
|
| 1239 |
+
"address": ticket.location_address
|
| 1240 |
+
}
|
| 1241 |
+
)
|
| 1242 |
+
|
| 1243 |
+
db.close()
|
| 1244 |
+
except Exception as e:
|
| 1245 |
+
# Retry with exponential backoff
|
| 1246 |
+
raise self.retry(exc=e, countdown=60 * (2 ** self.request.retries))
|
| 1247 |
+
```
|
| 1248 |
+
|
| 1249 |
+
---
|
| 1250 |
+
|
| 1251 |
+
## 🔨 Build Sequence (Complete Implementation Order)
|
| 1252 |
+
|
| 1253 |
+
### Phase 1: Foundation (Week 1)
|
| 1254 |
+
**Goal:** Set up core infrastructure and base components
|
| 1255 |
+
|
| 1256 |
+
#### Day 1-2: Project Setup
|
| 1257 |
+
- [ ] Initialize project structure (all folders)
|
| 1258 |
+
- [ ] Set up virtual environment
|
| 1259 |
+
- [ ] Install dependencies (requirements.txt)
|
| 1260 |
+
- [ ] Configure environment variables (.env)
|
| 1261 |
+
- [ ] Set up Docker Compose (PostgreSQL, Redis)
|
| 1262 |
+
- [ ] Initialize Alembic for migrations
|
| 1263 |
+
- [ ] Set up pre-commit hooks (black, isort, flake8)
|
| 1264 |
+
|
| 1265 |
+
#### Day 3-4: Core Components
|
| 1266 |
+
- [ ] `app/core/database.py` - Database session management
|
| 1267 |
+
- [ ] `app/core/logging.py` - Structured logging
|
| 1268 |
+
- [ ] `app/core/exceptions.py` - Custom exceptions
|
| 1269 |
+
- [ ] `app/config.py` - Configuration management
|
| 1270 |
+
- [ ] `app/models/base.py` - Base model with common fields
|
| 1271 |
+
- [ ] `app/models/enums.py` - All ENUM types
|
| 1272 |
+
- [ ] `app/schemas/base.py` - Base Pydantic schemas
|
| 1273 |
+
- [ ] `app/schemas/common.py` - Common schemas (pagination, filters)
|
| 1274 |
+
|
| 1275 |
+
#### Day 5-7: Authentication & Authorization
|
| 1276 |
+
- [ ] `app/core/auth.py` - JWT token management
|
| 1277 |
+
- [ ] `app/core/security.py` - Password hashing
|
| 1278 |
+
- [ ] `app/core/permissions.py` - RBAC definitions
|
| 1279 |
+
- [ ] `app/integrations/supabase.py` - Supabase client
|
| 1280 |
+
- [ ] `app/services/auth_service.py` - Auth business logic
|
| 1281 |
+
- [ ] `app/api/deps.py` - Auth dependencies
|
| 1282 |
+
- [ ] `app/api/v1/auth.py` - Auth endpoints
|
| 1283 |
+
- [ ] `app/middleware/authentication.py` - Auth middleware
|
| 1284 |
+
- [ ] Test authentication flow
|
| 1285 |
+
|
| 1286 |
+
---
|
| 1287 |
+
|
| 1288 |
+
### Phase 2: Core Domain Models (Week 2)
|
| 1289 |
+
**Goal:** Implement all database models and migrations
|
| 1290 |
+
|
| 1291 |
+
#### Day 1-2: User & Organization Models
|
| 1292 |
+
- [ ] `app/models/user.py` - Users, UserFinancialAccounts, UserAssetAssignments, UserPreferences
|
| 1293 |
+
- [ ] `app/models/organization.py` - Clients, Contractors
|
| 1294 |
+
- [ ] Create Alembic migration for users and organizations
|
| 1295 |
+
- [ ] Test models with sample data
|
| 1296 |
+
|
| 1297 |
+
#### Day 3-4: Project & Team Models
|
| 1298 |
+
- [ ] `app/models/project.py` - Projects, ProjectTeam, ProjectRoles, ProjectRegions, ProjectSubcontractors
|
| 1299 |
+
- [ ] Create Alembic migration for projects
|
| 1300 |
+
- [ ] Test project relationships
|
| 1301 |
+
|
| 1302 |
+
#### Day 5-7: Ticket & Customer Models
|
| 1303 |
+
- [ ] `app/models/ticket.py` - Tickets, TicketAssignments, TicketStatusHistory, TicketExpenses
|
| 1304 |
+
- [ ] `app/models/customer.py` - Customers, SalesOrders, Subscriptions
|
| 1305 |
+
- [ ] `app/models/incident.py` - Incidents
|
| 1306 |
+
- [ ] `app/models/inventory.py` - ProjectInventory, InventoryAssignments, InventoryTransactions
|
| 1307 |
+
- [ ] `app/models/finance.py` - ProjectFinance, UserPayroll, PaymentLogs
|
| 1308 |
+
- [ ] `app/models/timesheet.py` - Timesheets
|
| 1309 |
+
- [ ] `app/models/document.py` - Documents, DocumentVersions
|
| 1310 |
+
- [ ] `app/models/media.py` - MediaFiles
|
| 1311 |
+
- [ ] `app/models/audit_log.py` - AuditLogs
|
| 1312 |
+
- [ ] Create migrations for all remaining models
|
| 1313 |
+
- [ ] Run full migration: `alembic upgrade head`
|
| 1314 |
+
|
| 1315 |
+
---
|
| 1316 |
+
|
| 1317 |
+
### Phase 3: Repository Layer (Week 3)
|
| 1318 |
+
**Goal:** Implement data access layer for all domains
|
| 1319 |
+
|
| 1320 |
+
#### Day 1-2: Base Repository & Core Repositories
|
| 1321 |
+
- [ ] `app/repositories/base_repository.py` - Generic base repository
|
| 1322 |
+
- [ ] `app/repositories/user_repository.py` - User data access
|
| 1323 |
+
- [ ] `app/repositories/organization_repository.py` - Client/Contractor data access
|
| 1324 |
+
- [ ] Test repositories with unit tests
|
| 1325 |
+
|
| 1326 |
+
#### Day 3-4: Project & Ticket Repositories
|
| 1327 |
+
- [ ] `app/repositories/project_repository.py` - Project data access
|
| 1328 |
+
- [ ] `app/repositories/ticket_repository.py` - Ticket data access
|
| 1329 |
+
- [ ] `app/repositories/assignment_repository.py` - Assignment data access
|
| 1330 |
+
- [ ] Test complex queries (joins, filters)
|
| 1331 |
+
|
| 1332 |
+
#### Day 5-7: Remaining Repositories
|
| 1333 |
+
- [ ] `app/repositories/customer_repository.py`
|
| 1334 |
+
- [ ] `app/repositories/sales_order_repository.py`
|
| 1335 |
+
- [ ] `app/repositories/subscription_repository.py`
|
| 1336 |
+
- [ ] `app/repositories/incident_repository.py`
|
| 1337 |
+
- [ ] `app/repositories/inventory_repository.py`
|
| 1338 |
+
- [ ] `app/repositories/expense_repository.py`
|
| 1339 |
+
- [ ] `app/repositories/payroll_repository.py`
|
| 1340 |
+
- [ ] `app/repositories/timesheet_repository.py`
|
| 1341 |
+
- [ ] `app/repositories/document_repository.py`
|
| 1342 |
+
- [ ] `app/repositories/audit_log_repository.py`
|
| 1343 |
+
- [ ] Write unit tests for all repositories
|
| 1344 |
+
|
| 1345 |
+
---
|
| 1346 |
+
|
| 1347 |
+
### Phase 4: Pydantic Schemas (Week 4)
|
| 1348 |
+
**Goal:** Define all request/response schemas
|
| 1349 |
+
|
| 1350 |
+
#### Day 1-3: Core Domain Schemas
|
| 1351 |
+
- [ ] `app/schemas/user.py` - UserCreate, UserUpdate, UserResponse
|
| 1352 |
+
- [ ] `app/schemas/organization.py` - Client/Contractor schemas
|
| 1353 |
+
- [ ] `app/schemas/project.py` - Project schemas
|
| 1354 |
+
- [ ] `app/schemas/ticket.py` - Ticket schemas
|
| 1355 |
+
- [ ] `app/schemas/assignment.py` - Assignment schemas
|
| 1356 |
+
- [ ] Test schema validation
|
| 1357 |
+
|
| 1358 |
+
#### Day 4-7: Remaining Domain Schemas
|
| 1359 |
+
- [ ] `app/schemas/customer.py`
|
| 1360 |
+
- [ ] `app/schemas/sales_order.py`
|
| 1361 |
+
- [ ] `app/schemas/subscription.py`
|
| 1362 |
+
- [ ] `app/schemas/incident.py`
|
| 1363 |
+
- [ ] `app/schemas/inventory.py`
|
| 1364 |
+
- [ ] `app/schemas/expense.py`
|
| 1365 |
+
- [ ] `app/schemas/payroll.py`
|
| 1366 |
+
- [ ] `app/schemas/timesheet.py`
|
| 1367 |
+
- [ ] `app/schemas/document.py`
|
| 1368 |
+
- [ ] `app/schemas/media.py`
|
| 1369 |
+
- [ ] `app/schemas/report.py`
|
| 1370 |
+
- [ ] Test all schemas with edge cases
|
| 1371 |
+
|
| 1372 |
+
---
|
| 1373 |
+
|
| 1374 |
+
### Phase 5: Service Layer - Core Domains (Week 5-6)
|
| 1375 |
+
**Goal:** Implement business logic for core domains
|
| 1376 |
+
|
| 1377 |
+
#### Week 5: User, Organization, Project Services
|
| 1378 |
+
- [ ] `app/services/user_service.py`
|
| 1379 |
+
- User CRUD operations
|
| 1380 |
+
- Profile management
|
| 1381 |
+
- Financial account management
|
| 1382 |
+
- Asset assignment
|
| 1383 |
+
- [ ] `app/services/organization_service.py`
|
| 1384 |
+
- Client/Contractor CRUD
|
| 1385 |
+
- Organization activation
|
| 1386 |
+
- [ ] `app/services/project_service.py`
|
| 1387 |
+
- Project lifecycle management
|
| 1388 |
+
- Team assignment
|
| 1389 |
+
- Regional hub management
|
| 1390 |
+
- Subcontractor management
|
| 1391 |
+
- [ ] Write unit tests for services
|
| 1392 |
+
|
| 1393 |
+
#### Week 6: Ticket & Assignment Services
|
| 1394 |
+
- [ ] `app/services/ticket_service.py`
|
| 1395 |
+
- Ticket creation from sales orders, incidents, tasks
|
| 1396 |
+
- Status transitions
|
| 1397 |
+
- SLA tracking
|
| 1398 |
+
- Expense logging
|
| 1399 |
+
- [ ] `app/services/assignment_service.py`
|
| 1400 |
+
- Manual assignment
|
| 1401 |
+
- Self-assignment (max 3 tickets rule)
|
| 1402 |
+
- Assignment validation
|
| 1403 |
+
- GPS verification
|
| 1404 |
+
- [ ] Write comprehensive tests for ticket workflows
|
| 1405 |
+
|
| 1406 |
+
---
|
| 1407 |
+
|
| 1408 |
+
### Phase 6: Service Layer - Customer & Sales (Week 7)
|
| 1409 |
+
**Goal:** Implement customer and sales management
|
| 1410 |
+
|
| 1411 |
+
#### Day 1-3: Customer & Sales Order Services
|
| 1412 |
+
- [ ] `app/services/customer_service.py`
|
| 1413 |
+
- Customer CRUD
|
| 1414 |
+
- Deduplication by phone
|
| 1415 |
+
- Address management
|
| 1416 |
+
- [ ] `app/services/sales_order_service.py`
|
| 1417 |
+
- Sales order creation
|
| 1418 |
+
- CSV import processing
|
| 1419 |
+
- Ticket generation
|
| 1420 |
+
- Order validation
|
| 1421 |
+
|
| 1422 |
+
#### Day 4-7: Subscription & Incident Services
|
| 1423 |
+
- [ ] `app/services/subscription_service.py`
|
| 1424 |
+
- Subscription activation
|
| 1425 |
+
- Equipment tracking
|
| 1426 |
+
- Service lifecycle
|
| 1427 |
+
- [ ] `app/services/incident_service.py`
|
| 1428 |
+
- Incident creation
|
| 1429 |
+
- Ticket generation
|
| 1430 |
+
- Resolution tracking
|
| 1431 |
+
- [ ] Write integration tests
|
| 1432 |
+
|
| 1433 |
+
---
|
| 1434 |
+
|
| 1435 |
+
### Phase 7: Service Layer - Operations (Week 8)
|
| 1436 |
+
**Goal:** Implement operational services
|
| 1437 |
+
|
| 1438 |
+
#### Day 1-3: Inventory & Expense Services
|
| 1439 |
+
- [ ] `app/services/inventory_service.py`
|
| 1440 |
+
- Stock management
|
| 1441 |
+
- Equipment issuance
|
| 1442 |
+
- Return tracking
|
| 1443 |
+
- Low stock alerts
|
| 1444 |
+
- [ ] `app/services/expense_service.py`
|
| 1445 |
+
- Expense logging
|
| 1446 |
+
- Approval workflow
|
| 1447 |
+
- Receipt management
|
| 1448 |
+
|
| 1449 |
+
#### Day 4-7: Payroll & Timesheet Services
|
| 1450 |
+
- [ ] `app/services/payroll_service.py`
|
| 1451 |
+
- Payroll calculation (commission, flat rate, hybrid)
|
| 1452 |
+
- Payment queue management
|
| 1453 |
+
- Payroll reports
|
| 1454 |
+
- [ ] `app/services/timesheet_service.py`
|
| 1455 |
+
- Attendance tracking
|
| 1456 |
+
- Check-in/check-out
|
| 1457 |
+
- Leave management
|
| 1458 |
+
- [ ] Write tests for financial calculations
|
| 1459 |
+
|
| 1460 |
+
---
|
| 1461 |
+
|
| 1462 |
+
### Phase 8: API Endpoints - Core (Week 9)
|
| 1463 |
+
**Goal:** Implement REST API endpoints
|
| 1464 |
+
|
| 1465 |
+
#### Day 1-2: User & Organization Endpoints
|
| 1466 |
+
- [ ] `app/api/v1/users.py` - User management endpoints
|
| 1467 |
+
- [ ] `app/api/v1/organizations.py` - Client/Contractor endpoints
|
| 1468 |
+
- [ ] Test with Postman/HTTPie
|
| 1469 |
+
|
| 1470 |
+
#### Day 3-4: Project Endpoints
|
| 1471 |
+
- [ ] `app/api/v1/projects.py` - Project CRUD endpoints
|
| 1472 |
+
- [ ] Test project workflows
|
| 1473 |
+
|
| 1474 |
+
#### Day 5-7: Ticket & Assignment Endpoints
|
| 1475 |
+
- [ ] `app/api/v1/tickets.py` - Ticket management endpoints
|
| 1476 |
+
- [ ] `app/api/v1/assignments.py` - Assignment endpoints
|
| 1477 |
+
- [ ] Test ticket lifecycle
|
| 1478 |
+
- [ ] Test assignment rules
|
| 1479 |
+
|
| 1480 |
+
---
|
| 1481 |
+
|
| 1482 |
+
### Phase 9: API Endpoints - Customer & Sales (Week 10)
|
| 1483 |
+
**Goal:** Implement customer and sales endpoints
|
| 1484 |
+
|
| 1485 |
+
#### Day 1-3: Customer & Sales Order Endpoints
|
| 1486 |
+
- [ ] `app/api/v1/customers.py` - Customer endpoints
|
| 1487 |
+
- [ ] `app/api/v1/sales_orders.py` - Sales order endpoints
|
| 1488 |
+
- [ ] CSV import endpoint
|
| 1489 |
+
- [ ] Test CSV import with sample files
|
| 1490 |
+
|
| 1491 |
+
#### Day 4-7: Subscription & Incident Endpoints
|
| 1492 |
+
- [ ] `app/api/v1/subscriptions.py` - Subscription endpoints
|
| 1493 |
+
- [ ] `app/api/v1/incidents.py` - Incident endpoints
|
| 1494 |
+
- [ ] Test end-to-end workflows
|
| 1495 |
+
|
| 1496 |
+
---
|
| 1497 |
+
|
| 1498 |
+
### Phase 10: API Endpoints - Operations (Week 11)
|
| 1499 |
+
**Goal:** Implement operational endpoints
|
| 1500 |
+
|
| 1501 |
+
#### Day 1-3: Inventory & Expense Endpoints
|
| 1502 |
+
- [ ] `app/api/v1/inventory.py` - Inventory endpoints
|
| 1503 |
+
- [ ] `app/api/v1/expenses.py` - Expense endpoints
|
| 1504 |
+
- [ ] Test inventory workflows
|
| 1505 |
+
|
| 1506 |
+
#### Day 4-7: Payroll & Timesheet Endpoints
|
| 1507 |
+
- [ ] `app/api/v1/payroll.py` - Payroll endpoints
|
| 1508 |
+
- [ ] `app/api/v1/timesheets.py` - Timesheet endpoints
|
| 1509 |
+
- [ ] Test payroll generation
|
| 1510 |
+
|
| 1511 |
+
---
|
| 1512 |
+
|
| 1513 |
+
### Phase 11: External Integrations (Week 12)
|
| 1514 |
+
**Goal:** Integrate external services
|
| 1515 |
+
|
| 1516 |
+
#### Day 1-2: Media & Document Services
|
| 1517 |
+
- [ ] `app/integrations/cloudinary.py` - Image upload integration
|
| 1518 |
+
- [ ] `app/services/media_service.py` - Photo management
|
| 1519 |
+
- [ ] `app/services/document_service.py` - Document handling
|
| 1520 |
+
- [ ] `app/api/v1/media.py` - Media endpoints
|
| 1521 |
+
- [ ] `app/api/v1/documents.py` - Document endpoints
|
| 1522 |
+
- [ ] Test file uploads
|
| 1523 |
+
|
| 1524 |
+
#### Day 3-4: Email & Notification Services
|
| 1525 |
+
- [ ] `app/integrations/resend.py` - Email service
|
| 1526 |
+
- [ ] `app/services/notification_service.py` - Notification orchestration
|
| 1527 |
+
- [ ] Email templates (OTP, ticket assignment, payroll)
|
| 1528 |
+
- [ ] Test email sending
|
| 1529 |
+
|
| 1530 |
+
#### Day 5-7: Payment Integration
|
| 1531 |
+
- [ ] `app/integrations/mpesa.py` - M-Pesa integration
|
| 1532 |
+
- [ ] `app/services/payment_service.py` - Payment processing
|
| 1533 |
+
- [ ] `app/api/v1/webhooks.py` - Payment webhooks
|
| 1534 |
+
- [ ] Test payment flow (sandbox)
|
| 1535 |
+
|
| 1536 |
+
---
|
| 1537 |
+
|
| 1538 |
+
### Phase 12: Background Tasks (Week 13)
|
| 1539 |
+
**Goal:** Implement async processing
|
| 1540 |
+
|
| 1541 |
+
#### Day 1-3: Celery Setup & Core Tasks
|
| 1542 |
+
- [ ] `app/tasks/celery_app.py` - Celery configuration
|
| 1543 |
+
- [ ] `app/tasks/notification_tasks.py` - Email/SMS tasks
|
| 1544 |
+
- [ ] `app/tasks/payment_tasks.py` - Payment processing tasks
|
| 1545 |
+
- [ ] Test task execution
|
| 1546 |
+
|
| 1547 |
+
#### Day 4-7: Scheduled Tasks
|
| 1548 |
+
- [ ] `app/tasks/payroll_tasks.py` - Weekly payroll generation
|
| 1549 |
+
- [ ] `app/tasks/sla_tasks.py` - SLA monitoring
|
| 1550 |
+
- [ ] `app/tasks/cleanup_tasks.py` - Data cleanup
|
| 1551 |
+
- [ ] `app/tasks/analytics_tasks.py` - Analytics computation
|
| 1552 |
+
- [ ] Configure Celery Beat schedule
|
| 1553 |
+
- [ ] Test scheduled tasks
|
| 1554 |
+
|
| 1555 |
+
---
|
| 1556 |
+
|
| 1557 |
+
### Phase 13: Reporting & Analytics (Week 14)
|
| 1558 |
+
**Goal:** Implement reporting features
|
| 1559 |
+
|
| 1560 |
+
#### Day 1-3: CSV Export
|
| 1561 |
+
- [ ] `app/services/csv_export_service.py` - CSV export logic
|
| 1562 |
+
- [ ] `app/tasks/export_tasks.py` - Async export generation
|
| 1563 |
+
- [ ] `app/api/v1/reports.py` - Report endpoints
|
| 1564 |
+
- [ ] Test CSV export
|
| 1565 |
+
|
| 1566 |
+
#### Day 4-7: Analytics & Dashboards
|
| 1567 |
+
- [ ] `app/services/analytics_service.py` - Analytics computation
|
| 1568 |
+
- [ ] `app/api/v1/analytics.py` - Analytics endpoints
|
| 1569 |
+
- [ ] Dashboard metrics calculation
|
| 1570 |
+
- [ ] Performance reports
|
| 1571 |
+
- [ ] Test analytics queries
|
| 1572 |
+
|
| 1573 |
+
---
|
| 1574 |
+
|
| 1575 |
+
### Phase 14: Advanced Features (Week 15)
|
| 1576 |
+
**Goal:** Implement V2 features
|
| 1577 |
+
|
| 1578 |
+
#### Day 1-3: OTP & 2FA
|
| 1579 |
+
- [ ] `app/services/otp_service.py` - OTP generation/verification
|
| 1580 |
+
- [ ] OTP endpoints
|
| 1581 |
+
- [ ] Test OTP flow
|
| 1582 |
+
|
| 1583 |
+
#### Day 4-7: Search & Filtering
|
| 1584 |
+
- [ ] `app/utils/filters.py` - Query filter builders
|
| 1585 |
+
- [ ] Full-text search implementation
|
| 1586 |
+
- [ ] Autocomplete endpoints
|
| 1587 |
+
- [ ] Test search functionality
|
| 1588 |
+
|
| 1589 |
+
---
|
| 1590 |
+
|
| 1591 |
+
### Phase 15: Middleware & Security (Week 16)
|
| 1592 |
+
**Goal:** Implement security features
|
| 1593 |
+
|
| 1594 |
+
#### Day 1-2: Middleware
|
| 1595 |
+
- [ ] `app/middleware/rate_limiting.py` - Rate limiter
|
| 1596 |
+
- [ ] `app/middleware/request_logging.py` - Request logging
|
| 1597 |
+
- [ ] `app/middleware/error_handling.py` - Global error handler
|
| 1598 |
+
- [ ] `app/middleware/cors.py` - CORS configuration
|
| 1599 |
+
|
| 1600 |
+
#### Day 3-4: Security Features
|
| 1601 |
+
- [ ] Input validation and sanitization
|
| 1602 |
+
- [ ] Audit logging
|
| 1603 |
+
- [ ] Data encryption for sensitive fields
|
| 1604 |
+
- [ ] Test security measures
|
| 1605 |
+
|
| 1606 |
+
#### Day 5-7: Monitoring & Health Checks
|
| 1607 |
+
- [ ] `app/api/v1/health.py` - Health check endpoints
|
| 1608 |
+
- [ ] `app/integrations/sentry.py` - Error tracking
|
| 1609 |
+
- [ ] Logging configuration
|
| 1610 |
+
- [ ] Test monitoring
|
| 1611 |
+
|
| 1612 |
+
---
|
| 1613 |
+
|
| 1614 |
+
### Phase 16: Testing & Quality (Week 17-18)
|
| 1615 |
+
**Goal:** Comprehensive testing and code quality
|
| 1616 |
+
|
| 1617 |
+
#### Week 17: Unit & Integration Tests
|
| 1618 |
+
- [ ] Write unit tests for all services (80% coverage)
|
| 1619 |
+
- [ ] Write integration tests for API endpoints
|
| 1620 |
+
- [ ] Write repository tests
|
| 1621 |
+
- [ ] Test edge cases and error handling
|
| 1622 |
+
|
| 1623 |
+
#### Week 18: End-to-End Tests
|
| 1624 |
+
- [ ] Test complete workflows (sales order → ticket → completion)
|
| 1625 |
+
- [ ] Test payment flows
|
| 1626 |
+
- [ ] Test CSV import/export
|
| 1627 |
+
- [ ] Load testing with realistic data
|
| 1628 |
+
- [ ] Fix bugs and optimize
|
| 1629 |
+
|
| 1630 |
+
---
|
| 1631 |
+
|
| 1632 |
+
### Phase 17: Documentation (Week 19)
|
| 1633 |
+
**Goal:** Complete documentation
|
| 1634 |
+
|
| 1635 |
+
#### Day 1-3: API Documentation
|
| 1636 |
+
- [ ] OpenAPI/Swagger documentation
|
| 1637 |
+
- [ ] Endpoint descriptions
|
| 1638 |
+
- [ ] Request/response examples
|
| 1639 |
+
- [ ] Authentication guide
|
| 1640 |
+
|
| 1641 |
+
#### Day 4-7: Developer Documentation
|
| 1642 |
+
- [ ] Setup guide
|
| 1643 |
+
- [ ] Architecture documentation
|
| 1644 |
+
- [ ] Deployment guide
|
| 1645 |
+
- [ ] Troubleshooting guide
|
| 1646 |
+
- [ ] Contributing guidelines
|
| 1647 |
+
|
| 1648 |
+
---
|
| 1649 |
+
|
| 1650 |
+
### Phase 18: Deployment & DevOps (Week 20)
|
| 1651 |
+
**Goal:** Production deployment
|
| 1652 |
+
|
| 1653 |
+
#### Day 1-3: Docker & CI/CD
|
| 1654 |
+
- [ ] Optimize Dockerfile
|
| 1655 |
+
- [ ] Docker Compose for production
|
| 1656 |
+
- [ ] CI/CD pipeline (GitHub Actions)
|
| 1657 |
+
- [ ] Automated testing in CI
|
| 1658 |
+
|
| 1659 |
+
#### Day 4-7: Production Deployment
|
| 1660 |
+
- [ ] Deploy to production environment
|
| 1661 |
+
- [ ] Configure environment variables
|
| 1662 |
+
- [ ] Set up monitoring (Sentry)
|
| 1663 |
+
- [ ] Set up logging (CloudWatch/ELK)
|
| 1664 |
+
- [ ] Database backups
|
| 1665 |
+
- [ ] SSL certificates
|
| 1666 |
+
- [ ] Load balancer configuration
|
| 1667 |
+
- [ ] Final production testing
|
| 1668 |
+
|
| 1669 |
+
---
|
| 1670 |
+
|
| 1671 |
+
|
| 1672 |
+
## 🎯 Critical Missing Components
|
| 1673 |
+
|
| 1674 |
+
After reviewing the build plan against the backend features document, here are the **missing components** that need to be added:
|
| 1675 |
+
|
| 1676 |
+
---
|
| 1677 |
+
|
| 1678 |
+
### Missing Feature 1: CSV Import Service (Phase 6 Addition)
|
| 1679 |
+
|
| 1680 |
+
**Location:** Should be in Phase 6 (Week 7) alongside Sales Order Service
|
| 1681 |
+
|
| 1682 |
+
**Components to Add:**
|
| 1683 |
+
```
|
| 1684 |
+
- [ ] `app/services/csv_import_service.py`
|
| 1685 |
+
- CSV parsing and validation
|
| 1686 |
+
- Batch processing (chunks of 100)
|
| 1687 |
+
- Error reporting
|
| 1688 |
+
- Preview generation
|
| 1689 |
+
- Deduplication logic
|
| 1690 |
+
- [ ] `app/tasks/import_tasks.py`
|
| 1691 |
+
- Async CSV processing
|
| 1692 |
+
- Progress tracking
|
| 1693 |
+
- Import status updates
|
| 1694 |
+
- [ ] CSV import endpoints in `app/api/v1/sales_orders.py`
|
| 1695 |
+
- POST /sales-orders/upload-csv
|
| 1696 |
+
- POST /sales-orders/validate-csv
|
| 1697 |
+
- POST /sales-orders/confirm-csv-import
|
| 1698 |
+
- GET /sales-orders/import/{import_id}/status
|
| 1699 |
+
```
|
| 1700 |
+
|
| 1701 |
+
---
|
| 1702 |
+
|
| 1703 |
+
### Missing Feature 2: Google Maps Integration (Phase 11 Addition)
|
| 1704 |
+
|
| 1705 |
+
**Location:** Should be in Phase 11 (Week 12) with other integrations
|
| 1706 |
+
|
| 1707 |
+
**Components to Add:**
|
| 1708 |
+
```
|
| 1709 |
+
- [ ] `app/integrations/google_maps.py`
|
| 1710 |
+
- Geocoding (address → coordinates)
|
| 1711 |
+
- Reverse geocoding (coordinates → address)
|
| 1712 |
+
- Distance calculation
|
| 1713 |
+
- Directions API
|
| 1714 |
+
- Travel time estimation
|
| 1715 |
+
- [ ] `app/utils/location_utils.py`
|
| 1716 |
+
- GPS distance calculation
|
| 1717 |
+
- Location validation
|
| 1718 |
+
- Geofence checking
|
| 1719 |
+
- Proximity detection
|
| 1720 |
+
- [ ] Location endpoints
|
| 1721 |
+
- GET /tickets/{ticket_id}/route
|
| 1722 |
+
- GET /tickets/{ticket_id}/verify-location
|
| 1723 |
+
- POST /tickets/{ticket_id}/location-update
|
| 1724 |
+
```
|
| 1725 |
+
|
| 1726 |
+
---
|
| 1727 |
+
|
| 1728 |
+
### Missing Feature 3: Caching Layer (Phase 15 Addition)
|
| 1729 |
+
|
| 1730 |
+
**Location:** Should be in Phase 15 (Week 16) with middleware
|
| 1731 |
+
|
| 1732 |
+
**Components to Add:**
|
| 1733 |
+
```
|
| 1734 |
+
- [ ] `app/utils/cache.py`
|
| 1735 |
+
- Redis caching utilities
|
| 1736 |
+
- Cache decorators
|
| 1737 |
+
- Cache invalidation patterns
|
| 1738 |
+
- Multi-level caching
|
| 1739 |
+
- [ ] Implement caching for:
|
| 1740 |
+
- User sessions (TTL: 24 hours)
|
| 1741 |
+
- Dashboard metrics (TTL: 5 minutes)
|
| 1742 |
+
- Project settings (TTL: 1 hour)
|
| 1743 |
+
- Agent locations (TTL: 1 minute)
|
| 1744 |
+
- SLA thresholds (TTL: 1 hour)
|
| 1745 |
+
- [ ] Cache invalidation triggers
|
| 1746 |
+
- On data updates
|
| 1747 |
+
- Pattern-based invalidation
|
| 1748 |
+
```
|
| 1749 |
+
|
| 1750 |
+
---
|
| 1751 |
+
|
| 1752 |
+
### Missing Feature 4: Distributed Locks (Phase 15 Addition)
|
| 1753 |
+
|
| 1754 |
+
**Location:** Should be in Phase 15 (Week 16) with security
|
| 1755 |
+
|
| 1756 |
+
**Components to Add:**
|
| 1757 |
+
```
|
| 1758 |
+
- [ ] `app/utils/distributed_lock.py`
|
| 1759 |
+
- Redis-based distributed locks
|
| 1760 |
+
- Lock acquisition with timeout
|
| 1761 |
+
- Auto-release on timeout
|
| 1762 |
+
- Deadlock prevention
|
| 1763 |
+
- [ ] Apply locks to:
|
| 1764 |
+
- Payroll processing
|
| 1765 |
+
- Payment processing
|
| 1766 |
+
- Inventory updates
|
| 1767 |
+
- Concurrent ticket assignments
|
| 1768 |
+
```
|
| 1769 |
+
|
| 1770 |
+
---
|
| 1771 |
+
|
| 1772 |
+
### Missing Feature 5: Audit Logging (Phase 15 Addition)
|
| 1773 |
+
|
| 1774 |
+
**Location:** Should be in Phase 15 (Week 16) with security
|
| 1775 |
+
|
| 1776 |
+
**Components to Add:**
|
| 1777 |
+
```
|
| 1778 |
+
- [ ] `app/services/audit_service.py`
|
| 1779 |
+
- Audit log creation
|
| 1780 |
+
- Change tracking
|
| 1781 |
+
- User action logging
|
| 1782 |
+
- [ ] Audit logging for:
|
| 1783 |
+
- Financial operations (payments, payroll)
|
| 1784 |
+
- Security operations (login, role changes)
|
| 1785 |
+
- Data operations (deletions, bulk updates)
|
| 1786 |
+
- Configuration changes
|
| 1787 |
+
- [ ] Audit log endpoints
|
| 1788 |
+
- GET /audit-logs
|
| 1789 |
+
- GET /audit-logs/user/{user_id}
|
| 1790 |
+
- GET /audit-logs/entity/{entity_type}/{entity_id}
|
| 1791 |
+
```
|
| 1792 |
+
|
| 1793 |
+
---
|
| 1794 |
+
|
| 1795 |
+
### Missing Feature 6: WebSocket Support (New Phase 19)
|
| 1796 |
+
|
| 1797 |
+
**Location:** New phase for real-time features
|
| 1798 |
+
|
| 1799 |
+
**Components to Add:**
|
| 1800 |
+
```
|
| 1801 |
+
- [ ] `app/api/websockets/`
|
| 1802 |
+
- location.py - Real-time location tracking
|
| 1803 |
+
- notifications.py - Real-time notifications
|
| 1804 |
+
- [ ] WebSocket connection management
|
| 1805 |
+
- [ ] Location broadcast to dispatchers
|
| 1806 |
+
- [ ] Notification push to users
|
| 1807 |
+
- [ ] Connection authentication
|
| 1808 |
+
- [ ] Heartbeat/keepalive
|
| 1809 |
+
```
|
| 1810 |
+
|
| 1811 |
+
---
|
| 1812 |
+
|
| 1813 |
+
### Missing Feature 7: Data Validation & Sanitization (Phase 4 Addition)
|
| 1814 |
+
|
| 1815 |
+
**Location:** Should be in Phase 4 (Week 4) with schemas
|
| 1816 |
+
|
| 1817 |
+
**Components to Add:**
|
| 1818 |
+
```
|
| 1819 |
+
- [ ] `app/utils/validators.py`
|
| 1820 |
+
- Phone number validation (Kenya format)
|
| 1821 |
+
- Email validation
|
| 1822 |
+
- GPS coordinate validation
|
| 1823 |
+
- Serial number validation
|
| 1824 |
+
- Custom business rule validators
|
| 1825 |
+
- [ ] `app/utils/sanitizers.py`
|
| 1826 |
+
- HTML sanitization (prevent XSS)
|
| 1827 |
+
- SQL injection prevention
|
| 1828 |
+
- File upload validation
|
| 1829 |
+
- Input normalization
|
| 1830 |
+
```
|
| 1831 |
+
|
| 1832 |
+
---
|
| 1833 |
+
|
| 1834 |
+
### Missing Feature 8: Pagination & Filtering Utilities (Phase 4 Addition)
|
| 1835 |
+
|
| 1836 |
+
**Location:** Should be in Phase 4 (Week 4) with schemas
|
| 1837 |
+
|
| 1838 |
+
**Components to Add:**
|
| 1839 |
+
```
|
| 1840 |
+
- [ ] `app/utils/pagination.py`
|
| 1841 |
+
- Pagination helper functions
|
| 1842 |
+
- Cursor-based pagination
|
| 1843 |
+
- Offset-based pagination
|
| 1844 |
+
- [ ] `app/utils/filters.py`
|
| 1845 |
+
- Dynamic filter builder
|
| 1846 |
+
- Query parameter parsing
|
| 1847 |
+
- Filter validation
|
| 1848 |
+
- Sort parameter handling
|
| 1849 |
+
```
|
| 1850 |
+
|
| 1851 |
+
---
|
| 1852 |
+
|
| 1853 |
+
### Missing Feature 9: SMS Integration (V2 - New Phase 21)
|
| 1854 |
+
|
| 1855 |
+
**Location:** New phase for V2 features
|
| 1856 |
+
|
| 1857 |
+
**Components to Add:**
|
| 1858 |
+
```
|
| 1859 |
+
- [ ] `app/integrations/africastalking.py`
|
| 1860 |
+
- SMS sending
|
| 1861 |
+
- Bulk SMS
|
| 1862 |
+
- Delivery status tracking
|
| 1863 |
+
- [ ] SMS use cases:
|
| 1864 |
+
- OTP codes
|
| 1865 |
+
- Urgent ticket assignments
|
| 1866 |
+
- SLA violation alerts
|
| 1867 |
+
- Payment confirmations
|
| 1868 |
+
- [ ] SMS endpoints
|
| 1869 |
+
- POST /communications/sms/send
|
| 1870 |
+
- POST /communications/sms/bulk
|
| 1871 |
+
- GET /communications/sms/{sms_id}/status
|
| 1872 |
+
```
|
| 1873 |
+
|
| 1874 |
+
---
|
| 1875 |
+
|
| 1876 |
+
### Missing Feature 10: Agent Allocation Service (V2 - New Phase 21)
|
| 1877 |
+
|
| 1878 |
+
**Location:** New phase for V2 features
|
| 1879 |
+
|
| 1880 |
+
**Components to Add:**
|
| 1881 |
+
```
|
| 1882 |
+
- [ ] `app/services/allocation_service.py`
|
| 1883 |
+
- Intelligent agent allocation algorithm
|
| 1884 |
+
- Workload balancing
|
| 1885 |
+
- Skill matching
|
| 1886 |
+
- Distance-based assignment
|
| 1887 |
+
- Availability checking
|
| 1888 |
+
- [ ] `app/services/route_optimization_service.py`
|
| 1889 |
+
- Route optimization for multiple tickets
|
| 1890 |
+
- Travel time calculation
|
| 1891 |
+
- Optimal sequence determination
|
| 1892 |
+
- [ ] Allocation endpoints
|
| 1893 |
+
- POST /tickets/{ticket_id}/auto-assign
|
| 1894 |
+
- POST /tickets/bulk-auto-assign
|
| 1895 |
+
- GET /agents/available
|
| 1896 |
+
- GET /agents/nearest
|
| 1897 |
+
```
|
| 1898 |
+
|
| 1899 |
+
---
|
| 1900 |
+
|
| 1901 |
+
### Missing Feature 11: Health Checks & Monitoring (V2 - New Phase 21)
|
| 1902 |
+
|
| 1903 |
+
**Location:** New phase for V2 features
|
| 1904 |
+
|
| 1905 |
+
**Components to Add:**
|
| 1906 |
+
```
|
| 1907 |
+
- [ ] Health check endpoints
|
| 1908 |
+
- GET /health
|
| 1909 |
+
- GET /health/database
|
| 1910 |
+
- GET /health/redis
|
| 1911 |
+
- GET /health/celery
|
| 1912 |
+
- GET /health/external-services
|
| 1913 |
+
- [ ] Usage monitoring
|
| 1914 |
+
- API request tracking
|
| 1915 |
+
- Response time monitoring
|
| 1916 |
+
- Error rate tracking
|
| 1917 |
+
- Resource usage monitoring
|
| 1918 |
+
- [ ] Infrastructure monitoring
|
| 1919 |
+
- Database performance
|
| 1920 |
+
- Redis memory usage
|
| 1921 |
+
- Celery queue lengths
|
| 1922 |
+
- External API quota tracking
|
| 1923 |
+
- [ ] Alerting system
|
| 1924 |
+
- Critical alerts (email, SMS, Slack)
|
| 1925 |
+
- Warning alerts
|
| 1926 |
+
- Info notifications
|
| 1927 |
+
```
|
| 1928 |
+
|
| 1929 |
+
---
|
| 1930 |
+
|
| 1931 |
+
### Missing Feature 12: Data Encryption (Phase 15 Addition)
|
| 1932 |
+
|
| 1933 |
+
**Location:** Should be in Phase 15 (Week 16) with security
|
| 1934 |
+
|
| 1935 |
+
**Components to Add:**
|
| 1936 |
+
```
|
| 1937 |
+
- [ ] `app/utils/encryption.py`
|
| 1938 |
+
- Field-level encryption
|
| 1939 |
+
- Encryption key management
|
| 1940 |
+
- Decrypt on read
|
| 1941 |
+
- [ ] Encrypt sensitive fields:
|
| 1942 |
+
- Financial account numbers
|
| 1943 |
+
- ID numbers
|
| 1944 |
+
- Tax information
|
| 1945 |
+
- Bank account numbers
|
| 1946 |
+
```
|
| 1947 |
+
|
| 1948 |
+
---
|
| 1949 |
+
|
| 1950 |
+
### Missing Feature 13: Rate Limiting Configuration (Phase 15 Addition)
|
| 1951 |
+
|
| 1952 |
+
**Location:** Should be in Phase 15 (Week 16) with middleware
|
| 1953 |
+
|
| 1954 |
+
**Components to Add:**
|
| 1955 |
+
```
|
| 1956 |
+
- [ ] Configure rate limits per endpoint:
|
| 1957 |
+
- Auth endpoints: 5 requests/5 minutes
|
| 1958 |
+
- OTP generation: 3 requests/5 minutes
|
| 1959 |
+
- Standard API: 1000 requests/hour
|
| 1960 |
+
- Search: 100 requests/minute
|
| 1961 |
+
- Export: 10 requests/hour
|
| 1962 |
+
- [ ] Rate limit storage in Redis
|
| 1963 |
+
- [ ] Rate limit headers in responses
|
| 1964 |
+
- [ ] Rate limit exceeded error handling
|
| 1965 |
+
```
|
| 1966 |
+
|
| 1967 |
+
---
|
| 1968 |
+
|
| 1969 |
+
### Missing Feature 14: File Upload Validation (Phase 11 Addition)
|
| 1970 |
+
|
| 1971 |
+
**Location:** Should be in Phase 11 (Week 12) with media service
|
| 1972 |
+
|
| 1973 |
+
**Components to Add:**
|
| 1974 |
+
```
|
| 1975 |
+
- [ ] `app/utils/file_utils.py`
|
| 1976 |
+
- File type validation
|
| 1977 |
+
- File size validation
|
| 1978 |
+
- Image dimension validation
|
| 1979 |
+
- Malware scanning (optional)
|
| 1980 |
+
- EXIF data extraction
|
| 1981 |
+
- [ ] Validation rules:
|
| 1982 |
+
- Max file size: 10MB
|
| 1983 |
+
- Allowed types: JPG, PNG, PDF
|
| 1984 |
+
- Min image dimensions: 640x480
|
| 1985 |
+
```
|
| 1986 |
+
|
| 1987 |
+
---
|
| 1988 |
+
|
| 1989 |
+
### Missing Feature 15: Error Response Standardization (Phase 1 Addition)
|
| 1990 |
+
|
| 1991 |
+
**Location:** Should be in Phase 1 (Week 1) with core components
|
| 1992 |
+
|
| 1993 |
+
**Components to Add:**
|
| 1994 |
+
```
|
| 1995 |
+
- [ ] Standardized error response format:
|
| 1996 |
+
{
|
| 1997 |
+
"success": false,
|
| 1998 |
+
"error": {
|
| 1999 |
+
"code": "VALIDATION_ERROR",
|
| 2000 |
+
"message": "Invalid input data",
|
| 2001 |
+
"details": {...}
|
| 2002 |
+
},
|
| 2003 |
+
"timestamp": "2024-01-15T10:30:00Z"
|
| 2004 |
+
}
|
| 2005 |
+
- [ ] Success response format:
|
| 2006 |
+
{
|
| 2007 |
+
"success": true,
|
| 2008 |
+
"data": {...},
|
| 2009 |
+
"message": "Operation completed successfully",
|
| 2010 |
+
"timestamp": "2024-01-15T10:30:00Z"
|
| 2011 |
+
}
|
| 2012 |
+
```
|
| 2013 |
+
|
| 2014 |
+
---
|
| 2015 |
+
|
| 2016 |
+
## 📋 Updated Implementation Phases
|
| 2017 |
+
|
| 2018 |
+
### NEW Phase 19: WebSocket & Real-time Features (Week 21)
|
| 2019 |
+
**Goal:** Implement real-time communication
|
| 2020 |
+
|
| 2021 |
+
#### Day 1-3: WebSocket Infrastructure
|
| 2022 |
+
- [ ] Set up WebSocket support in FastAPI
|
| 2023 |
+
- [ ] Connection management
|
| 2024 |
+
- [ ] Authentication for WebSocket connections
|
| 2025 |
+
- [ ] Heartbeat/keepalive mechanism
|
| 2026 |
+
|
| 2027 |
+
#### Day 4-5: Location Tracking
|
| 2028 |
+
- [ ] Real-time location updates
|
| 2029 |
+
- [ ] Location broadcast to dispatchers
|
| 2030 |
+
- [ ] Journey tracking
|
| 2031 |
+
- [ ] GPS validation
|
| 2032 |
+
|
| 2033 |
+
#### Day 6-7: Real-time Notifications
|
| 2034 |
+
- [ ] Push notifications via WebSocket
|
| 2035 |
+
- [ ] Notification queue management
|
| 2036 |
+
- [ ] Connection recovery
|
| 2037 |
+
- [ ] Test real-time features
|
| 2038 |
+
|
| 2039 |
+
---
|
| 2040 |
+
|
| 2041 |
+
### NEW Phase 20: Performance Optimization (Week 22)
|
| 2042 |
+
**Goal:** Optimize system performance
|
| 2043 |
+
|
| 2044 |
+
#### Day 1-2: Database Optimization
|
| 2045 |
+
- [ ] Query optimization
|
| 2046 |
+
- [ ] Index analysis and creation
|
| 2047 |
+
- [ ] N+1 query elimination
|
| 2048 |
+
- [ ] Database connection pool tuning
|
| 2049 |
+
|
| 2050 |
+
#### Day 3-4: Caching Optimization
|
| 2051 |
+
- [ ] Implement caching strategy
|
| 2052 |
+
- [ ] Cache warming
|
| 2053 |
+
- [ ] Cache invalidation testing
|
| 2054 |
+
- [ ] Cache hit rate monitoring
|
| 2055 |
+
|
| 2056 |
+
#### Day 5-7: API Performance
|
| 2057 |
+
- [ ] Response time optimization
|
| 2058 |
+
- [ ] Payload size reduction
|
| 2059 |
+
- [ ] Compression configuration
|
| 2060 |
+
- [ ] Load testing and benchmarking
|
| 2061 |
+
|
| 2062 |
+
---
|
| 2063 |
+
|
| 2064 |
+
### NEW Phase 21: V2 Features (Week 23-24)
|
| 2065 |
+
**Goal:** Implement advanced features
|
| 2066 |
+
|
| 2067 |
+
#### Week 23: SMS & Agent Allocation
|
| 2068 |
+
- [ ] Africa's Talking SMS integration
|
| 2069 |
+
- [ ] SMS notification templates
|
| 2070 |
+
- [ ] Intelligent agent allocation service
|
| 2071 |
+
- [ ] Route optimization service
|
| 2072 |
+
- [ ] Test allocation algorithms
|
| 2073 |
+
|
| 2074 |
+
#### Week 24: Monitoring & Health Checks
|
| 2075 |
+
- [ ] Health check endpoints
|
| 2076 |
+
- [ ] Usage monitoring
|
| 2077 |
+
- [ ] Infrastructure monitoring
|
| 2078 |
+
- [ ] Alerting system
|
| 2079 |
+
- [ ] Dashboard for monitoring
|
| 2080 |
+
|
| 2081 |
+
---
|
| 2082 |
+
|
| 2083 |
+
## 🔍 Testing Strategy (Missing Section)
|
| 2084 |
+
|
| 2085 |
+
### Unit Testing
|
| 2086 |
+
**Coverage Goal:** 80%+
|
| 2087 |
+
|
| 2088 |
+
**What to Test:**
|
| 2089 |
+
- All service methods
|
| 2090 |
+
- All repository methods
|
| 2091 |
+
- All utility functions
|
| 2092 |
+
- Business rule validation
|
| 2093 |
+
- Error handling
|
| 2094 |
+
|
| 2095 |
+
**Tools:**
|
| 2096 |
+
- pytest
|
| 2097 |
+
- pytest-cov (coverage)
|
| 2098 |
+
- pytest-mock (mocking)
|
| 2099 |
+
- faker (test data)
|
| 2100 |
+
|
| 2101 |
+
### Integration Testing
|
| 2102 |
+
**What to Test:**
|
| 2103 |
+
- API endpoint workflows
|
| 2104 |
+
- Database transactions
|
| 2105 |
+
- External service integrations
|
| 2106 |
+
- Background task execution
|
| 2107 |
+
- Cache behavior
|
| 2108 |
+
|
| 2109 |
+
### End-to-End Testing
|
| 2110 |
+
**What to Test:**
|
| 2111 |
+
- Complete user workflows
|
| 2112 |
+
- Sales order → ticket → completion
|
| 2113 |
+
- Payment processing
|
| 2114 |
+
- CSV import/export
|
| 2115 |
+
- Multi-user scenarios
|
| 2116 |
+
|
| 2117 |
+
### Load Testing
|
| 2118 |
+
**What to Test:**
|
| 2119 |
+
- API response times under load
|
| 2120 |
+
- Database performance
|
| 2121 |
+
- Concurrent user handling
|
| 2122 |
+
- WebSocket connection limits
|
| 2123 |
+
|
| 2124 |
+
**Tools:**
|
| 2125 |
+
- Locust
|
| 2126 |
+
- Apache JMeter
|
| 2127 |
+
- k6
|
| 2128 |
+
|
| 2129 |
+
---
|
| 2130 |
+
|
| 2131 |
+
## 🚀 Deployment Checklist (Expanded)
|
| 2132 |
+
|
| 2133 |
+
### Pre-Deployment
|
| 2134 |
+
- [ ] All environment variables configured
|
| 2135 |
+
- [ ] Database migrations tested
|
| 2136 |
+
- [ ] Redis connection verified
|
| 2137 |
+
- [ ] Celery workers configured
|
| 2138 |
+
- [ ] External services tested (M-Pesa, Cloudinary, Resend)
|
| 2139 |
+
- [ ] SSL certificates configured
|
| 2140 |
+
- [ ] Monitoring setup (Sentry)
|
| 2141 |
+
- [ ] Backup strategy implemented
|
| 2142 |
+
- [ ] Load balancer configured
|
| 2143 |
+
- [ ] CDN configured (for static assets)
|
| 2144 |
+
- [ ] Rate limiting configured
|
| 2145 |
+
- [ ] CORS settings verified
|
| 2146 |
+
- [ ] Security headers configured
|
| 2147 |
+
- [ ] Database indexes created
|
| 2148 |
+
- [ ] Cache warming scripts ready
|
| 2149 |
+
|
| 2150 |
+
### Post-Deployment
|
| 2151 |
+
- [ ] Health checks passing
|
| 2152 |
+
- [ ] API documentation accessible
|
| 2153 |
+
- [ ] Webhooks configured
|
| 2154 |
+
- [ ] Scheduled tasks running
|
| 2155 |
+
- [ ] Logs being collected
|
| 2156 |
+
- [ ] Alerts configured
|
| 2157 |
+
- [ ] Performance monitoring active
|
| 2158 |
+
- [ ] Database backups running
|
| 2159 |
+
- [ ] SSL certificate auto-renewal configured
|
| 2160 |
+
- [ ] Smoke tests passed
|
| 2161 |
+
- [ ] Load testing completed
|
| 2162 |
+
- [ ] Rollback plan documented
|
| 2163 |
+
- [ ] On-call rotation established
|
| 2164 |
+
|
| 2165 |
+
---
|
| 2166 |
+
|
| 2167 |
+
## 📊 Success Metrics (Expanded)
|
| 2168 |
+
|
| 2169 |
+
### Technical Metrics
|
| 2170 |
+
- API response time < 200ms (p95)
|
| 2171 |
+
- Database query time < 50ms (p95)
|
| 2172 |
+
- Cache hit rate > 80%
|
| 2173 |
+
- Test coverage > 80%
|
| 2174 |
+
- Zero critical security vulnerabilities
|
| 2175 |
+
- 99.9% uptime
|
| 2176 |
+
- Error rate < 0.1%
|
| 2177 |
+
- Background job success rate > 99%
|
| 2178 |
+
|
| 2179 |
+
### Business Metrics
|
| 2180 |
+
- Support 1000+ concurrent field agents
|
| 2181 |
+
- Process 10,000+ tickets per month
|
| 2182 |
+
- Handle 500+ payroll payments per week
|
| 2183 |
+
- 95% SLA compliance rate
|
| 2184 |
+
- < 1% payment failure rate
|
| 2185 |
+
- Average ticket completion time < 48 hours
|
| 2186 |
+
- Customer satisfaction > 4.5/5
|
| 2187 |
+
|
| 2188 |
+
### Performance Benchmarks
|
| 2189 |
+
- Handle 1000 requests/second
|
| 2190 |
+
- Support 10,000 concurrent WebSocket connections
|
| 2191 |
+
- Process CSV with 10,000 rows in < 5 minutes
|
| 2192 |
+
- Generate payroll for 500 agents in < 10 minutes
|
| 2193 |
+
- Dashboard load time < 2 seconds
|
| 2194 |
+
|
| 2195 |
+
---
|
| 2196 |
+
|
| 2197 |
+
## 🔧 Maintenance & Operations (New Section)
|
| 2198 |
+
|
| 2199 |
+
### Daily Operations
|
| 2200 |
+
- [ ] Monitor error rates
|
| 2201 |
+
- [ ] Check background job status
|
| 2202 |
+
- [ ] Review payment failures
|
| 2203 |
+
- [ ] Check SLA violations
|
| 2204 |
+
- [ ] Monitor API performance
|
| 2205 |
+
|
| 2206 |
+
### Weekly Operations
|
| 2207 |
+
- [ ] Review logs for anomalies
|
| 2208 |
+
- [ ] Check database performance
|
| 2209 |
+
- [ ] Review security alerts
|
| 2210 |
+
- [ ] Update dependencies (security patches)
|
| 2211 |
+
- [ ] Backup verification
|
| 2212 |
+
|
| 2213 |
+
### Monthly Operations
|
| 2214 |
+
- [ ] Performance review
|
| 2215 |
+
- [ ] Cost optimization review
|
| 2216 |
+
- [ ] Security audit
|
| 2217 |
+
- [ ] Dependency updates
|
| 2218 |
+
- [ ] Database maintenance (vacuum, analyze)
|
| 2219 |
+
- [ ] Archive old data
|
| 2220 |
+
|
| 2221 |
+
### Quarterly Operations
|
| 2222 |
+
- [ ] Disaster recovery drill
|
| 2223 |
+
- [ ] Security penetration testing
|
| 2224 |
+
- [ ] Performance benchmarking
|
| 2225 |
+
- [ ] Infrastructure review
|
| 2226 |
+
- [ ] Documentation update
|
| 2227 |
+
|
| 2228 |
+
---
|
| 2229 |
+
|
| 2230 |
+
## 🎓 Knowledge Transfer (New Section)
|
| 2231 |
+
|
| 2232 |
+
### Documentation to Create
|
| 2233 |
+
- [ ] API documentation (OpenAPI/Swagger)
|
| 2234 |
+
- [ ] Architecture diagrams
|
| 2235 |
+
- [ ] Database schema documentation
|
| 2236 |
+
- [ ] Deployment runbook
|
| 2237 |
+
- [ ] Troubleshooting guide
|
| 2238 |
+
- [ ] Incident response playbook
|
| 2239 |
+
- [ ] Onboarding guide for new developers
|
| 2240 |
+
- [ ] Code style guide
|
| 2241 |
+
- [ ] Git workflow guide
|
| 2242 |
+
|
| 2243 |
+
### Training Materials
|
| 2244 |
+
- [ ] Video walkthrough of architecture
|
| 2245 |
+
- [ ] Code review guidelines
|
| 2246 |
+
- [ ] Testing best practices
|
| 2247 |
+
- [ ] Deployment procedures
|
| 2248 |
+
- [ ] Monitoring and alerting guide
|
| 2249 |
+
|
| 2250 |
+
---
|
| 2251 |
+
|
| 2252 |
+
## 🔐 Security Hardening Checklist (New Section)
|
| 2253 |
+
|
| 2254 |
+
### Application Security
|
| 2255 |
+
- [ ] Input validation on all endpoints
|
| 2256 |
+
- [ ] SQL injection prevention (ORM usage)
|
| 2257 |
+
- [ ] XSS prevention (HTML sanitization)
|
| 2258 |
+
- [ ] CSRF protection
|
| 2259 |
+
- [ ] Rate limiting configured
|
| 2260 |
+
- [ ] Authentication on all protected endpoints
|
| 2261 |
+
- [ ] Authorization checks on all operations
|
| 2262 |
+
- [ ] Sensitive data encryption
|
| 2263 |
+
- [ ] Secure password hashing (bcrypt)
|
| 2264 |
+
- [ ] JWT token expiration configured
|
| 2265 |
+
|
| 2266 |
+
### Infrastructure Security
|
| 2267 |
+
- [ ] HTTPS enforced
|
| 2268 |
+
- [ ] Security headers configured (HSTS, CSP, etc.)
|
| 2269 |
+
- [ ] Database access restricted (IP whitelist)
|
| 2270 |
+
- [ ] Redis access restricted
|
| 2271 |
+
- [ ] API keys rotated regularly
|
| 2272 |
+
- [ ] Secrets stored securely (not in code)
|
| 2273 |
+
- [ ] Firewall rules configured
|
| 2274 |
+
- [ ] DDoS protection enabled
|
| 2275 |
+
- [ ] Regular security updates
|
| 2276 |
+
|
| 2277 |
+
### Compliance
|
| 2278 |
+
- [ ] GDPR compliance (data deletion, export)
|
| 2279 |
+
- [ ] Audit logging for sensitive operations
|
| 2280 |
+
- [ ] Data retention policies implemented
|
| 2281 |
+
- [ ] Privacy policy documented
|
| 2282 |
+
- [ ] Terms of service documented
|
| 2283 |
+
|
| 2284 |
+
---
|
| 2285 |
+
|
| 2286 |
+
## 📈 Scalability Roadmap (New Section)
|
| 2287 |
+
|
| 2288 |
+
### Phase 1: Current (1-1000 users)
|
| 2289 |
+
- Single server deployment
|
| 2290 |
+
- Vertical scaling
|
| 2291 |
+
- Basic caching
|
| 2292 |
+
- Manual monitoring
|
| 2293 |
+
|
| 2294 |
+
### Phase 2: Growth (1000-10,000 users)
|
| 2295 |
+
- Load balancer
|
| 2296 |
+
- Multiple API servers
|
| 2297 |
+
- Redis cluster
|
| 2298 |
+
- Database read replicas
|
| 2299 |
+
- CDN for static assets
|
| 2300 |
+
- Automated monitoring
|
| 2301 |
+
|
| 2302 |
+
### Phase 3: Scale (10,000+ users)
|
| 2303 |
+
- Kubernetes orchestration
|
| 2304 |
+
- Auto-scaling
|
| 2305 |
+
- Database sharding
|
| 2306 |
+
- Message queue (RabbitMQ/Kafka)
|
| 2307 |
+
- Microservices architecture (if needed)
|
| 2308 |
+
- Advanced caching (Varnish)
|
| 2309 |
+
- Global CDN
|
| 2310 |
+
|
| 2311 |
+
---
|
| 2312 |
+
|
| 2313 |
+
## 🎯 Post-Launch Roadmap (New Section)
|
| 2314 |
+
|
| 2315 |
+
### Month 1-3: Stabilization
|
| 2316 |
+
- Bug fixes based on user feedback
|
| 2317 |
+
- Performance optimization
|
| 2318 |
+
- Monitoring and alerting refinement
|
| 2319 |
+
- Documentation updates
|
| 2320 |
+
|
| 2321 |
+
### Month 4-6: Feature Enhancements
|
| 2322 |
+
- SMS integration (Africa's Talking)
|
| 2323 |
+
- Intelligent agent allocation
|
| 2324 |
+
- Route optimization
|
| 2325 |
+
- Advanced analytics
|
| 2326 |
+
- Custom reports
|
| 2327 |
+
|
| 2328 |
+
### Month 7-12: Advanced Features
|
| 2329 |
+
- Mobile app optimization
|
| 2330 |
+
- Offline mode improvements
|
| 2331 |
+
- AI-powered insights
|
| 2332 |
+
- Predictive analytics
|
| 2333 |
+
- Multi-language support
|
| 2334 |
+
- Customer portal
|
| 2335 |
+
|
| 2336 |
+
---
|
| 2337 |
+
|
| 2338 |
+
**Document Status:** Complete with all missing components identified and added
|
| 2339 |
+
**Last Updated:** November 2025
|
| 2340 |
+
**Next Review:** Before Phase 1 implementation begins
|
docs/dev/TEMPLATES_ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps API - Templates Architecture
|
| 2 |
+
|
| 3 |
+
## 🏗️ Architecture Overview
|
| 4 |
+
|
| 5 |
+
Following FastAPI best practices, we've separated concerns into distinct layers:
|
| 6 |
+
|
| 7 |
+
```
|
| 8 |
+
src/app/
|
| 9 |
+
├── templates/ # Jinja2 HTML templates
|
| 10 |
+
│ ├── base.html # Base template (layout)
|
| 11 |
+
│ ├── index.html # Landing page
|
| 12 |
+
│ └── README.md # Template documentation
|
| 13 |
+
│
|
| 14 |
+
├── static/ # Static assets
|
| 15 |
+
│ ├── css/
|
| 16 |
+
│ │ └── main.css # Styles (theme-aware)
|
| 17 |
+
│ └── js/
|
| 18 |
+
│ └── main.js # Client-side JavaScript
|
| 19 |
+
│
|
| 20 |
+
├── api/v1/
|
| 21 |
+
│ ├── pages.py # Page routes (HTML)
|
| 22 |
+
│ ├── auth.py # API routes (JSON)
|
| 23 |
+
│ └── ... # Other API routes
|
| 24 |
+
│
|
| 25 |
+
├── constants/
|
| 26 |
+
│ └── app_metadata.py # Centralized app config
|
| 27 |
+
│
|
| 28 |
+
└── main.py # Application entry point
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## 📋 Design Principles
|
| 34 |
+
|
| 35 |
+
### 1. **Separation of Concerns**
|
| 36 |
+
- **Templates** (`templates/`) - HTML structure
|
| 37 |
+
- **Styles** (`static/css/`) - Visual presentation
|
| 38 |
+
- **Scripts** (`static/js/`) - Client behavior
|
| 39 |
+
- **Routes** (`api/v1/pages.py`) - Page logic
|
| 40 |
+
- **Config** (`constants/app_metadata.py`) - Metadata
|
| 41 |
+
|
| 42 |
+
### 2. **Template Inheritance**
|
| 43 |
+
```
|
| 44 |
+
base.html (layout)
|
| 45 |
+
↓
|
| 46 |
+
index.html (content)
|
| 47 |
+
↓
|
| 48 |
+
Future pages extend base.html
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
### 3. **Static File Serving**
|
| 52 |
+
```python
|
| 53 |
+
# Mounted in main.py
|
| 54 |
+
app.mount("/static", StaticFiles(directory="static"), name="static")
|
| 55 |
+
|
| 56 |
+
# Used in templates
|
| 57 |
+
<link rel="stylesheet" href="{{ url_for('static', path='/css/main.css') }}">
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
### 4. **Centralized Configuration**
|
| 61 |
+
```python
|
| 62 |
+
# constants/app_metadata.py
|
| 63 |
+
APP_NAME = "SwiftOps API"
|
| 64 |
+
APP_VERSION = "1.0.0"
|
| 65 |
+
|
| 66 |
+
# Used everywhere
|
| 67 |
+
from app.constants.app_metadata import APP_NAME, APP_VERSION
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
---
|
| 71 |
+
|
| 72 |
+
## 🎨 Features
|
| 73 |
+
|
| 74 |
+
### Theme Support
|
| 75 |
+
- ✅ Automatic dark/light mode detection
|
| 76 |
+
- ✅ Respects system preferences
|
| 77 |
+
- ✅ Smooth transitions
|
| 78 |
+
- ✅ CSS custom properties (variables)
|
| 79 |
+
|
| 80 |
+
### Responsive Design
|
| 81 |
+
- ✅ Mobile-first approach
|
| 82 |
+
- ✅ Flexible grid layouts
|
| 83 |
+
- ✅ Touch-friendly interactions
|
| 84 |
+
- ✅ Breakpoints for all devices
|
| 85 |
+
|
| 86 |
+
### Performance
|
| 87 |
+
- ✅ Minimal CSS/JS
|
| 88 |
+
- ✅ No external dependencies
|
| 89 |
+
- ✅ Fast page loads
|
| 90 |
+
- ✅ Optimized assets
|
| 91 |
+
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
## 📝 Adding New Pages
|
| 95 |
+
|
| 96 |
+
### Step 1: Create Template
|
| 97 |
+
|
| 98 |
+
```html
|
| 99 |
+
<!-- templates/about.html -->
|
| 100 |
+
{% extends "base.html" %}
|
| 101 |
+
|
| 102 |
+
{% block title %}About - {{ app_name }}{% endblock %}
|
| 103 |
+
|
| 104 |
+
{% block content %}
|
| 105 |
+
<div class="container">
|
| 106 |
+
<h1>About {{ app_name }}</h1>
|
| 107 |
+
<p>{{ app_description }}</p>
|
| 108 |
+
</div>
|
| 109 |
+
{% endblock %}
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
### Step 2: Add Route
|
| 113 |
+
|
| 114 |
+
```python
|
| 115 |
+
# api/v1/pages.py
|
| 116 |
+
@router.get("/about", response_class=HTMLResponse)
|
| 117 |
+
async def about(request: Request):
|
| 118 |
+
return templates.TemplateResponse("about.html", {
|
| 119 |
+
"request": request,
|
| 120 |
+
"app_name": APP_NAME,
|
| 121 |
+
"app_description": APP_DESCRIPTION
|
| 122 |
+
})
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
### Step 3: Update Navigation (if needed)
|
| 126 |
+
|
| 127 |
+
```html
|
| 128 |
+
<!-- templates/base.html -->
|
| 129 |
+
<nav>
|
| 130 |
+
<a href="/">Home</a>
|
| 131 |
+
<a href="/about">About</a>
|
| 132 |
+
</nav>
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
---
|
| 136 |
+
|
| 137 |
+
## 🎯 Best Practices
|
| 138 |
+
|
| 139 |
+
### 1. **Keep Templates Simple**
|
| 140 |
+
- Logic in Python (routes)
|
| 141 |
+
- Presentation in HTML (templates)
|
| 142 |
+
- Styling in CSS (separate file)
|
| 143 |
+
|
| 144 |
+
### 2. **Use Template Inheritance**
|
| 145 |
+
```html
|
| 146 |
+
{% extends "base.html" %}
|
| 147 |
+
{% block content %}...{% endblock %}
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
### 3. **Centralize Configuration**
|
| 151 |
+
```python
|
| 152 |
+
# Don't hardcode
|
| 153 |
+
app_name = "SwiftOps API"
|
| 154 |
+
|
| 155 |
+
# Do this
|
| 156 |
+
from app.constants.app_metadata import APP_NAME
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
### 4. **Include Request Object**
|
| 160 |
+
```python
|
| 161 |
+
# Always pass request to templates
|
| 162 |
+
return templates.TemplateResponse("page.html", {
|
| 163 |
+
"request": request, # Required by Jinja2Templates
|
| 164 |
+
"data": data
|
| 165 |
+
})
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
### 5. **Use url_for for Static Files**
|
| 169 |
+
```html
|
| 170 |
+
<!-- Good -->
|
| 171 |
+
<link href="{{ url_for('static', path='/css/main.css') }}">
|
| 172 |
+
|
| 173 |
+
<!-- Avoid -->
|
| 174 |
+
<link href="/static/css/main.css">
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
---
|
| 178 |
+
|
| 179 |
+
## 🔧 Customization
|
| 180 |
+
|
| 181 |
+
### Update App Metadata
|
| 182 |
+
|
| 183 |
+
Edit `constants/app_metadata.py`:
|
| 184 |
+
|
| 185 |
+
```python
|
| 186 |
+
APP_NAME = "Your App Name"
|
| 187 |
+
APP_VERSION = "2.0.0"
|
| 188 |
+
APP_DESCRIPTION = "Your description"
|
| 189 |
+
```
|
| 190 |
+
|
| 191 |
+
### Add Custom Styles
|
| 192 |
+
|
| 193 |
+
Edit `static/css/main.css`:
|
| 194 |
+
|
| 195 |
+
```css
|
| 196 |
+
/* Add your custom styles */
|
| 197 |
+
.custom-class {
|
| 198 |
+
color: var(--accent-color);
|
| 199 |
+
}
|
| 200 |
+
```
|
| 201 |
+
|
| 202 |
+
### Add Custom JavaScript
|
| 203 |
+
|
| 204 |
+
Edit `static/js/main.js`:
|
| 205 |
+
|
| 206 |
+
```javascript
|
| 207 |
+
// Add your custom scripts
|
| 208 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 209 |
+
// Your code here
|
| 210 |
+
});
|
| 211 |
+
```
|
| 212 |
+
|
| 213 |
+
---
|
| 214 |
+
|
| 215 |
+
## 📊 File Structure Benefits
|
| 216 |
+
|
| 217 |
+
### ✅ **Maintainability**
|
| 218 |
+
- Clear separation of concerns
|
| 219 |
+
- Easy to find and update files
|
| 220 |
+
- Consistent structure
|
| 221 |
+
|
| 222 |
+
### ✅ **Scalability**
|
| 223 |
+
- Add new pages easily
|
| 224 |
+
- Extend base template
|
| 225 |
+
- Reuse components
|
| 226 |
+
|
| 227 |
+
### ✅ **Testability**
|
| 228 |
+
- Routes are separate from templates
|
| 229 |
+
- Logic is in Python (testable)
|
| 230 |
+
- Templates are pure HTML
|
| 231 |
+
|
| 232 |
+
### ✅ **Performance**
|
| 233 |
+
- Static files cached by browser
|
| 234 |
+
- Minimal dependencies
|
| 235 |
+
- Fast rendering
|
| 236 |
+
|
| 237 |
+
---
|
| 238 |
+
|
| 239 |
+
## 🚀 Future Enhancements
|
| 240 |
+
|
| 241 |
+
### Planned Features
|
| 242 |
+
- [ ] Component library (reusable blocks)
|
| 243 |
+
- [ ] Admin dashboard template
|
| 244 |
+
- [ ] Error pages (404, 500)
|
| 245 |
+
- [ ] Email templates
|
| 246 |
+
- [ ] PDF generation templates
|
| 247 |
+
|
| 248 |
+
### Possible Additions
|
| 249 |
+
- [ ] Template fragments (HTMX support)
|
| 250 |
+
- [ ] Internationalization (i18n)
|
| 251 |
+
- [ ] Template caching
|
| 252 |
+
- [ ] Asset bundling/minification
|
| 253 |
+
|
| 254 |
+
---
|
| 255 |
+
|
| 256 |
+
## 📚 Resources
|
| 257 |
+
|
| 258 |
+
- [FastAPI Templates](https://fastapi.tiangolo.com/advanced/templates/)
|
| 259 |
+
- [Jinja2 Documentation](https://jinja.palletsprojects.com/)
|
| 260 |
+
- [Static Files in FastAPI](https://fastapi.tiangolo.com/tutorial/static-files/)
|
| 261 |
+
- [CSS Custom Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/--*)
|
| 262 |
+
|
| 263 |
+
---
|
| 264 |
+
|
| 265 |
+
**This architecture provides a solid foundation for building scalable, maintainable web pages in your FastAPI application!** 🎉
|
docs/dev/spec/DEVELOPMENT_CHECKLIST.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend - Development Checklist
|
| 2 |
+
|
| 3 |
+
Track your progress as you build the system.
|
| 4 |
+
|
| 5 |
+
## ✅ Phase 1: Foundation (Week 1)
|
| 6 |
+
|
| 7 |
+
### Day 1-2: Project Setup
|
| 8 |
+
- [ ] Virtual environment created and activated
|
| 9 |
+
- [ ] Dependencies installed (`pip install -r requirements-dev.txt`)
|
| 10 |
+
- [ ] `.env` file configured with credentials
|
| 11 |
+
- [ ] Docker services running (`docker-compose up -d`)
|
| 12 |
+
- [ ] Can access http://localhost:8000
|
| 13 |
+
- [ ] Can access http://localhost:8000/api/docs
|
| 14 |
+
|
| 15 |
+
### Day 3-4: Core Components
|
| 16 |
+
- [ ] `app/models/base.py` - Base model tested
|
| 17 |
+
- [ ] `app/models/enums.py` - All ENUMs defined
|
| 18 |
+
- [ ] `app/schemas/base.py` - Base schemas created
|
| 19 |
+
- [ ] `app/schemas/common.py` - Pagination schemas created
|
| 20 |
+
- [ ] First Alembic migration created
|
| 21 |
+
- [ ] Migration applied successfully
|
| 22 |
+
|
| 23 |
+
### Day 5-7: Authentication & Authorization
|
| 24 |
+
- [ ] `app/core/auth.py` - JWT functions tested
|
| 25 |
+
- [ ] `app/core/security.py` - Password hashing tested
|
| 26 |
+
- [ ] `app/integrations/supabase.py` - Supabase client working
|
| 27 |
+
- [ ] `app/services/auth_service.py` - Login logic implemented
|
| 28 |
+
- [ ] `app/api/v1/auth.py` - Auth endpoints working
|
| 29 |
+
- [ ] `app/api/deps.py` - Auth dependencies working
|
| 30 |
+
- [ ] Can login and get JWT token
|
| 31 |
+
- [ ] Protected endpoints require authentication
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## ✅ Phase 2: Core Domain Models (Week 2)
|
| 36 |
+
|
| 37 |
+
### Day 1-2: User & Organization Models
|
| 38 |
+
- [ ] `app/models/user.py` - Users table
|
| 39 |
+
- [ ] `app/models/user.py` - UserFinancialAccounts table
|
| 40 |
+
- [ ] `app/models/user.py` - UserAssetAssignments table
|
| 41 |
+
- [ ] `app/models/user.py` - UserPreferences table
|
| 42 |
+
- [ ] `app/models/organization.py` - Clients table
|
| 43 |
+
- [ ] `app/models/organization.py` - Contractors table
|
| 44 |
+
- [ ] Migration created and applied
|
| 45 |
+
- [ ] Can create users and organizations
|
| 46 |
+
|
| 47 |
+
### Day 3-4: Project & Team Models
|
| 48 |
+
- [ ] `app/models/project.py` - Projects table
|
| 49 |
+
- [ ] `app/models/project.py` - ProjectTeam table
|
| 50 |
+
- [ ] `app/models/project.py` - ProjectRoles table
|
| 51 |
+
- [ ] `app/models/project.py` - ProjectRegions table
|
| 52 |
+
- [ ] `app/models/project.py` - ProjectSubcontractors table
|
| 53 |
+
- [ ] Migration created and applied
|
| 54 |
+
- [ ] Can create projects with teams
|
| 55 |
+
|
| 56 |
+
### Day 5-7: Ticket & Customer Models
|
| 57 |
+
- [ ] `app/models/ticket.py` - Tickets table
|
| 58 |
+
- [ ] `app/models/ticket.py` - TicketAssignments table
|
| 59 |
+
- [ ] `app/models/ticket.py` - TicketStatusHistory table
|
| 60 |
+
- [ ] `app/models/ticket.py` - TicketExpenses table
|
| 61 |
+
- [ ] `app/models/customer.py` - Customers table
|
| 62 |
+
- [ ] `app/models/customer.py` - SalesOrders table
|
| 63 |
+
- [ ] `app/models/customer.py` - Subscriptions table
|
| 64 |
+
- [ ] `app/models/incident.py` - Incidents table
|
| 65 |
+
- [ ] `app/models/inventory.py` - All inventory tables
|
| 66 |
+
- [ ] `app/models/finance.py` - All finance tables
|
| 67 |
+
- [ ] `app/models/timesheet.py` - Timesheets table
|
| 68 |
+
- [ ] `app/models/document.py` - Documents table
|
| 69 |
+
- [ ] `app/models/media.py` - MediaFiles table
|
| 70 |
+
- [ ] `app/models/audit_log.py` - AuditLogs table
|
| 71 |
+
- [ ] All migrations created and applied
|
| 72 |
+
- [ ] Database schema matches schema.sql
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
## ✅ Phase 3: Repository Layer (Week 3)
|
| 77 |
+
|
| 78 |
+
### Day 1-2: Base Repository & Core Repositories
|
| 79 |
+
- [ ] `app/repositories/base_repository.py` - Tested with all CRUD operations
|
| 80 |
+
- [ ] `app/repositories/user_repository.py` - Implemented
|
| 81 |
+
- [ ] `app/repositories/organization_repository.py` - Implemented
|
| 82 |
+
- [ ] Unit tests written for repositories
|
| 83 |
+
|
| 84 |
+
### Day 3-4: Project & Ticket Repositories
|
| 85 |
+
- [ ] `app/repositories/project_repository.py` - Implemented
|
| 86 |
+
- [ ] `app/repositories/ticket_repository.py` - Implemented
|
| 87 |
+
- [ ] `app/repositories/assignment_repository.py` - Implemented
|
| 88 |
+
- [ ] Complex queries tested (joins, filters)
|
| 89 |
+
|
| 90 |
+
### Day 5-7: Remaining Repositories
|
| 91 |
+
- [ ] All 15 repositories implemented
|
| 92 |
+
- [ ] All repositories have unit tests
|
| 93 |
+
- [ ] Query performance tested
|
| 94 |
+
|
| 95 |
+
---
|
| 96 |
+
|
| 97 |
+
## ✅ Phase 4: Pydantic Schemas (Week 4)
|
| 98 |
+
|
| 99 |
+
### Day 1-3: Core Domain Schemas
|
| 100 |
+
- [ ] `app/schemas/user.py` - All user schemas
|
| 101 |
+
- [ ] `app/schemas/organization.py` - All org schemas
|
| 102 |
+
- [ ] `app/schemas/project.py` - All project schemas
|
| 103 |
+
- [ ] `app/schemas/ticket.py` - All ticket schemas
|
| 104 |
+
- [ ] `app/schemas/assignment.py` - All assignment schemas
|
| 105 |
+
- [ ] Schema validation tested
|
| 106 |
+
|
| 107 |
+
### Day 4-7: Remaining Domain Schemas
|
| 108 |
+
- [ ] All 19 schema files implemented
|
| 109 |
+
- [ ] All schemas have validation rules
|
| 110 |
+
- [ ] Edge cases tested
|
| 111 |
+
|
| 112 |
+
---
|
| 113 |
+
|
| 114 |
+
## ✅ Phase 5-6: Service Layer (Weeks 5-7)
|
| 115 |
+
|
| 116 |
+
### Week 5: User, Organization, Project Services
|
| 117 |
+
- [ ] `app/services/user_service.py` - Complete
|
| 118 |
+
- [ ] `app/services/organization_service.py` - Complete
|
| 119 |
+
- [ ] `app/services/project_service.py` - Complete
|
| 120 |
+
- [ ] Unit tests for all services
|
| 121 |
+
|
| 122 |
+
### Week 6: Ticket & Assignment Services
|
| 123 |
+
- [ ] `app/services/ticket_service.py` - Complete
|
| 124 |
+
- [ ] `app/services/assignment_service.py` - Complete
|
| 125 |
+
- [ ] Ticket workflows tested end-to-end
|
| 126 |
+
|
| 127 |
+
### Week 7: Customer & Sales Services
|
| 128 |
+
- [ ] `app/services/customer_service.py` - Complete
|
| 129 |
+
- [ ] `app/services/sales_order_service.py` - Complete
|
| 130 |
+
- [ ] `app/services/subscription_service.py` - Complete
|
| 131 |
+
- [ ] `app/services/incident_service.py` - Complete
|
| 132 |
+
- [ ] CSV import working
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
## ✅ Phase 7-8: Operations Services (Weeks 8-9)
|
| 137 |
+
|
| 138 |
+
### Week 8: Inventory & Expense Services
|
| 139 |
+
- [ ] `app/services/inventory_service.py` - Complete
|
| 140 |
+
- [ ] `app/services/expense_service.py` - Complete
|
| 141 |
+
- [ ] `app/services/payroll_service.py` - Complete
|
| 142 |
+
- [ ] `app/services/timesheet_service.py` - Complete
|
| 143 |
+
- [ ] Payroll calculations tested
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## ✅ Phase 9-11: API Endpoints (Weeks 9-11)
|
| 148 |
+
|
| 149 |
+
### Week 9: Core Endpoints
|
| 150 |
+
- [ ] `app/api/v1/users.py` - All endpoints
|
| 151 |
+
- [ ] `app/api/v1/organizations.py` - All endpoints
|
| 152 |
+
- [ ] `app/api/v1/projects.py` - All endpoints
|
| 153 |
+
- [ ] `app/api/v1/tickets.py` - All endpoints
|
| 154 |
+
- [ ] `app/api/v1/assignments.py` - All endpoints
|
| 155 |
+
- [ ] Postman collection created
|
| 156 |
+
|
| 157 |
+
### Week 10: Customer & Sales Endpoints
|
| 158 |
+
- [ ] `app/api/v1/customers.py` - All endpoints
|
| 159 |
+
- [ ] `app/api/v1/sales_orders.py` - All endpoints
|
| 160 |
+
- [ ] `app/api/v1/subscriptions.py` - All endpoints
|
| 161 |
+
- [ ] `app/api/v1/incidents.py` - All endpoints
|
| 162 |
+
- [ ] CSV import endpoint working
|
| 163 |
+
|
| 164 |
+
### Week 11: Operations Endpoints
|
| 165 |
+
- [ ] `app/api/v1/inventory.py` - All endpoints
|
| 166 |
+
- [ ] `app/api/v1/expenses.py` - All endpoints
|
| 167 |
+
- [ ] `app/api/v1/payroll.py` - All endpoints
|
| 168 |
+
- [ ] `app/api/v1/timesheets.py` - All endpoints
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## ✅ Phase 12: External Integrations (Week 12)
|
| 173 |
+
|
| 174 |
+
### Day 1-2: Media & Documents
|
| 175 |
+
- [ ] `app/integrations/cloudinary.py` - Image upload working
|
| 176 |
+
- [ ] `app/services/media_service.py` - Complete
|
| 177 |
+
- [ ] `app/services/document_service.py` - Complete
|
| 178 |
+
- [ ] `app/api/v1/media.py` - All endpoints
|
| 179 |
+
- [ ] `app/api/v1/documents.py` - All endpoints
|
| 180 |
+
- [ ] Can upload and retrieve images
|
| 181 |
+
|
| 182 |
+
### Day 3-4: Email & Notifications
|
| 183 |
+
- [ ] `app/integrations/resend.py` - Email sending working
|
| 184 |
+
- [ ] `app/services/notification_service.py` - Complete
|
| 185 |
+
- [ ] Email templates created
|
| 186 |
+
- [ ] Can send emails
|
| 187 |
+
|
| 188 |
+
### Day 5-7: Payment Integration (Skip M-Pesa for now)
|
| 189 |
+
- [ ] Payment service structure ready
|
| 190 |
+
- [ ] Webhook endpoints created
|
| 191 |
+
- [ ] Manual payment tracking working
|
| 192 |
+
|
| 193 |
+
---
|
| 194 |
+
|
| 195 |
+
## ✅ Phase 13: Background Tasks (Week 13)
|
| 196 |
+
|
| 197 |
+
### Day 1-3: Celery Setup
|
| 198 |
+
- [ ] `app/tasks/celery_app.py` - Configured
|
| 199 |
+
- [ ] `app/tasks/notification_tasks.py` - Email tasks working
|
| 200 |
+
- [ ] Celery worker running
|
| 201 |
+
- [ ] Can send async emails
|
| 202 |
+
|
| 203 |
+
### Day 4-7: Scheduled Tasks
|
| 204 |
+
- [ ] `app/tasks/payroll_tasks.py` - Weekly payroll
|
| 205 |
+
- [ ] `app/tasks/sla_tasks.py` - SLA monitoring
|
| 206 |
+
- [ ] `app/tasks/cleanup_tasks.py` - Data cleanup
|
| 207 |
+
- [ ] Celery Beat configured
|
| 208 |
+
- [ ] Scheduled tasks running
|
| 209 |
+
|
| 210 |
+
---
|
| 211 |
+
|
| 212 |
+
## ✅ Phase 14: Reporting & Analytics (Week 14)
|
| 213 |
+
|
| 214 |
+
### Day 1-3: CSV Export
|
| 215 |
+
- [ ] `app/services/csv_export_service.py` - Complete
|
| 216 |
+
- [ ] `app/tasks/export_tasks.py` - Async export
|
| 217 |
+
- [ ] `app/api/v1/reports.py` - Export endpoints
|
| 218 |
+
- [ ] Can export tickets to CSV
|
| 219 |
+
|
| 220 |
+
### Day 4-7: Analytics
|
| 221 |
+
- [ ] `app/services/analytics_service.py` - Complete
|
| 222 |
+
- [ ] `app/api/v1/analytics.py` - All endpoints
|
| 223 |
+
- [ ] Dashboard metrics working
|
| 224 |
+
- [ ] Performance reports working
|
| 225 |
+
|
| 226 |
+
---
|
| 227 |
+
|
| 228 |
+
## ✅ Phase 15: Advanced Features (Week 15)
|
| 229 |
+
|
| 230 |
+
### Day 1-3: OTP & 2FA
|
| 231 |
+
- [ ] `app/services/otp_service.py` - Complete
|
| 232 |
+
- [ ] OTP generation working
|
| 233 |
+
- [ ] OTP verification working
|
| 234 |
+
- [ ] Email OTP delivery working
|
| 235 |
+
|
| 236 |
+
### Day 4-7: Search & Filtering
|
| 237 |
+
- [ ] `app/utils/filters.py` - Filter builders
|
| 238 |
+
- [ ] Full-text search working
|
| 239 |
+
- [ ] Autocomplete endpoints
|
| 240 |
+
- [ ] Advanced filtering tested
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
## ✅ Phase 16: Middleware & Security (Week 16)
|
| 245 |
+
|
| 246 |
+
### Day 1-2: Middleware
|
| 247 |
+
- [ ] `app/middleware/rate_limiting.py` - Implemented
|
| 248 |
+
- [ ] `app/middleware/request_logging.py` - Implemented
|
| 249 |
+
- [ ] All middleware active
|
| 250 |
+
|
| 251 |
+
### Day 3-4: Security
|
| 252 |
+
- [ ] Input validation everywhere
|
| 253 |
+
- [ ] Audit logging working
|
| 254 |
+
- [ ] Data encryption for sensitive fields
|
| 255 |
+
- [ ] Security audit passed
|
| 256 |
+
|
| 257 |
+
### Day 5-7: Monitoring
|
| 258 |
+
- [ ] `app/api/v1/health.py` - Health checks
|
| 259 |
+
- [ ] `app/integrations/sentry.py` - Error tracking
|
| 260 |
+
- [ ] Logging configured
|
| 261 |
+
- [ ] Can monitor system health
|
| 262 |
+
|
| 263 |
+
---
|
| 264 |
+
|
| 265 |
+
## ✅ Phase 17-18: Testing & Quality (Weeks 17-18)
|
| 266 |
+
|
| 267 |
+
### Week 17: Unit & Integration Tests
|
| 268 |
+
- [ ] 80%+ test coverage
|
| 269 |
+
- [ ] All services have unit tests
|
| 270 |
+
- [ ] All endpoints have integration tests
|
| 271 |
+
- [ ] Edge cases covered
|
| 272 |
+
|
| 273 |
+
### Week 18: End-to-End Tests
|
| 274 |
+
- [ ] Complete workflows tested
|
| 275 |
+
- [ ] Payment flows tested
|
| 276 |
+
- [ ] CSV import/export tested
|
| 277 |
+
- [ ] Load testing completed
|
| 278 |
+
- [ ] All bugs fixed
|
| 279 |
+
|
| 280 |
+
---
|
| 281 |
+
|
| 282 |
+
## ✅ Phase 19: Documentation (Week 19)
|
| 283 |
+
|
| 284 |
+
### Day 1-3: API Documentation
|
| 285 |
+
- [ ] OpenAPI/Swagger complete
|
| 286 |
+
- [ ] All endpoints documented
|
| 287 |
+
- [ ] Request/response examples
|
| 288 |
+
- [ ] Authentication guide
|
| 289 |
+
|
| 290 |
+
### Day 4-7: Developer Documentation
|
| 291 |
+
- [ ] Setup guide complete
|
| 292 |
+
- [ ] Architecture documentation
|
| 293 |
+
- [ ] Deployment guide
|
| 294 |
+
- [ ] Troubleshooting guide
|
| 295 |
+
|
| 296 |
+
---
|
| 297 |
+
|
| 298 |
+
## ✅ Phase 20: Deployment (Week 20)
|
| 299 |
+
|
| 300 |
+
### Day 1-3: Docker & CI/CD
|
| 301 |
+
- [ ] Dockerfile optimized
|
| 302 |
+
- [ ] Docker Compose for production
|
| 303 |
+
- [ ] CI/CD pipeline working
|
| 304 |
+
- [ ] Automated testing in CI
|
| 305 |
+
|
| 306 |
+
### Day 4-7: Production Deployment
|
| 307 |
+
- [ ] Deployed to production
|
| 308 |
+
- [ ] Environment variables configured
|
| 309 |
+
- [ ] Monitoring active (Sentry)
|
| 310 |
+
- [ ] Logging configured
|
| 311 |
+
- [ ] Database backups working
|
| 312 |
+
- [ ] SSL certificates installed
|
| 313 |
+
- [ ] Load balancer configured
|
| 314 |
+
- [ ] Production testing complete
|
| 315 |
+
|
| 316 |
+
---
|
| 317 |
+
|
| 318 |
+
## 🎉 Project Complete!
|
| 319 |
+
|
| 320 |
+
- [ ] All features implemented
|
| 321 |
+
- [ ] All tests passing
|
| 322 |
+
- [ ] Documentation complete
|
| 323 |
+
- [ ] Production deployed
|
| 324 |
+
- [ ] Team trained
|
| 325 |
+
- [ ] Handover complete
|
| 326 |
+
|
| 327 |
+
---
|
| 328 |
+
|
| 329 |
+
**Track your progress and celebrate each milestone! 🚀**
|
docs/dev/spec/HUGGINGFACE_DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Deploying SwiftOps Backend to Hugging Face Spaces
|
| 2 |
+
|
| 3 |
+
## 🚀 Quick Deployment Guide
|
| 4 |
+
|
| 5 |
+
### Prerequisites
|
| 6 |
+
- Hugging Face account
|
| 7 |
+
- Supabase account (for PostgreSQL database)
|
| 8 |
+
- Redis instance (Upstash, Redis Cloud, or similar)
|
| 9 |
+
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
## 📋 Step-by-Step Deployment
|
| 13 |
+
|
| 14 |
+
### 1. Create a New Space
|
| 15 |
+
|
| 16 |
+
1. Go to https://huggingface.co/spaces
|
| 17 |
+
2. Click "Create new Space"
|
| 18 |
+
3. Configure:
|
| 19 |
+
- **Name**: `swiftops-backend`
|
| 20 |
+
- **License**: MIT
|
| 21 |
+
- **SDK**: Docker
|
| 22 |
+
- **Hardware**: CPU Basic (or upgrade as needed)
|
| 23 |
+
|
| 24 |
+
### 2. Set Up External Services
|
| 25 |
+
|
| 26 |
+
#### A. Supabase (PostgreSQL Database)
|
| 27 |
+
1. Create project at https://supabase.com
|
| 28 |
+
2. Get connection string from Settings → Database
|
| 29 |
+
3. Format: `postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres`
|
| 30 |
+
|
| 31 |
+
#### B. Redis (Upstash or Redis Cloud)
|
| 32 |
+
1. Create Redis instance at https://upstash.com or https://redis.com
|
| 33 |
+
2. Get connection URL
|
| 34 |
+
3. Format: `redis://default:[PASSWORD]@[HOST]:6379`
|
| 35 |
+
|
| 36 |
+
### 3. Configure Environment Variables
|
| 37 |
+
|
| 38 |
+
In your Hugging Face Space settings, add these secrets:
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
# Required
|
| 42 |
+
DATABASE_URL=postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres
|
| 43 |
+
SUPABASE_URL=https://[PROJECT].supabase.co
|
| 44 |
+
SUPABASE_KEY=[YOUR_ANON_KEY]
|
| 45 |
+
SUPABASE_SERVICE_KEY=[YOUR_SERVICE_KEY]
|
| 46 |
+
SECRET_KEY=[GENERATE_WITH: openssl rand -hex 32]
|
| 47 |
+
REDIS_URL=redis://default:[PASSWORD]@[HOST]:6379
|
| 48 |
+
CELERY_BROKER_URL=redis://default:[PASSWORD]@[HOST]:6379
|
| 49 |
+
CELERY_RESULT_BACKEND=redis://default:[PASSWORD]@[HOST]:6379
|
| 50 |
+
|
| 51 |
+
# Optional (for production features)
|
| 52 |
+
CLOUDINARY_CLOUD_NAME=[YOUR_CLOUD_NAME]
|
| 53 |
+
CLOUDINARY_API_KEY=[YOUR_API_KEY]
|
| 54 |
+
CLOUDINARY_API_SECRET=[YOUR_API_SECRET]
|
| 55 |
+
RESEND_API_KEY=[YOUR_RESEND_KEY]
|
| 56 |
+
GOOGLE_MAPS_API_KEY=[YOUR_GOOGLE_MAPS_KEY]
|
| 57 |
+
SENTRY_DSN=[YOUR_SENTRY_DSN]
|
| 58 |
+
|
| 59 |
+
# Application Settings
|
| 60 |
+
ENVIRONMENT=production
|
| 61 |
+
DEBUG=False
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
### 4. Push Code to Hugging Face
|
| 65 |
+
|
| 66 |
+
#### Option A: Using Git
|
| 67 |
+
|
| 68 |
+
```bash
|
| 69 |
+
# Add Hugging Face remote
|
| 70 |
+
git remote add hf https://huggingface.co/spaces/[YOUR_USERNAME]/swiftops-backend
|
| 71 |
+
|
| 72 |
+
# Push to Hugging Face
|
| 73 |
+
git push hf main
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
#### Option B: Using Hugging Face Hub
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
# Install huggingface_hub
|
| 80 |
+
pip install huggingface_hub
|
| 81 |
+
|
| 82 |
+
# Login
|
| 83 |
+
huggingface-cli login
|
| 84 |
+
|
| 85 |
+
# Upload repository
|
| 86 |
+
huggingface-cli upload [YOUR_USERNAME]/swiftops-backend . --repo-type=space
|
| 87 |
+
```
|
| 88 |
+
|
| 89 |
+
### 5. Verify Deployment
|
| 90 |
+
|
| 91 |
+
1. Wait for Docker build to complete (5-10 minutes)
|
| 92 |
+
2. Check build logs in Space settings
|
| 93 |
+
3. Visit your Space URL: `https://huggingface.co/spaces/[YOUR_USERNAME]/swiftops-backend`
|
| 94 |
+
4. Test endpoints:
|
| 95 |
+
- Health check: `https://[YOUR_SPACE].hf.space/health`
|
| 96 |
+
- API docs: `https://[YOUR_SPACE].hf.space/api/docs`
|
| 97 |
+
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
## 🔧 Important Configuration Changes
|
| 101 |
+
|
| 102 |
+
### 1. Port Configuration
|
| 103 |
+
Hugging Face Spaces uses **port 7860** by default. The Dockerfile has been updated:
|
| 104 |
+
|
| 105 |
+
```dockerfile
|
| 106 |
+
EXPOSE 7860
|
| 107 |
+
CMD uvicorn src.app.main:app --host 0.0.0.0 --port 7860
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
### 2. Database Migrations
|
| 111 |
+
Migrations run automatically on startup:
|
| 112 |
+
|
| 113 |
+
```dockerfile
|
| 114 |
+
CMD alembic upgrade head && uvicorn src.app.main:app --host 0.0.0.0 --port 7860
|
| 115 |
+
```
|
| 116 |
+
|
| 117 |
+
### 3. Files Included in Deployment
|
| 118 |
+
|
| 119 |
+
**Deployed:**
|
| 120 |
+
- ✅ `src/` - Application code
|
| 121 |
+
- ✅ `alembic/` - Database migrations
|
| 122 |
+
- ✅ `alembic.ini` - Migration config
|
| 123 |
+
- ✅ `requirements.txt` - Dependencies
|
| 124 |
+
- ✅ `Dockerfile` - Container definition
|
| 125 |
+
- ✅ `README.md` - Space description
|
| 126 |
+
|
| 127 |
+
**Not Deployed (via .dockerignore):**
|
| 128 |
+
- ❌ `tests/` - Test suite
|
| 129 |
+
- ❌ `scripts/` - Utility scripts
|
| 130 |
+
- ❌ `docs/` - Documentation
|
| 131 |
+
- ❌ `docker-compose.yml` - Local development
|
| 132 |
+
- ❌ `.pre-commit-config.yaml` - Dev tools
|
| 133 |
+
- ❌ `pytest.ini` - Test config
|
| 134 |
+
|
| 135 |
+
---
|
| 136 |
+
|
| 137 |
+
## 🎯 Post-Deployment Tasks
|
| 138 |
+
|
| 139 |
+
### 1. Run Database Migrations
|
| 140 |
+
Migrations run automatically, but you can verify:
|
| 141 |
+
|
| 142 |
+
```bash
|
| 143 |
+
# Check Space logs to confirm migrations ran
|
| 144 |
+
# Look for: "Running upgrade ... -> ..."
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
### 2. Create Admin User
|
| 148 |
+
Use the Space's terminal or API to create first admin user:
|
| 149 |
+
|
| 150 |
+
```bash
|
| 151 |
+
# Via API (once deployed)
|
| 152 |
+
curl -X POST https://[YOUR_SPACE].hf.space/api/v1/auth/register \
|
| 153 |
+
-H "Content-Type: application/json" \
|
| 154 |
+
-d '{
|
| 155 |
+
"email": "admin@swiftops.com",
|
| 156 |
+
"password": "secure_password",
|
| 157 |
+
"name": "Admin User",
|
| 158 |
+
"role": "platform_admin"
|
| 159 |
+
}'
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
### 3. Test API Endpoints
|
| 163 |
+
|
| 164 |
+
```bash
|
| 165 |
+
# Health check
|
| 166 |
+
curl https://[YOUR_SPACE].hf.space/health
|
| 167 |
+
|
| 168 |
+
# API documentation
|
| 169 |
+
open https://[YOUR_SPACE].hf.space/api/docs
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
---
|
| 173 |
+
|
| 174 |
+
## 🔍 Troubleshooting
|
| 175 |
+
|
| 176 |
+
### Build Fails
|
| 177 |
+
|
| 178 |
+
**Check Dockerfile:**
|
| 179 |
+
- Ensure all paths are correct
|
| 180 |
+
- Verify requirements.txt has all dependencies
|
| 181 |
+
- Check for syntax errors
|
| 182 |
+
|
| 183 |
+
**Check Logs:**
|
| 184 |
+
- Go to Space settings → Logs
|
| 185 |
+
- Look for error messages during build
|
| 186 |
+
|
| 187 |
+
### Database Connection Issues
|
| 188 |
+
|
| 189 |
+
**Verify Environment Variables:**
|
| 190 |
+
- Check DATABASE_URL format
|
| 191 |
+
- Ensure Supabase allows connections from Hugging Face IPs
|
| 192 |
+
- Test connection string locally first
|
| 193 |
+
|
| 194 |
+
**Supabase Configuration:**
|
| 195 |
+
- Go to Supabase → Settings → Database
|
| 196 |
+
- Enable "Allow connections from anywhere" (or add HF IPs)
|
| 197 |
+
- Check connection pooling settings
|
| 198 |
+
|
| 199 |
+
### Redis Connection Issues
|
| 200 |
+
|
| 201 |
+
**Verify Redis URL:**
|
| 202 |
+
- Check REDIS_URL format
|
| 203 |
+
- Ensure Redis instance is accessible
|
| 204 |
+
- Test connection with redis-cli
|
| 205 |
+
|
| 206 |
+
### Application Errors
|
| 207 |
+
|
| 208 |
+
**Check Logs:**
|
| 209 |
+
```bash
|
| 210 |
+
# View Space logs in real-time
|
| 211 |
+
# Go to Space → Settings → Logs
|
| 212 |
+
```
|
| 213 |
+
|
| 214 |
+
**Common Issues:**
|
| 215 |
+
- Missing environment variables
|
| 216 |
+
- Database migration failures
|
| 217 |
+
- Redis connection timeout
|
| 218 |
+
- Port conflicts (should be 7860)
|
| 219 |
+
|
| 220 |
+
---
|
| 221 |
+
|
| 222 |
+
## 📊 Monitoring & Maintenance
|
| 223 |
+
|
| 224 |
+
### View Logs
|
| 225 |
+
- Go to Space settings → Logs
|
| 226 |
+
- Monitor for errors and warnings
|
| 227 |
+
|
| 228 |
+
### Update Application
|
| 229 |
+
```bash
|
| 230 |
+
# Make changes locally
|
| 231 |
+
git add .
|
| 232 |
+
git commit -m "Update feature"
|
| 233 |
+
git push hf main
|
| 234 |
+
|
| 235 |
+
# Space will automatically rebuild
|
| 236 |
+
```
|
| 237 |
+
|
| 238 |
+
### Scale Resources
|
| 239 |
+
- Go to Space settings → Hardware
|
| 240 |
+
- Upgrade to CPU/GPU as needed
|
| 241 |
+
- Consider persistent storage for uploads
|
| 242 |
+
|
| 243 |
+
---
|
| 244 |
+
|
| 245 |
+
## 🔒 Security Checklist
|
| 246 |
+
|
| 247 |
+
- [ ] All secrets stored as Space secrets (not in code)
|
| 248 |
+
- [ ] DEBUG=False in production
|
| 249 |
+
- [ ] CORS configured properly
|
| 250 |
+
- [ ] Rate limiting enabled
|
| 251 |
+
- [ ] Database backups configured (Supabase)
|
| 252 |
+
- [ ] Redis password protected
|
| 253 |
+
- [ ] API authentication working
|
| 254 |
+
- [ ] HTTPS enabled (automatic on HF Spaces)
|
| 255 |
+
|
| 256 |
+
---
|
| 257 |
+
|
| 258 |
+
## 📚 Additional Resources
|
| 259 |
+
|
| 260 |
+
- [Hugging Face Spaces Documentation](https://huggingface.co/docs/hub/spaces)
|
| 261 |
+
- [Docker Spaces Guide](https://huggingface.co/docs/hub/spaces-sdks-docker)
|
| 262 |
+
- [Supabase Documentation](https://supabase.com/docs)
|
| 263 |
+
- [Upstash Redis Documentation](https://docs.upstash.com/redis)
|
| 264 |
+
|
| 265 |
+
---
|
| 266 |
+
|
| 267 |
+
## 🎉 Success!
|
| 268 |
+
|
| 269 |
+
Your SwiftOps backend is now deployed on Hugging Face Spaces!
|
| 270 |
+
|
| 271 |
+
**API URL**: `https://[YOUR_USERNAME]-swiftops-backend.hf.space`
|
| 272 |
+
**API Docs**: `https://[YOUR_USERNAME]-swiftops-backend.hf.space/api/docs`
|
| 273 |
+
|
| 274 |
+
---
|
| 275 |
+
|
| 276 |
+
**Need help?** Check the troubleshooting section or open an issue on GitHub.
|
docs/dev/spec/PROJECT_STATUS.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend - Project Status
|
| 2 |
+
|
| 3 |
+
**Date:** November 15, 2025
|
| 4 |
+
**Status:** ✅ **SCAFFOLDED - READY FOR DEVELOPMENT**
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## 🎉 Scaffolding Complete!
|
| 9 |
+
|
| 10 |
+
The complete project structure has been created with all necessary folders, files, and configurations. You can now begin development immediately.
|
| 11 |
+
|
| 12 |
+
## 📊 What's Been Created
|
| 13 |
+
|
| 14 |
+
### ✅ Core Infrastructure (100%)
|
| 15 |
+
- [x] Project folder structure (all directories)
|
| 16 |
+
- [x] FastAPI application entry point (`main.py`)
|
| 17 |
+
- [x] Configuration management (`config.py`)
|
| 18 |
+
- [x] Database session management (`core/database.py`)
|
| 19 |
+
- [x] Authentication utilities (`core/auth.py`)
|
| 20 |
+
- [x] Security utilities (`core/security.py`)
|
| 21 |
+
- [x] RBAC permissions (`core/permissions.py`)
|
| 22 |
+
- [x] Custom exceptions (`core/exceptions.py`)
|
| 23 |
+
- [x] Logging configuration (`core/logging.py`)
|
| 24 |
+
|
| 25 |
+
### ✅ Middleware (100%)
|
| 26 |
+
- [x] Authentication middleware (placeholder)
|
| 27 |
+
- [x] Rate limiting middleware (placeholder)
|
| 28 |
+
- [x] Request logging middleware (placeholder)
|
| 29 |
+
- [x] Error handling middleware (implemented)
|
| 30 |
+
- [x] CORS configuration
|
| 31 |
+
|
| 32 |
+
### ✅ API Layer (100%)
|
| 33 |
+
- [x] API dependencies (`api/deps.py`)
|
| 34 |
+
- [x] Main router (`api/v1/router.py`)
|
| 35 |
+
- [x] All endpoint files created (19 files):
|
| 36 |
+
- auth.py, users.py, organizations.py, projects.py
|
| 37 |
+
- tickets.py, assignments.py, customers.py, sales_orders.py
|
| 38 |
+
- subscriptions.py, incidents.py, inventory.py, expenses.py
|
| 39 |
+
- payroll.py, timesheets.py, documents.py, media.py
|
| 40 |
+
- reports.py, analytics.py, webhooks.py, health.py
|
| 41 |
+
|
| 42 |
+
### ✅ Models (100%)
|
| 43 |
+
- [x] Base model with common fields
|
| 44 |
+
- [x] All ENUM types defined
|
| 45 |
+
- [x] Model files created (12 files):
|
| 46 |
+
- user.py, organization.py, project.py, ticket.py
|
| 47 |
+
- customer.py, incident.py, inventory.py, finance.py
|
| 48 |
+
- timesheet.py, document.py, media.py, audit_log.py
|
| 49 |
+
|
| 50 |
+
### ✅ Repositories (100%)
|
| 51 |
+
- [x] Base repository with CRUD operations
|
| 52 |
+
- [x] Repository files created (15 files)
|
| 53 |
+
|
| 54 |
+
### ✅ Services (100%)
|
| 55 |
+
- [x] Service files created (22 files):
|
| 56 |
+
- auth_service, user_service, organization_service
|
| 57 |
+
- project_service, ticket_service, assignment_service
|
| 58 |
+
- customer_service, sales_order_service, subscription_service
|
| 59 |
+
- incident_service, inventory_service, expense_service
|
| 60 |
+
- payroll_service, timesheet_service, document_service
|
| 61 |
+
- media_service, notification_service, report_service
|
| 62 |
+
- analytics_service, csv_import_service, csv_export_service
|
| 63 |
+
- otp_service
|
| 64 |
+
|
| 65 |
+
### ✅ Schemas (100%)
|
| 66 |
+
- [x] Schema files created (19 files)
|
| 67 |
+
|
| 68 |
+
### ✅ Tasks (100%)
|
| 69 |
+
- [x] Task files created (9 files):
|
| 70 |
+
- celery_app, notification_tasks, payroll_tasks
|
| 71 |
+
- payment_tasks, import_tasks, export_tasks
|
| 72 |
+
- analytics_tasks, sla_tasks, cleanup_tasks
|
| 73 |
+
|
| 74 |
+
### ✅ Integrations (100%)
|
| 75 |
+
- [x] Integration files created (7 files):
|
| 76 |
+
- supabase, cloudinary, mpesa, resend
|
| 77 |
+
- africastalking, google_maps, sentry
|
| 78 |
+
|
| 79 |
+
### ✅ Utilities (100%)
|
| 80 |
+
- [x] Utility files created (12 files):
|
| 81 |
+
- cache, encryption, validators, formatters
|
| 82 |
+
- pagination, filters, date_utils, phone_utils
|
| 83 |
+
- location_utils, file_utils, csv_utils, distributed_lock
|
| 84 |
+
|
| 85 |
+
### ✅ Constants (100%)
|
| 86 |
+
- [x] Constant files created (4 files):
|
| 87 |
+
- roles, permissions, status, messages
|
| 88 |
+
|
| 89 |
+
### ✅ Configuration Files (100%)
|
| 90 |
+
- [x] requirements.txt (production dependencies)
|
| 91 |
+
- [x] requirements-dev.txt (development dependencies)
|
| 92 |
+
- [x] Dockerfile
|
| 93 |
+
- [x] docker-compose.yml
|
| 94 |
+
- [x] alembic.ini
|
| 95 |
+
- [x] pytest.ini
|
| 96 |
+
- [x] .pre-commit-config.yaml
|
| 97 |
+
- [x] README.md
|
| 98 |
+
|
| 99 |
+
### ✅ Testing Infrastructure (100%)
|
| 100 |
+
- [x] Test directory structure
|
| 101 |
+
- [x] pytest configuration (conftest.py)
|
| 102 |
+
- [x] Test fixtures directory
|
| 103 |
+
|
| 104 |
+
### ✅ Scripts (100%)
|
| 105 |
+
- [x] Database seeding script
|
| 106 |
+
- [x] Alembic environment configuration
|
| 107 |
+
|
| 108 |
+
---
|
| 109 |
+
|
| 110 |
+
## 🚀 Next Steps - Start Development!
|
| 111 |
+
|
| 112 |
+
### Phase 1: Foundation (Week 1) - START HERE
|
| 113 |
+
|
| 114 |
+
#### Step 1: Set Up Environment
|
| 115 |
+
```bash
|
| 116 |
+
# Create virtual environment
|
| 117 |
+
python -m venv venv
|
| 118 |
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
| 119 |
+
|
| 120 |
+
# Install dependencies
|
| 121 |
+
pip install -r requirements-dev.txt
|
| 122 |
+
|
| 123 |
+
# Copy environment file
|
| 124 |
+
cp .env.example .env
|
| 125 |
+
# Edit .env with your Supabase credentials
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
#### Step 2: Start Docker Services
|
| 129 |
+
```bash
|
| 130 |
+
# Start PostgreSQL and Redis
|
| 131 |
+
docker-compose up -d db redis
|
| 132 |
+
|
| 133 |
+
# Verify services are running
|
| 134 |
+
docker-compose ps
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
#### Step 3: Initialize Database
|
| 138 |
+
```bash
|
| 139 |
+
# Create initial migration
|
| 140 |
+
alembic revision --autogenerate -m "Initial schema"
|
| 141 |
+
|
| 142 |
+
# Apply migration
|
| 143 |
+
alembic upgrade head
|
| 144 |
+
```
|
| 145 |
+
|
| 146 |
+
#### Step 4: Implement Core Models
|
| 147 |
+
Start with `src/app/models/user.py`:
|
| 148 |
+
- Implement Users table
|
| 149 |
+
- Implement UserFinancialAccounts table
|
| 150 |
+
- Implement UserAssetAssignments table
|
| 151 |
+
- Implement UserPreferences table
|
| 152 |
+
|
| 153 |
+
Reference: `docs/schema/schema.sql` (lines 1-400)
|
| 154 |
+
|
| 155 |
+
#### Step 5: Test Your Setup
|
| 156 |
+
```bash
|
| 157 |
+
# Start the development server
|
| 158 |
+
uvicorn src.app.main:app --reload
|
| 159 |
+
|
| 160 |
+
# Visit http://localhost:8000
|
| 161 |
+
# Visit http://localhost:8000/api/docs (Swagger UI)
|
| 162 |
+
```
|
| 163 |
+
|
| 164 |
+
---
|
| 165 |
+
|
| 166 |
+
## 📋 Development Checklist
|
| 167 |
+
|
| 168 |
+
Follow the build plan in `docs/agent/COMPREHENSIVE_BUILD_PLAN.md`
|
| 169 |
+
|
| 170 |
+
### Week 1: Foundation ⏳
|
| 171 |
+
- [ ] Environment setup
|
| 172 |
+
- [ ] Docker services running
|
| 173 |
+
- [ ] Database migrations working
|
| 174 |
+
- [ ] Core models implemented
|
| 175 |
+
- [ ] Authentication working
|
| 176 |
+
|
| 177 |
+
### Week 2: Core Domain Models ⏳
|
| 178 |
+
- [ ] User & Organization models
|
| 179 |
+
- [ ] Project & Team models
|
| 180 |
+
- [ ] Ticket & Customer models
|
| 181 |
+
- [ ] All migrations created
|
| 182 |
+
|
| 183 |
+
### Week 3: Repository Layer ⏳
|
| 184 |
+
- [ ] Base repository tested
|
| 185 |
+
- [ ] All repositories implemented
|
| 186 |
+
- [ ] Unit tests written
|
| 187 |
+
|
| 188 |
+
### Week 4: Pydantic Schemas ⏳
|
| 189 |
+
- [ ] All schemas defined
|
| 190 |
+
- [ ] Validation tested
|
| 191 |
+
|
| 192 |
+
### Weeks 5-20: Continue with build plan...
|
| 193 |
+
|
| 194 |
+
---
|
| 195 |
+
|
| 196 |
+
## 📚 Key Documentation
|
| 197 |
+
|
| 198 |
+
- **Build Plan**: `docs/agent/COMPREHENSIVE_BUILD_PLAN.md`
|
| 199 |
+
- **Backend Features**: `docs/prod/BACKEND_FEATURES.md`
|
| 200 |
+
- **Database Schema**: `docs/schema/schema.sql`
|
| 201 |
+
- **Credentials Setup**: `docs/prod/CREDENTIALS_SETUP_GUIDE.md`
|
| 202 |
+
|
| 203 |
+
---
|
| 204 |
+
|
| 205 |
+
## 🎯 Success Criteria
|
| 206 |
+
|
| 207 |
+
✅ **Scaffolding Complete** - All files and folders created
|
| 208 |
+
⏳ **Phase 1 Complete** - Core foundation working
|
| 209 |
+
⏳ **Phase 2 Complete** - All models implemented
|
| 210 |
+
⏳ **Phase 3 Complete** - Repositories working
|
| 211 |
+
⏳ **MVP Complete** - Core ticket workflow end-to-end
|
| 212 |
+
⏳ **Production Ready** - All features implemented and tested
|
| 213 |
+
|
| 214 |
+
---
|
| 215 |
+
|
| 216 |
+
## 💡 Tips for Development
|
| 217 |
+
|
| 218 |
+
1. **Follow the build plan** - It's designed for logical progression
|
| 219 |
+
2. **Test as you go** - Write tests alongside implementation
|
| 220 |
+
3. **Use the schema** - Reference `schema.sql` for exact table definitions
|
| 221 |
+
4. **Start simple** - Get core workflows working before adding complexity
|
| 222 |
+
5. **Commit often** - Small, focused commits are easier to review
|
| 223 |
+
|
| 224 |
+
---
|
| 225 |
+
|
| 226 |
+
## 🆘 Need Help?
|
| 227 |
+
|
| 228 |
+
- Check the build plan for detailed implementation patterns
|
| 229 |
+
- Reference the backend features document for requirements
|
| 230 |
+
- Look at the schema for exact database structure
|
| 231 |
+
- Review existing placeholder files for structure
|
| 232 |
+
|
| 233 |
+
---
|
| 234 |
+
|
| 235 |
+
**Ready to build something amazing! 🚀**
|
| 236 |
+
|
| 237 |
+
Start with Phase 1, Day 1-2: Project Setup and Core Components.
|
docs/dev/spec/PROJECT_STRUCTURE.txt
ADDED
|
Binary file (16 kB). View file
|
|
|
docs/dev/spec/QUICKSTART.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend - Quick Start Guide
|
| 2 |
+
|
| 3 |
+
Get up and running in 5 minutes!
|
| 4 |
+
|
| 5 |
+
## 🚀 Quick Setup
|
| 6 |
+
|
| 7 |
+
### 1. Install Dependencies
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
# Create and activate virtual environment
|
| 11 |
+
python -m venv venv
|
| 12 |
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
| 13 |
+
|
| 14 |
+
# Install packages
|
| 15 |
+
pip install -r requirements-dev.txt
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
### 2. Configure Environment
|
| 19 |
+
|
| 20 |
+
```bash
|
| 21 |
+
# Copy environment template
|
| 22 |
+
cp .env.example .env
|
| 23 |
+
|
| 24 |
+
# Edit .env and add your credentials:
|
| 25 |
+
# - DATABASE_URL (Supabase PostgreSQL URL)
|
| 26 |
+
# - SUPABASE_URL
|
| 27 |
+
# - SUPABASE_KEY
|
| 28 |
+
# - SECRET_KEY (generate with: openssl rand -hex 32)
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
### 3. Start Services
|
| 32 |
+
|
| 33 |
+
```bash
|
| 34 |
+
# Option A: Use Docker (Recommended)
|
| 35 |
+
docker-compose up -d
|
| 36 |
+
|
| 37 |
+
# Option B: Local PostgreSQL and Redis
|
| 38 |
+
# Make sure PostgreSQL and Redis are running locally
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
### 4. Initialize Database
|
| 42 |
+
|
| 43 |
+
```bash
|
| 44 |
+
# Create initial migration
|
| 45 |
+
alembic revision --autogenerate -m "Initial schema"
|
| 46 |
+
|
| 47 |
+
# Apply migrations
|
| 48 |
+
alembic upgrade head
|
| 49 |
+
|
| 50 |
+
# (Optional) Seed database with test data
|
| 51 |
+
python scripts/seed_database.py
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
### 5. Run the Application
|
| 55 |
+
|
| 56 |
+
```bash
|
| 57 |
+
# Start development server
|
| 58 |
+
uvicorn src.app.main:app --reload
|
| 59 |
+
|
| 60 |
+
# Server will start at http://localhost:8000
|
| 61 |
+
# API docs at http://localhost:8000/api/docs
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
## ✅ Verify Installation
|
| 65 |
+
|
| 66 |
+
Visit these URLs to confirm everything works:
|
| 67 |
+
|
| 68 |
+
- **API Root**: http://localhost:8000
|
| 69 |
+
- **Health Check**: http://localhost:8000/health
|
| 70 |
+
- **API Documentation**: http://localhost:8000/api/docs
|
| 71 |
+
- **ReDoc**: http://localhost:8000/api/redoc
|
| 72 |
+
|
| 73 |
+
## 🧪 Run Tests
|
| 74 |
+
|
| 75 |
+
```bash
|
| 76 |
+
# Run all tests
|
| 77 |
+
pytest
|
| 78 |
+
|
| 79 |
+
# Run with coverage
|
| 80 |
+
pytest --cov=src/app
|
| 81 |
+
|
| 82 |
+
# Run specific test
|
| 83 |
+
pytest tests/unit/services/test_auth_service.py
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
## 🔧 Development Tools
|
| 87 |
+
|
| 88 |
+
```bash
|
| 89 |
+
# Format code
|
| 90 |
+
black src/ tests/
|
| 91 |
+
|
| 92 |
+
# Sort imports
|
| 93 |
+
isort src/ tests/
|
| 94 |
+
|
| 95 |
+
# Lint code
|
| 96 |
+
flake8 src/ tests/
|
| 97 |
+
|
| 98 |
+
# Type checking
|
| 99 |
+
mypy src/
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
## 📦 Docker Commands
|
| 103 |
+
|
| 104 |
+
```bash
|
| 105 |
+
# Start all services
|
| 106 |
+
docker-compose up -d
|
| 107 |
+
|
| 108 |
+
# View logs
|
| 109 |
+
docker-compose logs -f api
|
| 110 |
+
|
| 111 |
+
# Stop services
|
| 112 |
+
docker-compose down
|
| 113 |
+
|
| 114 |
+
# Rebuild after code changes
|
| 115 |
+
docker-compose up -d --build
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
## 🎯 Next Steps
|
| 119 |
+
|
| 120 |
+
1. **Read the Build Plan**: `docs/agent/COMPREHENSIVE_BUILD_PLAN.md`
|
| 121 |
+
2. **Check Project Status**: `PROJECT_STATUS.md`
|
| 122 |
+
3. **Start with Phase 1**: Implement core models
|
| 123 |
+
4. **Follow the checklist**: Week-by-week implementation
|
| 124 |
+
|
| 125 |
+
## 🆘 Troubleshooting
|
| 126 |
+
|
| 127 |
+
### Database Connection Error
|
| 128 |
+
```bash
|
| 129 |
+
# Check if PostgreSQL is running
|
| 130 |
+
docker-compose ps
|
| 131 |
+
|
| 132 |
+
# Check DATABASE_URL in .env
|
| 133 |
+
# Format: postgresql://user:password@host:port/database
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
### Import Errors
|
| 137 |
+
```bash
|
| 138 |
+
# Make sure you're in the virtual environment
|
| 139 |
+
source venv/bin/activate
|
| 140 |
+
|
| 141 |
+
# Reinstall dependencies
|
| 142 |
+
pip install -r requirements-dev.txt
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
### Alembic Migration Issues
|
| 146 |
+
```bash
|
| 147 |
+
# Reset migrations (CAUTION: Deletes all data)
|
| 148 |
+
alembic downgrade base
|
| 149 |
+
alembic upgrade head
|
| 150 |
+
|
| 151 |
+
# Or drop and recreate database
|
| 152 |
+
docker-compose down -v
|
| 153 |
+
docker-compose up -d
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
## 📚 Useful Commands
|
| 157 |
+
|
| 158 |
+
```bash
|
| 159 |
+
# Create new migration
|
| 160 |
+
alembic revision --autogenerate -m "Add new table"
|
| 161 |
+
|
| 162 |
+
# Apply migrations
|
| 163 |
+
alembic upgrade head
|
| 164 |
+
|
| 165 |
+
# Rollback one migration
|
| 166 |
+
alembic downgrade -1
|
| 167 |
+
|
| 168 |
+
# Start Celery worker
|
| 169 |
+
celery -A src.app.tasks.celery_app worker --loglevel=info
|
| 170 |
+
|
| 171 |
+
# Start Celery beat
|
| 172 |
+
celery -A src.app.tasks.celery_app beat --loglevel=info
|
| 173 |
+
|
| 174 |
+
# Monitor Celery with Flower
|
| 175 |
+
celery -A src.app.tasks.celery_app flower
|
| 176 |
+
```
|
| 177 |
+
|
| 178 |
+
## 🎉 You're Ready!
|
| 179 |
+
|
| 180 |
+
The project is fully scaffolded and ready for development. Start building! 🚀
|
docs/dev/spec/SCAFFOLDING_COMPLETE.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🎉 SwiftOps Backend - Scaffolding Complete!
|
| 2 |
+
|
| 3 |
+
**Date:** November 15, 2025
|
| 4 |
+
**Status:** ✅ **READY FOR DEVELOPMENT**
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## 📊 What We've Built
|
| 9 |
+
|
| 10 |
+
### Complete Project Structure
|
| 11 |
+
- **200+ files created**
|
| 12 |
+
- **18 directories** organized by domain
|
| 13 |
+
- **All placeholder files** with TODO comments
|
| 14 |
+
- **Production-ready configuration**
|
| 15 |
+
|
| 16 |
+
### Key Components Created
|
| 17 |
+
|
| 18 |
+
#### 1. Core Infrastructure ✅
|
| 19 |
+
```
|
| 20 |
+
src/app/core/
|
| 21 |
+
├── auth.py # JWT token management
|
| 22 |
+
├── security.py # Password hashing
|
| 23 |
+
├── permissions.py # RBAC definitions
|
| 24 |
+
├── exceptions.py # Custom exceptions
|
| 25 |
+
├── logging.py # Structured logging
|
| 26 |
+
└── database.py # Database sessions
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
#### 2. API Layer ✅
|
| 30 |
+
```
|
| 31 |
+
src/app/api/v1/
|
| 32 |
+
├── auth.py # Authentication endpoints
|
| 33 |
+
├── users.py # User management
|
| 34 |
+
├── projects.py # Project CRUD
|
| 35 |
+
├── tickets.py # Ticket operations
|
| 36 |
+
├── ... (19 endpoint files total)
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
#### 3. Business Logic ✅
|
| 40 |
+
```
|
| 41 |
+
src/app/services/
|
| 42 |
+
├── auth_service.py
|
| 43 |
+
├── ticket_service.py
|
| 44 |
+
├── payroll_service.py
|
| 45 |
+
├── ... (22 service files total)
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
#### 4. Data Access ✅
|
| 49 |
+
```
|
| 50 |
+
src/app/repositories/
|
| 51 |
+
├── base_repository.py # Generic CRUD
|
| 52 |
+
├── ticket_repository.py
|
| 53 |
+
├── ... (15 repository files total)
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
#### 5. Database Models ✅
|
| 57 |
+
```
|
| 58 |
+
src/app/models/
|
| 59 |
+
├── base.py # Base model with common fields
|
| 60 |
+
├── enums.py # All ENUM types
|
| 61 |
+
├── user.py, project.py, ticket.py
|
| 62 |
+
├── ... (12 model files total)
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
#### 6. Request/Response Schemas ✅
|
| 66 |
+
```
|
| 67 |
+
src/app/schemas/
|
| 68 |
+
├── base.py, common.py
|
| 69 |
+
├── ticket.py, user.py
|
| 70 |
+
├── ... (19 schema files total)
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
#### 7. Background Tasks ✅
|
| 74 |
+
```
|
| 75 |
+
src/app/tasks/
|
| 76 |
+
├── celery_app.py # Celery configuration
|
| 77 |
+
├── payroll_tasks.py # Weekly payroll
|
| 78 |
+
├── sla_tasks.py # SLA monitoring
|
| 79 |
+
├── ... (9 task files total)
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
#### 8. External Integrations ✅
|
| 83 |
+
```
|
| 84 |
+
src/app/integrations/
|
| 85 |
+
├── supabase.py # Supabase client
|
| 86 |
+
├── cloudinary.py # Image uploads
|
| 87 |
+
├── mpesa.py # Payment gateway
|
| 88 |
+
├── resend.py # Email service
|
| 89 |
+
├── ... (7 integration files total)
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
#### 9. Utilities ✅
|
| 93 |
+
```
|
| 94 |
+
src/app/utils/
|
| 95 |
+
├── cache.py # Redis caching
|
| 96 |
+
├── validators.py # Input validation
|
| 97 |
+
├── pagination.py # Pagination helpers
|
| 98 |
+
├── ... (12 utility files total)
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
#### 10. Configuration Files ✅
|
| 102 |
+
```
|
| 103 |
+
Root Directory:
|
| 104 |
+
├── requirements.txt # Production dependencies
|
| 105 |
+
├── Dockerfile # Docker image
|
| 106 |
+
├── docker-compose.yml # Multi-container setup
|
| 107 |
+
├── alembic.ini # Database migrations
|
| 108 |
+
├── pytest.ini # Test configuration
|
| 109 |
+
├── .pre-commit-config # Code quality hooks
|
| 110 |
+
└── README.md # Project documentation
|
| 111 |
+
```
|
| 112 |
+
|
| 113 |
+
---
|
| 114 |
+
|
| 115 |
+
## 🎯 Project Statistics
|
| 116 |
+
|
| 117 |
+
| Category | Count | Status |
|
| 118 |
+
|----------|-------|--------|
|
| 119 |
+
| **Total Files** | 200+ | ✅ Created |
|
| 120 |
+
| **Directories** | 18 | ✅ Created |
|
| 121 |
+
| **API Endpoints** | 19 | ✅ Scaffolded |
|
| 122 |
+
| **Services** | 22 | ✅ Scaffolded |
|
| 123 |
+
| **Repositories** | 15 | ✅ Scaffolded |
|
| 124 |
+
| **Models** | 12 | ✅ Scaffolded |
|
| 125 |
+
| **Schemas** | 19 | ✅ Scaffolded |
|
| 126 |
+
| **Tasks** | 9 | ✅ Scaffolded |
|
| 127 |
+
| **Integrations** | 7 | ✅ Scaffolded |
|
| 128 |
+
| **Utilities** | 12 | ✅ Scaffolded |
|
| 129 |
+
|
| 130 |
+
---
|
| 131 |
+
|
| 132 |
+
## 🚀 What's Implemented vs. What's Scaffolded
|
| 133 |
+
|
| 134 |
+
### ✅ Fully Implemented (Ready to Use)
|
| 135 |
+
- FastAPI application entry point
|
| 136 |
+
- Configuration management (Pydantic Settings)
|
| 137 |
+
- Database session management
|
| 138 |
+
- JWT token creation and verification
|
| 139 |
+
- Password hashing (bcrypt)
|
| 140 |
+
- RBAC permission system
|
| 141 |
+
- Custom exception classes
|
| 142 |
+
- Error handling middleware
|
| 143 |
+
- Base repository with CRUD operations
|
| 144 |
+
- Base model with soft delete
|
| 145 |
+
- All ENUM types
|
| 146 |
+
- API dependencies (auth, database)
|
| 147 |
+
- Docker Compose setup
|
| 148 |
+
- Alembic configuration
|
| 149 |
+
- Pytest configuration
|
| 150 |
+
|
| 151 |
+
### 📝 Scaffolded (TODO Comments)
|
| 152 |
+
- All API endpoint implementations
|
| 153 |
+
- All service business logic
|
| 154 |
+
- All repository queries
|
| 155 |
+
- All database models
|
| 156 |
+
- All Pydantic schemas
|
| 157 |
+
- All background tasks
|
| 158 |
+
- All external integrations
|
| 159 |
+
- All utility functions
|
| 160 |
+
|
| 161 |
+
---
|
| 162 |
+
|
| 163 |
+
## 📚 Documentation Created
|
| 164 |
+
|
| 165 |
+
1. **README.md** - Project overview and setup instructions
|
| 166 |
+
2. **QUICKSTART.md** - 5-minute setup guide
|
| 167 |
+
3. **PROJECT_STATUS.md** - Detailed status and checklist
|
| 168 |
+
4. **SCAFFOLDING_COMPLETE.md** - This file!
|
| 169 |
+
|
| 170 |
+
Existing Documentation:
|
| 171 |
+
- **COMPREHENSIVE_BUILD_PLAN.md** - 20-week implementation plan
|
| 172 |
+
- **BACKEND_FEATURES.md** - Complete feature specifications
|
| 173 |
+
- **schema.sql** - Database schema with workflows
|
| 174 |
+
|
| 175 |
+
---
|
| 176 |
+
|
| 177 |
+
## 🎓 How to Use This Scaffolding
|
| 178 |
+
|
| 179 |
+
### Step 1: Set Up Environment
|
| 180 |
+
```bash
|
| 181 |
+
python -m venv venv
|
| 182 |
+
source venv/bin/activate
|
| 183 |
+
pip install -r requirements-dev.txt
|
| 184 |
+
cp .env.example .env
|
| 185 |
+
# Edit .env with your credentials
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
### Step 2: Start Services
|
| 189 |
+
```bash
|
| 190 |
+
docker-compose up -d
|
| 191 |
+
```
|
| 192 |
+
|
| 193 |
+
### Step 3: Initialize Database
|
| 194 |
+
```bash
|
| 195 |
+
alembic revision --autogenerate -m "Initial schema"
|
| 196 |
+
alembic upgrade head
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
### Step 4: Start Development
|
| 200 |
+
```bash
|
| 201 |
+
uvicorn src.app.main:app --reload
|
| 202 |
+
```
|
| 203 |
+
|
| 204 |
+
### Step 5: Follow the Build Plan
|
| 205 |
+
Open `docs/agent/COMPREHENSIVE_BUILD_PLAN.md` and start with **Phase 1: Foundation (Week 1)**
|
| 206 |
+
|
| 207 |
+
---
|
| 208 |
+
|
| 209 |
+
## 🔍 Finding Your Way Around
|
| 210 |
+
|
| 211 |
+
### Need to implement a feature?
|
| 212 |
+
1. **Check the build plan** for the implementation order
|
| 213 |
+
2. **Find the TODO file** in the appropriate directory
|
| 214 |
+
3. **Reference the schema** (`docs/schema/schema.sql`) for database structure
|
| 215 |
+
4. **Check backend features** (`docs/prod/BACKEND_FEATURES.md`) for requirements
|
| 216 |
+
|
| 217 |
+
### Example: Implementing Ticket Creation
|
| 218 |
+
|
| 219 |
+
1. **Model**: `src/app/models/ticket.py` - Define Ticket table
|
| 220 |
+
2. **Schema**: `src/app/schemas/ticket.py` - Define TicketCreate, TicketResponse
|
| 221 |
+
3. **Repository**: `src/app/repositories/ticket_repository.py` - Add create_ticket()
|
| 222 |
+
4. **Service**: `src/app/services/ticket_service.py` - Add business logic
|
| 223 |
+
5. **API**: `src/app/api/v1/tickets.py` - Add POST /tickets endpoint
|
| 224 |
+
6. **Test**: `tests/unit/services/test_ticket_service.py` - Write tests
|
| 225 |
+
|
| 226 |
+
---
|
| 227 |
+
|
| 228 |
+
## 🎯 Next Immediate Steps
|
| 229 |
+
|
| 230 |
+
### Today (Day 1)
|
| 231 |
+
1. ✅ Scaffolding complete
|
| 232 |
+
2. ⏳ Set up your development environment
|
| 233 |
+
3. ⏳ Start Docker services
|
| 234 |
+
4. ⏳ Create first database migration
|
| 235 |
+
|
| 236 |
+
### This Week (Week 1)
|
| 237 |
+
1. ⏳ Implement User model
|
| 238 |
+
2. ⏳ Implement Organization model
|
| 239 |
+
3. ⏳ Implement authentication endpoints
|
| 240 |
+
4. ⏳ Write first tests
|
| 241 |
+
|
| 242 |
+
### This Month (Weeks 1-4)
|
| 243 |
+
1. ⏳ Complete all database models
|
| 244 |
+
2. ⏳ Implement all repositories
|
| 245 |
+
3. ⏳ Define all Pydantic schemas
|
| 246 |
+
4. ⏳ Set up CI/CD pipeline
|
| 247 |
+
|
| 248 |
+
---
|
| 249 |
+
|
| 250 |
+
## 💡 Pro Tips
|
| 251 |
+
|
| 252 |
+
1. **Start Small**: Get one complete workflow working end-to-end before adding complexity
|
| 253 |
+
2. **Test Early**: Write tests as you implement features (TDD approach)
|
| 254 |
+
3. **Use the Schema**: The `schema.sql` file is your source of truth for database structure
|
| 255 |
+
4. **Follow Patterns**: The base repository and service patterns are your templates
|
| 256 |
+
5. **Commit Often**: Small, focused commits make debugging easier
|
| 257 |
+
|
| 258 |
+
---
|
| 259 |
+
|
| 260 |
+
## 🆘 Need Help?
|
| 261 |
+
|
| 262 |
+
### Documentation
|
| 263 |
+
- **Build Plan**: `docs/agent/COMPREHENSIVE_BUILD_PLAN.md`
|
| 264 |
+
- **Backend Features**: `docs/prod/BACKEND_FEATURES.md`
|
| 265 |
+
- **Database Schema**: `docs/schema/schema.sql`
|
| 266 |
+
- **Quick Start**: `QUICKSTART.md`
|
| 267 |
+
|
| 268 |
+
### Common Issues
|
| 269 |
+
- **Import errors**: Make sure virtual environment is activated
|
| 270 |
+
- **Database errors**: Check DATABASE_URL in .env
|
| 271 |
+
- **Docker issues**: Run `docker-compose down -v` and restart
|
| 272 |
+
|
| 273 |
+
---
|
| 274 |
+
|
| 275 |
+
## 🎉 Congratulations!
|
| 276 |
+
|
| 277 |
+
You now have a **production-ready project structure** with:
|
| 278 |
+
- ✅ Clean architecture (API → Service → Repository → Model)
|
| 279 |
+
- ✅ Proper separation of concerns
|
| 280 |
+
- ✅ Scalable folder structure
|
| 281 |
+
- ✅ All necessary configuration files
|
| 282 |
+
- ✅ Testing infrastructure
|
| 283 |
+
- ✅ Docker support
|
| 284 |
+
- ✅ Comprehensive documentation
|
| 285 |
+
|
| 286 |
+
**Everything is in place. Now it's time to build! 🚀**
|
| 287 |
+
|
| 288 |
+
---
|
| 289 |
+
|
| 290 |
+
**Happy Coding!** 💻
|
| 291 |
+
|
| 292 |
+
Start with Phase 1 of the build plan and work your way through systematically.
|
docs/dev/spec/START_HERE.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚀 START HERE - SwiftOps Backend
|
| 2 |
+
|
| 3 |
+
## Welcome! Your Project is Ready 🎉
|
| 4 |
+
|
| 5 |
+
The complete SwiftOps backend has been **scaffolded and is ready for development**.
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## 📖 Quick Navigation
|
| 10 |
+
|
| 11 |
+
### 🏃 Want to Start Immediately?
|
| 12 |
+
**Read:** [`QUICKSTART.md`](QUICKSTART.md) - Get running in 5 minutes
|
| 13 |
+
|
| 14 |
+
### 📊 Want to See What's Built?
|
| 15 |
+
**Read:** [`SCAFFOLDING_COMPLETE.md`](SCAFFOLDING_COMPLETE.md) - Complete overview
|
| 16 |
+
|
| 17 |
+
### ✅ Want to Track Progress?
|
| 18 |
+
**Read:** [`DEVELOPMENT_CHECKLIST.md`](DEVELOPMENT_CHECKLIST.md) - Week-by-week checklist
|
| 19 |
+
|
| 20 |
+
### 📋 Want the Full Plan?
|
| 21 |
+
**Read:** [`docs/agent/COMPREHENSIVE_BUILD_PLAN.md`](docs/agent/COMPREHENSIVE_BUILD_PLAN.md) - 20-week implementation plan
|
| 22 |
+
|
| 23 |
+
### 🔍 Want to Understand the System?
|
| 24 |
+
**Read:** [`docs/prod/BACKEND_FEATURES.md`](docs/prod/BACKEND_FEATURES.md) - All features explained
|
| 25 |
+
|
| 26 |
+
### 🗄️ Want to See the Database?
|
| 27 |
+
**Read:** [`docs/schema/schema.sql`](docs/schema/schema.sql) - Complete database schema
|
| 28 |
+
|
| 29 |
+
---
|
| 30 |
+
|
| 31 |
+
## 🎯 What You Have
|
| 32 |
+
|
| 33 |
+
### ✅ Complete Project Structure
|
| 34 |
+
- 200+ files created
|
| 35 |
+
- 18 organized directories
|
| 36 |
+
- Production-ready configuration
|
| 37 |
+
- All placeholder files with TODO comments
|
| 38 |
+
|
| 39 |
+
### ✅ Core Infrastructure
|
| 40 |
+
- FastAPI application setup
|
| 41 |
+
- Database session management
|
| 42 |
+
- JWT authentication
|
| 43 |
+
- RBAC permissions
|
| 44 |
+
- Error handling
|
| 45 |
+
- Logging configuration
|
| 46 |
+
|
| 47 |
+
### ✅ Development Tools
|
| 48 |
+
- Docker Compose setup
|
| 49 |
+
- Alembic migrations
|
| 50 |
+
- Pytest configuration
|
| 51 |
+
- Pre-commit hooks
|
| 52 |
+
- Code quality tools
|
| 53 |
+
|
| 54 |
+
### ✅ Documentation
|
| 55 |
+
- Quick start guide
|
| 56 |
+
- Build plan (20 weeks)
|
| 57 |
+
- Feature specifications
|
| 58 |
+
- Database schema
|
| 59 |
+
- Development checklist
|
| 60 |
+
|
| 61 |
+
---
|
| 62 |
+
|
| 63 |
+
## 🚀 Get Started in 3 Steps
|
| 64 |
+
|
| 65 |
+
### Step 1: Set Up Environment (5 minutes)
|
| 66 |
+
```bash
|
| 67 |
+
# Create virtual environment
|
| 68 |
+
python -m venv venv
|
| 69 |
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
| 70 |
+
|
| 71 |
+
# Install dependencies
|
| 72 |
+
pip install -r requirements-dev.txt
|
| 73 |
+
|
| 74 |
+
# Configure environment
|
| 75 |
+
cp .env.example .env
|
| 76 |
+
# Edit .env with your Supabase credentials
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
### Step 2: Start Services (2 minutes)
|
| 80 |
+
```bash
|
| 81 |
+
# Start PostgreSQL and Redis
|
| 82 |
+
docker-compose up -d
|
| 83 |
+
|
| 84 |
+
# Verify services
|
| 85 |
+
docker-compose ps
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
### Step 3: Run the Application (1 minute)
|
| 89 |
+
```bash
|
| 90 |
+
# Start development server
|
| 91 |
+
uvicorn src.app.main:app --reload
|
| 92 |
+
|
| 93 |
+
# Visit http://localhost:8000
|
| 94 |
+
# API docs at http://localhost:8000/api/docs
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
---
|
| 98 |
+
|
| 99 |
+
## 📚 Key Files to Know
|
| 100 |
+
|
| 101 |
+
| File | Purpose |
|
| 102 |
+
|------|---------|
|
| 103 |
+
| `src/app/main.py` | FastAPI application entry point |
|
| 104 |
+
| `src/app/config.py` | Configuration management |
|
| 105 |
+
| `src/app/core/database.py` | Database sessions |
|
| 106 |
+
| `src/app/core/auth.py` | JWT authentication |
|
| 107 |
+
| `src/app/models/base.py` | Base model for all tables |
|
| 108 |
+
| `src/app/repositories/base_repository.py` | Base CRUD operations |
|
| 109 |
+
| `docker-compose.yml` | Docker services configuration |
|
| 110 |
+
| `alembic.ini` | Database migration configuration |
|
| 111 |
+
| `requirements.txt` | Python dependencies |
|
| 112 |
+
|
| 113 |
+
---
|
| 114 |
+
|
| 115 |
+
## 🎓 Development Workflow
|
| 116 |
+
|
| 117 |
+
### 1. Implement a Feature
|
| 118 |
+
```
|
| 119 |
+
Model → Schema → Repository → Service → API → Test
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
### 2. Example: Add Ticket Creation
|
| 123 |
+
1. **Model**: Define Ticket table in `src/app/models/ticket.py`
|
| 124 |
+
2. **Schema**: Define TicketCreate in `src/app/schemas/ticket.py`
|
| 125 |
+
3. **Repository**: Add create() in `src/app/repositories/ticket_repository.py`
|
| 126 |
+
4. **Service**: Add business logic in `src/app/services/ticket_service.py`
|
| 127 |
+
5. **API**: Add POST endpoint in `src/app/api/v1/tickets.py`
|
| 128 |
+
6. **Test**: Write tests in `tests/unit/services/test_ticket_service.py`
|
| 129 |
+
|
| 130 |
+
### 3. Create Database Migration
|
| 131 |
+
```bash
|
| 132 |
+
alembic revision --autogenerate -m "Add tickets table"
|
| 133 |
+
alembic upgrade head
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
### 4. Run Tests
|
| 137 |
+
```bash
|
| 138 |
+
pytest
|
| 139 |
+
pytest --cov=src/app
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
---
|
| 143 |
+
|
| 144 |
+
## 🗺️ Project Structure Overview
|
| 145 |
+
|
| 146 |
+
```
|
| 147 |
+
swiftops-backend/
|
| 148 |
+
├── src/app/ # Application code
|
| 149 |
+
│ ├── api/ # API endpoints (19 files)
|
| 150 |
+
│ ├── core/ # Core utilities (7 files)
|
| 151 |
+
│ ├── models/ # Database models (12 files)
|
| 152 |
+
│ ├── schemas/ # Request/response schemas (19 files)
|
| 153 |
+
│ ├── services/ # Business logic (22 files)
|
| 154 |
+
│ ├── repositories/ # Data access (15 files)
|
| 155 |
+
│ ├── tasks/ # Background tasks (9 files)
|
| 156 |
+
│ ├── integrations/ # External services (7 files)
|
| 157 |
+
│ ├── utils/ # Utilities (12 files)
|
| 158 |
+
│ └── constants/ # Constants (4 files)
|
| 159 |
+
├── tests/ # Test suite
|
| 160 |
+
├── alembic/ # Database migrations
|
| 161 |
+
├── docs/ # Documentation
|
| 162 |
+
└── scripts/ # Utility scripts
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
---
|
| 166 |
+
|
| 167 |
+
## 💡 Pro Tips
|
| 168 |
+
|
| 169 |
+
1. **Follow the Build Plan**: It's designed for logical progression
|
| 170 |
+
2. **Start with Models**: Get the database structure right first
|
| 171 |
+
3. **Test as You Go**: Write tests alongside implementation
|
| 172 |
+
4. **Use the Schema**: Reference `schema.sql` for exact table definitions
|
| 173 |
+
5. **Commit Often**: Small, focused commits are easier to review
|
| 174 |
+
|
| 175 |
+
---
|
| 176 |
+
|
| 177 |
+
## 🆘 Need Help?
|
| 178 |
+
|
| 179 |
+
### Common Issues
|
| 180 |
+
|
| 181 |
+
**Import Errors**
|
| 182 |
+
```bash
|
| 183 |
+
# Make sure virtual environment is activated
|
| 184 |
+
source venv/bin/activate
|
| 185 |
+
pip install -r requirements-dev.txt
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
**Database Connection Error**
|
| 189 |
+
```bash
|
| 190 |
+
# Check if PostgreSQL is running
|
| 191 |
+
docker-compose ps
|
| 192 |
+
|
| 193 |
+
# Check DATABASE_URL in .env
|
| 194 |
+
```
|
| 195 |
+
|
| 196 |
+
**Alembic Migration Issues**
|
| 197 |
+
```bash
|
| 198 |
+
# Reset migrations (CAUTION: Deletes data)
|
| 199 |
+
alembic downgrade base
|
| 200 |
+
alembic upgrade head
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
### Documentation
|
| 204 |
+
- **Quick Start**: `QUICKSTART.md`
|
| 205 |
+
- **Project Status**: `PROJECT_STATUS.md`
|
| 206 |
+
- **Build Plan**: `docs/agent/COMPREHENSIVE_BUILD_PLAN.md`
|
| 207 |
+
- **Features**: `docs/prod/BACKEND_FEATURES.md`
|
| 208 |
+
- **Schema**: `docs/schema/schema.sql`
|
| 209 |
+
|
| 210 |
+
---
|
| 211 |
+
|
| 212 |
+
## 🎯 Your First Task
|
| 213 |
+
|
| 214 |
+
**Implement the User Model** (Phase 1, Day 3-4)
|
| 215 |
+
|
| 216 |
+
1. Open `src/app/models/user.py`
|
| 217 |
+
2. Reference `docs/schema/schema.sql` (lines 1-400)
|
| 218 |
+
3. Implement:
|
| 219 |
+
- Users table
|
| 220 |
+
- UserFinancialAccounts table
|
| 221 |
+
- UserAssetAssignments table
|
| 222 |
+
- UserPreferences table
|
| 223 |
+
4. Create migration: `alembic revision --autogenerate -m "Add user tables"`
|
| 224 |
+
5. Apply migration: `alembic upgrade head`
|
| 225 |
+
6. Test: Create a user in the database
|
| 226 |
+
|
| 227 |
+
---
|
| 228 |
+
|
| 229 |
+
## 🎉 You're All Set!
|
| 230 |
+
|
| 231 |
+
Everything is in place. The project is scaffolded, documented, and ready for development.
|
| 232 |
+
|
| 233 |
+
**Now go build something amazing! 🚀**
|
| 234 |
+
|
| 235 |
+
---
|
| 236 |
+
|
| 237 |
+
**Questions?** Check the documentation files listed above.
|
| 238 |
+
|
| 239 |
+
**Ready to code?** Start with `QUICKSTART.md` and then follow the `COMPREHENSIVE_BUILD_PLAN.md`.
|
| 240 |
+
|
| 241 |
+
**Happy coding!** 💻
|
docs/huggingface/examples/Dockerfile
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dockerfile for Atlas GIS API on HuggingFace Spaces
|
| 2 |
+
# Includes GDAL installation for geospatial libraries
|
| 3 |
+
|
| 4 |
+
FROM python:3.11-slim
|
| 5 |
+
|
| 6 |
+
# Install system dependencies including GDAL and geospatial libraries
|
| 7 |
+
RUN apt-get update && apt-get install -y \
|
| 8 |
+
# GDAL and geospatial dependencies
|
| 9 |
+
gdal-bin \
|
| 10 |
+
libgdal-dev \
|
| 11 |
+
libproj-dev \
|
| 12 |
+
libgeos-dev \
|
| 13 |
+
libspatialindex-dev \
|
| 14 |
+
# Build tools for compilation
|
| 15 |
+
build-essential \
|
| 16 |
+
# Utilities
|
| 17 |
+
curl \
|
| 18 |
+
wget \
|
| 19 |
+
git \
|
| 20 |
+
# Cleanup
|
| 21 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 22 |
+
|
| 23 |
+
# Set GDAL environment variables
|
| 24 |
+
ENV GDAL_CONFIG=/usr/bin/gdal-config
|
| 25 |
+
ENV GDAL_DATA=/usr/share/gdal
|
| 26 |
+
ENV PROJ_LIB=/usr/share/proj
|
| 27 |
+
|
| 28 |
+
# Set up a new user named "user" with user ID 1000 (HuggingFace requirement)
|
| 29 |
+
RUN useradd -m -u 1000 user
|
| 30 |
+
|
| 31 |
+
# Switch to the "user" user
|
| 32 |
+
USER user
|
| 33 |
+
|
| 34 |
+
# Set home to the user's home directory
|
| 35 |
+
ENV HOME=/home/user \
|
| 36 |
+
PATH=/home/user/.local/bin:$PATH
|
| 37 |
+
|
| 38 |
+
# Set the working directory to the user's home directory
|
| 39 |
+
WORKDIR $HOME/app
|
| 40 |
+
|
| 41 |
+
# Set environment variables for the application
|
| 42 |
+
ENV PYTHONPATH=$HOME/app
|
| 43 |
+
ENV PYTHONUNBUFFERED=1
|
| 44 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 45 |
+
|
| 46 |
+
# Copy the requirements file and install Python dependencies
|
| 47 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 48 |
+
|
| 49 |
+
# Upgrade pip and install dependencies
|
| 50 |
+
RUN pip install --no-cache-dir --upgrade pip
|
| 51 |
+
|
| 52 |
+
# Install Python dependencies with specific handling for geospatial packages
|
| 53 |
+
# Note: GDAL Python bindings will be automatically matched to system GDAL version
|
| 54 |
+
# by the requirements.txt installation process
|
| 55 |
+
RUN pip install --no-cache-dir --user \
|
| 56 |
+
# Install other dependencies first
|
| 57 |
+
-r requirements.txt
|
| 58 |
+
|
| 59 |
+
# Copy the application source code
|
| 60 |
+
COPY --chown=user ./src src
|
| 61 |
+
|
| 62 |
+
# Create app.py entry point for HuggingFace Spaces
|
| 63 |
+
COPY --chown=user ./app.py app.py
|
| 64 |
+
|
| 65 |
+
# Create necessary directories
|
| 66 |
+
RUN mkdir -p \
|
| 67 |
+
$HOME/app/temp_exports \
|
| 68 |
+
$HOME/app/logs \
|
| 69 |
+
$HOME/.cache
|
| 70 |
+
|
| 71 |
+
# Expose port 7860 (HuggingFace Spaces requirement)
|
| 72 |
+
EXPOSE 7860
|
| 73 |
+
|
| 74 |
+
# Health check for container monitoring
|
| 75 |
+
HEALTHCHECK --interval=30s --timeout=30s --start-period=60s --retries=3 \
|
| 76 |
+
CMD curl -f http://localhost:7860/api/v1/health || exit 1
|
| 77 |
+
|
| 78 |
+
# Start the FastAPI application on port 7860
|
| 79 |
+
# HuggingFace Spaces requires this specific port and host configuration
|
| 80 |
+
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "7860"]
|
docs/huggingface/examples/requirements.txt
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Atlas FastAPI Service - Production Dependencies
|
| 2 |
+
|
| 3 |
+
# Core Web Framework
|
| 4 |
+
fastapi==0.104.1
|
| 5 |
+
uvicorn[standard]==0.24.0
|
| 6 |
+
pydantic==2.5.0
|
| 7 |
+
pydantic-settings==2.1.0
|
| 8 |
+
|
| 9 |
+
# Geospatial Core Libraries
|
| 10 |
+
geopandas==0.14.1
|
| 11 |
+
shapely==2.0.2
|
| 12 |
+
fiona==1.9.5
|
| 13 |
+
pyproj==3.6.1
|
| 14 |
+
rasterio==1.3.9
|
| 15 |
+
geojson-pydantic==1.1.0
|
| 16 |
+
|
| 17 |
+
# Data Source Libraries
|
| 18 |
+
earthengine-api==0.1.383
|
| 19 |
+
osmnx==1.7.1
|
| 20 |
+
overpy==0.7
|
| 21 |
+
requests==2.31.0
|
| 22 |
+
|
| 23 |
+
# Export Format Libraries
|
| 24 |
+
simplekml==1.3.6
|
| 25 |
+
ezdxf==1.1.4
|
| 26 |
+
openpyxl==3.1.2
|
| 27 |
+
|
| 28 |
+
# Async and Concurrency
|
| 29 |
+
aiohttp==3.9.1
|
| 30 |
+
aiofiles==23.2.1
|
| 31 |
+
asyncio-throttle==1.0.2
|
| 32 |
+
|
| 33 |
+
# Utilities
|
| 34 |
+
python-multipart==0.0.6
|
| 35 |
+
python-jose[cryptography]==3.3.0
|
| 36 |
+
python-dotenv==1.0.0
|
| 37 |
+
click==8.1.7
|
| 38 |
+
|
| 39 |
+
# Optional: Caching and Performance
|
| 40 |
+
redis==5.0.1
|
| 41 |
+
hiredis==2.2.3
|
| 42 |
+
|
| 43 |
+
# Monitoring and Logging
|
| 44 |
+
structlog==23.2.0
|
| 45 |
+
prometheus-client==0.19.0
|
| 46 |
+
|
| 47 |
+
# Data Processing
|
| 48 |
+
pandas==2.1.4
|
| 49 |
+
numpy==1.25.2
|
| 50 |
+
matplotlib==3.8.2
|
| 51 |
+
folium==0.15.1
|
| 52 |
+
|
| 53 |
+
# Development and Testing (commented for production)
|
| 54 |
+
# pytest==7.4.3
|
| 55 |
+
# pytest-asyncio==0.21.1
|
| 56 |
+
# pytest-cov==4.1.0
|
| 57 |
+
# black==23.11.0
|
| 58 |
+
# isort==5.12.0
|
| 59 |
+
# flake8==6.1.0
|
| 60 |
+
# mypy==1.7.1
|
| 61 |
+
# pre-commit==3.6.0
|
docs/prod/BACKEND_FEATURES.md
ADDED
|
@@ -0,0 +1,1821 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend Features & Responsibilities
|
| 2 |
+
|
| 3 |
+
**Version:** 1.0
|
| 4 |
+
**Last Updated:** November 2025
|
| 5 |
+
**Status:** Production Planning
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Overview
|
| 10 |
+
|
| 11 |
+
This document outlines the comprehensive backend features and responsibilities for the SwiftOps FastAPI server. The backend acts as the central orchestrator for all business logic, data management, external integrations, and security controls.
|
| 12 |
+
|
| 13 |
+
## Architecture Philosophy
|
| 14 |
+
|
| 15 |
+
The FastAPI backend is the **single source of truth** for all operations:
|
| 16 |
+
- Frontend applications (web, mobile) are thin clients
|
| 17 |
+
- All database operations go through the backend
|
| 18 |
+
- All business logic is enforced server-side
|
| 19 |
+
- All external service integrations are managed by the backend
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
## 1. 🔐 Authentication & Authorization
|
| 24 |
+
|
| 25 |
+
### 1.1 Supabase Auth Integration
|
| 26 |
+
|
| 27 |
+
**Responsibilities:**
|
| 28 |
+
- Integrate with Supabase Auth for user authentication
|
| 29 |
+
- Validate JWT tokens from Supabase
|
| 30 |
+
- Sync user data between Supabase Auth and application database
|
| 31 |
+
- Handle user registration and onboarding flows
|
| 32 |
+
|
| 33 |
+
**Implementation:**
|
| 34 |
+
```python
|
| 35 |
+
# app/core/auth.py
|
| 36 |
+
- verify_supabase_token()
|
| 37 |
+
- create_user_from_supabase()
|
| 38 |
+
- sync_user_roles()
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
**Endpoints:**
|
| 42 |
+
```
|
| 43 |
+
POST /api/v1/auth/login
|
| 44 |
+
POST /api/v1/auth/register
|
| 45 |
+
POST /api/v1/auth/logout
|
| 46 |
+
POST /api/v1/auth/refresh-token
|
| 47 |
+
GET /api/v1/auth/me
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
### 1.2 JWT Token Management
|
| 51 |
+
|
| 52 |
+
**Responsibilities:**
|
| 53 |
+
- Generate access tokens (24-hour expiry)
|
| 54 |
+
- Generate refresh tokens (30-day expiry)
|
| 55 |
+
- Token validation and verification
|
| 56 |
+
- Token blacklisting on logout
|
| 57 |
+
|
| 58 |
+
**Implementation:**
|
| 59 |
+
```python
|
| 60 |
+
# app/core/auth.py
|
| 61 |
+
- create_access_token()
|
| 62 |
+
- create_refresh_token()
|
| 63 |
+
- verify_token()
|
| 64 |
+
- blacklist_token()
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
**Token Structure:**
|
| 68 |
+
```json
|
| 69 |
+
{
|
| 70 |
+
"sub": "user_id",
|
| 71 |
+
"email": "user@example.com",
|
| 72 |
+
"role": "field_agent",
|
| 73 |
+
"client_id": "uuid",
|
| 74 |
+
"contractor_id": "uuid",
|
| 75 |
+
"exp": 1234567890,
|
| 76 |
+
"iat": 1234567890
|
| 77 |
+
}
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
### 1.3 OTP & 2FA (Two-Factor Authentication)
|
| 81 |
+
|
| 82 |
+
**Responsibilities:**
|
| 83 |
+
- Generate OTP codes for critical operations
|
| 84 |
+
- Send OTP via email (Resend) or SMS (Africa's Talking)
|
| 85 |
+
- Verify OTP codes with expiry validation
|
| 86 |
+
- Rate limiting on OTP generation (max 3 per 5 minutes)
|
| 87 |
+
|
| 88 |
+
**Critical Operations Requiring 2FA:**
|
| 89 |
+
- Bulk payment authorization (>$1000 or >10 transactions)
|
| 90 |
+
- Payroll approval and disbursement
|
| 91 |
+
- User role changes (elevation to admin)
|
| 92 |
+
- Project closure with financial settlement
|
| 93 |
+
- Bulk ticket reassignment (>20 tickets)
|
| 94 |
+
- Inventory write-offs (>$500 value)
|
| 95 |
+
|
| 96 |
+
**Implementation:**
|
| 97 |
+
```python
|
| 98 |
+
# app/services/otp_service.py
|
| 99 |
+
- generate_otp(user_id, operation_type)
|
| 100 |
+
- send_otp_email(user_id, otp_code)
|
| 101 |
+
- send_otp_sms(user_id, otp_code)
|
| 102 |
+
- verify_otp(user_id, otp_code, operation_type)
|
| 103 |
+
- invalidate_otp(user_id, operation_type)
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
**Endpoints:**
|
| 107 |
+
```
|
| 108 |
+
POST /api/v1/auth/otp/generate
|
| 109 |
+
POST /api/v1/auth/otp/verify
|
| 110 |
+
POST /api/v1/auth/otp/resend
|
| 111 |
+
```
|
| 112 |
+
|
| 113 |
+
**OTP Flow:**
|
| 114 |
+
```
|
| 115 |
+
1. User initiates critical operation
|
| 116 |
+
2. Backend generates 6-digit OTP (valid 5 minutes)
|
| 117 |
+
3. OTP sent via email/SMS
|
| 118 |
+
4. User enters OTP in frontend
|
| 119 |
+
5. Backend verifies OTP
|
| 120 |
+
6. Operation proceeds if valid
|
| 121 |
+
7. OTP invalidated after use
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
### 1.4 Role-Based Access Control (RBAC)
|
| 125 |
+
|
| 126 |
+
**Responsibilities:**
|
| 127 |
+
- Enforce role-based permissions on all endpoints
|
| 128 |
+
- Validate user has required role for operation
|
| 129 |
+
- Support hierarchical permissions (admin > manager > agent)
|
| 130 |
+
- Dynamic permission checking based on resource ownership
|
| 131 |
+
|
| 132 |
+
**Roles & Permissions:**
|
| 133 |
+
```python
|
| 134 |
+
# app/core/permissions.py
|
| 135 |
+
ROLES = {
|
| 136 |
+
"platform_admin": ["*"], # All permissions
|
| 137 |
+
"client_admin": ["manage_projects", "invite_users", "view_reports"],
|
| 138 |
+
"contractor_admin": ["manage_agents", "accept_projects", "view_payroll"],
|
| 139 |
+
"project_manager": ["create_tickets", "manage_inventory", "approve_expenses"],
|
| 140 |
+
"dispatcher": ["assign_tickets", "issue_equipment", "approve_expenses"],
|
| 141 |
+
"field_agent": ["view_tickets", "update_status", "log_expenses"],
|
| 142 |
+
"sales_agent": ["create_orders", "view_customers"],
|
| 143 |
+
"sales_manager": ["view_team_performance", "export_reports"]
|
| 144 |
+
}
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
---
|
| 148 |
+
|
| 149 |
+
## 2. 📧 Communication Services
|
| 150 |
+
|
| 151 |
+
### 2.1 Email Service (Resend)
|
| 152 |
+
|
| 153 |
+
**Responsibilities:**
|
| 154 |
+
- Send transactional emails (OTP, password reset, notifications)
|
| 155 |
+
- Send bulk emails (weekly reports, announcements)
|
| 156 |
+
- Email templating with dynamic content
|
| 157 |
+
- Track email delivery status
|
| 158 |
+
- Handle email bounces and failures
|
| 159 |
+
|
| 160 |
+
**Email Types:**
|
| 161 |
+
- **Transactional**: OTP codes, password resets, account verification
|
| 162 |
+
- **Notifications**: Ticket assignments, status updates, payment confirmations
|
| 163 |
+
- **Reports**: Weekly payroll summaries, SLA compliance reports
|
| 164 |
+
- **Marketing**: Feature announcements, system updates
|
| 165 |
+
|
| 166 |
+
**Implementation:**
|
| 167 |
+
```python
|
| 168 |
+
# app/integrations/resend.py
|
| 169 |
+
- send_email(to, subject, html_content, template_id)
|
| 170 |
+
- send_bulk_email(recipients, subject, html_content)
|
| 171 |
+
- send_templated_email(to, template_id, variables)
|
| 172 |
+
- get_email_status(email_id)
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
**Email Templates:**
|
| 176 |
+
```
|
| 177 |
+
- otp_verification.html
|
| 178 |
+
- password_reset.html
|
| 179 |
+
- ticket_assignment.html
|
| 180 |
+
- payroll_summary.html
|
| 181 |
+
- expense_approved.html
|
| 182 |
+
- payment_confirmation.html
|
| 183 |
+
```
|
| 184 |
+
|
| 185 |
+
**Endpoints:**
|
| 186 |
+
```
|
| 187 |
+
POST /api/v1/communications/email/send
|
| 188 |
+
POST /api/v1/communications/email/bulk
|
| 189 |
+
GET /api/v1/communications/email/{email_id}/status
|
| 190 |
+
```
|
| 191 |
+
|
| 192 |
+
### 2.2 SMS Service (Africa's Talking) - V2 Feature
|
| 193 |
+
|
| 194 |
+
**Responsibilities:**
|
| 195 |
+
- Send SMS notifications to field agents
|
| 196 |
+
- Send OTP codes via SMS
|
| 197 |
+
- Bulk SMS for urgent alerts
|
| 198 |
+
- Track SMS delivery status
|
| 199 |
+
- Handle SMS failures and retries
|
| 200 |
+
|
| 201 |
+
**SMS Use Cases:**
|
| 202 |
+
- OTP codes for 2FA
|
| 203 |
+
- Urgent ticket assignments
|
| 204 |
+
- SLA violation alerts
|
| 205 |
+
- Payment confirmations
|
| 206 |
+
- Emergency notifications
|
| 207 |
+
|
| 208 |
+
**Implementation:**
|
| 209 |
+
```python
|
| 210 |
+
# app/integrations/africastalking.py
|
| 211 |
+
- send_sms(phone_number, message)
|
| 212 |
+
- send_bulk_sms(phone_numbers, message)
|
| 213 |
+
- get_sms_status(sms_id)
|
| 214 |
+
```
|
| 215 |
+
|
| 216 |
+
**Endpoints:**
|
| 217 |
+
```
|
| 218 |
+
POST /api/v1/communications/sms/send
|
| 219 |
+
POST /api/v1/communications/sms/bulk
|
| 220 |
+
GET /api/v1/communications/sms/{sms_id}/status
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
### 2.3 Push Notifications - V2 Feature
|
| 224 |
+
|
| 225 |
+
**Responsibilities:**
|
| 226 |
+
- Send push notifications to mobile apps
|
| 227 |
+
- Real-time alerts for critical events
|
| 228 |
+
- Notification preferences management
|
| 229 |
+
- Badge count management
|
| 230 |
+
|
| 231 |
+
**Implementation:**
|
| 232 |
+
```python
|
| 233 |
+
# app/services/push_notification_service.py
|
| 234 |
+
- send_push_notification(user_id, title, body, data)
|
| 235 |
+
- send_bulk_push_notification(user_ids, title, body, data)
|
| 236 |
+
```
|
| 237 |
+
|
| 238 |
+
---
|
| 239 |
+
|
| 240 |
+
## 3. 📸 Media & Photo Management
|
| 241 |
+
|
| 242 |
+
### 3.1 Cloudinary Integration
|
| 243 |
+
|
| 244 |
+
**Responsibilities:**
|
| 245 |
+
- Upload images to Cloudinary
|
| 246 |
+
- Generate optimized image URLs
|
| 247 |
+
- Image transformation (resize, crop, compress)
|
| 248 |
+
- Map images to tickets, users, documents
|
| 249 |
+
- Delete images when records are deleted
|
| 250 |
+
|
| 251 |
+
**Image Types:**
|
| 252 |
+
- **Ticket Photos**: Before/after installation photos, issue documentation
|
| 253 |
+
- **Profile Photos**: User avatars, field agent photos
|
| 254 |
+
- **Receipt Photos**: Expense receipts, delivery notes
|
| 255 |
+
- **Document Scans**: Contracts, invoices, reports
|
| 256 |
+
|
| 257 |
+
**Implementation:**
|
| 258 |
+
```python
|
| 259 |
+
# app/integrations/cloudinary.py
|
| 260 |
+
- upload_image(file, folder, public_id)
|
| 261 |
+
- get_image_url(public_id, transformations)
|
| 262 |
+
- delete_image(public_id)
|
| 263 |
+
- upload_multiple_images(files, folder)
|
| 264 |
+
```
|
| 265 |
+
|
| 266 |
+
**Image Transformations:**
|
| 267 |
+
```python
|
| 268 |
+
# Thumbnail: 150x150, quality 80
|
| 269 |
+
# Medium: 800x600, quality 85
|
| 270 |
+
# Large: 1920x1080, quality 90
|
| 271 |
+
# Original: No transformation
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
**Endpoints:**
|
| 275 |
+
```
|
| 276 |
+
POST /api/v1/media/upload
|
| 277 |
+
POST /api/v1/media/upload-multiple
|
| 278 |
+
GET /api/v1/media/{media_id}
|
| 279 |
+
DELETE /api/v1/media/{media_id}
|
| 280 |
+
GET /api/v1/tickets/{ticket_id}/photos
|
| 281 |
+
POST /api/v1/tickets/{ticket_id}/photos
|
| 282 |
+
GET /api/v1/users/{user_id}/profile-photo
|
| 283 |
+
POST /api/v1/users/{user_id}/profile-photo
|
| 284 |
+
```
|
| 285 |
+
|
| 286 |
+
### 3.2 Image Validation
|
| 287 |
+
|
| 288 |
+
**Responsibilities:**
|
| 289 |
+
- Validate file type (JPEG, PNG, PDF)
|
| 290 |
+
- Validate file size (max 10MB per file)
|
| 291 |
+
- Validate image dimensions (min 640x480)
|
| 292 |
+
- Scan for malware (optional)
|
| 293 |
+
- EXIF data extraction (GPS, timestamp)
|
| 294 |
+
|
| 295 |
+
**Implementation:**
|
| 296 |
+
```python
|
| 297 |
+
# app/utils/media_validation.py
|
| 298 |
+
- validate_image_file(file)
|
| 299 |
+
- validate_file_size(file, max_size_mb)
|
| 300 |
+
- extract_exif_data(file)
|
| 301 |
+
- validate_image_dimensions(file, min_width, min_height)
|
| 302 |
+
```
|
| 303 |
+
|
| 304 |
+
### 3.3 Image Metadata Management
|
| 305 |
+
|
| 306 |
+
**Responsibilities:**
|
| 307 |
+
- Store image metadata in database
|
| 308 |
+
- Link images to entities (tickets, users, expenses)
|
| 309 |
+
- Track upload timestamp and uploader
|
| 310 |
+
- Support image captions and descriptions
|
| 311 |
+
|
| 312 |
+
**Database Schema:**
|
| 313 |
+
```sql
|
| 314 |
+
CREATE TABLE media_files (
|
| 315 |
+
id UUID PRIMARY KEY,
|
| 316 |
+
cloudinary_public_id VARCHAR(255),
|
| 317 |
+
cloudinary_url TEXT,
|
| 318 |
+
file_type VARCHAR(50),
|
| 319 |
+
file_size_bytes INTEGER,
|
| 320 |
+
width INTEGER,
|
| 321 |
+
height INTEGER,
|
| 322 |
+
uploaded_by_user_id UUID,
|
| 323 |
+
entity_type VARCHAR(50), -- 'ticket', 'user', 'expense'
|
| 324 |
+
entity_id UUID,
|
| 325 |
+
caption TEXT,
|
| 326 |
+
exif_data JSONB,
|
| 327 |
+
created_at TIMESTAMP,
|
| 328 |
+
deleted_at TIMESTAMP
|
| 329 |
+
);
|
| 330 |
+
```
|
| 331 |
+
|
| 332 |
+
---
|
| 333 |
+
|
| 334 |
+
## 4. 📍 Location & Field Agent Allocation (V2 Feature)
|
| 335 |
+
|
| 336 |
+
### 4.1 Intelligent Agent Allocation
|
| 337 |
+
|
| 338 |
+
**Responsibilities:**
|
| 339 |
+
- Auto-assign tickets to nearest available agents
|
| 340 |
+
- Consider agent workload (max 3 active tickets)
|
| 341 |
+
- Consider agent skills and specializations
|
| 342 |
+
- Optimize routes for multiple tickets
|
| 343 |
+
- Balance workload across team
|
| 344 |
+
|
| 345 |
+
**Allocation Algorithm:**
|
| 346 |
+
```python
|
| 347 |
+
# app/services/allocation_service.py
|
| 348 |
+
def allocate_ticket(ticket_id):
|
| 349 |
+
1. Get ticket location
|
| 350 |
+
2. Find agents in same region
|
| 351 |
+
3. Filter agents with < 3 active tickets
|
| 352 |
+
4. Filter agents with required skills
|
| 353 |
+
5. Calculate distance from each agent's current location
|
| 354 |
+
6. Score agents: (distance × 0.4) + (workload × 0.3) + (skill_match × 0.3)
|
| 355 |
+
7. Assign to highest scoring agent
|
| 356 |
+
8. Send notification to agent
|
| 357 |
+
```
|
| 358 |
+
|
| 359 |
+
**Endpoints:**
|
| 360 |
+
```
|
| 361 |
+
POST /api/v1/tickets/{ticket_id}/auto-assign
|
| 362 |
+
POST /api/v1/tickets/bulk-auto-assign
|
| 363 |
+
GET /api/v1/agents/available
|
| 364 |
+
GET /api/v1/agents/nearest?lat={lat}&lng={lng}
|
| 365 |
+
```
|
| 366 |
+
|
| 367 |
+
### 4.2 Route Optimization
|
| 368 |
+
|
| 369 |
+
**Responsibilities:**
|
| 370 |
+
- Calculate optimal route for agent's daily tickets
|
| 371 |
+
- Minimize travel time and distance
|
| 372 |
+
- Consider ticket priorities and SLA deadlines
|
| 373 |
+
- Provide turn-by-turn directions
|
| 374 |
+
|
| 375 |
+
**Implementation:**
|
| 376 |
+
```python
|
| 377 |
+
# app/services/route_optimization_service.py
|
| 378 |
+
- optimize_route(agent_id, ticket_ids)
|
| 379 |
+
- calculate_travel_time(origin, destination)
|
| 380 |
+
- get_directions(origin, destination)
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
**Endpoints:**
|
| 384 |
+
```
|
| 385 |
+
GET /api/v1/agents/{agent_id}/optimized-route
|
| 386 |
+
GET /api/v1/tickets/{ticket_id}/directions
|
| 387 |
+
```
|
| 388 |
+
|
| 389 |
+
### 4.3 Geofencing & Proximity Alerts
|
| 390 |
+
|
| 391 |
+
**Responsibilities:**
|
| 392 |
+
- Alert agent when approaching customer location
|
| 393 |
+
- Verify agent is within geofence before allowing check-in
|
| 394 |
+
- Track time spent at customer location
|
| 395 |
+
- Detect if agent leaves before completing work
|
| 396 |
+
|
| 397 |
+
**Implementation:**
|
| 398 |
+
```python
|
| 399 |
+
# app/services/geofencing_service.py
|
| 400 |
+
- check_proximity(agent_location, customer_location, radius_meters)
|
| 401 |
+
- create_geofence(center_lat, center_lng, radius_meters)
|
| 402 |
+
- check_agent_in_geofence(agent_location, geofence)
|
| 403 |
+
```
|
| 404 |
+
|
| 405 |
+
---
|
| 406 |
+
|
| 407 |
+
## 5. 🔍 Filtering & Search
|
| 408 |
+
|
| 409 |
+
### 5.1 Advanced Filtering
|
| 410 |
+
|
| 411 |
+
**Responsibilities:**
|
| 412 |
+
- Filter tickets by status, priority, region, date range
|
| 413 |
+
- Filter users by role, organization, status
|
| 414 |
+
- Filter inventory by type, location, availability
|
| 415 |
+
- Support multiple filter combinations
|
| 416 |
+
- Pagination and sorting
|
| 417 |
+
|
| 418 |
+
**Filter Examples:**
|
| 419 |
+
```
|
| 420 |
+
GET /api/v1/tickets?status=open&priority=high®ion_id=uuid&created_after=2024-01-01
|
| 421 |
+
GET /api/v1/users?role=field_agent&contractor_id=uuid&status=active
|
| 422 |
+
GET /api/v1/inventory?type=equipment&location=regional_hub&available=true
|
| 423 |
+
```
|
| 424 |
+
|
| 425 |
+
**Implementation:**
|
| 426 |
+
```python
|
| 427 |
+
# app/repositories/base_repository.py
|
| 428 |
+
def apply_filters(query, filters):
|
| 429 |
+
for key, value in filters.items():
|
| 430 |
+
if key == 'status':
|
| 431 |
+
query = query.filter(Model.status == value)
|
| 432 |
+
elif key == 'created_after':
|
| 433 |
+
query = query.filter(Model.created_at >= value)
|
| 434 |
+
# ... more filters
|
| 435 |
+
return query
|
| 436 |
+
```
|
| 437 |
+
|
| 438 |
+
### 5.2 Full-Text Search
|
| 439 |
+
|
| 440 |
+
**Responsibilities:**
|
| 441 |
+
- Search tickets by customer name, address, description
|
| 442 |
+
- Search users by name, email, phone
|
| 443 |
+
- Search inventory by serial number, description
|
| 444 |
+
- Support fuzzy matching and typo tolerance
|
| 445 |
+
|
| 446 |
+
**Implementation:**
|
| 447 |
+
```python
|
| 448 |
+
# app/services/search_service.py
|
| 449 |
+
- search_tickets(query, filters)
|
| 450 |
+
- search_users(query, filters)
|
| 451 |
+
- search_customers(query)
|
| 452 |
+
- search_inventory(query)
|
| 453 |
+
```
|
| 454 |
+
|
| 455 |
+
**Endpoints:**
|
| 456 |
+
```
|
| 457 |
+
GET /api/v1/search/tickets?q={query}
|
| 458 |
+
GET /api/v1/search/users?q={query}
|
| 459 |
+
GET /api/v1/search/customers?q={query}
|
| 460 |
+
GET /api/v1/search/global?q={query}
|
| 461 |
+
```
|
| 462 |
+
|
| 463 |
+
### 5.3 Autocomplete & Suggestions
|
| 464 |
+
|
| 465 |
+
**Responsibilities:**
|
| 466 |
+
- Provide autocomplete suggestions for search
|
| 467 |
+
- Suggest customers based on partial phone number
|
| 468 |
+
- Suggest locations based on partial address
|
| 469 |
+
- Cache frequent searches
|
| 470 |
+
|
| 471 |
+
**Endpoints:**
|
| 472 |
+
```
|
| 473 |
+
GET /api/v1/autocomplete/customers?q={query}
|
| 474 |
+
GET /api/v1/autocomplete/locations?q={query}
|
| 475 |
+
```
|
| 476 |
+
|
| 477 |
+
---
|
| 478 |
+
|
| 479 |
+
## 6. 💳 Payment Processing
|
| 480 |
+
|
| 481 |
+
### 6.1 Expense Payments
|
| 482 |
+
|
| 483 |
+
**Responsibilities:**
|
| 484 |
+
- Process expense reimbursements to field agents
|
| 485 |
+
- Support M-Pesa and bank transfer
|
| 486 |
+
- Track payment status (pending, processing, completed, failed)
|
| 487 |
+
- Handle payment failures and retries
|
| 488 |
+
- Generate payment receipts
|
| 489 |
+
|
| 490 |
+
**Payment Flow:**
|
| 491 |
+
```
|
| 492 |
+
1. Dispatcher approves expense
|
| 493 |
+
2. Expense added to payment queue
|
| 494 |
+
3. Backend initiates payment via M-Pesa/Bank
|
| 495 |
+
4. Payment gateway returns transaction ID
|
| 496 |
+
5. Backend polls for payment status
|
| 497 |
+
6. On success: Update expense status, send notification
|
| 498 |
+
7. On failure: Retry with exponential backoff (max 3 retries)
|
| 499 |
+
```
|
| 500 |
+
|
| 501 |
+
**Implementation:**
|
| 502 |
+
```python
|
| 503 |
+
# app/services/payment_service.py
|
| 504 |
+
- initiate_expense_payment(expense_id)
|
| 505 |
+
- process_payment_queue()
|
| 506 |
+
- check_payment_status(transaction_id)
|
| 507 |
+
- retry_failed_payment(payment_id)
|
| 508 |
+
- generate_payment_receipt(payment_id)
|
| 509 |
+
```
|
| 510 |
+
|
| 511 |
+
**Endpoints:**
|
| 512 |
+
```
|
| 513 |
+
POST /api/v1/payments/expenses/{expense_id}/pay
|
| 514 |
+
GET /api/v1/payments/{payment_id}/status
|
| 515 |
+
POST /api/v1/payments/{payment_id}/retry
|
| 516 |
+
GET /api/v1/payments/{payment_id}/receipt
|
| 517 |
+
```
|
| 518 |
+
|
| 519 |
+
### 6.2 Payroll Disbursement
|
| 520 |
+
|
| 521 |
+
**Responsibilities:**
|
| 522 |
+
- Process weekly payroll payments
|
| 523 |
+
- Support bulk payments (100+ agents)
|
| 524 |
+
- Validate payment details before processing
|
| 525 |
+
- Handle partial failures (some succeed, some fail)
|
| 526 |
+
- Generate payroll reports
|
| 527 |
+
|
| 528 |
+
**Bulk Payment Flow:**
|
| 529 |
+
```
|
| 530 |
+
1. Payroll generated (Celery task)
|
| 531 |
+
2. Payments added to queue
|
| 532 |
+
3. Process in batches of 50
|
| 533 |
+
4. For each batch:
|
| 534 |
+
- Validate payment details
|
| 535 |
+
- Initiate bulk payment via M-Pesa B2C
|
| 536 |
+
- Track individual payment statuses
|
| 537 |
+
5. Generate success/failure report
|
| 538 |
+
6. Retry failed payments
|
| 539 |
+
7. Send notifications to agents
|
| 540 |
+
```
|
| 541 |
+
|
| 542 |
+
**Implementation:**
|
| 543 |
+
```python
|
| 544 |
+
# app/services/payroll_payment_service.py
|
| 545 |
+
- process_payroll_payments(payroll_period_id)
|
| 546 |
+
- validate_payment_batch(payments)
|
| 547 |
+
- initiate_bulk_payment(payments)
|
| 548 |
+
- handle_payment_callback(callback_data)
|
| 549 |
+
- generate_payroll_report(payroll_period_id)
|
| 550 |
+
```
|
| 551 |
+
|
| 552 |
+
**Endpoints:**
|
| 553 |
+
```
|
| 554 |
+
POST /api/v1/payroll/{period_id}/disburse
|
| 555 |
+
GET /api/v1/payroll/{period_id}/payment-status
|
| 556 |
+
POST /api/v1/payroll/{period_id}/retry-failed
|
| 557 |
+
GET /api/v1/payroll/{period_id}/report
|
| 558 |
+
```
|
| 559 |
+
|
| 560 |
+
### 6.3 Payment Webhooks
|
| 561 |
+
|
| 562 |
+
**Responsibilities:**
|
| 563 |
+
- Receive payment callbacks from M-Pesa
|
| 564 |
+
- Validate webhook signatures
|
| 565 |
+
- Update payment statuses
|
| 566 |
+
- Trigger post-payment actions (notifications, reports)
|
| 567 |
+
|
| 568 |
+
**Implementation:**
|
| 569 |
+
```python
|
| 570 |
+
# app/api/v1/webhooks.py
|
| 571 |
+
@router.post("/webhooks/mpesa")
|
| 572 |
+
async def mpesa_callback(payload: dict):
|
| 573 |
+
# 1. Validate signature
|
| 574 |
+
# 2. Parse payment result
|
| 575 |
+
# 3. Update payment status
|
| 576 |
+
# 4. Send notification
|
| 577 |
+
# 5. Log callback
|
| 578 |
+
```
|
| 579 |
+
|
| 580 |
+
---
|
| 581 |
+
|
| 582 |
+
## 7. 🔄 Queue Management & Concurrency Control
|
| 583 |
+
|
| 584 |
+
### 7.1 Task Queues (Celery)
|
| 585 |
+
|
| 586 |
+
**Responsibilities:**
|
| 587 |
+
- Process background tasks asynchronously
|
| 588 |
+
- Retry failed tasks with exponential backoff
|
| 589 |
+
- Monitor queue health and length
|
| 590 |
+
- Prioritize critical tasks
|
| 591 |
+
|
| 592 |
+
**Queue Types:**
|
| 593 |
+
```python
|
| 594 |
+
# High Priority Queue (SLA-critical)
|
| 595 |
+
- ticket_assignment_notifications
|
| 596 |
+
- sla_violation_alerts
|
| 597 |
+
- payment_processing
|
| 598 |
+
|
| 599 |
+
# Medium Priority Queue
|
| 600 |
+
- email_notifications
|
| 601 |
+
- report_generation
|
| 602 |
+
- inventory_updates
|
| 603 |
+
|
| 604 |
+
# Low Priority Queue
|
| 605 |
+
- analytics_computation
|
| 606 |
+
- data_cleanup
|
| 607 |
+
- log_archival
|
| 608 |
+
```
|
| 609 |
+
|
| 610 |
+
**Implementation:**
|
| 611 |
+
```python
|
| 612 |
+
# app/tasks/celery_app.py
|
| 613 |
+
celery_app.conf.task_routes = {
|
| 614 |
+
'app.tasks.notifications.*': {'queue': 'high_priority'},
|
| 615 |
+
'app.tasks.reports.*': {'queue': 'medium_priority'},
|
| 616 |
+
'app.tasks.analytics.*': {'queue': 'low_priority'},
|
| 617 |
+
}
|
| 618 |
+
```
|
| 619 |
+
|
| 620 |
+
### 7.2 Optimistic Locking
|
| 621 |
+
|
| 622 |
+
**Responsibilities:**
|
| 623 |
+
- Prevent concurrent update conflicts
|
| 624 |
+
- Use version field for conflict detection
|
| 625 |
+
- Retry on conflict with fresh data
|
| 626 |
+
- Inform user of conflicts
|
| 627 |
+
|
| 628 |
+
**Implementation:**
|
| 629 |
+
```python
|
| 630 |
+
# app/models/base.py
|
| 631 |
+
class BaseModel:
|
| 632 |
+
version = Column(Integer, default=1, nullable=False)
|
| 633 |
+
|
| 634 |
+
# app/repositories/base_repository.py
|
| 635 |
+
def update_with_optimistic_lock(id, updates, version):
|
| 636 |
+
result = db.query(Model).filter(
|
| 637 |
+
Model.id == id,
|
| 638 |
+
Model.version == version
|
| 639 |
+
).update({
|
| 640 |
+
**updates,
|
| 641 |
+
'version': Model.version + 1
|
| 642 |
+
})
|
| 643 |
+
|
| 644 |
+
if result == 0:
|
| 645 |
+
raise ConcurrentUpdateError("Record was modified by another user")
|
| 646 |
+
|
| 647 |
+
db.commit()
|
| 648 |
+
```
|
| 649 |
+
|
| 650 |
+
**Use Cases:**
|
| 651 |
+
- Inventory quantity updates
|
| 652 |
+
- Ticket status changes
|
| 653 |
+
- Payroll calculations
|
| 654 |
+
- Financial transactions
|
| 655 |
+
|
| 656 |
+
### 7.3 Distributed Locks (Redis)
|
| 657 |
+
|
| 658 |
+
**Responsibilities:**
|
| 659 |
+
- Prevent duplicate task execution
|
| 660 |
+
- Ensure only one worker processes a task
|
| 661 |
+
- Lock critical sections (payment processing)
|
| 662 |
+
- Auto-release locks on timeout
|
| 663 |
+
|
| 664 |
+
**Implementation:**
|
| 665 |
+
```python
|
| 666 |
+
# app/utils/distributed_lock.py
|
| 667 |
+
from redis import Redis
|
| 668 |
+
from contextlib import contextmanager
|
| 669 |
+
|
| 670 |
+
@contextmanager
|
| 671 |
+
def distributed_lock(lock_key, timeout=30):
|
| 672 |
+
redis_client = Redis()
|
| 673 |
+
lock = redis_client.lock(lock_key, timeout=timeout)
|
| 674 |
+
|
| 675 |
+
try:
|
| 676 |
+
acquired = lock.acquire(blocking=True, blocking_timeout=10)
|
| 677 |
+
if not acquired:
|
| 678 |
+
raise LockAcquisitionError(f"Could not acquire lock: {lock_key}")
|
| 679 |
+
yield
|
| 680 |
+
finally:
|
| 681 |
+
lock.release()
|
| 682 |
+
|
| 683 |
+
# Usage
|
| 684 |
+
with distributed_lock(f"payroll_processing:{period_id}"):
|
| 685 |
+
process_payroll(period_id)
|
| 686 |
+
```
|
| 687 |
+
|
| 688 |
+
---
|
| 689 |
+
|
| 690 |
+
## 8. 📊 CSV Parsing & Export
|
| 691 |
+
|
| 692 |
+
### 8.1 CSV Import
|
| 693 |
+
|
| 694 |
+
**Responsibilities:**
|
| 695 |
+
- Parse CSV files for bulk data import
|
| 696 |
+
- Validate data before import
|
| 697 |
+
- Handle large files (10,000+ rows)
|
| 698 |
+
- Provide detailed error reports
|
| 699 |
+
- Support preview before import
|
| 700 |
+
|
| 701 |
+
**Supported Imports:**
|
| 702 |
+
- Sales orders (customer details, installation addresses)
|
| 703 |
+
- Field agents (contact details, financial accounts)
|
| 704 |
+
- Inventory (serial numbers, quantities)
|
| 705 |
+
- Customers (bulk customer creation)
|
| 706 |
+
|
| 707 |
+
**Implementation:**
|
| 708 |
+
```python
|
| 709 |
+
# app/services/csv_import_service.py
|
| 710 |
+
def import_sales_orders_csv(file):
|
| 711 |
+
1. Parse CSV file
|
| 712 |
+
2. Validate headers
|
| 713 |
+
3. Validate each row
|
| 714 |
+
4. Deduplicate customers by phone
|
| 715 |
+
5. Create preview with errors
|
| 716 |
+
6. Return validation report
|
| 717 |
+
|
| 718 |
+
def confirm_csv_import(import_id):
|
| 719 |
+
1. Retrieve validated data
|
| 720 |
+
2. Create records in batches of 100
|
| 721 |
+
3. Track progress
|
| 722 |
+
4. Generate success/failure report
|
| 723 |
+
5. Return import summary
|
| 724 |
+
```
|
| 725 |
+
|
| 726 |
+
**Endpoints:**
|
| 727 |
+
```
|
| 728 |
+
POST /api/v1/import/sales-orders/validate
|
| 729 |
+
POST /api/v1/import/sales-orders/confirm
|
| 730 |
+
GET /api/v1/import/{import_id}/status
|
| 731 |
+
GET /api/v1/import/{import_id}/errors
|
| 732 |
+
POST /api/v1/import/field-agents/validate
|
| 733 |
+
POST /api/v1/import/inventory/validate
|
| 734 |
+
```
|
| 735 |
+
|
| 736 |
+
### 8.2 CSV Export
|
| 737 |
+
|
| 738 |
+
**Responsibilities:**
|
| 739 |
+
- Export data to CSV format
|
| 740 |
+
- Support large datasets (streaming)
|
| 741 |
+
- Apply filters before export
|
| 742 |
+
- Generate downloadable files
|
| 743 |
+
- Clean up old exports
|
| 744 |
+
|
| 745 |
+
**Supported Exports:**
|
| 746 |
+
- Tickets (filtered by date, status, region)
|
| 747 |
+
- Payroll reports (by period, agent)
|
| 748 |
+
- Inventory reports (by location, type)
|
| 749 |
+
- Financial reports (by project, date range)
|
| 750 |
+
- Agent performance reports
|
| 751 |
+
|
| 752 |
+
**Implementation:**
|
| 753 |
+
```python
|
| 754 |
+
# app/services/csv_export_service.py
|
| 755 |
+
def export_tickets_csv(filters):
|
| 756 |
+
1. Apply filters to query
|
| 757 |
+
2. Stream results to CSV
|
| 758 |
+
3. Upload to temporary storage
|
| 759 |
+
4. Generate signed download URL
|
| 760 |
+
5. Schedule cleanup after 24 hours
|
| 761 |
+
6. Return download URL
|
| 762 |
+
```
|
| 763 |
+
|
| 764 |
+
**Endpoints:**
|
| 765 |
+
```
|
| 766 |
+
POST /api/v1/export/tickets
|
| 767 |
+
POST /api/v1/export/payroll
|
| 768 |
+
POST /api/v1/export/inventory
|
| 769 |
+
POST /api/v1/export/financial-report
|
| 770 |
+
GET /api/v1/export/{export_id}/download
|
| 771 |
+
```
|
| 772 |
+
|
| 773 |
+
### 8.3 Excel Integration
|
| 774 |
+
|
| 775 |
+
**Responsibilities:**
|
| 776 |
+
- Generate Excel files with formatting
|
| 777 |
+
- Support multiple sheets
|
| 778 |
+
- Add charts and pivot tables
|
| 779 |
+
- Password-protect sensitive reports
|
| 780 |
+
|
| 781 |
+
**Implementation:**
|
| 782 |
+
```python
|
| 783 |
+
# app/services/excel_service.py
|
| 784 |
+
- generate_excel_report(data, template)
|
| 785 |
+
- add_formatting(workbook, styles)
|
| 786 |
+
- create_pivot_table(worksheet, data_range)
|
| 787 |
+
```
|
| 788 |
+
|
| 789 |
+
---
|
| 790 |
+
|
| 791 |
+
## 9. 🏥 Health Checks & Monitoring (V2 Feature)
|
| 792 |
+
|
| 793 |
+
### 9.1 System Health Checks
|
| 794 |
+
|
| 795 |
+
**Responsibilities:**
|
| 796 |
+
- Monitor API server health
|
| 797 |
+
- Check database connectivity
|
| 798 |
+
- Check Redis connectivity
|
| 799 |
+
- Check external service availability
|
| 800 |
+
- Report system status
|
| 801 |
+
|
| 802 |
+
**Health Check Endpoints:**
|
| 803 |
+
```
|
| 804 |
+
GET /api/v1/health
|
| 805 |
+
GET /api/v1/health/database
|
| 806 |
+
GET /api/v1/health/redis
|
| 807 |
+
GET /api/v1/health/celery
|
| 808 |
+
GET /api/v1/health/external-services
|
| 809 |
+
```
|
| 810 |
+
|
| 811 |
+
**Health Check Response:**
|
| 812 |
+
```json
|
| 813 |
+
{
|
| 814 |
+
"status": "healthy",
|
| 815 |
+
"timestamp": "2024-01-15T10:30:00Z",
|
| 816 |
+
"checks": {
|
| 817 |
+
"database": {
|
| 818 |
+
"status": "healthy",
|
| 819 |
+
"response_time_ms": 15,
|
| 820 |
+
"connection_pool": {
|
| 821 |
+
"active": 5,
|
| 822 |
+
"idle": 15,
|
| 823 |
+
"max": 20
|
| 824 |
+
}
|
| 825 |
+
},
|
| 826 |
+
"redis": {
|
| 827 |
+
"status": "healthy",
|
| 828 |
+
"response_time_ms": 3
|
| 829 |
+
},
|
| 830 |
+
"celery": {
|
| 831 |
+
"status": "healthy",
|
| 832 |
+
"workers": 4,
|
| 833 |
+
"queue_length": {
|
| 834 |
+
"high_priority": 5,
|
| 835 |
+
"medium_priority": 23,
|
| 836 |
+
"low_priority": 102
|
| 837 |
+
}
|
| 838 |
+
},
|
| 839 |
+
"external_services": {
|
| 840 |
+
"supabase": "healthy",
|
| 841 |
+
"cloudinary": "healthy",
|
| 842 |
+
"mpesa": "degraded",
|
| 843 |
+
"resend": "healthy"
|
| 844 |
+
}
|
| 845 |
+
}
|
| 846 |
+
}
|
| 847 |
+
```
|
| 848 |
+
|
| 849 |
+
### 9.2 Usage Monitoring
|
| 850 |
+
|
| 851 |
+
**Responsibilities:**
|
| 852 |
+
- Track API request counts
|
| 853 |
+
- Monitor response times
|
| 854 |
+
- Track error rates
|
| 855 |
+
- Monitor resource usage (CPU, memory, disk)
|
| 856 |
+
- Alert on anomalies
|
| 857 |
+
|
| 858 |
+
**Metrics Tracked:**
|
| 859 |
+
```python
|
| 860 |
+
# Request Metrics
|
| 861 |
+
- Total requests per endpoint
|
| 862 |
+
- Average response time per endpoint
|
| 863 |
+
- Error rate per endpoint
|
| 864 |
+
- Requests per user/organization
|
| 865 |
+
|
| 866 |
+
# Resource Metrics
|
| 867 |
+
- Database connection pool usage
|
| 868 |
+
- Redis memory usage
|
| 869 |
+
- Celery queue lengths
|
| 870 |
+
- Disk space usage
|
| 871 |
+
|
| 872 |
+
# Business Metrics
|
| 873 |
+
- Active users
|
| 874 |
+
- Tickets created/completed per day
|
| 875 |
+
- Payments processed per day
|
| 876 |
+
- API calls per organization (for billing)
|
| 877 |
+
```
|
| 878 |
+
|
| 879 |
+
**Implementation:**
|
| 880 |
+
```python
|
| 881 |
+
# app/middleware/monitoring.py
|
| 882 |
+
class MonitoringMiddleware:
|
| 883 |
+
async def __call__(self, request, call_next):
|
| 884 |
+
start_time = time.time()
|
| 885 |
+
|
| 886 |
+
response = await call_next(request)
|
| 887 |
+
|
| 888 |
+
duration = time.time() - start_time
|
| 889 |
+
|
| 890 |
+
# Log metrics
|
| 891 |
+
metrics.record_request(
|
| 892 |
+
endpoint=request.url.path,
|
| 893 |
+
method=request.method,
|
| 894 |
+
status_code=response.status_code,
|
| 895 |
+
duration_ms=duration * 1000,
|
| 896 |
+
user_id=request.state.user_id
|
| 897 |
+
)
|
| 898 |
+
|
| 899 |
+
return response
|
| 900 |
+
```
|
| 901 |
+
|
| 902 |
+
**Endpoints:**
|
| 903 |
+
```
|
| 904 |
+
GET /api/v1/monitoring/metrics
|
| 905 |
+
GET /api/v1/monitoring/metrics/requests
|
| 906 |
+
GET /api/v1/monitoring/metrics/errors
|
| 907 |
+
GET /api/v1/monitoring/metrics/performance
|
| 908 |
+
GET /api/v1/monitoring/usage/by-organization
|
| 909 |
+
```
|
| 910 |
+
|
| 911 |
+
### 9.3 Infrastructure Monitoring
|
| 912 |
+
|
| 913 |
+
**Responsibilities:**
|
| 914 |
+
- Monitor Netlify deployment status
|
| 915 |
+
- Monitor database performance (Supabase)
|
| 916 |
+
- Monitor storage usage (Cloudinary)
|
| 917 |
+
- Track API quota usage (Google Maps, M-Pesa)
|
| 918 |
+
- Alert on quota limits
|
| 919 |
+
|
| 920 |
+
**Monitored Services:**
|
| 921 |
+
```python
|
| 922 |
+
# Netlify
|
| 923 |
+
- Deployment status
|
| 924 |
+
- Build times
|
| 925 |
+
- Bandwidth usage
|
| 926 |
+
|
| 927 |
+
# Supabase
|
| 928 |
+
- Database size
|
| 929 |
+
- Connection count
|
| 930 |
+
- Query performance
|
| 931 |
+
- Storage usage
|
| 932 |
+
|
| 933 |
+
# Cloudinary
|
| 934 |
+
- Storage used
|
| 935 |
+
- Bandwidth used
|
| 936 |
+
- Transformations used
|
| 937 |
+
|
| 938 |
+
# External APIs
|
| 939 |
+
- Google Maps API calls
|
| 940 |
+
- M-Pesa transaction count
|
| 941 |
+
- Resend email quota
|
| 942 |
+
- Africa's Talking SMS quota
|
| 943 |
+
```
|
| 944 |
+
|
| 945 |
+
**Endpoints:**
|
| 946 |
+
```
|
| 947 |
+
GET /api/v1/monitoring/infrastructure
|
| 948 |
+
GET /api/v1/monitoring/infrastructure/netlify
|
| 949 |
+
GET /api/v1/monitoring/infrastructure/supabase
|
| 950 |
+
GET /api/v1/monitoring/infrastructure/cloudinary
|
| 951 |
+
GET /api/v1/monitoring/infrastructure/quotas
|
| 952 |
+
```
|
| 953 |
+
|
| 954 |
+
### 9.4 Alerting & Notifications
|
| 955 |
+
|
| 956 |
+
**
|
| 957 |
+
Responsibilities:**
|
| 958 |
+
- Alert on system errors (500 errors, database failures)
|
| 959 |
+
- Alert on performance degradation (slow queries, high latency)
|
| 960 |
+
- Alert on quota limits (80% usage)
|
| 961 |
+
- Alert on security events (failed login attempts, suspicious activity)
|
| 962 |
+
- Send alerts via email, SMS, Slack
|
| 963 |
+
|
| 964 |
+
**Alert Levels:**
|
| 965 |
+
```python
|
| 966 |
+
# Critical (Immediate action required)
|
| 967 |
+
- Database connection failure
|
| 968 |
+
- Payment gateway down
|
| 969 |
+
- API server crash
|
| 970 |
+
- Security breach detected
|
| 971 |
+
|
| 972 |
+
# Warning (Action required soon)
|
| 973 |
+
- High error rate (>5%)
|
| 974 |
+
- Slow response times (>2s)
|
| 975 |
+
- Queue backlog (>1000 items)
|
| 976 |
+
- Quota at 80%
|
| 977 |
+
|
| 978 |
+
# Info (Monitoring)
|
| 979 |
+
- Deployment completed
|
| 980 |
+
- Scheduled task completed
|
| 981 |
+
- Daily summary reports
|
| 982 |
+
```
|
| 983 |
+
|
| 984 |
+
**Implementation:**
|
| 985 |
+
```python
|
| 986 |
+
# app/services/alerting_service.py
|
| 987 |
+
def send_alert(level, title, message, channels):
|
| 988 |
+
if level == "critical":
|
| 989 |
+
send_email(ADMIN_EMAILS, title, message)
|
| 990 |
+
send_sms(ADMIN_PHONES, message)
|
| 991 |
+
send_slack(CRITICAL_CHANNEL, message)
|
| 992 |
+
elif level == "warning":
|
| 993 |
+
send_email(ADMIN_EMAILS, title, message)
|
| 994 |
+
send_slack(WARNING_CHANNEL, message)
|
| 995 |
+
else:
|
| 996 |
+
send_slack(INFO_CHANNEL, message)
|
| 997 |
+
```
|
| 998 |
+
|
| 999 |
+
---
|
| 1000 |
+
|
| 1001 |
+
## 10. 🔒 Security Features
|
| 1002 |
+
|
| 1003 |
+
### 10.1 Rate Limiting
|
| 1004 |
+
|
| 1005 |
+
**Responsibilities:**
|
| 1006 |
+
- Limit API requests per user/IP
|
| 1007 |
+
- Prevent brute force attacks
|
| 1008 |
+
- Protect against DDoS
|
| 1009 |
+
- Different limits for different endpoints
|
| 1010 |
+
|
| 1011 |
+
**Rate Limits:**
|
| 1012 |
+
```python
|
| 1013 |
+
# Authentication endpoints
|
| 1014 |
+
- Login: 5 requests per 5 minutes per IP
|
| 1015 |
+
- OTP generation: 3 requests per 5 minutes per user
|
| 1016 |
+
- Password reset: 3 requests per hour per email
|
| 1017 |
+
|
| 1018 |
+
# General API
|
| 1019 |
+
- Standard endpoints: 1000 requests per hour per user
|
| 1020 |
+
- Search endpoints: 100 requests per minute per user
|
| 1021 |
+
- Export endpoints: 10 requests per hour per user
|
| 1022 |
+
|
| 1023 |
+
# Webhooks
|
| 1024 |
+
- Payment callbacks: 1000 requests per hour per IP
|
| 1025 |
+
```
|
| 1026 |
+
|
| 1027 |
+
**Implementation:**
|
| 1028 |
+
```python
|
| 1029 |
+
# app/middleware/rate_limiting.py
|
| 1030 |
+
from slowapi import Limiter
|
| 1031 |
+
from slowapi.util import get_remote_address
|
| 1032 |
+
|
| 1033 |
+
limiter = Limiter(key_func=get_remote_address)
|
| 1034 |
+
|
| 1035 |
+
@app.post("/api/v1/auth/login")
|
| 1036 |
+
@limiter.limit("5/5minutes")
|
| 1037 |
+
async def login(request: Request):
|
| 1038 |
+
pass
|
| 1039 |
+
```
|
| 1040 |
+
|
| 1041 |
+
### 10.2 Input Validation & Sanitization
|
| 1042 |
+
|
| 1043 |
+
**Responsibilities:**
|
| 1044 |
+
- Validate all input data using Pydantic
|
| 1045 |
+
- Sanitize user input to prevent XSS
|
| 1046 |
+
- Validate file uploads (type, size, content)
|
| 1047 |
+
- Prevent SQL injection (using ORM)
|
| 1048 |
+
|
| 1049 |
+
**Implementation:**
|
| 1050 |
+
```python
|
| 1051 |
+
# app/schemas/ticket.py
|
| 1052 |
+
from pydantic import BaseModel, validator, Field
|
| 1053 |
+
|
| 1054 |
+
class TicketCreate(BaseModel):
|
| 1055 |
+
title: str = Field(..., min_length=5, max_length=200)
|
| 1056 |
+
description: str = Field(..., max_length=2000)
|
| 1057 |
+
priority: str = Field(..., regex="^(low|medium|high|critical)$")
|
| 1058 |
+
|
| 1059 |
+
@validator('title', 'description')
|
| 1060 |
+
def sanitize_html(cls, v):
|
| 1061 |
+
return bleach.clean(v, tags=[], strip=True)
|
| 1062 |
+
```
|
| 1063 |
+
|
| 1064 |
+
### 10.3 Audit Logging
|
| 1065 |
+
|
| 1066 |
+
**Responsibilities:**
|
| 1067 |
+
- Log all critical operations
|
| 1068 |
+
- Track who did what and when
|
| 1069 |
+
- Immutable audit trail
|
| 1070 |
+
- Compliance reporting
|
| 1071 |
+
|
| 1072 |
+
**Logged Operations:**
|
| 1073 |
+
```python
|
| 1074 |
+
# Financial Operations
|
| 1075 |
+
- Payment processing
|
| 1076 |
+
- Payroll generation
|
| 1077 |
+
- Expense approval
|
| 1078 |
+
- Invoice creation
|
| 1079 |
+
|
| 1080 |
+
# Security Operations
|
| 1081 |
+
- User login/logout
|
| 1082 |
+
- Role changes
|
| 1083 |
+
- Permission grants
|
| 1084 |
+
- Password changes
|
| 1085 |
+
|
| 1086 |
+
# Data Operations
|
| 1087 |
+
- Record deletion
|
| 1088 |
+
- Bulk updates
|
| 1089 |
+
- Data exports
|
| 1090 |
+
- Configuration changes
|
| 1091 |
+
```
|
| 1092 |
+
|
| 1093 |
+
**Implementation:**
|
| 1094 |
+
```python
|
| 1095 |
+
# app/models/audit_log.py
|
| 1096 |
+
class AuditLog(Base):
|
| 1097 |
+
id = Column(UUID, primary_key=True)
|
| 1098 |
+
user_id = Column(UUID, nullable=False)
|
| 1099 |
+
action = Column(String(100), nullable=False)
|
| 1100 |
+
entity_type = Column(String(50), nullable=False)
|
| 1101 |
+
entity_id = Column(UUID, nullable=True)
|
| 1102 |
+
old_values = Column(JSONB, nullable=True)
|
| 1103 |
+
new_values = Column(JSONB, nullable=True)
|
| 1104 |
+
ip_address = Column(String(45), nullable=True)
|
| 1105 |
+
user_agent = Column(Text, nullable=True)
|
| 1106 |
+
created_at = Column(DateTime, nullable=False)
|
| 1107 |
+
|
| 1108 |
+
# app/services/audit_service.py
|
| 1109 |
+
def log_action(user_id, action, entity_type, entity_id, old_values, new_values):
|
| 1110 |
+
audit_log = AuditLog(
|
| 1111 |
+
user_id=user_id,
|
| 1112 |
+
action=action,
|
| 1113 |
+
entity_type=entity_type,
|
| 1114 |
+
entity_id=entity_id,
|
| 1115 |
+
old_values=old_values,
|
| 1116 |
+
new_values=new_values,
|
| 1117 |
+
ip_address=request.client.host,
|
| 1118 |
+
user_agent=request.headers.get("user-agent"),
|
| 1119 |
+
created_at=datetime.utcnow()
|
| 1120 |
+
)
|
| 1121 |
+
db.add(audit_log)
|
| 1122 |
+
db.commit()
|
| 1123 |
+
```
|
| 1124 |
+
|
| 1125 |
+
**Endpoints:**
|
| 1126 |
+
```
|
| 1127 |
+
GET /api/v1/audit-logs
|
| 1128 |
+
GET /api/v1/audit-logs/user/{user_id}
|
| 1129 |
+
GET /api/v1/audit-logs/entity/{entity_type}/{entity_id}
|
| 1130 |
+
POST /api/v1/audit-logs/export
|
| 1131 |
+
```
|
| 1132 |
+
|
| 1133 |
+
### 10.4 Data Encryption
|
| 1134 |
+
|
| 1135 |
+
**Responsibilities:**
|
| 1136 |
+
- Encrypt sensitive data at rest
|
| 1137 |
+
- Encrypt data in transit (HTTPS)
|
| 1138 |
+
- Encrypt database backups
|
| 1139 |
+
- Secure key management
|
| 1140 |
+
|
| 1141 |
+
**Encrypted Fields:**
|
| 1142 |
+
```python
|
| 1143 |
+
# User Data
|
| 1144 |
+
- Financial account numbers
|
| 1145 |
+
- ID numbers
|
| 1146 |
+
- Tax information
|
| 1147 |
+
|
| 1148 |
+
# Payment Data
|
| 1149 |
+
- M-Pesa transaction details
|
| 1150 |
+
- Bank account numbers
|
| 1151 |
+
|
| 1152 |
+
# Sensitive Documents
|
| 1153 |
+
- Contracts
|
| 1154 |
+
- Legal documents
|
| 1155 |
+
```
|
| 1156 |
+
|
| 1157 |
+
**Implementation:**
|
| 1158 |
+
```python
|
| 1159 |
+
# app/utils/encryption.py
|
| 1160 |
+
from cryptography.fernet import Fernet
|
| 1161 |
+
|
| 1162 |
+
def encrypt_field(value: str) -> str:
|
| 1163 |
+
cipher = Fernet(ENCRYPTION_KEY)
|
| 1164 |
+
return cipher.encrypt(value.encode()).decode()
|
| 1165 |
+
|
| 1166 |
+
def decrypt_field(encrypted_value: str) -> str:
|
| 1167 |
+
cipher = Fernet(ENCRYPTION_KEY)
|
| 1168 |
+
return cipher.decrypt(encrypted_value.encode()).decode()
|
| 1169 |
+
```
|
| 1170 |
+
|
| 1171 |
+
---
|
| 1172 |
+
|
| 1173 |
+
## 11. 🔄 Data Synchronization & Caching
|
| 1174 |
+
|
| 1175 |
+
### 11.1 Redis Caching Strategy
|
| 1176 |
+
|
| 1177 |
+
**Responsibilities:**
|
| 1178 |
+
- Cache frequently accessed data
|
| 1179 |
+
- Reduce database load
|
| 1180 |
+
- Improve response times
|
| 1181 |
+
- Invalidate cache on updates
|
| 1182 |
+
|
| 1183 |
+
**Cached Data:**
|
| 1184 |
+
```python
|
| 1185 |
+
# User Sessions (TTL: 24 hours)
|
| 1186 |
+
cache_key = f"user_session:{user_id}"
|
| 1187 |
+
|
| 1188 |
+
# Dashboard Metrics (TTL: 5 minutes)
|
| 1189 |
+
cache_key = f"dashboard_metrics:{project_id}"
|
| 1190 |
+
|
| 1191 |
+
# Project Settings (TTL: 1 hour)
|
| 1192 |
+
cache_key = f"project_settings:{project_id}"
|
| 1193 |
+
|
| 1194 |
+
# Agent Locations (TTL: 1 minute)
|
| 1195 |
+
cache_key = f"agent_location:{agent_id}"
|
| 1196 |
+
|
| 1197 |
+
# SLA Thresholds (TTL: 1 hour)
|
| 1198 |
+
cache_key = f"sla_thresholds:{project_id}"
|
| 1199 |
+
```
|
| 1200 |
+
|
| 1201 |
+
**Implementation:**
|
| 1202 |
+
```python
|
| 1203 |
+
# app/utils/cache.py
|
| 1204 |
+
from redis import Redis
|
| 1205 |
+
import json
|
| 1206 |
+
|
| 1207 |
+
redis_client = Redis.from_url(REDIS_URL)
|
| 1208 |
+
|
| 1209 |
+
def cache_get(key: str):
|
| 1210 |
+
value = redis_client.get(key)
|
| 1211 |
+
return json.loads(value) if value else None
|
| 1212 |
+
|
| 1213 |
+
def cache_set(key: str, value: any, ttl: int = 300):
|
| 1214 |
+
redis_client.setex(key, ttl, json.dumps(value))
|
| 1215 |
+
|
| 1216 |
+
def cache_delete(key: str):
|
| 1217 |
+
redis_client.delete(key)
|
| 1218 |
+
|
| 1219 |
+
def cache_delete_pattern(pattern: str):
|
| 1220 |
+
keys = redis_client.keys(pattern)
|
| 1221 |
+
if keys:
|
| 1222 |
+
redis_client.delete(*keys)
|
| 1223 |
+
```
|
| 1224 |
+
|
| 1225 |
+
### 11.2 Cache Invalidation
|
| 1226 |
+
|
| 1227 |
+
**Responsibilities:**
|
| 1228 |
+
- Invalidate cache when data changes
|
| 1229 |
+
- Support pattern-based invalidation
|
| 1230 |
+
- Prevent stale data
|
| 1231 |
+
|
| 1232 |
+
**Invalidation Triggers:**
|
| 1233 |
+
```python
|
| 1234 |
+
# Ticket updated → Invalidate ticket cache + dashboard cache
|
| 1235 |
+
cache_delete(f"ticket:{ticket_id}")
|
| 1236 |
+
cache_delete_pattern(f"dashboard_metrics:{project_id}*")
|
| 1237 |
+
|
| 1238 |
+
# User role changed → Invalidate user session
|
| 1239 |
+
cache_delete(f"user_session:{user_id}")
|
| 1240 |
+
|
| 1241 |
+
# Project settings updated → Invalidate project cache
|
| 1242 |
+
cache_delete(f"project_settings:{project_id}")
|
| 1243 |
+
```
|
| 1244 |
+
|
| 1245 |
+
### 11.3 Database Query Optimization
|
| 1246 |
+
|
| 1247 |
+
**Responsibilities:**
|
| 1248 |
+
- Use database indexes effectively
|
| 1249 |
+
- Optimize N+1 queries with eager loading
|
| 1250 |
+
- Use database views for complex queries
|
| 1251 |
+
- Implement query result caching
|
| 1252 |
+
|
| 1253 |
+
**Implementation:**
|
| 1254 |
+
```python
|
| 1255 |
+
# app/repositories/ticket_repository.py
|
| 1256 |
+
def get_tickets_with_relations(project_id):
|
| 1257 |
+
# Use eager loading to prevent N+1 queries
|
| 1258 |
+
return db.query(Ticket)\
|
| 1259 |
+
.options(
|
| 1260 |
+
joinedload(Ticket.customer),
|
| 1261 |
+
joinedload(Ticket.assigned_agent),
|
| 1262 |
+
joinedload(Ticket.project)
|
| 1263 |
+
)\
|
| 1264 |
+
.filter(Ticket.project_id == project_id)\
|
| 1265 |
+
.all()
|
| 1266 |
+
```
|
| 1267 |
+
|
| 1268 |
+
---
|
| 1269 |
+
|
| 1270 |
+
## 12. 📱 Mobile API Optimizations
|
| 1271 |
+
|
| 1272 |
+
### 12.1 Lightweight Responses
|
| 1273 |
+
|
| 1274 |
+
**Responsibilities:**
|
| 1275 |
+
- Return only necessary fields for mobile
|
| 1276 |
+
- Support field selection (?fields=id,title,status)
|
| 1277 |
+
- Compress responses (gzip)
|
| 1278 |
+
- Optimize image URLs (thumbnails)
|
| 1279 |
+
|
| 1280 |
+
**Implementation:**
|
| 1281 |
+
```python
|
| 1282 |
+
# app/api/v1/tickets.py
|
| 1283 |
+
@router.get("/tickets/{ticket_id}")
|
| 1284 |
+
async def get_ticket(
|
| 1285 |
+
ticket_id: UUID,
|
| 1286 |
+
fields: Optional[str] = None
|
| 1287 |
+
):
|
| 1288 |
+
ticket = ticket_service.get_ticket(ticket_id)
|
| 1289 |
+
|
| 1290 |
+
if fields:
|
| 1291 |
+
# Return only requested fields
|
| 1292 |
+
field_list = fields.split(',')
|
| 1293 |
+
return {k: v for k, v in ticket.dict().items() if k in field_list}
|
| 1294 |
+
|
| 1295 |
+
return ticket
|
| 1296 |
+
```
|
| 1297 |
+
|
| 1298 |
+
### 12.2 Offline Support
|
| 1299 |
+
|
| 1300 |
+
**Responsibilities:**
|
| 1301 |
+
- Queue operations when offline
|
| 1302 |
+
- Sync when connection restored
|
| 1303 |
+
- Handle conflicts (optimistic locking)
|
| 1304 |
+
- Provide offline-first endpoints
|
| 1305 |
+
|
| 1306 |
+
**Offline Operations:**
|
| 1307 |
+
```python
|
| 1308 |
+
# Operations that work offline (queued)
|
| 1309 |
+
- Update ticket status
|
| 1310 |
+
- Log expenses
|
| 1311 |
+
- Add photos
|
| 1312 |
+
- Record location updates
|
| 1313 |
+
- Clock in/out
|
| 1314 |
+
|
| 1315 |
+
# Operations that require online
|
| 1316 |
+
- Create new tickets
|
| 1317 |
+
- Assign tickets
|
| 1318 |
+
- Process payments
|
| 1319 |
+
- Generate reports
|
| 1320 |
+
```
|
| 1321 |
+
|
| 1322 |
+
**Sync Endpoint:**
|
| 1323 |
+
```
|
| 1324 |
+
POST /api/v1/sync/queue
|
| 1325 |
+
```
|
| 1326 |
+
|
| 1327 |
+
**Request:**
|
| 1328 |
+
```json
|
| 1329 |
+
{
|
| 1330 |
+
"operations": [
|
| 1331 |
+
{
|
| 1332 |
+
"id": "local_uuid_1",
|
| 1333 |
+
"type": "update_ticket_status",
|
| 1334 |
+
"entity_id": "ticket_uuid",
|
| 1335 |
+
"data": {"status": "in_progress"},
|
| 1336 |
+
"timestamp": "2024-01-15T10:30:00Z"
|
| 1337 |
+
},
|
| 1338 |
+
{
|
| 1339 |
+
"id": "local_uuid_2",
|
| 1340 |
+
"type": "log_expense",
|
| 1341 |
+
"entity_id": "ticket_uuid",
|
| 1342 |
+
"data": {"amount": 500, "category": "transport"},
|
| 1343 |
+
"timestamp": "2024-01-15T11:00:00Z"
|
| 1344 |
+
}
|
| 1345 |
+
]
|
| 1346 |
+
}
|
| 1347 |
+
```
|
| 1348 |
+
|
| 1349 |
+
**Response:**
|
| 1350 |
+
```json
|
| 1351 |
+
{
|
| 1352 |
+
"success": true,
|
| 1353 |
+
"results": [
|
| 1354 |
+
{
|
| 1355 |
+
"local_id": "local_uuid_1",
|
| 1356 |
+
"status": "success",
|
| 1357 |
+
"server_id": "ticket_uuid"
|
| 1358 |
+
},
|
| 1359 |
+
{
|
| 1360 |
+
"local_id": "local_uuid_2",
|
| 1361 |
+
"status": "conflict",
|
| 1362 |
+
"error": "Ticket already completed by another user",
|
| 1363 |
+
"server_data": {...}
|
| 1364 |
+
}
|
| 1365 |
+
]
|
| 1366 |
+
}
|
| 1367 |
+
```
|
| 1368 |
+
|
| 1369 |
+
### 12.3 Data Compression
|
| 1370 |
+
|
| 1371 |
+
**Responsibilities:**
|
| 1372 |
+
- Compress API responses (gzip)
|
| 1373 |
+
- Optimize JSON payloads
|
| 1374 |
+
- Use efficient data formats
|
| 1375 |
+
- Support delta updates
|
| 1376 |
+
|
| 1377 |
+
**Implementation:**
|
| 1378 |
+
```python
|
| 1379 |
+
# app/middleware/compression.py
|
| 1380 |
+
from fastapi.middleware.gzip import GZipMiddleware
|
| 1381 |
+
|
| 1382 |
+
app.add_middleware(GZipMiddleware, minimum_size=1000)
|
| 1383 |
+
```
|
| 1384 |
+
|
| 1385 |
+
---
|
| 1386 |
+
|
| 1387 |
+
## 13. 🔧 Background Jobs & Scheduled Tasks
|
| 1388 |
+
|
| 1389 |
+
### 13.1 Scheduled Tasks (Celery Beat)
|
| 1390 |
+
|
| 1391 |
+
**Daily Tasks:**
|
| 1392 |
+
```python
|
| 1393 |
+
# Midnight (00:00)
|
| 1394 |
+
- compute_daily_metrics()
|
| 1395 |
+
- cleanup_old_exports()
|
| 1396 |
+
- archive_old_logs()
|
| 1397 |
+
- send_daily_summary_reports()
|
| 1398 |
+
|
| 1399 |
+
# 6:00 AM
|
| 1400 |
+
- check_sla_violations()
|
| 1401 |
+
- send_morning_briefing_to_managers()
|
| 1402 |
+
|
| 1403 |
+
# Every Hour
|
| 1404 |
+
- monitor_sla_deadlines()
|
| 1405 |
+
- sync_payment_statuses()
|
| 1406 |
+
- cleanup_expired_otps()
|
| 1407 |
+
```
|
| 1408 |
+
|
| 1409 |
+
**Weekly Tasks:**
|
| 1410 |
+
```python
|
| 1411 |
+
# Friday 6:00 PM
|
| 1412 |
+
- generate_weekly_payroll()
|
| 1413 |
+
- send_payroll_notifications()
|
| 1414 |
+
|
| 1415 |
+
# Sunday 11:00 PM
|
| 1416 |
+
- generate_weekly_reports()
|
| 1417 |
+
- send_weekly_summary_to_admins()
|
| 1418 |
+
```
|
| 1419 |
+
|
| 1420 |
+
**Monthly Tasks:**
|
| 1421 |
+
```python
|
| 1422 |
+
# Last day of month
|
| 1423 |
+
- generate_contractor_invoices()
|
| 1424 |
+
- generate_monthly_reports()
|
| 1425 |
+
- archive_old_data()
|
| 1426 |
+
```
|
| 1427 |
+
|
| 1428 |
+
**Implementation:**
|
| 1429 |
+
```python
|
| 1430 |
+
# app/tasks/celery_app.py
|
| 1431 |
+
from celery.schedules import crontab
|
| 1432 |
+
|
| 1433 |
+
celery_app.conf.beat_schedule = {
|
| 1434 |
+
'generate-weekly-payroll': {
|
| 1435 |
+
'task': 'app.tasks.payroll_tasks.generate_weekly_payroll',
|
| 1436 |
+
'schedule': crontab(day_of_week=5, hour=18, minute=0),
|
| 1437 |
+
},
|
| 1438 |
+
'monitor-sla-violations': {
|
| 1439 |
+
'task': 'app.tasks.sla_tasks.monitor_sla_violations',
|
| 1440 |
+
'schedule': crontab(minute=0), # Every hour
|
| 1441 |
+
},
|
| 1442 |
+
'compute-daily-metrics': {
|
| 1443 |
+
'task': 'app.tasks.analytics_tasks.compute_daily_metrics',
|
| 1444 |
+
'schedule': crontab(hour=0, minute=0), # Midnight
|
| 1445 |
+
},
|
| 1446 |
+
}
|
| 1447 |
+
```
|
| 1448 |
+
|
| 1449 |
+
### 13.2 Async Task Processing
|
| 1450 |
+
|
| 1451 |
+
**Long-Running Tasks:**
|
| 1452 |
+
```python
|
| 1453 |
+
# CSV Import (10,000+ rows)
|
| 1454 |
+
- Parse and validate CSV
|
| 1455 |
+
- Create records in batches
|
| 1456 |
+
- Generate import report
|
| 1457 |
+
|
| 1458 |
+
# Report Generation
|
| 1459 |
+
- Query large datasets
|
| 1460 |
+
- Generate Excel/PDF
|
| 1461 |
+
- Upload to storage
|
| 1462 |
+
- Send download link
|
| 1463 |
+
|
| 1464 |
+
# Bulk Operations
|
| 1465 |
+
- Bulk ticket assignment
|
| 1466 |
+
- Bulk payment processing
|
| 1467 |
+
- Bulk email sending
|
| 1468 |
+
```
|
| 1469 |
+
|
| 1470 |
+
**Implementation:**
|
| 1471 |
+
```python
|
| 1472 |
+
# app/tasks/import_tasks.py
|
| 1473 |
+
@celery_app.task(bind=True)
|
| 1474 |
+
def import_sales_orders_task(self, import_id, file_path):
|
| 1475 |
+
try:
|
| 1476 |
+
# Update progress
|
| 1477 |
+
self.update_state(state='PROGRESS', meta={'progress': 0})
|
| 1478 |
+
|
| 1479 |
+
# Process CSV
|
| 1480 |
+
results = process_csv(file_path)
|
| 1481 |
+
|
| 1482 |
+
# Update progress
|
| 1483 |
+
self.update_state(state='PROGRESS', meta={'progress': 50})
|
| 1484 |
+
|
| 1485 |
+
# Create records
|
| 1486 |
+
create_records(results)
|
| 1487 |
+
|
| 1488 |
+
# Update progress
|
| 1489 |
+
self.update_state(state='PROGRESS', meta={'progress': 100})
|
| 1490 |
+
|
| 1491 |
+
return {'status': 'completed', 'imported': len(results)}
|
| 1492 |
+
except Exception as e:
|
| 1493 |
+
self.update_state(state='FAILURE', meta={'error': str(e)})
|
| 1494 |
+
raise
|
| 1495 |
+
```
|
| 1496 |
+
|
| 1497 |
+
**Task Status Endpoint:**
|
| 1498 |
+
```
|
| 1499 |
+
GET /api/v1/tasks/{task_id}/status
|
| 1500 |
+
```
|
| 1501 |
+
|
| 1502 |
+
**Response:**
|
| 1503 |
+
```json
|
| 1504 |
+
{
|
| 1505 |
+
"task_id": "uuid",
|
| 1506 |
+
"status": "PROGRESS",
|
| 1507 |
+
"progress": 50,
|
| 1508 |
+
"result": null,
|
| 1509 |
+
"error": null
|
| 1510 |
+
}
|
| 1511 |
+
```
|
| 1512 |
+
|
| 1513 |
+
---
|
| 1514 |
+
|
| 1515 |
+
## 14. 🌐 External Service Integrations
|
| 1516 |
+
|
| 1517 |
+
### 14.1 Supabase Integration
|
| 1518 |
+
|
| 1519 |
+
**Services Used:**
|
| 1520 |
+
- **Auth**: User authentication and JWT tokens
|
| 1521 |
+
- **Database**: PostgreSQL with Row-Level Security
|
| 1522 |
+
- **Storage**: File uploads (documents, receipts)
|
| 1523 |
+
- **Realtime**: WebSocket subscriptions (optional)
|
| 1524 |
+
|
| 1525 |
+
**Implementation:**
|
| 1526 |
+
```python
|
| 1527 |
+
# app/integrations/supabase.py
|
| 1528 |
+
from supabase import create_client
|
| 1529 |
+
|
| 1530 |
+
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 1531 |
+
|
| 1532 |
+
# Auth
|
| 1533 |
+
def verify_supabase_token(token):
|
| 1534 |
+
return supabase.auth.get_user(token)
|
| 1535 |
+
|
| 1536 |
+
# Storage
|
| 1537 |
+
def upload_to_supabase_storage(file, bucket, path):
|
| 1538 |
+
return supabase.storage.from_(bucket).upload(path, file)
|
| 1539 |
+
|
| 1540 |
+
# Database (for simple queries)
|
| 1541 |
+
def query_supabase(table, filters):
|
| 1542 |
+
return supabase.table(table).select('*').match(filters).execute()
|
| 1543 |
+
```
|
| 1544 |
+
|
| 1545 |
+
### 14.2 Cloudinary Integration
|
| 1546 |
+
|
| 1547 |
+
**Services Used:**
|
| 1548 |
+
- Image uploads
|
| 1549 |
+
- Image transformations
|
| 1550 |
+
- CDN delivery
|
| 1551 |
+
- Video uploads (future)
|
| 1552 |
+
|
| 1553 |
+
**Implementation:**
|
| 1554 |
+
```python
|
| 1555 |
+
# app/integrations/cloudinary.py
|
| 1556 |
+
import cloudinary
|
| 1557 |
+
import cloudinary.uploader
|
| 1558 |
+
|
| 1559 |
+
cloudinary.config(
|
| 1560 |
+
cloud_name=CLOUDINARY_CLOUD_NAME,
|
| 1561 |
+
api_key=CLOUDINARY_API_KEY,
|
| 1562 |
+
api_secret=CLOUDINARY_API_SECRET
|
| 1563 |
+
)
|
| 1564 |
+
|
| 1565 |
+
def upload_image(file, folder, public_id=None):
|
| 1566 |
+
result = cloudinary.uploader.upload(
|
| 1567 |
+
file,
|
| 1568 |
+
folder=folder,
|
| 1569 |
+
public_id=public_id,
|
| 1570 |
+
resource_type="image",
|
| 1571 |
+
transformation=[
|
| 1572 |
+
{'width': 1920, 'height': 1080, 'crop': 'limit'},
|
| 1573 |
+
{'quality': 'auto'},
|
| 1574 |
+
{'fetch_format': 'auto'}
|
| 1575 |
+
]
|
| 1576 |
+
)
|
| 1577 |
+
return result['secure_url']
|
| 1578 |
+
```
|
| 1579 |
+
|
| 1580 |
+
### 14.3 M-Pesa Integration
|
| 1581 |
+
|
| 1582 |
+
**Services Used:**
|
| 1583 |
+
- B2C payments (business to customer)
|
| 1584 |
+
- Payment status queries
|
| 1585 |
+
- Transaction callbacks
|
| 1586 |
+
|
| 1587 |
+
**Implementation:**
|
| 1588 |
+
```python
|
| 1589 |
+
# app/integrations/mpesa.py
|
| 1590 |
+
import requests
|
| 1591 |
+
import base64
|
| 1592 |
+
|
| 1593 |
+
def get_mpesa_access_token():
|
| 1594 |
+
url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"
|
| 1595 |
+
response = requests.get(url, auth=(MPESA_CONSUMER_KEY, MPESA_CONSUMER_SECRET))
|
| 1596 |
+
return response.json()['access_token']
|
| 1597 |
+
|
| 1598 |
+
def initiate_b2c_payment(phone_number, amount, remarks):
|
| 1599 |
+
access_token = get_mpesa_access_token()
|
| 1600 |
+
|
| 1601 |
+
payload = {
|
| 1602 |
+
"InitiatorName": MPESA_INITIATOR_NAME,
|
| 1603 |
+
"SecurityCredential": MPESA_SECURITY_CREDENTIAL,
|
| 1604 |
+
"CommandID": "BusinessPayment",
|
| 1605 |
+
"Amount": amount,
|
| 1606 |
+
"PartyA": MPESA_SHORTCODE,
|
| 1607 |
+
"PartyB": phone_number,
|
| 1608 |
+
"Remarks": remarks,
|
| 1609 |
+
"QueueTimeOutURL": f"{API_BASE_URL}/webhooks/mpesa/timeout",
|
| 1610 |
+
"ResultURL": f"{API_BASE_URL}/webhooks/mpesa/result",
|
| 1611 |
+
"Occasion": ""
|
| 1612 |
+
}
|
| 1613 |
+
|
| 1614 |
+
headers = {"Authorization": f"Bearer {access_token}"}
|
| 1615 |
+
response = requests.post(MPESA_B2C_URL, json=payload, headers=headers)
|
| 1616 |
+
return response.json()
|
| 1617 |
+
```
|
| 1618 |
+
|
| 1619 |
+
### 14.4 Resend Integration
|
| 1620 |
+
|
| 1621 |
+
**Services Used:**
|
| 1622 |
+
- Transactional emails
|
| 1623 |
+
- Email templates
|
| 1624 |
+
- Delivery tracking
|
| 1625 |
+
|
| 1626 |
+
**Implementation:**
|
| 1627 |
+
```python
|
| 1628 |
+
# app/integrations/resend.py
|
| 1629 |
+
import resend
|
| 1630 |
+
|
| 1631 |
+
resend.api_key = RESEND_API_KEY
|
| 1632 |
+
|
| 1633 |
+
def send_email(to, subject, html):
|
| 1634 |
+
return resend.Emails.send({
|
| 1635 |
+
"from": "SwiftOps <noreply@swiftops.com>",
|
| 1636 |
+
"to": to,
|
| 1637 |
+
"subject": subject,
|
| 1638 |
+
"html": html
|
| 1639 |
+
})
|
| 1640 |
+
|
| 1641 |
+
def send_templated_email(to, template_id, variables):
|
| 1642 |
+
return resend.Emails.send({
|
| 1643 |
+
"from": "SwiftOps <noreply@swiftops.com>",
|
| 1644 |
+
"to": to,
|
| 1645 |
+
"template_id": template_id,
|
| 1646 |
+
"template_data": variables
|
| 1647 |
+
})
|
| 1648 |
+
```
|
| 1649 |
+
|
| 1650 |
+
### 14.5 Google Maps Integration
|
| 1651 |
+
|
| 1652 |
+
**Services Used:**
|
| 1653 |
+
- Geocoding (address → coordinates)
|
| 1654 |
+
- Reverse geocoding (coordinates → address)
|
| 1655 |
+
- Distance calculation
|
| 1656 |
+
- Directions API
|
| 1657 |
+
|
| 1658 |
+
**Implementation:**
|
| 1659 |
+
```python
|
| 1660 |
+
# app/integrations/google_maps.py
|
| 1661 |
+
import googlemaps
|
| 1662 |
+
|
| 1663 |
+
gmaps = googlemaps.Client(key=GOOGLE_MAPS_API_KEY)
|
| 1664 |
+
|
| 1665 |
+
def geocode_address(address):
|
| 1666 |
+
result = gmaps.geocode(address)
|
| 1667 |
+
if result:
|
| 1668 |
+
location = result[0]['geometry']['location']
|
| 1669 |
+
return location['lat'], location['lng']
|
| 1670 |
+
return None, None
|
| 1671 |
+
|
| 1672 |
+
def calculate_distance(origin, destination):
|
| 1673 |
+
result = gmaps.distance_matrix(origin, destination, mode="driving")
|
| 1674 |
+
if result['rows']:
|
| 1675 |
+
element = result['rows'][0]['elements'][0]
|
| 1676 |
+
return {
|
| 1677 |
+
'distance_meters': element['distance']['value'],
|
| 1678 |
+
'duration_seconds': element['duration']['value']
|
| 1679 |
+
}
|
| 1680 |
+
return None
|
| 1681 |
+
```
|
| 1682 |
+
|
| 1683 |
+
---
|
| 1684 |
+
|
| 1685 |
+
## 15. 📋 Implementation Priority
|
| 1686 |
+
|
| 1687 |
+
### Phase 1: Core Backend (Weeks 1-4)
|
| 1688 |
+
1. ✅ Authentication & JWT
|
| 1689 |
+
2. ✅ Supabase integration
|
| 1690 |
+
3. ✅ Basic CRUD operations
|
| 1691 |
+
4. ✅ Role-based access control
|
| 1692 |
+
5. ✅ Database models and migrations
|
| 1693 |
+
|
| 1694 |
+
### Phase 2: Essential Features (Weeks 5-8)
|
| 1695 |
+
1. 🔄 Email service (Resend)
|
| 1696 |
+
2. 🔄 OTP & 2FA
|
| 1697 |
+
3. 🔄 Media management (Cloudinary)
|
| 1698 |
+
4. 🔄 Payment processing (M-Pesa)
|
| 1699 |
+
5. 🔄 CSV import/export
|
| 1700 |
+
|
| 1701 |
+
### Phase 3: Advanced Features (Weeks 9-12)
|
| 1702 |
+
1. 📋 Queue management (Celery)
|
| 1703 |
+
2. 📋 Background tasks
|
| 1704 |
+
3. 📋 Caching (Redis)
|
| 1705 |
+
4. 📋 Filtering & search
|
| 1706 |
+
5. 📋 Optimistic locking
|
| 1707 |
+
|
| 1708 |
+
### Phase 4: V2 Features (Weeks 13-16)
|
| 1709 |
+
1. 📋 SMS service (Africa's Talking)
|
| 1710 |
+
2. 📋 Intelligent agent allocation
|
| 1711 |
+
3. 📋 Route optimization
|
| 1712 |
+
4. 📋 Health checks & monitoring
|
| 1713 |
+
5. 📋 Usage tracking
|
| 1714 |
+
|
| 1715 |
+
### Phase 5: Polish & Optimization (Weeks 17-20)
|
| 1716 |
+
1. 📋 Performance optimization
|
| 1717 |
+
2. 📋 Security hardening
|
| 1718 |
+
3. 📋 Documentation
|
| 1719 |
+
4. 📋 Testing (80% coverage)
|
| 1720 |
+
5. 📋 Deployment automation
|
| 1721 |
+
|
| 1722 |
+
---
|
| 1723 |
+
|
| 1724 |
+
## 16. 🔑 Environment Variables Required
|
| 1725 |
+
|
| 1726 |
+
```bash
|
| 1727 |
+
# Application
|
| 1728 |
+
APP_NAME=SwiftOps API
|
| 1729 |
+
DEBUG=False
|
| 1730 |
+
ENVIRONMENT=production
|
| 1731 |
+
SECRET_KEY=your-secret-key-here
|
| 1732 |
+
ALGORITHM=HS256
|
| 1733 |
+
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
| 1734 |
+
|
| 1735 |
+
# Database (Supabase)
|
| 1736 |
+
DATABASE_URL=postgresql://user:password@host:5432/dbname
|
| 1737 |
+
SUPABASE_URL=https://your-project.supabase.co
|
| 1738 |
+
SUPABASE_KEY=your-anon-key
|
| 1739 |
+
SUPABASE_SERVICE_KEY=your-service-role-key
|
| 1740 |
+
|
| 1741 |
+
# Redis
|
| 1742 |
+
REDIS_URL=redis://localhost:6379/0
|
| 1743 |
+
|
| 1744 |
+
# Celery
|
| 1745 |
+
CELERY_BROKER_URL=redis://localhost:6379/0
|
| 1746 |
+
CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
| 1747 |
+
|
| 1748 |
+
# Cloudinary
|
| 1749 |
+
CLOUDINARY_CLOUD_NAME=your-cloud-name
|
| 1750 |
+
CLOUDINARY_API_KEY=your-api-key
|
| 1751 |
+
CLOUDINARY_API_SECRET=your-api-secret
|
| 1752 |
+
|
| 1753 |
+
# M-Pesa
|
| 1754 |
+
MPESA_CONSUMER_KEY=your-mpesa-key
|
| 1755 |
+
MPESA_CONSUMER_SECRET=your-mpesa-secret
|
| 1756 |
+
MPESA_SHORTCODE=174379
|
| 1757 |
+
MPESA_PASSKEY=your-passkey
|
| 1758 |
+
MPESA_INITIATOR_NAME=your-initiator
|
| 1759 |
+
MPESA_SECURITY_CREDENTIAL=your-credential
|
| 1760 |
+
|
| 1761 |
+
# Resend
|
| 1762 |
+
RESEND_API_KEY=your-resend-key
|
| 1763 |
+
|
| 1764 |
+
# Africa's Talking (V2)
|
| 1765 |
+
AFRICASTALKING_USERNAME=your-username
|
| 1766 |
+
AFRICASTALKING_API_KEY=your-api-key
|
| 1767 |
+
|
| 1768 |
+
# Google Maps
|
| 1769 |
+
GOOGLE_MAPS_API_KEY=your-google-maps-key
|
| 1770 |
+
|
| 1771 |
+
# Monitoring (V2)
|
| 1772 |
+
SENTRY_DSN=your-sentry-dsn
|
| 1773 |
+
```
|
| 1774 |
+
|
| 1775 |
+
---
|
| 1776 |
+
|
| 1777 |
+
## 17. 📊 Success Metrics
|
| 1778 |
+
|
| 1779 |
+
### Technical Metrics
|
| 1780 |
+
- API response time < 200ms (p95)
|
| 1781 |
+
- Database query time < 50ms (p95)
|
| 1782 |
+
- Cache hit rate > 80%
|
| 1783 |
+
- Test coverage > 80%
|
| 1784 |
+
- Zero critical security vulnerabilities
|
| 1785 |
+
- 99.9% uptime
|
| 1786 |
+
|
| 1787 |
+
### Business Metrics
|
| 1788 |
+
- Support 1000+ concurrent field agents
|
| 1789 |
+
- Process 10,000+ tickets per month
|
| 1790 |
+
- Handle 500+ payroll payments per week
|
| 1791 |
+
- 95% SLA compliance rate
|
| 1792 |
+
- < 1% payment failure rate
|
| 1793 |
+
|
| 1794 |
+
---
|
| 1795 |
+
|
| 1796 |
+
## 18. 🚀 Deployment Checklist
|
| 1797 |
+
|
| 1798 |
+
### Pre-Deployment
|
| 1799 |
+
- [ ] All environment variables configured
|
| 1800 |
+
- [ ] Database migrations tested
|
| 1801 |
+
- [ ] Redis connection verified
|
| 1802 |
+
- [ ] Celery workers configured
|
| 1803 |
+
- [ ] External services tested (M-Pesa, Cloudinary, Resend)
|
| 1804 |
+
- [ ] SSL certificates configured
|
| 1805 |
+
- [ ] Monitoring setup (Sentry)
|
| 1806 |
+
- [ ] Backup strategy implemented
|
| 1807 |
+
|
| 1808 |
+
### Post-Deployment
|
| 1809 |
+
- [ ] Health checks passing
|
| 1810 |
+
- [ ] API documentation accessible
|
| 1811 |
+
- [ ] Webhooks configured
|
| 1812 |
+
- [ ] Scheduled tasks running
|
| 1813 |
+
- [ ] Logs being collected
|
| 1814 |
+
- [ ] Alerts configured
|
| 1815 |
+
- [ ] Performance monitoring active
|
| 1816 |
+
|
| 1817 |
+
---
|
| 1818 |
+
|
| 1819 |
+
**Document Version:** 1.0
|
| 1820 |
+
**Last Updated:** November 2025
|
| 1821 |
+
**Maintained By:** SwiftOps Backend Team
|
docs/prod/CREDENTIALS_SETUP_GUIDE.md
ADDED
|
@@ -0,0 +1,734 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SwiftOps Backend - Credentials & Services Setup Guide
|
| 2 |
+
|
| 3 |
+
**Version:** 1.0
|
| 4 |
+
**Last Updated:** November 2025
|
| 5 |
+
**Purpose:** Step-by-step guide to set up all external services and obtain required credentials
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Overview
|
| 10 |
+
|
| 11 |
+
This guide walks you through setting up all external services required for the SwiftOps backend. Follow each section in order to obtain all necessary API keys and credentials.
|
| 12 |
+
|
| 13 |
+
**Estimated Time:** 2-3 hours
|
| 14 |
+
**Cost:** Most services have free tiers suitable for development
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
## 1. 🗄️ Supabase (Database & Auth)
|
| 19 |
+
|
| 20 |
+
**What you need:**
|
| 21 |
+
- Database URL
|
| 22 |
+
- Anon Key (public)
|
| 23 |
+
- Service Role Key (private)
|
| 24 |
+
- JWT Secret
|
| 25 |
+
|
| 26 |
+
### Setup Steps:
|
| 27 |
+
|
| 28 |
+
1. **Create Account**
|
| 29 |
+
- Go to [https://supabase.com](https://supabase.com)
|
| 30 |
+
- Click "Start your project"
|
| 31 |
+
- Sign up with GitHub, Google, or email
|
| 32 |
+
|
| 33 |
+
2. **Create New Project**
|
| 34 |
+
- Click "New Project"
|
| 35 |
+
- Choose your organization (or create one)
|
| 36 |
+
- Fill in project details:
|
| 37 |
+
- **Name:** `swiftops-production` (or `swiftops-dev` for development)
|
| 38 |
+
- **Database Password:** Generate a strong password (save this!)
|
| 39 |
+
- **Region:** Choose closest to your users (e.g., `eu-west-1` for Europe)
|
| 40 |
+
- Click "Create new project"
|
| 41 |
+
- Wait 2-3 minutes for provisioning
|
| 42 |
+
|
| 43 |
+
3. **Get Database Credentials**
|
| 44 |
+
- Go to **Settings** → **Database**
|
| 45 |
+
- Under "Connection string", select **URI**
|
| 46 |
+
- Copy the connection string (looks like):
|
| 47 |
+
```
|
| 48 |
+
postgresql://postgres:[YOUR-PASSWORD]@db.xxxxx.supabase.co:5432/postgres
|
| 49 |
+
```
|
| 50 |
+
- Replace `[YOUR-PASSWORD]` with your database password
|
| 51 |
+
- Save as `DATABASE_URL`
|
| 52 |
+
|
| 53 |
+
4. **Get API Keys**
|
| 54 |
+
- Go to **Settings** → **API**
|
| 55 |
+
- Copy the following:
|
| 56 |
+
- **Project URL** → Save as `SUPABASE_URL`
|
| 57 |
+
- **anon public** key → Save as `SUPABASE_KEY`
|
| 58 |
+
- **service_role** key → Save as `SUPABASE_SERVICE_KEY` (⚠️ Keep secret!)
|
| 59 |
+
|
| 60 |
+
5. **Get JWT Secret**
|
| 61 |
+
- Still in **Settings** → **API**
|
| 62 |
+
- Scroll down to "JWT Settings"
|
| 63 |
+
- Copy **JWT Secret** → Save as `SUPABASE_JWT_SECRET`
|
| 64 |
+
|
| 65 |
+
6. **Configure Auth Providers** (Optional)
|
| 66 |
+
- Go to **Authentication** → **Providers**
|
| 67 |
+
- Enable email/password authentication
|
| 68 |
+
- Configure OAuth providers if needed (Google, GitHub, etc.)
|
| 69 |
+
|
| 70 |
+
### Environment Variables:
|
| 71 |
+
```bash
|
| 72 |
+
DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@db.xxxxx.supabase.co:5432/postgres
|
| 73 |
+
SUPABASE_URL=https://xxxxx.supabase.co
|
| 74 |
+
SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
| 75 |
+
SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
| 76 |
+
SUPABASE_JWT_SECRET=your-jwt-secret-here
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
---
|
| 80 |
+
|
| 81 |
+
## 2. ☁️ Cloudinary (Image Storage)
|
| 82 |
+
|
| 83 |
+
**What you need:**
|
| 84 |
+
- Cloud Name
|
| 85 |
+
- API Key
|
| 86 |
+
- API Secret
|
| 87 |
+
|
| 88 |
+
### Setup Steps:
|
| 89 |
+
|
| 90 |
+
1. **Create Account**
|
| 91 |
+
- Go to [https://cloudinary.com](https://cloudinary.com)
|
| 92 |
+
- Click "Sign Up Free"
|
| 93 |
+
- Sign up with email or Google
|
| 94 |
+
|
| 95 |
+
2. **Verify Email**
|
| 96 |
+
- Check your email for verification link
|
| 97 |
+
- Click to verify your account
|
| 98 |
+
|
| 99 |
+
3. **Get Credentials**
|
| 100 |
+
- After login, you'll see the **Dashboard**
|
| 101 |
+
- Find "Account Details" section (top right)
|
| 102 |
+
- Copy the following:
|
| 103 |
+
- **Cloud Name** → Save as `CLOUDINARY_CLOUD_NAME`
|
| 104 |
+
- **API Key** → Save as `CLOUDINARY_API_KEY`
|
| 105 |
+
- **API Secret** → Save as `CLOUDINARY_API_SECRET` (click "eye" icon to reveal)
|
| 106 |
+
|
| 107 |
+
4. **Configure Upload Settings** (Optional)
|
| 108 |
+
- Go to **Settings** → **Upload**
|
| 109 |
+
- Set upload presets if needed
|
| 110 |
+
- Configure folder structure:
|
| 111 |
+
- `/swiftops/tickets/`
|
| 112 |
+
- `/swiftops/users/`
|
| 113 |
+
- `/swiftops/receipts/`
|
| 114 |
+
|
| 115 |
+
5. **Set Up Transformations** (Optional)
|
| 116 |
+
- Go to **Settings** → **Upload**
|
| 117 |
+
- Create named transformations:
|
| 118 |
+
- `thumbnail`: 150x150, quality 80
|
| 119 |
+
- `medium`: 800x600, quality 85
|
| 120 |
+
- `large`: 1920x1080, quality 90
|
| 121 |
+
|
| 122 |
+
### Environment Variables:
|
| 123 |
+
```bash
|
| 124 |
+
CLOUDINARY_CLOUD_NAME=your-cloud-name
|
| 125 |
+
CLOUDINARY_API_KEY=123456789012345
|
| 126 |
+
CLOUDINARY_API_SECRET=abcdefghijklmnopqrstuvwxyz123456
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
### Free Tier Limits:
|
| 130 |
+
- 25 GB storage
|
| 131 |
+
- 25 GB bandwidth/month
|
| 132 |
+
- 25,000 transformations/month
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
## 3. 📧 Resend (Email Service)
|
| 137 |
+
|
| 138 |
+
**What you need:**
|
| 139 |
+
- API Key
|
| 140 |
+
- Verified domain (optional for production)
|
| 141 |
+
|
| 142 |
+
### Setup Steps:
|
| 143 |
+
|
| 144 |
+
1. **Create Account**
|
| 145 |
+
- Go to [https://resend.com](https://resend.com)
|
| 146 |
+
- Click "Get Started"
|
| 147 |
+
- Sign up with email or GitHub
|
| 148 |
+
|
| 149 |
+
2. **Verify Email**
|
| 150 |
+
- Check your email for verification link
|
| 151 |
+
- Click to verify
|
| 152 |
+
|
| 153 |
+
3. **Get API Key**
|
| 154 |
+
- After login, go to **API Keys**
|
| 155 |
+
- Click "Create API Key"
|
| 156 |
+
- Name it: `swiftops-production` (or `swiftops-dev`)
|
| 157 |
+
- Select permissions: **Full Access** (or **Sending access** only)
|
| 158 |
+
- Click "Create"
|
| 159 |
+
- Copy the API key (shown only once!) → Save as `RESEND_API_KEY`
|
| 160 |
+
|
| 161 |
+
4. **Add Domain** (For Production)
|
| 162 |
+
- Go to **Domains**
|
| 163 |
+
- Click "Add Domain"
|
| 164 |
+
- Enter your domain: `swiftops.com`
|
| 165 |
+
- Follow DNS verification steps:
|
| 166 |
+
- Add TXT record to your DNS
|
| 167 |
+
- Add CNAME records for DKIM
|
| 168 |
+
- Wait for verification (can take up to 48 hours)
|
| 169 |
+
|
| 170 |
+
5. **Test Email** (Development)
|
| 171 |
+
- For development, you can send from `onboarding@resend.dev`
|
| 172 |
+
- For production, use your verified domain: `noreply@swiftops.com`
|
| 173 |
+
|
| 174 |
+
### Environment Variables:
|
| 175 |
+
```bash
|
| 176 |
+
RESEND_API_KEY=re_123456789abcdefghijklmnop
|
| 177 |
+
FROM_EMAIL=noreply@swiftops.com
|
| 178 |
+
```
|
| 179 |
+
|
| 180 |
+
### Free Tier Limits:
|
| 181 |
+
- 100 emails/day
|
| 182 |
+
- 3,000 emails/month
|
| 183 |
+
|
| 184 |
+
---
|
| 185 |
+
|
| 186 |
+
## 4. 💳 M-Pesa (Payment Gateway) - Kenya
|
| 187 |
+
|
| 188 |
+
**What you need:**
|
| 189 |
+
- Consumer Key
|
| 190 |
+
- Consumer Secret
|
| 191 |
+
- Shortcode
|
| 192 |
+
- Passkey
|
| 193 |
+
- Initiator Name
|
| 194 |
+
- Security Credential
|
| 195 |
+
|
| 196 |
+
### Setup Steps:
|
| 197 |
+
|
| 198 |
+
1. **Create Safaricom Developer Account**
|
| 199 |
+
- Go to [https://developer.safaricom.co.ke](https://developer.safaricom.co.ke)
|
| 200 |
+
- Click "Sign Up"
|
| 201 |
+
- Fill in your details
|
| 202 |
+
- Verify your email
|
| 203 |
+
|
| 204 |
+
2. **Create App (Sandbox)**
|
| 205 |
+
- Login to developer portal
|
| 206 |
+
- Go to **My Apps**
|
| 207 |
+
- Click "Create App"
|
| 208 |
+
- Fill in details:
|
| 209 |
+
- **App Name:** SwiftOps Backend
|
| 210 |
+
- **Description:** Field service management platform
|
| 211 |
+
- Select APIs:
|
| 212 |
+
- ✅ M-Pesa Sandbox
|
| 213 |
+
- ✅ M-Pesa B2C (Business to Customer)
|
| 214 |
+
- Click "Create App"
|
| 215 |
+
|
| 216 |
+
3. **Get Sandbox Credentials**
|
| 217 |
+
- Go to your app details
|
| 218 |
+
- Under "Keys", copy:
|
| 219 |
+
- **Consumer Key** → Save as `MPESA_CONSUMER_KEY`
|
| 220 |
+
- **Consumer Secret** → Save as `MPESA_CONSUMER_SECRET`
|
| 221 |
+
|
| 222 |
+
4. **Get Test Credentials**
|
| 223 |
+
- Go to **Test Credentials** tab
|
| 224 |
+
- Copy the following:
|
| 225 |
+
- **Shortcode** → Save as `MPESA_SHORTCODE` (usually `174379` for sandbox)
|
| 226 |
+
- **Passkey** → Save as `MPESA_PASSKEY`
|
| 227 |
+
- **Initiator Name** → Save as `MPESA_INITIATOR_NAME` (usually `testapi`)
|
| 228 |
+
- **Security Credential** → Save as `MPESA_SECURITY_CREDENTIAL`
|
| 229 |
+
|
| 230 |
+
5. **Configure Callback URLs**
|
| 231 |
+
- In your app settings, add callback URLs:
|
| 232 |
+
- **Validation URL:** `https://your-api.com/api/v1/webhooks/mpesa/validation`
|
| 233 |
+
- **Confirmation URL:** `https://your-api.com/api/v1/webhooks/mpesa/confirmation`
|
| 234 |
+
- **Result URL:** `https://your-api.com/api/v1/webhooks/mpesa/result`
|
| 235 |
+
- **Timeout URL:** `https://your-api.com/api/v1/webhooks/mpesa/timeout`
|
| 236 |
+
|
| 237 |
+
6. **Go Live (Production)**
|
| 238 |
+
- Once tested, apply for production access
|
| 239 |
+
- Go to **Go Live** section
|
| 240 |
+
- Fill in business details
|
| 241 |
+
- Submit for approval (takes 2-5 business days)
|
| 242 |
+
- Once approved, get production credentials
|
| 243 |
+
|
| 244 |
+
### Environment Variables:
|
| 245 |
+
```bash
|
| 246 |
+
# Sandbox
|
| 247 |
+
MPESA_ENVIRONMENT=sandbox
|
| 248 |
+
MPESA_CONSUMER_KEY=your-consumer-key
|
| 249 |
+
MPESA_CONSUMER_SECRET=your-consumer-secret
|
| 250 |
+
MPESA_SHORTCODE=174379
|
| 251 |
+
MPESA_PASSKEY=your-passkey
|
| 252 |
+
MPESA_INITIATOR_NAME=testapi
|
| 253 |
+
MPESA_SECURITY_CREDENTIAL=your-security-credential
|
| 254 |
+
|
| 255 |
+
# Production (after approval)
|
| 256 |
+
MPESA_ENVIRONMENT=production
|
| 257 |
+
MPESA_CONSUMER_KEY=your-prod-consumer-key
|
| 258 |
+
MPESA_CONSUMER_SECRET=your-prod-consumer-secret
|
| 259 |
+
MPESA_SHORTCODE=your-business-shortcode
|
| 260 |
+
MPESA_PASSKEY=your-prod-passkey
|
| 261 |
+
MPESA_INITIATOR_NAME=your-initiator-name
|
| 262 |
+
MPESA_SECURITY_CREDENTIAL=your-prod-security-credential
|
| 263 |
+
```
|
| 264 |
+
|
| 265 |
+
### Important Notes:
|
| 266 |
+
- Sandbox is for testing only (uses test phone numbers)
|
| 267 |
+
- Production requires business registration and approval
|
| 268 |
+
- Keep security credentials encrypted and secure
|
| 269 |
+
|
| 270 |
+
---
|
| 271 |
+
|
| 272 |
+
## 5. 📱 Africa's Talking (SMS Service) - V2 Feature
|
| 273 |
+
|
| 274 |
+
**What you need:**
|
| 275 |
+
- Username
|
| 276 |
+
- API Key
|
| 277 |
+
|
| 278 |
+
### Setup Steps:
|
| 279 |
+
|
| 280 |
+
1. **Create Account**
|
| 281 |
+
- Go to [https://africastalking.com](https://africastalking.com)
|
| 282 |
+
- Click "Sign Up"
|
| 283 |
+
- Choose your country (Kenya, Uganda, etc.)
|
| 284 |
+
- Fill in your details
|
| 285 |
+
- Verify your email
|
| 286 |
+
|
| 287 |
+
2. **Get Sandbox Credentials**
|
| 288 |
+
- After login, go to **Sandbox**
|
| 289 |
+
- You'll see:
|
| 290 |
+
- **Username:** `sandbox` → Save as `AFRICASTALKING_USERNAME`
|
| 291 |
+
- **API Key:** Click "Generate" → Save as `AFRICASTALKING_API_KEY`
|
| 292 |
+
|
| 293 |
+
3. **Test SMS**
|
| 294 |
+
- In sandbox, you can only send to test numbers
|
| 295 |
+
- Add test numbers in **Sandbox** → **Simulator**
|
| 296 |
+
|
| 297 |
+
4. **Go Live (Production)**
|
| 298 |
+
- Go to **Go Live** section
|
| 299 |
+
- Fill in business details
|
| 300 |
+
- Add payment method
|
| 301 |
+
- Purchase SMS credits
|
| 302 |
+
- Get production credentials:
|
| 303 |
+
- **Username:** Your chosen username
|
| 304 |
+
- **API Key:** Generate new production key
|
| 305 |
+
|
| 306 |
+
### Environment Variables:
|
| 307 |
+
```bash
|
| 308 |
+
# Sandbox
|
| 309 |
+
AFRICASTALKING_USERNAME=sandbox
|
| 310 |
+
AFRICASTALKING_API_KEY=your-sandbox-api-key
|
| 311 |
+
AFRICASTALKING_ENVIRONMENT=sandbox
|
| 312 |
+
|
| 313 |
+
# Production
|
| 314 |
+
AFRICASTALKING_USERNAME=your-username
|
| 315 |
+
AFRICASTALKING_API_KEY=your-production-api-key
|
| 316 |
+
AFRICASTALKING_ENVIRONMENT=production
|
| 317 |
+
```
|
| 318 |
+
|
| 319 |
+
### Pricing (Kenya):
|
| 320 |
+
- KES 0.80 per SMS (local)
|
| 321 |
+
- Buy credits in bulk for discounts
|
| 322 |
+
|
| 323 |
+
---
|
| 324 |
+
|
| 325 |
+
## 6. 🗺️ Google Maps Platform
|
| 326 |
+
|
| 327 |
+
**What you need:**
|
| 328 |
+
- API Key with enabled services
|
| 329 |
+
|
| 330 |
+
### Setup Steps:
|
| 331 |
+
|
| 332 |
+
1. **Create Google Cloud Account**
|
| 333 |
+
- Go to [https://console.cloud.google.com](https://console.cloud.google.com)
|
| 334 |
+
- Sign in with Google account
|
| 335 |
+
- Accept terms of service
|
| 336 |
+
|
| 337 |
+
2. **Create New Project**
|
| 338 |
+
- Click project dropdown (top left)
|
| 339 |
+
- Click "New Project"
|
| 340 |
+
- Name: `swiftops-backend`
|
| 341 |
+
- Click "Create"
|
| 342 |
+
|
| 343 |
+
3. **Enable Billing**
|
| 344 |
+
- Go to **Billing**
|
| 345 |
+
- Click "Link a billing account"
|
| 346 |
+
- Add payment method (credit card)
|
| 347 |
+
- Note: Google gives $300 free credits for 90 days
|
| 348 |
+
|
| 349 |
+
4. **Enable APIs**
|
| 350 |
+
- Go to **APIs & Services** → **Library**
|
| 351 |
+
- Search and enable the following:
|
| 352 |
+
- ✅ **Maps JavaScript API**
|
| 353 |
+
- ✅ **Geocoding API**
|
| 354 |
+
- ✅ **Distance Matrix API**
|
| 355 |
+
- ✅ **Directions API**
|
| 356 |
+
- ✅ **Places API** (optional)
|
| 357 |
+
|
| 358 |
+
5. **Create API Key**
|
| 359 |
+
- Go to **APIs & Services** → **Credentials**
|
| 360 |
+
- Click "Create Credentials" → "API Key"
|
| 361 |
+
- Copy the API key → Save as `GOOGLE_MAPS_API_KEY`
|
| 362 |
+
|
| 363 |
+
6. **Restrict API Key** (Important!)
|
| 364 |
+
- Click on your API key to edit
|
| 365 |
+
- Under "Application restrictions":
|
| 366 |
+
- Select "IP addresses"
|
| 367 |
+
- Add your server IP addresses
|
| 368 |
+
- Under "API restrictions":
|
| 369 |
+
- Select "Restrict key"
|
| 370 |
+
- Select only the APIs you enabled
|
| 371 |
+
- Click "Save"
|
| 372 |
+
|
| 373 |
+
### Environment Variables:
|
| 374 |
+
```bash
|
| 375 |
+
GOOGLE_MAPS_API_KEY=AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
| 376 |
+
```
|
| 377 |
+
|
| 378 |
+
### Free Tier:
|
| 379 |
+
- $200 free credits per month
|
| 380 |
+
- Geocoding: $5 per 1,000 requests (40,000 free/month)
|
| 381 |
+
- Distance Matrix: $5 per 1,000 requests (40,000 free/month)
|
| 382 |
+
|
| 383 |
+
---
|
| 384 |
+
|
| 385 |
+
## 7. 🔴 Redis (Caching & Queue)
|
| 386 |
+
|
| 387 |
+
**What you need:**
|
| 388 |
+
- Redis URL
|
| 389 |
+
|
| 390 |
+
### Option A: Local Redis (Development)
|
| 391 |
+
|
| 392 |
+
1. **Install Redis**
|
| 393 |
+
- **Windows:** Download from [https://github.com/microsoftarchive/redis/releases](https://github.com/microsoftarchive/redis/releases)
|
| 394 |
+
- **Mac:** `brew install redis`
|
| 395 |
+
- **Linux:** `sudo apt-get install redis-server`
|
| 396 |
+
|
| 397 |
+
2. **Start Redis**
|
| 398 |
+
- **Windows:** Run `redis-server.exe`
|
| 399 |
+
- **Mac/Linux:** `redis-server`
|
| 400 |
+
|
| 401 |
+
3. **Test Connection**
|
| 402 |
+
```bash
|
| 403 |
+
redis-cli ping
|
| 404 |
+
# Should return: PONG
|
| 405 |
+
```
|
| 406 |
+
|
| 407 |
+
### Environment Variables:
|
| 408 |
+
```bash
|
| 409 |
+
REDIS_URL=redis://localhost:6379/0
|
| 410 |
+
```
|
| 411 |
+
|
| 412 |
+
### Option B: Redis Cloud (Production)
|
| 413 |
+
|
| 414 |
+
1. **Create Account**
|
| 415 |
+
- Go to [https://redis.com/try-free](https://redis.com/try-free)
|
| 416 |
+
- Sign up with email or Google
|
| 417 |
+
|
| 418 |
+
2. **Create Database**
|
| 419 |
+
- Click "New Database"
|
| 420 |
+
- Choose "Free" plan (30MB)
|
| 421 |
+
- Select region closest to your server
|
| 422 |
+
- Click "Create"
|
| 423 |
+
|
| 424 |
+
3. **Get Connection URL**
|
| 425 |
+
- Click on your database
|
| 426 |
+
- Copy "Public endpoint"
|
| 427 |
+
- Format: `redis://default:password@redis-12345.c1.us-east-1-2.ec2.cloud.redislabs.com:12345`
|
| 428 |
+
- Save as `REDIS_URL`
|
| 429 |
+
|
| 430 |
+
### Environment Variables:
|
| 431 |
+
```bash
|
| 432 |
+
REDIS_URL=redis://default:password@redis-12345.cloud.redislabs.com:12345
|
| 433 |
+
```
|
| 434 |
+
|
| 435 |
+
---
|
| 436 |
+
|
| 437 |
+
## 8. 📊 Sentry (Error Tracking) - Optional
|
| 438 |
+
|
| 439 |
+
**What you need:**
|
| 440 |
+
- DSN (Data Source Name)
|
| 441 |
+
|
| 442 |
+
### Setup Steps:
|
| 443 |
+
|
| 444 |
+
1. **Create Account**
|
| 445 |
+
- Go to [https://sentry.io](https://sentry.io)
|
| 446 |
+
- Click "Get Started"
|
| 447 |
+
- Sign up with email or GitHub
|
| 448 |
+
|
| 449 |
+
2. **Create Project**
|
| 450 |
+
- Click "Create Project"
|
| 451 |
+
- Select platform: **Python**
|
| 452 |
+
- Select framework: **FastAPI**
|
| 453 |
+
- Name: `swiftops-backend`
|
| 454 |
+
- Click "Create Project"
|
| 455 |
+
|
| 456 |
+
3. **Get DSN**
|
| 457 |
+
- After project creation, you'll see setup instructions
|
| 458 |
+
- Copy the DSN (looks like):
|
| 459 |
+
```
|
| 460 |
+
https://xxxxx@o123456.ingest.sentry.io/123456
|
| 461 |
+
```
|
| 462 |
+
- Save as `SENTRY_DSN`
|
| 463 |
+
|
| 464 |
+
4. **Configure Alerts** (Optional)
|
| 465 |
+
- Go to **Alerts** → **Create Alert**
|
| 466 |
+
- Set up alerts for:
|
| 467 |
+
- Error rate > 5%
|
| 468 |
+
- Response time > 2s
|
| 469 |
+
- Failed payments
|
| 470 |
+
|
| 471 |
+
### Environment Variables:
|
| 472 |
+
```bash
|
| 473 |
+
SENTRY_DSN=https://xxxxx@o123456.ingest.sentry.io/123456
|
| 474 |
+
SENTRY_ENVIRONMENT=production
|
| 475 |
+
```
|
| 476 |
+
|
| 477 |
+
### Free Tier:
|
| 478 |
+
- 5,000 errors/month
|
| 479 |
+
- 10,000 performance units/month
|
| 480 |
+
|
| 481 |
+
---
|
| 482 |
+
|
| 483 |
+
## 9. 🔐 JWT Secret Key
|
| 484 |
+
|
| 485 |
+
**What you need:**
|
| 486 |
+
- Strong secret key for JWT signing
|
| 487 |
+
|
| 488 |
+
### Generate Secret Key:
|
| 489 |
+
|
| 490 |
+
**Option 1: Using Python**
|
| 491 |
+
```bash
|
| 492 |
+
python -c "import secrets; print(secrets.token_urlsafe(32))"
|
| 493 |
+
```
|
| 494 |
+
|
| 495 |
+
**Option 2: Using OpenSSL**
|
| 496 |
+
```bash
|
| 497 |
+
openssl rand -base64 32
|
| 498 |
+
```
|
| 499 |
+
|
| 500 |
+
**Option 3: Online Generator**
|
| 501 |
+
- Go to [https://randomkeygen.com](https://randomkeygen.com)
|
| 502 |
+
- Use "CodeIgniter Encryption Keys" (256-bit)
|
| 503 |
+
|
| 504 |
+
### Environment Variables:
|
| 505 |
+
```bash
|
| 506 |
+
SECRET_KEY=your-super-secret-key-here-min-32-characters
|
| 507 |
+
ALGORITHM=HS256
|
| 508 |
+
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
| 509 |
+
REFRESH_TOKEN_EXPIRE_DAYS=30
|
| 510 |
+
```
|
| 511 |
+
|
| 512 |
+
---
|
| 513 |
+
|
| 514 |
+
## 10. 📋 Complete .env File Template
|
| 515 |
+
|
| 516 |
+
Create a `.env` file in your project root with all credentials:
|
| 517 |
+
|
| 518 |
+
```bash
|
| 519 |
+
# ============================================
|
| 520 |
+
# Application Settings
|
| 521 |
+
# ============================================
|
| 522 |
+
APP_NAME=SwiftOps API
|
| 523 |
+
DEBUG=False
|
| 524 |
+
ENVIRONMENT=production
|
| 525 |
+
SECRET_KEY=your-super-secret-key-here
|
| 526 |
+
ALGORITHM=HS256
|
| 527 |
+
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
| 528 |
+
REFRESH_TOKEN_EXPIRE_DAYS=30
|
| 529 |
+
|
| 530 |
+
# ============================================
|
| 531 |
+
# Database & Supabase
|
| 532 |
+
# ============================================
|
| 533 |
+
DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@db.xxxxx.supabase.co:5432/postgres
|
| 534 |
+
SUPABASE_URL=https://xxxxx.supabase.co
|
| 535 |
+
SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
| 536 |
+
SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
| 537 |
+
SUPABASE_JWT_SECRET=your-jwt-secret
|
| 538 |
+
|
| 539 |
+
# ============================================
|
| 540 |
+
# Redis
|
| 541 |
+
# ============================================
|
| 542 |
+
REDIS_URL=redis://localhost:6379/0
|
| 543 |
+
|
| 544 |
+
# ============================================
|
| 545 |
+
# Celery
|
| 546 |
+
# ============================================
|
| 547 |
+
CELERY_BROKER_URL=redis://localhost:6379/0
|
| 548 |
+
CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
| 549 |
+
|
| 550 |
+
# ============================================
|
| 551 |
+
# Cloudinary
|
| 552 |
+
# ============================================
|
| 553 |
+
CLOUDINARY_CLOUD_NAME=your-cloud-name
|
| 554 |
+
CLOUDINARY_API_KEY=123456789012345
|
| 555 |
+
CLOUDINARY_API_SECRET=abcdefghijklmnopqrstuvwxyz
|
| 556 |
+
|
| 557 |
+
# ============================================
|
| 558 |
+
# M-Pesa
|
| 559 |
+
# ============================================
|
| 560 |
+
MPESA_ENVIRONMENT=sandbox
|
| 561 |
+
MPESA_CONSUMER_KEY=your-consumer-key
|
| 562 |
+
MPESA_CONSUMER_SECRET=your-consumer-secret
|
| 563 |
+
MPESA_SHORTCODE=174379
|
| 564 |
+
MPESA_PASSKEY=your-passkey
|
| 565 |
+
MPESA_INITIATOR_NAME=testapi
|
| 566 |
+
MPESA_SECURITY_CREDENTIAL=your-security-credential
|
| 567 |
+
|
| 568 |
+
# ============================================
|
| 569 |
+
# Resend (Email)
|
| 570 |
+
# ============================================
|
| 571 |
+
RESEND_API_KEY=re_123456789abcdefghijklmnop
|
| 572 |
+
FROM_EMAIL=noreply@swiftops.com
|
| 573 |
+
|
| 574 |
+
# ============================================
|
| 575 |
+
# Africa's Talking (SMS) - V2
|
| 576 |
+
# ============================================
|
| 577 |
+
AFRICASTALKING_USERNAME=sandbox
|
| 578 |
+
AFRICASTALKING_API_KEY=your-api-key
|
| 579 |
+
AFRICASTALKING_ENVIRONMENT=sandbox
|
| 580 |
+
|
| 581 |
+
# ============================================
|
| 582 |
+
# Google Maps
|
| 583 |
+
# ============================================
|
| 584 |
+
GOOGLE_MAPS_API_KEY=AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
| 585 |
+
|
| 586 |
+
# ============================================
|
| 587 |
+
# Sentry (Optional)
|
| 588 |
+
# ============================================
|
| 589 |
+
SENTRY_DSN=https://xxxxx@o123456.ingest.sentry.io/123456
|
| 590 |
+
SENTRY_ENVIRONMENT=production
|
| 591 |
+
|
| 592 |
+
# ============================================
|
| 593 |
+
# CORS Settings
|
| 594 |
+
# ============================================
|
| 595 |
+
CORS_ORIGINS=http://localhost:3000,https://swiftops.com
|
| 596 |
+
```
|
| 597 |
+
|
| 598 |
+
---
|
| 599 |
+
|
| 600 |
+
## 11. ✅ Verification Checklist
|
| 601 |
+
|
| 602 |
+
After setting up all services, verify each one:
|
| 603 |
+
|
| 604 |
+
### Database & Auth
|
| 605 |
+
- [ ] Can connect to Supabase database
|
| 606 |
+
- [ ] Can create a test user via Supabase Auth
|
| 607 |
+
- [ ] JWT tokens are being generated correctly
|
| 608 |
+
|
| 609 |
+
### Image Storage
|
| 610 |
+
- [ ] Can upload image to Cloudinary
|
| 611 |
+
- [ ] Can retrieve image URL
|
| 612 |
+
- [ ] Can delete image from Cloudinary
|
| 613 |
+
|
| 614 |
+
### Email
|
| 615 |
+
- [ ] Can send test email via Resend
|
| 616 |
+
- [ ] Email is delivered to inbox (check spam)
|
| 617 |
+
- [ ] Email templates are rendering correctly
|
| 618 |
+
|
| 619 |
+
### Payments
|
| 620 |
+
- [ ] Can generate M-Pesa access token
|
| 621 |
+
- [ ] Can initiate test B2C payment (sandbox)
|
| 622 |
+
- [ ] Webhook callbacks are being received
|
| 623 |
+
|
| 624 |
+
### SMS (V2)
|
| 625 |
+
- [ ] Can send test SMS via Africa's Talking
|
| 626 |
+
- [ ] SMS is delivered to test number
|
| 627 |
+
|
| 628 |
+
### Maps
|
| 629 |
+
- [ ] Can geocode an address
|
| 630 |
+
- [ ] Can calculate distance between two points
|
| 631 |
+
- [ ] Can get directions
|
| 632 |
+
|
| 633 |
+
### Caching
|
| 634 |
+
- [ ] Can connect to Redis
|
| 635 |
+
- [ ] Can set and get cache values
|
| 636 |
+
- [ ] Celery workers can connect to Redis
|
| 637 |
+
|
| 638 |
+
### Monitoring
|
| 639 |
+
- [ ] Sentry is receiving test errors
|
| 640 |
+
- [ ] Error alerts are being sent
|
| 641 |
+
|
| 642 |
+
---
|
| 643 |
+
|
| 644 |
+
## 12. 🔒 Security Best Practices
|
| 645 |
+
|
| 646 |
+
1. **Never commit .env file to Git**
|
| 647 |
+
```bash
|
| 648 |
+
# Add to .gitignore
|
| 649 |
+
.env
|
| 650 |
+
.env.local
|
| 651 |
+
.env.production
|
| 652 |
+
```
|
| 653 |
+
|
| 654 |
+
2. **Use different credentials for dev/staging/production**
|
| 655 |
+
- Development: Use sandbox/test credentials
|
| 656 |
+
- Staging: Use separate production-like credentials
|
| 657 |
+
- Production: Use production credentials with restrictions
|
| 658 |
+
|
| 659 |
+
3. **Rotate credentials regularly**
|
| 660 |
+
- API keys: Every 90 days
|
| 661 |
+
- Database passwords: Every 180 days
|
| 662 |
+
- JWT secrets: Every 365 days
|
| 663 |
+
|
| 664 |
+
4. **Restrict API keys**
|
| 665 |
+
- Add IP restrictions where possible
|
| 666 |
+
- Use least privilege (only enable needed APIs)
|
| 667 |
+
- Monitor usage for anomalies
|
| 668 |
+
|
| 669 |
+
5. **Encrypt sensitive credentials**
|
| 670 |
+
- Use environment variables (never hardcode)
|
| 671 |
+
- Use secret management tools (AWS Secrets Manager, HashiCorp Vault)
|
| 672 |
+
- Encrypt .env files in production
|
| 673 |
+
|
| 674 |
+
---
|
| 675 |
+
|
| 676 |
+
## 13. 💰 Cost Estimation
|
| 677 |
+
|
| 678 |
+
### Development (Free Tier)
|
| 679 |
+
- Supabase: Free (500MB database, 2GB bandwidth)
|
| 680 |
+
- Cloudinary: Free (25GB storage, 25GB bandwidth)
|
| 681 |
+
- Resend: Free (100 emails/day)
|
| 682 |
+
- M-Pesa: Free (sandbox)
|
| 683 |
+
- Africa's Talking: Free (sandbox)
|
| 684 |
+
- Google Maps: Free ($200 credits/month)
|
| 685 |
+
- Redis Cloud: Free (30MB)
|
| 686 |
+
- Sentry: Free (5,000 errors/month)
|
| 687 |
+
|
| 688 |
+
**Total: $0/month**
|
| 689 |
+
|
| 690 |
+
### Production (Estimated)
|
| 691 |
+
- Supabase: $25/month (Pro plan)
|
| 692 |
+
- Cloudinary: $89/month (Plus plan) or stay on free tier
|
| 693 |
+
- Resend: $20/month (10,000 emails)
|
| 694 |
+
- M-Pesa: Transaction fees only (~1% per transaction)
|
| 695 |
+
- Africa's Talking: ~$50/month (5,000 SMS)
|
| 696 |
+
- Google Maps: ~$50/month (within free credits)
|
| 697 |
+
- Redis Cloud: $7/month (250MB)
|
| 698 |
+
- Sentry: $26/month (Team plan)
|
| 699 |
+
|
| 700 |
+
**Total: ~$267/month** (scales with usage)
|
| 701 |
+
|
| 702 |
+
---
|
| 703 |
+
|
| 704 |
+
## 14. 📞 Support & Resources
|
| 705 |
+
|
| 706 |
+
### Supabase
|
| 707 |
+
- Docs: [https://supabase.com/docs](https://supabase.com/docs)
|
| 708 |
+
- Discord: [https://discord.supabase.com](https://discord.supabase.com)
|
| 709 |
+
|
| 710 |
+
### Cloudinary
|
| 711 |
+
- Docs: [https://cloudinary.com/documentation](https://cloudinary.com/documentation)
|
| 712 |
+
- Support: support@cloudinary.com
|
| 713 |
+
|
| 714 |
+
### Resend
|
| 715 |
+
- Docs: [https://resend.com/docs](https://resend.com/docs)
|
| 716 |
+
- Support: support@resend.com
|
| 717 |
+
|
| 718 |
+
### M-Pesa
|
| 719 |
+
- Docs: [https://developer.safaricom.co.ke/docs](https://developer.safaricom.co.ke/docs)
|
| 720 |
+
- Support: apisupport@safaricom.co.ke
|
| 721 |
+
|
| 722 |
+
### Africa's Talking
|
| 723 |
+
- Docs: [https://developers.africastalking.com](https://developers.africastalking.com)
|
| 724 |
+
- Support: support@africastalking.com
|
| 725 |
+
|
| 726 |
+
### Google Maps
|
| 727 |
+
- Docs: [https://developers.google.com/maps](https://developers.google.com/maps)
|
| 728 |
+
- Support: Google Cloud Console
|
| 729 |
+
|
| 730 |
+
---
|
| 731 |
+
|
| 732 |
+
**Document Version:** 1.0
|
| 733 |
+
**Last Updated:** November 2025
|
| 734 |
+
**Next Review:** Before production deployment
|
docs/prod/TEST_TEMPLATES.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Testing the New Template Architecture
|
| 2 |
+
|
| 3 |
+
## ✅ What We Built
|
| 4 |
+
|
| 5 |
+
### **Proper FastAPI Architecture**
|
| 6 |
+
```
|
| 7 |
+
src/app/
|
| 8 |
+
├── templates/ # Jinja2 templates (HTML)
|
| 9 |
+
├── static/ # CSS, JS, images
|
| 10 |
+
├── api/v1/pages.py # Page routes (separate from API)
|
| 11 |
+
├── constants/ # Centralized configuration
|
| 12 |
+
└── main.py # Application entry point
|
| 13 |
+
```
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## 🚀 How to Test
|
| 18 |
+
|
| 19 |
+
### 1. Install New Dependencies
|
| 20 |
+
|
| 21 |
+
```bash
|
| 22 |
+
pip install jinja2==3.1.2 aiofiles==23.2.1
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
### 2. Start the Server
|
| 26 |
+
|
| 27 |
+
```bash
|
| 28 |
+
uvicorn src.app.main:app --reload
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
### 3. Visit the Pages
|
| 32 |
+
|
| 33 |
+
- **Landing Page**: http://localhost:8000/
|
| 34 |
+
- **API Docs**: http://localhost:8000/api/docs
|
| 35 |
+
- **Health Check**: http://localhost:8000/health
|
| 36 |
+
|
| 37 |
+
### 4. Test Theme Switching
|
| 38 |
+
|
| 39 |
+
**Windows:**
|
| 40 |
+
- Settings → Personalization → Colors → Choose your mode
|
| 41 |
+
|
| 42 |
+
**Mac:**
|
| 43 |
+
- System Preferences → General → Appearance
|
| 44 |
+
|
| 45 |
+
**Linux:**
|
| 46 |
+
- Depends on desktop environment
|
| 47 |
+
|
| 48 |
+
The page will automatically switch between light and dark themes! 🌓
|
| 49 |
+
|
| 50 |
+
---
|
| 51 |
+
|
| 52 |
+
## 📁 File Structure
|
| 53 |
+
|
| 54 |
+
### **Templates** (`src/app/templates/`)
|
| 55 |
+
- `base.html` - Base layout (header, footer, meta tags)
|
| 56 |
+
- `index.html` - Landing page content
|
| 57 |
+
- `README.md` - Template documentation
|
| 58 |
+
|
| 59 |
+
### **Static Files** (`src/app/static/`)
|
| 60 |
+
- `css/main.css` - Styles with theme support
|
| 61 |
+
- `js/main.js` - Client-side JavaScript
|
| 62 |
+
|
| 63 |
+
### **Routes** (`src/app/api/v1/pages.py`)
|
| 64 |
+
- Page routes (HTML responses)
|
| 65 |
+
- Separate from API routes (JSON responses)
|
| 66 |
+
|
| 67 |
+
### **Configuration** (`src/app/constants/app_metadata.py`)
|
| 68 |
+
- Centralized app metadata
|
| 69 |
+
- Version, name, description
|
| 70 |
+
- Used across all pages
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## 🎯 Benefits of This Architecture
|
| 75 |
+
|
| 76 |
+
### ✅ **Separation of Concerns**
|
| 77 |
+
- Templates handle HTML structure
|
| 78 |
+
- CSS handles styling
|
| 79 |
+
- JavaScript handles behavior
|
| 80 |
+
- Python handles logic
|
| 81 |
+
|
| 82 |
+
### ✅ **Maintainability**
|
| 83 |
+
- Easy to find files
|
| 84 |
+
- Clear responsibilities
|
| 85 |
+
- Consistent structure
|
| 86 |
+
|
| 87 |
+
### ✅ **Scalability**
|
| 88 |
+
- Add new pages easily
|
| 89 |
+
- Extend base template
|
| 90 |
+
- Reuse components
|
| 91 |
+
|
| 92 |
+
### ✅ **Best Practices**
|
| 93 |
+
- Follows FastAPI conventions
|
| 94 |
+
- Uses Jinja2 templates
|
| 95 |
+
- Static file serving
|
| 96 |
+
- Template inheritance
|
| 97 |
+
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
## 📝 Adding New Pages
|
| 101 |
+
|
| 102 |
+
### Example: Add an "About" Page
|
| 103 |
+
|
| 104 |
+
**1. Create template** (`templates/about.html`):
|
| 105 |
+
```html
|
| 106 |
+
{% extends "base.html" %}
|
| 107 |
+
|
| 108 |
+
{% block title %}About - {{ app_name }}{% endblock %}
|
| 109 |
+
|
| 110 |
+
{% block content %}
|
| 111 |
+
<div class="container">
|
| 112 |
+
<h1>About {{ app_name }}</h1>
|
| 113 |
+
<p>{{ app_description }}</p>
|
| 114 |
+
</div>
|
| 115 |
+
{% endblock %}
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
**2. Add route** (`api/v1/pages.py`):
|
| 119 |
+
```python
|
| 120 |
+
@router.get("/about", response_class=HTMLResponse)
|
| 121 |
+
async def about(request: Request):
|
| 122 |
+
return templates.TemplateResponse("about.html", {
|
| 123 |
+
"request": request,
|
| 124 |
+
"app_name": APP_NAME,
|
| 125 |
+
"app_description": APP_DESCRIPTION
|
| 126 |
+
})
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
**3. Visit**: http://localhost:8000/about
|
| 130 |
+
|
| 131 |
+
---
|
| 132 |
+
|
| 133 |
+
## 🎨 Customization
|
| 134 |
+
|
| 135 |
+
### Update App Info
|
| 136 |
+
|
| 137 |
+
Edit `src/app/constants/app_metadata.py`:
|
| 138 |
+
```python
|
| 139 |
+
APP_NAME = "Your App Name"
|
| 140 |
+
APP_VERSION = "2.0.0"
|
| 141 |
+
APP_DESCRIPTION = "Your description"
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
### Add Custom Styles
|
| 145 |
+
|
| 146 |
+
Edit `src/app/static/css/main.css`:
|
| 147 |
+
```css
|
| 148 |
+
.custom-button {
|
| 149 |
+
background: var(--accent-color);
|
| 150 |
+
padding: 1rem 2rem;
|
| 151 |
+
}
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
### Add Custom JavaScript
|
| 155 |
+
|
| 156 |
+
Edit `src/app/static/js/main.js`:
|
| 157 |
+
```javascript
|
| 158 |
+
console.log('Custom script loaded!');
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
---
|
| 162 |
+
|
| 163 |
+
## 🔍 Troubleshooting
|
| 164 |
+
|
| 165 |
+
### Templates Not Found
|
| 166 |
+
```bash
|
| 167 |
+
# Check templates directory exists
|
| 168 |
+
ls src/app/templates/
|
| 169 |
+
|
| 170 |
+
# Should show: base.html, index.html, README.md
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
### Static Files Not Loading
|
| 174 |
+
```bash
|
| 175 |
+
# Check static directory exists
|
| 176 |
+
ls src/app/static/css/
|
| 177 |
+
ls src/app/static/js/
|
| 178 |
+
|
| 179 |
+
# Should show: main.css and main.js
|
| 180 |
+
```
|
| 181 |
+
|
| 182 |
+
### Import Errors
|
| 183 |
+
```bash
|
| 184 |
+
# Reinstall dependencies
|
| 185 |
+
pip install -r requirements.txt
|
| 186 |
+
|
| 187 |
+
# Check Jinja2 is installed
|
| 188 |
+
pip show jinja2
|
| 189 |
+
```
|
| 190 |
+
|
| 191 |
+
---
|
| 192 |
+
|
| 193 |
+
## ✨ Features
|
| 194 |
+
|
| 195 |
+
### 🌓 **Theme Support**
|
| 196 |
+
- Automatic dark/light mode
|
| 197 |
+
- Respects system preferences
|
| 198 |
+
- Smooth transitions
|
| 199 |
+
|
| 200 |
+
### 📱 **Responsive Design**
|
| 201 |
+
- Mobile-friendly
|
| 202 |
+
- Tablet-optimized
|
| 203 |
+
- Desktop-enhanced
|
| 204 |
+
|
| 205 |
+
### ⚡ **Performance**
|
| 206 |
+
- Fast page loads
|
| 207 |
+
- Minimal dependencies
|
| 208 |
+
- Optimized assets
|
| 209 |
+
|
| 210 |
+
### 🎯 **SEO Ready**
|
| 211 |
+
- Proper meta tags
|
| 212 |
+
- Semantic HTML
|
| 213 |
+
- Accessible markup
|
| 214 |
+
|
| 215 |
+
---
|
| 216 |
+
|
| 217 |
+
## 📚 Documentation
|
| 218 |
+
|
| 219 |
+
- **Architecture**: `docs/dev/TEMPLATES_ARCHITECTURE.md`
|
| 220 |
+
- **Template Guide**: `src/app/templates/README.md`
|
| 221 |
+
- **API Docs**: http://localhost:8000/api/docs
|
| 222 |
+
|
| 223 |
+
---
|
| 224 |
+
|
| 225 |
+
## 🎉 Success!
|
| 226 |
+
|
| 227 |
+
Your FastAPI application now has:
|
| 228 |
+
- ✅ Proper template architecture
|
| 229 |
+
- ✅ Theme-aware landing page
|
| 230 |
+
- ✅ Separated concerns (HTML/CSS/JS/Python)
|
| 231 |
+
- ✅ Scalable structure
|
| 232 |
+
- ✅ Best practices followed
|
| 233 |
+
|
| 234 |
+
**Ready for production and easy to maintain!** 🚀
|
docs/spec/USER_STORIES.md
ADDED
|
@@ -0,0 +1,1118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# User Stories & API Endpoints
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
This document outlines user stories for the Field Service Management Platform, organized by user role. Each story includes acceptance criteria and required FastAPI backend endpoints.
|
| 5 |
+
|
| 6 |
+
**Architecture:** FastAPI backend handles all database interactions. Frontend queries the backend via REST API.
|
| 7 |
+
|
| 8 |
+
**User Roles:**
|
| 9 |
+
- Platform Admin
|
| 10 |
+
- Client Admin (Telecom Operator)
|
| 11 |
+
- Contractor Admin
|
| 12 |
+
- Project Manager
|
| 13 |
+
- Dispatcher
|
| 14 |
+
- Field Agent
|
| 15 |
+
- Sales Agent
|
| 16 |
+
- Sales Manager
|
| 17 |
+
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
## 1. PLATFORM ADMIN
|
| 21 |
+
|
| 22 |
+
### 1.1 Organization Management
|
| 23 |
+
|
| 24 |
+
**US-PA-001: Create Client Organization**
|
| 25 |
+
- **As a** Platform Admin
|
| 26 |
+
- **I want to** create new client organizations (telecom operators)
|
| 27 |
+
- **So that** they can use the platform for their field operations
|
| 28 |
+
|
| 29 |
+
**Acceptance Criteria:**
|
| 30 |
+
- Can create client with name, industry, contact details
|
| 31 |
+
- System validates unique client name and email
|
| 32 |
+
- Client is created with default SLA settings
|
| 33 |
+
- Client admin user is automatically invited
|
| 34 |
+
|
| 35 |
+
**API Endpoints:**
|
| 36 |
+
```
|
| 37 |
+
POST /api/v1/clients
|
| 38 |
+
GET /api/v1/clients
|
| 39 |
+
GET /api/v1/clients/{client_id}
|
| 40 |
+
PUT /api/v1/clients/{client_id}
|
| 41 |
+
DELETE /api/v1/clients/{client_id}
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
**US-PA-002: Create Contractor Organization**
|
| 45 |
+
- **As a** Platform Admin
|
| 46 |
+
- **I want to** create contractor organizations
|
| 47 |
+
- **So that** they can be assigned to client projects
|
| 48 |
+
|
| 49 |
+
**Acceptance Criteria:**
|
| 50 |
+
- Can create contractor with name, competencies, contact details
|
| 51 |
+
- System validates unique contractor name
|
| 52 |
+
- Contractor admin user is automatically invited
|
| 53 |
+
- Can specify contractor specializations (FTTH, Fixed Wireless, etc.)
|
| 54 |
+
|
| 55 |
+
**API Endpoints:**
|
| 56 |
+
```
|
| 57 |
+
POST /api/v1/contractors
|
| 58 |
+
GET /api/v1/contractors
|
| 59 |
+
GET /api/v1/contractors/{contractor_id}
|
| 60 |
+
PUT /api/v1/contractors/{contractor_id}
|
| 61 |
+
DELETE /api/v1/contractors/{contractor_id}
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
### 1.2 Platform Billing Management
|
| 66 |
+
|
| 67 |
+
**US-PA-003: Manage Billing Plans**
|
| 68 |
+
- **As a** Platform Admin
|
| 69 |
+
- **I want to** create and manage billing plans
|
| 70 |
+
- **So that** organizations can subscribe to different service tiers
|
| 71 |
+
|
| 72 |
+
**Acceptance Criteria:**
|
| 73 |
+
- Can create plans with pricing, features, and limits
|
| 74 |
+
- Can set user limits, project limits, and storage quotas
|
| 75 |
+
- Can mark plans as public or private
|
| 76 |
+
- Can activate/deactivate plans
|
| 77 |
+
|
| 78 |
+
**API Endpoints:**
|
| 79 |
+
```
|
| 80 |
+
POST /api/v1/billing/plans
|
| 81 |
+
GET /api/v1/billing/plans
|
| 82 |
+
GET /api/v1/billing/plans/{plan_id}
|
| 83 |
+
PUT /api/v1/billing/plans/{plan_id}
|
| 84 |
+
DELETE /api/v1/billing/plans/{plan_id}
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
**US-PA-004: Monitor Platform Usage**
|
| 88 |
+
- **As a** Platform Admin
|
| 89 |
+
- **I want to** view usage metrics across all organizations
|
| 90 |
+
- **So that** I can monitor platform health and billing
|
| 91 |
+
|
| 92 |
+
**Acceptance Criteria:**
|
| 93 |
+
- Can view active users, projects, tickets per organization
|
| 94 |
+
- Can see storage usage and API call counts
|
| 95 |
+
- Can filter by date range and organization type
|
| 96 |
+
- Can export usage reports
|
| 97 |
+
|
| 98 |
+
**API Endpoints:**
|
| 99 |
+
```
|
| 100 |
+
GET /api/v1/usage-metrics
|
| 101 |
+
GET /api/v1/usage-metrics/summary
|
| 102 |
+
GET /api/v1/usage-metrics/by-organization
|
| 103 |
+
POST /api/v1/usage-metrics/export
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
---
|
| 107 |
+
|
| 108 |
+
## 2. CLIENT ADMIN (Telecom Operator)
|
| 109 |
+
|
| 110 |
+
### 2.1 Project Setup
|
| 111 |
+
|
| 112 |
+
**US-CA-001: Initiate Project Creation**
|
| 113 |
+
- **As a** Client Admin
|
| 114 |
+
- **I want to** initiate a project and invite a contractor
|
| 115 |
+
- **So that** we can collaborate on field work
|
| 116 |
+
|
| 117 |
+
**Acceptance Criteria:**
|
| 118 |
+
- Can create project with title, description, service type
|
| 119 |
+
- Can invite contractor from available contractors
|
| 120 |
+
- Contractor receives invitation to join project
|
| 121 |
+
- Project is created in 'pending' state until contractor accepts
|
| 122 |
+
- Can set project dates and budget
|
| 123 |
+
- Can define activation requirements (ONT serial, MAC address, etc.)
|
| 124 |
+
- Can specify photo requirements for installations
|
| 125 |
+
|
| 126 |
+
**API Endpoints:**
|
| 127 |
+
```
|
| 128 |
+
POST /api/v1/projects/initiate # Client initiates
|
| 129 |
+
POST /api/v1/projects/invitations # Send contractor invitation
|
| 130 |
+
GET /api/v1/projects
|
| 131 |
+
GET /api/v1/projects/{project_id}
|
| 132 |
+
PUT /api/v1/projects/{project_id}
|
| 133 |
+
DELETE /api/v1/projects/{project_id}
|
| 134 |
+
POST /api/v1/projects/{project_id}/close
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
**US-CA-002: Define Project Regions**
|
| 139 |
+
- **As a** Client Admin
|
| 140 |
+
- **I want to** create regional hubs within a project
|
| 141 |
+
- **So that** inventory and teams can be organized geographically
|
| 142 |
+
|
| 143 |
+
**Acceptance Criteria:**
|
| 144 |
+
- Can create regions with name, location, and manager
|
| 145 |
+
- Can assign regional manager from project team
|
| 146 |
+
- Regions are used for inventory distribution
|
| 147 |
+
- Can view all regions on a map
|
| 148 |
+
|
| 149 |
+
**API Endpoints:**
|
| 150 |
+
```
|
| 151 |
+
POST /api/v1/projects/{project_id}/regions
|
| 152 |
+
GET /api/v1/projects/{project_id}/regions
|
| 153 |
+
GET /api/v1/regions/{region_id}
|
| 154 |
+
PUT /api/v1/regions/{region_id}
|
| 155 |
+
DELETE /api/v1/regions/{region_id}
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
### 2.2 User Management
|
| 159 |
+
|
| 160 |
+
**US-CA-003: Invite Users**
|
| 161 |
+
- **As a** Client Admin
|
| 162 |
+
- **I want to** invite users to my organization
|
| 163 |
+
- **So that** they can access the platform
|
| 164 |
+
|
| 165 |
+
**Acceptance Criteria:**
|
| 166 |
+
- Can invite users with email and role
|
| 167 |
+
- System sends invitation email
|
| 168 |
+
- Can set user role (sales_manager, project_manager, dispatcher, sales_agent)
|
| 169 |
+
- User receives onboarding instructions
|
| 170 |
+
|
| 171 |
+
**API Endpoints:**
|
| 172 |
+
```
|
| 173 |
+
POST /api/v1/users/invite
|
| 174 |
+
GET /api/v1/users
|
| 175 |
+
GET /api/v1/users/{user_id}
|
| 176 |
+
PUT /api/v1/users/{user_id}
|
| 177 |
+
DELETE /api/v1/users/{user_id}
|
| 178 |
+
POST /api/v1/users/{user_id}/suspend
|
| 179 |
+
POST /api/v1/users/{user_id}/activate
|
| 180 |
+
```
|
| 181 |
+
|
| 182 |
+
---
|
| 183 |
+
|
| 184 |
+
## 3. CONTRACTOR ADMIN
|
| 185 |
+
|
| 186 |
+
### 3.1 Project Collaboration
|
| 187 |
+
|
| 188 |
+
**US-CO-001: Accept or Initiate Project**
|
| 189 |
+
- **As a** Contractor Admin
|
| 190 |
+
- **I want to** accept project invitations from clients or initiate projects
|
| 191 |
+
- **So that** I can collaborate with clients on field work
|
| 192 |
+
|
| 193 |
+
**Acceptance Criteria:**
|
| 194 |
+
- Can view pending project invitations from clients
|
| 195 |
+
- Can accept or decline project invitations
|
| 196 |
+
- Can also initiate projects and invite clients
|
| 197 |
+
- Project becomes 'active' when both parties agree
|
| 198 |
+
- Can negotiate project terms before acceptance
|
| 199 |
+
|
| 200 |
+
**API Endpoints:**
|
| 201 |
+
```
|
| 202 |
+
GET /api/v1/projects/invitations/pending
|
| 203 |
+
POST /api/v1/projects/invitations/{invitation_id}/accept
|
| 204 |
+
POST /api/v1/projects/invitations/{invitation_id}/decline
|
| 205 |
+
POST /api/v1/projects/initiate # Contractor initiates
|
| 206 |
+
POST /api/v1/projects/invitations # Invite client
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
### 3.2 Team Management
|
| 210 |
+
|
| 211 |
+
**US-CO-002: Manage Field Agents**
|
| 212 |
+
- **As a** Contractor Admin
|
| 213 |
+
- **I want to** add and manage field agents
|
| 214 |
+
- **So that** they can be assigned to projects
|
| 215 |
+
|
| 216 |
+
**Acceptance Criteria:**
|
| 217 |
+
- Can add field agents with contact details
|
| 218 |
+
- Can record health & safety information
|
| 219 |
+
- Can record PPE sizes for equipment allocation
|
| 220 |
+
- Can assign financial accounts for payouts
|
| 221 |
+
- Can track agent location in real-time
|
| 222 |
+
|
| 223 |
+
**API Endpoints:**
|
| 224 |
+
```
|
| 225 |
+
POST /api/v1/field-agents
|
| 226 |
+
GET /api/v1/field-agents
|
| 227 |
+
GET /api/v1/field-agents/{agent_id}
|
| 228 |
+
PUT /api/v1/field-agents/{agent_id}
|
| 229 |
+
GET /api/v1/field-agents/{agent_id}/location
|
| 230 |
+
POST /api/v1/field-agents/{agent_id}/financial-accounts
|
| 231 |
+
```
|
| 232 |
+
|
| 233 |
+
**US-CO-003: Invite Team Members to Project**
|
| 234 |
+
- **As a** Contractor Admin
|
| 235 |
+
- **I want to** invite my team members to join a project
|
| 236 |
+
- **So that** they can be assigned work
|
| 237 |
+
|
| 238 |
+
**Acceptance Criteria:**
|
| 239 |
+
- Can invite field agents to specific projects
|
| 240 |
+
- Can set project role and compensation structure
|
| 241 |
+
- Can assign agents to specific regions
|
| 242 |
+
- Team members receive invitation notification
|
| 243 |
+
- Can track agent availability across projects
|
| 244 |
+
|
| 245 |
+
**API Endpoints:**
|
| 246 |
+
```
|
| 247 |
+
POST /api/v1/projects/{project_id}/team/invite
|
| 248 |
+
GET /api/v1/projects/{project_id}/team/invitations
|
| 249 |
+
POST /api/v1/projects/{project_id}/team/invitations/{id}/resend
|
| 250 |
+
DELETE /api/v1/projects/{project_id}/team/invitations/{id}/cancel
|
| 251 |
+
GET /api/v1/projects/{project_id}/team
|
| 252 |
+
DELETE /api/v1/projects/{project_id}/team/{member_id}
|
| 253 |
+
GET /api/v1/field-agents/{agent_id}/projects
|
| 254 |
+
```
|
| 255 |
+
|
| 256 |
+
---
|
| 257 |
+
|
| 258 |
+
## 4. PROJECT MANAGER
|
| 259 |
+
|
| 260 |
+
### 4.1 Sales Order Management
|
| 261 |
+
|
| 262 |
+
**US-PM-001: Create Sales Order (Single)**
|
| 263 |
+
- **As a** Project Manager
|
| 264 |
+
- **I want to** create individual sales orders
|
| 265 |
+
- **So that** I can add orders one at a time
|
| 266 |
+
|
| 267 |
+
**Acceptance Criteria:**
|
| 268 |
+
- Can enter customer details (name, phone, address)
|
| 269 |
+
- System deduplicates customers by phone number
|
| 270 |
+
- Can specify package, price, and installation details
|
| 271 |
+
- Can set preferred installation date/time
|
| 272 |
+
- Can add installation address with GPS coordinates
|
| 273 |
+
- Order is created with 'pending' status
|
| 274 |
+
|
| 275 |
+
**API Endpoints:**
|
| 276 |
+
```
|
| 277 |
+
POST /api/v1/sales-orders
|
| 278 |
+
GET /api/v1/sales-orders
|
| 279 |
+
GET /api/v1/sales-orders/{order_id}
|
| 280 |
+
PUT /api/v1/sales-orders/{order_id}
|
| 281 |
+
DELETE /api/v1/sales-orders/{order_id}
|
| 282 |
+
POST /api/v1/customers/check-duplicate
|
| 283 |
+
```
|
| 284 |
+
|
| 285 |
+
**US-PM-002: Upload Sales Orders (CSV Bulk Import)**
|
| 286 |
+
- **As a** Project Manager
|
| 287 |
+
- **I want to** upload sales orders via CSV
|
| 288 |
+
- **So that** installation tickets can be generated in bulk
|
| 289 |
+
|
| 290 |
+
**Acceptance Criteria:**
|
| 291 |
+
- Can upload CSV with customer details and installation addresses
|
| 292 |
+
- System validates and deduplicates customers by phone
|
| 293 |
+
- System creates SalesOrder records in batch
|
| 294 |
+
- Can preview orders before confirming
|
| 295 |
+
- Can see validation errors for invalid rows
|
| 296 |
+
- Can download error report for failed rows
|
| 297 |
+
- Successfully imported orders are marked as 'pending'
|
| 298 |
+
|
| 299 |
+
**API Endpoints:**
|
| 300 |
+
```
|
| 301 |
+
POST /api/v1/sales-orders/upload-csv
|
| 302 |
+
POST /api/v1/sales-orders/validate-csv
|
| 303 |
+
POST /api/v1/sales-orders/confirm-csv-import
|
| 304 |
+
GET /api/v1/sales-orders/import-history
|
| 305 |
+
GET /api/v1/sales-orders/import/{import_id}/errors
|
| 306 |
+
```
|
| 307 |
+
|
| 308 |
+
**US-PM-002: Generate Tickets from Sales Orders**
|
| 309 |
+
- **As a** Project Manager
|
| 310 |
+
- **I want to** convert unprocessed sales orders into tickets
|
| 311 |
+
- **So that** field agents can execute installations
|
| 312 |
+
|
| 313 |
+
**Acceptance Criteria:**
|
| 314 |
+
- Can select multiple sales orders to process
|
| 315 |
+
- System creates installation tickets with cached location data
|
| 316 |
+
- Tickets are created with 'open' status
|
| 317 |
+
- Sales orders are marked as 'processed'
|
| 318 |
+
- Can bulk generate tickets
|
| 319 |
+
|
| 320 |
+
**API Endpoints:**
|
| 321 |
+
```
|
| 322 |
+
POST /api/v1/sales-orders/{order_id}/create-ticket
|
| 323 |
+
POST /api/v1/sales-orders/bulk-create-tickets
|
| 324 |
+
GET /api/v1/sales-orders/unprocessed
|
| 325 |
+
```
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
### 4.2 Inventory Management
|
| 329 |
+
|
| 330 |
+
**US-PM-003: Receive Inventory from Client**
|
| 331 |
+
- **As a** Project Manager
|
| 332 |
+
- **I want to** record inventory received from the client
|
| 333 |
+
- **So that** equipment can be tracked and distributed
|
| 334 |
+
|
| 335 |
+
**Acceptance Criteria:**
|
| 336 |
+
- Can record equipment type, quantity, and serial numbers
|
| 337 |
+
- Can specify if items are tools (returnable) or equipment (installable)
|
| 338 |
+
- Can record delivery note reference
|
| 339 |
+
- Can track inventory value
|
| 340 |
+
|
| 341 |
+
**API Endpoints:**
|
| 342 |
+
```
|
| 343 |
+
POST /api/v1/projects/{project_id}/inventory
|
| 344 |
+
GET /api/v1/projects/{project_id}/inventory
|
| 345 |
+
GET /api/v1/inventory/{inventory_id}
|
| 346 |
+
PUT /api/v1/inventory/{inventory_id}
|
| 347 |
+
GET /api/v1/inventory/{inventory_id}/serial-numbers
|
| 348 |
+
```
|
| 349 |
+
|
| 350 |
+
**US-PM-004: Distribute Inventory to Regional Hubs**
|
| 351 |
+
- **As a** Project Manager
|
| 352 |
+
- **I want to** distribute inventory from main office to regional hubs
|
| 353 |
+
- **So that** field agents can collect equipment locally
|
| 354 |
+
|
| 355 |
+
**Acceptance Criteria:**
|
| 356 |
+
- Can allocate quantities to specific regions
|
| 357 |
+
- Can track serial numbers per region
|
| 358 |
+
- System updates available quantities
|
| 359 |
+
- Can view inventory levels per region
|
| 360 |
+
|
| 361 |
+
**API Endpoints:**
|
| 362 |
+
```
|
| 363 |
+
POST /api/v1/inventory/{inventory_id}/distribute
|
| 364 |
+
GET /api/v1/regions/{region_id}/inventory
|
| 365 |
+
GET /api/v1/inventory-distribution/{distribution_id}
|
| 366 |
+
PUT /api/v1/inventory-distribution/{distribution_id}
|
| 367 |
+
```
|
| 368 |
+
|
| 369 |
+
### 4.3 Task Management (Infrastructure Projects)
|
| 370 |
+
|
| 371 |
+
**US-PM-005: Create Infrastructure Tasks**
|
| 372 |
+
- **As a** Project Manager
|
| 373 |
+
- **I want to** create tasks for infrastructure rollout
|
| 374 |
+
- **So that** contractors can execute infrastructure work
|
| 375 |
+
|
| 376 |
+
**Acceptance Criteria:**
|
| 377 |
+
- Can create tasks with title, description, location
|
| 378 |
+
- Can set task type (installation, maintenance, survey, testing)
|
| 379 |
+
- Can assign priority and schedule date
|
| 380 |
+
- Can generate tickets from tasks
|
| 381 |
+
|
| 382 |
+
**API Endpoints:**
|
| 383 |
+
```
|
| 384 |
+
POST /api/v1/projects/{project_id}/tasks
|
| 385 |
+
GET /api/v1/projects/{project_id}/tasks
|
| 386 |
+
GET /api/v1/tasks/{task_id}
|
| 387 |
+
PUT /api/v1/tasks/{task_id}
|
| 388 |
+
DELETE /api/v1/tasks/{task_id}
|
| 389 |
+
POST /api/v1/tasks/{task_id}/create-ticket
|
| 390 |
+
```
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
### 4.4 Financial Management
|
| 394 |
+
|
| 395 |
+
**US-PM-006: Track Project Finances**
|
| 396 |
+
- **As a** Project Manager
|
| 397 |
+
- **I want to** record project income and expenses
|
| 398 |
+
- **So that** I can monitor project cash flow
|
| 399 |
+
|
| 400 |
+
**Acceptance Criteria:**
|
| 401 |
+
- Can record inflows (funding from finance department)
|
| 402 |
+
- Can record outflows (payroll, equipment, transport)
|
| 403 |
+
- Can link transactions to specific entities (tickets, payroll, invoices)
|
| 404 |
+
- Can view financial summary and balance
|
| 405 |
+
|
| 406 |
+
**API Endpoints:**
|
| 407 |
+
```
|
| 408 |
+
POST /api/v1/projects/{project_id}/finance
|
| 409 |
+
GET /api/v1/projects/{project_id}/finance
|
| 410 |
+
GET /api/v1/projects/{project_id}/finance/summary
|
| 411 |
+
GET /api/v1/finance/{transaction_id}
|
| 412 |
+
PUT /api/v1/finance/{transaction_id}
|
| 413 |
+
POST /api/v1/finance/{transaction_id}/approve
|
| 414 |
+
POST /api/v1/finance/{transaction_id}/reject
|
| 415 |
+
```
|
| 416 |
+
|
| 417 |
+
**US-PM-007: Generate Contractor Invoices**
|
| 418 |
+
- **As a** Project Manager
|
| 419 |
+
- **I want to** generate invoices for contractor work
|
| 420 |
+
- **So that** contractors can be paid for completed tickets
|
| 421 |
+
|
| 422 |
+
**Acceptance Criteria:**
|
| 423 |
+
- Can select completed tickets for invoicing
|
| 424 |
+
- System calculates total based on compensation structure
|
| 425 |
+
- Can add line items and adjustments
|
| 426 |
+
- Can mark invoice as paid
|
| 427 |
+
|
| 428 |
+
**API Endpoints:**
|
| 429 |
+
```
|
| 430 |
+
POST /api/v1/projects/{project_id}/invoices
|
| 431 |
+
GET /api/v1/projects/{project_id}/invoices
|
| 432 |
+
GET /api/v1/invoices/{invoice_id}
|
| 433 |
+
PUT /api/v1/invoices/{invoice_id}
|
| 434 |
+
POST /api/v1/invoices/{invoice_id}/mark-paid
|
| 435 |
+
GET /api/v1/invoices/{invoice_id}/tickets
|
| 436 |
+
```
|
| 437 |
+
|
| 438 |
+
---
|
| 439 |
+
|
| 440 |
+
## 5. DISPATCHER
|
| 441 |
+
|
| 442 |
+
### 5.1 Ticket Assignment
|
| 443 |
+
|
| 444 |
+
**US-DI-001: View Available Tickets**
|
| 445 |
+
- **As a** Dispatcher
|
| 446 |
+
- **I want to** view all open tickets
|
| 447 |
+
- **So that** I can assign them to field agents
|
| 448 |
+
|
| 449 |
+
**Acceptance Criteria:**
|
| 450 |
+
- Can view tickets filtered by status, priority, region
|
| 451 |
+
- Can see ticket details including location and requirements
|
| 452 |
+
- Can view tickets on a map
|
| 453 |
+
- Can see agent availability and current workload
|
| 454 |
+
|
| 455 |
+
**API Endpoints:**
|
| 456 |
+
```
|
| 457 |
+
GET /api/v1/tickets
|
| 458 |
+
GET /api/v1/tickets/open
|
| 459 |
+
GET /api/v1/tickets/by-region/{region_id}
|
| 460 |
+
GET /api/v1/tickets/map-view
|
| 461 |
+
GET /api/v1/field-agents/availability
|
| 462 |
+
```
|
| 463 |
+
|
| 464 |
+
|
| 465 |
+
**US-DI-002: Assign Tickets to Field Agents**
|
| 466 |
+
- **As a** Dispatcher
|
| 467 |
+
- **I want to** assign tickets to field agents
|
| 468 |
+
- **So that** work can be executed
|
| 469 |
+
|
| 470 |
+
**Acceptance Criteria:**
|
| 471 |
+
- Can assign single or multiple tickets to an agent
|
| 472 |
+
- Can set scheduled date and time slot
|
| 473 |
+
- System creates ticket assignment record
|
| 474 |
+
- Agent receives notification
|
| 475 |
+
- Ticket status changes to 'assigned'
|
| 476 |
+
|
| 477 |
+
**API Endpoints:**
|
| 478 |
+
```
|
| 479 |
+
POST /api/v1/tickets/{ticket_id}/assign
|
| 480 |
+
POST /api/v1/tickets/bulk-assign
|
| 481 |
+
GET /api/v1/tickets/{ticket_id}/assignments
|
| 482 |
+
POST /api/v1/tickets/{ticket_id}/reassign
|
| 483 |
+
POST /api/v1/tickets/{ticket_id}/unassign
|
| 484 |
+
```
|
| 485 |
+
|
| 486 |
+
### 5.2 Inventory Issuance
|
| 487 |
+
|
| 488 |
+
**US-DI-003: Issue Equipment to Field Agents**
|
| 489 |
+
- **As a** Dispatcher
|
| 490 |
+
- **I want to** issue equipment to field agents from regional hub
|
| 491 |
+
- **So that** they have materials for installations
|
| 492 |
+
|
| 493 |
+
**Acceptance Criteria:**
|
| 494 |
+
- Can scan or enter serial numbers/box numbers
|
| 495 |
+
- Can issue multiple items at once
|
| 496 |
+
- System tracks who issued and who received
|
| 497 |
+
- Can link equipment to specific tickets
|
| 498 |
+
- System updates inventory quantities
|
| 499 |
+
|
| 500 |
+
**API Endpoints:**
|
| 501 |
+
```
|
| 502 |
+
POST /api/v1/regions/{region_id}/issue-equipment
|
| 503 |
+
GET /api/v1/field-agents/{agent_id}/equipment
|
| 504 |
+
GET /api/v1/equipment-assignments
|
| 505 |
+
POST /api/v1/equipment-assignments/{assignment_id}/return
|
| 506 |
+
GET /api/v1/equipment-assignments/unreturned
|
| 507 |
+
```
|
| 508 |
+
|
| 509 |
+
### 5.3 Expense Approval
|
| 510 |
+
|
| 511 |
+
**US-DI-004: Review and Approve Expenses**
|
| 512 |
+
- **As a** Dispatcher
|
| 513 |
+
- **I want to** review expense claims from field agents
|
| 514 |
+
- **So that** valid expenses can be reimbursed
|
| 515 |
+
|
| 516 |
+
**Acceptance Criteria:**
|
| 517 |
+
- Can view pending expense claims
|
| 518 |
+
- Can see expense details, receipts, and location verification
|
| 519 |
+
- Can approve or reject with reason
|
| 520 |
+
- Can filter by agent, date, or ticket
|
| 521 |
+
- System validates location before approval
|
| 522 |
+
|
| 523 |
+
**API Endpoints:**
|
| 524 |
+
```
|
| 525 |
+
GET /api/v1/expenses/pending
|
| 526 |
+
GET /api/v1/expenses/{expense_id}
|
| 527 |
+
POST /api/v1/expenses/{expense_id}/approve
|
| 528 |
+
POST /api/v1/expenses/{expense_id}/reject
|
| 529 |
+
GET /api/v1/tickets/{ticket_id}/expenses
|
| 530 |
+
GET /api/v1/field-agents/{agent_id}/expenses
|
| 531 |
+
```
|
| 532 |
+
|
| 533 |
+
|
| 534 |
+
---
|
| 535 |
+
|
| 536 |
+
## 6. FIELD AGENT
|
| 537 |
+
|
| 538 |
+
### 6.1 Ticket Management
|
| 539 |
+
|
| 540 |
+
**US-FA-001: View My Assigned Tickets**
|
| 541 |
+
- **As a** Field Agent
|
| 542 |
+
- **I want to** view tickets assigned to me
|
| 543 |
+
- **So that** I know what work I need to do
|
| 544 |
+
|
| 545 |
+
**Acceptance Criteria:**
|
| 546 |
+
- Can view assigned tickets in list or map view
|
| 547 |
+
- Can see ticket details, customer info, and location
|
| 548 |
+
- Can filter by status and priority
|
| 549 |
+
- Can see route to customer location
|
| 550 |
+
- Can set execution order for my tickets
|
| 551 |
+
|
| 552 |
+
**API Endpoints:**
|
| 553 |
+
```
|
| 554 |
+
GET /api/v1/field-agents/me/tickets
|
| 555 |
+
GET /api/v1/field-agents/me/tickets/today
|
| 556 |
+
GET /api/v1/tickets/{ticket_id}
|
| 557 |
+
PUT /api/v1/tickets/{ticket_id}/execution-order
|
| 558 |
+
GET /api/v1/tickets/{ticket_id}/route
|
| 559 |
+
```
|
| 560 |
+
|
| 561 |
+
**US-FA-002: Accept or Reject Ticket Assignment**
|
| 562 |
+
- **As a** Field Agent
|
| 563 |
+
- **I want to** accept or reject assigned tickets
|
| 564 |
+
- **So that** I can manage my workload
|
| 565 |
+
|
| 566 |
+
**Acceptance Criteria:**
|
| 567 |
+
- Can accept ticket (status changes to 'in_progress')
|
| 568 |
+
- Can reject ticket with reason
|
| 569 |
+
- Can request reassignment
|
| 570 |
+
- System records response timestamp
|
| 571 |
+
- Dispatcher is notified of rejection
|
| 572 |
+
|
| 573 |
+
**API Endpoints:**
|
| 574 |
+
```
|
| 575 |
+
POST /api/v1/tickets/{ticket_id}/accept
|
| 576 |
+
POST /api/v1/tickets/{ticket_id}/reject
|
| 577 |
+
POST /api/v1/tickets/{ticket_id}/request-reassignment
|
| 578 |
+
```
|
| 579 |
+
|
| 580 |
+
**US-FA-003: Start Journey to Customer Site**
|
| 581 |
+
- **As a** Field Agent
|
| 582 |
+
- **I want to** start journey tracking when I leave for a ticket
|
| 583 |
+
- **So that** my travel can be monitored
|
| 584 |
+
|
| 585 |
+
**Acceptance Criteria:**
|
| 586 |
+
- Can start journey with one tap
|
| 587 |
+
- System records journey start location and time
|
| 588 |
+
- GPS tracking begins (breadcrumb trail)
|
| 589 |
+
- Can see estimated arrival time
|
| 590 |
+
- Can pause/resume journey
|
| 591 |
+
|
| 592 |
+
**API Endpoints:**
|
| 593 |
+
```
|
| 594 |
+
POST /api/v1/tickets/{ticket_id}/start-journey
|
| 595 |
+
POST /api/v1/tickets/{ticket_id}/pause-journey
|
| 596 |
+
POST /api/v1/tickets/{ticket_id}/resume-journey
|
| 597 |
+
POST /api/v1/tickets/{ticket_id}/location-update
|
| 598 |
+
GET /api/v1/tickets/{ticket_id}/journey-status
|
| 599 |
+
```
|
| 600 |
+
|
| 601 |
+
|
| 602 |
+
**US-FA-004: Mark Arrival at Customer Site**
|
| 603 |
+
- **As a** Field Agent
|
| 604 |
+
- **I want to** mark when I arrive at customer location
|
| 605 |
+
- **So that** my arrival time is recorded
|
| 606 |
+
|
| 607 |
+
**Acceptance Criteria:**
|
| 608 |
+
- Can mark arrival with GPS verification
|
| 609 |
+
- System validates location matches customer address
|
| 610 |
+
- Journey tracking stops
|
| 611 |
+
- Arrival time is recorded
|
| 612 |
+
- Can proceed to work execution
|
| 613 |
+
|
| 614 |
+
**API Endpoints:**
|
| 615 |
+
```
|
| 616 |
+
POST /api/v1/tickets/{ticket_id}/mark-arrival
|
| 617 |
+
GET /api/v1/tickets/{ticket_id}/verify-location
|
| 618 |
+
```
|
| 619 |
+
|
| 620 |
+
### 6.2 Customer Communication
|
| 621 |
+
|
| 622 |
+
**US-FA-005: Contact Customer**
|
| 623 |
+
- **As a** Field Agent
|
| 624 |
+
- **I want to** record customer communication attempts
|
| 625 |
+
- **So that** contact history is tracked
|
| 626 |
+
|
| 627 |
+
**Acceptance Criteria:**
|
| 628 |
+
- Can record call, SMS, WhatsApp, or in-person contact
|
| 629 |
+
- Can record outcome (successful, no answer, busy, etc.)
|
| 630 |
+
- Can schedule follow-up
|
| 631 |
+
- Can see previous communication history
|
| 632 |
+
- Can initiate call from app
|
| 633 |
+
|
| 634 |
+
**API Endpoints:**
|
| 635 |
+
```
|
| 636 |
+
POST /api/v1/tickets/{ticket_id}/communications
|
| 637 |
+
GET /api/v1/tickets/{ticket_id}/communications
|
| 638 |
+
GET /api/v1/customers/{customer_id}/communications
|
| 639 |
+
POST /api/v1/communications/{comm_id}/follow-up
|
| 640 |
+
```
|
| 641 |
+
|
| 642 |
+
### 6.3 Work Execution
|
| 643 |
+
|
| 644 |
+
**US-FA-006: Complete Installation**
|
| 645 |
+
- **As a** Field Agent
|
| 646 |
+
- **I want to** record installation details and activate service
|
| 647 |
+
- **So that** customer can start using the service
|
| 648 |
+
|
| 649 |
+
**Acceptance Criteria:**
|
| 650 |
+
- Can enter equipment details (ONT serial, MAC address, etc.)
|
| 651 |
+
- Can capture before/after photos
|
| 652 |
+
- Can record activation details
|
| 653 |
+
- Can create subscription record
|
| 654 |
+
- Ticket status changes to 'completed'
|
| 655 |
+
- System validates all required fields
|
| 656 |
+
|
| 657 |
+
**API Endpoints:**
|
| 658 |
+
```
|
| 659 |
+
POST /api/v1/tickets/{ticket_id}/complete
|
| 660 |
+
POST /api/v1/tickets/{ticket_id}/photos
|
| 661 |
+
POST /api/v1/tickets/{ticket_id}/equipment-details
|
| 662 |
+
POST /api/v1/subscriptions
|
| 663 |
+
GET /api/v1/projects/{project_id}/activation-requirements
|
| 664 |
+
```
|
| 665 |
+
|
| 666 |
+
|
| 667 |
+
**US-FA-007: Log Expenses**
|
| 668 |
+
- **As a** Field Agent
|
| 669 |
+
- **I want to** record expenses incurred during ticket execution
|
| 670 |
+
- **So that** I can be reimbursed
|
| 671 |
+
|
| 672 |
+
**Acceptance Criteria:**
|
| 673 |
+
- Can log transport, materials, meals, etc.
|
| 674 |
+
- Can attach receipt photos
|
| 675 |
+
- Can specify quantity and unit cost
|
| 676 |
+
- System validates location (must be at customer site)
|
| 677 |
+
- Can see expense approval status
|
| 678 |
+
|
| 679 |
+
**API Endpoints:**
|
| 680 |
+
```
|
| 681 |
+
POST /api/v1/tickets/{ticket_id}/expenses
|
| 682 |
+
GET /api/v1/field-agents/me/expenses
|
| 683 |
+
GET /api/v1/expenses/{expense_id}
|
| 684 |
+
PUT /api/v1/expenses/{expense_id}
|
| 685 |
+
DELETE /api/v1/expenses/{expense_id}
|
| 686 |
+
```
|
| 687 |
+
|
| 688 |
+
### 6.4 Inventory Management
|
| 689 |
+
|
| 690 |
+
**US-FA-008: View My Equipment**
|
| 691 |
+
- **As a** Field Agent
|
| 692 |
+
- **I want to** view equipment issued to me
|
| 693 |
+
- **So that** I know what I have and what needs to be returned
|
| 694 |
+
|
| 695 |
+
**Acceptance Criteria:**
|
| 696 |
+
- Can see all equipment currently in my possession
|
| 697 |
+
- Can see tools that need to be returned
|
| 698 |
+
- Can see equipment installed at customer sites
|
| 699 |
+
- Can scan equipment for quick lookup
|
| 700 |
+
|
| 701 |
+
**API Endpoints:**
|
| 702 |
+
```
|
| 703 |
+
GET /api/v1/field-agents/me/equipment
|
| 704 |
+
GET /api/v1/field-agents/me/equipment/unreturned
|
| 705 |
+
GET /api/v1/equipment/{serial_number}
|
| 706 |
+
```
|
| 707 |
+
|
| 708 |
+
**US-FA-009: Return Equipment**
|
| 709 |
+
- **As a** Field Agent
|
| 710 |
+
- **I want to** return tools to the regional hub
|
| 711 |
+
- **So that** they can be reissued to other agents
|
| 712 |
+
|
| 713 |
+
**Acceptance Criteria:**
|
| 714 |
+
- Can scan equipment to return
|
| 715 |
+
- Can specify condition (good, damaged, worn)
|
| 716 |
+
- Can add return notes
|
| 717 |
+
- System updates inventory quantities
|
| 718 |
+
- Dispatcher confirms receipt
|
| 719 |
+
|
| 720 |
+
**API Endpoints:**
|
| 721 |
+
```
|
| 722 |
+
POST /api/v1/equipment-assignments/{assignment_id}/return
|
| 723 |
+
POST /api/v1/equipment-assignments/bulk-return
|
| 724 |
+
```
|
| 725 |
+
|
| 726 |
+
|
| 727 |
+
### 6.5 Attendance & Timesheets
|
| 728 |
+
|
| 729 |
+
**US-FA-010: Clock In/Out**
|
| 730 |
+
- **As a** Field Agent
|
| 731 |
+
- **I want to** record my daily attendance
|
| 732 |
+
- **So that** my work hours are tracked
|
| 733 |
+
|
| 734 |
+
**Acceptance Criteria:**
|
| 735 |
+
- Can clock in at start of day
|
| 736 |
+
- Can clock out at end of day
|
| 737 |
+
- System records timestamps and location
|
| 738 |
+
- Can view my timesheet history
|
| 739 |
+
- Can request leave
|
| 740 |
+
|
| 741 |
+
**API Endpoints:**
|
| 742 |
+
```
|
| 743 |
+
POST /api/v1/field-agents/me/clock-in
|
| 744 |
+
POST /api/v1/field-agents/me/clock-out
|
| 745 |
+
GET /api/v1/field-agents/me/timesheets
|
| 746 |
+
POST /api/v1/field-agents/me/request-leave
|
| 747 |
+
```
|
| 748 |
+
|
| 749 |
+
---
|
| 750 |
+
|
| 751 |
+
## 7. SALES AGENT
|
| 752 |
+
|
| 753 |
+
### 7.1 Sales Order Management
|
| 754 |
+
|
| 755 |
+
**US-SA-001: Create Sales Order**
|
| 756 |
+
- **As a** Sales Agent
|
| 757 |
+
- **I want to** create sales orders for new customers
|
| 758 |
+
- **So that** installations can be scheduled
|
| 759 |
+
|
| 760 |
+
**Acceptance Criteria:**
|
| 761 |
+
- Can enter customer details (name, phone, address)
|
| 762 |
+
- System deduplicates customers by phone number
|
| 763 |
+
- Can specify package and price
|
| 764 |
+
- Can set preferred installation date/time
|
| 765 |
+
- Can add installation address with GPS coordinates
|
| 766 |
+
|
| 767 |
+
**API Endpoints:**
|
| 768 |
+
```
|
| 769 |
+
POST /api/v1/sales-orders
|
| 770 |
+
GET /api/v1/sales-agents/me/orders
|
| 771 |
+
GET /api/v1/sales-orders/{order_id}
|
| 772 |
+
PUT /api/v1/sales-orders/{order_id}
|
| 773 |
+
POST /api/v1/customers/check-duplicate
|
| 774 |
+
```
|
| 775 |
+
|
| 776 |
+
**US-SA-002: Track My Sales**
|
| 777 |
+
- **As a** Sales Agent
|
| 778 |
+
- **I want to** view my sales performance
|
| 779 |
+
- **So that** I can track my commissions
|
| 780 |
+
|
| 781 |
+
**Acceptance Criteria:**
|
| 782 |
+
- Can view total orders, completed installations, pending
|
| 783 |
+
- Can see commission earned and pending
|
| 784 |
+
- Can filter by date range
|
| 785 |
+
- Can see conversion funnel (orders → tickets → installations)
|
| 786 |
+
|
| 787 |
+
**API Endpoints:**
|
| 788 |
+
```
|
| 789 |
+
GET /api/v1/sales-agents/me/stats
|
| 790 |
+
GET /api/v1/sales-agents/me/commissions
|
| 791 |
+
GET /api/v1/sales-agents/me/conversion-funnel
|
| 792 |
+
```
|
| 793 |
+
|
| 794 |
+
|
| 795 |
+
---
|
| 796 |
+
|
| 797 |
+
## 8. SALES MANAGER
|
| 798 |
+
|
| 799 |
+
### 8.1 Team Performance
|
| 800 |
+
|
| 801 |
+
**US-SM-001: View Team Sales Performance**
|
| 802 |
+
- **As a** Sales Manager
|
| 803 |
+
- **I want to** view sales performance across my team
|
| 804 |
+
- **So that** I can identify top performers and areas for improvement
|
| 805 |
+
|
| 806 |
+
**Acceptance Criteria:**
|
| 807 |
+
- Can view sales by agent, region, package type
|
| 808 |
+
- Can see conversion rates and average deal size
|
| 809 |
+
- Can filter by date range
|
| 810 |
+
- Can export reports
|
| 811 |
+
|
| 812 |
+
**API Endpoints:**
|
| 813 |
+
```
|
| 814 |
+
GET /api/v1/sales/team-performance
|
| 815 |
+
GET /api/v1/sales/by-agent
|
| 816 |
+
GET /api/v1/sales/by-region
|
| 817 |
+
GET /api/v1/sales/by-package
|
| 818 |
+
POST /api/v1/sales/export-report
|
| 819 |
+
```
|
| 820 |
+
|
| 821 |
+
---
|
| 822 |
+
|
| 823 |
+
## 9. SUPPORT TICKETS (All Roles)
|
| 824 |
+
|
| 825 |
+
### 9.1 Incident Management
|
| 826 |
+
|
| 827 |
+
**US-SUP-001: Create Support Incident**
|
| 828 |
+
- **As a** Support Staff
|
| 829 |
+
- **I want to** create incidents for customer complaints
|
| 830 |
+
- **So that** support tickets can be generated
|
| 831 |
+
|
| 832 |
+
**Acceptance Criteria:**
|
| 833 |
+
- Can search for customer by phone or subscription
|
| 834 |
+
- Can record incident type and description
|
| 835 |
+
- Can set priority
|
| 836 |
+
- System creates support ticket automatically
|
| 837 |
+
- Customer is notified
|
| 838 |
+
|
| 839 |
+
**API Endpoints:**
|
| 840 |
+
```
|
| 841 |
+
POST /api/v1/incidents
|
| 842 |
+
GET /api/v1/incidents
|
| 843 |
+
GET /api/v1/incidents/{incident_id}
|
| 844 |
+
PUT /api/v1/incidents/{incident_id}
|
| 845 |
+
POST /api/v1/incidents/{incident_id}/create-ticket
|
| 846 |
+
POST /api/v1/incidents/{incident_id}/resolve
|
| 847 |
+
```
|
| 848 |
+
|
| 849 |
+
---
|
| 850 |
+
|
| 851 |
+
## 10. COMMON ENDPOINTS
|
| 852 |
+
|
| 853 |
+
### 10.1 Authentication & Authorization
|
| 854 |
+
|
| 855 |
+
**API Endpoints:**
|
| 856 |
+
```
|
| 857 |
+
POST /api/v1/auth/login
|
| 858 |
+
POST /api/v1/auth/logout
|
| 859 |
+
POST /api/v1/auth/refresh-token
|
| 860 |
+
GET /api/v1/auth/me
|
| 861 |
+
PUT /api/v1/auth/me/profile
|
| 862 |
+
POST /api/v1/auth/change-password
|
| 863 |
+
POST /api/v1/auth/forgot-password
|
| 864 |
+
POST /api/v1/auth/reset-password
|
| 865 |
+
```
|
| 866 |
+
|
| 867 |
+
|
| 868 |
+
### 10.2 Dashboard & Analytics
|
| 869 |
+
|
| 870 |
+
**API Endpoints:**
|
| 871 |
+
```
|
| 872 |
+
GET /api/v1/dashboard/overview
|
| 873 |
+
GET /api/v1/dashboard/tickets-pipeline
|
| 874 |
+
GET /api/v1/dashboard/sla-compliance
|
| 875 |
+
GET /api/v1/dashboard/team-performance
|
| 876 |
+
GET /api/v1/dashboard/financial-summary
|
| 877 |
+
GET /api/v1/dashboard/inventory-status
|
| 878 |
+
GET /api/v1/dashboard/map-view
|
| 879 |
+
```
|
| 880 |
+
|
| 881 |
+
### 10.3 Notifications
|
| 882 |
+
|
| 883 |
+
**API Endpoints:**
|
| 884 |
+
```
|
| 885 |
+
GET /api/v1/notifications
|
| 886 |
+
GET /api/v1/notifications/unread
|
| 887 |
+
POST /api/v1/notifications/{notification_id}/mark-read
|
| 888 |
+
POST /api/v1/notifications/mark-all-read
|
| 889 |
+
DELETE /api/v1/notifications/{notification_id}
|
| 890 |
+
```
|
| 891 |
+
|
| 892 |
+
### 10.4 Documents & Files
|
| 893 |
+
|
| 894 |
+
**API Endpoints:**
|
| 895 |
+
```
|
| 896 |
+
POST /api/v1/documents/upload
|
| 897 |
+
GET /api/v1/documents/{document_id}
|
| 898 |
+
GET /api/v1/documents/{document_id}/download
|
| 899 |
+
DELETE /api/v1/documents/{document_id}
|
| 900 |
+
GET /api/v1/tickets/{ticket_id}/documents
|
| 901 |
+
GET /api/v1/users/{user_id}/documents
|
| 902 |
+
```
|
| 903 |
+
|
| 904 |
+
### 10.5 Search & Filters
|
| 905 |
+
|
| 906 |
+
**API Endpoints:**
|
| 907 |
+
```
|
| 908 |
+
GET /api/v1/search/customers
|
| 909 |
+
GET /api/v1/search/tickets
|
| 910 |
+
GET /api/v1/search/users
|
| 911 |
+
GET /api/v1/search/global
|
| 912 |
+
```
|
| 913 |
+
|
| 914 |
+
---
|
| 915 |
+
|
| 916 |
+
## 11. WORKFLOW ENDPOINTS
|
| 917 |
+
|
| 918 |
+
### 11.1 Sales Order → Installation Workflow
|
| 919 |
+
|
| 920 |
+
**Complete Flow:**
|
| 921 |
+
```
|
| 922 |
+
1. POST /api/v1/sales-orders # Create order
|
| 923 |
+
2. POST /api/v1/sales-orders/{id}/create-ticket # Generate ticket
|
| 924 |
+
3. POST /api/v1/tickets/{id}/assign # Assign to agent
|
| 925 |
+
4. POST /api/v1/tickets/{id}/accept # Agent accepts
|
| 926 |
+
5. POST /api/v1/tickets/{id}/start-journey # Start travel
|
| 927 |
+
6. POST /api/v1/tickets/{id}/mark-arrival # Arrive at site
|
| 928 |
+
7. POST /api/v1/tickets/{id}/complete # Complete work
|
| 929 |
+
8. POST /api/v1/subscriptions # Activate service
|
| 930 |
+
```
|
| 931 |
+
|
| 932 |
+
|
| 933 |
+
### 11.2 Support Incident → Resolution Workflow
|
| 934 |
+
|
| 935 |
+
**Complete Flow:**
|
| 936 |
+
```
|
| 937 |
+
1. POST /api/v1/incidents # Create incident
|
| 938 |
+
2. POST /api/v1/incidents/{id}/create-ticket # Generate ticket
|
| 939 |
+
3. POST /api/v1/tickets/{id}/assign # Assign to agent
|
| 940 |
+
4. POST /api/v1/tickets/{id}/accept # Agent accepts
|
| 941 |
+
5. POST /api/v1/tickets/{id}/start-journey # Start travel
|
| 942 |
+
6. POST /api/v1/tickets/{id}/mark-arrival # Arrive at site
|
| 943 |
+
7. POST /api/v1/tickets/{id}/complete # Complete repair
|
| 944 |
+
8. POST /api/v1/incidents/{id}/resolve # Mark resolved
|
| 945 |
+
```
|
| 946 |
+
|
| 947 |
+
### 11.3 Infrastructure Task → Completion Workflow
|
| 948 |
+
|
| 949 |
+
**Complete Flow:**
|
| 950 |
+
```
|
| 951 |
+
1. POST /api/v1/projects/{id}/tasks # Create task
|
| 952 |
+
2. POST /api/v1/tasks/{id}/create-ticket # Generate ticket
|
| 953 |
+
3. POST /api/v1/tickets/{id}/assign # Assign to contractor
|
| 954 |
+
4. POST /api/v1/tickets/{id}/accept # Contractor accepts
|
| 955 |
+
5. POST /api/v1/tickets/{id}/start-journey # Start travel
|
| 956 |
+
6. POST /api/v1/tickets/{id}/mark-arrival # Arrive at site
|
| 957 |
+
7. POST /api/v1/tickets/{id}/complete # Complete work
|
| 958 |
+
```
|
| 959 |
+
|
| 960 |
+
---
|
| 961 |
+
|
| 962 |
+
## 12. API DESIGN PRINCIPLES
|
| 963 |
+
|
| 964 |
+
### 12.1 RESTful Conventions
|
| 965 |
+
|
| 966 |
+
- **GET** - Retrieve resources
|
| 967 |
+
- **POST** - Create new resources
|
| 968 |
+
- **PUT** - Update entire resource
|
| 969 |
+
- **PATCH** - Partial update
|
| 970 |
+
- **DELETE** - Remove resource
|
| 971 |
+
|
| 972 |
+
### 12.2 Response Format
|
| 973 |
+
|
| 974 |
+
**Success Response:**
|
| 975 |
+
```json
|
| 976 |
+
{
|
| 977 |
+
"success": true,
|
| 978 |
+
"data": { ... },
|
| 979 |
+
"message": "Operation completed successfully",
|
| 980 |
+
"timestamp": "2024-01-15T10:30:00Z"
|
| 981 |
+
}
|
| 982 |
+
```
|
| 983 |
+
|
| 984 |
+
**Error Response:**
|
| 985 |
+
```json
|
| 986 |
+
{
|
| 987 |
+
"success": false,
|
| 988 |
+
"error": {
|
| 989 |
+
"code": "VALIDATION_ERROR",
|
| 990 |
+
"message": "Invalid input data",
|
| 991 |
+
"details": { ... }
|
| 992 |
+
},
|
| 993 |
+
"timestamp": "2024-01-15T10:30:00Z"
|
| 994 |
+
}
|
| 995 |
+
```
|
| 996 |
+
|
| 997 |
+
### 12.3 Pagination
|
| 998 |
+
|
| 999 |
+
**Query Parameters:**
|
| 1000 |
+
```
|
| 1001 |
+
?page=1&limit=25&sort_by=created_at&sort_order=desc
|
| 1002 |
+
```
|
| 1003 |
+
|
| 1004 |
+
**Response:**
|
| 1005 |
+
```json
|
| 1006 |
+
{
|
| 1007 |
+
"success": true,
|
| 1008 |
+
"data": [...],
|
| 1009 |
+
"pagination": {
|
| 1010 |
+
"page": 1,
|
| 1011 |
+
"limit": 25,
|
| 1012 |
+
"total": 150,
|
| 1013 |
+
"total_pages": 6
|
| 1014 |
+
}
|
| 1015 |
+
}
|
| 1016 |
+
```
|
| 1017 |
+
|
| 1018 |
+
|
| 1019 |
+
### 12.4 Filtering & Search
|
| 1020 |
+
|
| 1021 |
+
**Query Parameters:**
|
| 1022 |
+
```
|
| 1023 |
+
?status=open&priority=high®ion_id=uuid&search=customer_name
|
| 1024 |
+
```
|
| 1025 |
+
|
| 1026 |
+
### 12.5 Authentication
|
| 1027 |
+
|
| 1028 |
+
**Header:**
|
| 1029 |
+
```
|
| 1030 |
+
Authorization: Bearer <jwt_token>
|
| 1031 |
+
```
|
| 1032 |
+
|
| 1033 |
+
### 12.6 Rate Limiting
|
| 1034 |
+
|
| 1035 |
+
**Headers:**
|
| 1036 |
+
```
|
| 1037 |
+
X-RateLimit-Limit: 1000
|
| 1038 |
+
X-RateLimit-Remaining: 999
|
| 1039 |
+
X-RateLimit-Reset: 1640000000
|
| 1040 |
+
```
|
| 1041 |
+
|
| 1042 |
+
---
|
| 1043 |
+
|
| 1044 |
+
## 13. PRIORITY IMPLEMENTATION ORDER
|
| 1045 |
+
|
| 1046 |
+
### Phase 1: Core Foundation (MVP)
|
| 1047 |
+
1. Authentication & User Management
|
| 1048 |
+
2. Organization Management (Clients, Contractors)
|
| 1049 |
+
3. Project Setup
|
| 1050 |
+
4. User Invitations
|
| 1051 |
+
|
| 1052 |
+
### Phase 2: Sales & Ticketing
|
| 1053 |
+
1. Sales Order Management
|
| 1054 |
+
2. Customer Management
|
| 1055 |
+
3. Ticket Generation
|
| 1056 |
+
4. Ticket Assignment
|
| 1057 |
+
|
| 1058 |
+
### Phase 3: Field Operations
|
| 1059 |
+
1. Field Agent Ticket Management
|
| 1060 |
+
2. Journey Tracking
|
| 1061 |
+
3. Work Completion
|
| 1062 |
+
4. Subscription Activation
|
| 1063 |
+
|
| 1064 |
+
### Phase 4: Inventory & Expenses
|
| 1065 |
+
1. Inventory Management
|
| 1066 |
+
2. Equipment Issuance
|
| 1067 |
+
3. Expense Logging
|
| 1068 |
+
4. Expense Approval
|
| 1069 |
+
|
| 1070 |
+
### Phase 5: Financial & Reporting
|
| 1071 |
+
1. Project Finance Tracking
|
| 1072 |
+
2. Contractor Invoicing
|
| 1073 |
+
3. Payroll Management
|
| 1074 |
+
4. Dashboard Analytics
|
| 1075 |
+
|
| 1076 |
+
### Phase 6: Advanced Features
|
| 1077 |
+
1. Support Incidents
|
| 1078 |
+
2. Infrastructure Tasks
|
| 1079 |
+
3. Document Management
|
| 1080 |
+
4. Advanced Analytics
|
| 1081 |
+
|
| 1082 |
+
---
|
| 1083 |
+
|
| 1084 |
+
## 14. TECHNICAL NOTES
|
| 1085 |
+
|
| 1086 |
+
### 14.1 Database Access
|
| 1087 |
+
- All database operations go through FastAPI backend
|
| 1088 |
+
- Frontend NEVER queries Supabase directly
|
| 1089 |
+
- Backend handles all business logic and validation
|
| 1090 |
+
|
| 1091 |
+
### 14.2 Real-time Updates
|
| 1092 |
+
- Use WebSockets for real-time location tracking
|
| 1093 |
+
- Use Server-Sent Events (SSE) for notifications
|
| 1094 |
+
- Polling for dashboard updates (every 30 seconds)
|
| 1095 |
+
|
| 1096 |
+
### 14.3 File Uploads
|
| 1097 |
+
- Images uploaded to Supabase Storage
|
| 1098 |
+
- Backend generates signed URLs
|
| 1099 |
+
- Maximum file size: 10MB per file
|
| 1100 |
+
- Supported formats: JPG, PNG, PDF
|
| 1101 |
+
|
| 1102 |
+
### 14.4 GPS & Location
|
| 1103 |
+
- Location accuracy threshold: 50 meters
|
| 1104 |
+
- Location updates every 30 seconds during journey
|
| 1105 |
+
- Offline support: Queue location updates, sync when online
|
| 1106 |
+
|
| 1107 |
+
### 14.5 Security
|
| 1108 |
+
- JWT tokens with 24-hour expiry
|
| 1109 |
+
- Refresh tokens with 30-day expiry
|
| 1110 |
+
- Role-based access control (RBAC)
|
| 1111 |
+
- Row-level security (RLS) in database
|
| 1112 |
+
- API rate limiting: 1000 requests/hour per user
|
| 1113 |
+
|
| 1114 |
+
---
|
| 1115 |
+
|
| 1116 |
+
**Document Version:** 1.0
|
| 1117 |
+
**Last Updated:** 2024-01-15
|
| 1118 |
+
**Status:** Draft - Ready for Backend Implementation
|
requirements-dev.txt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Development dependencies
|
| 2 |
+
-r requirements.txt
|
| 3 |
+
|
| 4 |
+
# Testing
|
| 5 |
+
pytest==7.4.3
|
| 6 |
+
pytest-asyncio==0.21.1
|
| 7 |
+
pytest-cov==4.1.0
|
| 8 |
+
pytest-mock==3.12.0
|
| 9 |
+
faker==20.1.0
|
| 10 |
+
|
| 11 |
+
# Code Quality
|
| 12 |
+
black==23.11.0
|
| 13 |
+
isort==5.12.0
|
| 14 |
+
flake8==6.1.0
|
| 15 |
+
mypy==1.7.1
|
| 16 |
+
pylint==3.0.3
|
| 17 |
+
|
| 18 |
+
# Documentation
|
| 19 |
+
mkdocs==1.5.3
|
| 20 |
+
mkdocs-material==9.5.2
|
| 21 |
+
|
| 22 |
+
# Development Tools
|
| 23 |
+
ipython==8.18.1
|
| 24 |
+
ipdb==0.13.13
|
| 25 |
+
watchdog==3.0.0
|
requirements.txt
CHANGED
|
@@ -1,126 +1,49 @@
|
|
| 1 |
-
# ============================================
|
| 2 |
# Core Framework
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
gunicorn==21.2.0
|
| 7 |
-
pydantic==2.5.3
|
| 8 |
pydantic-settings==2.1.0
|
|
|
|
|
|
|
| 9 |
|
| 10 |
-
#
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
sqlalchemy==2.0.25
|
| 14 |
-
alembic==1.13.1
|
| 15 |
psycopg2-binary==2.9.9
|
| 16 |
-
asyncpg==0.29.0
|
| 17 |
|
| 18 |
-
# ============================================
|
| 19 |
-
# Supabase Integration
|
| 20 |
-
# ============================================
|
| 21 |
-
supabase==2.3.4
|
| 22 |
-
postgrest-py==0.13.2
|
| 23 |
-
|
| 24 |
-
# ============================================
|
| 25 |
# Authentication & Security
|
| 26 |
-
# ============================================
|
| 27 |
python-jose[cryptography]==3.3.0
|
| 28 |
passlib[bcrypt]==1.7.4
|
| 29 |
python-multipart==0.0.6
|
| 30 |
-
bcrypt==4.1.2
|
| 31 |
|
| 32 |
-
#
|
| 33 |
-
# Background Tasks
|
| 34 |
-
# ============================================
|
| 35 |
-
celery==5.3.6
|
| 36 |
redis==5.0.1
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
flower==2.0.1
|
| 38 |
|
| 39 |
-
#
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
requests==2.31.0
|
| 44 |
-
aiohttp==3.9.1
|
| 45 |
|
| 46 |
-
#
|
| 47 |
-
# Data Validation & Serialization
|
| 48 |
-
# ============================================
|
| 49 |
python-dateutil==2.8.2
|
| 50 |
-
pytz==2023.3
|
| 51 |
-
|
| 52 |
-
# ============================================
|
| 53 |
-
# Payment Gateway Integration
|
| 54 |
-
# ============================================
|
| 55 |
-
# M-Pesa (Safaricom)
|
| 56 |
-
# Note: Install specific M-Pesa SDK based on your provider
|
| 57 |
-
# Example: mpesa-sdk==1.0.0
|
| 58 |
-
|
| 59 |
-
# ============================================
|
| 60 |
-
# SMS & Email
|
| 61 |
-
# ============================================
|
| 62 |
-
sendgrid==6.11.0
|
| 63 |
-
twilio==8.11.1
|
| 64 |
-
# Africa's Talking
|
| 65 |
-
africastalking==1.2.6
|
| 66 |
|
| 67 |
-
# ============================================
|
| 68 |
-
# Google Maps API
|
| 69 |
-
# ============================================
|
| 70 |
-
googlemaps==4.10.0
|
| 71 |
-
|
| 72 |
-
# ============================================
|
| 73 |
-
# File Storage
|
| 74 |
-
# ============================================
|
| 75 |
-
boto3==1.34.34 # AWS S3
|
| 76 |
-
python-magic==0.4.27 # File type detection
|
| 77 |
-
|
| 78 |
-
# ============================================
|
| 79 |
# Monitoring & Logging
|
| 80 |
-
|
| 81 |
-
sentry-sdk[fastapi]==1.40.0
|
| 82 |
-
structlog==24.1.0
|
| 83 |
-
python-json-logger==2.0.7
|
| 84 |
-
|
| 85 |
-
# ============================================
|
| 86 |
-
# Testing
|
| 87 |
-
# ============================================
|
| 88 |
-
pytest==7.4.4
|
| 89 |
-
pytest-asyncio==0.23.3
|
| 90 |
-
pytest-cov==4.1.0
|
| 91 |
-
pytest-mock==3.12.0
|
| 92 |
-
faker==22.2.0
|
| 93 |
-
factory-boy==3.3.0
|
| 94 |
-
httpx==0.26.0 # For testing async endpoints
|
| 95 |
|
| 96 |
-
#
|
| 97 |
-
|
| 98 |
-
# ============================================
|
| 99 |
-
black==24.1.1
|
| 100 |
-
isort==5.13.2
|
| 101 |
-
flake8==7.0.0
|
| 102 |
-
mypy==1.8.0
|
| 103 |
-
pylint==3.0.3
|
| 104 |
-
pre-commit==3.6.0
|
| 105 |
|
| 106 |
-
#
|
| 107 |
-
#
|
| 108 |
-
# ============================================
|
| 109 |
-
ipython==8.20.0
|
| 110 |
-
ipdb==0.13.13
|
| 111 |
-
python-dotenv==1.0.1
|
| 112 |
-
|
| 113 |
-
# ============================================
|
| 114 |
-
# Documentation
|
| 115 |
-
# ============================================
|
| 116 |
-
mkdocs==1.5.3
|
| 117 |
-
mkdocs-material==9.5.6
|
| 118 |
-
|
| 119 |
-
# ============================================
|
| 120 |
-
# Utilities
|
| 121 |
-
# ============================================
|
| 122 |
-
python-slugify==8.0.2
|
| 123 |
-
phonenumbers==8.13.28
|
| 124 |
-
email-validator==2.1.0.post1
|
| 125 |
-
openpyxl==3.1.2 # Excel file handling
|
| 126 |
-
pandas==2.2.0 # Data processing (for reports)
|
|
|
|
|
|
|
| 1 |
# Core Framework
|
| 2 |
+
fastapi==0.104.1
|
| 3 |
+
uvicorn[standard]==0.24.0
|
| 4 |
+
pydantic==2.5.0
|
|
|
|
|
|
|
| 5 |
pydantic-settings==2.1.0
|
| 6 |
+
jinja2==3.1.2
|
| 7 |
+
aiofiles==23.2.1
|
| 8 |
|
| 9 |
+
# Database
|
| 10 |
+
sqlalchemy==2.0.23
|
| 11 |
+
alembic==1.12.1
|
|
|
|
|
|
|
| 12 |
psycopg2-binary==2.9.9
|
|
|
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
# Authentication & Security
|
|
|
|
| 15 |
python-jose[cryptography]==3.3.0
|
| 16 |
passlib[bcrypt]==1.7.4
|
| 17 |
python-multipart==0.0.6
|
|
|
|
| 18 |
|
| 19 |
+
# Redis & Caching
|
|
|
|
|
|
|
|
|
|
| 20 |
redis==5.0.1
|
| 21 |
+
hiredis==2.2.3
|
| 22 |
+
|
| 23 |
+
# Celery (Background Tasks)
|
| 24 |
+
celery==5.3.4
|
| 25 |
flower==2.0.1
|
| 26 |
|
| 27 |
+
# External Integrations
|
| 28 |
+
supabase==2.0.3
|
| 29 |
+
cloudinary==1.36.0
|
| 30 |
+
resend==0.7.0
|
| 31 |
+
googlemaps==4.10.0
|
| 32 |
+
|
| 33 |
+
# HTTP Client
|
| 34 |
+
httpx==0.25.2
|
| 35 |
requests==2.31.0
|
|
|
|
| 36 |
|
| 37 |
+
# Utilities
|
|
|
|
|
|
|
| 38 |
python-dateutil==2.8.2
|
| 39 |
+
pytz==2023.3
|
| 40 |
+
phonenumbers==8.13.26
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
# Monitoring & Logging
|
| 43 |
+
sentry-sdk==1.38.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
# Rate Limiting
|
| 46 |
+
slowapi==0.1.9
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
+
# Note: Development dependencies moved to requirements-dev.txt
|
| 49 |
+
# This file contains only production dependencies
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/seed_database.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Database Seeding Script
|
| 3 |
+
Populates database with initial test data
|
| 4 |
+
"""
|
| 5 |
+
from sqlalchemy.orm import Session
|
| 6 |
+
from app.core.database import SessionLocal, engine
|
| 7 |
+
from app.models.base import Base
|
| 8 |
+
|
| 9 |
+
# TODO: Import models and create seed data
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def seed_database():
|
| 13 |
+
"""Seed database with initial data"""
|
| 14 |
+
db = SessionLocal()
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
print("Seeding database...")
|
| 18 |
+
|
| 19 |
+
# TODO: Create seed data
|
| 20 |
+
# - Platform admin user
|
| 21 |
+
# - Sample client
|
| 22 |
+
# - Sample contractor
|
| 23 |
+
# - Sample project
|
| 24 |
+
# - Sample users
|
| 25 |
+
|
| 26 |
+
db.commit()
|
| 27 |
+
print("Database seeded successfully!")
|
| 28 |
+
|
| 29 |
+
except Exception as e:
|
| 30 |
+
print(f"Error seeding database: {e}")
|
| 31 |
+
db.rollback()
|
| 32 |
+
finally:
|
| 33 |
+
db.close()
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
if __name__ == "__main__":
|
| 37 |
+
seed_database()
|
src/app/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
SwiftOps Backend Application
|
| 3 |
+
Field Service Management Platform for African Telecom
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
__version__ = "1.0.0"
|
src/app/api/__init__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
API Layer - HTTP Endpoints
|
| 3 |
+
"""
|
src/app/api/deps.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
API Route Dependencies
|
| 3 |
+
"""
|
| 4 |
+
from typing import Generator
|
| 5 |
+
from fastapi import Depends, HTTPException, status
|
| 6 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
| 7 |
+
from sqlalchemy.orm import Session
|
| 8 |
+
from app.core.database import SessionLocal
|
| 9 |
+
from app.core.auth import verify_token
|
| 10 |
+
from app.core.permissions import AppRole
|
| 11 |
+
|
| 12 |
+
security = HTTPBearer()
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def get_db() -> Generator[Session, None, None]:
|
| 16 |
+
"""Database session dependency"""
|
| 17 |
+
db = SessionLocal()
|
| 18 |
+
try:
|
| 19 |
+
yield db
|
| 20 |
+
finally:
|
| 21 |
+
db.close()
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
async def get_current_user(
|
| 25 |
+
credentials: HTTPAuthorizationCredentials = Depends(security),
|
| 26 |
+
db: Session = Depends(get_db)
|
| 27 |
+
):
|
| 28 |
+
"""
|
| 29 |
+
Get current authenticated user from JWT token
|
| 30 |
+
"""
|
| 31 |
+
token = credentials.credentials
|
| 32 |
+
payload = verify_token(token)
|
| 33 |
+
|
| 34 |
+
if not payload:
|
| 35 |
+
raise HTTPException(
|
| 36 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 37 |
+
detail="Could not validate credentials"
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
# TODO: Fetch user from database using payload['sub']
|
| 41 |
+
# For now, return payload
|
| 42 |
+
return payload
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def require_role(*allowed_roles: AppRole):
|
| 46 |
+
"""
|
| 47 |
+
Role-based access control dependency
|
| 48 |
+
"""
|
| 49 |
+
async def role_checker(current_user: dict = Depends(get_current_user)):
|
| 50 |
+
user_role = current_user.get("role")
|
| 51 |
+
if user_role not in [role.value for role in allowed_roles]:
|
| 52 |
+
raise HTTPException(
|
| 53 |
+
status_code=status.HTTP_403_FORBIDDEN,
|
| 54 |
+
detail=f"Access denied. Required roles: {', '.join([r.value for r in allowed_roles])}"
|
| 55 |
+
)
|
| 56 |
+
return current_user
|
| 57 |
+
return role_checker
|
src/app/api/v1/__init__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
API Version 1
|
| 3 |
+
"""
|
src/app/api/v1/analytics.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
ANALYTICS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement analytics endpoints
|
src/app/api/v1/assignments.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
ASSIGNMENTS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement assignments endpoints
|
src/app/api/v1/auth.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Authentication Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement authentication endpoints
|
| 9 |
+
# POST /login
|
| 10 |
+
# POST /register
|
| 11 |
+
# POST /logout
|
| 12 |
+
# POST /refresh-token
|
| 13 |
+
# GET /me
|
| 14 |
+
# POST /otp/generate
|
| 15 |
+
# POST /otp/verify
|
src/app/api/v1/customers.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CUSTOMERS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement customers endpoints
|
src/app/api/v1/documents.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
DOCUMENTS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement documents endpoints
|
src/app/api/v1/expenses.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
EXPENSES Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement expenses endpoints
|
src/app/api/v1/health.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
HEALTH Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement health endpoints
|
src/app/api/v1/incidents.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
INCIDENTS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement incidents endpoints
|
src/app/api/v1/inventory.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
INVENTORY Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement inventory endpoints
|
src/app/api/v1/media.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
MEDIA Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement media endpoints
|
src/app/api/v1/organizations.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
ORGANIZATIONS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement organizations endpoints
|
src/app/api/v1/pages.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Page Routes (HTML Templates)
|
| 3 |
+
Separate from API routes for clean architecture
|
| 4 |
+
"""
|
| 5 |
+
from fastapi import APIRouter, Request
|
| 6 |
+
from fastapi.responses import HTMLResponse
|
| 7 |
+
from fastapi.templating import Jinja2Templates
|
| 8 |
+
from datetime import datetime
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
from app.constants.app_metadata import (
|
| 11 |
+
APP_NAME,
|
| 12 |
+
APP_VERSION,
|
| 13 |
+
APP_DESCRIPTION,
|
| 14 |
+
APP_GITHUB_URL,
|
| 15 |
+
DOCS_URL,
|
| 16 |
+
REDOC_URL
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
# Get templates directory
|
| 20 |
+
templates_dir = Path(__file__).parent.parent.parent / "templates"
|
| 21 |
+
templates = Jinja2Templates(directory=str(templates_dir))
|
| 22 |
+
|
| 23 |
+
router = APIRouter(tags=["Pages"])
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@router.get("/", response_class=HTMLResponse, include_in_schema=False)
|
| 27 |
+
async def index(request: Request):
|
| 28 |
+
"""
|
| 29 |
+
Landing page - displays API information and available endpoints
|
| 30 |
+
"""
|
| 31 |
+
# Application metadata
|
| 32 |
+
app_data = {
|
| 33 |
+
"app_name": APP_NAME,
|
| 34 |
+
"app_version": APP_VERSION,
|
| 35 |
+
"app_description": APP_DESCRIPTION,
|
| 36 |
+
"current_year": datetime.now().year,
|
| 37 |
+
"github_url": APP_GITHUB_URL,
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
# Available endpoints (will be dynamically generated later)
|
| 41 |
+
endpoints = [
|
| 42 |
+
{
|
| 43 |
+
"method": "GET",
|
| 44 |
+
"path": "/health",
|
| 45 |
+
"description": "Health check endpoint to verify API availability and system status.",
|
| 46 |
+
"status": "Operational"
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"method": "GET",
|
| 50 |
+
"path": "/api/docs",
|
| 51 |
+
"description": "Interactive API documentation powered by Swagger UI.",
|
| 52 |
+
"status": "Operational"
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"method": "GET",
|
| 56 |
+
"path": "/api/redoc",
|
| 57 |
+
"description": "Alternative API documentation with ReDoc interface.",
|
| 58 |
+
"status": "Operational"
|
| 59 |
+
},
|
| 60 |
+
]
|
| 61 |
+
|
| 62 |
+
return templates.TemplateResponse(
|
| 63 |
+
"index.html",
|
| 64 |
+
{
|
| 65 |
+
"request": request,
|
| 66 |
+
**app_data,
|
| 67 |
+
"endpoints": endpoints,
|
| 68 |
+
}
|
| 69 |
+
)
|
src/app/api/v1/payroll.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
PAYROLL Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement payroll endpoints
|
src/app/api/v1/projects.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
PROJECTS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement projects endpoints
|
src/app/api/v1/reports.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
REPORTS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement reports endpoints
|
src/app/api/v1/router.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Main API Router - Aggregates all v1 endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
# Import all routers
|
| 7 |
+
# from app.api.v1 import auth, users, organizations, projects, tickets
|
| 8 |
+
|
| 9 |
+
api_router = APIRouter()
|
| 10 |
+
|
| 11 |
+
# Include all routers
|
| 12 |
+
# api_router.include_router(auth.router, prefix="/auth", tags=["Authentication"])
|
| 13 |
+
# api_router.include_router(users.router, prefix="/users", tags=["Users"])
|
| 14 |
+
# api_router.include_router(organizations.router, prefix="/organizations", tags=["Organizations"])
|
| 15 |
+
# api_router.include_router(projects.router, prefix="/projects", tags=["Projects"])
|
| 16 |
+
# api_router.include_router(tickets.router, prefix="/tickets", tags=["Tickets"])
|
| 17 |
+
|
| 18 |
+
# TODO: Include remaining routers as they are implemented
|
src/app/api/v1/sales_orders.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
SALES ORDERS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement sales_orders endpoints
|
src/app/api/v1/subscriptions.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
SUBSCRIPTIONS Endpoints
|
| 3 |
+
"""
|
| 4 |
+
from fastapi import APIRouter
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
# TODO: Implement subscriptions endpoints
|