Skip to main content

CODITECT Cloud Infrastructure - Implementation Roadmap

Executive Summary

Current Status: Infrastructure 100% Deployed ✅ (November 23, 2025)

Deployed Resources:

  • ✅ GKE Cluster (3 nodes, autoscaling 1-10)
  • ✅ Cloud SQL PostgreSQL 16 (db-custom-2-7680, Regional HA)
  • ✅ Redis Memorystore (6GB BASIC tier)
  • ✅ VPC Networking (private cluster, Cloud NAT)
  • ✅ Secret Manager (9 secrets configured)
  • ✅ Firewall Rules (secure defaults)

Next Steps: Backend application development ETA to Working License System: 1-2 weeks Monthly Cost: ~$310 (dev environment)


Phase 1: Infrastructure ✅ COMPLETE

Duration: November 20-23, 2025 (3 days) Status: ✅ 100% Complete Cost: $310/month

Completed Tasks

1.1 OpenTofu Modules ✅

  • VPC networking module
  • GKE cluster module (fixed API conflicts)
  • Cloud SQL PostgreSQL module (removed PostgreSQL flags)
  • Redis Memorystore module (conditional HA)
  • Firewall rules module
  • Secret Manager module

1.2 GCP Resource Deployment ✅

  • VPC network: coditect-vpc-dev
  • GKE cluster: coditect-PostgreSQL-dev (renamed to coditect-cluster-dev needed)
  • Cloud SQL instance: coditect-PostgreSQL-dev (connection: 10.67.0.3)
  • Redis instance: coditect-redis-dev (host: 10.121.42.67:6378)
  • 9 secrets in Secret Manager

1.3 Repository Cleanup ✅

  • Renamed coditect-PostgreSQL-django-infracoditect-cloud-infra
  • Updated all documentation references
  • Fixed git submodule configuration
  • Committed and pushed changes

Infrastructure Outputs

# GKE Cluster
gcloud container clusters get-credentials coditect-PostgreSQL-dev \
--region us-central1 --project coditect-PostgreSQL-prod

# Cloud SQL
cloud_sql_proxy -instances=coditect-PostgreSQL-prod:us-central1:coditect-PostgreSQL-dev=tcp:5432

# Redis
# Internal IP: 10.121.42.67:6378 (accessible from GKE pods)

Phase 2: Cloud KMS + Identity Platform (IN PROGRESS)

Duration: 2-3 days Status: ⏸️ Not Started Blockers: None

2.1 Cloud KMS Module

Create OpenTofu module for license signing:

mkdir -p opentofu/modules/kms
touch opentofu/modules/kms/{main.tf,variables.tf,outputs.tf}

Files to create:

opentofu/modules/kms/main.tf

resource "google_kms_key_ring" "license_keyring" {
name = "${var.project_id}-license-keys-${var.environment}"
location = "global"
}

resource "google_kms_crypto_key" "license_signing_key" {
name = "license-signing-key"
key_ring = google_kms_key_ring.license_keyring.id
rotation_period = "7776000s" # 90 days

purpose = "ASYMMETRIC_SIGN"

version_template {
algorithm = "RSA_SIGN_PKCS1_4096_SHA256"
}

lifecycle {
prevent_destroy = true
}
}

output "key_name" {
value = google_kms_crypto_key.license_signing_key.id
}

Estimated Time: 2 hours

2.2 Identity Platform Setup

Create OpenTofu module:

mkdir -p opentofu/modules/identity-platform
touch opentofu/modules/identity-platform/{main.tf,variables.tf,outputs.tf}

opentofu/modules/identity-platform/main.tf

resource "google_identity_platform_config" "default" {
project = var.project_id

sign_in {
email {
enabled = true
password_required = true
}

phone_number {
enabled = false
}
}

autodelete_anonymous_users = true
}

resource "google_identity_platform_oauth_idp_config" "google" {
name = "google.com"
display_name = "Google"
enabled = true
client_id = var.google_oauth_client_id
client_secret = var.google_oauth_client_secret
issuer = "https://accounts.google.com"
}

Estimated Time: 4 hours (including OAuth app setup)

2.3 Integration with Existing Infrastructure

Update opentofu/environments/dev/main.tf:

module "kms" {
source = "../../modules/kms"

project_id = var.project_id
environment = var.environment
}

module "identity_platform" {
source = "../../modules/identity-platform"

project_id = var.project_id
google_oauth_client_id = var.google_oauth_client_id
google_oauth_client_secret = data.google_secret_manager_secret_version.google_oauth_secret.secret_data
}

Deploy:

cd opentofu/environments/dev
tofu plan
tofu apply

Estimated Time: 1 hour


Phase 3: FastAPI Backend Development

Duration: 5-7 days Status: ⏸️ Not Started Dependencies: Phase 2 complete

3.1 Project Setup

Create FastAPI project structure:

cd /path/to/coditect-cloud-backend  # Separate repo
mkdir -p src/{api,models,services,utils}
touch src/{__init__.py,main.py,config.py}

