Files
City10/docs/superpowers/specs/2026-10-18-citizens-persistence-design.md
T
marcocosta10000 79ce2a1825 feat(world): add persistent citizen simulation with needs, jobs, and social features
- 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
2026-10-17 21:46:23 -03:00

8.7 KiB
Raw Blame History

City10 — Cidadãos Persistentes, Economia Social e Expansão Territorial

Data: 2026-10-18 Status: Aprovado pelo usuário (design + spec + implementação em um ciclo)

1. Objetivo

Cada usuário registrado e aprovado pelo Admin ganha um personagem (Character) próprio na plataforma 3D, capaz de viver como um humano simulado: mover-se, construir e habitar, trabalhar, comer, estudar, comprar/vender, dormir/acordar, fazer amigos, formar família e ter filhos, conversar com outros personagens. O mundo persiste em nuvem sem reiniciar quando alguém entra ou sai, progride continuamente via ticker agendado, e suporta expansão de território e criação de novas cidades.

2. Aprovação de contas e personagem

  • users.status: pending | active | banned (campo novo; is_active permanece espelhando status === active para compatibilidade).
  • POST /register cria usuário como pending (sem login no mundo até aprovação; login pendente mostra tela "aguardando aprovação").
  • Admin: rota /admin/citizens — listar, aprovar (active), banir (banned).
  • Ao transitar para active, cria-se Character automaticamente (factory: nome = first name do usuário, aparência aleatória, spawn no centro de cities ativa).
  • Usuários existentes com is_active=true migram para status=active; character é criado sob demanda no primeiro acesso se faltar (lazy-seed).

3. Modelo de dados

cities

id, name, slug, origin_x/z (não usado — bounds), bounds_min_x, bounds_max_x, bounds_min_z, bounds_max_z, is_active, created_at, updated_at

  • Seed: City10 com bounds equivalentes ao grid atual (−80..80).

characters

id, user_id (unique), city_id, name, skin, hair, shirt, pos_x, pos_y, pos_z, money (decimal), energy (0-100), hunger (0-100), thirst (0-100), state (awake|sleeping|working|studying|eating), job_id (nullable), house_id (nullable), education (0-100), is_online (boolean), last_tick_at, created_at, updated_at

buildings

id, city_id, owner_character_id, type (house|shop_extension|school|restaurant), name, pos_x, pos_z, width, depth, height, is_complete, build_progress (0-100), created_at, updated_at

relationships

id, character_a_id, character_b_id, type (friend|spouse|parent_child), status (pending|accepted), created_at

  • parent_child: character_a = filho, character_b = pai/mãe (para filhos NPCs: child pode ter user_id null via character órfão — na prática filhos são characters sem user_id).

inventory_items

id, character_id, item (food|water|materials|product), qty, created_at, updated_at (unique character_id+item)

transactions

id, from_character_id, to_character_id (nullable = loja/NPC), store_id (nullable), item, qty, amount, created_at

jobs

id, city_id, store_id (nullable), title, salary, requires_education (0-100), created_at, updated_at

  • Seed: Padeiro (Padaria), Mercado, Prefeitura, Escola.

children_npc

Filhos nascem como characters com user_id = NULL, state=awake, idade simulada via created_at + growth_days opcional. Sem login.

4. Ticker de mundo (city:tick)

Comando Artisan agendado a cada 1 minuto (routes/console.php → Schedule::command('city:tick')->everyMinute()):

Para cada character com state != 'dead' (não existe morte):

  1. Necessidades: hunger -= 0.5, thirst -= 0.8, energy -= 0.4 por tick (proporção ao delta real de tempo desde last_tick_at, com cap).
  2. Dormindo (state=sleeping): energy += 15 até 100; se energy>=100 → state=awake.
  3. Trabalhando (state=working com job_id): creditar salary/30 (dia de trabalho ≈ 30 ticks) em money; consumir energy extra.
  4. Estudando: education += 0.5 até 100, consome energy.
  5. Fome/sede severas (hunger<=0 ou thirst<=0): energy drena 2× e state vira awake (não morre).
  6. IA offline simples: se is_online=false e energy<20 e house existe → dormir; se energy>80 e job existe e horário “dia” (tick % 1440 entre 480–1080) → trabalhar; senão awake.
  7. Filhos: characters sem user_id com education crescendo automaticamente se age_days < 18*365 (simplificado: growth +1/tick até cap de adulto).

city:tick é idempotente por last_tick_at (skip se < 50s).

