- Tabela `profiles` + coluna `profile_id` em todas as entidades (categories, transactions, recurring_expenses, accounts, player_profile, xp_events, player_quests, player_achievements, player_cosmetics) - Dados existentes migrados para profile_id = 1 (Manoel) - CLI `./api create-user --name <n> --password <p>` cria perfil com seed de categorias e player_profile; faz upsert de senha se já existir - Auth substituída: cookie+APP_PASSWORD → JWT Bearer 24h (HS256) - Middleware RequireAuth injeta profile_id no context de todas as rotas - Todos os repositórios filtram por profile_id do context - Endpoints: POST /api/auth/login, GET /api/auth/me, POST /api/auth/change-password, POST /api/logout - Frontend: auth store usa localStorage (fc_token/fc_profile), api.ts envia Authorization header, LoginView usa campo name - SettingsView reescrita com troca de senha e logout - docker-compose.yml: remove APP_USERNAME/APP_PASSWORD, adiciona JWT_SECRET Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
5.9 KiB
Financeiro Carvalho · Handoff (Arcade Neon)
Pacote de design pronto pra ser entregue ao Claude Code / Cursor / Aider implementar. Direção visual escolhida: Arcade Neon.
O que tem aqui
neon-handoff/
├── STYLE_GUIDE.md ← leia primeiro
├── preview.html ← referência visual interativa (abra num servidor local)
├── tokens.css ← variáveis CSS + reset + classes utilitárias
├── components/ ← Vue 3 SFCs de referência
│ ├── NeonPanel.vue
│ ├── XPBar.vue
│ ├── HUDStat.vue
│ └── CharacterSprite.vue
├── sprites/
│ ├── sprite-data.json ← grade raw 17×24 + lista de cosméticos
│ ├── icons.json ← heart, coin, star, anchor (8×8 cada)
│ ├── manoel-default.png (e 4x)
│ ├── manoel-lv01.png (e 4x) · cabelo castanho, camisa azul, calça caqui
│ ├── manoel-lv03-bone-verolme.png · boné azul
│ ├── manoel-lv05-wingspan.png · camisa verde
│ ├── manoel-lv07-chapeu-sol.png · look "equipado" atual
│ ├── manoel-lv10-anti-vento.png · casaco roxo
│ ├── manoel-lv15-capitao.png · trajado de capitão (vermelho/preto)
│ └── manoel-sheet-4x.png · todos lado a lado pra referência
└── README.md ← este arquivo
Como integrar no apps/web
-
Copie
tokens.cssparasrc/styles/tokens.css. Importe uma vez emsrc/main.ts:import './styles/tokens.css' -
Copie
components/*.vueparasrc/components/. Eles já consomemvar(--fc-*). -
Copie
sprites/sprite-data.jsonesprites/icons.jsonprasrc/assets/. Garanta quetsconfig.jsontenha"resolveJsonModule": true(Vite default já tem). -
Embrulhe o
<router-view>em<div class="fc-app">— é isso que aplica o fundo + scanlines + grid.<!-- App.vue --> <template> <div class="fc-app"> <AppHud /> <RouterView /> </div> </template> -
As 8 rotas do PRD (
/,/transacoes,/importar,/categorias,/recorrencias,/contas,/personagem,/configuracoes) usam o mesmo header HUD. VejaSTYLE_GUIDE.md§3.6 pro shape do componente.
Sprites · uso
Renderizar dinâmico (recomendado)
<CharacterSprite> lê sprite-data.json e aceita theme como prop. Cosméticos
equipados são merged no store (Pinia) e passados como theme.
<CharacterSprite :scale="6" :theme="gameStore.equippedTheme" :celebrate="gameStore.justLeveledUp" />
Exemplo de store getter:
// stores/game.ts
const equippedTheme = computed(() => {
return cosmetics.value
.filter(c => c.equipped)
.reduce((acc, c) => ({ ...acc, ...c.colors }), {} as Record<string, string>)
})
Usar PNG estático
Útil pra previews em página de loja (/personagem → seção "cosméticos"):
<img src="@/assets/sprites/manoel-lv03-bone-verolme-4x.png" alt="Boné Verolme" />
Sempre image-rendering: pixelated; no CSS pra não suavizar.
Regenerar PNGs
sprites/sprite-data.json é a fonte da verdade. Se você ajustar uma cor de
cosmético lá, regenere os PNGs com um script Node:
// scripts/build-sprites.mjs
import { createCanvas } from '@napi-rs/canvas' // ou node-canvas
import fs from 'node:fs/promises'
const data = JSON.parse(await fs.readFile('src/assets/sprite-data.json', 'utf8'))
// ... mesmo render do PixelSprite acima, salva PNG por cosmético
Ou peça pro Claude Code regenerar — o algoritmo é trivial (loop pela grade, fillRect por célula com a cor do slot).
Princípios para o Claude implementar
Por ordem de importância:
- HUD persistente em todas as rotas. Não use sidebar — o app é um HUD de jogo.
- Nunca use hex direto. Sempre
var(--fc-*). Se faltar token, adicione-o aotokens.csse documente noSTYLE_GUIDE.md§1.1. - Press Start 2P pra label e número. JetBrains Mono pra dado. Inter pra prosa. Press Start 2P sempre em maiúscula.
- Glow é raro. Só nos números heroicos (47%) e no painel principal de cada rota. Se cada card brilha, nada brilha.
- Verde/vermelho são binários — meta sim / meta não. Não use vermelho pra valor negativo (transação) — só pra alerta.
- Cada animação tem propósito. Ver §6 do guia.
- Mobile vira bottom-nav. Não tente espremer a HUD horizontal num iPhone.
Telas a implementar
Conforme STYLE_GUIDE.md + screens visíveis em preview.html (Arcade · 01):
/Dashboard (hero poupado, categorias, histórico, transações, recorrências, quests, patrimônio, widget personagem)/transacoeslista + CRUD/importarupload OFX/CSV + preview de deduplicação/categoriasCRUD com pixel-icon picker/recorrenciaslista mensal com status (paid / due / missing)/contascards de conta + patrimônio total/personagempainel RPG completo/configuracoesformulário simples (perfil, meta %, prefs visuais)
Para qualquer tela nova: comece copiando a estrutura do dashboard, substitua o conteúdo dos painéis, mantenha a HUD.
Componentes adicionais que faltam
Esses não estão neste pacote — implemente seguindo os tokens já definidos:
AppHud.vue(cabeçalho persistente)BottomNav.vue(mobile)TransactionRow.vueQuestCard.vueCategoryBar.vueAchievementCell.vueLevelUpModal.vue(overlay celebratório no level up)MonthSwitcher.vue(‹ MAIO · 2026 ›)
Tom de voz
Português brasileiro, direto, com vocabulário de jogo. Não é app corporativo.
Ver STYLE_GUIDE.md §8.
Qualquer dúvida sobre intenção visual (não implementação), volte ao
STYLE_GUIDE.md ou ao preview.html. A página de design original do projeto
(canvas com 4 direções) também segue acessível pra comparação.