Phase 1 Steps 7-9: Complete Commercial Revenue Flow - Orchestration Plan
Project: CODITECT Cloud Backend License Management Date: December 1, 2025 Status: Phase 1 Steps 1-6 Complete (66.7%) → Completing Steps 7-9 (Final 33.3%) Timeline: 3-4 days to completion (Target: December 5, 2025) Objective: Enable complete user → payment → license → usage → renewal cycle
Executive Summary
Current Status:
- ✅ Phase 1 Steps 1-6: 100% Complete (user registration, Stripe, licenses, email, seat management)
- ⏳ Phase 1 Steps 7-9: 0% Complete (client SDK, renewal automation, admin APIs)
- 📊 Code: ~5,300 lines implemented, 196 tests, 72% coverage
- 🎯 Milestone: First paying customer by December 22, 2025 (21 days remaining)
Steps to Complete:
| Step | Component | Complexity | Est. LOC | Est. Time | Dependencies |
|---|---|---|---|---|---|
| 7 | Client-Side Python SDK + Heartbeat | Medium | ~800 | 8-10h | Step 6 (API) ✅ |
| 8 | Monthly Renewal Automation | Medium | ~600 | 6-8h | Steps 2,5 ✅ |
| 9 | Admin Dashboard Endpoints | High | ~1,200 | 12-14h | All previous ✅ |
| Total | ~2,600 | 26-32h | 3-4 days |
Parallelization Strategy:
- Step 7 and Step 8 can execute in parallel (no dependencies)
- Step 9 requires Steps 7-8 complete (needs live data for analytics)
Table of Contents
- Dependency Analysis
- Step 7: Client-Side Python SDK
- Step 8: Monthly Renewal Automation
- Step 9: Admin Dashboard Endpoints
- Multi-Agent Coordination Plan
- Execution Timeline
- Success Verification Checklist
- Risk Mitigation
Dependency Analysis
Execution Order
┌─────────────────┐
│ Steps 1-6 │ ✅ COMPLETE (user registration, Stripe, licenses, email, seats)
└────────┬────────┘
│
┌────┴────┐
│ │
▼ ▼
┌───────┐ ┌───────┐
│ Step 7│ │ Step 8│ ⚡ PARALLEL EXECUTION (no dependencies)
│ SDK │ │Renewal│
└───┬───┘ └───┬───┘
│ │
└────┬────┘
│
▼
┌────────┐
│ Step 9 │ 📊 SEQUENTIAL (needs live data from 7+8)
│ Admin │
└────────┘
Optimal Execution Strategy
Phase A: Parallel Implementation (Days 1-2)
- Agent 1: Implement Step 7 (Client SDK)
- Agent 2: Implement Step 8 (Renewal Webhooks)
- Estimated Time: 14-18 hours (1.5-2 days)
Phase B: Sequential Implementation (Days 3-4)
- Agent 3: Implement Step 9 (Admin Dashboard)
- Estimated Time: 12-14 hours (1.5-2 days)
Total Timeline: 3-4 days to completion
Step 7: Client-Side Python SDK
Overview
Purpose: Python SDK for CODITECT CLI/framework to acquire licenses, send heartbeats, and release seats automatically.
Status: ❌ Not Started (0%) Complexity: Medium (client library development, threading, error handling) Estimated LOC: ~800 lines Estimated Time: 8-10 hours Dependencies: Step 6 (Seat Management API) ✅ Complete
Technical Specifications
7.1 SDK Architecture
Package Structure:
coditect_license_sdk/
├── __init__.py # Public API exports
├── client.py # Main LicenseClient class (300 lines)
├── session.py # LicenseSession management (200 lines)
├── heartbeat.py # Background heartbeat thread (150 lines)
├── exceptions.py # Custom exceptions (50 lines)
├── models.py # Data models (100 lines)
└── utils.py # Helper functions (50 lines)
tests/
├── test_client.py # Client tests (200 lines)
├── test_session.py # Session tests (150 lines)
├── test_heartbeat.py # Heartbeat tests (100 lines)
└── conftest.py # Pytest fixtures (50 lines)
Total: ~1,350 lines (implementation + tests)
7.2 Core Components
LicenseClient (Main Interface)
from coditect_license_sdk import LicenseClient
# Initialize client
client = LicenseClient(
api_url="https://api.coditect.ai",
api_key="user_api_token"
)
# Acquire license (blocks until seat available)
session = client.acquire_license(
license_key="CODITECT-A7B2-9C4D-E6F8-1G3H-5J7K",
machine_id="a7b2c4d6e8f0a1b3c5d7e9f1a3b5c7d9",
machine_info={
"hostname": "johns-macbook",
"os": "macOS 14.1",
"coditect_version": "1.0.0"
}
)
# Session automatically sends heartbeats every 2 minutes
# Use CODITECT features...
# Release when done (automatically called on process exit)
session.release()
Automatic Heartbeat Management
# Heartbeat thread (background daemon)
import threading
import time
class HeartbeatThread(threading.Thread):
def __init__(self, session_id, client, interval=120):
super().__init__(daemon=True)
self.session_id = session_id
self.client = client
self.interval = interval # 2 minutes
self.running = True
def run(self):
while self.running:
time.sleep(self.interval)
try:
self.client.send_heartbeat(self.session_id)
except Exception as e:
# Exponential backoff on failure
time.sleep(min(300, self.interval * 2))
def stop(self):
self.running = False
Graceful Shutdown
import atexit
import signal
class LicenseSession:
def __init__(self, session_id, client):
self.session_id = session_id
self.client = client
self.released = False
# Register cleanup handlers
atexit.register(self.release)
signal.signal(signal.SIGTERM, self._signal_handler)
signal.signal(signal.SIGINT, self._signal_handler)
def _signal_handler(self, signum, frame):
self.release()
sys.exit(0)
def release(self):
if not self.released:
self.client.release_license(self.session_id)
self.released = True
7.3 Error Handling
Custom Exceptions:
class LicenseError(Exception):
"""Base exception for license operations"""
pass
class LicenseAcquisitionError(LicenseError):
"""Failed to acquire license seat"""
pass
class SeatUnavailableError(LicenseAcquisitionError):
"""All seats currently in use"""
pass
class LicenseExpiredError(LicenseError):
"""License has expired"""
pass
class HeartbeatFailedError(LicenseError):
"""Heartbeat request failed"""
pass
class NetworkError(LicenseError):
"""Network connectivity issue"""
pass
Retry Logic:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def acquire_license_with_retry(self, license_key, machine_id, machine_info):
"""Retry acquisition up to 3 times with exponential backoff"""
response = self.api_client.post("/licenses/acquire", json={
"license_key": license_key,
"machine_id": machine_id,
"machine_info": machine_info
})
if response.status_code == 409: # Seat unavailable
raise SeatUnavailableError("All license seats are in use")
elif response.status_code == 401: # Unauthorized
raise LicenseAcquisitionError("Invalid license key")
response.raise_for_status()
return response.json()
7.4 Implementation Tasks
Agent Assignment: Backend Python Developer (codi-python-backend-developer)
Task Breakdown:
-
Package Setup (1 hour)
- Create package structure
- Setup pyproject.toml with dependencies
- Configure pytest for testing
-
Core Client Implementation (3 hours)
- Implement LicenseClient class
- HTTP client with requests library
- Authentication header handling
- Error response parsing
-
Session Management (2 hours)
- LicenseSession class
- Graceful shutdown handlers
- State management (active/released)
-
Heartbeat Threading (2 hours)
- Background daemon thread
- Exponential backoff on failure
- Graceful thread termination
-
Exception Handling (1 hour)
- Custom exception hierarchy
- Retry logic with tenacity
- Network error handling
-
Testing (2-3 hours)
- Unit tests with mocked API
- Integration tests with live API
- Threading tests
- Edge case handling
Dependencies:
# pyproject.toml
[project]
name = "coditect-license-sdk"
version = "1.0.0"
dependencies = [
"requests>=2.31.0",
"tenacity>=8.2.0",
"pydantic>=2.5.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"responses>=0.24.0", # Mock HTTP responses
]
7.5 Integration with CODITECT Framework
Usage in CODITECT CLI:
# coditect/cli/license_manager.py
from coditect_license_sdk import LicenseClient
def initialize_license():
"""Initialize license on CODITECT startup"""
config = load_coditect_config()
client = LicenseClient(
api_url=config.get("license_api_url"),
api_key=config.get("user_api_token")
)
session = client.acquire_license(
license_key=config.get("license_key"),
machine_id=get_machine_id(),
machine_info=get_machine_info()
)
# Store session globally for cleanup
global _active_license_session
_active_license_session = session
return session
7.6 Success Criteria
- ✅ SDK can acquire license seat successfully
- ✅ Heartbeat sends every 2 minutes automatically
- ✅ Graceful release on normal exit
- ✅ Graceful release on SIGTERM/SIGINT
- ✅ Retry logic handles transient failures
- ✅ Clear error messages for all failure modes
- ✅ Unit tests: 80%+ coverage
- ✅ Integration tests: All API endpoints tested
- ✅ Documentation: API reference + examples
7.7 Deliverables
- SDK Package:
coditect_license_sdk/(800 lines) - Test Suite:
tests/(500 lines, 80%+ coverage) - Documentation: README.md with API reference and examples
- Integration: Modified CODITECT CLI to use SDK
- PyPI Package: Published
coditect-license-sdkv1.0.0
Step 8: Monthly Renewal Automation
Overview
Purpose: Automatically renew licenses when Stripe charges monthly subscription, handle payment failures, send notifications.
Status: ❌ Not Started (0%) Complexity: Medium (webhook integration, edge cases, idempotency) Estimated LOC: ~600 lines Estimated Time: 6-8 hours Dependencies: Step 2 (Stripe Integration) ✅, Step 5 (SendGrid Email) ✅
Technical Specifications
8.1 Webhook Architecture
Stripe Webhooks to Handle:
1. invoice.payment_succeeded → Renew license automatically
2. invoice.payment_failed → Suspend license + notify user
3. customer.subscription.deleted → Deactivate license + notify
4. customer.subscription.updated → Update license tier
Webhook Endpoint:
POST /api/v1/webhooks/stripe
Headers:
- stripe-signature: [webhook signature]
Body: JSON event from Stripe
8.2 Renewal Flow
┌─────────────────┐
│ Stripe charges │ Monthly billing cycle (e.g., 1st of month)
│ subscription │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Webhook Event │ invoice.payment_succeeded
│ Received │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Verify Signature│ Validate webhook authenticity
└────────┬────────┘
│
▼
┌─────────────────┐
│ Find License │ subscription_id → license mapping
└────────┬────────┘
│
▼
┌─────────────────┐
│ Renew License │ Update valid_until = now + 30 days
└────────┬────────┘
│
▼
┌─────────────────┐
│ Send Email │ "Your CODITECT license has been renewed"
└─────────────────┘
8.3 Core Components
Webhook Handler View
File: api/v1/views/stripe_webhook.py (250 lines)
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from django.db import transaction
import stripe
import logging
logger = logging.getLogger(__name__)
@csrf_exempt
def stripe_webhook_handler(request):
"""
Handle Stripe webhook events for subscription lifecycle.
Idempotent: Safe to receive duplicate events.
"""
payload = request.body
sig_header = request.META.get('HTTP_STRIPE_SIGNATURE')
try:
# Verify webhook signature
event = stripe.Webhook.construct_event(
payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
)
except ValueError:
logger.error("Invalid webhook payload")
return JsonResponse({'error': 'Invalid payload'}, status=400)
except stripe.error.SignatureVerificationError:
logger.error("Invalid webhook signature")
return JsonResponse({'error': 'Invalid signature'}, status=400)
# Route to appropriate handler
handlers = {
'invoice.payment_succeeded': handle_payment_succeeded,
'invoice.payment_failed': handle_payment_failed,
'customer.subscription.deleted': handle_subscription_deleted,
'customer.subscription.updated': handle_subscription_updated,
}
handler = handlers.get(event['type'])
if handler:
try:
handler(event['data']['object'])
return JsonResponse({'status': 'success'})
except Exception as e:
logger.error(f"Webhook handler failed: {e}", exc_info=True)
return JsonResponse({'error': str(e)}, status=500)
# Unknown event type (ignore)
return JsonResponse({'status': 'ignored'})
Payment Success Handler
@transaction.atomic
def handle_payment_succeeded(invoice):
"""
Renew license when monthly payment succeeds.
Idempotent: Check if already renewed for this billing period.
"""
subscription_id = invoice['subscription']
payment_intent = invoice['payment_intent']
# Find license by subscription
try:
license = License.objects.select_for_update().get(
subscription__stripe_subscription_id=subscription_id
)
except License.DoesNotExist:
logger.warning(f"License not found for subscription {subscription_id}")
return
# Check if already renewed (idempotency)
if license.valid_until and license.valid_until > timezone.now():
logger.info(f"License {license.key} already renewed")
return
# Renew license for 30 days
license.valid_until = timezone.now() + timedelta(days=30)
license.is_active = True
license.save()
# Create audit log
AuditLog.objects.create(
license=license,
action='license_renewed',
details={
'subscription_id': subscription_id,
'payment_intent': payment_intent,
'renewed_until': license.valid_until.isoformat(),
}
)
# Send renewal email
send_license_renewed_email(license)
logger.info(f"License {license.key} renewed until {license.valid_until}")
Payment Failure Handler
@transaction.atomic
def handle_payment_failed(invoice):
"""
Suspend license when payment fails.
Grace period: Allow 3 days before hard suspension.
"""
subscription_id = invoice['subscription']
attempt_count = invoice['attempt_count']
try:
license = License.objects.select_for_update().get(
subscription__stripe_subscription_id=subscription_id
)
except License.DoesNotExist:
return
# First failure: Send warning email (grace period)
if attempt_count == 1:
grace_until = timezone.now() + timedelta(days=3)
send_payment_failed_email(license, grace_until)
logger.warning(f"Payment failed for license {license.key} (attempt {attempt_count})")
return
# Multiple failures: Suspend license
if attempt_count >= 2:
license.is_active = False
license.save()
# Create audit log
AuditLog.objects.create(
license=license,
action='license_suspended',
details={
'reason': 'payment_failure',
'attempt_count': attempt_count,
}
)
# Send suspension email
send_license_suspended_email(license)
logger.error(f"License {license.key} suspended due to payment failure")
Subscription Deletion Handler
@transaction.atomic
def handle_subscription_deleted(subscription):
"""
Deactivate license when subscription is cancelled.
Immediate effect: No grace period.
"""
subscription_id = subscription['id']
try:
license = License.objects.select_for_update().get(
subscription__stripe_subscription_id=subscription_id
)
except License.DoesNotExist:
return
# Deactivate license
license.is_active = False
license.save()
# Create audit log
AuditLog.objects.create(
license=license,
action='license_deactivated',
details={
'reason': 'subscription_cancelled',
'subscription_id': subscription_id,
}
)
# Send cancellation confirmation email
send_subscription_cancelled_email(license)
logger.info(f"License {license.key} deactivated (subscription cancelled)")
8.4 Email Templates
File: api/v1/emails/license_renewed.py (150 lines)
def send_license_renewed_email(license):
"""
Send renewal confirmation email.
Template: license_renewed.html
"""
user = license.subscription.user
context = {
'user_name': user.full_name,
'license_key': license.key,
'valid_until': license.valid_until.strftime('%B %d, %Y'),
'plan_name': license.subscription.stripe_price_id,
'dashboard_url': 'https://dashboard.coditect.ai',
}
send_email(
to_email=user.email,
subject="Your CODITECT License Has Been Renewed",
template='license_renewed.html',
context=context
)
SendGrid Template Structure:
<!-- license_renewed.html -->
<h1>License Renewed Successfully</h1>
<p>Hi {{user_name}},</p>
<p>Your CODITECT license has been automatically renewed.</p>
<ul>
<li>License Key: <code>{{license_key}}</code></li>
<li>Valid Until: {{valid_until}}</li>
<li>Plan: {{plan_name}}</li>
</ul>
<p>Continue building amazing projects!</p>
<a href="{{dashboard_url}}">View Dashboard</a>
8.5 Implementation Tasks
Agent Assignment: Backend API Developer (codi-backend-api-developer)
Task Breakdown:
-
Stripe Webhook Setup (1 hour)
- Register webhook endpoint in Stripe Dashboard
- Configure event types to listen for
- Get webhook signing secret
-
Webhook Handler Implementation (2 hours)
- Main webhook view with signature verification
- Event routing to specific handlers
- Error handling and logging
-
Renewal Logic Implementation (2 hours)
- Payment success handler
- Payment failure handler (with grace period)
- Subscription deletion handler
- Subscription update handler
-
Email Integration (1 hour)
- Renewal confirmation email
- Payment failure warning email
- License suspension email
- Cancellation confirmation email
-
Testing (2 hours)
- Unit tests with mocked Stripe events
- Webhook signature verification tests
- Idempotency tests (duplicate events)
- Integration tests with Stripe CLI
Testing with Stripe CLI:
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Forward webhooks to local server
stripe listen --forward-to localhost:8000/api/v1/webhooks/stripe
# Trigger test events
stripe trigger invoice.payment_succeeded
stripe trigger invoice.payment_failed
stripe trigger customer.subscription.deleted
8.6 Idempotency Considerations
Critical: Stripe may send duplicate webhook events. All handlers must be idempotent.
Idempotency Strategies:
- Database Constraints:
# Prevent duplicate license renewals for same billing period
class LicenseRenewalLog(models.Model):
license = models.ForeignKey(License)
stripe_invoice_id = models.CharField(max_length=255, unique=True)
renewed_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ('license', 'stripe_invoice_id')
- Check-Before-Act:
# Check if action already performed
if LicenseRenewalLog.objects.filter(stripe_invoice_id=invoice_id).exists():
logger.info(f"Invoice {invoice_id} already processed")
return # Skip duplicate
- Atomic Transactions:
@transaction.atomic
def handle_payment_succeeded(invoice):
# Use select_for_update to prevent race conditions
license = License.objects.select_for_update().get(...)
# ... perform operations ...
8.7 Success Criteria
- ✅ Webhook endpoint receives Stripe events correctly
- ✅ Signature verification prevents spoofed webhooks
- ✅ Licenses renew automatically on payment success
- ✅ Licenses suspend after 2 failed payments
- ✅ Licenses deactivate on subscription cancellation
- ✅ All email notifications sent correctly
- ✅ Idempotency: Duplicate events handled safely
- ✅ Unit tests: 85%+ coverage
- ✅ Integration tests: All webhook types tested
- ✅ Manual testing: Stripe CLI triggers verified
8.8 Deliverables
- Webhook Handler:
api/v1/views/stripe_webhook.py(250 lines) - Event Handlers: Payment, failure, cancellation handlers (200 lines)
- Email Templates: 4 SendGrid templates (150 lines)
- Test Suite: Webhook tests (200 lines, 85%+ coverage)
- Documentation: Webhook setup guide and testing procedures
Step 9: Admin Dashboard Endpoints
Overview
Purpose: Comprehensive API endpoints for admin dashboard to manage organizations, licenses, users, billing, and view analytics.
Status: ❌ Not Started (0%) Complexity: High (CRUD operations + analytics + admin auth) Estimated LOC: ~1,200 lines Estimated Time: 12-14 hours Dependencies: All previous steps (needs live data)
Technical Specifications
9.1 Admin Dashboard Requirements
User Stories:
- As an admin, I want to view all organizations so I can monitor customer base
- As an admin, I want to search organizations by name/email for support
- As an admin, I want to view all licenses and their status (active/expired/suspended)
- As an admin, I want to manually activate/deactivate licenses for edge cases
- As an admin, I want to view license usage analytics (seat utilization, uptime)
- As an admin, I want to manage users (view, suspend, delete)
- As an admin, I want to view billing history (Stripe transactions)
- As an admin, I want to view system health metrics (API performance, errors)
9.2 API Endpoints
Admin Organization Management:
GET /api/v1/admin/organizations # List all organizations
GET /api/v1/admin/organizations/{id} # Get organization details
POST /api/v1/admin/organizations # Create organization (manual)
PATCH /api/v1/admin/organizations/{id} # Update organization
DELETE /api/v1/admin/organizations/{id} # Delete organization
GET /api/v1/admin/organizations/search # Search by name/email
Admin License Management:
GET /api/v1/admin/licenses # List all licenses
GET /api/v1/admin/licenses/{key} # Get license details
POST /api/v1/admin/licenses # Create license manually
PATCH /api/v1/admin/licenses/{key} # Update license
DELETE /api/v1/admin/licenses/{key} # Revoke license
POST /api/v1/admin/licenses/{key}/activate # Activate license
POST /api/v1/admin/licenses/{key}/deactivate # Deactivate license
GET /api/v1/admin/licenses/{key}/sessions # View active sessions
POST /api/v1/admin/licenses/{key}/sessions/{id}/terminate # Kill session
Admin User Management:
GET /api/v1/admin/users # List all users
GET /api/v1/admin/users/{id} # Get user details
POST /api/v1/admin/users # Create user manually
PATCH /api/v1/admin/users/{id} # Update user
DELETE /api/v1/admin/users/{id} # Delete user
POST /api/v1/admin/users/{id}/suspend # Suspend user account
POST /api/v1/admin/users/{id}/unsuspend # Unsuspend user account
GET /api/v1/admin/users/search # Search users
Admin Analytics:
GET /api/v1/admin/analytics/overview # Dashboard overview stats
GET /api/v1/admin/analytics/revenue # Revenue metrics
GET /api/v1/admin/analytics/licenses # License usage metrics
GET /api/v1/admin/analytics/users # User growth metrics
GET /api/v1/admin/analytics/sessions # Session analytics
Admin Billing:
GET /api/v1/admin/billing/transactions # All Stripe transactions
GET /api/v1/admin/billing/subscriptions # All subscriptions
GET /api/v1/admin/billing/invoices # All invoices
POST /api/v1/admin/billing/refunds # Issue refund
Total Endpoints: 31 admin endpoints
9.3 Core Components
Admin Authentication Middleware
File: api/middleware/admin_auth.py (100 lines)
from django.http import JsonResponse
from functools import wraps
def admin_required(view_func):
"""
Decorator for admin-only endpoints.
Requires:
- Valid JWT token
- User has 'admin' role
"""
@wraps(view_func)
def wrapper(request, *args, **kwargs):
# Check authentication
if not request.user or not request.user.is_authenticated:
return JsonResponse({
'error': 'Authentication required'
}, status=401)
# Check admin role
if not request.user.is_staff and not request.user.is_superuser:
return JsonResponse({
'error': 'Admin privileges required'
}, status=403)
return view_func(request, *args, **kwargs)
return wrapper
Organization Management View
File: api/v1/views/admin/organizations.py (250 lines)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.core.paginator import Paginator
from api.middleware.admin_auth import admin_required
class AdminOrganizationListView(APIView):
"""
List all organizations with pagination and filtering.
Query params:
- page: Page number (default: 1)
- page_size: Items per page (default: 50)
- search: Search by name/email
- status: Filter by status (active/suspended)
"""
@admin_required
def get(self, request):
# Parse query params
page = int(request.GET.get('page', 1))
page_size = int(request.GET.get('page_size', 50))
search = request.GET.get('search', '')
status_filter = request.GET.get('status', '')
# Build queryset
orgs = Organization.objects.all()
if search:
orgs = orgs.filter(
Q(name__icontains=search) |
Q(owner__email__icontains=search)
)
if status_filter:
orgs = orgs.filter(is_active=(status_filter == 'active'))
# Order by creation date
orgs = orgs.order_by('-created_at')
# Paginate
paginator = Paginator(orgs, page_size)
page_obj = paginator.get_page(page)
# Serialize
data = {
'organizations': [
{
'id': org.id,
'name': org.name,
'owner_email': org.owner.email,
'created_at': org.created_at.isoformat(),
'is_active': org.is_active,
'license_count': org.licenses.count(),
'user_count': org.users.count(),
}
for org in page_obj
],
'pagination': {
'page': page,
'page_size': page_size,
'total_pages': paginator.num_pages,
'total_count': paginator.count,
}
}
return Response(data)
License Management View
File: api/v1/views/admin/licenses.py (300 lines)
class AdminLicenseListView(APIView):
"""
List all licenses with filtering and search.
"""
@admin_required
def get(self, request):
# Similar structure to OrganizationListView
# Filters: status, plan, expiration date range
pass
class AdminLicenseActivateView(APIView):
"""
Manually activate a license.
"""
@admin_required
@transaction.atomic
def post(self, request, license_key):
try:
license = License.objects.select_for_update().get(key=license_key)
except License.DoesNotExist:
return Response({
'error': 'License not found'
}, status=404)
# Activate license
license.is_active = True
license.save()
# Create audit log
AuditLog.objects.create(
license=license,
action='admin_activated',
details={
'admin_user': request.user.email,
'reason': request.data.get('reason', 'Manual activation'),
}
)
return Response({
'status': 'activated',
'license_key': license.key,
})
class AdminLicenseSessionTerminateView(APIView):
"""
Forcefully terminate an active license session.
"""
@admin_required
@transaction.atomic
def post(self, request, license_key, session_id):
try:
session = LicenseSession.objects.get(
id=session_id,
license__key=license_key
)
except LicenseSession.DoesNotExist:
return Response({
'error': 'Session not found'
}, status=404)
# End session
session.ended_at = timezone.now()
session.save()
# Release seat in Redis
redis_client.decr(f"license_seats:{license_key}")
# Create audit log
AuditLog.objects.create(
license=session.license,
action='admin_session_terminated',
details={
'admin_user': request.user.email,
'session_id': str(session_id),
'reason': request.data.get('reason', 'Admin intervention'),
}
)
return Response({
'status': 'terminated',
'session_id': str(session_id),
})
Analytics View
File: api/v1/views/admin/analytics.py (400 lines)
from django.db.models import Count, Sum, Avg
from datetime import datetime, timedelta
class AdminAnalyticsOverviewView(APIView):
"""
Dashboard overview with key metrics.
"""
@admin_required
def get(self, request):
now = timezone.now()
last_30_days = now - timedelta(days=30)
# Calculate metrics
metrics = {
'organizations': {
'total': Organization.objects.count(),
'active': Organization.objects.filter(is_active=True).count(),
'new_this_month': Organization.objects.filter(
created_at__gte=last_30_days
).count(),
},
'licenses': {
'total': License.objects.count(),
'active': License.objects.filter(is_active=True).count(),
'expired': License.objects.filter(
valid_until__lt=now
).count(),
'suspended': License.objects.filter(
is_active=False,
valid_until__gte=now
).count(),
},
'users': {
'total': User.objects.count(),
'active': User.objects.filter(is_active=True).count(),
'new_this_month': User.objects.filter(
created_at__gte=last_30_days
).count(),
},
'sessions': {
'active_now': LicenseSession.objects.filter(
ended_at__isnull=True,
last_heartbeat_at__gte=now - timedelta(minutes=6)
).count(),
'total_this_month': LicenseSession.objects.filter(
started_at__gte=last_30_days
).count(),
},
'revenue': {
'mrr': calculate_monthly_recurring_revenue(),
'arr': calculate_annual_recurring_revenue(),
'churn_rate': calculate_churn_rate(),
},
}
return Response(metrics)
class AdminAnalyticsLicenseUsageView(APIView):
"""
Detailed license usage analytics.
"""
@admin_required
def get(self, request):
# Calculate seat utilization per license
licenses = License.objects.annotate(
total_sessions=Count('sessions'),
active_sessions=Count('sessions', filter=Q(
sessions__ended_at__isnull=True,
sessions__last_heartbeat_at__gte=timezone.now() - timedelta(minutes=6)
))
)
usage_data = []
for license in licenses:
usage_data.append({
'license_key': license.key,
'max_seats': license.max_seats,
'active_sessions': license.active_sessions,
'utilization_percent': (license.active_sessions / license.max_seats) * 100 if license.max_seats > 0 else 0,
'total_sessions_all_time': license.total_sessions,
})
# Sort by utilization (highest first)
usage_data.sort(key=lambda x: x['utilization_percent'], reverse=True)
return Response({
'license_usage': usage_data,
'summary': {
'avg_utilization': sum(d['utilization_percent'] for d in usage_data) / len(usage_data) if usage_data else 0,
'over_utilized': [d for d in usage_data if d['utilization_percent'] >= 90],
'under_utilized': [d for d in usage_data if d['utilization_percent'] < 20],
}
})
9.4 Pagination & Filtering
Standard Pagination:
# Query params
?page=1&page_size=50
# Response format
{
"data": [...],
"pagination": {
"page": 1,
"page_size": 50,
"total_pages": 10,
"total_count": 487,
"has_next": true,
"has_previous": false
}
}
Standard Filtering:
# Organizations
?status=active&search=acme
# Licenses
?status=active&plan=pro&expires_after=2025-12-01
# Users
?status=active&role=admin&search=john
# Sessions
?active=true&license_key=CODITECT-xxx
9.5 Implementation Tasks
Agent Assignment: Full-Stack API Developer (codi-fullstack-developer)
Task Breakdown:
-
Admin Middleware Setup (1 hour)
- Admin authentication decorator
- Role-based access control
- Audit logging for admin actions
-
Organization Management (2 hours)
- List, view, create, update, delete endpoints
- Search and filtering
- Pagination
-
License Management (3 hours)
- List, view, create, update, delete endpoints
- Activate/deactivate actions
- Session management (view, terminate)
- Search and filtering
-
User Management (2 hours)
- List, view, create, update, delete endpoints
- Suspend/unsuspend actions
- Search and filtering
-
Analytics Implementation (3 hours)
- Overview dashboard metrics
- Revenue calculations (MRR, ARR, churn)
- License usage analytics
- User growth metrics
- Session analytics
-
Billing Integration (1 hour)
- Transaction history
- Subscription listing
- Refund API
-
Testing (3 hours)
- Unit tests for all endpoints
- Authorization tests (admin vs. non-admin)
- Pagination tests
- Analytics calculation tests
Testing Strategy:
# pytest tests/admin/test_admin_organizations.py
def test_admin_can_list_organizations(admin_client):
response = admin_client.get('/api/v1/admin/organizations')
assert response.status_code == 200
assert 'organizations' in response.json()
def test_non_admin_cannot_list_organizations(user_client):
response = user_client.get('/api/v1/admin/organizations')
assert response.status_code == 403
def test_organization_search_works(admin_client):
response = admin_client.get('/api/v1/admin/organizations?search=acme')
assert response.status_code == 200
results = response.json()['organizations']
assert all('acme' in org['name'].lower() for org in results)
9.6 Success Criteria
- ✅ All 31 admin endpoints implemented
- ✅ Admin-only authorization enforced
- ✅ Pagination works on all list endpoints
- ✅ Search and filtering functional
- ✅ Analytics calculations accurate (MRR, ARR, churn, utilization)
- ✅ Audit logging for all admin actions
- ✅ Manual license activation/deactivation works
- ✅ Session termination functional
- ✅ Unit tests: 80%+ coverage
- ✅ Integration tests: All endpoints tested
- ✅ OpenAPI documentation generated
9.7 Deliverables
- Admin Middleware:
api/middleware/admin_auth.py(100 lines) - Organization Management:
api/v1/views/admin/organizations.py(250 lines) - License Management:
api/v1/views/admin/licenses.py(300 lines) - User Management:
api/v1/views/admin/users.py(200 lines) - Analytics:
api/v1/views/admin/analytics.py(400 lines) - Billing:
api/v1/views/admin/billing.py(150 lines) - Test Suite:
tests/admin/(500 lines, 80%+ coverage) - API Documentation: OpenAPI specs for all endpoints
Multi-Agent Coordination Plan
Agent Assignments
| Agent Type | Step | Tasks | Parallel? |
|---|---|---|---|
| codi-python-backend-developer | Step 7 | Client SDK implementation | ✅ Yes (with Agent 2) |
| codi-backend-api-developer | Step 8 | Stripe webhook handlers | ✅ Yes (with Agent 1) |
| codi-fullstack-developer | Step 9 | Admin dashboard APIs | ❌ Sequential (after 7+8) |
| codi-test-engineer | All Steps | Comprehensive testing | ⚡ Continuous |
| codi-documentation-writer | All Steps | API documentation | ⚡ Continuous |
Execution Phases
Phase A: Parallel Implementation (Days 1-2)
Agent 1: Python Backend Developer (Step 7)
Task(
subagent_type="codi-python-backend-developer",
description="Implement CODITECT License SDK with automatic heartbeat scheduling",
prompt="""
Implement client-side Python SDK for CODITECT license management:
1. Package Structure:
- coditect_license_sdk/ (main package)
- client.py (LicenseClient class)
- session.py (LicenseSession management)
- heartbeat.py (background thread)
- exceptions.py (custom errors)
2. Core Features:
- acquire_license(): Obtain seat from API
- Automatic heartbeat every 2 minutes (background thread)
- Graceful release on exit (atexit, signal handlers)
- Retry logic with exponential backoff
- Clear error messages
3. API Integration:
- POST /api/v1/licenses/acquire
- PATCH /api/v1/licenses/sessions/{id}/heartbeat
- DELETE /api/v1/licenses/sessions/{id}
4. Testing:
- Unit tests with mocked API (responses library)
- Threading tests
- Integration tests with live API
- 80%+ coverage
5. Documentation:
- README.md with examples
- API reference
- Error handling guide
Reference: phase1-step6-api-quick-reference.md for API specs
Target: 800 lines implementation + 500 lines tests
Completion: 8-10 hours
"""
)
Agent 2: Backend API Developer (Step 8)
Task(
subagent_type="codi-backend-api-developer",
description="Implement Stripe webhook handlers for automatic license renewal",
prompt="""
Implement Stripe webhook integration for subscription lifecycle:
1. Webhook Endpoint:
- POST /api/v1/webhooks/stripe
- Signature verification (stripe.Webhook.construct_event)
- Event routing to handlers
2. Event Handlers:
- invoice.payment_succeeded → Renew license (valid_until + 30 days)
- invoice.payment_failed → Suspend license (grace period: 3 days)
- customer.subscription.deleted → Deactivate license
- customer.subscription.updated → Update license tier
3. Idempotency:
- Check for duplicate events (invoice_id uniqueness)
- Atomic transactions (select_for_update)
- LicenseRenewalLog table for tracking
4. Email Notifications:
- Renewal confirmation (license_renewed.html)
- Payment failure warning (payment_failed.html)
- License suspended (license_suspended.html)
- Cancellation confirmation (subscription_cancelled.html)
5. Testing:
- Unit tests with mocked Stripe events
- Idempotency tests (duplicate events)
- Integration tests with Stripe CLI
- 85%+ coverage
Reference: phase1-step2-stripe-design.md, phase1-step5-sendgrid-email-design.md
Target: 600 lines implementation + 200 lines tests
Completion: 6-8 hours
"""
)
Synchronization Point: Wait for both agents to complete Phase A before starting Phase B.
Phase B: Sequential Implementation (Days 3-4)
Agent 3: Full-Stack Developer (Step 9)
Task(
subagent_type="codi-fullstack-developer",
description="Implement comprehensive admin dashboard API endpoints",
prompt="""
Implement 31 admin endpoints for dashboard management:
1. Admin Authentication:
- @admin_required decorator
- JWT + is_staff/is_superuser check
- Audit logging for all admin actions
2. Organization Management (6 endpoints):
- GET /admin/organizations (list with pagination)
- GET /admin/organizations/{id} (details)
- POST /admin/organizations (create)
- PATCH /admin/organizations/{id} (update)
- DELETE /admin/organizations/{id} (delete)
- GET /admin/organizations/search (search by name/email)
3. License Management (10 endpoints):
- GET /admin/licenses (list with filtering)
- GET /admin/licenses/{key} (details)
- POST /admin/licenses (create manually)
- PATCH /admin/licenses/{key} (update)
- DELETE /admin/licenses/{key} (revoke)
- POST /admin/licenses/{key}/activate
- POST /admin/licenses/{key}/deactivate
- GET /admin/licenses/{key}/sessions (view active)
- POST /admin/licenses/{key}/sessions/{id}/terminate
- GET /admin/licenses/search
4. User Management (7 endpoints):
- GET /admin/users (list with pagination)
- GET /admin/users/{id} (details)
- POST /admin/users (create)
- PATCH /admin/users/{id} (update)
- DELETE /admin/users/{id} (delete)
- POST /admin/users/{id}/suspend
- POST /admin/users/{id}/unsuspend
5. Analytics (5 endpoints):
- GET /admin/analytics/overview (dashboard metrics)
- GET /admin/analytics/revenue (MRR, ARR, churn)
- GET /admin/analytics/licenses (seat utilization)
- GET /admin/analytics/users (growth metrics)
- GET /admin/analytics/sessions (activity)
6. Billing (3 endpoints):
- GET /admin/billing/transactions
- GET /admin/billing/subscriptions
- POST /admin/billing/refunds
7. Pagination & Filtering:
- Standard pagination (page, page_size)
- Search and filtering on all list endpoints
- Consistent response format
8. Testing:
- Unit tests for all endpoints
- Authorization tests (admin vs. non-admin)
- Pagination tests
- Analytics calculation tests
- 80%+ coverage
Reference: All previous PHASE1-STEP* documents for data models
Target: 1,200 lines implementation + 500 lines tests
Completion: 12-14 hours
Dependencies: Steps 7-8 complete (needs live session data for analytics)
"""
)
Continuous Tasks (All Phases)
Test Engineer: Comprehensive Testing
Task(
subagent_type="codi-test-engineer",
description="Create comprehensive test suite for Steps 7-9",
prompt="""
Develop and execute comprehensive testing:
1. Unit Tests:
- Step 7: SDK client, session, heartbeat (500 lines)
- Step 8: Webhook handlers, idempotency (200 lines)
- Step 9: Admin endpoints, analytics (500 lines)
2. Integration Tests:
- Step 7: Live API integration
- Step 8: Stripe CLI webhook testing
- Step 9: End-to-end admin workflows
3. Edge Cases:
- Network failures and retries
- Concurrent requests and race conditions
- Duplicate events (idempotency)
- Invalid authentication
- Missing data scenarios
4. Performance Tests:
- SDK heartbeat timing accuracy
- Admin endpoint response times
- Pagination efficiency
5. Coverage Goals:
- Overall: 80%+ coverage
- Critical paths: 95%+ coverage
- Admin endpoints: 85%+ coverage
Tools: pytest, pytest-cov, responses (HTTP mocking), Stripe CLI
Target: 1,200 lines of tests across all steps
"""
)
Documentation Writer: API Documentation
Task(
subagent_type="codi-documentation-writer",
description="Create comprehensive API documentation for Steps 7-9",
prompt="""
Generate complete API documentation:
1. SDK Documentation:
- Installation guide
- Quick start example
- API reference (all classes and methods)
- Error handling guide
- Threading considerations
2. Webhook Documentation:
- Stripe webhook setup guide
- Event types and handlers
- Idempotency guarantees
- Testing with Stripe CLI
- Troubleshooting guide
3. Admin API Documentation:
- Authentication requirements
- Endpoint reference (31 endpoints)
- Pagination and filtering guide
- Analytics metrics explanation
- Example requests/responses
4. Integration Guides:
- SDK integration in CODITECT CLI
- Webhook deployment checklist
- Admin dashboard frontend integration
Deliverables:
- SDK_README.md (SDK usage guide)
- WEBHOOK_SETUP_GUIDE.md (Stripe integration)
- ADMIN_API_REFERENCE.md (Admin endpoints)
- INTEGRATION_GUIDES.md (End-to-end flows)
"""
)
Execution Timeline
Day 1: Phase A Start (Parallel Implementation)
Morning (4 hours):
- Agent 1: SDK package setup + LicenseClient implementation
- Agent 2: Webhook endpoint + signature verification
Afternoon (4 hours):
- Agent 1: Session management + heartbeat threading
- Agent 2: Event handlers (payment success, failure, cancellation)
Evening (2 hours):
- Agent 1: Exception handling + retry logic
- Agent 2: Email template integration
Status Check:
- Step 7: ~60% complete
- Step 8: ~70% complete
Day 2: Phase A Completion
Morning (4 hours):
- Agent 1: SDK testing (unit + integration)
- Agent 2: Webhook testing (Stripe CLI)
Afternoon (3 hours):
- Agent 1: SDK documentation + PyPI packaging
- Agent 2: Idempotency testing + edge cases
Evening (1 hour):
- Integration verification
- Code review
- Phase A sign-off
Status Check:
- Step 7: ✅ 100% complete
- Step 8: ✅ 100% complete
Day 3: Phase B Start (Sequential Implementation)
Morning (4 hours):
- Agent 3: Admin middleware + organization endpoints
Afternoon (4 hours):
- Agent 3: License management endpoints
Evening (2 hours):
- Agent 3: User management endpoints
Status Check:
- Step 9: ~50% complete
Day 4: Phase B Completion
Morning (4 hours):
- Agent 3: Analytics endpoints + calculations
Afternoon (3 hours):
- Agent 3: Billing endpoints + testing
Evening (2 hours):
- Agent 3: Comprehensive testing + documentation
Status Check:
- Step 9: ✅ 100% complete
Final Review (1-2 hours)
- ✅ All tests passing (196 existing + ~1,200 new = ~1,400 tests)
- ✅ Code coverage ≥80% overall
- ✅ Documentation complete
- ✅ Integration verified end-to-end
- ✅ project-plan.md updated
- ✅ tasklist.md updated
Total Timeline: 3-4 days (26-32 hours of development)
Success Verification Checklist
Step 7: Client SDK
Functional Tests:
- SDK can acquire license seat successfully
- Heartbeat sends every 2 minutes automatically
- Graceful release on normal exit
- Graceful release on SIGTERM signal
- Graceful release on SIGINT (Ctrl+C)
- Retry logic handles transient API failures
- Clear error messages for all failure modes
- No memory leaks in heartbeat thread
Technical Tests:
- Unit tests: 80%+ coverage
- Integration tests: All API endpoints tested
- Threading tests: Heartbeat timing verified
- Edge case tests: Network failures, API errors
- Performance: <100ms overhead for heartbeat
Documentation:
- README.md with installation and examples
- API reference for all public methods
- Error handling guide
- PyPI package published
Step 8: Renewal Automation
Functional Tests:
- Webhook receives Stripe events successfully
- Signature verification prevents spoofed webhooks
- Payment success → License renewed (valid_until + 30 days)
- Payment failure (1st attempt) → Warning email sent
- Payment failure (2nd attempt) → License suspended
- Subscription cancelled → License deactivated
- All email notifications sent correctly
Technical Tests:
- Unit tests: 85%+ coverage
- Idempotency tests: Duplicate events handled safely
- Integration tests: All webhook types tested with Stripe CLI
- Atomic transactions prevent race conditions
- LicenseRenewalLog prevents duplicate renewals
Documentation:
- Webhook setup guide
- Event handler documentation
- Testing procedures with Stripe CLI
- Troubleshooting guide
Step 9: Admin Dashboard
Functional Tests:
- Admin authentication enforced on all endpoints
- Non-admin users cannot access endpoints (403 Forbidden)
- All 31 endpoints return correct responses
- Pagination works on all list endpoints
- Search and filtering functional
- Analytics calculations accurate (MRR, ARR, churn, utilization)
- Manual license activation/deactivation works
- Session termination functional
Technical Tests:
- Unit tests: 80%+ coverage
- Authorization tests (admin vs. non-admin)
- Pagination tests (page boundaries)
- Analytics calculation tests (edge cases)
- Performance: List endpoints <500ms
Documentation:
- Admin API reference (31 endpoints)
- Pagination and filtering guide
- Analytics metrics explanation
- Frontend integration guide
Overall Integration
End-to-End Flow:
- User registers → Pays → Receives license
- User installs SDK → Acquires seat
- Heartbeats send automatically
- Monthly payment → License renews automatically
- Payment failure → Suspension after grace period
- Admin can view all data in dashboard
- Admin can manage licenses manually
Production Readiness:
- All tests passing (1,400+ tests)
- Code coverage ≥80%
- No security vulnerabilities (admin auth, webhook signature)
- Performance acceptable (<1s response times)
- Error handling comprehensive
- Logging comprehensive (info, warning, error)
- Documentation complete
Project Management:
- project-plan.md updated with completion status
- tasklist.md checkboxes updated
- Git commits with conventional commit messages
- PHASE1-STEPS-7-9-implementation-summary.md created
Risk Mitigation
Risk 1: SDK Threading Issues
Risk: Heartbeat thread may not terminate cleanly, causing zombie processes.
Likelihood: Medium Impact: High (bad user experience)
Mitigation:
- Use daemon threads (automatically killed on exit)
- Implement explicit
stop()method - Register atexit handlers
- Test with
kill -9(hard kill) scenarios - Add timeout to thread join (5 seconds max)
Acceptance Criteria:
- Thread terminates within 5 seconds on normal exit
- No zombie processes after force kill
- Seat released correctly in all scenarios
Risk 2: Webhook Idempotency Failures
Risk: Duplicate Stripe events may cause double renewals or incorrect state.
Likelihood: High (Stripe guarantees at-least-once delivery) Impact: Critical (incorrect billing, license state)
Mitigation:
- Database uniqueness constraints (invoice_id)
- Check-before-act pattern in all handlers
- Atomic transactions with select_for_update
- Comprehensive idempotency tests
- LicenseRenewalLog table for audit trail
Acceptance Criteria:
- Same event processed 5 times → Only 1 renewal
- No race conditions under concurrent webhook load
- All duplicate events logged but skipped
Risk 3: Admin API Performance Degradation
Risk: Analytics queries may be slow with large datasets (10K+ licenses).
Likelihood: Medium Impact: Medium (slow dashboard)
Mitigation:
- Database indexes on frequently queried fields
- Pagination on all list endpoints
- Caching for analytics (Redis, 5-minute TTL)
- Query optimization (select_related, prefetch_related)
- Background job for complex analytics (Celery)
Acceptance Criteria:
- List endpoints: <500ms with 10K records
- Analytics endpoints: <2s with caching
- Dashboard loads in <3s total
Risk 4: Timeline Slippage
Risk: Implementation takes longer than 3-4 days.
Likelihood: Medium Impact: High (delays first paying customer)
Mitigation:
- Start with parallel execution (Steps 7+8)
- Daily progress check-ins
- Reduce scope if needed (defer low-priority admin endpoints)
- Use AI-assisted development for faster coding
- Focus on critical path (Steps 7-8 more important than 9)
Acceptance Criteria:
- Phase A complete by end of Day 2
- If Day 3 slips, defer non-critical admin endpoints
- Minimum viable: Steps 7-8 complete, Step 9 at 60%
Risk 5: Integration Bugs
Risk: SDK doesn't work correctly with CODITECT CLI in production.
Likelihood: Low Impact: Critical (blocks usage)
Mitigation:
- Integration tests with live API
- Manual testing with actual CODITECT CLI
- Staging environment deployment
- Gradual rollout (beta users first)
- Rollback plan ready
Acceptance Criteria:
- SDK works in CODITECT CLI staging environment
- Manual end-to-end test successful
- Beta user validation before GA
Post-Completion Actions
Immediate (Same Day)
-
Update Documentation:
- Update project-plan.md (Phase 1 complete: 9/9 steps)
- Update tasklist.md (mark all Step 7-9 tasks complete)
- Create PHASE1-STEPS-7-9-implementation-summary.md
-
Git Operations:
- Commit all code with conventional commits
- Tag release:
v1.0.0-phase1-complete - Push to GitHub
- Create PR for review
-
Deploy to Staging:
- Deploy backend to staging environment
- Publish SDK to PyPI (or internal registry)
- Configure Stripe webhooks for staging
Short-Term (Within 1 Week)
-
Testing & Validation:
- Manual end-to-end testing in staging
- Beta user testing (5-10 users)
- Performance testing under load
- Security audit (webhook signatures, admin auth)
-
Monitoring Setup:
- Configure alerts for webhook failures
- Monitor SDK heartbeat success rates
- Track admin dashboard performance
- Setup error tracking (Sentry)
-
Documentation Finalization:
- User guide for SDK installation
- Admin dashboard user manual
- Troubleshooting FAQ
- Video tutorials (optional)
Medium-Term (1-2 Weeks)
-
Production Deployment:
- Deploy to production environment
- Configure production Stripe webhooks
- Publish SDK to public PyPI
- Announce availability to beta users
-
First Paying Customer Milestone:
- Complete first payment flow
- Verify license acquisition works
- Confirm monthly renewal works
- Collect feedback and iterate
Appendix A: Technology Stack Summary
Backend (Django REST Framework):
- Python 3.12
- Django 5.2.8
- Django REST Framework
- PostgreSQL (Cloud SQL)
- Redis (Memorystore)
- Cloud KMS (license signing)
- Stripe API (payments)
- SendGrid API (emails)
Client SDK (Python):
- Python 3.9+ compatibility
- requests library (HTTP client)
- tenacity (retry logic)
- threading (heartbeat daemon)
- pydantic (data validation)
Testing:
- pytest (test framework)
- pytest-cov (coverage)
- responses (HTTP mocking)
- Stripe CLI (webhook testing)
Infrastructure:
- Google Kubernetes Engine (GKE)
- Cloud Build (CI/CD)
- Cloud Load Balancer
- Identity Platform (OAuth2)
Appendix B: Estimated Lines of Code
| Component | Implementation | Tests | Documentation | Total |
|---|---|---|---|---|
| Step 7: Client SDK | 800 | 500 | 200 | 1,500 |
| Step 8: Renewal | 600 | 200 | 150 | 950 |
| Step 9: Admin APIs | 1,200 | 500 | 300 | 2,000 |
| Total | 2,600 | 1,200 | 650 | 4,450 |
Current Codebase: ~5,300 lines + 196 tests After Steps 7-9: ~7,900 lines + 1,396 tests (~50% increase)
Appendix C: API Endpoint Summary
Existing Endpoints (Steps 1-6)
POST /api/v1/auth/register
POST /api/v1/auth/login
POST /api/v1/auth/verify-email
POST /api/v1/subscriptions
GET /api/v1/subscriptions/{id}
GET /api/v1/licenses
GET /api/v1/licenses/{key}
POST /api/v1/licenses/{key}/sign
POST /api/v1/licenses/acquire
PATCH /api/v1/licenses/sessions/{id}/heartbeat
DELETE /api/v1/licenses/sessions/{id}
Total: 11 endpoints ✅ Complete
New Endpoints (Steps 7-9)
Step 7: None (client SDK, no new backend endpoints)
Step 8: Webhooks
POST /api/v1/webhooks/stripe
Total: 1 endpoint
Step 9: Admin Dashboard
# Organizations (6)
GET /api/v1/admin/organizations
GET /api/v1/admin/organizations/{id}
POST /api/v1/admin/organizations
PATCH /api/v1/admin/organizations/{id}
DELETE /api/v1/admin/organizations/{id}
GET /api/v1/admin/organizations/search
# Licenses (10)
GET /api/v1/admin/licenses
GET /api/v1/admin/licenses/{key}
POST /api/v1/admin/licenses
PATCH /api/v1/admin/licenses/{key}
DELETE /api/v1/admin/licenses/{key}
POST /api/v1/admin/licenses/{key}/activate
POST /api/v1/admin/licenses/{key}/deactivate
GET /api/v1/admin/licenses/{key}/sessions
POST /api/v1/admin/licenses/{key}/sessions/{id}/terminate
GET /api/v1/admin/licenses/search
# Users (7)
GET /api/v1/admin/users
GET /api/v1/admin/users/{id}
POST /api/v1/admin/users
PATCH /api/v1/admin/users/{id}
DELETE /api/v1/admin/users/{id}
POST /api/v1/admin/users/{id}/suspend
POST /api/v1/admin/users/{id}/unsuspend
# Analytics (5)
GET /api/v1/admin/analytics/overview
GET /api/v1/admin/analytics/revenue
GET /api/v1/admin/analytics/licenses
GET /api/v1/admin/analytics/users
GET /api/v1/admin/analytics/sessions
# Billing (3)
GET /api/v1/admin/billing/transactions
GET /api/v1/admin/billing/subscriptions
POST /api/v1/admin/billing/refunds
Total: 31 endpoints
Grand Total After Phase 1: 43 endpoints
Appendix D: Success Metrics
Phase 1 Completion Criteria:
| Metric | Target | Verification |
|---|---|---|
| Steps Complete | 9/9 (100%) | All steps implemented and tested |
| Lines of Code | ~7,900 | find . -name "*.py" | xargs wc -l |
| Test Count | 1,396+ tests | pytest --collect-only |
| Test Coverage | ≥80% | pytest --cov |
| API Endpoints | 43 total | OpenAPI schema |
| Documentation | 100% | All endpoints documented |
| First Customer | By Dec 22 | Payment → License → Usage flow complete |
Quality Gates:
- ✅ All tests passing
- ✅ No security vulnerabilities
- ✅ Performance acceptable (<1s API responses)
- ✅ Error handling comprehensive
- ✅ Logging configured
- ✅ Admin authentication enforced
- ✅ Webhook idempotency verified
- ✅ SDK integration tested
Document Status: Draft v1.0 - Ready for Implementation Next Action: Begin Phase A (Parallel Implementation) with Agent 1 and Agent 2 Target Completion: December 5, 2025 (4 days from December 1) Critical Path: Steps 7-8 (parallel) → Step 9 (sequential)