- Adds Character model with survival needs (hunger, thirst, energy) and state machine - Implements city:tick world ticker for offline progression every minute - Adds city territory expansion and building construction system - Introduces job economy, inventory, and transaction audit trail - Adds social graph (friends, marriage, children) and character chat - Implements admin approval workflow for new registrations - Adds hospital admission system for traffic accidents - Includes comprehensive feature tests and world seeders
8.8 KiB
Cidadãos Persistentes — Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Each admin-approved user gets a persistent human-like character (needs, jobs, housing, family, chat) in a multi-city world that progresses via an always-on scheduler without requiring anyone online.
Architecture: Laravel 13 + MariaDB hold all character/world state. city:tick (every minute) applies need decay, salaries, building progress and simple offline AI. The existing Three.js viewer becomes a client for the caller's character (throttled position sync) plus action HUD/UI. Admin manages citizen approval, territory expansion and new cities.
Tech Stack: Laravel 13, PHP 8.3+, MariaDB, Sanctum (existing), Three.js viewer (existing), PHPUnit, Playwright MCP. No new production dependencies.
Spec: docs/superpowers/specs/2026-10-18-citizens-persistence-design.md
Global Constraints
- PHP 8.3+; follow existing conventions (Form Requests,
#[Fillable], English PHPDoc, Pint). - All user-visible strings in
lang/pt_BR.json,lang/en.json,lang/es.json. - LGPD protections, CAPTCHA, CSRF unchanged; no secrets in repo.
php artisan testandvendor/bin/pint --testmust pass before considering a task done.- Registration must leave users
pendinguntil admin approval. - World must progress with zero users online (
city:tick+schedule:run). - Character death is not simulated; needs floor at 0 with energy penalties only.
Review Focus
- Unapproved login: user with
status=pendingmust not enter dashboard/city; expect friendly wait screen + logout. - Tick idempotency: running
city:ticktwice in one minute must not double-decay needs or double-pay salary (guard bylast_tick_at). - Ownership: actions (eat/build/sleep/position) must reject another user's character ID (403/422).
- Build occupancy: two characters must not complete houses on the same footprint (unique site check by AABB).
- City bounds: movement and building must clamp/fail outside active city bounds; new city layout must derive from
cities.bounds, not only store positions. - Family graph: spouse requires accepted friendship; child requires both spouses; child NPC has
user_id=nulland never logs in. - Migration safety: existing
is_activeusers becomeactiveand can still log in after thestatuscolumn ships.
Task 1: Schema + seeders (cities, characters, buildings, relationships, inventory, transactions, jobs, messages)
Files:
- Create:
database/migrations/2026_10_18_000100_add_status_to_users_table.php - Create:
database/migrations/2026_10_18_000200_create_cities_table.php - Create:
database/migrations/2026_10_18_000300_create_characters_table.php - Create:
database/migrations/2026_10_18_000400_create_buildings_table.php - Create:
database/migrations/2026_10_18_000500_create_relationships_table.php - Create:
database/migrations/2026_10_18_000600_create_inventory_items_table.php - Create:
database/migrations/2026_10_18_000700_create_transactions_table.php - Create:
database/migrations/2026_10_18_000800_create_jobs_table.php - Create:
database/migrations/2026_10_18_000900_create_character_messages_table.php - Create:
app/Models/City.php,Character.php,Building.php,Relationship.php,InventoryItem.php,Transaction.php,Job.php,CharacterMessage.php - Create:
database/factories/CharacterFactory.php,CityFactory.php - Create:
database/seeders/CityWorldSeeder.php(City10 + jobs; backfill users status; ensure characters for active users) - Modify:
database/seeders/DatabaseSeeder.php(register seeder) - Modify:
app/Models/User.php(status const/cast/relation)
Steps:
- Write migrations/models/factories/seeder per spec §3
php artisan migratein container- Feature test: seeder creates City10 + character for active user;
users.statusbackfilled - Run
php artisan test --filter=CityWorldand Pint - Commit
Task 2: Registration pending + admin citizens approval
Files:
- Create:
app/Http/Controllers/Web/Admin/CitizenAdminController.php - Create:
resources/views/admin/citizens/index.blade.php - Create:
app/Http/Requests/...if needed - Modify:
app/Http/Controllers/Web/AuthController.php(register → pending; login branch for pending) - Create:
resources/views/auth/pending.blade.php - Modify:
routes/web.php(admin citizens routes; pending view route or inline response) - Modify:
app/Http/Middleware/EnsureUserIsActive.phpif needed - Modify: lang files (pending/approve/ban strings)
- Modify:
resources/views/dashboardor layout nav (Admin → Cidadãos link)
Steps:
- Failing tests: register creates pending; login as pending redirects to wait screen; admin approve activates + creates character; banned cannot login
- Implement controller/views/routes
php artisan test --filter=Citizengreen + Pint- Commit
Task 3: World ticker city:tick + schedule
Files:
- Create:
app/Console/Commands/CityTick.php - Modify:
routes/console.php(everyMinute) - Create:
tests/Feature/CityTickTest.php
Steps:
- Failing test: needs decay once per call; second immediate call no-ops; sleep recovers energy; work pays; building progress completes at 100
- Implement command + offline AI rules (spec §4)
- Tests green + Pint;
php artisan schedule:listshows entry - Commit
Task 4: City data payload + layout from bounds + character position sync
Files:
- Modify:
app/Http/Controllers/Web/CityViewerController.php(city param, characters/buildings/jobs/bounds; layout from city bounds) - Modify:
app/Http/Controllers/Api/...if mirrored - Create:
app/Http/Controllers/Web/CityActionController.php(position + actions stubs for this task: position only) - Modify:
routes/web.php - Create:
tests/Feature/CityDataTest.php,CityPositionTest.php
Steps:
- Failing tests:
/city/dataincludes own character + bounds; layout covers full bounds; position POST persists and clamps to bounds; cannot set another character - Implement
- Tests green + Pint
- Commit
Task 5: Actions API (eat/drink/sleep/wake/work/study/buy/sell/build)
Files:
- Modify:
app/Http/Controllers/Web/CityActionController.php - Create: Form Requests under
app/Http/Requests/ - Create:
tests/Feature/CityActionsTest.php - Modify: lang files (action labels/errors)
Steps:
- Failing tests per action happy path + key rejects (no house, no job, no money, occupied site, insufficient materials)
- Implement actions with DB transactions where money/inventory move
- Tests green + Pint
- Commit
Task 6: Social (friends, spouse, child, character chat)
Files:
- Modify:
app/Http/Controllers/Web/CitySocialController.php(create) - Create:
app/Http/Controllers/Web/CharacterChatController.phpor extendChatController - Create:
tests/Feature/CitySocialTest.php - Modify: lang files
Steps:
- Failing tests: friend request/accept; marry requires accepted friend + no existing spouse; child creates NPC character with parent links; message POST persists and is readable by recipient
- Implement
- Tests green + Pint
- Commit
Task 7: Admin territory expand + multi-city
Files:
- Create:
app/Http/Controllers/Web/Admin/CityAdminController.php - Create:
resources/views/admin/cities/*(index + create + expand form) - Modify:
routes/web.php - Create:
tests/Feature/CityExpansionTest.php - Modify: lang files
Steps:
- Failing tests: create city; expand bounds +40 up to cap; layout for new city uses its bounds
- Implement
- Tests green + Pint
- Commit
Task 8: Viewer frontend — own character, HUD needs, action menu, citizens, buildings
Files:
- Modify:
resources/views/city/viewer.blade.php(HUD + action panel markup) - Modify:
public/js/city/app.js(own character control, needs HUD poll, action fetches, render characters/buildings from payload, bounds clamp, position throttle) - Modify: lang files
Steps:
- Manual/Playwright: after Task 2–7, load
/city, see own avatar, move persists (reload keeps position), action buttons update needs/money, second character visible, build marker - No console errors; Pint N/A (JS);
node --check app.js - Commit
Task 9: End-to-end Playwright + bugfix pass
Files:
- Screenshots under
.playwright-mcp/ - Fix any bugs found in previous tasks
Steps:
- Full journey: register → pending screen → admin approves → login → accept terms if needed →
/city→ move → eat/work/sleep → build house → friend with second user → chat → admin expand → new city - Console clean; PHPUnit full suite green; Pint green
- Final commit