# GigLez Deployment Considerations: Development vs Production

**Created**: 2026-01-12
**Purpose**: Identify critical differences between local development and production deployment

---

## Executive Summary

GigLez needs to support two distinct deployment scenarios:

1. **Local Development** (Termux on Android)
   - Resource-constrained (mobile device)
   - Single-user access
   - Direct USB serial communication
   - Local file storage
   - Development/testing workflow

2. **Production Server** (Cloud/VPS)
   - Multi-user platform
   - Public API access
   - No hardware connection
   - Object storage for files
   - High availability requirements

**Key Insight**: We need a **modular architecture** that supports both scenarios without code duplication.

---

## Architecture Strategy

### Hybrid Architecture: "Capture" vs "Platform" Mode

```
┌─────────────────────────────────────────────────────────┐
│                    GigLez Application                    │
├─────────────────────────────────────────────────────────┤
│                                                           │
│  ┌────────────────┐         ┌────────────────┐          │
│  │  Capture Mode  │         │ Platform Mode  │          │
│  │   (Termux)     │         │   (Server)     │          │
│  ├────────────────┤         ├────────────────┤          │
│  │ - T-Embed USB  │         │ - No hardware  │          │
│  │ - Local GPS    │         │ - File uploads │          │
│  │ - Auto-capture │         │ - Multi-user   │          │
│  │ - Local API    │         │ - Public API   │          │
│  └────────────────┘         └────────────────┘          │
│           │                          │                    │
│           └──────────┬───────────────┘                    │
│                      │                                    │
│              ┌───────▼────────┐                           │
│              │  Shared Core   │                           │
│              ├────────────────┤                           │
│              │ - Database     │                           │
│              │ - Parser       │                           │
│              │ - Matcher      │                           │
│              │ - GPS Validator│                           │
│              │ - API Endpoints│                           │
│              └────────────────┘                           │
└─────────────────────────────────────────────────────────┘
```

---

## Detailed Comparison

### 1. Hardware Access

#### Development (Termux)
- **T-Embed Connection**: USB serial communication (pyserial)
- **GPS Source**: Android native GPS via SL4A or Termux:API
- **Real-time Capture**: Direct signal scanning and capture
- **Storage**: Local filesystem on Android device

**Implications**:
- Need hardware abstraction layer
- Support offline operation
- Handle USB disconnections
- Batch upload when network available

#### Production (Server)
- **No Hardware**: Accept pre-captured .sub files only
- **GPS Source**: Embedded in upload manifest
- **No Real-time**: Historical data only
- **Storage**: Object storage (S3, MinIO, or filesystem)

**Implications**:
- No serial communication code needed
- Network-dependent operation
- Focus on file processing pipeline
- Horizontal scaling possible

**Solution**:
```python
# Abstract hardware interface
class CaptureSource(ABC):
    @abstractmethod
    def scan_signals(self): pass

    @abstractmethod
    def get_gps(self): pass

class TEmbedSource(CaptureSource):
    """Development: Direct hardware"""
    pass

class UploadSource(CaptureSource):
    """Production: File uploads"""
    pass
```

---

### 2. Database Configuration

#### Development (Termux)
- **PostgreSQL**: Local installation via `pkg install postgresql`
- **Host**: localhost or 127.0.0.1
- **Port**: 5432
- **Connections**: Small pool (5 + 5 overflow)
- **Storage**: Device internal storage or SD card

**Considerations**:
- Limited RAM on mobile devices
- Smaller connection pool
- May need to tune PostgreSQL for mobile
- Backup to SD card or cloud

#### Production (Server)
- **PostgreSQL**: Dedicated server or managed database (RDS, Cloud SQL)
- **Host**: Remote database server
- **Port**: 5432 (or custom)
- **Connections**: Larger pool (20 + 40 overflow)
- **Storage**: SSD/NVMe for performance

**Considerations**:
- Connection pooling via PgBouncer
- Read replicas for scaling
- Automated backups
- Point-in-time recovery

**Solution**: Environment-based configuration
```bash
# Development (.env)
GIGLEZ_DB_HOST=localhost
GIGLEZ_DB_POOL_SIZE=5
GIGLEZ_DB_MAX_OVERFLOW=5

# Production (.env.production)
GIGLEZ_DB_HOST=db.giglez.com
GIGLEZ_DB_POOL_SIZE=20
GIGLEZ_DB_MAX_OVERFLOW=40
```

---

### 3. File Storage