Dependencies (requirements.txt):

fastapi==0.104.1
uvicorn[standard]==0.24.0
sqlalchemy[asyncio]==2.0.23
asyncpg==0.29.0
redis==5.0.1
google-cloud-kms==2.19.2
google-cloud-secret-manager==2.16.4
firebase-admin==6.2.0
pydantic==2.5.0
python-jose[cryptography]==3.3.0
aiohttp==3.9.1

Estimated Time: 2 hours

3.2 Database Models

File: src/models/database.py

from sqlalchemy import Column, String, Integer, DateTime, Boolean, ForeignKey, JSON
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import declarative_base, relationship
import uuid
from datetime import datetime

Base = declarative_base()

class Tenant(Base):
__tablename__ = "tenants"

id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String(255), nullable=False)
plan = Column(String(50), default="FREE")
max_seats = Column(Integer, default=1)
created_at = Column(DateTime, default=datetime.utcnow)

licenses = relationship("License", back_populates="tenant")
users = relationship("User", back_populates="tenant")

class License(Base):
__tablename__ = "licenses"

id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"))
key_string = Column(String(255), unique=True, nullable=False)
tier = Column(String(50), nullable=False)
expiry_date = Column(DateTime, nullable=False)
features = Column(JSON, default=list)
created_at = Column(DateTime, default=datetime.utcnow)

tenant = relationship("Tenant", back_populates="licenses")

class User(Base):
__tablename__ = "users"

id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"))
email = Column(String(255), unique=True, nullable=False)
firebase_uid = Column(String(255), unique=True)
role = Column(String(50), default="MEMBER")
created_at = Column(DateTime, default=datetime.utcnow)

tenant = relationship("Tenant", back_populates="users")

Estimated Time: 3 hours

3.3 Core License Endpoints

File: src/api/licenses.py

from fastapi import APIRouter, Depends, HTTPException, Header
from sqlalchemy.ext.asyncio import AsyncSession
from redis import Redis
from google.cloud import kms
import hashlib
import base64
import json

router = APIRouter(prefix="/api/v1/licenses", tags=["licenses"])

# Redis Lua script for atomic seat acquisition
ACQUIRE_SEAT_SCRIPT = """
local tenant_id = KEYS[1]
local session_id = ARGV[1]
local max_seats = tonumber(ARGV[2])

local current_count = tonumber(redis.call('GET', 'tenant:' .. tenant_id .. ':seat_count') or '0')

if current_count < max_seats then
redis.call('INCR', 'tenant:' .. tenant_id .. ':seat_count')
redis.call('SADD', 'tenant:' .. tenant_id .. ':active_sessions', session_id)
redis.call('SETEX', 'session:' .. session_id, 360, '1')
return 1
else
return 0
end
"""

@router.post("/acquire")
async def acquire_license(
req: LicenseAcquireRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
redis: Redis = Depends(get_redis),
kms_client: kms.KeyManagementServiceClient = Depends(get_kms)
):
# Implementation per license-acquisition-workflow.md
pass

@router.put("/heartbeat")
async def heartbeat(
req: HeartbeatRequest,
redis: Redis = Depends(get_redis)
):
result = await redis.expire(f"session:{req.session_id}", 360)
if result == 0:
raise HTTPException(404, "Session not found")
return {"status": "alive", "expires_in": 360}

@router.delete("/release")
async def release_license(
req: LicenseReleaseRequest,
current_user: User = Depends(get_current_user),
redis: Redis = Depends(get_redis)
):
# Implementation per license-acquisition-workflow.md
pass

Estimated Time: 2 days (8 hours)

3.4 Authentication Middleware

File: src/utils/auth.py

from fastapi import Depends, HTTPException, Header
from firebase_admin import auth
import firebase_admin

# Initialize Firebase Admin SDK
cred = firebase_admin.credentials.ApplicationDefault()
firebase_admin.initialize_app(cred)

async def get_current_user(
authorization: str = Header(...)
) -> User:
token = authorization.replace("Bearer ", "")

try:
decoded = auth.verify_id_token(token)
user_id = decoded["uid"]
tenant_id = decoded.get("tenant_id")

# Load from database
async with get_db() as db:
user = await db.query(User).filter(firebase_uid=user_id).first()

if not user:
raise HTTPException(401, "User not found")

return user

except Exception as e:
raise HTTPException(401, f"Invalid token: {e}")

Estimated Time: 4 hours

3.5 Testing

Unit Tests:

pytest tests/test_licenses.py -v
pytest tests/test_auth.py -v

Integration Tests:

pytest tests/integration/test_license_flow.py -v

Estimated Time: 1 day (6 hours)


Phase 4: Kubernetes Deployment

Duration: 2-3 days Status: ⏸️ Not Started Dependencies: Phase 3 complete

4.1 Dockerize FastAPI Application

File: Dockerfile

