first commit

This commit is contained in:
2025-11-24 23:10:55 -06:00
commit 8315fa51c9
279 changed files with 74600 additions and 0 deletions

464
public_web/CLAUDE.md Normal file
View File

@@ -0,0 +1,464 @@
# CLAUDE.md - Public Web Frontend
## Service Overview
**Public Web Frontend** for Code of Conquest - Browser-based UI using Flask + Jinja2 + HTMX.
**Tech Stack:** Flask + Jinja2 + HTMX + Vanilla CSS
**Port:** 5001 (development), 8080 (production)
**Location:** `/public_web`
---
## Architecture Role
This web frontend is a **thin UI layer** that makes HTTP requests to the API backend:
- ✅ Render HTML templates (Jinja2)
- ✅ Form validation (UI only)
- ✅ Make HTTP requests to API backend
- ✅ Display API responses
- ✅ Handle user input
**What this service does NOT do:**
- ❌ No business logic (all in `/api`)
- ❌ No direct database access (use API)
- ❌ No direct Appwrite calls (use API)
- ❌ No game mechanics calculations (use API)
**Communication:**
```
User Browser → Public Web (views) → HTTP Request → API Backend
↑ ↓
←─────────── HTTP Response ─────────┘
```
---
## Documentation Index
**Web Frontend Documentation:**
- **[README.md](README.md)** - Setup and usage guide
- **[docs/TEMPLATES.md](docs/TEMPLATES.md)** - Template structure and conventions
- **[docs/HTMX_PATTERNS.md](docs/HTMX_PATTERNS.md)** - HTMX integration patterns
- **[docs/TESTING.md](docs/TESTING.md)** - Manual testing guide
- **[docs/MULTIPLAYER.md](docs/MULTIPLAYER.md)** - Multiplayer UI implementation
**Project-Wide Documentation:**
- **[../docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md)** - System architecture overview
- **[../api/docs/API_REFERENCE.md](../api/docs/API_REFERENCE.md)** - API endpoints to call
- **[../docs/DEPLOYMENT.md](../docs/DEPLOYMENT.md)** - Deployment guide
- **[../docs/WEB_VS_CLIENT_SYSTEMS.md](../docs/WEB_VS_CLIENT_SYSTEMS.md)** - Feature distribution between frontends
**Documentation Guidelines:**
- ✅ Place all public_web service documentation in `/public_web/docs/`
- ✅ Each microservice maintains its own documentation
- ❌ Do NOT add public_web-specific docs to `/docs/` (main repo docs are for cross-service architecture only)
---
## Development Guidelines
### Project Structure
```
public_web/
├── app/ # Application code
│ ├── views/ # View blueprints (Flask routes)
│ └── utils/ # Utilities (logging, auth helpers, API client)
├── templates/ # Jinja2 HTML templates
│ ├── auth/ # Authentication pages
│ ├── character/ # Character pages
│ ├── errors/ # Error pages (404, 500)
│ └── base.html # Base template
├── static/ # CSS, JS, images
│ └── css/ # Stylesheets
├── docs/ # Service-specific documentation
├── config/ # Configuration files
└── README.md # Setup and usage guide
```
### Coding Standards
**Style & Structure**
- Prefer longer, explicit code over compact one-liners
- Always include docstrings for functions/classes + inline comments
- Strong typing for view functions (type hints)
- Keep views simple (delegate to API)
**Templates & UI**
- Don't mix large HTML/CSS blocks in Python code
- Use Jinja2 templates for all HTML rendering
- Clean CSS, minimal inline styles
- Readable template logic (avoid complex Python in templates)
- Use HTMX for dynamic interactions
**Logging**
- Use structlog (pip package)
- Setup logging at app start: `logger = structlog.get_logger(__file__)`
**Preferred Pip Packages**
- Web Server: Flask
- Templates: Jinja2
- HTTP Client: Requests
- Logging: Structlog
### View Development Standards
**View Functions (Flask Routes):**
```python
from flask import Blueprint, render_template, request, redirect, url_for
import requests
from app.config import load_config
character_bp = Blueprint('character', __name__, url_prefix='/characters')
@character_bp.route('/')
def list_characters():
"""
Display list of user's characters.
Makes HTTP request to API backend to fetch character data.
"""
config = load_config()
# Make API request
response = requests.get(
f"{config.api.base_url}/api/v1/characters",
timeout=config.api.timeout
)
if response.status_code == 200:
data = response.json()
characters = data.get('result', [])
return render_template('character/list.html', characters=characters)
else:
# Handle error
return render_template('error.html', message="Failed to load characters"), 500
```
**DO:**
- ✅ Make HTTP requests to API backend
- ✅ Pass data to templates
- ✅ Handle errors gracefully
- ✅ Validate form inputs (UI validation only)
- ✅ Redirect to appropriate pages
- ✅ Use flash messages for user feedback
**DON'T:**
- ❌ No business logic in views
- ❌ No direct database access
- ❌ No game mechanics calculations
- ❌ No complex data transformations (keep it simple)
### Template Best Practices
**Base Template (`templates/base.html`):**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Code of Conquest{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head>
<body>
<header>
{% include 'components/navbar.html' %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% include 'components/footer.html' %}
</footer>
</body>
</html>
```
**Child Template:**
```html
{% extends "base.html" %}
{% block title %}Characters - Code of Conquest{% endblock %}
{% block content %}
<div class="container">
<h1>Your Characters</h1>
{% for character in characters %}
<div class="character-card">
<h2>{{ character.name }}</h2>
<p>{{ character.class_name }} - Level {{ character.level }}</p>
</div>
{% endfor %}
</div>
{% endblock %}
```
**HTMX Usage:**
```html
<!-- Form with HTMX -->
<form hx-post="/api/v1/characters"
hx-target="#character-list"
hx-swap="beforeend">
<input type="text" name="name" placeholder="Character name">
<button type="submit">Create</button>
</form>
<!-- Result container -->
<div id="character-list"></div>
```
### CSS Standards
**Organization:**
- Use BEM naming convention (Block Element Modifier)
- Group related styles together
- Use CSS variables for colors/spacing
- Mobile-first responsive design
**Example:**
```css
:root {
--color-primary: #8b5cf6;
--color-bg: #1a1a1a;
--color-text: #e5e7eb;
--spacing-unit: 1rem;
}
.character-card {
background: var(--color-bg);
color: var(--color-text);
padding: calc(var(--spacing-unit) * 2);
border-radius: 8px;
}
.character-card__title {
font-size: 1.5rem;
margin-bottom: var(--spacing-unit);
}
.character-card--highlighted {
border: 2px solid var(--color-primary);
}
```
### Configuration
- Environment-specific configs in `/config/*.yaml`
- `development.yaml` - Local dev settings (API URL: http://localhost:5000)
- `production.yaml` - Production settings (API URL from env var)
- `.env` for secrets (never committed)
- Typed config loaders using dataclasses
**Configuration Structure:**
```yaml
# config/development.yaml
api:
base_url: "http://localhost:5000"
timeout: 30
verify_ssl: false
server:
host: "0.0.0.0"
port: 5001
workers: 1
session:
lifetime_hours: 24
cookie_secure: false
cookie_httponly: true
```
### Error Handling
**View Error Handling:**
```python
@character_bp.route('/<character_id>')
def character_detail(character_id):
"""Display character details."""
config = load_config()
try:
response = requests.get(
f"{config.api.base_url}/api/v1/characters/{character_id}",
timeout=config.api.timeout
)
response.raise_for_status()
data = response.json()
character = data.get('result')
return render_template('character/detail.html', character=character)
except requests.exceptions.Timeout:
logger.error("API timeout", character_id=character_id)
return render_template('error.html', message="Request timed out"), 504
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return render_template('error.html', message="Character not found"), 404
logger.error("API error", status=e.response.status_code)
return render_template('error.html', message="An error occurred"), 500
except Exception as e:
logger.exception("Unexpected error", character_id=character_id)
return render_template('error.html', message="An unexpected error occurred"), 500
```
### Dependency Management
- Use `requirements.txt` in `/public_web` directory
- Minimal dependencies (Flask, Jinja2, requests, structlog)
- Use virtual environment: `python3 -m venv venv`
- Activate venv before running: `source venv/bin/activate`
### Testing Standards
**Manual Testing:**
- Use the checklist in README.md
- Test all user flows:
- [ ] Login flow
- [ ] Registration flow
- [ ] Character creation wizard (all 4 steps)
- [ ] Character list and detail views
- [ ] Logout
- [ ] Error handling
**Browser Testing:**
- Test in Chrome, Firefox, Safari
- Test mobile responsive design
- Test HTMX interactions
---
## Architecture Status
**COMPLETE:** All views use the `APIClient` class for HTTP requests to the API backend.
**What's Implemented:**
- All views use `get_api_client()` from `app/utils/api_client.py`
- Typed error handling with `APIError`, `APINotFoundError`, `APITimeoutError`, `APIAuthenticationError`
- Session cookie forwarding for authentication
- Proper JSON serialization/deserialization
**Minor Improvements (Optional):**
- Auth decorator could re-validate expired API sessions
- Origin/class validation could use single-item lookups instead of fetching full lists
---
## Workflow for Web Frontend Development
When implementing new pages:
1. **Design the page** - Sketch layout, user flow
2. **Create template** - Add Jinja2 template in `/templates`
3. **Create view** - Add Flask route in `/app/views`
4. **Make API calls** - Use requests library to call API backend
5. **Handle errors** - Graceful error handling with user feedback
6. **Add styles** - Update CSS in `/static/css`
7. **Test manually** - Check all user flows
**Example Flow:**
```bash
# 1. Create template
# templates/quest/list.html
# 2. Create view
# app/views/quest_views.py
@quest_bp.route('/')
def list_quests():
# Make API request
response = requests.get(f"{api_url}/api/v1/quests")
quests = response.json()['result']
return render_template('quest/list.html', quests=quests)
# 3. Register blueprint
# app/__init__.py
from .views.quest_views import quest_bp
app.register_blueprint(quest_bp)
# 4. Add styles
# static/css/quest.css
# 5. Test in browser
# http://localhost:5001/quests
```
---
## Running the Web Frontend
### Development
**Prerequisites:**
- Python 3.11+
- API backend running at http://localhost:5000
**Setup:**
```bash
cd public_web
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env with your settings
```
**Run Development Server:**
```bash
source venv/bin/activate
export FLASK_ENV=development
python wsgi.py # → http://localhost:5001
```
### Production
**Run with Gunicorn:**
```bash
gunicorn --bind 0.0.0.0:8080 --workers 4 wsgi:app
```
**Environment Variables:**
```
FLASK_ENV=production
SECRET_KEY=...
API_BASE_URL=https://api.codeofconquest.com
```
---
## Git Standards
**Commit Messages:**
- Use conventional commit format: `feat:`, `fix:`, `docs:`, `style:`, etc.
- Examples:
- `feat(web): add quest list page`
- `fix(views): handle API timeout errors`
- `style(css): improve character card layout`
**Branch Strategy:**
- Branch off `dev` for features
- Merge back to `dev` for testing
- Promote to `master` for production
---
## Notes for Claude Code
When working on the web frontend:
1. **Thin client only** - No business logic, just UI
2. **Always call API** - Use HTTP requests for all data operations
3. **Handle errors gracefully** - Show user-friendly error messages
4. **Keep templates clean** - Avoid complex logic in Jinja2
5. **Mobile responsive** - Design for all screen sizes
6. **HTMX for interactivity** - Use HTMX instead of heavy JavaScript
7. **Document refactoring needs** - Note any technical debt you encounter
**Remember:**
- This is a thin client - all logic lives in the API backend
- The API serves multiple frontends (this web UI and Godot client)
- Security validation happens in the API, but do basic UI validation for UX
- Keep it simple - complicated logic belongs in the API