new DRAMA & BILLBOARD apps to start provenance system; new billboard.html & _scroll.html templates; admin area now displays game event log; new CLAUDE.md file to free up Claude Code's memory.md space; minor additions to apps.epic.views to ensure new systems just described adhere to existing game views
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
104
CLAUDE.md
Normal file
104
CLAUDE.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# EarthmanRPG — Project Context
|
||||
|
||||
Originally built following Harry Percival's *Test-Driven Development with Python* (3rd ed., complete through ch. 25). Now an ongoing game app — EarthmanRPG — extended well beyond the book.
|
||||
|
||||
## Browser Integration
|
||||
**Claudezilla** is installed — a Firefox extension + native host that lets Claude observe and interact with the browser directly. Use `mcp__claudezilla__*` tools to inspect the dev/staging server in Firefox (screenshots, console logs, DOM queries, navigation). Native host: `E:\ClaudeLibrary\claudezilla\host\`. Extension: `claudezilla@boot.industries`.
|
||||
|
||||
## Stack
|
||||
- **Python 3.13 / Django 6.0 / Django Channels** (ASGI via Daphne/uvicorn)
|
||||
- **Celery + Redis** (async email, channel layer)
|
||||
- **django-compressor + SCSS** (`src/static_src/scss/core.scss`)
|
||||
- **Selenium** (functional tests) + Django test framework (integration/unit tests)
|
||||
- **Stripe** (payment, sandbox only so far)
|
||||
- **Hosting:** DigitalOcean staging (`staging.earthmanrpg.me`) | CI: Gitea + Woodpecker
|
||||
|
||||
## Project Layout
|
||||
|
||||
The app pairs follow a tripartite structure:
|
||||
- **1st-person** (personal UX): `lyric` (backend — auth, user, tokens) · `dashboard` (frontend — notes, applets, wallet UI)
|
||||
- **3rd-person** (game table UX): `epic` (backend — rooms, gates, role select, game logic) · `gameboard` (frontend — room listing, gameboard UI)
|
||||
- **2nd-person** (inter-player events): `drama` (backend — activity streams, provenance) · `billboard` (frontend — provenance feed, embeddable in dashboard/gameboard)
|
||||
|
||||
```
|
||||
src/
|
||||
apps/
|
||||
lyric/ # auth (magic-link email), user model, token economy
|
||||
dashboard/ # Notes (formerly Lists), applets, wallet UI [1st-person frontend]
|
||||
epic/ # rooms, gates, role select, game logic [3rd-person backend]
|
||||
gameboard/ # room listing, gameboard UI [3rd-person frontend]
|
||||
drama/ # activity streams, provenance system [2nd-person backend]
|
||||
billboard/ # provenance feed, embeds in dashboard/gameboard [2nd-person frontend]
|
||||
api/ # REST API
|
||||
applets/ # Applet model + context helpers
|
||||
core/ # settings, urls, asgi, runner
|
||||
static_src/ # SCSS source
|
||||
templates/
|
||||
functional_tests/
|
||||
```
|
||||
|
||||
## Dev Commands
|
||||
```bash
|
||||
# Dev server (ASGI — required for WebSockets; no npm/webpack build step)
|
||||
cd src
|
||||
uvicorn core.asgi:application --host 0.0.0.0 --port 8000 --reload --app-dir src
|
||||
|
||||
# Integration + unit tests only (from project root — targets src/apps, skips src/functional_tests)
|
||||
python src/manage.py test src/apps
|
||||
|
||||
# Functional tests only
|
||||
python src/manage.py test src/functional_tests
|
||||
|
||||
# All tests (integration + unit + FT)
|
||||
python src/manage.py test src
|
||||
```
|
||||
|
||||
**Test tags:** The only tag in use is `channels` — for async consumer tests that require a live Redis channel layer.
|
||||
- Exclude channels tests: `python src/manage.py test src/apps --exclude-tag=channels`
|
||||
- Channels tests only: `python src/manage.py test src/apps --tag=channels`
|
||||
|
||||
FTs are isolated by **directory path** (`src/functional_tests/`), not by tag.
|
||||
|
||||
Test runner is `core.runner.RobustCompressorTestRunner` — handles the Windows compressor PermissionError by deleting stale CACHE at startup + monkey-patching retry logic.
|
||||
|
||||
## CI/CD
|
||||
- Git remote: `git@gitea:discoman/python-tdd.git` (port 222, key `~/.ssh/gitea_keys/id_ed25519_python-tdd`)
|
||||
- Gitea: `https://gitea.earthmanrpg.me` | Woodpecker CI: `https://ci.earthmanrpg.me`
|
||||
- Push to `main` triggers Woodpecker → deploys to staging
|
||||
|
||||
## SCSS Import Order
|
||||
`core.scss`: `rootvars → applets → base → button-pad → dashboard → gameboard → room → palette-picker → wallet-tokens`
|
||||
|
||||
## Critical Gotchas
|
||||
|
||||
### TransactionTestCase flushes migration data
|
||||
FTs use `TransactionTestCase` which flushes migration-seeded rows. Any IT/FT `setUp` that needs `Applet` rows must call `Applet.objects.get_or_create(slug=..., defaults={...})` — never rely on migration data surviving.
|
||||
|
||||
### Static files in tests
|
||||
`StaticLiveServerTestCase` serves via `STATICFILES_FINDERS` only — NOT from `STATIC_ROOT`. JS/CSS that lives only in `src/static/` (STATIC_ROOT, gitignored) is a silent 404 in CI. All app JS must live in `src/apps/<app>/static/` or `src/static_src/`.
|
||||
|
||||
### msgpack integer key bug (Django Channels)
|
||||
`channels_redis` uses msgpack with `strict_map_key=True` — integer dict keys in `group_send` payloads raise `ValueError` and crash consumers. Always use `str(slot_number)` as dict keys.
|
||||
|
||||
### Multi-browser FTs in CI
|
||||
Any FT opening a second browser must pass `FirefoxOptions` with `--headless` when `HEADLESS` env var is set. Bare `webdriver.Firefox()` crashes in headless CI with `Process unexpectedly closed with status 1`.
|
||||
|
||||
### Selenium + CSS text-transform
|
||||
Selenium `.text` returns visually rendered text. CSS `text-transform: uppercase` causes `assertIn("Test Room", body.text)` to fail. Assert against the uppercased string or use `body.text.upper()`.
|
||||
|
||||
### Tooltip portal pattern
|
||||
`mask-image` on grid containers clips `position: absolute` tooltips. Use `#id_tooltip_portal` (`position: fixed; z-index: 9999`) at page root. See `gameboard.js` + `wallet.js`.
|
||||
|
||||
### Applet menus + container-type
|
||||
`container-type: inline-size` creates a containing block for all positioned descendants — applet menus must live OUTSIDE `#id_applets_container` to be viewport-fixed.
|
||||
|
||||
### ABU session auth
|
||||
`create_pre_authenticated_session` must set `HASH_SESSION_KEY = user.get_session_auth_hash()` and hardcode `BACKEND_SESSION_KEY` to the passwordless backend string.
|
||||
|
||||
### Magic login email mock paths
|
||||
- View tests: `apps.lyric.views.send_login_email_task.delay`
|
||||
- Task unit tests: `apps.lyric.tasks.requests.post`
|
||||
- FTs: mock both with `side_effect=send_login_email_task`
|
||||
|
||||
## Teaching Style
|
||||
User prefers guided learning: describe what to type and why, let them write the code, then review together. But for now, given user's accelerated timetable, please respond with complete code snippets for user to transcribe directly.
|
||||
Reference in New Issue
Block a user