FROM python:3.11-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY src/ ./src/

# Run as non-root
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser

# Expose port
EXPOSE 8000

# Run with Uvicorn
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

Build and push:

docker build -t gcr.io/coditect-PostgreSQL-prod/license-api:latest .
docker push gcr.io/coditect-PostgreSQL-prod/license-api:latest

Estimated Time: 3 hours

4.2 Kubernetes Manifests

File: kubernetes/deployments/license-api.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: license-api
namespace: coditect-prod
spec:
replicas: 3
selector:
matchLabels:
app: license-api
template:
metadata:
labels:
app: license-api
spec:
serviceAccountName: license-api-sa
containers:
- name: license-api
image: gcr.io/coditect-PostgreSQL-prod/license-api:latest
ports:
- containerPort: 8000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: database-credentials
key: connection_string
- name: REDIS_HOST
value: "10.121.42.67"
- name: REDIS_PORT
value: "6378"
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
---
apiVersion: v1
kind: Service
metadata:
name: license-api
namespace: coditect-prod
spec:
selector:
app: license-api
ports:
- protocol: TCP
port: 8000
targetPort: 8000
type: ClusterIP

Deploy:

kubectl apply -f kubernetes/deployments/license-api.yaml
kubectl apply -f kubernetes/ingress.yaml

Estimated Time: 4 hours

4.3 CI/CD Pipeline

File: .github/workflows/deploy.yml

name: Deploy to GKE

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}

- name: Configure Docker for GCR
run: gcloud auth configure-docker

- name: Build and Push
run: |
docker build -t gcr.io/coditect-PostgreSQL-prod/license-api:${{ github.sha }} .
docker push gcr.io/coditect-PostgreSQL-prod/license-api:${{ github.sha }}

- name: Deploy to GKE
run: |
gcloud container clusters get-credentials coditect-PostgreSQL-dev \
--region us-central1 --project coditect-PostgreSQL-prod

kubectl set image deployment/license-api \
license-api=gcr.io/coditect-PostgreSQL-prod/license-api:${{ github.sha }}

kubectl rollout status deployment/license-api

Estimated Time: 2 hours


Phase 5: Frontend Admin Dashboard (OPTIONAL)

Duration: 1-2 weeks Status: ⏸️ Not Started Priority: P2 (can use API directly initially)

5.1 React Application Setup

Technology: React 18 + TypeScript + TailwindCSS

Features:

  • License management (CRUD)
  • Active session monitoring
  • User management
  • Billing integration (Stripe)
  • Analytics dashboard

Estimated Time: 1-2 weeks


Progress Tracking

Overall Completion

PhaseStatusCompletionTime SpentTime Remaining
Phase 1: Infrastructure✅ Complete100%3 days0 days
Phase 2: KMS + Identity⏸️ Not Started0%0 days2-3 days
Phase 3: FastAPI Backend⏸️ Not Started0%0 days5-7 days
Phase 4: K8s Deployment⏸️ Not Started0%0 days2-3 days
Phase 5: Admin UI⏸️ Optional0%0 days1-2 weeks

Critical Path to Working License System

Minimum Viable Product (MVP):

  1. ✅ Infrastructure (Complete)
  2. ⏸️ Cloud KMS + Identity Platform (2-3 days)
  3. ⏸️ FastAPI License Endpoints (5-7 days)
  4. ⏸️ Deploy to GKE (2-3 days)

Total Time to MVP: 9-13 days (1.5-2 weeks)

Near-Term Action Items (Next 48 Hours)

  1. Create Cloud KMS module (2 hours)
  2. Create Identity Platform module (4 hours)
  3. Deploy Phase 2 infrastructure (1 hour)
  4. Setup FastAPI project structure (2 hours)
  5. Implement database models (3 hours)

Total: 12 hours (1.5 work days)


Cost Analysis

Current Monthly Costs (Dev Environment)

ServiceConfigurationMonthly Cost
GKE3x n1-standard-2, preemptible$100
Cloud SQLdb-custom-2-7680, HA$150
Redis6GB BASIC$30
Cloud KMS10K ops/month$10
NetworkingNAT, Egress$20
Total$310/month

Production Scaling Estimates

UsersMonthly CostNotes
1,000$500Add load balancer
10,000$1,500Scale GKE to 10 nodes, Redis STANDARD_HA
100,000$5,000Multi-region, read replicas

Risk Assessment

Technical Risks

RiskImpactProbabilityMitigation
Identity Platform learning curveMediumHighAllocate extra time for OAuth setup
Redis keyspace notification complexityLowMediumUse well-tested pattern from docs
GKE autoscaling issuesMediumLowThorough load testing

Timeline Risks

RiskImpactMitigation
Underestimated FastAPI development+3-5 daysBuild MVP first, iterate
Identity Platform OAuth approval delays+1-2 daysStart OAuth app review early

Last Updated: November 23, 2025 Next Review: November 25, 2025 Target MVP Date: December 7, 2025