Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .claude/skills/nova-tab/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Cria a interface completa de uma etapa do fluxo do `Project` (Tab + Schemas), no

Pergunte ao usuário (ou infira do pedido):

- **Nome da etapa em inglês, PascalCase** — ex. `Payment`, `Inspection`. Define os nomes de arquivos (`<Etapa>Tab.vue`, `Schemas/<Etapa>/`).
- **Nome da etapa em inglês, PascalCase** — ex. `Payment`, `Inspection`. Define os nomes de arquivos (`<Etapa>Tab.vue`, identificador da tab no catálogo de visualização e export `<etapa>FormSections`).
- **Nome da relação no model `Project`** — ex. `payment`. Define `props.project.<relacao>` e os nomes de rotas (`projects.<relacao>.store|update`).

Depois confira se o backend já existe:
Expand All @@ -30,13 +30,13 @@ Estes arquivos do repo são a fonte de verdade do padrão. Leia todos:
|---|---|
| `resources/js/Pages/ProjectDetails/Partials/Tabs/FormalizationTab.vue` | Tab completa: useForm, init no onMounted, validação, upload, submit, tramitação |
| `resources/js/Pages/ProjectDetails/Partials/Tabs/MonitoringTab.vue` | Tab que consome viewSections via SectionContent |
| `resources/js/Schemas/Monitoring/viewSections.js` | Estrutura de campos `{label, key|compute, format}` e uso do useDate |
| `resources/js/Schemas/Monitoring/formSections.js` e `index.js` | formSections `{title, key}` e barrel export |
| `resources/js/Schemas/viewSections.js` | Estrutura de campos `{label, key|compute, format}` e uso do useDate |
| `resources/js/Schemas/formSections.js` | formSections `{title, key}` com exports por etapa |
| `resources/js/Components/SplitScreenTab.vue`, `SectionContent.vue`, `SectionForm.vue`, `SectionChips.vue` | Contrato de props e slots |

## Passo 3 — Criar os Schemas

Criar `resources/js/Schemas/<Etapa>/`:
Editar os dois arquivos únicos em `resources/js/Schemas/`; não criar cópias por etapa:

1. **`viewSections.js`** — array de seções `{ title, fields: [...] }`. Cada field:
- `{ label: 'Texto em português', key: 'relacao.campo' }` — acesso por dot notation
Expand All @@ -45,8 +45,8 @@ Criar `resources/js/Schemas/<Etapa>/`:
- `addDaysTo('campo', dias)` — data + N dias (combine com `format: 'datetime'`)
- `daysBetween('relacao.inicio', 'relacao.fim')` — dias entre duas datas
- Exceção conhecida: a relação de **Formalization** chama-se **`formalizations`** (plural, mesmo sendo `HasOne`) no JSON — use esse nome só para essa etapa. Para todas as outras etapas, use o nome de relação definido com o usuário no Passo 1 (`props.project.<relacao>`), nunca `formalizations`.
2. **`formSections.js`** — `export const formSections = [{ title: '...', key: 'slug-da-secao' }]`
3. **`index.js`** — barrel export: `export { viewSections } from './viewSections'; export { formSections } from './formSections';`
2. **`formSections.js`** — `export const <etapa>FormSections = [{ title: '...', key: 'slug-da-secao' }]`
3. No catálogo `viewSections`, cada seção tem `key` único e `tabs` com as etapas pertinentes. Reutilizar seções existentes adicionando a etapa a `tabs`. Na Tab, usar `import { getViewSections } from '@/Schemas/viewSections';` e `const viewSections = getViewSections('<etapa>');`. A ordem segue o catálogo. Importar o array de formulário com alias `formSections`.

## Passo 4 — Criar a Tab

Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ Dois workers separados por responsabilidade:

### Tabs de etapa e Schemas

As telas de cada etapa do Project são Tabs em `resources/js/Pages/ProjectDetails/Partials/Tabs/` (registradas em `ProcessTabs.vue`), construídas sobre `SplitScreenTab` + `SectionChips` + `SectionContent` (visualização) + `SectionForm` (edição). Os campos exibidos/editados são declarados em Schemas (`resources/js/Schemas/<Etapa>/`):
As telas de cada etapa do Project são Tabs em `resources/js/Pages/ProjectDetails/Partials/Tabs/` (registradas em `ProcessTabs.vue`), construídas sobre `SplitScreenTab` + `SectionChips` + `SectionContent` (visualização) + `SectionForm` (edição). Os campos exibidos/editados são declarados em Schemas (`resources/js/Schemas/`):