#### Development (Termux)
- **Location**: `/data/data/com.termux/files/home/giglez/storage/`
- **Structure**: Organized by session/date
- **Size**: Limited by device storage (typically < 64GB)
- **Access**: Direct filesystem access

**Structure**:
```
storage/
├── captures/
│   ├── 2026-01-12/
│   │   ├── session_abc123/
│   │   │   ├── capture_001.sub
│   │   │   ├── capture_002.sub
│   │   │   └── manifest.json
```

#### Production (Server)
- **Location**: Object storage (S3, MinIO, GCS) or networked filesystem
- **Structure**: Content-addressed by file hash
- **Size**: Unlimited (cloud storage)
- **Access**: Via storage API or CDN

**Structure**:
```
s3://giglez-captures/
├── ab/
│   ├── c1/
│   │   └── abc123...def456.sub  # First 2+2 chars of hash for sharding
```

**Solution**: Storage abstraction
```python
class StorageBackend(ABC):
    @abstractmethod
    def save_file(self, file_hash: str, content: bytes): pass

    @abstractmethod
    def get_file(self, file_hash: str) -> bytes: pass

class LocalStorage(StorageBackend):
    """Development: Filesystem"""
    pass

class S3Storage(StorageBackend):
    """Production: S3-compatible storage"""
    pass
```

---

### 4. API Access & Security

#### Development (Termux)
- **Access**: Local only (127.0.0.1) or local network
- **Port**: 8000 (or any available)
- **HTTPS**: Not required (localhost)
- **Authentication**: Optional (single user)
- **CORS**: Permissive (development)
- **Rate Limiting**: None needed

**Use Cases**:
- Testing API endpoints
- Web UI development
- Local data management
- Debugging

