diff --git a/.cursor/rules/seahaven-admin.mdc b/.cursor/rules/seahaven-admin.mdc index fcf3114f..a9d3acf0 100644 --- a/.cursor/rules/seahaven-admin.mdc +++ b/.cursor/rules/seahaven-admin.mdc @@ -1,52 +1,52 @@ --- -description: SeaHaven Admin — arquitetura IrisLoan, convenções de rebuild seletivo +description: SeaHaven Admin — IrisLoan architecture, selective rebuild conventions alwaysApply: true --- -# SeaHaven Admin — convenções IrisLoan +# SeaHaven Admin — IrisLoan conventions ## Stack - Vite SPA + React Router 7, TypeScript strict, Tailwind v4 + MUI -- HTTP: Ky com `credentials: "include"` (cookies httpOnly) +- HTTP: Ky with `credentials: "include"` (httpOnly cookies) - Server state: TanStack Query; forms: React Hook Form + Zod -- **Não usar** em código novo: Next.js, Redux, axios, `apiUtil.js`, `tokenUtility.js` +- **Do not use** in new code: Next.js, Redux, axios, `apiUtil.js`, `tokenUtility.js` -## Estrutura alvo (`src/`) +## Target structure (`src/`) ``` api/ domain// app/ infra/query-key/ lib/ hooks/ components/ui|common|layout/ config/menu.ts providers/ main.tsx ``` -- Alias `@/` para imports; arquivos novos em **kebab-case** (`use-debounce.ts`, `query-key.ts`) -- `pages/` é **somente referência** de endpoints e regras de negócio — deletar após entrega em `domain/` + `app/` +- `@/` alias for imports; new files in **kebab-case** (`use-debounce.ts`, `query-key.ts`) +- `pages/` is **reference only** for endpoints and business rules — delete after delivery in `domain/` + `app/` -## HTTP e auth +## HTTP and auth -- Centralizar paths em `api/api-paths.ts` e respostas em `api/handle-api-response.ts` -- Auth via AuthProvider + cookies; não criar slices Redux para sessão +- Centralize paths in `api/api-paths.ts` and responses in `api/handle-api-response.ts` +- Auth via AuthProvider + cookies; do not create Redux slices for session -## Estado e dados +## State and data -- Cache e mutations: React Query + `infra/query-key/query-key.ts` -- Defaults do client em `lib/query/query-client.ts` +- Cache and mutations: React Query + `infra/query-key/query-key.ts` +- Client defaults in `lib/query/query-client.ts` -## Forms e UI +## Forms and UI -- Schemas Zod em `domain//schemas/`; views finas em `app/` -- Tailwind utilitário + componentes MUI; **não** importar `site.css` em código novo +- Zod schemas in `domain//schemas/`; thin views in `app/` +- Utility Tailwind + MUI components; **do not** import `site.css` in new code -## Fluxo ao implementar feature +## Feature implementation flow -1. Consultar legado em `pages//` (endpoints, campos, regras) -2. Criar `domain//` (schemas, hooks, use-cases) -3. View fina em `app/` + rota em `app/routes.tsx` -4. Deletar `pages//` quando a feature nova estiver pronta +1. Consult legacy in `pages//` (endpoints, fields, rules) +2. Create `domain//` (schemas, hooks, use-cases) +3. Thin view in `app/` + route in `app/routes.tsx` +4. Delete `pages//` when the new feature is ready ## Tooling -- ESLint strict só em `.ts/.tsx` da arquitetura nova; legado em `pages/` ignorado +- Strict ESLint only on new architecture `.ts/.tsx`; legacy in `pages/` ignored - Commits: Conventional Commits (`feat(scope): subject`) -Referência: `docs/ARCHITECTURE_PLAN.md` +Reference: `docs/ARCHITECTURE_PLAN.md` diff --git a/docs/ARCHITECTURE_PLAN.md b/docs/ARCHITECTURE_PLAN.md index 27c4651b..57a583b7 100644 --- a/docs/ARCHITECTURE_PLAN.md +++ b/docs/ARCHITECTURE_PLAN.md @@ -1,53 +1,53 @@ -# Plano de Arquitetura — SeaHaven (Rebuild Seletivo) +# Architecture Plan — SeaHaven (Selective Rebuild) -> Alinhamento com IrisLoan.Admin · SPA Vite + React Router · **sem Next.js** · Tailwind + MUI +> Aligned with IrisLoan.Admin · Vite SPA + React Router · **no Next.js** · Tailwind + MUI -Documento espelho do plano Cursor. Estratégia: **reaproveitar conhecimento, descartar código legado** — não normalizar/refatorar o projeto atual. +Mirror document of the Cursor plan. Strategy: **reuse knowledge, discard legacy code** — do not normalize/refactor the current project. --- -## Estratégia em uma frase +## Strategy in one sentence -Montar `api/` + `domain/` + `app/` do zero; usar `pages/` apenas como **referência de endpoints e regras**; **deletar** cada pasta legada quando a feature nova estiver pronta. +Build `api/` + `domain/` + `app/` from scratch; use `pages/` only as **endpoint and business rule reference**; **delete** each legacy folder when the new feature is ready. --- -## Matriz: Manter vs Descartar +## Matrix: Keep vs Discard -### Salvar (extrair lógica → código novo) +### Keep (extract logic → new code) -| Legado | Salvar | Destino | -| ------------------------------------- | --------------------------------- | ------------------------------------------------ | -| `lib/api/services.js` | Paths ASP.NET + parse de resposta | `api/api-paths.ts`, `api/handle-api-response.ts` | -| `pages/*/api.js` | Endpoints reais | `api/api-paths.ts` | -| `constants/queryKeys.js` | Entidades | `infra/query-key/query-key.ts` | -| `hooks/useDebounce.js`, `useModal.js` | Hooks | `hooks/*.ts` | -| `hooks/api/usePMSchedules.js` | Padrão RQ | Template `domain/*/use-cases/` | -| `lib/queryClient.js` | Defaults cache | `lib/query/query-client.ts` | -| `App.js`, `Sidebar.js` | Rotas e menu | `app/routes.tsx`, `config/menu.ts` | -| `pages/workorders/` (list) | Fluxo de negócio | Referência para POC | +| Legacy | Keep | Destination | +| ------------------------------------- | -------------------------------- | ------------------------------------------------ | +| `lib/api/services.js` | ASP.NET paths + response parsing | `api/api-paths.ts`, `api/handle-api-response.ts` | +| `pages/*/api.js` | Real endpoints | `api/api-paths.ts` | +| `constants/queryKeys.js` | Entities | `infra/query-key/query-key.ts` | +| `hooks/useDebounce.js`, `useModal.js` | Hooks | `hooks/*.ts` | +| `hooks/api/usePMSchedules.js` | RQ pattern | Template `domain/*/use-cases/` | +| `lib/queryClient.js` | Cache defaults | `lib/query/query-client.ts` | +| `App.js`, `Sidebar.js` | Routes and menu | `app/routes.tsx`, `config/menu.ts` | +| `pages/workorders/` (list) | Business flow | Reference for POC | -### Descartar (apagar sem refatorar) +### Discard (delete without refactoring) - `apiUtil.js`, `services/api.js`, `lib/api/client.js` - `tokenUtility.js`, `authService.js`, Redux (`app/store.js`, slices) -- `usePaginatedList.js`, toda pasta `pages/` (após substituição) -- `Site.Layout.js`, `setupProxy.js`, `site.css`, CSS por feature, Font Awesome -- Forms `*FormPage.js` (reescrever com RHF + Zod) -- `SharedTable.js`, `ActionBar.js` (recriar se adaptar for caro) +- `usePaginatedList.js`, entire `pages/` folder (after replacement) +- `Site.Layout.js`, `setupProxy.js`, `site.css`, per-feature CSS, Font Awesome +- Forms `*FormPage.js` (rewrite with RHF + Zod) +- `SharedTable.js`, `ActionBar.js` (recreate if adapting is costly) -### Adiar (later) +### Defer (later) - `pages/vendor-portal/` → `domain/vendor-portal/` -- `pages/calendar/` → wrapper FullCalendar novo +- `pages/calendar/` → new FullCalendar wrapper --- -## Prioridade de features +## Feature priority -Matriz completa (waves, dependências, LOC, critérios de done): **[`FEATURE_PRIORITIZATION.md`](FEATURE_PRIORITIZATION.md)** · config TS: [`src/config/feature-priorities.ts`](../src/config/feature-priorities.ts). +Full matrix (waves, dependencies, LOC, done criteria): **[`FEATURE_PRIORITIZATION.md`](FEATURE_PRIORITIZATION.md)** · TS config: [`src/config/feature-priorities.ts`](../src/config/feature-priorities.ts). -| Wave | Escopo | +| Wave | Scope | | ----------------- | --------------------------------------------------------------------------- | | **0 POC** | auth → work-orders (list) | | **1 must-have** | work-orders (full), dashboard, settings/dropdowns | @@ -55,11 +55,11 @@ Matriz completa (waves, dependências, LOC, critérios de done): **[`FEATURE_PRI | **3 should-have** | vendors, vendor-pos, uplifts, follow-ups, contacts, settings/task-templates | | **4 later** | calendar, vendor-portal, pm-schedules, assets, reports/documents | -Decisão stakeholder: **auth + work-orders primeiro**; POC = auth + work-orders list (não pm-schedules). +Stakeholder decision: **auth + work-orders first**; POC = auth + work-orders list (not pm-schedules). --- -## Estrutura alvo +## Target structure ``` src/ @@ -77,26 +77,26 @@ src/ --- -## Fases +## Phases -| Fase | Objetivo | -| ----- | --------------------------------------------------------------------------------------- | -| **0** | Completar fundação (Ky, routes, layout, AuthProvider, tooling) — Vite/TS/Tailwind já ok | -| **1** | Ky + auth cookies httpOnly; deletar stacks HTTP legadas | -| **2** | Reescrever features must-have; delete `pages//` por entrega | -| **3** | Shell UI + forms RHF+Zod | -| **4** | Apagar `pages/`, Redux, CSS legado; Docker + CI + Vitest | +| Phase | Goal | +| ----- | ------------------------------------------------------------------------------------- | +| **0** | Complete foundation (Ky, routes, layout, AuthProvider, tooling) — Vite/TS/Tailwind ok | +| **1** | Ky + httpOnly auth cookies; delete legacy HTTP stacks | +| **2** | Rewrite must-have features; delete `pages//` per delivery | +| **3** | UI shell + RHF+Zod forms | +| **4** | Remove `pages/`, Redux, legacy CSS; Docker + CI + Vitest | --- -## Próximos passos +## Next steps -1. Completar fundação (`api/api.ts`, `routes.tsx`, AuthProvider, layout shell) -2. `api/api-paths.ts` (extrair de `lib/api/services.js`) +1. Complete foundation (`api/api.ts`, `routes.tsx`, AuthProvider, layout shell) +2. `api/api-paths.ts` (extract from `lib/api/services.js`) 3. POC: `domain/auth` + login → delete `pages/auth/` -4. POC: `domain/work-orders` (list) → delete trecho list de `pages/workorders/` -5. Contrato cookies com backend +4. POC: `domain/work-orders` (list) → delete list portion of `pages/workorders/` +5. Cookie contract with backend --- -Ver plano completo com diagramas em `.cursor/plans/migração_arquitetura_irisloan_cf39e1a6.plan.md`. +See full plan with diagrams in `.cursor/plans/migração_arquitetura_irisloan_cf39e1a6.plan.md`. diff --git a/docs/FEATURE_PRIORITIZATION.md b/docs/FEATURE_PRIORITIZATION.md index 32876efd..bc97714b 100644 --- a/docs/FEATURE_PRIORITIZATION.md +++ b/docs/FEATURE_PRIORITIZATION.md @@ -1,24 +1,24 @@ -# Matriz de Priorização de Features — SeaHaven +# Feature Prioritization Matrix — SeaHaven -> Fonte de verdade para ordem de migração legado → `domain/` + `app/`. -> Config machine-readable: [`src/config/feature-priorities.ts`](../src/config/feature-priorities.ts). +> Source of truth for legacy → `domain/` + `app/` migration order. +> Machine-readable config: [`src/config/feature-priorities.ts`](../src/config/feature-priorities.ts). --- -## Decisões de stakeholders +## Stakeholder decisions -| Decisão | Detalhe | -| ------------------- | -------------------------------------------------------------------------------------- | -| Prioridade absoluta | **`auth`** e **`work-orders`** | -| POC end-to-end | **`auth` + work-orders (list)** — validar Ky, React Query, layout shell e AuthProvider | -| Demais features | Ordem flexível, guiada por dependências técnicas (waves abaixo) | -| POC **não** inclui | `pm-schedules` (adiado para Wave 4) | +| Decision | Detail | +| ------------------------ | ----------------------------------------------------------------------------------------- | +| Top priority | **`auth`** and **`work-orders`** | +| End-to-end POC | **`auth` + work-orders (list)** — validate Ky, React Query, layout shell and AuthProvider | +| Other features | Flexible order, guided by technical dependencies (waves below) | +| POC **does not** include | `pm-schedules` (deferred to Wave 4) | --- -## Matriz completa +## Full matrix -| Ordem | Feature | Tier | Wave | Pasta legado | Rotas | LOC ~ | Dependências | +| Order | Feature | Tier | Wave | Legacy folder | Routes | LOC ~ | Dependencies | | ----- | ------------------------- | ----------- | ---- | ----------------------------------- | ----------------------------------------------------------------------------- | ------ | ---------------------------------------------------------------------------- | | 1 | auth | POC | 0 | `pages/auth/` | `/login` | 513 | — | | 2 | work-orders (list) | POC | 0 | `pages/workorders/` (list) | `/workorders` | 4.3k\* | auth | @@ -38,26 +38,26 @@ | 16 | vendor-portal | later | 4 | `pages/vendor-portal/` | `/v/:token`, `/v/:token/dashboard`, `/v/:token/pos`, `/v/:token/dispatch/:id` | 1.4k | auth, vendors | | 17 | pm-schedules | later | 4 | `pages/PmSchedule/` | `/pmschedules`, `/pmschedules/new`, `/pmschedules/edit/:id` | 1.1k | auth | | 18 | assets | later | 4 | `pages/assets/` | `/assets`, `/assets/new`, `/assets/edit/:id` | 638 | auth, accounts | -| 19 | reports / documents | later | 4 | — (sem implementação) | `/reports`, `/documents` (menu apenas) | — | auth | +| 19 | reports / documents | later | 4 | — (no implementation) | `/reports`, `/documents` (menu only) | — | auth | -\* LOC da pasta inteira; escopo POC usa somente o submódulo de listagem. +\* LOC for the entire folder; POC scope uses only the list submodule. -### Complexidade legada (referência) +### Legacy complexity (reference) -| Feature | Complexidade | Observação | -| ------------- | ------------ | ----------------------------------------------------------- | -| auth | Baixa | Substituir Redux/`tokenUtility` por AuthProvider + cookies | -| dashboard | Média | KPIs reais via `GET /Dashboard/Stats` | -| work-orders | **Alta** | View monolítica; dispatch, checklist, signoff | -| contacts | Alta | Form legado **stub** (save TODO) — reescrever com RHF + Zod | -| employees | Alta | Form grande | -| vendor-portal | Alta | Auth por token URL + assinatura | -| calendar | Alta | Wrapper FullCalendar | -| pm-schedules | Média | Bugs API legados (`PmSchedule/Create` vs `Save`) | +| Feature | Complexity | Notes | +| ------------- | ---------- | --------------------------------------------------------- | +| auth | Low | Replace Redux/`tokenUtility` with AuthProvider + cookies | +| dashboard | Medium | Real KPIs via `GET /Dashboard/Stats` | +| work-orders | **High** | Monolithic view; dispatch, checklist, signoff | +| contacts | High | Legacy form **stub** (save TODO) — rewrite with RHF + Zod | +| employees | High | Large form | +| vendor-portal | High | URL token auth + signature | +| calendar | High | FullCalendar wrapper | +| pm-schedules | Medium | Legacy API bugs (`PmSchedule/Create` vs `Save`) | --- -## Grafo de dependências +## Dependency graph ```mermaid flowchart TD @@ -102,7 +102,7 @@ flowchart TD woFull --> uplifts ``` -### Waves (resumo) +### Waves (summary) | Wave | Tier | Features | | ----- | ----------- | --------------------------------------------------------------------------- | @@ -112,49 +112,49 @@ flowchart TD | **3** | should-have | vendors, vendor-pos, uplifts, follow-ups, contacts, settings/task-templates | | **4** | later | calendar, vendor-portal, pm-schedules, assets, reports/documents | -> `accounts` e `locations` podem avançar em paralelo à view de WO se a list POC usar dados já existentes no backend; a ordem acima é a sequência mínima para o form completo de WO. +> `accounts` and `locations` can progress in parallel with the WO view if the list POC uses data already available in the backend; the order above is the minimum sequence for the full WO form. --- -## Gaps e cleanup do legado +## Legacy gaps and cleanup -| Item | Local | Ação na migração | -| ------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| Dashboard duplicado | `pages/dashboard/` (protótipo mock) | **Não roteado** — ignorar; usar apenas `pages/Dashboard.js` como referência | -| Login órfão | `pages/user/api.js` | Deletar na Fase 1 (Ky + auth); duplica fluxo de `pages/auth/` | -| Menu fantasma | `Sidebar.js` → Reports `/reports`, Documents `/documents` | Sem rotas nem páginas — implementar do zero (Wave 4) ou remover do menu em `config/menu.ts` | -| Contacts form incompleto | `pages/contacts/form/` | Não portar stub; reescrever com RHF + Zod na Wave 3 | -| PM schedules API | `pages/PmSchedule/` | Documentar inconsistência Create vs Save; corrigir na reescrita | +| Item | Location | Migration action | +| ------------------------ | --------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| Duplicate dashboard | `pages/dashboard/` (mock prototype) | **Not routed** — ignore; use only `pages/Dashboard.js` as reference | +| Orphan login | `pages/user/api.js` | Delete in Phase 1 (Ky + auth); duplicates `pages/auth/` flow | +| Ghost menu | `Sidebar.js` → Reports `/reports`, Documents `/documents` | No routes or pages — implement from scratch (Wave 4) or remove from menu in `config/menu.ts` | +| Incomplete contacts form | `pages/contacts/form/` | Do not port stub; rewrite with RHF + Zod in Wave 3 | +| PM schedules API | `pages/PmSchedule/` | Document Create vs Save inconsistency; fix in rewrite | --- -## Critérios de "done" por feature +## "Done" criteria per feature -Uma feature está **done** quando todos os itens abaixo forem atendidos: +A feature is **done** when all items below are met: -1. **`domain//`** — schemas Zod, hooks/use-cases, tipos; sem imports de `pages/`, Redux, axios ou `apiUtil` -2. **`app/`** — views finas (list, form, view conforme escopo) registradas em `app/routes.tsx` -3. **`api/api-paths.ts`** — endpoints da feature centralizados; respostas via `handle-api-response.ts` -4. **`infra/query-key/query-key.ts`** — query keys da feature -5. **Rota protegida** — navegação via `config/menu.ts` (quando aplicável à wave) -6. **Delete legado** — pasta `pages//` (ou arquivos equivalentes) removida após validação -7. **Sem regressão** — fluxo principal testado manualmente ou com Vitest (quando existir) +1. **`domain//`** — Zod schemas, hooks/use-cases, types; no imports from `pages/`, Redux, axios or `apiUtil` +2. **`app/`** — thin views (list, form, view as scoped) registered in `app/routes.tsx` +3. **`api/api-paths.ts`** — feature endpoints centralized; responses via `handle-api-response.ts` +4. **`infra/query-key/query-key.ts`** — feature query keys +5. **Protected route** — navigation via `config/menu.ts` (when applicable to the wave) +6. **Delete legacy** — `pages//` folder (or equivalent files) removed after validation +7. **No regression** — main flow tested manually or with Vitest (when available) -### Done por escopo especial +### Done criteria for special scope -| Escopo | Critério adicional | +| Scope | Additional criterion | | ------------------------ | ---------------------------------------------------------------------------------- | -| **POC auth** | Login/logout com cookies httpOnly; `AuthProvider` substitui Redux + `tokenUtility` | -| **POC work-orders list** | Listagem paginada/filtrada com Ky + RQ; sem form/view nesta entrega | -| **work-orders full** | Form + view (dispatch, checklist, signoff) funcionais | -| **settings/dropdowns** | Dropdowns Problem/Trade/SubTrade disponíveis para WO form | -| **reports/documents** | Decisão explícita: implementar feature ou remover links do menu | +| **POC auth** | Login/logout with httpOnly cookies; `AuthProvider` replaces Redux + `tokenUtility` | +| **POC work-orders list** | Paginated/filtered list with Ky + RQ; no form/view in this delivery | +| **work-orders full** | Form + view (dispatch, checklist, signoff) functional | +| **settings/dropdowns** | Problem/Trade/SubTrade dropdowns available for WO form | +| **reports/documents** | Explicit decision: implement feature or remove menu links | --- -## Referências +## References -- Plano de arquitetura: [`ARCHITECTURE_PLAN.md`](ARCHITECTURE_PLAN.md) -- Convenções IrisLoan: `.cursor/rules/seahaven-admin.mdc` -- Rotas legado: `src/App.js` -- Menu legado: `src/components/Sidebar.js` +- Architecture plan: [`ARCHITECTURE_PLAN.md`](ARCHITECTURE_PLAN.md) +- IrisLoan conventions: `.cursor/rules/seahaven-admin.mdc` +- Legacy routes: `src/App.js` +- Legacy menu: `src/components/Sidebar.js`