Files
City10/docs/superpowers/specs/2026-10-18-citizens-persistence-design.md
T
marcocosta10000 c299a4ae21 feat(city): implement marketplace, missions, customization and admin dashboard
- Add database migrations for market_listings, missions and character cosmetics
- Create controllers for marketplace, missions, presence and character customization
- Implement admin world dashboard with live platform metrics
- Add feature tests for world functionality
- Include phase 2 design documents and gap analysis
2026-10-17 23:21:23 -03:00

131 lines
8.7 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 **de**bita 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.