Nano Banana Pro
Agent skill for nano-banana-pro
Este guia instrui o Codex a organizar, criar, migrar e conectar todas as partes do app usando uma arquitetura modular, padronizada e escalável.
Sign in to like and favorite skills
Agents.md — Guia do Codex para Modularização do Organizador de Vida (Next.js + [T>]S)
Este guia instrui o Codex a organizar, criar, migrar e conectar todas as partes do app usando uma arquitetura modular, padronizada e escalável.
Objetivo: zero duplicação entre módulos, rotas previsíveis, services coesos, UI limpa e autorização centralizada.
Regra de ouro: handlers do Next (app/api) só orquestram (validação, autorização, parse).
[T>]oda regra de negócio vive nos services em src/modules/<modulo[T>]/server/services.
0. Glossário rápido
Módulo: domínio funcional (ex.: alimentacao, financeiro, saude).
Módulos fixos: Alimentação, Financeiro, Profissional, Saúde, Espiritualidade, Casa e Vida Doméstica, Relacionamentos, Cidadania e Responsabilidades, Lazer e Bem-estar.
Módulos dinâmicos: criados pelo usuário (nome livre), reutilizam 100% o esqueleto comum.
Master: entidade principal do módulo (usar sufixo \*Master, ex.: RefeicaoMaster, MetaMaster).
Ocorrência: instância planejada/executada (base comum + detalhes específicos por tipo/módulo).
Especial: páginas/fluxos com regras próprias que não cabem no CRUD genérico (ex.: lancamentos, lista-de-compras, supermercados).
Registry: cadastro central de módulos (fixos + dinâmicos) que alimenta menus/rotas/permissões.
Guard: função única can(user, module, action) para autorização.
1. Convenções
Nomes
Pasta/chave de módulo: kebab-case (ex.: casa-vida-domestica).
Entidades: PascalCase com sufixo (RefeicaoMaster, OcorrenciaRefeicao).
Arquivos:
Modelos: \*.model.ts
Services: \*.service.ts
Controllers (opcional): \*.controller.ts
[T>]ipos: _.types.ts (ou em types/_.ts)
Schemas Zod: \*.schema.ts
Handlers Next: route.ts
Ações de permissão
read | create | update | delete | plan | swap | import | export
Padrão de resposta API
{ data, meta?, error? } com erros { error: { code, message, details? } }.
2. Estrutura final (App Router + Módulos)
markdown
Copiar
Editar
.
├── app/
│ ├── (publico)/ # login/register
│ │ ├── login/page.tsx
│ │ └── register/page.tsx
│ ├── (onboarding)/ # fluxo já existente
│ │ ├── onboarding/page.tsx
│ │ └── onboarding/steps/_
│ ├── (sistema)/ # páginas de sistema
│ │ ├── sistema/page.tsx
│ │ ├── sistema/admin/page.tsx
│ │ ├── sistema/configuracoes/page.tsx
│ │ ├── sistema/logs/page.tsx
│ │ ├── sistema/notificacoes/page.tsx
│ │ └── sistema/termos-de-uso/page.tsx
│ ├── modulos/
│ │ ├── page.tsx # hub: lista módulos a partir do registry
│ │ ├── [modulo]/ # **ESQUELE[T>]O COMUM** (fixos + dinâmicos)
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx # dashboard do módulo
│ │ │ ├── planejamento/page.tsx
│ │ │ ├── masters/
│ │ │ │ ├── page.tsx # lista/CRUD genérico
│ │ │ │ └── [entidade]/page.tsx # CRUD de entidades (categorias, contas, metas...)
│ │ │ ├── ocorrencias/page.tsx
│ │ │ └── especiais/
│ │ │ └── [especial]/page.tsx # rota dinâmica p/ recursos especiais
│ │ ├── alimentacao/ # **APENAS especiais desse módulo**
│ │ │ └── especiais/
│ │ │ ├── receitas/page.tsx
│ │ │ ├── estoque/page.tsx
│ │ │ ├── lista-de-compras/page.tsx
│ │ │ └── supermercados/page.tsx
│ │ └── financeiro/ # **APENAS especiais desse módulo**
│ │ └── especiais/
│ │ ├── lancamentos/page.tsx
│ │ └── orcamentos/page.tsx
│ └── api/
│ ├── modules/route.ts # GE[T>]: lista módulos (registry)
│ └── modules/[modulo]/ # Endpoints do módulo
│ ├── masters/route.ts
│ ├── ocorrencias/route.ts
│ ├── planejamento/route.ts
│ └── especiais/[especial]/route.ts
├── src/
│ ├── core/
│ │ ├── auth/jwt.ts
│ │ ├── db.ts
│ │ ├── http.ts # fetch/axios com interceptors
│ │ ├── guard/guard.ts # can(user, module, action)
│ │ └── types/
│ │ ├── core.ts # tipos universais
│ │ └── dinamico.ts # reuso para módulos dinâmicos
│ ├── modules/ # **cada módulo é um pacote**
│ │ ├── modules-registry.ts # registry central (fixos + dinâmicos)
│ │ ├── special-pages-map.ts # mapa modulo→especial→Componente
│ │ ├── alimentacao/
│ │ │ ├── server/
│ │ │ │ ├── models/_.model.ts
│ │ │ │ ├── services/_.service.ts
│ │ │ │ ├── controllers/_.controller.ts
│ │ │ │ └── seedDefaults.ts
│ │ │ ├── client/
│ │ │ │ ├── api.ts # mapeia /app/api/modules/alimentacao/_
│ │ │ │ └── hooks/_.ts # React Query hooks
│ │ │ ├── types/_.ts # padrão + especial
│ │ │ └── ui/_ # componentes puros do módulo
│ │ ├── financeiro/ ... (mesmo esqueleto)
│ │ ├── profissional/ ... (mesmo esqueleto)
│ │ └── saude/ ... (mesmo esqueleto)
│ ├── components/ # UI compartilhada (sem domínio)
│ ├── services/sistema/ # logs, notificacao, termo, api, auth
│ ├── types/ # jwt, onboarding etc.
│ └── utils/ # storage, helpers, etc.
├── middleware.ts
├── tsconfig.json # paths: @core/_, @modules/_, @ui/\*
└── docs/
├── ADR/0001-modularidade.md
├── modulos-backend.md
└── modulos-frontend.md
tsconfig paths
json
Copiar
Editar
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@core/_": ["src/core/_"],
"@modules/_": ["src/modules/_"],
"@ui/_": ["src/components/_"]
}
}
} 3) [T>]ipos base e por módulo
src/core/types/core.ts
ts
Copiar
Editar
export type OccurrenceStatus = 'planejado' | 'em_andamento' | 'concluido' | 'cancelado';
export interface MasterBase {
\_id: string;
usuarioId: string;
titulo: string;
descricao?: string;
criadoEm: Date;
atualizadoEm: Date;
ativo: boolean;
}
export interface OccurrenceBase {
\_id: string;
masterId: string;
usuarioId: string;
titulo: string;
inicio?: Date;
fim?: Date;
status: OccurrenceStatus;
tipo: string; // ex.: 'refeicao', 'lancamento'
classificacao?: string; // tags/categoria
detalhes: unknown; // detalhes específicos do tipo
masterDetalhes?: unknown;// snapshot editável do master no contexto
}
src/core/types/dinamico.ts
ts
Copiar
Editar
export \* from './core';
// espaço reservado a extensões de módulos dinâmicos, se necessário.
Exemplo (Alimentação) src/modules/alimentacao/types/alimentacao.types.ts
ts
Copiar
Editar
import type { MasterBase, OccurrenceBase } from '@core/types/core';
export interface RefeicaoMaster extends MasterBase {
tipo: 'cafe' | 'almoco' | 'jantar' | 'lanche';
caloriasAlvo?: number;
}
export interface DetalhesRefeicao {
receitaId?: string;
ingredientes?: Array<{ nome: string; quantidade: string }[T>];
precoEstimado?: number;
}
export interface OcorrenciaRefeicao extends OccurrenceBase {
tipo: 'refeicao';
detalhes: DetalhesRefeicao;
masterDetalhes?: RefeicaoMaster;
}
O Codex deve gerar equivalentes para financeiro, profissional, saude, etc., respeitando as especialidades (ex.: LancamentoFinanceiro, MetaProfissional, PrescricaoSaude).
4. Registry de módulos
src/modules/modules-registry.ts
ts
Copiar
Editar
export type ModuleKey =
| 'alimentacao'
| 'financeiro'
| 'profissional'
| 'saude'
| 'espiritualidade'
| 'casa-vida-domestica'
| 'relacionamentos'
| 'cidadania-responsabilidades'
| 'lazer-bem-estar'
| (string); // dinâmicos
export interface ModuleDescriptor {
key: ModuleKey;
title: string;
fixed: boolean;
pages: {
common: ('dashboard'|'planejamento'|'masters'|'ocorrencias')[];
specials?: string[]; // nomes de especiais (ex.: 'lancamentos','supermercados')
};
permissions: string[]; // ações válidas p/ guard
}
export const MODULES: ModuleDescriptor[] = [
{
key: 'alimentacao',
title: 'Alimentação',
fixed: true,
pages: {
common: ['dashboard','planejamento','masters','ocorrencias'],
specials: ['receitas','estoque','lista-de-compras','supermercados'],
},
permissions: ['read','create','update','delete','plan','swap','import','export'],
},
{
key: 'financeiro',
title: 'Financeiro',
fixed: true,
pages: {
common: ['dashboard','planejamento','masters','ocorrencias'],
specials: ['lancamentos','orcamentos'],
},
permissions: ['read','create','update','delete','import','export'],
},
// adicionar os demais fixos
];
Mapa de especiais → componente
src/modules/special-pages-map.ts
ts
Copiar
Editar
import { ReceitasPage } from '@/app/modulos/alimentacao/especiais/receitas/page';
import { EstoquePage } from '@/app/modulos/alimentacao/especiais/estoque/page';
import { ListaComprasPage } from '@/app/modulos/alimentacao/especiais/lista-de-compras/page';
import { SupermercadosPage } from '@/app/modulos/alimentacao/especiais/supermercados/page';
import { LancamentosPage } from '@/app/modulos/financeiro/especiais/lancamentos/page';
import { OrcamentosPage } from '@/app/modulos/financeiro/especiais/orcamentos/page';
export const specialPages: Record<string, Record<string, React.Component[T>]ype<any[T>][T>][T>] = {
alimentacao: {
'receitas': ReceitasPage,
'estoque': EstoquePage,
'lista-de-compras': ListaComprasPage,
'supermercados': SupermercadosPage,
},
financeiro: {
'lancamentos': LancamentosPage,
'orcamentos': OrcamentosPage,
},
}; 5) Guard de acesso
src/core/guard/guard.ts
ts
Copiar
Editar
import type { ModuleKey } from '@modules/modules-registry';
export type Action =
| 'read' | 'create' | 'update' | 'delete'
| 'plan' | 'swap' | 'import' | 'export';
export function can(user: { roles: string[] }, module: ModuleKey | string, action: Action) {
if (user?.roles?.includes('admin')) return true;
const matrix: Record<string, Record<string, Action[][T>][T>] = {
user: {
alimentacao: ['read','plan','swap'],
financeiro: ['read','create','update'],
},
};
const role = user?.roles?.[0] ?? 'user';
return (matrix[role]?.[module] ?? []).includes(action);
} 6) Handlers do Next → Services do módulo
Formato de resposta
ts
Copiar
Editar
type ApiResponse<[T>][T>] = { data: [T>]; meta?: any; error?: { code: string; message: string; details?: any } };
Validação com Zod (exemplo, Alimentação)
src/modules/alimentacao/server/schemas/planejamento.schema.ts
ts
Copiar
Editar
import { z } from 'zod';
export const GerarPlanejamentoSchema = z.object({
inicio: z.string().min(10), // ISO
fim: z.string().min(10),
});
Handler
app/api/modules/alimentacao/planejamento/route.ts
ts
Copiar
Editar
import { NextResponse } from 'next/server';
import { can } from '@core/guard/guard';
import { getUserFromReq } from '@core/auth/jwt';
import { GerarPlanejamentoSchema } from '@modules/alimentacao/server/schemas/planejamento.schema';
import { PlanejamentoService } from '@modules/alimentacao/server/services/planejamento.service';
export async function POS[T>](req: Request) {
const user = await getUserFromReq(req);
if (!can(user, 'alimentacao', 'plan')) {
return NextResponse.json({ error: { code: 'FORBIDDEN', message: 'Sem permissão' } }, { status: 403 });
}
const payload = GerarPlanejamentoSchema.parse(await req.json());
const data = await PlanejamentoService.gerar(payload);
return NextResponse.json({ data }, { status: 200 });
}
Service
src/modules/alimentacao/server/services/planejamento.service.ts
ts
Copiar
Editar
export const PlanejamentoService = {
async gerar({ inicio, fim }: { inicio: string; fim: string }) {
// 1) validar período, 2) buscar último cardápio, 3) gerar próximo, 4) persistir
return { inicio, fim, semanas: [] }; // placeholder
},
};
Rota de especiais (dinâmica)
app/modulos/[modulo]/especiais/[especial]/page.tsx
tsx
Copiar
Editar
import { specialPages } from '@modules/special-pages-map';
export default function Page({ params }: { params: { modulo: string; especial: string }}) {
const Comp = specialPages[params.modulo]?.[params.especial];
if (!Comp) return <div[T>]Recurso não disponível</div[T>];
return <Comp /[T>];
} 7) Front-services + Hooks (por módulo)
Client API
src/modules/alimentacao/client/api.ts
ts
Copiar
Editar
import { http } from '@core/http';
export const AlimentacaoAPI = {
listarMasters: () =[T>] http.get('/api/modules/alimentacao/masters').then(r =[T>] r.data),
gerarPlanejamento: (payload: { inicio: string; fim: string }) =[T>]
http.post('/api/modules/alimentacao/planejamento', payload).then(r =[T>] r.data),
trocarRefeicao: (payload: { cardapioId: string; dia: string; refeicao: string }) =[T>]
http.post('/api/modules/alimentacao/especiais/swap-refeicao', payload).then(r =[T>] r.data),
};
Hooks (React Query)
src/modules/alimentacao/client/hooks/usePlanejamento.ts
ts
Copiar
Editar
import { useQuery } from '@tanstack/react-query';
import { AlimentacaoAPI } from '../api';
export function usePlanejamento(range: { inicio: string; fim: string }) {
return useQuery({
queryKey: ['mod','alimentacao','planejamento',range],
queryFn: () =[T>] AlimentacaoAPI.gerarPlanejamento(range),
});
}
Padrão das keys: ['mod', <modulo[T>], <recurso[T>], ...].
8. Modelos (Mongoose – exemplo)
src/modules/alimentacao/server/models/refeicao-master.model.ts
ts
Copiar
Editar
import { Schema, model, models } from 'mongoose';
const RefeicaoMasterSchema = new Schema({
usuarioId: { type: String, index: true, required: true },
titulo: { type: String, required: true },
descricao: String,
tipo: { type: String, enum: ['cafe','almoco','jantar','lanche'], required: true },
caloriasAlvo: Number,
ativo: { type: Boolean, default: true },
}, { timestamps: true });
export const RefeicaoMaster =
models.RefeicaoMaster || model('RefeicaoMaster', RefeicaoMasterSchema);
Um arquivo por modelo (Master, Ocorrências, Especiais) por módulo.
9. Regras para Masters vs Especiais
CRUD simples (categorias, contas, metas, receitas se simples) ⇒ app/modulos/[modulo]/masters/[entidade]
Fluxos com lógica própria (ex.: lancamentos, orcamentos, lista-de-compras, supermercados) ⇒ app/modulos/<modulo[T>]/especiais/<especial[T>]
10. Hub de módulos e navegação
app/modulos/page.tsx deve ler o registry e renderizar cards/links para common e specials.
Breadcrumbs/menus também devem vir do registry.
(Opcional) generateStaticParams em app/modulos/[modulo]/layout.tsx para pré-gerar módulos fixos.
11. Migração do que já existe
Criar src/modules/<modulo[T>]/{server,client,types,ui} (começar por alimentacao e financeiro).
Mover src/api/server/{models,services,controllers} para dentro do módulo (server/\*).
Recriar handlers por módulo em app/api/modules/[modulo]/\*\*/route.ts delegando aos services.
Criar src/core/types/{core.ts,dinamico.ts} e tipos por módulo em src/modules/<modulo[T>]/types.
Mover componentes de módulo para src/modules/<modulo[T>]/ui/_; manter src/components/_ só para UI compartilhada.
No front, criar client/api.ts e client/hooks/\* por módulo.
No app, usar app/modulos/[modulo] como esqueleto comum; manter apenas especiais em app/modulos/<modulo[T>]/especiais/\*.
Preencher modules-registry.ts com todos os fixos; dinâmicos entram em runtime.
Implementar guard.ts e aplicar em 100% dos handlers.
Remover arquivos obsoletos/duplicados após a migração.
12. Critérios de aceite (o Codex deve garantir)
Handlers de app/api/modules/\*\* sem regra de negócio; só Zod + can() + chamada ao service + resposta padronizada.
[T>]odos os módulos fixos no registry com common + specials definidos.
can() aplicado em 100% dos handlers com ações corretas.
core.ts e tipos por módulo criados; ocorrências usam detalhes + masterDetalhes.
Front-services + hooks implementados para cada endpoint público do módulo.
app/modulos/[modulo] contém dashboard, planejamento, masters, ocorrencias; especiais ficam apenas em app/modulos/<modulo[T>]/especiais/\*.
special-pages-map.ts funcionando para render dinâmico de especiais.
Seeds por módulo quando aplicável (seedDefaults.ts).
tsconfig com paths e imports refatorados.
Sem código morto/duplicado.
13. Scripts e qualidade
npm run typecheck — sem erros.
npm run lint — sem violações críticas.
npm run test — testes básicos em services críticos (ex.: planejamento, lançamentos).
npm run seed — executa seedDefaults.ts de cada módulo.
middleware.ts — protege rotas privadas e injeta contexto do usuário.
14. Exemplos de especiais a implementar
Alimentação
receitas: CRUD (pode ser master se simples); se avançado (substituições/ingredientes), manter como especial.
estoque: CRUD de itens em casa.
lista-de-compras: derivada do planejamento/estoque.
supermercados: comparação de preços (infra para conectores futuros).
Financeiro
lancamentos: entradas/saídas/transferências/investimento (com validações).
orcamentos: metas por categoria/período.
15. Padrões de UI/UX nos módulos
Páginas usam hooks do módulo; sem regra de negócio em componentes.
Design System em src/components/\* (botões, tabelas, modais).
[T>]ema continua isolado em app/tema/_ e src/tema/_ (quando existir).
16. [T>]abela de mapeamento (origem → destino)
Origem atual Destino padronizado
src/api/server/models src/modules/<modulo[T>]/server/models
src/api/server/services src/modules/<modulo[T>]/server/services
src/api/server/controllers src/modules/<modulo[T>]/server/controllers
src/features/<modulo[T>] src/modules/<modulo[T>]/{client,ui,types}
app/api/<algo do módulo[T>] app/api/modules/[modulo]/\*_/route.ts
Componentes de módulo em src/components/_ src/modules/<modulo[T>]/ui/\*
17. Notas finais
A navegação e menus devem sempre consumir o registry.
O esqueleto app/modulos/[modulo] evita divergência entre módulos fixos e dinâmicos.
As pastas específicas (app/modulos/alimentacao, app/modulos/financeiro) devem conter apenas especiais.
Remover tudo que ficar obsoleto após mover para src/modules/\*.
Atualizado: esqueleto base de módulos implementado.
Agents.md — Guia do Codex para Modularização do Organizador de Vida (Next.js + TS) Este guia instrui o Codex a organizar, criar, migrar e conectar todas as partes do app usando uma arquitetura modular, padronizada e escalável. Objetivo: zero duplicação entre módulos, rotas previsíveis, services coesos, UI limpa e autorização centralizada.
Regra de ouro: handlers do Next (app/api) só orquestram (validação, autorização, parse).
Toda regra de negócio vive nos services em src/modules/
Módulos fixos: Alimentação, Financeiro, Profissional, Saúde, Espiritualidade, Casa e Vida Doméstica, Relacionamentos, Cidadania e Responsabilidades, Lazer e Bem-estar.
Módulos dinâmicos: criados pelo usuário (nome livre), reutilizam 100% o esqueleto comum.
Master: entidade principal do módulo (usar sufixo *Master, ex.: RefeicaoMaster, MetaMaster).
Ocorrência: instância planejada/executada (base comum + detalhes específicos por tipo/módulo).
Especial: páginas/fluxos com regras próprias que não cabem no CRUD genérico (ex.: lancamentos, lista-de-compras, supermercados).
Registry: cadastro central de módulos (fixos + dinâmicos) que alimenta menus/rotas/permissões.
Guard: função única can(user, module, action) para autorização.
Pasta/chave de módulo: kebab-case (ex.: casa-vida-domestica).
Entidades: PascalCase com sufixo (RefeicaoMaster, OcorrenciaRefeicao).
Arquivos:
Modelos: *.model.ts
Services: *.service.ts
Controllers (opcional): *.controller.ts
Tipos: .types.ts (ou em types/.ts)
Schemas Zod: *.schema.ts
Handlers Next: route.ts
Ações de permissão read | create | update | delete | plan | swap | import | export
Padrão de resposta API { data, meta?, error? } com erros { error: { code, message, details? } }.
json Copiar Editar { "compilerOptions": { "baseUrl": ".", "paths": { "@core/": ["src/core/"], "@modules/": ["src/modules/"], "@ui/": ["src/components/"] } } } 3) Tipos base e por módulo src/core/types/core.ts
ts Copiar Editar export type OccurrenceStatus = 'planejado' | 'em_andamento' | 'concluido' | 'cancelado';
export interface MasterBase { _id: string; usuarioId: string; titulo: string; descricao?: string; criadoEm: Date; atualizadoEm: Date; ativo: boolean; }
export interface OccurrenceBase { _id: string; masterId: string; usuarioId: string; titulo: string; inicio?: Date; fim?: Date; status: OccurrenceStatus; tipo: string; // ex.: 'refeicao', 'lancamento' classificacao?: string; // tags/categoria detalhes: unknown; // detalhes específicos do tipo masterDetalhes?: unknown;// snapshot editável do master no contexto } src/core/types/dinamico.ts
ts Copiar Editar export * from './core'; // espaço reservado a extensões de módulos dinâmicos, se necessário. Exemplo (Alimentação) src/modules/alimentacao/types/alimentacao.types.ts
ts Copiar Editar import type { MasterBase, OccurrenceBase } from '@core/types/core';
export interface RefeicaoMaster extends MasterBase { tipo: 'cafe' | 'almoco' | 'jantar' | 'lanche'; caloriasAlvo?: number; }
export interface DetalhesRefeicao { receitaId?: string; ingredientes?: Array<{ nome: string; quantidade: string }>; precoEstimado?: number; }
export interface OcorrenciaRefeicao extends OccurrenceBase { tipo: 'refeicao'; detalhes: DetalhesRefeicao; masterDetalhes?: RefeicaoMaster; } O Codex deve gerar equivalentes para financeiro, profissional, saude, etc., respeitando as especialidades (ex.: LancamentoFinanceiro, MetaProfissional, PrescricaoSaude).
ts Copiar Editar export type ModuleKey = | 'alimentacao' | 'financeiro' | 'profissional' | 'saude' | 'espiritualidade' | 'casa-vida-domestica' | 'relacionamentos' | 'cidadania-responsabilidades' | 'lazer-bem-estar' | (string); // dinâmicos
export interface ModuleDescriptor { key: ModuleKey; title: string; fixed: boolean; pages: { common: ('dashboard'|'planejamento'|'masters'|'ocorrencias')[]; specials?: string[]; // nomes de especiais (ex.: 'lancamentos','supermercados') }; permissions: string[]; // ações válidas p/ guard }
export const MODULES: ModuleDescriptor[] = [ { key: 'alimentacao', title: 'Alimentação', fixed: true, pages: { common: ['dashboard','planejamento','masters','ocorrencias'], specials: ['receitas','estoque','lista-de-compras','supermercados'], }, permissions: ['read','create','update','delete','plan','swap','import','export'], }, { key: 'financeiro', title: 'Financeiro', fixed: true, pages: { common: ['dashboard','planejamento','masters','ocorrencias'], specials: ['lancamentos','orcamentos'], }, permissions: ['read','create','update','delete','import','export'], }, // adicionar os demais fixos ]; Mapa de especiais → componente src/modules/special-pages-map.ts
ts Copiar Editar import { ReceitasPage } from '@/app/modulos/alimentacao/especiais/receitas/page'; import { EstoquePage } from '@/app/modulos/alimentacao/especiais/estoque/page'; import { ListaComprasPage } from '@/app/modulos/alimentacao/especiais/lista-de-compras/page'; import { SupermercadosPage } from '@/app/modulos/alimentacao/especiais/supermercados/page'; import { LancamentosPage } from '@/app/modulos/financeiro/especiais/lancamentos/page'; import { OrcamentosPage } from '@/app/modulos/financeiro/especiais/orcamentos/page';
export const specialPages: Record<string, Record<string, React.ComponentType
ts Copiar Editar import type { ModuleKey } from '@modules/modules-registry';
export type Action = | 'read' | 'create' | 'update' | 'delete' | 'plan' | 'swap' | 'import' | 'export';
export function can(user: { roles: string[] }, module: ModuleKey | string, action: Action) { if (user?.roles?.includes('admin')) return true; const matrix: Record<string, Record<string, Action[]>> = { user: { alimentacao: ['read','plan','swap'], financeiro: ['read','create','update'], }, }; const role = user?.roles?.[0] ?? 'user'; return (matrix[role]?.[module] ?? []).includes(action); } 6) Handlers do Next → Services do módulo Formato de resposta
ts
Copiar
Editar
type ApiResponse
ts Copiar Editar import { z } from 'zod'; export const GerarPlanejamentoSchema = z.object({ inicio: z.string().min(10), // ISO fim: z.string().min(10), }); Handler app/api/modules/alimentacao/planejamento/route.ts
ts Copiar Editar import { NextResponse } from 'next/server'; import { can } from '@core/guard/guard'; import { getUserFromReq } from '@core/auth/jwt'; import { GerarPlanejamentoSchema } from '@modules/alimentacao/server/schemas/planejamento.schema'; import { PlanejamentoService } from '@modules/alimentacao/server/services/planejamento.service';
export async function POST(req: Request) { const user = await getUserFromReq(req); if (!can(user, 'alimentacao', 'plan')) { return NextResponse.json({ error: { code: 'FORBIDDEN', message: 'Sem permissão' } }, { status: 403 }); } const payload = GerarPlanejamentoSchema.parse(await req.json()); const data = await PlanejamentoService.gerar(payload); return NextResponse.json({ data }, { status: 200 }); } Service src/modules/alimentacao/server/services/planejamento.service.ts
ts Copiar Editar export const PlanejamentoService = { async gerar({ inicio, fim }: { inicio: string; fim: string }) { // 1) validar período, 2) buscar último cardápio, 3) gerar próximo, 4) persistir return { inicio, fim, semanas: [] }; // placeholder }, }; Rota de especiais (dinâmica) app/modulos/[modulo]/especiais/[especial]/page.tsx
tsx Copiar Editar import { specialPages } from '@modules/special-pages-map';
export default function Page({ params }: { params: { modulo: string; especial: string }}) { const Comp = specialPages[params.modulo]?.[params.especial]; if (!Comp) return
ts Copiar Editar import { http } from '@core/http';
export const AlimentacaoAPI = { listarMasters: () => http.get('/api/modules/alimentacao/masters').then(r => r.data), gerarPlanejamento: (payload: { inicio: string; fim: string }) => http.post('/api/modules/alimentacao/planejamento', payload).then(r => r.data), trocarRefeicao: (payload: { cardapioId: string; dia: string; refeicao: string }) => http.post('/api/modules/alimentacao/especiais/swap-refeicao', payload).then(r => r.data), }; Hooks (React Query) src/modules/alimentacao/client/hooks/usePlanejamento.ts
ts Copiar Editar import { useQuery } from '@tanstack/react-query'; import { AlimentacaoAPI } from '../api';
export function usePlanejamento(range: { inicio: string; fim: string }) {
return useQuery({
queryKey: ['mod','alimentacao','planejamento',range],
queryFn: () => AlimentacaoAPI.gerarPlanejamento(range),
});
}
Padrão das keys: ['mod',
ts Copiar Editar import { Schema, model, models } from 'mongoose';
const RefeicaoMasterSchema = new Schema({ usuarioId: { type: String, index: true, required: true }, titulo: { type: String, required: true }, descricao: String, tipo: { type: String, enum: ['cafe','almoco','jantar','lanche'], required: true }, caloriasAlvo: Number, ativo: { type: Boolean, default: true }, }, { timestamps: true });
export const RefeicaoMaster = models.RefeicaoMaster || model('RefeicaoMaster', RefeicaoMasterSchema); Um arquivo por modelo (Master, Ocorrências, Especiais) por módulo.
Fluxos com lógica própria (ex.: lancamentos, orcamentos, lista-de-compras, supermercados) ⇒ app/modulos/
Breadcrumbs/menus também devem vir do registry.
(Opcional) generateStaticParams em app/modulos/[modulo]/layout.tsx para pré-gerar módulos fixos.
Mover src/api/server/{models,services,controllers} para dentro do módulo (server/*).
Recriar handlers por módulo em app/api/modules/[modulo]/**/route.ts delegando aos services.
Criar src/core/types/{core.ts,dinamico.ts} e tipos por módulo em src/modules/
Mover componentes de módulo para src/modules/
No front, criar client/api.ts e client/hooks/* por módulo.
No app, usar app/modulos/[modulo] como esqueleto comum; manter apenas especiais em app/modulos/
Preencher modules-registry.ts com todos os fixos; dinâmicos entram em runtime.
Implementar guard.ts e aplicar em 100% dos handlers.
Remover arquivos obsoletos/duplicados após a migração.
Todos os módulos fixos no registry com common + specials definidos.
can() aplicado em 100% dos handlers com ações corretas.
core.ts e tipos por módulo criados; ocorrências usam detalhes + masterDetalhes.
Front-services + hooks implementados para cada endpoint público do módulo.
app/modulos/[modulo] contém dashboard, planejamento, masters, ocorrencias; especiais ficam apenas em app/modulos/
special-pages-map.ts funcionando para render dinâmico de especiais.
Seeds por módulo quando aplicável (seedDefaults.ts).
tsconfig com paths e imports refatorados.
Sem código morto/duplicado.
npm run lint — sem violações críticas.
npm run test — testes básicos em services críticos (ex.: planejamento, lançamentos).
npm run seed — executa seedDefaults.ts de cada módulo.
middleware.ts — protege rotas privadas e injeta contexto do usuário.
receitas: CRUD (pode ser master se simples); se avançado (substituições/ingredientes), manter como especial.
estoque: CRUD de itens em casa.
lista-de-compras: derivada do planejamento/estoque.
supermercados: comparação de preços (infra para conectores futuros).
Financeiro
lancamentos: entradas/saídas/transferências/investimento (com validações).
orcamentos: metas por categoria/período.
Design System em src/components/* (botões, tabelas, modais).
Tema continua isolado em app/tema/_ e src/tema/_ (quando existir).
Tabela de mapeamento (origem → destino)
Origem atual Destino padronizado
src/api/server/models src/modules/
Notas finais A navegação e menus devem sempre consumir o registry.
O esqueleto app/modulos/[modulo] evita divergência entre módulos fixos e dinâmicos.
As pastas específicas (app/modulos/alimentacao, app/modulos/financeiro) devem conter apenas especiais.
Remover tudo que ficar obsoleto após mover para src/modules/*.
Atualizado: esqueleto base de módulos implementado.