5. Gameplay (ações do jogador)

Endereços web (sessão) + espelho API Sanctum opcional:

Ação Rota Efeito
Comer POST /city/actions/eat consome 1 food do inventário; hunger +40
Beber POST /city/actions/drink consome water; thirst +40
Dormir POST /city/actions/sleep state=sleeping (exige casa completa)
Acordar POST /city/actions/wake state=awake
Trabalhar POST /city/actions/work state=working (exige emprego)
Parar trabalho POST /city/actions/stop-work state=awake
Estudar POST /city/actions/study state=studying (exige school na cidade)
Comprar POST /city/actions/buy store → inventário, money−preço
Vender POST /city/actions/sell inventário → money
Construir casa POST /city/actions/build valida terreno livre em quadra + materials ≥ 50; cria building build_progress=0 e debita os materials no ato; ticker avança build_progress += 10 por tick até 100 → is_complete=true e vira house_id do dono se ainda não tiver casa
Amizade POST /city/social/friend + accept relationship friend pending/accepted
Casamento POST /city/social/marry ambos accepted friends → spouse (1 esposo)
Filho POST /city/social/child exige casal spouse; cria character NPC criança
Chat POST /city/chat/{character} (estender fluxo existente) mensagens persistidas em character_messages (nova tabela simples: id, from, to, body, created_at)

Validações em Form Requests; autorização via policy/ownership (só o próprio character).

6. Viewer 3D (evolução do existente)

  • Rota GET /city usa ?city= (slug/id; default ativa).
  • /city/data retorna também characters (posição, estado, nome, money/needs do próprio), buildings, jobs, bounds da cidade.
  • Controla character do usuário: WASD grava posição localmente e persiste (throttled POST /city/actions/position, 1–2 s).
  • HUD: fome, sede, energia, dinheiro, estado.
  • Menu de ações (botões) chamando as rotas de ações; inventário simples.
  • Cidadãos (characters com user ou NPC filhos) renderizados como humanoides; is_online destaca.
  • Terrenos livres: quadras sem building de casa → painel “Construir aqui” quando próximo.
  • Limites da cidade aplicados (clipe nos bounds da cidade ativa).

7. Expansão e multi-cidade

  • Admin POST /admin/cities cria cidade nova (bounds default 160×160) + layout grid gerado no cliente a partir de bounds (estender CityViewerController::cityLayout para usar bounds da cidade, não só stores).
  • Admin POST /admin/cities/{city}/expand aumenta bounds_max_* em 40 (uma quadra) — limitado a 10 expansões/cidade (coluna expansions).
  • Viewer e ticker filtram por city_id.

8. Persistência em nuvem

  • Estado exclusivamente em MariaDB; city:tick via cron * * * * * php artisan schedule:run documentado no README de deploy.
  • Entrar/sair não reseta nada; múltiplas sessões simultâneas: posição mais recente vence (updated_at).
  • Fila opcional não é obrigatória neste ciclo.

9. LGPD e regras do repo

  • Sem dados pessoais em payloads de IA; chat entre characters é dado do usuário (consentimento LGPD já coberto pelos termos).
  • Nenhuma remoção de proteção LGPD; CAPTCHA mantido; CSRF; i18n completa (pt_BR/en/es) para TODAS as strings novas.
  • PHPDoc em inglês; Pint; testes PHPUnit nos fluxos; licenças registradas em RULES.md se houver dependência nova (não planejado).

10. Testes e critérios de aceite

PHPUnit:

  • Registro cria pending; login pendente bloqueado com mensagem.
  • Admin aprova → active + character criado.
  • Tick degrada necessidades; dormir recupera energy; trabalhar paga salário; comer/beber funcionam com inventário.
  • Comprar/vender alteram money/inventário/transactions.
  • Construir valida terreno e materiais; progresso avança no tick.
  • Amizade → casamento → filho cria character NPC.
  • Expansão de bounds e criação de cidade pelo admin.

Playwright MCP:

  • Fluxo completo: register → pending → login vê espera → admin aprova → usuário entra no city com character → HUD necessidades → comer/dormir/trabalhar via UI → construir casa → adicionar amigo (2º usuário) → chat → admin expande território → nova cidade visível.
  • Console sem erros; screenshots de evidência; corrigir bugs até limpo.

11. Fora de escopo

Morte permanente, combate, Reverb realtime, OpenRouter obrigatório no tick, moeda fiat real, mobile nativo.