#### Production (Server)
- **Access**: Public internet
- **Port**: 443 (HTTPS) behind reverse proxy
- **HTTPS**: Required (Let's Encrypt)
- **Authentication**: JWT + API keys mandatory
- **CORS**: Strict origin whitelisting
- **Rate Limiting**: Aggressive (per-user, per-IP)

**Security Requirements**:
- Nginx/Caddy reverse proxy
- SSL/TLS certificates
- API key rotation
- Request validation
- SQL injection prevention
- File upload limits
- DDoS protection

**Solution**: Environment-based security
```python
# config/security.py
if os.getenv("GIGLEZ_MODE") == "production":
    REQUIRE_AUTH = True
    RATE_LIMIT = "10/minute"
    ALLOWED_ORIGINS = ["https://giglez.com"]
else:
    REQUIRE_AUTH = False
    RATE_LIMIT = None
    ALLOWED_ORIGINS = ["*"]
```

---

### 5. Performance & Scaling

#### Development (Termux)
- **Workers**: 1 Uvicorn worker
- **Concurrency**: Minimal (single user)
- **Caching**: In-memory only (LRU)
- **Background Tasks**: Simple queue or synchronous
- **Resource Limits**: RAM < 2GB, CPU 2-4 cores

**Optimization Focus**:
- Memory efficiency
- Minimal background processes
- Battery life considerations
- Offline operation

#### Production (Server)
- **Workers**: Multiple Uvicorn workers (4-8)
- **Concurrency**: High (100+ concurrent users)
- **Caching**: Redis + LRU
- **Background Tasks**: Celery + RabbitMQ/Redis
- **Resource Limits**: RAM 8-32GB, CPU 4-16 cores

**Optimization Focus**:
- Query performance
- Connection pooling
- Horizontal scaling
- CDN for static assets
- Load balancing

**Solution**: Conditional imports
```python
# src/api/main.py
if PRODUCTION_MODE:
    from celery import Celery
    celery_app = Celery('giglez', broker='redis://localhost')
else:
    # Use FastAPI BackgroundTasks for development
    celery_app = None
```

---

### 6. Logging & Monitoring

#### Development (Termux)
- **Logging**: Console output (stdout)
- **Level**: DEBUG
- **Format**: Colorized, verbose
- **Storage**: Optional file logging
- **Monitoring**: Manual observation

**Example**:
```python
logger.add(sys.stdout, level="DEBUG", colorize=True)
```

#### Production (Server)
- **Logging**: Structured JSON to file + syslog
- **Level**: INFO/WARNING
- **Format**: JSON for parsing
- **Storage**: Log rotation + cloud storage
- **Monitoring**: Prometheus + Grafana, error tracking (Sentry)

**Example**:
```python
logger.add(
    "/var/log/giglez/app.log",
    level="INFO",
    format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
    rotation="100 MB",
    compression="gz"
)
```

**Solution**: Environment-based logging
```python
# config/logging.py
if PRODUCTION_MODE:
    setup_production_logging()
else:
    setup_development_logging()
```

---

### 7. Backup & Disaster Recovery

#### Development (Termux)
- **Database**: Manual pg_dump to SD card
- **Files**: Synced to cloud storage (Google Drive, Dropbox)
- **Frequency**: On-demand
- **Recovery**: Restore from local backups

#### Production (Server)
- **Database**: Automated daily backups with PITR
- **Files**: Object storage replication (S3 versioning)
- **Frequency**: Hourly incremental, daily full
- **Recovery**: Automated restore procedures

**Backup Strategy**:
```bash
# Development
pg_dump giglez > /sdcard/giglez_backup_$(date +%Y%m%d).sql

# Production
pg_dump giglez | gzip | aws s3 cp - s3://giglez-backups/$(date +%Y%m%d).sql.gz
```

---

### 8. Network Considerations

#### Development (Termux)
- **Connectivity**: WiFi or cellular (intermittent)
- **Bandwidth**: Potentially limited (mobile data)
- **Latency**: Variable (mobile networks)
- **Offline Support**: Critical (wardriving in field)

**Implications**:
- Queue uploads for when network available
- Support offline capture and analysis
- Minimize API calls
- Compress uploads

#### Production (Server)
- **Connectivity**: Always online (datacenter)
- **Bandwidth**: High (1Gbps+)
- **Latency**: Low (< 50ms typical)
- **Offline Support**: Not applicable

**Implications**:
- Assume network availability
- No offline mode needed
- Can make external API calls freely
- Stream large responses

**Solution**: Offline queue
```python
# src/capture/uploader.py
class UploadQueue:
    def queue_capture(self, capture_data):
        if network_available():
            upload_immediately(capture_data)
        else:
            save_to_local_queue(capture_data)

    def process_queue(self):
        """Called when network becomes available"""
        for item in get_queued_items():
            try:
                upload_immediately(item)
                mark_as_uploaded(item)
            except NetworkError:
                break  # Stop and try again later
```

---

## Configuration Strategy

### Environment Variables Approach

Use different `.env` files for each environment:

```bash
# .env.development (Termux)
GIGLEZ_MODE=development
GIGLEZ_DB_HOST=localhost
GIGLEZ_DB_POOL_SIZE=5
GIGLEZ_API_HOST=127.0.0.1
GIGLEZ_API_PORT=8000
GIGLEZ_STORAGE_TYPE=filesystem
GIGLEZ_STORAGE_PATH=/data/data/com.termux/files/home/giglez/storage
GIGLEZ_REQUIRE_AUTH=false
GIGLEZ_LOG_LEVEL=DEBUG
GIGLEZ_ENABLE_HARDWARE=true
GIGLEZ_TEMBED_PORT=/dev/ttyUSB0

# .env.production (Server)
GIGLEZ_MODE=production
GIGLEZ_DB_HOST=db.giglez.com
GIGLEZ_DB_POOL_SIZE=20
GIGLEZ_API_HOST=0.0.0.0
GIGLEZ_API_PORT=8000
GIGLEZ_STORAGE_TYPE=s3
GIGLEZ_STORAGE_BUCKET=giglez-captures
GIGLEZ_REQUIRE_AUTH=true
GIGLEZ_LOG_LEVEL=INFO
GIGLEZ_ENABLE_HARDWARE=false
```

### Configuration Loading

```python
# config/settings.py
import os
from enum import Enum

class DeploymentMode(Enum):
    DEVELOPMENT = "development"
    PRODUCTION = "production"

class Settings:
    def __init__(self):
        self.mode = DeploymentMode(os.getenv("GIGLEZ_MODE", "development"))

    @property
    def is_production(self) -> bool:
        return self.mode == DeploymentMode.PRODUCTION

    @property
    def is_development(self) -> bool:
        return self.mode == DeploymentMode.DEVELOPMENT

    @property
    def enable_hardware(self) -> bool:
        """Only enable hardware access in development"""
        return os.getenv("GIGLEZ_ENABLE_HARDWARE", "false").lower() == "true"

    @property
    def storage_backend(self) -> str:
        return os.getenv("GIGLEZ_STORAGE_TYPE", "filesystem")

settings = Settings()
```

---

## Recommended Architecture

### Modular Component Design

```
giglez/
├── src/
│   ├── core/                    # Shared core (both modes)
│   │   ├── database/            # Database models & queries
│   │   ├── parser/              # .sub file parser
│   │   ├── matcher/             # Signature matching
│   │   ├── gps/                 # GPS validation
│   │   └── storage/             # Storage abstraction
│   │
│   ├── capture/                 # Capture mode only (Termux)
│   │   ├── tembed.py            # T-Embed communication
│   │   ├── scanner.py           # Signal scanning
│   │   ├── gps_manager.py       # Android GPS integration
│   │   └── uploader.py          # Offline queue & upload
│   │
│   ├── api/                     # API endpoints (both modes)
│   │   ├── main.py              # FastAPI app
│   │   ├── routes/
│   │   │   ├── captures.py      # Upload endpoints
│   │   │   ├── devices.py       # Device catalog
│   │   │   ├── query.py         # Search endpoints
│   │   │   └── stats.py         # Statistics
│   │   ├── auth.py              # Authentication
│   │   ├── middleware.py        # Rate limiting, CORS
│   │   └── dependencies.py      # Dependency injection
│   │
│   └── web/                     # Web interface (both modes)
│       ├── static/              # CSS, JS, images
│       └── templates/           # HTML templates
│
└── config/
    ├── settings.py              # Environment-based config
    ├── database.py              # Database connection
    ├── storage.py               # Storage backend selection
    └── logging.py               # Logging configuration
```

---

## Implementation Recommendations

### 1. Use Feature Flags

```python
# src/api/main.py
from config.settings import settings

app = FastAPI()

# Conditional hardware endpoints
if settings.enable_hardware:
    @app.post("/api/capture/start")
    async def start_capture():
        # Only available in Termux mode
        pass

# Always available endpoints
@app.post("/api/captures/upload")
async def upload_captures():
    # Available in both modes
    pass
```

### 2. Storage Abstraction

```python
# config/storage.py
from src.core.storage import LocalStorage, S3Storage

def get_storage_backend():
    if settings.storage_backend == "s3":
        return S3Storage(
            bucket=os.getenv("GIGLEZ_STORAGE_BUCKET"),
            access_key=os.getenv("AWS_ACCESS_KEY_ID"),
            secret_key=os.getenv("AWS_SECRET_ACCESS_KEY")
        )
    else:
        return LocalStorage(
            base_path=os.getenv("GIGLEZ_STORAGE_PATH")
        )

storage = get_storage_backend()
```

### 3. Optional Dependencies

```python
# requirements.txt (core)
fastapi==0.109.0
sqlalchemy==2.0.25
psycopg2-binary==2.9.9
...

# requirements-dev.txt (Termux additions)
-r requirements.txt
pyserial==3.5
aioserial==1.3.2

# requirements-prod.txt (Server additions)
-r requirements.txt
boto3==1.34.0  # S3 storage
redis==5.0.1   # Caching
celery==5.3.4  # Background tasks
gunicorn==21.2.0  # WSGI server
```

### 4. Graceful Degradation

```python
# src/api/routes/captures.py
@app.post("/api/captures/upload")
async def upload_captures(files: List[UploadFile]):
    # Core functionality works in both modes
    captures = []

    for file in files:
        # Parse .sub file (works everywhere)
        metadata = parse_sub_file(file)

        # Store file (abstracted)
        storage.save_file(metadata.file_hash, file.content)

        # Save to database (works everywhere)
        capture = Capture(**metadata)
        db.add(capture)

        captures.append(capture)

    db.commit()

    # Background matching (production) or synchronous (development)
    if settings.is_production:
        celery_app.send_task('match_signatures', args=[capture.file_hash])
    else:
        match_signatures_sync(capture.file_hash)

    return {"uploaded": len(captures)}
```

---

## Testing Strategy

### Development Testing (Termux)
- Direct hardware testing
- USB serial communication
- GPS acquisition
- Offline queue processing
- Local file storage

### Production Testing (Server)
- API endpoint testing
- File upload validation
- Multi-user concurrency
- Rate limiting
- Authentication
- S3 storage integration

### Shared Testing
- Database operations
- .sub file parsing
- Signature matching
- GPS validation
- Query performance

**Test Structure**:
```
tests/
├── unit/                    # Unit tests (both modes)
│   ├── test_parser.py
│   ├── test_matcher.py
│   └── test_gps.py
│
├── integration/             # Integration tests
│   ├── test_api.py          # Both modes
│   ├── test_hardware.py     # Development only
│   └── test_storage.py      # Both modes
│
└── e2e/                     # End-to-end tests
    ├── test_capture.py      # Development only
    └── test_upload.py       # Both modes
```

---

## Deployment Checklist

### Development (Termux) Setup
- [ ] Install Termux from F-Droid
- [ ] Install PostgreSQL: `pkg install postgresql`
- [ ] Install Python: `pkg install python`
- [ ] Install dependencies: `pip install -r requirements-dev.txt`
- [ ] Configure USB permissions for T-Embed
- [ ] Set up Termux:API for GPS
- [ ] Create `.env.development`
- [ ] Run database setup: `./scripts/setup_database.sh`
- [ ] Test hardware connection
- [ ] Start API: `python src/api/main.py`

### Production (Server) Setup
- [ ] Provision VPS (2GB+ RAM, 2+ cores)
- [ ] Install PostgreSQL 16 + PostGIS
- [ ] Install Python 3.10+
- [ ] Install Redis (for caching)
- [ ] Install Nginx (reverse proxy)
- [ ] Configure SSL with Let's Encrypt
- [ ] Set up S3/MinIO for file storage
- [ ] Configure firewall (allow 80, 443)
- [ ] Create `.env.production`
- [ ] Run database setup
- [ ] Set up systemd service
- [ ] Configure automated backups
- [ ] Set up monitoring (optional)

---

## Performance Considerations

### Development (Termux) Optimizations
- Smaller connection pool (5 + 5)
- In-memory caching only
- Synchronous processing (no Celery)
- Minimal logging
- Local file storage

### Production (Server) Optimizations
- Larger connection pool (20 + 40)
- Redis caching
- Async background tasks (Celery)
- Structured logging with rotation
- CDN for file delivery
- Read replicas for scaling
- Materialized view refresh (cron)

---

## Cost Considerations

### Development (Termux)
- **Hardware**: LilyGo T-Embed (~$30-50)
- **Android Device**: Existing phone/tablet
- **Infrastructure**: $0 (local)
- **Storage**: Device storage only
- **Total**: ~$30-50 one-time

### Production (Server)
- **VPS**: $10-50/month (2-8GB RAM)
- **Database**: Included or $10-30/month (managed)
- **Storage**: $0.02/GB/month (S3) or included (filesystem)
- **Bandwidth**: Typically included (1-5TB)
- **Domain**: $10-15/year
- **SSL**: $0 (Let's Encrypt)
- **Total**: $10-80/month

---

## Recommended Phase 2 Approach

### Build for Both from the Start

**Strategy**: Implement the API with abstraction layers that work in both environments.

**Implementation Order**:
1. ✅ Core API structure (FastAPI app)
2. ✅ Storage abstraction (filesystem + S3)
3. ✅ Upload endpoint (works in both modes)
4. ✅ Authentication (optional in dev, required in prod)
5. ✅ Background tasks (sync in dev, Celery in prod)
6. ✅ Environment-based configuration

**Key Principle**:
> Write code that works in both environments by default, with conditional imports/features for mode-specific functionality.

---

## Summary: Key Differences

| Aspect | Development (Termux) | Production (Server) |
|--------|---------------------|---------------------|
| **Hardware** | T-Embed USB + GPS | None (file uploads) |
| **Users** | Single user | Multi-user |
| **Database** | Local PostgreSQL (small pool) | Remote PostgreSQL (large pool) |
| **Storage** | Local filesystem | S3/object storage |
| **API Access** | localhost only | Public internet |
| **Security** | Optional auth | Required auth + HTTPS |
| **Background Tasks** | Synchronous | Celery async |
| **Caching** | In-memory LRU | Redis + LRU |
| **Logging** | Console (DEBUG) | File + JSON (INFO) |
| **Monitoring** | Manual | Automated (Prometheus) |
| **Scaling** | N/A | Horizontal |
| **Cost** | $0/month | $10-80/month |

---

## Next Steps

Before implementing Phase 2, we need to:

1. ✅ **Create environment configuration** (`.env.development`, `.env.production`)
2. ✅ **Implement storage abstraction** (`src/core/storage/`)
3. ✅ **Create settings module** (`config/settings.py`)
4. ✅ **Document deployment procedures** (development guide, production guide)
5. ✅ **Begin FastAPI implementation** with environment awareness

**Recommendation**: Start with a **shared API implementation** that works in both modes, then add mode-specific features as needed.

---

**Document Version**: 1.0
**Status**: Ready for Phase 2 Implementation
**Next Action**: Create environment-aware FastAPI application structure
