Reescrita dos geradores: biblioteca IGenerator, minimal API e novo frontend #1
71
GeradoresService/README.md
Normal file
71
GeradoresService/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# GeradoresService
|
||||
|
||||
Biblioteca .NET 10 com os algoritmos de geração e validação. Não tem dependências externas e é usada pela API
|
||||
([GeradoresWS](../GeradoresWS/README.md)) e pelos testes ([UnitTest](../UnitTest/README.md)).
|
||||
|
||||
## Estrutura
|
||||
|
||||
| Caminho | Conteúdo |
|
||||
|---|---|
|
||||
| `Core/IGenerator.cs` | Contrato de um gerador/validador e as categorias |
|
||||
| `Core/GeneratorBase.cs` | Classe base com valores por omissão e o helper `Option(...)` |
|
||||
| `Core/Models.cs` | `GeneratorOption`, `GeneratedItem`, `ValidationResult`, `GeneratorContext` |
|
||||
| `Core/Checksums.cs` | Algoritmos partilhados: módulo 11, Luhn (com letras), MOD 97-10, limpeza de input |
|
||||
| `Data/PtData.cs` | Nomes, apelidos, localidades, bancos e outros dados portugueses fictícios |
|
||||
| `Generators/<Categoria>/` | Um ficheiro por tipo |
|
||||
| `GeneratorRegistry.cs` | Lista de geradores, geração em lote e detecção automática do tipo |
|
||||
|
||||
## Geradores
|
||||
|
||||
| Id | Nome | Categoria | Validação |
|
||||
|---|---|---|---|
|
||||
| `nif` | NIF | Identificação | Módulo 11, pesos 9..2 |
|
||||
| `nipc` | NIPC | Identificação | Igual ao NIF, só prefixos de pessoa colectiva |
|
||||
| `niss` | NISS | Identificação | 9 − (Σ dígito × peso) mod 10, pesos 29, 23, 19, 17, 13, 11, 7, 5, 3, 2 |
|
||||
| `cc` | Cartão de Cidadão | Identificação | Módulo 11 no NIC + Luhn (A=10..Z=35) no documento |
|
||||
| `passaporte` | Passaporte | Identificação | Só formato (letra + 6 dígitos) |
|
||||
| `iban` | IBAN | Financeiro | ISO 7064 MOD 97-10; aceita IBAN de qualquer país |
|
||||
| `nib` | NIB | Financeiro | 98 − (NIB19 × 100 mod 97) |
|
||||
| `cartao-credito` | Cartão de crédito | Financeiro | Luhn |
|
||||
| `multibanco` | Referência Multibanco | Financeiro | 98 − (Σ dígito × peso mod 97) sobre entidade + referência + montante |
|
||||
| `pessoa` | Pessoa fictícia | Contactos e Morada | Não valida (gerador composto) |
|
||||
| `telefone` | Telefone | Contactos e Morada | Só formato (Plano Nacional de Numeração) |
|
||||
| `codigo-postal` | Código postal | Contactos e Morada | Só formato (NNNN-NNN) |
|
||||
| `email` | Email | Contactos e Morada | Só formato |
|
||||
| `matricula` | Matrícula | Outros | Só formato (todos os formatos desde 1937) |
|
||||
| `ean` | EAN / Código de barras | Outros | Dígito GS1 (pesos 3,1,3,1…) |
|
||||
| `uuid` | UUID / GUID | Outros | Só formato (v4 ou v7) |
|
||||
|
||||
`HasChecksum` indica se a validação verifica um dígito de controlo ou apenas o formato; `CanValidate` é
|
||||
`false` para geradores compostos como `pessoa`.
|
||||
|
||||
## Utilização
|
||||
|
||||
```csharp
|
||||
var registry = new GeneratorRegistry();
|
||||
var nif = registry.Find("nif")!;
|
||||
|
||||
// 10 NIF de pessoa colectiva, reprodutíveis com seed
|
||||
var items = registry.Generate(nif, 10, new Dictionary<string, string?> { ["tipo"] = "5" }, seed: 42);
|
||||
|
||||
// Validação de um tipo
|
||||
ValidationResult r = nif.Validate("123456789"); // IsValid, FormatMatch, Message, Normalized, Details
|
||||
|
||||
// Detecção automática: válidos primeiro, depois os que têm o formato mas falham o controlo
|
||||
var matches = registry.Detect("PT50 0002 0123 1234 5678 9015 4");
|
||||
```
|
||||
|
||||
- O lote vai de 1 a `GeneratorRegistry.MaxBatch` (1000); fora disso lança `ArgumentOutOfRangeException`.
|
||||
- Um valor de opção que não esteja nas escolhas do gerador lança `ArgumentException`.
|
||||
- `ValidationResult.Details` traz os passos do cálculo, para explicar porque um valor é (in)válido.
|
||||
|
||||
## Adicionar um gerador
|
||||
|
||||
1. Criar uma classe em `Generators/<Categoria>/` que herde de `GeneratorBase` e implemente `Id`, `Name`,
|
||||
`Category`, `Description`, `Generate` e `Validate`. As opções declaram-se com `Option(key, label, default, choices...)`
|
||||
e lêem-se com `context.Option(Options[i])`.
|
||||
2. Usar sempre `context.Random` (nunca `Random.Shared`), para que o `seed` produza resultados reprodutíveis.
|
||||
3. Registar a instância no construtor de `GeneratorRegistry`.
|
||||
|
||||
O novo tipo aparece automaticamente na API e no frontend, e o `GeneratorRoundTripTests` passa a gerá-lo com
|
||||
todas as opções e a confirmar que o validador aceita os valores gerados.
|
||||
64
GeradoresWS/README.md
Normal file
64
GeradoresWS/README.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# GeradoresWS
|
||||
|
||||
API REST ASP.NET Core (.NET 10, minimal APIs) que expõe os geradores do
|
||||
[GeradoresService](../GeradoresService/README.md). É só de leitura, não tem autenticação nem base de dados.
|
||||
|
||||
## Executar
|
||||
|
||||
```bash
|
||||
dotnet run --project GeradoresWS --launch-profile http
|
||||
# http://localhost:5053 → redirecciona para /docs
|
||||
```
|
||||
|
||||
| Perfil (`launchSettings.json`) | URL |
|
||||
|---|---|
|
||||
| `http` | http://localhost:5053 |
|
||||
| `https` | https://localhost:7266 e http://localhost:5053 |
|
||||
| `Docker` | Visual Studio, usa o `Dockerfile` desta pasta |
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Método | Rota | Descrição |
|
||||
|---|---|---|
|
||||
| GET | `/api/v1/generators` | Lista os geradores e as opções de cada um |
|
||||
| GET | `/api/v1/generators/{id}` | Detalhe de um gerador (404 se não existir) |
|
||||
| GET | `/api/v1/generators/{id}/generate` | Gera valores. Query: `count` (1–1000, por omissão 1), `seed` (opcional) e as opções do gerador |
|
||||
| GET | `/api/v1/generators/{id}/validate?value=...` | Valida um valor de um tipo (404 se o tipo não validar) |
|
||||
| GET | `/api/v1/validate?value=...` | Validador livre: detecta o tipo e valida |
|
||||
| GET | `/openapi/v1.json` | Documento OpenAPI |
|
||||
| GET | `/docs` | Documentação interactiva (Scalar) |
|
||||
| GET | `/health` | Health check |
|
||||
|
||||
Exemplos:
|
||||
|
||||
```bash
|
||||
curl "http://localhost:5053/api/v1/generators/nif/generate?count=5&tipo=5"
|
||||
curl "http://localhost:5053/api/v1/generators/iban/validate?value=PT50000201231234567890154"
|
||||
curl "http://localhost:5053/api/v1/validate?value=123456789"
|
||||
```
|
||||
|
||||
Erros de input (opção desconhecida, valor de opção inválido, `count` fora do intervalo) devolvem
|
||||
`400` com `ValidationProblemDetails`; as restantes falhas devolvem `ProblemDetails`.
|
||||
|
||||
## Configuração
|
||||
|
||||
- **CORS**: qualquer origem pode fazer `GET` (API pública, sem credenciais).
|
||||
- **Porta em container**: `8080` (`ASPNETCORE_HTTP_PORTS`).
|
||||
- `InvariantGlobalization` está activo, por isso a imagem não precisa de ICU.
|
||||
|
||||
## Docker
|
||||
|
||||
O `Dockerfile` da raiz do repositório é o usado no `docker compose` e no Jenkins. O `Dockerfile` desta pasta é
|
||||
equivalente, com o stage `base` que o Visual Studio espera. Em ambos o contexto de build é a raiz do repositório:
|
||||
|
||||
```bash
|
||||
docker build -t geradoresws .
|
||||
docker run -p 5050:8080 geradoresws
|
||||
```
|
||||
|
||||
## Ficheiros
|
||||
|
||||
| Ficheiro | Conteúdo |
|
||||
|---|---|
|
||||
| `Program.cs` | Serviços (registry, OpenAPI, CORS, health checks) e pipeline |
|
||||
| `GeneratorEndpoints.cs` | Rotas `/api/v1` e DTOs de resposta |
|
||||
@@ -12,10 +12,10 @@ matrículas, EAN e UUID.
|
||||
|
||||
| Pasta | Conteúdo |
|
||||
|---|---|
|
||||
| `GeradoresService/` | Biblioteca com os algoritmos. Cada tipo é uma classe `IGenerator` em `Generators/` |
|
||||
| `GeradoresWS/` | API ASP.NET Core (.NET 10, minimal APIs, OpenAPI + Scalar) |
|
||||
| `UnitTest/` | Testes xUnit (algoritmos, valores conhecidos e API) |
|
||||
| `geradoresfe/` | Frontend React + Vite + Tailwind. A UI é construída a partir dos metadados da API |
|
||||
| [`GeradoresService/`](GeradoresService/README.md) | Biblioteca com os algoritmos. Cada tipo é uma classe `IGenerator` em `Generators/` |
|
||||
| [`GeradoresWS/`](GeradoresWS/README.md) | API ASP.NET Core (.NET 10, minimal APIs, OpenAPI + Scalar) |
|
||||
| [`UnitTest/`](UnitTest/README.md) | Testes xUnit (algoritmos, valores conhecidos e API) |
|
||||
| [`geradoresfe/`](geradoresfe/README.md) | Frontend React + Vite + Tailwind. A UI é construída a partir dos metadados da API |
|
||||
|
||||
## Desenvolvimento
|
||||
|
||||
|
||||
20
UnitTest/README.md
Normal file
20
UnitTest/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# UnitTest
|
||||
|
||||
Testes xUnit da biblioteca [GeradoresService](../GeradoresService/README.md) e da API
|
||||
[GeradoresWS](../GeradoresWS/README.md).
|
||||
|
||||
```bash
|
||||
dotnet test UnitTest
|
||||
```
|
||||
|
||||
| Ficheiro | O que cobre |
|
||||
|---|---|
|
||||
| `GeneratorRoundTripTests.cs` | Para cada gerador e cada valor de cada opção, gera valores e confirma que o validador os aceita. Também: campos da pessoa fictícia válidos, `seed` reprodutível, ids únicos, opções e quantidades inválidas |
|
||||
| `KnownValuesTests.cs` | Valores reais/conhecidos válidos e inválidos (NIF, NIPC, NISS, CC, IBAN, …) e o dígito de controlo esperado |
|
||||
| `DetectTests.cs` | Validador livre: ordem dos resultados, quase-acertos (formato certo, controlo errado) e valores sem correspondência |
|
||||
| `ApiTests.cs` | Testes de integração com `WebApplicationFactory<Program>`: listagem, geração em lote, 400/404, validação, detecção, OpenAPI e `/health` |
|
||||
|
||||
Os testes de ida e volta são gerados a partir do `GeneratorRegistry`, por isso um gerador novo fica coberto sem
|
||||
escrever testes. Os valores conhecidos devem ser acrescentados à mão sempre que se corrige um bug num algoritmo.
|
||||
|
||||
O Jenkins corre `dotnet test UnitTest/UnitTest.csproj -c Release` antes de construir as imagens.
|
||||
63
geradoresfe/README.md
Normal file
63
geradoresfe/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# geradoresfe
|
||||
|
||||
Frontend React 19 + Vite + Tailwind CSS 4 + TypeScript. A UI não conhece os tipos de gerador: lê
|
||||
`/api/v1/generators` e constrói as páginas e os formulários de opções a partir dos metadados da
|
||||
[API](../GeradoresWS/README.md).
|
||||
|
||||
## Desenvolvimento
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # http://localhost:3000
|
||||
```
|
||||
|
||||
O Vite faz proxy de `/api`, `/docs` e `/openapi` para `http://localhost:5053`
|
||||
(`dotnet run --project GeradoresWS --launch-profile http`). Para outro backend:
|
||||
`API_PROXY_TARGET=http://host:porta npm run dev`.
|
||||
|
||||
| Script | Descrição |
|
||||
|---|---|
|
||||
| `npm run dev` | Servidor de desenvolvimento |
|
||||
| `npm run build` | Type-check (`tsc -b`) e build de produção em `dist/` |
|
||||
| `npm run lint` | ESLint |
|
||||
| `npm test` | Vitest |
|
||||
| `npm run preview` | Serve o build localmente |
|
||||
|
||||
## Páginas
|
||||
|
||||
| Rota | Página |
|
||||
|---|---|
|
||||
| `/` | Lista de geradores por categoria |
|
||||
| `/gerador/:id` | Opções, geração em lote (até 1000), cópia e exportação CSV/JSON/TXT |
|
||||
| `/validar` | Validador livre: detecta o tipo e explica porque é (in)válido |
|
||||
| `/NIF`, `/NISS`, `/CC` | Redireccionam para as rotas novas |
|
||||
|
||||
## Estrutura
|
||||
|
||||
| Caminho | Conteúdo |
|
||||
|---|---|
|
||||
| `src/lib/api.ts` | Cliente da API e tipos |
|
||||
| `src/lib/useGenerators.tsx` | Contexto que carrega a lista de geradores uma vez |
|
||||
| `src/lib/export.ts` | Exportação CSV/JSON/TXT (testado em `export.test.ts`) |
|
||||
| `src/pages/` | Páginas das rotas |
|
||||
| `src/components/` | Cartões, formulário de opções, validador, resultados |
|
||||
| `src/components/ui/` | Componentes base (botão, input, select, badge, …) |
|
||||
| `src/layout/` | Cabeçalho, rodapé e layout |
|
||||
| `src/context/ThemeContext.tsx` | Modo claro/escuro |
|
||||
|
||||
## API
|
||||
|
||||
Por omissão o cliente usa caminhos relativos (`/api/v1`). Em dev é o proxy do Vite; em produção é o nginx.
|
||||
`VITE_API_URL` (em build time) permite apontar para outro host.
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
docker build -t geradoresfe .
|
||||
docker run -p 3000:80 -e API_UPSTREAM=http://geradoresws:8080 geradoresfe
|
||||
```
|
||||
|
||||
A imagem serve o build com nginx. O `nginx.conf.template` é processado com `envsubst` no arranque, e
|
||||
`/api`, `/docs` e `/openapi` são encaminhados para `API_UPSTREAM` (por omissão `http://geradoresws:8080`).
|
||||
A mesma imagem serve em qualquer ambiente sem rebuild. Os ficheiros em `/assets/` têm cache longa e o resto
|
||||
cai no `index.html` (SPA).
|
||||
Reference in New Issue
Block a user