# X10 Life RPG
X10 is a self-hosted Life RPG: real-life quests update a character balance, level progress, daily rhythm, history, and a lightweight Phaser world. Version `0.6.0` contains a Rust/SQLite API, a Vue/Vuetify administration SPA, and a separate React game.
## Applications
- Admin SPA: `/` — CRUD operations and operational visibility.
- Life RPG: `/game` — Dashboard, Quest Board, Character, Spheres, History, and Onboarding.
- API documentation: `/docs/` — Scalar UI backed by the generated OpenAPI document.
- API: `/api/v2` — profiles, photos, spheres, quests, executions, balances, levels, dashboard, and day finalizations.
The playable onboarding flow creates a hero, ten starter spheres, 3–7 selected quests, and the first execution. The Dashboard then exposes only quests that the backend marks available for the current cadence period. Cadence periods are anchored to each quest's `starts_on` date and evaluated in the profile's validated IANA timezone.
## Requirements
- Rust toolchain with Cargo
- Node.js 22+ and npm
- Chromium for `make e2e-test` (`/usr/bin/chromium` by default, or set `PLAYWRIGHT_EXECUTABLE_PATH`)
## Quick Start
Generate an Argon2 password hash and start the production-style combined server:
```bash
cargo run --bin hash_admin_password -- admin123
export X10_ADMIN_USERNAME=admin
export X10_ADMIN_PASSWORD_HASH='<argon2 hash>'
export X10_ADMIN_SESSION_SECRET='replace-with-a-random-secret'
make run
```
Open:
- `http://127.0.0.1:3000/` — admin
- `http://127.0.0.1:3000/game` — game
- `http://127.0.0.1:3000/docs/` — API documentation
For game development, start the backend and Vite game server together:
```bash
make game-start
# game: http://127.0.0.1:5173/game/
# backend: http://127.0.0.1:3000/
make game-stop
```
`make game-start` supplies local-only fallback admin credentials when the three required admin variables are absent. `make run` deliberately requires explicit values.
## Architecture
```mermaid
flowchart TD
Browser --> Admin["Vue/Vuetify admin at /"]
Browser --> Game["React Life RPG at /game"]
Browser --> Docs["Scalar at /docs"]
Admin --> AdminApi["/api/admin and /api/v2"]
Game --> GameApi["/api/v2"]
Docs --> GameApi
AdminApi --> App["Rust application service"]
GameApi --> App
App --> Domain["Domain scoring and cadence"]
App --> Repository["Repository abstraction"]
Repository --> SQLite[(SQLite)]
```
- `src/api/` — Axum routes, auth middleware, errors, metrics, OpenAPI, and static delivery.
- `src/application/` — validation, ownership, transactions, cadence scheduling, and progression workflows.
- `src/domain/` — typed models and scoring rules.
- `src/infrastructure/` — SQLite repository and transactional persistence.
- `web/src/` — Vue/Vuetify admin.
- `web/game/src/` — Feature-Sliced React game; TanStack Query owns server state, Zustand owns selected-profile/UI state, and Phaser is visual-only.
## Authentication and Actor Scope
- `/api/admin/auth/login` creates the signed `x10_admin_session` HTTP-only cookie.
- `/api/admin/*` requires a valid admin session except the auth endpoints.
- The game does not require an admin cookie.
- Profile-scoped `/api/v2/*` operations require `X-Actor-Id` matching the target profile. Public profile creation/listing and sphere reads/writes follow the current API contract.
This actor header is an ownership boundary for the current single-user game, not a replacement for production identity authentication.
## Configuration
| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `X10_HOST` | no | `127.0.0.1` | Axum bind address |
| `X10_PORT` | no | `3000` | Combined server port |
| `X10_DATABASE_PATH` | no | `data/x10.sqlite3` | SQLite file |
| `X10_UPLOADS_PATH` | no | `data/uploads` | Profile photo storage |
| `X10_WEB_DIST_PATH` | no | `web/dist` | Built frontend root |
| `X10_ADMIN_USERNAME` | yes for `make run` | none | Admin username |
| `X10_ADMIN_PASSWORD_HASH` | yes for `make run` | none | Argon2 PHC hash |
| `X10_ADMIN_SESSION_SECRET` | yes for `make run` | none | Cookie signing secret |
| `X10_ADMIN_SESSION_SECURE` | no | `false` | Enable the cookie `Secure` attribute |
| `VITE_API_BASE_URL` | no | same origin | Standalone game API origin |
| `VITE_API_PROXY_TARGET` | no | `http://127.0.0.1:3000` | Game dev-server proxy target |
| `PLAYWRIGHT_EXECUTABLE_PATH` | no | `/usr/bin/chromium` | Browser used by E2E |
## Verification and Development Commands
| Command | Purpose |
| --- | --- |
| `make build` | Build both frontends and the Rust backend |
| `make fmt` | Format Rust sources |
| `make format-check` | Verify Rust formatting without rewriting |
| `make lint` | Run Rust Clippy, ESLint/JSX accessibility rules, and game TypeScript checks |
| `make test` | Run admin smoke checks, game Vitest tests, and Rust tests |
| `make game-build` | Clean-install and build the React game |
| `make game-test` | Run game unit and interaction tests |
| `make game-bundle-check` | Build and enforce the 200 KiB gzip initial-JS budget |
| `make e2e-test` | Run API, UI, axe, onboarding, cadence, history, finalization, and Phaser blackbox scenarios on temporary databases |
| `make game-start` / `make game-stop` | Start or stop the local game development stack |
| `make actor-id` | Create a demo profile and print its `X-Actor-Id` |
| `make clean` | Remove Cargo build artifacts |
## Documentation
- [Codex playbook](docs/codex/README.md)
- [Implementation audit](docs/codex/IMPLEMENTATION_AUDIT.md)
- [Progress](docs/codex/PROGRESS.md)
- [API reference](docs/codex/api-reference.md)
- [Roadmap](docs/codex/ROADMAP.md)
- [Playable demo seed](docs/demo-seed.md)
- [Life RPG E2E scenario](docs/life-rpg-test-scenario.md)
- [Phaser scenario](docs/phaser-test-scenario.md)
- [Admin documentation](docs/admin-vuetify/README.md)
- [Changelog](CHANGELOG.md)
查看 README 源文件