184 lines
4.9 KiB
Markdown
184 lines
4.9 KiB
Markdown
# AGENTS.md - Guidelines for Agentic Coding
|
|
|
|
## Project Overview
|
|
|
|
This is a Flask web application - a "Jeopardy-style" quiz game about the Russian short story "Уроки французского" by Valentin Rasputin.
|
|
|
|
**Tech Stack:**
|
|
- Backend: Python 3.13 with Flask
|
|
- Frontend: HTML, CSS, JavaScript (vanilla)
|
|
- Data Storage: JSON file (`data/questions.json`)
|
|
- State: Browser localStorage (client-side)
|
|
- Container: Docker
|
|
|
|
## Build/Test Commands
|
|
|
|
### Running Locally (without Docker)
|
|
|
|
```bash
|
|
# Activate virtual environment
|
|
source venv/bin/activate
|
|
|
|
# Run Flask app (default port 5000)
|
|
python src/app.py
|
|
|
|
# Run on specific port
|
|
python -c "from src.app import app; app.run(port=5002)"
|
|
```
|
|
|
|
### Running with Docker
|
|
|
|
```bash
|
|
# Build image
|
|
./build.sh
|
|
|
|
# Run container
|
|
./run.sh
|
|
|
|
# Stop container
|
|
docker stop sigra && docker rm sigra
|
|
```
|
|
|
|
**Note:** Dockerfile copies only `src/` directory into the container (app.py, data/, templates/, static/).
|
|
|
|
### Manual Testing
|
|
|
|
This project does not have a formal test suite. For manual testing:
|
|
- Use `curl` to test API endpoints
|
|
- Test in browser at http://localhost:5000
|
|
|
|
## Code Style Guidelines
|
|
|
|
### Python (app.py)
|
|
|
|
**Imports** - Standard library first, then third-party:
|
|
```python
|
|
import json
|
|
from flask import Flask, render_template, request, redirect, url_for, make_response
|
|
```
|
|
|
|
**Formatting**
|
|
- Use 4 spaces for indentation
|
|
- Maximum line length: 100 characters
|
|
- Blank lines: 2 between top-level definitions, 1 between function definitions
|
|
|
|
**Naming Conventions**
|
|
- `snake_case` for variables, functions
|
|
- `PascalCase` for classes
|
|
- `UPPER_SNAKE_CASE` for constants
|
|
|
|
**Error Handling**
|
|
- Use try/except for file operations (JSON loading/saving)
|
|
- Return proper HTTP error codes (400, 404, 500)
|
|
- Log errors to console
|
|
|
|
**Flask-Specific**
|
|
- Use `app.secret_key` for sessions
|
|
- Always use `ensure_ascii=False` with JSON for Cyrillic support
|
|
- Use `context_processor` for global template variables
|
|
|
|
### JavaScript (templates/*.html)
|
|
|
|
**General**
|
|
- Use vanilla JavaScript (no frameworks)
|
|
- Prefer `var` over `let/const` for compatibility
|
|
- Use `function` keyword instead of arrow functions
|
|
|
|
**Event Handling**
|
|
- Use `onclick` directly in HTML or `element.onclick = function()`
|
|
- Avoid `addEventListener` for simplicity
|
|
|
|
**DOM Manipulation**
|
|
- Use `document.getElementById` and `document.querySelector`
|
|
- Template literals for dynamic content
|
|
- Use `JSON.parse()` and `JSON.stringify()` for localStorage
|
|
|
|
**Naming** - camelCase for variables and functions
|
|
|
|
### HTML/CSS (templates/*.html)
|
|
|
|
**Template Syntax (Jinja2)**
|
|
- Use `{% for %}` loops with `enumerate()` for indexed iteration
|
|
- Pass data via `{{ variable }}` syntax
|
|
- Use `|tojson` filter for JavaScript data
|
|
|
|
**CSS**
|
|
- Use CSS custom properties (variables) for colors
|
|
- Follow BEM-like naming for classes
|
|
- Keep responsive design in mind
|
|
|
|
**Structure**
|
|
- Inline CSS in `<style>` tags
|
|
- Inline JS in `<script>` tags at end of body
|
|
|
|
## File Organization
|
|
|
|
```
|
|
/home/eof/dev/roma/sigra/
|
|
├── Dockerfile # Docker image definition
|
|
├── build.sh # Build script
|
|
├── run.sh # Run script
|
|
├── .dockerignore # Docker ignore
|
|
├── src/ # Application source (copied to container)
|
|
│ ├── app.py # Flask application
|
|
│ ├── data/
|
|
│ │ └── questions.json # Game questions
|
|
│ ├── templates/ # Jinja2 templates
|
|
│ └── static/ # Static assets
|
|
├── helm/ # Kubernetes Helm chart
|
|
├── venv/ # Virtual environment
|
|
├── SPEC.md # Project specification
|
|
├── AGENTS.md # This file
|
|
└── .gitignore # Git ignore rules
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Adding a New Question
|
|
1. Edit `data/questions.json` manually or via admin panel at `/admin`
|
|
2. Structure:
|
|
```json
|
|
{
|
|
"cost": 600,
|
|
"question": "Question text?",
|
|
"options": ["Option 1", "Option 2", "Option 3", "Option 4"],
|
|
"answer": 0
|
|
}
|
|
```
|
|
|
|
### Adding a New Route
|
|
1. Add route in `app.py` using `@app.route()`
|
|
2. Return `render_template()` or `jsonify()`
|
|
|
|
### Game State (localStorage)
|
|
- Key: `francuzskiy_game`
|
|
- Structure: `{ score: 0, answered: [], userAnswers: {}, teams: [] }`
|
|
- `answered`: array of "cat_q" keys (e.g., ["0_0", "1_2"])
|
|
- `userAnswers`: object with keys and `{team, answer}` values
|
|
|
|
### Multi-team Support
|
|
- Teams: 1-3 teams supported
|
|
- Questions: 30 (always, regardless of team count)
|
|
- Auto-switch to next team after answering
|
|
|
|
## Security Notes
|
|
|
|
- Admin panel password: stored in `app.py` (`ADMIN_PASSWORD`)
|
|
- No database - data in JSON file
|
|
- No SQL injection risk
|
|
- XSS: user input in questions is trusted (admin-only)
|
|
|
|
## Dependencies
|
|
|
|
```
|
|
Flask==3.1.3
|
|
Jinja2==3.1.6
|
|
Werkzeug==3.1.6
|
|
```
|
|
|
|
## Git Conventions
|
|
|
|
- Do NOT commit without explicit user request
|
|
- Run lint/typecheck before committing if available
|
|
- Keep commits focused and descriptive
|