- `viewSections.js` — seções `{ title, fields }`; cada field usa `{ label, key }` (dot notation) ou `{ label, compute }` para valores calculados.
- `formSections.js` — `{ title, key }`; o `SectionForm` renderiza um slot por `section.key`.
- `index.js` — barrel export.
Cada arquivo é único no projeto. `viewSections.js` exporta um catálogo de seções com `key` e `tabs`; cada Tab usa `getViewSections('opening')` (ou sua etapa) para selecionar as seções pertinentes na ordem do catálogo. Reutilizar as seções compartilhadas e preservar variantes quando os campos diferirem. `formSections.js` exporta arrays por etapa (ex.: `openingFormSections`), importados com o alias `formSections`. Não criar cópias em pastas por etapa.

Para datas nos Schemas, usar o composable `useDate`: `getDate(key)` formata, `addDaysTo(key, dias)` soma dias, `daysBetween(startKey, endKey)` retorna o intervalo em dias.

Expand Down
2 changes: 1 addition & 1 deletion docs/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ As skills ficam em `.claude/skills/` na raiz do projeto:

| Skill | Quando usar | O que faz |
|---|---|---|
| `/nova-tab` | Criar a tela de uma nova etapa do fluxo do Project (ex.: PaymentTab) | Cria `Schemas/<Etapa>/` (viewSections, formSections, index), a `<Etapa>Tab.vue` no padrão SplitScreenTab e registra no `ProcessTabs.vue`. Se o backend da etapa não existir, oferece o fluxo guiado do `checklist-backend.md` |
| `/nova-tab` | Criar a tela de uma nova etapa do fluxo do Project (ex.: PaymentTab) | Configura a visibilidade da etapa no catálogo `Schemas/viewSections.js` e adiciona seu export em `Schemas/formSections.js`, a `<Etapa>Tab.vue` no padrão SplitScreenTab e registra no `ProcessTabs.vue`. Se o backend da etapa não existir, oferece o fluxo guiado do `checklist-backend.md` |
| `/novo-componente` | Criar componente Vue reutilizável em `resources/js/Components/` | Verifica se já existe componente similar (prefere estender/compor), usa `TextField.vue`/`FormField.vue` como referência e aplica o checklist (props tipadas, v-model, Vuetify outlined + Tailwind) |
| `/novo-composable` | Extrair lógica reutilizável para `resources/js/Composables/` | Confere os 12 composables existentes para não duplicar (ex.: nova função de data vai no `useDate`, não num composable novo), segue o padrão `export function useXxx()` |
| `/tratamento-erros` | Lançar/capturar erros, criar Service/Controller novo, tratar erro de API no Vue | Aplica a hierarquia `AppException` (backend) e o padrão `useErrorHandler` (frontend) descritos em `docs/error_handling.md` |
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Components/DocumentViewerDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { computed } from 'vue';
import DocumentDownloadMenu from '@/Components/DocumentDownloadMenu.vue';
import SanitizedHtml from '@/Components/SanitizedHtml.vue';
import { getBudgetAllocation } from '@/Schemas/getBudgetAllocation';
import { getBudgetAllocation } from '@/Schemas/schemaUtils';

