Commit inicial - upload de todos os arquivos da pasta
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-07-24
|
||||
@@ -0,0 +1,33 @@
|
||||
## Context
|
||||
|
||||
`fiscal_documents` já possui a coluna `categoria_id` (FK nullable para `categoria`), preenchida hoje apenas no fluxo de importação em lote (`confirm_batch`, auto-categorização por palavra-chave). O cadastro manual (`/documents/new`) e as duas telas de listagem (Dashboard "Últimos documentos" e `/documents`) não expõem categoria. Não há ORM — o acesso a dados é feito com `sqlite3` puro em `app/database.py`. O padrão de select populado a partir de tabela já existe no filtro de categoria da Dashboard (`list_categorias`, ordenado por `id ASC`).
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Permitir escolher a categoria ao criar um documento manualmente em `/documents/new`.
|
||||
- Persistir essa escolha em `fiscal_documents.categoria_id`.
|
||||
- Exibir a coluna "Categoria" (nome, não id) logo após "Fornecedor" nas tabelas da Dashboard e de `/documents`.
|
||||
- Ordenar o select de categorias por nome (`categoria` ASC), não por `id`, para facilitar a localização pelo usuário.
|
||||
|
||||
**Non-Goals:**
|
||||
- Não altera o fluxo de auto-categorização por palavra-chave já existente em `confirm_batch`.
|
||||
- Não adiciona edição de categoria em documentos já existentes fora do formulário atual (sem tela de edição dedicada nesta mudança, a menos que já exista `update_fiscal` chamada por uma tela de edição — nesse caso o mesmo campo é reaproveitado).
|
||||
- Não altera o schema do banco (coluna já existe).
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **Ordenação do select por nome, não por id**: `list_categorias` atual faz `ORDER BY id ASC`. Para o novo select em `/documents/new` será usada uma consulta (nova função `list_categorias_ordenadas_por_nome` ou parâmetro de ordenação em `list_categorias`) com `ORDER BY categoria ASC`, conforme pedido explícito do usuário. Optamos por não alterar o `ORDER BY` do `list_categorias` existente (usado no filtro da Dashboard) para não mudar comportamento não solicitado; em vez disso adicionamos uma variante/parâmetro.
|
||||
2. **Exposição do nome da categoria nas listagens via LEFT JOIN**: em vez de fazer uma segunda query por linha (N+1), a consulta usada por Dashboard e `/documents` (`list_fiscal` ou equivalente) passa a fazer `LEFT JOIN categoria ON fiscal_documents.categoria_id = categoria.id`, trazendo `categoria.categoria AS categoria_nome`. LEFT JOIN (não INNER) para não esconder documentos sem categoria.
|
||||
3. **Campo opcional no formulário**: o `<select name="categoria_id">` inclui uma opção vazia/"Sem categoria" para não obrigar o usuário a categorizar manualmente, mantendo compatibilidade com documentos sem categoria.
|
||||
4. **Reuso de `create_fiscal`/`update_fiscal`**: adicionar parâmetro opcional `categoria_id=None` a essas funções em vez de criar novas funções, minimizando duplicação.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Alterar `list_fiscal` para incluir JOIN pode impactar outros chamadores que dependem do shape atual do retorno (linha como tupla/Row)] → Mitigação: adicionar apenas colunas extras ao final do SELECT (não remover/reordenar colunas existentes) e verificar todos os call sites de `list_fiscal` antes de alterar.
|
||||
- [Footer com colspan fixo em `documents_list.html` pode quebrar visualmente ao adicionar coluna] → Mitigação: ajustar o colspan do footer/total ao adicionar a nova `<th>`.
|
||||
- [Usuário pode confundir "Sem categoria" com a categoria "Não Encontrado" (id=1) já existente] → Mitigação: usar valor vazio (NULL) para "Sem categoria" no select, distinto da categoria seedada "Não Encontrado".
|
||||
|
||||
## Migration Plan
|
||||
|
||||
Sem migração de dados necessária (coluna já existe). Deploy é apenas código: rotas, templates e função de listagem. Rollback trivial (reverter os arquivos alterados), pois nenhuma escrita de schema é feita.
|
||||
@@ -0,0 +1,26 @@
|
||||
## Why
|
||||
|
||||
Atualmente a categoria de um documento fiscal só é atribuída automaticamente durante a importação em lote (`confirm_batch`), com base em palavra-chave. Ao cadastrar um documento manualmente pela tela "Novo Documento" (`/documents/new`) não há como escolher a categoria, então o registro fica sempre com `categoria_id` nulo. Além disso, nem a Dashboard ("Últimos documentos") nem a listagem `/documents` exibem a categoria do lançamento, dificultando a conferência visual de como os documentos foram classificados.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Adicionar campo select "Categoria" ao formulário de novo documento (`/documents/new`), populado a partir da tabela `categoria` ordenada por nome (ASC), permitindo escolher a categoria no cadastro manual.
|
||||
- Persistir o `categoria_id` selecionado ao criar (e editar, quando aplicável) o documento fiscal, passando a informação para `create_fiscal`/`update_fiscal`.
|
||||
- Incluir coluna "Categoria" na tabela "Últimos documentos" do Dashboard, posicionada logo após a coluna "Fornecedor".
|
||||
- Incluir coluna "Categoria" na tabela de listagem da rota `/documents`, posicionada logo após a coluna "Fornecedor".
|
||||
- Ajustar a consulta de listagem de documentos (`list_fiscal` ou variante) para trazer o nome da categoria via LEFT JOIN com a tabela `categoria`, já que a consulta atual não expõe esse dado.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `document-categorization`: Cobre a seleção de categoria no formulário de novo documento e a persistência do vínculo documento-categoria.
|
||||
- `document-listing-category-column`: Cobre a exibição da coluna "Categoria" nas listagens de documentos (Dashboard "Últimos documentos" e rota `/documents`), logo após a coluna "Fornecedor".
|
||||
|
||||
### Modified Capabilities
|
||||
(nenhuma — não há specs existentes em `openspec/specs/`; os itens acima são tratados como novas capacidades)
|
||||
|
||||
## Impact
|
||||
|
||||
- **Código afetado**: `app/routes/documents_routes.py` (rota `/documents/new` e `create_document`), `app/templates/document_form.html`, `app/database.py` (`create_fiscal`, `update_fiscal`, `list_fiscal`, uso de `list_categorias`), `app/routes/dashboard_routes.py`, `app/templates/dashboard.html`, `app/templates/documents_list.html`.
|
||||
- **Banco de dados**: nenhuma alteração de schema — a coluna `fiscal_documents.categoria_id` já existe; apenas passa a ser preenchida também no fluxo manual.
|
||||
- **Compatibilidade**: campo "Categoria" no formulário é opcional (documentos sem categoria continuam válidos, exibindo "Não Encontrado" ou vazio); sem impacto em dados existentes.
|
||||
@@ -0,0 +1,19 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Seleção de categoria no cadastro de documento
|
||||
O formulário de novo documento, na rota `/documents/new`, SHALL exibir um campo select "Categoria" populado com todos os registros da tabela `categoria`, ordenados por nome (`categoria`) em ordem ascendente (ASC).
|
||||
|
||||
#### Scenario: Formulário exibe categorias ordenadas por nome
|
||||
- **WHEN** o usuário acessa a rota `/documents/new`
|
||||
- **THEN** o select "Categoria" é exibido com as opções carregadas da tabela `categoria`, ordenadas alfabeticamente (ASC) pelo campo `categoria`
|
||||
|
||||
#### Scenario: Campo categoria é opcional
|
||||
- **WHEN** o usuário envia o formulário de novo documento sem selecionar nenhuma categoria
|
||||
- **THEN** o documento é criado com sucesso e `categoria_id` fica nulo (sem categoria)
|
||||
|
||||
### Requirement: Persistência da categoria selecionada
|
||||
Ao submeter o formulário de novo documento com uma categoria selecionada, o sistema SHALL salvar o `id` da categoria escolhida no campo `categoria_id` do documento fiscal criado.
|
||||
|
||||
#### Scenario: Categoria selecionada é persistida
|
||||
- **WHEN** o usuário seleciona uma categoria no formulário e submete o novo documento
|
||||
- **THEN** o registro criado em `fiscal_documents` possui `categoria_id` igual ao id da categoria selecionada
|
||||
@@ -0,0 +1,23 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Coluna Categoria na Dashboard
|
||||
A tabela "Últimos documentos" da Dashboard SHALL exibir uma coluna "Categoria" posicionada imediatamente após a coluna "Fornecedor", mostrando o nome da categoria do documento (ou vazio/"Não Encontrado" quando não houver categoria associada).
|
||||
|
||||
#### Scenario: Coluna Categoria aparece após Fornecedor na Dashboard
|
||||
- **WHEN** o usuário acessa a Dashboard
|
||||
- **THEN** a tabela "Últimos documentos" exibe as colunas na ordem: Data, Fornecedor, Categoria, Valor (demais colunas mantidas), com "Categoria" logo após "Fornecedor"
|
||||
|
||||
#### Scenario: Documento sem categoria exibido corretamente
|
||||
- **WHEN** um documento listado na Dashboard possui `categoria_id` nulo
|
||||
- **THEN** a célula da coluna "Categoria" é exibida vazia ou com um indicador de "sem categoria", sem gerar erro
|
||||
|
||||
### Requirement: Coluna Categoria na listagem de documentos
|
||||
A tabela de listagem da rota `/documents` SHALL exibir uma coluna "Categoria" posicionada imediatamente após a coluna "Fornecedor", mostrando o nome da categoria do documento.
|
||||
|
||||
#### Scenario: Coluna Categoria aparece após Fornecedor em /documents
|
||||
- **WHEN** o usuário acessa a rota `/documents`
|
||||
- **THEN** a tabela de documentos exibe as colunas na ordem: Data, Fornecedor, Categoria, Valor, Origem, Ações (demais colunas mantidas), com "Categoria" logo após "Fornecedor"
|
||||
|
||||
#### Scenario: Documento sem categoria exibido corretamente em /documents
|
||||
- **WHEN** um documento listado em `/documents` possui `categoria_id` nulo
|
||||
- **THEN** a célula da coluna "Categoria" é exibida vazia ou com um indicador de "sem categoria", sem gerar erro
|
||||
@@ -0,0 +1,34 @@
|
||||
## 1. Camada de dados (app/database.py)
|
||||
|
||||
- [x] 1.1 Adicionar função (ou parâmetro) para listar categorias ordenadas por nome ASC (`ORDER BY categoria ASC`), reutilizando `list_categorias` como referência sem alterar seu comportamento atual.
|
||||
- [x] 1.2 Adicionar parâmetro opcional `categoria_id=None` em `create_fiscal` e persistir o valor no INSERT de `fiscal_documents`.
|
||||
- [x] 1.3 Adicionar parâmetro opcional `categoria_id` em `update_fiscal` (se existir fluxo de edição), persistindo no UPDATE.
|
||||
- [x] 1.4 Levantar todos os call sites de `list_fiscal` (ou função equivalente usada por Dashboard e `/documents`) e confirmar o shape de retorno atual antes de alterar.
|
||||
- [x] 1.5 Alterar a consulta usada pela listagem (`list_fiscal` ou variante) para incluir `LEFT JOIN categoria ON fiscal_documents.categoria_id = categoria.id`, adicionando `categoria.categoria AS categoria_nome` ao final do SELECT sem remover/reordenar colunas existentes.
|
||||
|
||||
## 2. Formulário de novo documento (/documents/new)
|
||||
|
||||
- [x] 2.1 Em `app/routes/documents_routes.py`, na rota GET de `/documents/new`, buscar a lista de categorias ordenadas por nome (via 1.1) e passar ao template.
|
||||
- [x] 2.2 Em `app/templates/document_form.html`, adicionar `<select name="categoria_id">` com opção vazia "Sem categoria" seguida das opções carregadas, próximo aos demais campos do formulário.
|
||||
- [x] 2.3 Na rota POST `create_document`, ler `categoria_id` do form (tratando string vazia como `None`) e repassar para `create_fiscal`.
|
||||
- [x] 2.4 Testar manualmente: criar documento sem categoria e criar documento com categoria selecionada; confirmar persistência via consulta ao banco.
|
||||
|
||||
## 3. Coluna Categoria na Dashboard
|
||||
|
||||
- [x] 3.1 Em `app/routes/dashboard_routes.py`, confirmar que os dados de "Últimos documentos" já incluem `categoria_nome` após a alteração da query (item 1.5); ajustar se necessário.
|
||||
- [x] 3.2 Em `app/templates/dashboard.html`, adicionar `<th>Categoria</th>` logo após `<th>Fornecedor</th>` no cabeçalho da tabela "Últimos documentos".
|
||||
- [x] 3.3 Adicionar a célula correspondente (`{{ item.categoria_nome or '' }}` ou equivalente) na mesma posição nas linhas da tabela.
|
||||
- [x] 3.4 Validar visualmente que a coluna aparece corretamente para documentos com e sem categoria, e que o restante do layout não quebra.
|
||||
|
||||
## 4. Coluna Categoria na listagem /documents
|
||||
|
||||
- [x] 4.1 Confirmar que a rota `/documents` (`list_documents`) já recebe `categoria_nome` via a query alterada (item 1.5).
|
||||
- [x] 4.2 Em `app/templates/documents_list.html`, adicionar `<th>Categoria</th>` logo após `<th>Fornecedor</th>` no cabeçalho.
|
||||
- [x] 4.3 Adicionar a célula correspondente na mesma posição nas linhas da tabela.
|
||||
- [x] 4.4 Ajustar o `colspan` do footer/linha de total, se existir, para refletir a coluna adicional.
|
||||
- [x] 4.5 Validar visualmente a listagem completa, incluindo documentos com e sem categoria.
|
||||
|
||||
## 5. Verificação final
|
||||
|
||||
- [x] 5.1 Rodar a aplicação localmente e testar o fluxo completo: cadastrar documento com categoria em `/documents/new`, confirmar exibição correta em `/documents` e na Dashboard.
|
||||
- [x] 5.2 Rodar a suíte de testes existente (`tests/`) e corrigir eventuais quebras relacionadas às funções alteradas em `database.py`.
|
||||
Reference in New Issue
Block a user