922 lines
35 KiB
Markdown
922 lines
35 KiB
Markdown
# 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:** `/api` directory
|
|
|
|
**`/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_web` directory
|
|
|
|
**`/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_client` directory
|
|
|
|
---
|
|
|
|
## Core Design Principles
|
|
|
|
1. **Microservices Architecture:** Three independent, deployable components (API, Web, Godot)
|
|
2. **API as Single Source of Truth:** All business logic centralized in API backend
|
|
3. **AI-Driven Narrative:** Claude models generate story, NPC dialogue, combat descriptions
|
|
4. **Code-Driven Mechanics:** All game mechanics (damage, stats, effects) use deterministic formulas (JRPG-style)
|
|
5. **Turn-Based Gameplay:** Classic D&D style, not real-time
|
|
6. **Scalable Architecture:** Independent services, horizontal scaling ready
|
|
7. **Security First:** Developer is cybersecurity senior engineer/director - security is paramount
|
|
8. **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:**
|
|
```json
|
|
{
|
|
"min_players": 2,
|
|
"timeout_minutes": 30,
|
|
"auto_save_interval": 5
|
|
}
|
|
```
|
|
|
|
**Conversation History Entry:**
|
|
```json
|
|
{
|
|
"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.md` for 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:**
|
|
```bash
|
|
# 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
|
|
|
|
1. User takes action in game
|
|
2. Action queued to RQ with job ID
|
|
3. API returns 202 Accepted with job ID
|
|
4. Worker processes job asynchronously
|
|
5. Worker updates Appwrite document
|
|
6. Appwrite Realtime notifies all clients
|
|
7. 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:**
|
|
```javascript
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
```gdscript
|
|
# In settings.gd or environment config
|
|
var api_base_url = "https://api.codeofconquest.com"
|
|
```
|