const props = defineProps({
modelValue: { type: Boolean, default: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ import TextField from '@/Components/TextField.vue';
import TramitButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/TramitButton.vue';
import SaveButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/SaveButton.vue';

import { viewSections, formSections } from '@/Schemas/Budget';
import { getViewSections } from '@/Schemas/viewSections';
import { budgetFormSections as formSections } from '@/Schemas/formSections';

import { useDate } from '@/Composables/useDate';
import { useSnackbar } from '@/Composables/useSnackbar';
import { useAlert } from '@/Composables/useAlert';
import { useSaveShortcut } from '@/Composables/useSaveShortcut';
import { useStageAdvance } from '@/Composables/useStageAdvance';

const viewSections = getViewSections('budget');

const props = defineProps({
project: { type: Object, required: true },
canReturn: { type: Boolean, default: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import SelectField from '@/Components/SelectField.vue';
import TramitButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/TramitButton.vue';
import SaveButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/SaveButton.vue';

import { viewSections } from '@/Schemas/Opening';
import { formSections } from '@/Schemas/Formalization';
import { getViewSections } from '@/Schemas/viewSections';
import { formalizationFormSections as formSections } from '@/Schemas/formSections';

import { useDate } from '@/Composables/useDate';
import { useSnackbar } from '@/Composables/useSnackbar';
Expand All @@ -25,6 +25,8 @@ import { useSaveShortcut } from '@/Composables/useSaveShortcut';
import { useStageAdvance } from '@/Composables/useStageAdvance';
import { useAuth } from '@/Composables/useAuth';

const viewSections = getViewSections('formalization');

const props = defineProps({
project: { type: Object, required: true },
canReturn: { type: Boolean, default: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import StepActions from '@/Components/StepActions.vue';
import DocumentEvaluationList from '@/Components/DocumentEvaluationList.vue';
import ReturnProcessAction from '@/Components/ReturnProcessAction.vue';
import TramitButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/TramitButton.vue';
import { viewSections } from '@/Schemas/Opening';
import { getViewSections } from '@/Schemas/viewSections';
import { useLegalAnalysis } from '@/Composables/useLegalAnalysis';
import { useStageAdvance } from '@/Composables/useStageAdvance';

const viewSections = getViewSections('legalAnalysis');

const props = defineProps({
project: { type: Object, required: true },
canReturn: { type: Boolean, default: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import ReturnProcessAction from '@/Components/ReturnProcessAction.vue';
import DiligenceChat from '@/Components/DiligenceChat.vue';
import TramitButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/TramitButton.vue';
import SaveButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/SaveButton.vue';
import { viewSections, formSections } from '@/Schemas/Monitoring';
import { getViewSections } from '@/Schemas/viewSections';
import { monitoringFormSections as formSections } from '@/Schemas/formSections';
import { useSnackbar } from '@/Composables/useSnackbar';
import { useAlert } from '@/Composables/useAlert';
import { sanitizeExternalUrl } from '@/Composables/useExternalLink';
import { useAuth } from '@/Composables/useAuth';
import { useStageAdvance } from '@/Composables/useStageAdvance';

const viewSections = getViewSections('monitoring');

const props = defineProps({
project: { type: Object, required: true },
canReturn: { type: Boolean, default: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import SectionChips from '@/Components/SectionChips.vue';
import SectionContent from '@/Components/SectionContent.vue';
import SectionForm from '@/Components/SectionForm.vue';
import AuxLinks from '@/Components/AuxLinks.vue';
import { getViewSections } from '@/Schemas/viewSections';
import { openingFormSections as formSections } from '@/Schemas/formSections';
import StepActions from '@/Components/StepActions.vue';
import { viewSections, formSections } from '@/Schemas/Opening';
import { router, useForm } from '@inertiajs/vue3';
import { onMounted } from 'vue';
import { useSnackbar } from '@/Composables/useSnackbar';
Expand All @@ -22,6 +23,8 @@ import { useSaveShortcut } from '@/Composables/useSaveShortcut';
import { useMask } from '@/Composables/useMask';
import { useStageAdvance } from '@/Composables/useStageAdvance';

const viewSections = getViewSections('opening');

const { showSnackbar } = useSnackbar();
const { normalizeDate } = useDate();
const { showAlert } = useAlert();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ import StepActions from '@/Components/StepActions.vue';
import TramitButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/TramitButton.vue';
import SaveButton from '@/Pages/ProjectDetails/Partials/Tabs/Actions/SaveButton.vue';

import { viewSections, formSections } from '@/Schemas/Payment';
import { getViewSections } from '@/Schemas/viewSections';
import { paymentFormSections as formSections } from '@/Schemas/formSections';

import { useDate } from '@/Composables/useDate';
import { useSnackbar } from '@/Composables/useSnackbar';
import { useAlert } from '@/Composables/useAlert';
import { useInstallmentStatus } from '@/Composables/useInstallments';
import { useStageAdvance } from '@/Composables/useStageAdvance';

const viewSections = getViewSections('payment');

const props = defineProps({
project: {
type: Object,
Expand Down
5 changes: 0 additions & 5 deletions resources/js/Schemas/Budget/formSections.js

This file was deleted.

4 changes: 0 additions & 4 deletions resources/js/Schemas/Budget/index.js

This file was deleted.

88 changes: 0 additions & 88 deletions resources/js/Schemas/Budget/viewSections.js

This file was deleted.

7 changes: 0 additions & 7 deletions resources/js/Schemas/Formalization/formSections.js

This file was deleted.

3 changes: 0 additions & 3 deletions resources/js/Schemas/Formalization/index.js

This file was deleted.

4 changes: 0 additions & 4 deletions resources/js/Schemas/Monitoring/formSections.js

This file was deleted.

2 changes: 0 additions & 2 deletions resources/js/Schemas/Monitoring/index.js

This file was deleted.

Loading
Loading