35 KiB
Architecture
System Overview
Microservices Architecture - Three independent, deployable components:
┌─────────────────────────────────────────────────────────────┐
│ Frontend Layer (2 options) │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Public Web │ │ Godot Client │ │
│ │ (Flask + Jinja2) │ │ (Native Game) │ │
│ │ │ │ │ │
│ │ - Browser-based UI │ │ - Desktop/Mobile │ │
│ │ - HTMX interactions │ │ - Cross-platform │ │
│ │ - Server-side │ │ - GDScript │ │
│ │ rendering │ │ │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │ │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ │ HTTP/REST │
└──────────────────────────┼─────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ API Backend (Flask) │
│ │
│ Single Source of Truth - All Business Logic │
│ - Authentication (via Appwrite) │
│ - Game logic & mechanics │
│ - Character management │
│ - Combat system │
│ - Marketplace transactions │
│ - Session management │
│ - Data models & validation │
│ - AI orchestration │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Appwrite │ │ Redis + RQ │ │ AI APIs │
│ │ │ │ │ │
│ - Auth │ │ - Job Queue │ │ - Replicate │
│ - Database │ │ - Caching │ │ - Anthropic │
│ - Storage │ │ - Sessions │ │ │
│ - Realtime │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
Component Responsibilities
/api - API Backend (Port 5000)
- Role: Single source of truth, all business logic
- Tech: Flask REST API + Appwrite + RQ + Redis
- Contains: Models, services, game logic, AI integration
- Deployment: Independent with own venv, config, tests
- Location:
/apidirectory
/public_web - Web Frontend (Port 5001)
- Role: Thin UI layer for browsers
- Tech: Flask + Jinja2 + HTMX
- Contains: Views, templates, static assets
- Communication: HTTP requests to API backend
- Deployment: Independent with own venv, config
- Location:
/public_webdirectory
/godot_client - Game Client
- Role: Native cross-platform game client
- Tech: Godot 4.5 + GDScript
- Contains: UI, scenes, client-side logic
- Communication: HTTP requests to API backend
- Deployment: Exports to Desktop/Mobile/Web
- Location:
/godot_clientdirectory
Core Design Principles
- Microservices Architecture: Three independent, deployable components (API, Web, Godot)
- API as Single Source of Truth: All business logic centralized in API backend
- AI-Driven Narrative: Claude models generate story, NPC dialogue, combat descriptions
- Code-Driven Mechanics: All game mechanics (damage, stats, effects) use deterministic formulas (JRPG-style)
- Turn-Based Gameplay: Classic D&D style, not real-time
- Scalable Architecture: Independent services, horizontal scaling ready
- Security First: Developer is cybersecurity senior engineer/director - security is paramount
- Monetization: Tiered subscription model with free tier
Tech Stack
API Backend (/api)
| Component | Technology | Purpose |
|---|---|---|
| Framework | Flask 3.x | REST API framework |
| Authentication | Appwrite Auth | User management, session tokens |
| Database | Appwrite Database | NoSQL document storage |
| Realtime | Appwrite Realtime | WebSocket connections for multiplayer |
| Storage | Appwrite Storage | User assets, logs |
| Job Queue | RQ (Redis Queue) | Async AI calls, background tasks |
| Caching | Redis | Session data, rate limiting |
| AI (Free) | Replicate API | Free tier users (Llama 3 70B) |
| AI (Paid) | Anthropic Claude | Paid tier users (Haiku/Sonnet) |
| Data Models | Dataclasses | Typed domain models |
| Logging | Structlog | Structured logging |
| Testing | Pytest | Unit and integration tests |
| WSGI Server | Gunicorn | Production WSGI server |
Web Frontend (/public_web)
| Component | Technology | Purpose |
|---|---|---|
| Framework | Flask 3.x | Lightweight web server |
| Templates | Jinja2 | Server-side HTML rendering |
| UI Enhancement | HTMX | Dynamic updates without heavy JS |
| Styling | Vanilla CSS | Custom dark theme |
| API Client | Python requests | HTTP calls to API backend |
| Logging | Structlog | Structured logging |
| WSGI Server | Gunicorn | Production WSGI server |
Godot Client (/godot_client)
| Component | Technology | Purpose |
|---|---|---|
| Engine | Godot 4.5 | Cross-platform game engine |
| Language | GDScript | Game logic and UI |
| HTTP Client | HTTPClient singleton | API communication |
| State Management | StateManager singleton | Global game state |
| Fonts | Cinzel + Lato | Display and body fonts |
| Exports | Desktop/Mobile/Web | Multi-platform deployment |
Shared Infrastructure
| Component | Technology | Purpose |
|---|---|---|
| Configuration | YAML files | Environment-specific settings |
| Secrets | .env files | API keys, credentials |
| Deployment | Docker | Containerized services |
| Version Control | Git | Source code management |
AI Model Strategy
Model Selection Philosophy
- Use Anthropic Claude models for all paid tier interactions
- Use Replicate free models only for free tier users
- Model selection is per-call based, determined by context importance and user tier
Model Tiers
| Tier | Provider | Model | Max Tokens | Temperature | Use Cases |
|---|---|---|---|---|---|
| FREE | Replicate | meta-llama-3-70b-instruct | 256 | 0.7 | Free tier users only |
| STANDARD | Anthropic | claude-3-5-haiku-20241022 | 512 | 0.8 | Most interactions (paid) |
| PREMIUM | Anthropic | claude-3-5-sonnet-20241022 | 1024 | 0.9 | Important moments (paid) |
Context-Based Model Selection
| Context | Model Tier | Examples |
|---|---|---|
| Simple acknowledgment | FREE | "You enter the room", "Item picked up" |
| Item description | FREE | Basic item lore |
| NPC dialogue | STANDARD | Merchant conversations, quest givers |
| Combat narrative | STANDARD | Regular combat descriptions |
| Story progression | PREMIUM | Major plot developments |
| Boss encounter | PREMIUM | Epic boss fight narratives |
| Character death | PREMIUM | Dramatic death scenes |
Note: Free tier users always get FREE tier models regardless of context.
Prompt Management
- Use Jinja2 templates for all AI prompts
- Enable easy data injection and maintainability
- Templates stored in
app/ai/prompt_templates.py
Appwrite Collections
users
Handled automatically by Appwrite Auth.
characters
| Field | Type | Description |
|---|---|---|
$id |
String | Unique ID |
userId |
String | Owner user ID |
characterData |
JSON String | Serialized Character dataclass |
created_at |
ISO Timestamp | Creation time |
updated_at |
ISO Timestamp | Last update |
is_active |
Boolean | Active character flag |
game_sessions
| Field | Type | Description |
|---|---|---|
$id |
String | Session ID |
party_member_ids |
Array[String] | Character IDs in party |
config |
Object | Session configuration |
combat_encounter |
JSON String | Current combat or null |
conversation_history |
Array[Object] | Turn-by-turn history |
game_state |
Object | Current location, quests, events |
turn_order |
Array[String] | Character IDs in turn order |
current_turn |
Integer | Index in turn_order |
turn_number |
Integer | Global turn counter |
created_at |
ISO Timestamp | Session start |
last_activity |
ISO Timestamp | Last action |
status |
String | active, completed, timeout |
Session Config Structure:
{
"min_players": 2,
"timeout_minutes": 30,
"auto_save_interval": 5
}
Conversation History Entry:
{
"turn": 1,
"character_id": "char_id_1",
"character_name": "Aragorn",
"action": "I search for traps",
"dm_response": "You notice...",
"combat_log": []
}
marketplace_listings
| Field | Type | Description |
|---|---|---|
$id |
String | Listing ID |
seller_id |
String | User ID |
character_id |
String | Character ID |
item_data |
Object | Full item details |
listing_type |
String | "auction" or "fixed_price" |
price |
Integer | For fixed_price |
starting_bid |
Integer | For auction |
current_bid |
Integer | For auction |
buyout_price |
Integer | Optional instant buy |
bids |
Array[Object] | Bid history |
auction_end |
ISO Timestamp | For auction |
status |
String | active, sold, expired, removed |
created_at |
ISO Timestamp | Listing creation |
transactions
| Field | Type | Description |
|---|---|---|
$id |
String | Transaction ID |
buyer_id |
String | User ID |
seller_id |
String | User ID |
listing_id |
String | Listing ID |
item_data |
Object | Item details |
price |
Integer | Final price |
timestamp |
ISO Timestamp | Transaction time |
transaction_type |
String | marketplace_sale, shop_purchase, etc. |
Project Structure
Repository Root:
/coc
├── api/ # API Backend Component
├── public_web/ # Web Frontend Component
├── godot_client/ # Godot Game Client Component
├── docs/ # Project-wide documentation
├── CLAUDE.md # Development guidelines
└── README.md # Project overview
API Backend (/api)
Single source of truth - All business logic
api/
├── app/
│ ├── __init__.py # Flask app factory
│ ├── config.py # Configuration management
│ ├── models/ # Data models (dataclasses)
│ │ ├── __init__.py
│ │ ├── enums.py # All enum types
│ │ ├── stats.py # Stats dataclass
│ │ ├── effects.py # Effect dataclass
│ │ ├── abilities.py # Ability dataclass
│ │ ├── items.py # Item dataclass
│ │ ├── skills.py # SkillNode, SkillTree, PlayerClass
│ │ ├── origins.py # Origin dataclass
│ │ ├── character.py # Character with get_effective_stats()
│ │ ├── combat.py # Combatant, CombatEncounter
│ │ ├── session.py # GameSession, SessionConfig
│ │ └── marketplace.py # Marketplace models
│ ├── api/ # REST API endpoints
│ │ ├── __init__.py
│ │ ├── health.py # Health check
│ │ ├── auth.py # Authentication endpoints
│ │ ├── characters.py # Character CRUD
│ │ ├── sessions.py # Session management (TODO)
│ │ ├── combat.py # Combat actions (TODO)
│ │ ├── marketplace.py # Marketplace operations (TODO)
│ │ └── shop.py # NPC shop (TODO)
│ ├── game_logic/ # Game mechanics
│ │ ├── __init__.py
│ │ ├── combat_engine.py # Combat calculations (TODO)
│ │ ├── damage_calculator.py # Damage formulas (TODO)
│ │ ├── effect_processor.py # Effect tick processing (TODO)
│ │ ├── skill_manager.py # Skill unlock logic (TODO)
│ │ └── loot_generator.py # Random loot generation (TODO)
│ ├── ai/ # AI integration
│ │ ├── __init__.py
│ │ ├── ai_client.py # Replicate + Anthropic clients (TODO)
│ │ ├── model_selector.py # Model tier selection (TODO)
│ │ ├── prompt_templates.py # Jinja2 prompt templates (TODO)
│ │ └── narrative_generator.py # AI narrative wrapper (TODO)
│ ├── tasks/ # Background jobs (RQ)
│ │ ├── __init__.py
│ │ ├── ai_tasks.py # RQ jobs for AI calls (TODO)
│ │ ├── combat_tasks.py # Async combat processing (TODO)
│ │ └── marketplace_tasks.py # Auction processing (TODO)
│ ├── services/ # Business logic & integrations
│ │ ├── __init__.py
│ │ ├── appwrite_service.py # Appwrite SDK wrapper
│ │ ├── database_service.py # Database operations
│ │ ├── database_init.py # Database initialization
│ │ ├── character_service.py # Character management
│ │ ├── class_loader.py # Load classes from YAML
│ │ └── origin_service.py # Load origins from YAML
│ ├── utils/ # Utilities
│ │ ├── __init__.py
│ │ ├── logging.py # Structlog setup
│ │ ├── response.py # Standardized API responses
│ │ └── auth.py # Auth decorators
│ └── data/ # Game data (YAML)
│ ├── abilities/ # Ability definitions
│ ├── classes/ # Character class definitions
│ ├── items/ # Item definitions (TODO)
│ └── origins.yaml # Origin definitions
├── config/ # Environment configs
│ ├── development.yaml # Dev environment settings
│ └── production.yaml # Production settings
├── tests/ # Pytest test suite
│ ├── __init__.py
│ ├── test_character.py
│ ├── test_stats.py
│ ├── test_effects.py
│ ├── test_combat_simulation.py
│ ├── test_class_loader.py
│ ├── test_origin_service.py
│ ├── test_character_service.py
│ └── test_api_characters_integration.py
├── scripts/ # Utility scripts
│ ├── init_database.py # Database initialization
│ ├── setup.sh # Project setup
│ └── README.md
├── logs/ # Application logs
│ └── app.log
├── docs/ # API documentation
│ ├── API_REFERENCE.md # API endpoint docs
│ ├── API_TESTING.md # API testing guide
│ ├── DATA_MODELS.md # Data model documentation
│ ├── GAME_SYSTEMS.md # Game mechanics docs
│ └── APPWRITE_SETUP.md # Database setup guide
├── requirements.txt # Python dependencies (full stack)
├── wsgi.py # WSGI entry point
├── docker-compose.yml # Redis service
├── .env.example # Environment variable template
└── README.md # API backend README
Web Frontend (/public_web)
Thin UI layer - Makes HTTP requests to API
public_web/
├── app/
│ ├── __init__.py # Flask app factory
│ ├── config.py # Configuration loader
│ ├── views/ # View blueprints (Flask routes)
│ │ ├── __init__.py
│ │ ├── auth_views.py # Auth pages (login, register, etc.)
│ │ └── character_views.py # Character pages
│ ├── services/ # (Stub) API client services
│ │ ├── __init__.py # TODO: Refactor to HTTP client
│ │ ├── character_service.py # Stub (raises NotImplementedError)
│ │ ├── class_loader.py # Stub (raises NotImplementedError)
│ │ └── origin_service.py # Stub (raises NotImplementedError)
│ └── utils/ # Utilities
│ ├── __init__.py
│ ├── logging.py # Structlog setup
│ └── auth.py # Auth helpers (stubs, need refactor)
├── templates/ # Jinja2 HTML templates
│ ├── base.html # Base layout
│ ├── auth/ # Authentication pages
│ │ ├── login.html
│ │ ├── register.html
│ │ ├── forgot_password.html
│ │ ├── reset_password.html
│ │ └── verify_email.html
│ └── character/ # Character pages
│ ├── list.html # Character list
│ ├── detail.html # Character detail
│ ├── create_origin.html # Creation step 1
│ ├── create_class.html # Creation step 2
│ ├── create_customize.html # Creation step 3
│ └── create_confirm.html # Creation step 4
├── static/ # CSS, JS, images
│ └── css/
│ └── main.css # Main stylesheet
├── config/ # Web frontend configs
│ ├── development.yaml # Dev settings (API URL, etc.)
│ └── production.yaml # Production settings
├── logs/ # Application logs
├── docs/ # Frontend documentation
├── requirements.txt # Python dependencies (minimal)
├── wsgi.py # WSGI entry point
├── .env.example # Environment template
└── README.md # Web frontend README
Known Technical Debt:
- Views currently import stub services that raise
NotImplementedError - Need to refactor views to make HTTP requests to API backend
- Auth helpers need to validate sessions via API
- See
/public_web/README.mdfor details
Godot Client (/godot_client)
Native cross-platform game client
godot_client/
├── project.godot # Godot project configuration
├── scenes/ # Godot scene files (.tscn)
│ ├── main.tscn # Entry point
│ ├── auth/ # Authentication scenes
│ │ └── login.tscn
│ ├── character/ # Character scenes
│ ├── combat/ # Combat scenes
│ ├── world/ # World exploration scenes
│ └── components/ # Reusable UI components
├── scripts/ # GDScript code
│ ├── main.gd # Main scene controller
│ ├── services/ # Singleton autoloads
│ │ ├── settings.gd # Settings management
│ │ ├── http_client.gd # HTTP client for API calls
│ │ └── state_manager.gd # Global state management
│ ├── models/ # Data models
│ │ └── api_response.gd # API response wrapper
│ ├── components/ # Component scripts
│ │ ├── form_field.gd # Form input component
│ │ ├── card.gd # Card container
│ │ └── custom_button.gd # Styled button
│ └── utils/ # Helper utilities
│ └── theme_colors.gd # Color constants
├── assets/ # Game assets
│ ├── fonts/ # Cinzel + Lato fonts
│ ├── themes/ # UI theme files
│ └── ui/ # UI assets
├── docs/ # Godot client documentation
│ ├── ARCHITECTURE.md # Client architecture
│ ├── GETTING_STARTED.md # Setup guide
│ ├── EXPORT.md # Export instructions
│ └── THEME_SETUP.md # Theming guide
├── ARCHITECTURE.md # Architecture overview
├── README.md # Setup and usage
└── EXPORT.md # Platform export guide
RQ Job Processing
Job Types
| Queue | Job Function | Purpose |
|---|---|---|
| ai_tasks | generate_dm_response() |
Generate narrative responses |
generate_npc_dialogue() |
NPC conversations | |
narrate_combat_action() |
Combat descriptions | |
| combat_tasks | process_combat_round() |
Execute combat turn |
finalize_combat() |
Handle combat end | |
| marketplace_tasks | process_ended_auctions() |
Periodic auction cleanup |
cleanup_old_session_logs() |
Periodic log cleanup |
Worker Configuration
Start RQ workers:
# Single worker for all queues
rq worker ai_tasks combat_tasks marketplace_tasks --url redis://localhost:6379
# Or separate workers
rq worker ai_tasks --url redis://localhost:6379
rq worker combat_tasks --url redis://localhost:6379
rq worker marketplace_tasks --url redis://localhost:6379
Job Flow
- User takes action in game
- Action queued to RQ with job ID
- API returns 202 Accepted with job ID
- Worker processes job asynchronously
- Worker updates Appwrite document
- Appwrite Realtime notifies all clients
- UI updates automatically
Realtime Synchronization
Use Appwrite Realtime for WebSocket connections:
Frontend subscribes to session updates and receives automatic notifications when game state changes.
Benefits:
- No polling required
- Instant updates for all party members
- Built-in connection management
- Automatic reconnection
Subscription Tiers
| Tier | Price | AI Calls/Day | AI Model | Marketplace | Log Retention | Max Chars | Party Size |
|---|---|---|---|---|---|---|---|
| FREE | $0 | 50 | Replicate | ✗ | 7 days | 1 | Solo |
| BASIC | $4.99 | 200 | Haiku | ✗ | 14 days | 3 | 2 |
| PREMIUM | $9.99 | 1000 | Sonnet | ✓ | 30 days | 10 | 6 |
| ELITE | $19.99 | Unlimited | Sonnet | ✓+ | 90 days | Unlimited | 10 |
ELITE Perks:
- Priority marketplace listings
- Early access to new classes
- Exclusive items
Security Architecture
Authentication & Authorization
- Appwrite Auth handles user authentication
- HTTP-only cookies (
coc_session) for session storage- Prevents XSS attacks (JavaScript cannot access)
- HTTPS only in production (Secure flag)
- SameSite=Lax for CSRF protection
- 24-hour sessions (30 days with "remember me")
- Email verification required before login
- Password reset via email flow
- Auth decorators for protected routes:
@require_auth- Enforce authentication@require_tier(tier)- Enforce minimum subscription tier@require_email_verified- Enforce verified email
- User tier system (Free/Basic/Premium/Elite)
- Session validation on every protected API call
- User ID verification (users can only access their own data)
Input Validation
- Validate all JSON payloads against schemas
- Sanitize user inputs (character names, chat messages)
- Prevent injection attacks
Rate Limiting
- AI endpoint limits based on subscription tier
- Marketplace actions (max listings per day)
- Combat actions (prevent spam/automation)
- Use Flask-Limiter with Redis backend
API Security
- CORS properly configured (only allow frontend domain)
- API keys stored in environment variables
- Appwrite permissions set correctly on all collections
- HTTPS only in production
Cost Control (AI)
- Daily limits on AI calls per tier
- Max tokens per request type
- Cost logging for analytics and alerts
- Graceful degradation if limits exceeded
Data Protection
| Resource | Read Access | Write Access |
|---|---|---|
| Characters | Owner only | Owner only |
| Sessions | Party members | Active player |
| Marketplace | All users | Listing owner |
| Transactions | Buyer + Seller | System only |
Why These Technologies?
Flask over FastAPI
- Team familiarity with Flask
- Async handled by RQ (don't need FastAPI's native async)
- Mature ecosystem for templates (Jinja2)
- Can migrate specific endpoints later if needed
RQ over Celery
- Simpler setup and configuration
- Adequate for current scale
- Easier debugging
- Redis already required for caching
Appwrite
- Reduces infrastructure overhead
- Built-in auth, database, storage, realtime
- Handles scaling of data layer
- Real-time WebSocket support out of box
- Self-hosted option available if needed later
Dataclasses over ORM
- Flexibility in data structure (easy to change)
- No database migration headaches
- JSON storage in Appwrite is schema-flexible
- Easier to serialize/deserialize
- Performance (no ORM overhead)
Turn-Based
- Simpler AI prompt construction
- Better for multiplayer coordination
- Classic D&D feel
- Easier to balance than real-time
- Less server load (no constant state updates)
Microservices Architecture
- Independent Deployment: Each component can be updated/scaled separately
- Technology Flexibility: Can use different tech stacks per component (Flask + Godot)
- Team Scalability: Different teams can work on different components
- Fault Isolation: Failures in one component don't crash entire system
- API as Contract: Clear interface between frontend and backend
Microservices Communication
API-First Design
All frontends communicate with the API backend exclusively via HTTP/REST:
┌─────────────┐
│ Public Web │──┐
└─────────────┘ │
│ HTTP/REST
┌─────────────┐ │ (JSON)
│ Godot Client│──┼──────────► ┌──────────────┐
└─────────────┘ │ │ API Backend │
│ │ (Port 5000) │
│ └──────────────┘
│
Other │
Clients │
(Future) ────┘
Communication Patterns
1. Request/Response (Synchronous)
- Standard CRUD operations
- Character creation, updates
- Authentication
- Data retrieval
Example:
POST /api/v1/characters
{
"name": "Aragorn",
"class_id": "vanguard",
"origin_id": "noble_exile"
}
→ API processes request
→ Returns character data
Response:
{
"app": "Code of Conquest",
"status": 200,
"result": { character_data },
"error": null
}
2. Job Queue (Asynchronous)
- AI narrative generation
- Combat processing
- Long-running operations
Example:
POST /api/v1/sessions/{id}/action
{
"action": "I search the ancient library"
}
→ API queues job to RQ
→ Returns job ID immediately
Response:
{
"status": 202,
"result": {
"job_id": "abc123",
"status": "queued"
}
}
→ Worker processes AI call
→ Updates Appwrite document
→ Appwrite Realtime notifies clients
3. Real-Time (WebSocket via Appwrite)
- Multiplayer session updates
- Combat state changes
- Party member actions
Example:
// Subscribe to session updates
appwrite.subscribe('sessions.{sessionId}', callback);
// When another player acts:
→ Worker updates session in Appwrite
→ Appwrite broadcasts to all subscribers
→ All clients update UI automatically
API Endpoints Structure
/api/v1/
├── health # Health check
├── auth/ # Authentication
│ ├── login
│ ├── register
│ ├── logout
│ └── reset-password
├── characters/ # Character management
│ ├── GET / # List characters
│ ├── POST / # Create character
│ ├── GET /{id} # Get character
│ ├── PUT /{id} # Update character
│ └── DELETE /{id} # Delete character
├── sessions/ # Game sessions (TODO)
│ ├── POST / # Create session
│ ├── GET /{id} # Get session
│ └── POST /{id}/action # Take action
├── combat/ # Combat system (TODO)
│ └── POST /sessions/{id}/combat/action
├── marketplace/ # Marketplace (TODO)
│ ├── GET /listings
│ └── POST /listings
└── shop/ # NPC shop (TODO)
└── GET /items
Frontend Responsibilities
API Backend (/api):
- ✅ All business logic
- ✅ Data validation
- ✅ Database operations
- ✅ Authentication & authorization
- ✅ Game mechanics calculations
- ✅ AI orchestration
Web Frontend (/public_web):
- ❌ No business logic
- ✅ Render HTML templates
- ✅ Form validation (UI only)
- ✅ Make HTTP requests to API
- ✅ Display API responses
- ⚠️ Current: Has stub services (needs refactoring)
Godot Client (/godot_client):
- ❌ No business logic
- ✅ Render game UI
- ✅ Handle user input
- ✅ Make HTTP requests to API
- ✅ Display API responses
- ✅ Client-side animations/effects
Deployment Architecture
Development Environment
┌────────────────────┐
│ Developer Machine │
├────────────────────┤
│ │
│ API Backend │ ← Port 5000
│ (Flask dev server)│
│ │
│ Web Frontend │ ← Port 5001
│ (Flask dev server)│
│ │
│ Godot Editor │ ← F5 to test
│ │
│ Redis (Docker) │ ← Port 6379
│ │
└────────────────────┘
│
│ API calls
▼
┌──────────────┐
│ Appwrite │
│ (Cloud) │
└──────────────┘
Commands:
# Terminal 1: API Backend
cd api
source venv/bin/activate
python wsgi.py # → http://localhost:5000
# Terminal 2: Web Frontend
cd public_web
source venv/bin/activate
python wsgi.py # → http://localhost:5001
# Terminal 3: Redis
cd api
docker-compose up
# Terminal 4: RQ Worker (optional)
cd api
source venv/bin/activate
rq worker ai_tasks --url redis://localhost:6379
# Godot: Open project and press F5
Production Environment
┌──────────────────────────────────────┐
│ Load Balancer / CDN │
└────────────┬─────────────────────────┘
│
┌──────┴──────┐
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Web │ │ Web │ ← Port 8080 (internal)
│ Frontend │ │ Frontend │
│(Gunicorn)│ │(Gunicorn)│
└────┬─────┘ └────┬─────┘
│ │
│ HTTP Requests
└──────┬──────┘
▼
┌──────────┐
│ API │ ← Port 5000 (internal)
│ Backend │
│(Gunicorn)│
└────┬─────┘
│
┌────┴────┬──────────┬──────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌─────┐ ┌────────┐ ┌────────┐
│ Appwrite │ │Redis│ │ RQ │ │ AI │
│ │ │ │ │Workers │ │ APIs │
└──────────┘ └─────┘ └────────┘ └────────┘
Deployment Strategy:
- Each component containerized with Docker
- Independent scaling (more web servers if needed)
- API backend as single deployment (multiple workers via Gunicorn)
- Godot client exported to native apps (distributed separately)
Environment Variables
API Backend:
FLASK_ENV=production
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
APPWRITE_PROJECT_ID=...
APPWRITE_API_KEY=...
APPWRITE_DATABASE_ID=...
ANTHROPIC_API_KEY=...
REPLICATE_API_TOKEN=...
REDIS_URL=redis://redis:6379
SECRET_KEY=...
Web Frontend:
FLASK_ENV=production
SECRET_KEY=...
API_BASE_URL=https://api.codeofconquest.com
Godot Client:
# In settings.gd or environment config
var api_base_url = "https://api.codeofconquest.com"