first commit
This commit is contained in:
464
public_web/CLAUDE.md
Normal file
464
public_web/CLAUDE.md
Normal 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
|
||||
Reference in New Issue
Block a user