Skip to content

Feature/keycloak client automation#107

Merged
frigini merged 60 commits intomasterfrom
feature/keycloak-client-automation
Jan 22, 2026
Merged

Feature/keycloak client automation#107
frigini merged 60 commits intomasterfrom
feature/keycloak-client-automation

Conversation

@frigini
Copy link
Owner

@frigini frigini commented Jan 17, 2026

Summary by CodeRabbit

  • New Features

    • Automated Keycloak setup on startup; new accessibility helpers and live-region messages; input sanitization; custom account-claims handling; new lightweight layout and improved loading UI.
  • Documentation

    • Major reorganization and expansion: README, architecture, Keycloak, Kubernetes/Helm, CI/CD, security, roadmap, troubleshooting, and backend-frontend alignment.
  • Improvements

    • Streamlined Admin Portal quick-start, updated service URLs, localized messages (PT/EN), resilience and test workflow updates.
  • Breaking Changes

    • Role names renamed and admin API routes/DTO shapes changed — review docs and integrations before upgrading.

✏️ Tip: You can customize this high-level summary in your review settings.

Filipe Frigini added 3 commits January 17, 2026 00:37
- Add setup-keycloak-clients.ps1 (600+ lines) to automate OIDC client setup
- Automates 15+ manual steps from keycloak-admin-portal-setup.md
- Creates admin-portal and customer-app clients with PKCE
- Creates demo users: admin.portal/admin123, customer.demo/customer123
- Creates realm roles: admin, customer, operator, viewer
- Idempotent design allows safe re-execution
- Update documentation to promote automated setup
- Resolves Sprint 7.16 Task 1 (BLOCKER for Sprint 8 Customer App)

Benefits:
- Eliminates manual configuration errors
- Consistent setup across dev environments
- One-command onboarding for new developers
- Reduces setup time from 30 minutes to 2 minutes
Corrige 22 erros de broken links detectados pelo lychee link checker:

Referências removidas:
- Sprint 7.6 fragments (#sprint-76) - sprint foi removido do roadmap
- docs/development-guidelines.md - arquivo não existe
- docs/minor-improvements-roadmap.md - arquivo não existe
- build/README.md - arquivo não existe
- infrastructure/docs/keycloak-custom-theme.md - arquivo não existe
- docs/infrastructure/{k8s,azure,compose}/*.{yaml,bicep,yml} - arquivos não existem

Fragments corrigidos:
- #frontend-architecture-sprint-6 → sem fragment
- #integration-test-infrastructure → sem fragment
- #implementado-otimizacao-iclassfixture → sem fragment

Paths corrigidos:
- Referências absolutas para arquivos em src/ ajustadas
- Links para Keycloak docs redirecionados para documentação oficial

Arquivos modificados: 13
Erros corrigidos: 22/22
…ortuguês

Melhorias realizadas:

1. Versões atualizadas:
   - .NET 10.0.2, Blazor 10.0.2, MudBlazor 8.5.1, Fluxor 6.10.0
   - PostgreSQL 16, Keycloak 26.0.7, EF Core 10.0.2

2. Estrutura do Projeto:
   - Unificada (removida seção duplicada)
   - Adicionados: automation/, atualizada estrutura de docs/

3. Estrutura da Documentação:
   - Links diretos para arquivos .md
   - Adicionados: security/, deployment/, api-automation.md

4. Scripts e URLs:
   - URLs corretas: Admin Portal https://localhost:7032/
   - Script único: ./scripts/dev.ps1 (detecta primeira execução)
   - Keycloak automation: setup-keycloak-clients.ps1

5. Admin Portal simplificado:
   - Removidas referências a sprints
   - Removida stack redundante
   - Configuração Keycloak não duplicada

6. Desenvolvimento:
   - Removida seção 'Executar Testes' redundante
   - Removida 'Implementação de Eventos - Providers' (foco único)
   - Padrões de código consolidados

7. Tradução completa para português:
   - Removidas seções em inglês redundantes
   - Security Features → Segurança
   - Deployment Environments → Deploy
   - Testing Strategy → integrado em seções anteriores
   - Contributing → Contribuição

Resultado: README.md ~40% menor, mais focado e sem redundâncias.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

Walkthrough

Converted many DTOs to positional C# records, updated testcontainer builder usage and container images, reorganized Admin Portal namespaces and DI, added accessibility and resilience helpers (connection status + Polly), introduced FluentValidation validators and sanitization, expanded Keycloak/Kubernetes docs, and removed frontend WASM coverage from CI.

Changes

Cohort / File(s) Summary
Docs & README
README.md, docs/..., docs/architecture.md, docs/roadmap.md, docs/technical-debt.md, docs/deployment/environment-variables.md, infrastructure/keycloak/README.md, docs/backend-frontend-alignment.md
Large documentation additions and reorganizations; Portuguese localization; new C# Records Standardization guidance; Keycloak automation and Kubernetes/Helm/Kustomize examples; roadmap/technical-debt updates.
Keycloak realms & themes
infrastructure/keycloak/realms/*, infrastructure/keycloak/themes/*
Realms JSON updated (roles, clients, users, token/session lifespans, PKCE/redirects); theme CSS and automation docs updated.
Contracts / DTOs (positional records)
src/Contracts/.../DTOs/*, src/Modules/*/DTOs/*, src/Modules/SearchProviders/Domain/SearchResult.cs
Many property-based records converted to positional records (public signatures changed). Callers updated to use constructor parameters.
Module mappings & handlers
src/Modules/Providers/..., src/Modules/SearchProviders/...
Mappers and handlers updated to construct positional DTOs; added validation check in SearchProvidersQueryHandler (distances vs providers).
Test infra & Testcontainers
tests/**, src/*/Tests/**, tests/MeAjudaAi.E2E.Tests/**
Testcontainers builders switched to constructor(image) API and .Build(); container images bumped to newer PostGIS/Redis/Azurite images; added small HTTP helper overloads and log text changes.
Admin Portal namespaces & DI
src/Web/MeAjudaAi.Web.Admin/** (Services/Interfaces, Features/Modules, Constants/Modules, Program.cs)
Namespaces reorganized under Modules.*; new interfaces added (IConfigurationService, ICorrelationIdProvider, IConnectionStatusService); several services converted to primary-constructor style; Program.cs wiring adjusted (FluentValidation, claims factory).
Accessibility helpers & deprecation
src/Web/MeAjudaAi.Web.Admin/Helpers/Accessibility/*, src/Web/MeAjudaAi.Web.Admin/Helpers/AccessibilityHelper.cs
Added AriaHelper, LiveRegionHelper, KeyboardNavigationHelper, ColorContrastHelper; marked legacy AccessibilityHelper obsolete and delegating to new helpers.
Resilience / Polly & connection status
src/Web/MeAjudaAi.Web.Admin/Services/Resilience/Http/*, .../Interfaces/*
Introduced ConnectionStatus enum, IConnectionStatusService, ConnectionStatusService; refactored PollyLoggingHandler to DI primary-constructor; resilience types moved under .Http.
Fluxor / API call wrapper
src/Web/MeAjudaAi.Web.Admin/Extensions/FluxorEffectExtensions.cs, src/Web/MeAjudaAi.Web.Admin/Features/Modules/*/Effects.cs
ExecuteApiCallAsync extension receiver changed from IDispatcher to ISnackbar; Effects updated to call _snackbar.ExecuteApiCallAsync (snackbar param removed).
Validation & sanitization
src/Web/MeAjudaAi.Web.Admin/Validators/*, src/Web/MeAjudaAi.Web.Admin/Helpers/InputSanitizer.cs, src/Web/MeAjudaAi.Web.Admin/DTOs/UploadDocumentDto.cs
Added FluentValidation validators (create/update/contact/address/upload), UploadDocumentDto and UploadDocumentValidator, and InputSanitizer; removed some inline validators and obsolete README docs.
UI cleanups & sample removals
src/Web/MeAjudaAi.Web.Admin/Pages/*, wwwroot/sample-data/weather.json, README.FluentValidation.md, README.Resilience.md
Removed sample pages/data and outdated READMEs; added EmptyLayout; small UI/markup adjustments (App.razor, RedirectToLogin).
Tests: bUnit API & namespaces
tests/MeAjudaAi.Web.Admin.Tests/**, various tests/**
Tests migrated from Bunit.TestContextBunit.BunitContext, RenderComponent<T>()Render<T>(), updated namespaces and DTO constructions to match code changes.
CI / packages / lockfiles
.github/workflows/*, Directory.Packages.props, **/packages.lock.json, MeAjudaAi.slnx
Frontend WASM coverage collection removed/relaxed in CI; Aspire.Hosting.Redis downgraded; broad package lockfile updates (Microsoft.* → 10.0.2, MudBlazor/Fluxor/Polly additions); admin tests project added to solution.
Routing / API paths
src/Client/MeAjudaAi.Client.Contracts/Api/ILocationsApi.cs
Endpoint route attributes for allowed-cities updated from /api/v1/locations/.../api/v1/admin/....
Localization & docstrings
multiple src/* and tests/* files
Many XML doc comments and log messages translated between English and Portuguese; minor log text changes.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI/Effect
    participant Snackbar as ISnackbar (rgba(52,160,51,0.5))
    participant HttpClient as HttpClient (Polly pipeline) (rgba(66,133,244,0.5))
    participant PollyHandler as PollyLoggingHandler (rgba(255,193,7,0.5))
    participant ConnSvc as ConnectionStatusService (rgba(156,39,176,0.5))

    UI->>Snackbar: _snackbar.ExecuteApiCallAsync(apiCall)
    activate Snackbar
    Snackbar->>HttpClient: invoke HTTP request via HttpClient pipeline
    activate HttpClient
    HttpClient->>PollyHandler: pass through DelegatingHandler
    PollyHandler->>ConnSvc: UpdateStatus(Reconnecting / Disconnected / Connected)
    PollyHandler-->>HttpClient: continue pipeline
    HttpClient-->>Snackbar: return response or throw
    deactivate HttpClient
    Snackbar-->>UI: return result / show notification
    deactivate Snackbar
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

"I hop through docs and DTOs, nibbling lines of code,
Records sit neat like carrots lined in row,
Keycloak realms refreshed, helpers hum with cheer,
Tests march in step, CI blinks — the burrow's clear,
A rabbit's happy twitch — refactor takes a bow!" 🐇✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR has no description provided. The required template includes sections for Summary, Problem, Solution, Changes, Impact, Testing, and Checklist, all of which are missing. Provide a comprehensive PR description following the template with at least Summary, Problem, Solution, and Testing sections to explain the Keycloak automation feature and its impact.
Docstring Coverage ⚠️ Warning Docstring coverage is 43.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature/keycloak client automation' clearly describes the main focus of automated Keycloak client setup, which aligns with the PR's extensive changes to Keycloak configuration files and automation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

297-301: PostgreSQL version inconsistency.

Line 300 cites PostgreSQL 18, but the tech list earlier states PostgreSQL 16. Please align these to a single version to avoid confusion.

✏️ Suggested fix
- - **Compatibilidade PostgreSQL 18** para melhor indexação
+ - **Compatibilidade PostgreSQL 16** para melhor indexação
🤖 Fix all issues with AI agents
In `@docs/deployment/environment-variables.md`:
- Line 485: Add a new "Kubernetes" section to the infrastructure README
mirroring the existing Docker/Docker Compose and Azure examples: include sample
Deployment and Service manifests, Ingress rules, ConfigMap and Secret usage for
environment variables, a Helm chart (values.yaml) or kustomize overlay example,
and rollout/upgrade commands; ensure the examples demonstrate how to set the
same environment variables referenced in the environment-variables.md and
include notes on secrets, namespace and resource limits so Kubernetes coverage
matches the scope of the other environment sections.

In `@docs/scripts-inventory.md`:
- Line 79: Update the misleading inline reference "Ver seção Makefile abaixo" in
docs/scripts-inventory.md: either remove that phrase or replace it with an
accurate pointer to the build docs (for example "Consulte build/README.md" or
"Ver seção /build/") so it no longer implies a non-existent "Makefile" section;
search for the exact string "Ver seção Makefile abaixo" to locate the text to
change.

In `@infrastructure/keycloak/setup-keycloak-clients.ps1`:
- Around line 299-302: The script assumes the user lookup returned results and
directly accesses $users[0].id, which will fail if Invoke-RestMethod returns an
empty array or null; modify the block that calls Invoke-RestMethod (the $users
variable) to check that $users is not null/empty before assigning $userId, and
if it is empty log a clear error including $Username and either retry/exit with
non-zero status or throw a descriptive exception so later code using $userId
does not receive a null reference.

In `@README.md`:
- Around line 21-30: Update the README technical stack entries to match the
repository's authoritative configuration: change MudBlazor to 8.15.0 (from
Directory.Packages.props), change Fluxor to 6.9.0 (from
Directory.Packages.props), change Keycloak to 26.0.2 (from keycloak.yml), and
change RabbitMQ to reflect the docker tag used (e.g.,
rabbitmq:3-management-alpine or "RabbitMQ 3") instead of "4"; also resolve the
PostgreSQL discrepancy by declaring a single supported version (use PostgreSQL
16 as used in compose) and remove or update the "Compatibilidade PostgreSQL 18"
statement so the README consistently reflects the actual configs.

In `@src/Contracts/README.md`:
- Line 22: Replace the incorrect relative link string
'../../../../docs/architecture.md' in the README content with the correct
'../../docs/architecture.md' so the "Documentação" reference points to the
project's docs/architecture.md; locate the literal
'../../../../docs/architecture.md' entry in the README and update it to
'../../docs/architecture.md'.

In `@src/Modules/Locations/API/API.Client/AllowedCitiesAdmin/README.md`:
- Line 38: The relative link in README.md under
src/Modules/Locations/API/API.Client/AllowedCitiesAdmin currently uses an
incorrect number of parent-directory references; update the hyperlink target so
it goes up exactly six levels and points to docs/modules/locations.md (i.e., use
../../../../../../docs/modules/locations.md) so the reference from
AllowedCitiesAdmin resolves to the repository docs correctly.
🧹 Nitpick comments (2)
infrastructure/keycloak/themes/README.md (1)

56-56: Consider using the cleaner keycloak.org/ui-customization/themes URL instead.

The current /latest/server_development/#_themes link works, but https://www.keycloak.org/ui-customization/themes is a more modern and stable URL that doesn't depend on anchor stability across documentation versions. This pattern is less likely to break if Keycloak restructures their docs.

infrastructure/keycloak/setup-keycloak-clients.ps1 (1)

65-73: Avoid shadowing built-in PowerShell cmdlets.

The custom Write-Warning and Write-Error functions shadow the built-in cmdlets with the same names. This can cause confusion and unexpected behavior. Consider renaming to avoid conflicts.

♻️ Suggested rename
-function Write-Warning {
+function Write-WarningMessage {
     param([string]$Message)
     Write-Host "⚠ $Message" -ForegroundColor $WarningColor
 }

-function Write-Error {
+function Write-ErrorMessage {
     param([string]$Message)
     Write-Host "✗ $Message" -ForegroundColor $ErrorColor
 }

Then update all usages throughout the script accordingly.

Filipe Frigini added 3 commits January 17, 2026 10:38
Substituir script PowerShell por automação integrada no AppHost:

ANTES:
- Script externo: infrastructure/keycloak/setup-keycloak-clients.ps1
- Desenvolvedor precisava executar manualmente
- Script separado para manter

DEPOIS:
- KeycloakSetupService integrado ao AppHost
- Executa automaticamente no startup (development)
- Menos scripts, mais código
- Type-safe e testável

Implementação:
- src/Aspire/MeAjudaAi.AppHost/Extensions/KeycloakSetupService.cs
  * Aguarda Keycloak estar pronto (/health/ready)
  * Cria realm 'meajudaai'
  * Cria clients: admin-portal, customer-app (PKCE S256)
  * Cria roles: admin, customer, operator, viewer
  * Cria usuários demo: admin.portal/admin123, customer.demo/customer123
  * Idempotente (pode rodar múltiplas vezes)

- src/Aspire/MeAjudaAi.AppHost/Program.cs
  * Setup automático em background após 10s
  * Apenas em ambiente Development
  * Não bloqueia startup da aplicação

Documentação atualizada:
- docs/keycloak-admin-portal-setup.md
- README.md

Benefícios:
- ✅ Zero configuração manual
- ✅ Onboarding automático
- ✅ Menos scripts para manter
- ✅ Type-safe com C#
- ✅ Testável e extensível

Build: 0 errors, 3 warnings (nullability + disposal - não críticos)
Script setup-keycloak-clients.ps1 substituído por implementação C#.

Removido:
- infrastructure/keycloak/setup-keycloak-clients.ps1 (~600 linhas)

Atualizado:
- infrastructure/keycloak/README.md
  * Referências ao script removidas
  * Documentação aponta para KeycloakSetupService.cs
  * Estrutura de arquivos atualizada

Motivação:
- Menos scripts externos para manter
- Automação integrada ao código (type-safe)
- Setup acontece automaticamente no startup
- Desenvolvedor não precisa executar nada manualmente
- Remove KeycloakSetupService.cs (400 lines eliminated)
- Revert Program.cs to simple Main() with native JSON import
- Update meajudaai-realm.dev.json with correct ports and clients
- Update meajudaai-realm.prod.json with production settings
- Simplify dev passwords to admin123
- Add customer-app client with PKCE S256
- Add operator, viewer roles

Follows Julio Casal best practice - zero custom code, just config.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

297-301: PostgreSQL version inconsistency within README.

Line 27 states "PostgreSQL 16" as the main database, but line 300 mentions "Compatibilidade PostgreSQL 18". Clarify the actual supported/targeted version.

🧹 Suggested fix

If PostgreSQL 16 is the current version (as per compose files), update line 300:

 ### 🆔 UUID v7 Implementation
 - **Migração completa** de UUID v4 para UUID v7 (.NET 10)
 - **Performance melhorada** com ordenação temporal nativa
-- **Compatibilidade PostgreSQL 18** para melhor indexação
+- **Compatibilidade PostgreSQL 16+** para melhor indexação
 - **UuidGenerator centralizado** em `MeAjudaAi.Shared.Time`
🤖 Fix all issues with AI agents
In `@docs/keycloak-admin-portal-setup.md`:
- Around line 28-31: Remove the duplicated "Usuários Demo" block by deleting the
second occurrence (the later list showing "admin.portal / admin123" and
"customer.demo / customer123") so only the original "✅ **Usuários Demo**"
section remains; locate the duplicate block in the file (the repetition after
the main setup flow) and remove that entire bullet list to avoid redundancy.

In `@src/Aspire/MeAjudaAi.AppHost/Program.cs`:
- Around line 43-47: The line mixing a call and a signature must be fixed:
replace the corrupted call
`builder.Build().RunnfigureTestingEnvironment(IDistributedApplicationBuilder
builder)` with a proper invocation of the intended setup helper (e.g., call
`ConfigureTestingEnvironment(app)` or the correct Keycloak setup method) after
building the app, ensure you call `var app = builder.Build();` then invoke the
setup helper (reference `ConfigureTestingEnvironment` or the actual Keycloak
setup function) and finally call `app.Run();`, and close the Main method with
the missing brace.
♻️ Duplicate comments (1)
README.md (1)

21-30: Version inaccuracies persist.

Per previous review feedback, multiple versions in this section don't match repository configuration. This should be addressed before merge.

🧹 Nitpick comments (5)
docs/keycloak-admin-portal-setup.md (2)

48-48: Consider using markdown link format for bare URL.

Static analysis flagged the bare URL. Consider wrapping it for consistency:

-1. Acesse http://localhost:8080/
+1. Acesse [http://localhost:8080/](http://localhost:8080/)

65-94: Add language identifier to fenced code block.

The code block showing expected output lacks a language identifier. Consider adding text or plaintext:

-```
+```text
 ╔════════════════════════════════════════════════════════════════╗
infrastructure/keycloak/realms/meajudaai-realm.dev.json (1)

65-74: Consider removing production URLs from development realm.

The admin-portal client includes production URLs (https://admin.meajudaai.com.br/*) in the development realm. While this enables testing against a shared Keycloak instance, it could pose a security risk if the dev realm is accidentally exposed or credentials leak.

Consider keeping production URLs only in the production realm file.

♻️ Suggested change
       "redirectUris": [
         "https://localhost:7032/*",
-        "https://localhost:7281/*",
-        "https://admin.meajudaai.com.br/*"
+        "https://localhost:7281/*"
       ],
       "webOrigins": [
         "https://localhost:7032",
-        "https://localhost:7281",
-        "https://admin.meajudaai.com.br"
+        "https://localhost:7281"
       ],
infrastructure/keycloak/README.md (1)

23-33: Add language identifier to file structure code block.

Per markdownlint, the fenced code block should specify a language:

-```
+```text
 keycloak/
 ├── README.md                     # Este arquivo
README.md (1)

74-107: Add language identifier to project structure code block.

The fenced code block should specify a language for proper rendering:

-```
+```text
 📦 MeAjudaAi/
 ├── 📁 api/              # Especificações OpenAPI (api-spec.json)

Filipe Frigini added 2 commits January 17, 2026 15:22
- CS8620 (nullability): Adicionar ! em validators FluentValidation (4 fixes)
- CS0618 (obsolete): Atualizar construtores Testcontainers (15 fixes)
  * PostgreSqlBuilder: new PostgreSqlBuilder(image) em 9 arquivos
  * RedisBuilder: new RedisBuilder(image) em 2 arquivos
  * AzuriteBuilder: new AzuriteBuilder(image) em 4 arquivos
- S1939 (redundant interface): Remover IModuleApi de UsersModuleApi
- Fix Program.cs: Corrigir linha corrompida de commit anterior

Build agora com 0 warnings em todos os 40 projetos.
- Documentar positional vs nominal records pattern
- Análise do projeto: 158 positional (79%), 41 nominal (21%)
- Padrão recomendado: positional para DTOs, nominal apenas para requests/states/config
- Checklist de conversão: 15 records podem migrar para positional
- Benefícios: 87% redução de código, type-safety, imutabilidade
- Guidelines de code review incluídos
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/MeAjudaAi.Integration.Tests/Fixtures/Database/DatabaseMigrationFixture.cs (1)

137-206: Translate runtime log messages to English.

Several Console messages are in Portuguese (e.g., “Migrations e seeds executados com sucesso”, “Diretório de seeds não encontrado”). These should be English per the logging language policy. Based on learnings, please keep runtime logs in English.

🌐 Example translations
-Console.WriteLine("[MIGRATION-FIXTURE] Migrations e seeds executados com sucesso");
+Console.WriteLine("[MIGRATION-FIXTURE] Migrations and seeds executed successfully");

-Console.Error.WriteLine($"[MIGRATION-FIXTURE] Diretório de seeds não encontrado. Tentativas: {attemptedPaths}");
+Console.Error.WriteLine($"[MIGRATION-FIXTURE] Seeds directory not found. Attempted paths: {attemptedPaths}");
tests/MeAjudaAi.E2E.Tests/Base/BaseTestContainerTest.cs (1)

320-334: Exception messages should be in English.

These messages are in Portuguese and surface in runtime/test output. Based on learnings, please keep runtime logs/messages in English.

🌐 Example translations
-throw new InvalidOperationException("SearchProvidersDbContext NÃO está registrado no DI!");
+throw new InvalidOperationException("SearchProvidersDbContext is not registered in DI.");

-throw new Exception($"Falha ao aplicar migrations do SearchProviders: {ex.Message}", ex);
+throw new Exception($"Failed to apply SearchProviders migrations: {ex.Message}", ex);
🧹 Nitpick comments (5)
tests/MeAjudaAi.Integration.Tests/Fixtures/Database/DatabaseMigrationFixture.cs (1)

28-41: Align PostGIS image version with the rest of the test suite.

Other fixtures in this PR use postgis/postgis:16-3.4; keeping 15-3.4 here risks drift in migrations/behavior across tests. If CI is standardized on 16-3.4, consider aligning this fixture as well.

🔧 Suggested adjustment (if 16-3.4 is canonical)
-_postgresContainer = new PostgreSqlBuilder("postgis/postgis:15-3.4")
+_postgresContainer = new PostgreSqlBuilder("postgis/postgis:16-3.4")
tests/MeAjudaAi.E2E.Tests/Base/BaseTestContainerTest.cs (1)

52-66: Centralize container image versions to avoid drift.

This fixture pins Azurite to 3.34.0, while other test fixtures in this PR use 3.33.0. Consider extracting a shared image constant or aligning versions to prevent cross-suite inconsistencies.

tests/MeAjudaAi.Shared.Tests/TestInfrastructure/Containers/SharedTestContainers.cs (1)

79-91: Avoid image version skew across test fixtures.

Azurite is pinned to 3.33.0 here while the E2E base uses 3.34.0. Consider centralizing image versions (e.g., shared constants) so all fixtures run against the same images.

tests/MeAjudaAi.E2E.Tests/Base/TestContainerFixture.cs (1)

72-86: Align container image versions with other E2E fixtures.

This fixture uses Azurite 3.33.0 while BaseTestContainerTest uses 3.34.0. Consider aligning versions or centralizing the image constants to avoid inconsistent behavior across E2E suites.

src/Modules/Documents/Tests/Integration/Handlers/ApproveDocumentCommandHandlerIntegrationTests.cs (1)

37-43: Confirm PostgreSQL image version consistency.

This test uses postgres:15-alpine while other fixtures in the PR use PostGIS 16-3.4. If the suite is standardizing on 16.x, consider aligning the major version to avoid migration/behavior drift.

@frigini
Copy link
Owner Author

frigini commented Jan 17, 2026

@coderabbitai knowing the standards for english and portuguese through the projects, analyse if there are inconsistences in language (comments, logs, return to user, etc.), then generate a prompt to ai agents to fix it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 17, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for potential Portuguese log messages (common Portuguese words in log statements)
# Look for _logger.Log, LogInformation, LogWarning, LogError, etc. with Portuguese content

echo "=== Searching for Portuguese in log statements ==="
rg -n -C2 --type=cs '(LogInformation|LogWarning|LogError|LogDebug|LogTrace|LogCritical)\s*\(' | \
  rg -i '(erro|falha|sucesso|processando|iniciando|finalizando|não|documento|usuário|criado|atualizado|deletado|inválido|válido)' | \
  head -100

echo ""
echo "=== Searching for English in XML documentation comments ==="
# Look for XML doc comments with English content
rg -n --type=cs '^\s*///.*\b(The|Returns|Gets|Sets|Initializes|Represents|Provides|Contains|Indicates|Specifies)\b' | head -50

echo ""
echo "=== Searching for English in regular comments ==="
# Look for single-line comments with English (excluding test AAA headers)
rg -n --type=cs '^\s*//\s+(The|This|Returns|Gets|Creates|Updates|Deletes|Handles|Processes|Validates)' -g '!*Tests.cs' | head -50

echo ""
echo "=== Checking ValidationMessages.cs files for language ==="
fd -e cs ValidationMessages.cs --exec cat {}

echo ""
echo "=== Checking for English user-facing error messages in Results calls ==="
rg -n --type=cs 'Results\.(NotFound|BadRequest|Problem|ValidationProblem|Conflict|Unauthorized)\s*\(' -A1 | head -50

Length of output: 30494


@frigini, I've analyzed the codebase for language inconsistencies against the established standards. Here are the violations found:

🔍 Language Inconsistency Analysis

❌ Portuguese in Logs (Should be English)

Major violator:

  • src/Web/MeAjudaAi.Web.Admin/Services/ErrorHandlingService.cs - 10+ Portuguese log statements
    • Lines 40, 48-50, 115-117, 124-126, 132-134, 140-142, 148-150

Other violations:

  • src/Aspire/MeAjudaAi.ServiceDefaults/HealthChecks/ExternalServicesHealthCheck.cs:72
  • tests/MeAjudaAi.Integration.Tests/Base/DatabaseSchemaCacheService.cs:51

❌ English in XML Documentation (Should be Portuguese)

Web.Admin services:

  • src/Web/MeAjudaAi.Web.Admin/Services/ICorrelationIdProvider.cs
  • src/Web/MeAjudaAi.Web.Admin/Services/CorrelationIdProvider.cs
  • src/Web/MeAjudaAi.Web.Admin/Services/LiveRegionService.cs
  • src/Web/MeAjudaAi.Web.Admin/Themes/BrandTheme.cs

Test infrastructure (systematic violations):

  • tests/MeAjudaAi.Shared.Tests/TestInfrastructure/Handlers/ConfigurableTestAuthenticationHandler.cs
  • tests/MeAjudaAi.Integration.Tests/Fixtures/External/WireMockFixture.cs
  • tests/MeAjudaAi.E2E.Tests/Base/BaseTestContainerTest.cs

Providers module:

  • src/Modules/Providers/Application/ModuleApi/ProvidersModuleApi.cs:281
  • src/Modules/Providers/Tests/Unit/Infrastructure/Events/Handlers/ProviderRegisteredDomainEventHandlerTests.cs

✅ Correct Usage

  • ValidationMessages.cs - correctly in Portuguese
  • Most user-facing API responses - correctly in Portuguese

🤖 AI Agent Prompt to Fix Language Inconsistencies

Task: Fix language inconsistencies in the MeAjudaAi codebase according to these standards:
1. ALL log messages (_logger.Log*, LogInformation, LogWarning, LogError, etc.) MUST be in English
2. ALL XML documentation comments (///<summary>, ///<param>, ///<returns>, etc.) MUST be in Portuguese
3. ALL user-facing messages (validation errors, API responses) MUST be in Portuguese
4. Test AAA headers (Arrange/Act/Assert) remain in English (exception to Portuguese comment rule)

FILES TO FIX:

Priority 1 - Portuguese logs (translate to English):
- File: src/Web/MeAjudaAi.Web.Admin/Services/ErrorHandlingService.cs
  Lines: 40, 48-50, 115-117, 124-126, 132-134, 140-142, 148-150
  Action: Translate all Portuguese log messages to English while preserving placeholders and structured logging format

- File: src/Aspire/MeAjudaAi.ServiceDefaults/HealthChecks/ExternalServicesHealthCheck.cs
  Line: 72
  Action: Translate "Erro inesperado durante verificação de saúde dos serviços externos" to English

- File: tests/MeAjudaAi.Integration.Tests/Base/DatabaseSchemaCacheService.cs
  Line: 51
  Action: Translate "Schema atualizado no cache para módulo {Module}" to English

Priority 2 - English XML docs (translate to Portuguese):
- File: src/Web/MeAjudaAi.Web.Admin/Services/ICorrelationIdProvider.cs
  Action: Translate all XML documentation comments from English to Portuguese

- File: src/Web/MeAjudaAi.Web.Admin/Services/CorrelationIdProvider.cs
  Action: Translate all XML documentation comments from English to Portuguese

- File: src/Web/MeAjudaAi.Web.Admin/Services/LiveRegionService.cs
  Action: Translate all XML documentation comments from English to Portuguese

- File: src/Web/MeAjudaAi.Web.Admin/Themes/BrandTheme.cs
  Line: 12
  Action: Translate XML comment from English to Portuguese

- File: tests/MeAjudaAi.Shared.Tests/TestInfrastructure/Handlers/ConfigurableTestAuthenticationHandler.cs
  Action: Translate all XML documentation comments from English to Portuguese

- File: tests/MeAjudaAi.Integration.Tests/Fixtures/External/WireMockFixture.cs
  Action: Translate all XML documentation comments from English to Portuguese

- File: tests/MeAjudaAi.E2E.Tests/Base/BaseTestContainerTest.cs
  Action: Translate XML documentation comments (lines 346-377, 451-464) from English to Portuguese

- File: src/Modules/Providers/Application/ModuleApi/ProvidersModuleApi.cs
  Line: 281
  Action: Translate XML comment from English to Portuguese

- File: src/Modules/Providers/Tests/Unit/Infrastructure/Events/Handlers/ProviderRegisteredDomainEventHandlerTests.cs
  Line: 25
  Action: Translate XML comment from English to Portuguese

IMPORTANT NOTES:
- Preserve all structured logging placeholders (e.g., {Operation}, {StatusCode}, {CorrelationId})
- Maintain technical terminology consistency
- Do NOT translate test method names or AAA section headers (Arrange/Act/Assert)
- Do NOT translate user-facing validation messages (these are already correct in Portuguese)
- Keep code logic, variable names, and method signatures unchanged

Would you like me to create an issue to track these language standardization fixes?


🧠 Learnings used
Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Locations/API/Endpoints/GetAllowedCityByIdEndpoint.cs:38-38
Timestamp: 2025-12-17T21:10:58.245Z
Learning: In the MeAjudaAi codebase, there are three distinct language standards: (1) Logs must be in English, (2) Comments and XML summaries (///, <summary>, <param>, etc.) must be in Portuguese, (3) User-facing validation messages and API responses shown to the frontend must be in Portuguese. User-facing messages include error responses like Results.NotFound, Results.BadRequest, and constants in ValidationMessages.cs.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 29
File: tests/MeAjudaAi.Shared.Tests/Middleware/GeographicRestrictionMiddlewareTests.cs:178-178
Timestamp: 2025-11-25T01:05:52.410Z
Learning: In the MeAjudaAi codebase, the standard for comments is Portuguese (due to the Brazilian team), and English is only required for logs. Do not suggest changing Portuguese comments to English.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryTests.cs:65-77
Timestamp: 2025-12-18T00:35:33.829Z
Learning: MeAjudaAi repo: Exceção à política de idioma para comentários — em testes, os cabeçalhos AAA (Arrange, Act, Assert) devem permanecer em inglês e não devem ser traduzidos. Comentários/XML continuam em português; logs em inglês; mensagens ao usuário (validações/APIs) em português.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Documents/Application/Handlers/UploadDocumentCommandHandler.cs:133-143
Timestamp: 2025-12-17T18:18:43.521Z
Learning: In the MeAjudaAi codebase, Portuguese log messages were found across 9 files: Documents module handlers/ModuleApi/Jobs (35+ logs), Shared Jobs/Seeding/RabbitMq (7 logs), and integration test infrastructure (5 logs). The Documents module is the primary violator with most Portuguese logs requiring translation to English per the logging policy.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Documents/Application/Handlers/UploadDocumentCommandHandler.cs:133-143
Timestamp: 2025-12-17T18:26:37.409Z
Learning: MeAjudaAi logging policy: logs must be in English, comments may remain in Portuguese. Portuguese logs were additionally found in Users (API/Extensions.cs:83), Providers (API/Extensions.cs:74), ServiceCatalogs (API/Extensions.cs:78,86,93), and Locations (multiple clients/services lines listed). SearchProviders module currently has no Portuguese logs.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Documents/Application/Handlers/UploadDocumentCommandHandler.cs:133-143
Timestamp: 2025-12-17T18:09:54.585Z
Learning: In the MeAjudaAi codebase, when reviewing log messages in application handlers, verify they are in English. The file src/Modules/Documents/Application/Handlers/UploadDocumentCommandHandler.cs had Portuguese logs that violated the English-only logging policy.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Documents/Application/Handlers/UploadDocumentCommandHandler.cs:133-143
Timestamp: 2025-12-17T18:32:51.210Z
Learning: Além de manter logs em inglês, os comentários e a documentação XML (/// <summary>, <param>, etc.) devem ser escritos em português em todo o código MeAjudaAi.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 0
File: :0-0
Timestamp: 2026-01-16T21:50:23.572Z
Learning: For frigini/MeAjudaAi Web reviews, prefer commit-by-commit (newest-first) with concise verdicts and concrete follow-ups; prioritize reuse of Shared.Contracts for enums/constants to keep Web aligned with backend/shared code.

Learnt from: frigini
Repo: frigini/MeAjudaAi PR: 77
File: src/Modules/Providers/Tests/Unit/Application/Queries/GetProvidersByIdsQueryTests.cs:48-63
Timestamp: 2025-12-18T00:36:23.299Z
Learning: Nos testes do repositório MeAjudaAi, os rótulos do padrão AAA (Arrange/Act/Assert) devem permanecer em inglês e não devem ser traduzidos para português, mesmo que comentários e XML docs sejam em português.

💡 Use @coderabbitai plan to create a plan for code changes

Filipe Frigini added 3 commits January 17, 2026 15:43
- Converted 10 DTO records from nominal to positional pattern
- Updated all usages in Application, Infrastructure, and Test layers
- Preserved validation attributes and optional parameters
- Benefits: 87% code reduction, improved type-safety and immutability

Records converted:
  - SearchableProviderDto (11 props → 7 required + 4 optional)
  - LocationDto (2 props with Range validation)
  - SearchResult (3 required + 1 computed property)
  - ValidateServicesResponse (simplified from hybrid pattern)
  - ModuleProviderIndexingDto (9 required + 3 optional)
  - ModuleProviderDto (9 required + 1 optional)
  - ModuleProviderBasicDto (6 required)
  - ModuleSearchableProviderDto (7 required + 4 optional)
  - ModuleLocationDto (2 required)
  - ModulePagedSearchResultDto (4 required + 3 computed)

All tests passing. Build successful.
- Translate runtime log messages to English (DatabaseMigrationFixture, BaseTestContainerTest)
- Remove duplicate 'Usuários Demo' section in keycloak-admin-portal-setup.md
- Fix PostgreSQL version: 18 → 16+ in README.md
- Add language identifiers to markdown code blocks (text)
- Use markdown link format for URL in keycloak docs

All logging/exception messages now follow English-only policy for runtime output.
Applied language standards:
- Log messages: Portuguese → English (runtime consistency)
- XML documentation: English → Portuguese (code documentation standard)
- User-facing messages: Already correct in Portuguese (unchanged)

Priority 1 - Portuguese logs → English:
- ErrorHandlingService.cs: 7 log messages translated
- ExternalServicesHealthCheck.cs: error log translated
- DatabaseSchemaCacheService.cs: info log translated

Priority 2 - English XML docs → Portuguese:
- ICorrelationIdProvider.cs: interface + method docs
- CorrelationIdProvider.cs: class + method docs
- LiveRegionService.cs: all public API docs
- BrandTheme.cs: property doc
- ConfigurableTestAuthenticationHandler.cs: constant docs
- WireMockFixture.cs: class + property + method docs
- BaseTestContainerTest.cs: helper method docs (4 methods)
- ProvidersModuleApi.cs: method doc
- ProviderRegisteredDomainEventHandlerTests.cs: constructor doc

All changes preserve:
- Structured logging placeholders ({Operation}, {StatusCode}, etc.)
- Technical terminology consistency
- AAA test headers in English
- Code logic and signatures unchanged
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@src/Contracts/Contracts/Modules/SearchProviders/DTOs/ModulePagedSearchResultDto.cs`:
- Around line 3-10: Translate the XML summary for the ModulePagedSearchResultDto
record to Portuguese and add XML <param> documentation for each constructor
parameter (Items, TotalCount, PageNumber, PageSize); update the existing English
<summary> to a Portuguese sentence describing that this DTO representa um
resultado de pesquisa paginada para a API de módulos and add <param> entries
explaining each parameter (Items: lista de ModuleSearchableProviderDto,
TotalCount: número total de itens, PageNumber: número da página atual, PageSize:
tamanho da página).
🧹 Nitpick comments (7)
docs/architecture.md (2)

1825-1825: Fix markdown link formatting.

The line has inconsistent formatting with the previous bullet points. Ensure consistency with the list format.

📝 Suggested fix
-- [docs/roadmap.md](roadmap.md) - Project roadmap
+- [Project roadmap](roadmap.md)

2680-2680: Minor: Duplicate emoji in heading.

The heading appears to have unintended emoji characters.

📝 Suggested fix
-## �🚀 C# 14 Features Utilizados
+## 🚀 C# 14 Features Utilizados
src/Modules/ServiceCatalogs/Application/DTOs/Requests/Service/ValidateServicesResponse.cs (1)

3-6: Add XML documentation in Portuguese.

Per project language policy, XML documentation (/// <summary>) should be in Portuguese for all public types. This response DTO is missing its documentation.

📝 Suggested fix
 namespace MeAjudaAi.Modules.ServiceCatalogs.Application.DTOs.Requests.Service;

+/// <summary>
+/// Resposta da validação de serviços contendo os IDs inválidos e inativos.
+/// </summary>
+/// <param name="AllValid">Indica se todos os serviços são válidos.</param>
+/// <param name="InvalidServiceIds">IDs dos serviços que não existem.</param>
+/// <param name="InactiveServiceIds">IDs dos serviços que estão inativos.</param>
 public sealed record ValidateServicesResponse(
     bool AllValid,
     IReadOnlyCollection<Guid> InvalidServiceIds,
     IReadOnlyCollection<Guid> InactiveServiceIds);

Based on learnings, XML documentation must be in Portuguese.

src/Contracts/Contracts/Modules/SearchProviders/DTOs/ModuleLocationDto.cs (1)

3-8: Consider adding <param> docs for the positional parameters.

This keeps public API docs complete after the switch to positional records.

📎 Suggested documentation update
 /// <summary>
 /// DTO de localização geográfica para a API do módulo.
 /// </summary>
+/// <param name="Latitude">Latitude geográfica.</param>
+/// <param name="Longitude">Longitude geográfica.</param>
 public sealed record ModuleLocationDto(
     double Latitude,
     double Longitude);
Based on learnings, comments/XML docs should remain in Portuguese.
src/Modules/SearchProviders/Application/Handlers/SearchProvidersQueryHandler.cs (1)

69-82: Guard against provider/distance count mismatches before indexing.

Line 80 assumes DistancesInKm and Providers are aligned; if the repository ever returns mismatched counts, this will throw. Please confirm the repository contract or add a defensive check.

🛡️ Suggested defensive guard
         logger.LogInformation(
             "Found {Count} providers out of {Total} total matches",
             searchResult.Providers.Count,
             searchResult.TotalCount);

         // Mapeia para DTOs usando distâncias pré-computadas do repositório
         // Distância é calculada uma vez no repositório (filter/sort/cache) para evitar cálculos redundantes
+        if (searchResult.DistancesInKm.Count != searchResult.Providers.Count)
+        {
+            logger.LogError(
+                "Distance/provider count mismatch (Distances: {DistancesCount}, Providers: {ProvidersCount})",
+                searchResult.DistancesInKm.Count,
+                searchResult.Providers.Count);
+            return Result<PagedResult<SearchableProviderDto>>.Failure(
+                "As distâncias retornadas não correspondem ao número de prestadores.");
+        }
         var providerDtos = searchResult.Providers
             .Select((p, index) => new SearchableProviderDto(
                 ProviderId: p.ProviderId,
                 Name: p.Name,
                 Location: new LocationDto(
                     Latitude: p.Location.Latitude,
                     Longitude: p.Location.Longitude),
                 AverageRating: p.AverageRating,
                 TotalReviews: p.TotalReviews,
                 SubscriptionTier: p.SubscriptionTier,
                 ServiceIds: p.ServiceIds,
                 Description: p.Description,
-                DistanceInKm: searchResult.DistancesInKm[index],
+                DistanceInKm: searchResult.DistancesInKm[index],
                 City: p.City,
                 State: p.State))
             .ToList();
src/Modules/SearchProviders/Application/DTOs/LocationDto.cs (2)

5-8: XML documentation should be in Portuguese per codebase language policy.

Based on learnings, XML summaries (/// <summary>, /// <param>, etc.) must be written in Portuguese.

Proposed fix
 /// <summary>
-/// DTO representing geographic coordinates.
-/// Valid ranges: Latitude [-90, 90], Longitude [-180, 180].
+/// DTO representando coordenadas geográficas.
+/// Intervalos válidos: Latitude [-90, 90], Longitude [-180, 180].
 /// </summary>

9-13: Validation ErrorMessage should be in Portuguese for user-facing messages.

Per the codebase language policy, user-facing validation messages must be in Portuguese. These ErrorMessage strings are surfaced to frontend users.

Proposed fix
 public sealed record LocationDto(
-    [property: Range(-90, 90, ErrorMessage = "Latitude must be between -90 and 90")]
+    [property: Range(-90, 90, ErrorMessage = "Latitude deve estar entre -90 e 90")]
     double Latitude,
-    [property: Range(-180, 180, ErrorMessage = "Longitude must be between -180 and 180")]
+    [property: Range(-180, 180, ErrorMessage = "Longitude deve estar entre -180 e 180")]
     double Longitude);

XML Documentation (Portuguese):
- ModulePagedSearchResultDto: translate summary + add <param> docs for all 4 parameters
- ModuleLocationDto: add <param> docs for Latitude/Longitude
- ValidateServicesResponse: add complete XML docs with <param> for all 3 parameters
- LocationDto: translate summary to Portuguese

User-Facing Messages (Portuguese):
- LocationDto: translate Range validation error messages (Latitude/Longitude)

Code Safety:
- SearchProvidersQueryHandler: add defensive guard against distance/provider count mismatch

Documentation Formatting:
- architecture.md: fix markdown link format for roadmap
- architecture.md: remove duplicate emoji character in C# 14 heading

All changes follow project standards:
- XML docs in Portuguese
- User-facing messages in Portuguese
- Log messages remain in English
- Defensive programming for data integrity
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/MeAjudaAi.Integration.Tests/Fixtures/Database/DatabaseMigrationFixture.cs (2)

36-40: Inconsistent log prefix in startup callback.

The startup callback still uses [SEED-FIXTURE] prefix (line 38) while all other log messages in this file now use [MIGRATION-FIXTURE]. This appears to be an oversight during the prefix rename.

Proposed fix
             .WithStartupCallback((container, ct) =>
             {
-                Console.WriteLine($"[SEED-FIXTURE] Started PostgreSQL container {container.Id[..12]} on port {container.GetMappedPublicPort(5432)}");
+                Console.WriteLine($"[MIGRATION-FIXTURE] Started PostgreSQL container {container.Id[..12]} on port {container.GetMappedPublicPort(5432)}");
                 return Task.CompletedTask;
             })

30-41: Align PostgreSQL/PostGIS version and log prefix with other test fixtures.

This fixture uses postgis/postgis:15-3.4 while all other test fixtures (SharedTestContainers, BaseTestContainerTest, SimpleDatabaseFixture, and integration tests) use postgis/postgis:16-3.4, which matches the CI/CD environment. Align this fixture to postgis/postgis:16-3.4 for consistency.

Additionally, the startup callback at line 38 logs with [SEED-FIXTURE] prefix while all other log messages in this file (lines 140, 147, 174, 182, 190, 206, 222, 226) use [MIGRATION-FIXTURE]. Update line 38 to use the consistent [MIGRATION-FIXTURE] prefix.

🤖 Fix all issues with AI agents
In `@README.md`:
- Around line 21-30: Update the tech stack entries in README.md to match actual
configurations: change the "MudBlazor 8.5.1" entry to "MudBlazor 8.15.0", change
"Fluxor 6.10.0" to "Fluxor 6.9.0", change "Keycloak 26.0.7" to "Keycloak
26.0.2", and change "RabbitMQ 4" to "RabbitMQ 3" (the lines containing the exact
strings "MudBlazor 8.5.1", "Fluxor 6.10.0", "Keycloak 26.0.7", and "RabbitMQ 4"
should be updated to the new version numbers).

Filipe Frigini added 2 commits January 17, 2026 15:56
README.md version updates:
- MudBlazor: 8.5.1 → 8.15.0
- Fluxor: 6.10.0 → 6.9.0
- Keycloak: 26.0.7 → 26.0.2
- RabbitMQ: 4 → 3

Test fixture consistency:
- DatabaseMigrationFixture: upgrade PostgreSQL/PostGIS from 15-3.4 to 16-3.4 (aligns with all other test fixtures and CI/CD environment)
- DatabaseMigrationFixture: fix log prefix from [SEED-FIXTURE] to [MIGRATION-FIXTURE] for consistency with all other logs in the file

All versions now match actual package/container configurations.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/architecture.md (1)

1186-1261: Fix malformed code fences to prevent broken Markdown rendering.

There are several stray language tags without opening backticks (e.g., csharp, yaml, sql, ext, and �ash). These break formatting for the following sections.

🧩 Example fix pattern
-`csharp
+```csharp
...
-`yaml
+```yaml
...
-`sql
+```sql
...
-`ext
+```text
...
-`�ash
+```bash

Close each block with ``` as usual.

Also applies to: 1303-1382, 1417-1476, 1509-1603, 2294-2374

🤖 Fix all issues with AI agents
In `@docs/architecture.md`:
- Around line 2419-2421: The header "## � C# Records Standardization" contains a
garbled character; search for occurrences of "�" in the document (e.g., the
header string and the similar occurrence around the later section noted) and
replace the garbled character with a valid emoji or plain text (for example "🔧"
or simply remove it so it reads "## C# Records Standardization"); ensure the
file is saved in UTF-8 so the replacement persists and re-run a quick render to
confirm the header displays correctly.

In `@docs/roadmap.md`:
- Around line 1071-1074: Update the Sprint 7.16 entry so it does not read as
already finished in the future: replace the status text "✅ COMPLETA (17-21 Jan
2026)" with an appropriate current status such as "In progress" or adjust the
dates to reflect completion only after the end date; specifically edit the
"Sprint 7.16" heading and its status line (the string "✅ COMPLETA (17-21 Jan
2026)") and apply the same change to the other similar sprint entries noted in
the review to ensure the roadmap doesn't claim future sprints are completed.

In `@README.md`:
- Around line 130-135: The README contains bare URLs in the access list (entries
for "Aspire Dashboard", "Admin Portal", "API", and "Keycloak") which triggers
markdownlint MD034; update each bullet to use explicit markdown links of the
form [label](https://...) — e.g. replace the plain URL after "Aspire Dashboard"
with [https://localhost:17063/](https://localhost:17063/) or a descriptive label
link, and do the same for "Admin Portal", "API" (include the Swagger suffix if
desired), and "Keycloak"; apply the same transformation to the other occurrences
mentioned (lines 210-218).

✅ Estruturação de Arquivos:
- Criada pasta DTOs/ e movido UploadDocumentDto
- Dividido UploadDocumentDtoValidator em 3 arquivos separados
- Criado Helpers/InputSanitizer.cs (extraído de FluentValidationValidator)
- Criada estrutura Constants/Modules/{Providers,Documents,Common}/

✅ Consolidação de Documentação:
- Mesclados README.md, README.FluentValidation.md e README.Resilience.md
- Novo README consolidado com índice e seções organizadas
- Removidos README.FluentValidation.md e README.Resilience.md

✅ Limpeza de Template:
- Removido Pages/Counter.razor (página de exemplo)
- Removido Pages/Weather.razor (página de exemplo)
- Removido wwwroot/sample-data/ (dados de exemplo)
- Removida pasta vazia src/Shared/MeAjudaAi.Shared.Contracts

✅ Refatoração de Extensões:
- Removido parâmetro dispatcher não utilizado de ExecuteApiCallAsync
- Atualizado assinatura: de 'this IDispatcher' para 'this ISnackbar'
- Atualizado 9 chamadas em Effects (Documents, Providers, ServiceCatalogs, Locations)
- Melhorada documentação XML dos métodos

✅ Testes:
- Traduzidos comentários de PermissionServiceTests para português (exceto AAA)
- Substituído TestContext por BunitContext em testes de Pages/Layout/Components
- TODO: Corrigir erros CS0618/CS0619 restantes e atualizar DTOs nos testes

Refs: Sprint 7.16 - Technical Debt Sprint (Task 19)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/Web/MeAjudaAi.Web.Admin/Extensions/FluxorEffectExtensions.cs (1)

1-1: Remove unused Fluxor import.

The Fluxor namespace is no longer used in this file. The extension methods operate on ISnackbar (from MudBlazor), and no Fluxor types are referenced in the code (only in the XML documentation comment). Delete the using Fluxor; statement on line 1.

tests/MeAjudaAi.Web.Admin.Tests/Layout/DarkModeToggleTests.cs (1)

43-60: Make the test fail if the toggle button is missing.

Right now the test passes when there is only one button (no dispatch verification runs). This can mask regressions if the toggle disappears. Assert the expected button count before clicking.

🔧 Suggested fix
-        var buttons = cut.FindAll("button");
-        buttons.Should().NotBeEmpty("Deve haver botões no layout");
+        var buttons = cut.FindAll("button");
+        buttons.Should().HaveCountGreaterOrEqualTo(2, "o botão de dark mode deve existir no AppBar");
@@
-        if (buttons.Count >= 2)
-        {
-            buttons[1].Click();
-
-            // Assert
-            _mockDispatcher.Verify(
-                x => x.Dispatch(It.IsAny<ToggleDarkModeAction>()), 
-                Times.AtLeastOnce,
-                "ToggleDarkModeAction deve ser disparada ao clicar no botão");
-        }
+        buttons[1].Click();
+
+        // Assert
+        _mockDispatcher.Verify(
+            x => x.Dispatch(It.IsAny<ToggleDarkModeAction>()), 
+            Times.AtLeastOnce,
+            "ToggleDarkModeAction deve ser disparada ao clicar no botão");
🤖 Fix all issues with AI agents
In `@src/Web/MeAjudaAi.Web.Admin/README.md`:
- Around line 7-15: The table of contents uses emoji-prefixed anchor fragments
that don't match GitHub-generated heading IDs; update each TOC link to the exact
GitHub anchor for its heading (remove the emoji and any leading hyphen from
anchors) so, for example, change "#-estrutura-do-projeto" to
"#estrutura-do-projeto" and do the same for "#-quick-start",
"#-state-management-fluxor", "#-sistema-de-resiliência-polly",
"#-validação-fluentvalidation", "#-componentes-mudblazor", "#-configuração",
"#-testes", and "#-debugging"; alternatively, remove the emoji from the
corresponding headings so current anchors remain valid—ensure TOC entries
exactly match the resulting heading IDs.

In `@src/Web/MeAjudaAi.Web.Admin/Validators/PrimaryAddressDtoValidator.cs`:
- Around line 39-45: The Neighborhood rule currently lives inside a When(...)
guard and therefore allows null/empty values to pass; update the validator in
PrimaryAddressDtoValidator (the RuleFor(x => x.Neighborhood) block) to be
unconditional and include NotEmpty() with the required message, then chain
MaximumLength(100).WithMessage("Bairro deve ter no máximo 100 caracteres") and
.NoXss(); i.e. remove the When(...) wrapper and make RuleFor(x =>
x.Neighborhood).NotEmpty().WithMessage("Bairro é
obrigatório").MaximumLength(100).WithMessage("Bairro deve ter no máximo 100
caracteres").NoXss().

In `@src/Web/MeAjudaAi.Web.Admin/Validators/UploadDocumentDtoValidator.cs`:
- Around line 17-20: Remove the redundant null-forgiving operator from the
constructor call in the rule definition: in UploadDocumentDtoValidator where you
call RuleFor(x => x.File).SetValidator(new UploadDocumentValidator()!), drop the
trailing "!" so it becomes SetValidator(new UploadDocumentValidator()); this
aligns with other validators (e.g., BusinessProfileDtoValidator,
CreateProviderRequestDtoValidator) and avoids unnecessary null-forgiving usage.

In `@src/Web/MeAjudaAi.Web.Admin/Validators/UploadDocumentValidator.cs`:
- Around line 15-21: The AllowedContentTypes HashSet in UploadDocumentValidator
contains the non-standard MIME 'image/jpg'; remove 'image/jpg' from
AllowedContentTypes (or if you intentionally allow it, keep it but add an inline
comment explaining the decision) so only the standard 'image/jpeg' is relied
upon for validation; update AllowedContentTypes accordingly and adjust any unit
tests or documentation that expect 'image/jpg'.

In `@tests/MeAjudaAi.Web.Admin.Tests/packages.lock.json`:
- Around line 592-600: The lock file shows HtmlSanitizer 9.0.889 expecting
AngleSharp 0.17.x but the repo resolves AngleSharp 1.4.0/AngleSharp.Css
1.0.0-beta due to bUnit; to fix, validate and lock a compatible combination: run
unit and integration tests that touch ValidationExtensions.cs (where
HtmlSanitizer is used) under the resolved AngleSharp 1.x to detect regressions,
and then either (A) pin HtmlSanitizer/AngleSharp to a compatible set by updating
package references to versions that match each other, or (B) upgrade
HtmlSanitizer to a release that officially supports AngleSharp 1.x, or (C) add
appropriate assembly binding/restore constraints; update the packages.lock.json
accordingly and rerun the test suite to confirm no XSS/sanitization behavior
changed.
- Around line 727-736: The lock file shows Microsoft.Extensions.Http.Polly
(10.0.2) resolving Polly 7.2.4 which conflicts with the project's direct Polly
8.6.5; fix by either removing Microsoft.Extensions.Http.Polly and replacing
usages with Microsoft.Extensions.Http.Resilience (update project/CSProj package
references and any code that references Microsoft.Extensions.Http.Polly types)
or by aligning Polly to 7.x (change the direct Polly dependency to a 7.x version
and run restore to regenerate packages.lock.json); ensure the final change
updates package references (e.g., remove/replace Microsoft.Extensions.Http.Polly
or change Polly version) and then restore/commit the regenerated
packages.lock.json so the dependency graph no longer mixes Polly 7.x and 8.x.
🧹 Nitpick comments (5)
src/Web/MeAjudaAi.Web.Admin/Helpers/InputSanitizer.cs (1)

29-35: Consider adding a defensive null check for setter.

If setter is accidentally passed as null, the error will only surface when the callback is invoked, not at creation time. A guard clause makes failures immediate and easier to diagnose.

💡 Suggested improvement
 public static EventCallback<string> CreateSanitizedCallback(object? receiver, Action<string> setter)
 {
+    ArgumentNullException.ThrowIfNull(setter);
+
     return EventCallback.Factory.Create<string>(receiver ?? new object(), (value) =>
     {
         setter(Sanitize(value));
     });
 }
src/Web/MeAjudaAi.Web.Admin/Validators/PrimaryAddressUpdateDtoValidator.cs (1)

73-81: Minor style inconsistency: rule ordering differs from other fields.

For Country, NoXss() is placed before length checks (line 76), whereas other fields like Street (lines 16-21) have NoXss() after length validations. This is functionally correct but inconsistent with the rest of the file.

♻️ Suggested reordering for consistency
         When(x => !string.IsNullOrWhiteSpace(x.Country), () =>
         {
             RuleFor(x => x.Country)
-                .NoXss()
                 .MinimumLength(2)
                 .WithMessage("País deve ter no mínimo 2 caracteres")
                 .MaximumLength(100)
-                .WithMessage("País deve ter no máximo 100 caracteres");
+                .WithMessage("País deve ter no máximo 100 caracteres")
+                .NoXss();
         });
src/Web/MeAjudaAi.Web.Admin/Services/ConfigurationService.cs (1)

96-101: Consider using structured logging for validation errors.

Line 99 uses LogError(errorMessage) without the exception overload, which is correct since there's no exception. However, consider using a structured log template for better log analysis:

♻️ Suggested improvement for structured logging
         if (errors.Any())
         {
-            var errorMessage = "Configuration validation failed:\n" + string.Join("\n", errors.Select(e => $"  - {e}"));
-            logger.LogError(errorMessage);
+            logger.LogError(
+                "Configuration validation failed. Errors: {ValidationErrors}",
+                errors);
             throw new InvalidOperationException(errorMessage);
         }
src/Web/MeAjudaAi.Web.Admin/README.md (1)

62-80: Add language specifier to fenced code block.

The directory structure code block lacks a language identifier. Adding one improves syntax highlighting and resolves the MD040 lint warning.

📝 Proposed fix
-```
+```text
 MeAjudaAi.Web.Admin/
 ├── Features/              # Fluxor stores (State + Actions + Reducers + Effects)
src/Web/MeAjudaAi.Web.Admin/Services/ErrorHandlingService.cs (1)

137-144: Consider sanitizing exception message in user-facing error.

Line 143 exposes ex.Message directly to the user. Depending on the exception type, this could leak internal implementation details (stack traces, database errors, file paths).

Suggested fix
         catch (Exception ex)
         {
             logger.LogError(ex,
                 "Unexpected exception in operation '{Operation}' [CorrelationId: {CorrelationId}]",
                 operation, correlationId);

-            return Result<T>.Failure(Error.Internal($"Erro inesperado: {ex.Message}"));
+            return Result<T>.Failure(Error.Internal("Ocorreu um erro inesperado. Tente novamente."));
         }

The full exception details are already logged with the correlation ID, so users can reference that for support without seeing raw error messages.

Filipe Frigini added 5 commits January 17, 2026 19:58
…zados

- Criado AriaHelper: labels, roles e descrições ARIA
- Criado LiveRegionHelper: anúncios para leitores de tela
- Criado KeyboardNavigationHelper: atalhos e ordem de foco
- Criado ColorContrastHelper: verificação WCAG com TODO para implementação completa
- AccessibilityHelper mantido como wrapper obsoleto para retrocompatibilidade
- Corrigido PerformanceHelper (assinaturas de métodos)
- README: corrigir âncoras da TOC (remover emojis dos links)
- FluxorEffectExtensions: remover using Fluxor não usado
- UploadDocumentValidator: remover 'image/jpg' não-padrão
- PrimaryAddressDtoValidator: tornar Neighborhood obrigatório
- PrimaryAddressUpdateDtoValidator: reordenar NoXss() consistentemente
- InputSanitizer: adicionar null check defensivo em CreateSanitizedCallback
- ConfigurationService: usar structured logging
- ErrorHandlingService: não expor ex.Message ao usuário
- DarkModeToggleTests: melhorar teste para falhar se botão não existir
- Criado ConnectionStatus.cs: enum com estados de conexão
- Criado IConnectionStatusService.cs: interface do serviço
- ConnectionStatusService.cs: mantém apenas implementação
- Adicionado inheritdoc nos membros da implementação
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@docs/backend-frontend-alignment.md`:
- Around line 82-99: The fenced code blocks showing "Web.Admin/Validators/" and
"Modules/*/Application/Validators/" lack a language tag causing MD040 warnings;
update each triple-backtick fence to include a language (e.g., ```text) so the
blocks read ```text ... ``` instead of ```, leaving the block contents unchanged
(apply to both the Frontend block containing
CreateProviderRequestDtoValidator.cs and the Backend block containing
CreateProviderCommandValidator.cs).
- Around line 13-16: Corrija a concordância na terceira linha do bloco de
bullets alterando "Refresh tokens automático" para a forma plural correta
"Refresh tokens automáticos"; localize a string exata "Refresh tokens
automático" no arquivo docs/backend-frontend-alignment.md e atualize para
"Refresh tokens automáticos" mantendo o mesmo estilo de formatação dos outros
itens.
🧹 Nitpick comments (3)
infrastructure/keycloak/realms/meajudaai-realm.prod.json (2)

12-26: Confirme políticas de sessão e verificação de e‑mail em produção.
verifyEmail: true exige SMTP configurado, e os lifespans devem refletir requisitos de segurança/UX.


109-110: Realm prod sem usuários seed: confirme bootstrap administrativo.
Garanta um mecanismo de provisionamento inicial antes do rollout.

infrastructure/keycloak/realms/meajudaai-realm.dev.json (1)

77-112: Verifique se as origens do realm dev incluem domínios de produção intencionalmente.
Se não forem necessárias em dev, separar reduz risco de confiar origens indevidas.

Filipe Frigini added 2 commits January 20, 2026 17:24
- Atualizar UserRolesTests para nova estrutura de roles (7 roles)
- Remover referências a BasicRoles em validators (usar CustomerRoles)
- Traduzir cabeçalhos TODO para português (LIMITAÇÃO, OPÇÕES, ATUAL)
- Adicionar responsividade mobile para logo do tema Keycloak (height auto, margin -40px)
- Remover testes obsoletos relacionados a BasicRoles
- Corrigir concordância verbal: 'Refresh tokens automáticos'
- Adicionar language tags 'text' nos code blocks (MD040)
- Documentar requisitos de deployment de produção:
  - SMTP obrigatório para verifyEmail: true
  - Mecanismo de bootstrap para usuário admin inicial
  - Validação de session lifespans
- Documentar origens de produção no realm dev (intencional para testes híbridos)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/Modules/Users/Application/Validators/CreateUserRequestValidator.cs (2)

91-96: Validation logic mismatch: error message doesn't match accepted roles.

IsValidRole(role) validates against AllRoles (7 roles), but the error message displays only CustomerRoles (just "customer"). If a user submits an invalid role, they'll see misleading guidance.

Additionally, the message is in English—user-facing validation messages should be in Portuguese per the language policy. Based on learnings, use ValidationMessages.InvalidFormat.Role for consistency with CreateUserCommandValidator.

Proposed fix
         When(x => x.Roles != null, () =>
         {
             RuleForEach(x => x.Roles)
                 .NotEmpty()
-                .WithMessage("Role cannot be empty")
+                .WithMessage(ValidationMessages.Required.Role)
                 .Must(role => UserRoles.IsValidRole(role))
-                .WithMessage($"Invalid role. Valid roles: {string.Join(", ", UserRoles.CustomerRoles)}");
+                .WithMessage(string.Format(ValidationMessages.InvalidFormat.Role, string.Join(", ", UserRoles.AllRoles)));
         });

80-87: Password validation messages are in English.

Per the language policy, user-facing validation messages should be in Portuguese. These hardcoded English strings should use the centralized ValidationMessages constants for consistency with the rest of the validator.

Proposed fix
-        // Manter validação de password original (não está nas constantes)
         RuleFor(x => x.Password)
             .NotEmpty()
-            .WithMessage("Password is required")
-            .MinimumLength(8)
-            .WithMessage("Password must be at least 8 characters long")
-            .Matches(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)")
-            .WithMessage("Password must contain at least one lowercase letter, one uppercase letter and one number");
+            .WithMessage(ValidationMessages.Required.Password)
+            .MinimumLength(ValidationConstants.PasswordLimits.MinLength)
+            .WithMessage(ValidationMessages.Length.PasswordTooShort)
+            .Matches(ValidationConstants.Patterns.Password)
+            .WithMessage(ValidationMessages.InvalidFormat.Password);
src/Modules/Users/Application/Validators/CreateUserCommandValidator.cs (1)

61-68: Validation logic mismatch: error message doesn't match accepted roles.

Same issue as CreateUserRequestValidator: IsValidRole(role) validates against AllRoles (7 roles including admin, provider-manager, etc.), but the error message displays only CustomerRoles (just "customer").

If this endpoint is intentionally restricted to customer roles only, the validation logic should use a dedicated check. Otherwise, update the message to show all valid roles.

Option A: If all roles should be valid (match current logic)
         When(x => x.Roles != null, () =>
         {
             RuleForEach(x => x.Roles)
                 .NotEmpty()
                 .WithMessage(ValidationMessages.Required.Role)
                 .Must(role => UserRoles.IsValidRole(role))
-                .WithMessage(string.Format(ValidationMessages.InvalidFormat.Role, string.Join(", ", UserRoles.CustomerRoles)));
+                .WithMessage(string.Format(ValidationMessages.InvalidFormat.Role, string.Join(", ", UserRoles.AllRoles)));
         });
Option B: If only customer roles should be valid (restrict validation)
         When(x => x.Roles != null, () =>
         {
             RuleForEach(x => x.Roles)
                 .NotEmpty()
                 .WithMessage(ValidationMessages.Required.Role)
-                .Must(role => UserRoles.IsValidRole(role))
+                .Must(role => UserRoles.CustomerRoles.Contains(role, StringComparer.OrdinalIgnoreCase))
                 .WithMessage(string.Format(ValidationMessages.InvalidFormat.Role, string.Join(", ", UserRoles.CustomerRoles)));
         });
🤖 Fix all issues with AI agents
In `@infrastructure/keycloak/README.md`:
- Around line 42-48: Adicione um aviso explícito no README perto da seção
"Configurações" indicando que o seed user 'admin.portal' com senha 'admin123' é
somente para desenvolvimento, deve ser trocado imediatamente e nunca usado em
ambientes expostos; sugira ações concretas: alterar a senha ao primeiro login,
remover o usuário seed ou não aplicar o seed em ambientes de produção, e
rotacionar credenciais/segredos; mantenha a referência às entradas atuais
('users' seed, senha 'admin123', e a configuração de origens/Redirect URIs) para
que o leitor saiba exatamente o que alterar.
♻️ Duplicate comments (1)
src/Web/MeAjudaAi.Web.Admin/Extensions/ServiceCollectionExtensions.cs (1)

42-63: Polly policy events still suppressed by NullLogger (duplicate).
This keeps OnRetry/OnOpened logs silent. Please apply the prior DI-logger approach or confirm that suppression is intentional.

Does Microsoft.Extensions.Http.Resilience (AddStandardResilienceHandler) support resolving ILogger/IServiceProvider for policy callbacks, or is there a recommended pattern for logging Polly events?
🧹 Nitpick comments (1)
tests/MeAjudaAi.Shared.Tests/Unit/Utilities/UserRolesTests.cs (1)

194-203: LGTM! Consider adding CustomerRoles consistency test.

Tests correctly reflect the updated role structure. The consistency section verifies AdminRoles is a subset of AllRoles—consider adding the same for CustomerRoles for completeness.

Optional: Add CustomerRoles consistency test
     [Fact]
     public void AdminRoles_ShouldBeSubsetOfAllRoles()
     {
         // Assert
         UserRoles.AdminRoles.Should().BeSubsetOf(UserRoles.AllRoles);
     }
+
+    [Fact]
+    public void CustomerRoles_ShouldBeSubsetOfAllRoles()
+    {
+        // Assert
+        UserRoles.CustomerRoles.Should().BeSubsetOf(UserRoles.AllRoles);
+    }
 
     `#endregion`

Filipe Frigini added 12 commits January 20, 2026 17:39
- Adicionar aviso crítico no README sobre usuário seed admin.portal
  - Senha admin123 é EXCLUSIVA para desenvolvimento
  - Ações obrigatórias: alterar senha, remover seed, nunca usar em produção
  - Instruções de remoção e rotação de credenciais
- Corrigir CreateUserRequestValidator:
  - Mensagens de password em português usando ValidationMessages
  - Usar ValidationConstants.PasswordLimits e Patterns
  - Corrigir validação de roles: AllRoles em vez de CustomerRoles
- Corrigir CreateUserCommandValidator:
  - Validação de roles: AllRoles em vez de CustomerRoles
- Adicionar teste CustomerRoles_ShouldBeSubsetOfAllRoles
- Resultado: 38/38 testes passando
…tuguês

- Atualizar asserções de mensagens de erro para usar ValidationMessages
- Password is required → ValidationMessages.Required.Password
- Password must be at least 8 characters long → ValidationMessages.Length.PasswordTooShort
- Password must contain... → ValidationMessages.InvalidFormat.Password
- Resultado: 48/48 testes passando
- Adicionar oidc-usermodel-realm-role-mapper nos realms dev e prod
- Mapear realm roles para claim 'roles' no access token
- Resolver problema de autorização onde roles não eram incluídas no token
- Páginas do admin portal agora verificarão roles corretamente
- Fluxor requer 'unsafe-eval' para inicializar state management
- Adicionar diretiva apenas em desenvolvimento (seguro para local)
- Corrigir erro: JavaScript error - StoreInitializationException
- Criar CustomAccountClaimsPrincipalFactory para processar roles do Keycloak
- Keycloak retorna roles como array JSON, Blazor precisa de claims individuais
- Configurar RoleClaimType correto para IsInRole() funcionar
- Adicionar post.logout.redirect.uris e frontchannelLogout no Keycloak
- Corrigir protocol mapper incluindo id.token e userinfo claims
- Adicionar 'unsafe-eval' ao CSP para Fluxor funcionar
- Criar página de debug de claims para troubleshooting

Fixes: #autorizacao #roles #logout
- Content Security Policy agora aceita https://localhost:* http://localhost:*
- Aspire usa portas dinâmicas, CSP estava bloqueando fetch API
- Corrigir erro: Refused to connect violates CSP
- Melhorar mensagem de erro de logout
- AuthorizationMessageHandler agora aceita localhost com qualquer porta
- Aspire usa portas dinâmicas, handler estava rejeitando tokens
- Resolver 401 Unauthorized em endpoints protegidos
- Melhorar mensagem de logout (Success ao invés de Warning)

Fixes: #401-unauthorized #aspire-dynamic-ports
- Criar EmptyLayout para páginas de autenticação
- Aplicar EmptyLayout na página Authentication.razor
- Melhorar tela de Authorizing (sem layout)
- Prevenir flash do menu lateral antes do login

Fixes: #ui-flash-before-login
- Usar NavigateTo com forceLoad ao invés de NavigateToLogin
- Adicionar feedback visual durante redirecionamento
- Prevenir redirect para login-failed ao acessar portal

Fixes: #login-redirect
- Blazor WASM requer 'unsafe-inline' para scripts de bootstrap
- Corrigir erro: script violates CSP directive
- Permitir execução de scripts inline necessários

Fixes: #csp-inline-scripts
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/Web/MeAjudaAi.Web.Admin/Features/Dashboard/DashboardEffects.cs (1)

50-61: Dispatch a failure or dedicated action on the 401 path to clear the loading state.

The reducer sets IsLoading = true on LoadDashboardStatsAction, but the early return on 401 (line 53–55) skips dispatching LoadDashboardStatsSuccessAction or LoadDashboardStatsFailureAction, leaving IsLoading stuck as true. Either dispatch LoadDashboardStatsFailureAction or add a dedicated "abort/unauthorized" action to ensure the loading flag is cleared.

src/Web/MeAjudaAi.Web.Admin/Features/Modules/Providers/ProvidersEffects.cs (1)

133-162: Remove the redundant null-check that causes double dispatch of DeleteProviderFailureAction.

The ExecuteApiCallAsync extension method invokes the onError callback and returns null when an API call fails. The null-check at lines 156–160 unnecessarily dispatches failure again, duplicating the failure action already dispatched by the onError callback at lines 151–153.

Suggested fix
-        if (result is null)
-        {
-            dispatcher.Dispatch(new DeleteProviderFailureAction(
-                action.ProviderId,
-                "Falha ao deletar provedor"));
-        }

The onError callback already handles all failure cases; the null-check is redundant.

🤖 Fix all issues with AI agents
In `@infrastructure/keycloak/realms/meajudaai-realm.dev.json`:
- Around line 136-177: The dev realm currently contains hardcoded credentials
for users "admin.portal" and "customer.demo" with credentials. Locate the
"credentials" objects for those users in the JSON (look for username
"admin.portal" and "customer.demo") and change the "temporary" flag from false
to true so the passwords are treated as temporary and require a reset on first
login; ensure the credentials entries remain otherwise unchanged.
- Around line 77-93: The post-logout redirect configuration is incomplete:
update the client attributes so that "post.logout.redirect.uris" either lists
all entries currently in "redirectUris" (http://localhost:5165/*,
https://localhost:7032/*, https://localhost:7281/*,
https://admin.meajudaai.com.br/*) or set it to "+" to inherit them; modify the
attributes block (where "pkce.code.challenge.method" and
"post.logout.redirect.uris" are defined) to include the full set or "+" so
frontchannelLogout works correctly across all "webOrigins"/"redirectUris".

In
`@src/Web/MeAjudaAi.Web.Admin/Authentication/CustomAccountClaimsPrincipalFactory.cs`:
- Around line 34-70: The code in CustomAccountClaimsPrincipalFactory uses
newIdentity.FindFirst(...) so only the first "roles"/"role" claim is processed
and additional role claims are dropped; update the logic to use
newIdentity.FindAll(c => c.Type == "roles" || c.Type == "role") and iterate over
that collection, removing each original claim and normalizing its Value (detect
JSON array vs single string) to add one or more Claim(ClaimTypes.Role, role)
entries for each original claim processed; ensure JsonSerializer.Deserialize
handling and the fallback catch behavior are applied per claim.

In
`@src/Web/MeAjudaAi.Web.Admin/Configuration/ContentSecurityPolicyConfiguration.cs`:
- Around line 18-23: In ContentSecurityPolicyConfiguration (the CSP list where
the directives are defined) the "frame-src http://localhost:*" entry only allows
HTTP localhost and will block Keycloak over HTTPS; update the CSP directives to
also allow HTTPS localhost by adding a matching "frame-src https://localhost:*"
alternative (or combine into a single directive that includes both
http://localhost:* and https://localhost:* for the "frame-src" entry) so dev
Keycloak iframes served with dev certs are permitted.

In `@src/Web/MeAjudaAi.Web.Admin/Services/ApiAuthorizationMessageHandler.cs`:
- Around line 18-24: The current code strips the port when building baseUrl
causing AuthorizationMessageHandler to miss non-default ports; instead pass the
full origin (including port) to ConfigureHandler so Uri.IsBaseOf matches
requests — e.g., stop using the host-only baseUrl and use the full
authority/origin from apiUri (or simply clientConfiguration.ApiBaseUrl) when
calling ConfigureHandler (refer to apiUri, baseUrl,
clientConfiguration.ApiBaseUrl, and
ConfigureHandler/AuthorizationMessageHandler).
♻️ Duplicate comments (1)
src/Web/MeAjudaAi.Web.Admin/Services/ErrorHandlingService.cs (1)

113-123: Apply user-friendly mapping on non-exception failures.
This path still returns the raw result without ensuring a friendly message when the backend message is missing. Consider mapping result.Error?.Message via GetUserFriendlyMessage before returning, or clarify in remarks that callers must handle mapping.

🧹 Nitpick comments (3)
src/Web/MeAjudaAi.Web.Admin/App.razor (1)

41-46: LGTM—consider extracting the repeated loading container style.

The authorizing loading UI is consistent with other auth-related loading states. The hardcoded style (height: 100vh; background-color: #f5f5f5``) is duplicated in RedirectToLogin.razor and `EmptyLayout.razor`.

If you anticipate changes to this pattern, consider extracting to a shared CSS class or a small LoadingContainer component.

src/Web/MeAjudaAi.Web.Admin/Features/Dashboard/DashboardEffects.cs (1)

14-19: Avoid the hard‑coded verification status string.
Consider referencing a shared enum/constant (e.g., in Shared.Contracts) to keep Web aligned with backend values and avoid drift. Based on learnings, ...

infrastructure/keycloak/realms/meajudaai-realm.dev.json (1)

77-88: Confirm production origins are intentionally allowed in the dev realm.
Both admin and customer clients list production domains in redirectUris/webOrigins. If this realm is ever exposed beyond local dev, that can blur environment boundaries and token issuance. If not intentional, consider splitting env-specific realm configs to keep prod origins out of dev.

Also applies to: 122-129

- Keycloak realm: set temporary=true for hardcoded dev credentials (admin.portal, customer.demo) to force password reset on first login
- Keycloak realm: update post.logout.redirect.uris to '+' to inherit all redirectUris for proper frontchannel logout
- CustomAccountClaimsPrincipalFactory: fix role claim processing to use FindAll instead of FindFirst, ensuring all role claims are processed (fixes multi-role support)
- ContentSecurityPolicyConfiguration: add https://localhost:* to frame-src directive to allow Keycloak iframes over HTTPS in dev
- ApiAuthorizationMessageHandler: pass full API URL with port to ConfigureHandler (fixes non-default port authorization issues)
- DashboardEffects: dispatch failure action on 401 to clear loading state (prevents stuck loading indicator)
- ProvidersEffects: remove redundant null-check after ExecuteApiCallAsync to prevent double dispatch of failure action
- ErrorHandlingService: apply user-friendly message mapping when backend message is missing
- E2E test: remove unsupported Phone field from UpdateProvider test request (fixes 400 BadRequest - field not in UpdateProviderProfileRequest DTO)

Fixes race condition handling, authorization flow, and test stability.

Co-Authored-By: Warp <agent@warp.dev>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@infrastructure/keycloak/realms/meajudaai-realm.dev.json`:
- Around line 111-134: The customer-app client configuration lacks frontchannel
logout settings and optional role mapping; update the "customer-app" client JSON
to add the attribute "frontchannelLogout": "true" and include
"post.logout.redirect.uris" with the same URIs you want Keycloak to redirect to
after logout (e.g., "https://localhost:7282/*" and
"https://app.meajudaai.com.br/*"), and optionally add a protocol mapper
equivalent to the admin-portal's "realm-roles" mapper if you need realm role
claims in tokens; locate the "clientId": "customer-app" block and add these
attributes to its attributes object and add the mapper entry mirroring
admin-portal's realm-roles mapper configuration.
♻️ Duplicate comments (1)
infrastructure/keycloak/realms/meajudaai-realm.dev.json (1)

136-178: LGTM - User configuration addresses previous security feedback.

The temporary: true flag on credentials ensures password reset on first login, which was the recommended best practice from prior review. The admin.portal user having all roles is appropriate for comprehensive dev/testing coverage.

🧹 Nitpick comments (6)
src/Web/MeAjudaAi.Web.Admin/Features/Modules/Providers/ProvidersEffects.cs (2)

133-154: Unused result variable.

The return value of ExecuteApiCallAsync is captured but never used since all logic is handled via callbacks. Discard the result explicitly to clarify intent.

♻️ Suggested fix
-        var result = await _snackbar.ExecuteApiCallAsync(
+        await _snackbar.ExecuteApiCallAsync(
             apiCall: () => _providersApi.DeleteProviderAsync(action.ProviderId),
             operationName: "Deletar provedor",

44-44: CancellationTokenSource created but never cancelled.

The CancellationTokenSource is created and disposed properly, but no cancellation is ever triggered. If cancellation isn't needed, consider using CancellationToken.None directly. If cancellation should be supported (e.g., on navigation away), the token would need to be wired to a component lifecycle.

src/Web/MeAjudaAi.Web.Admin/Authentication/CustomAccountClaimsPrincipalFactory.cs (2)

34-35: Consider using shared constants for claim type strings.

The hardcoded "roles" string is also defined in AuthConstants.Claims.Roles. Using the shared constant improves consistency and maintainability across the codebase.

♻️ Suggested refactor
+using MeAjudaAi.Shared.Utilities.Constants;
             // Procurar todos os claims de roles (pode ser "roles" ou "role")
-            var rolesClaims = newIdentity.FindAll(c => c.Type == "roles" || c.Type == "role").ToList();
+            var rolesClaims = newIdentity.FindAll(c => c.Type == AuthConstants.Claims.Roles || c.Type == "role").ToList();

Based on learnings, prefer reuse of Shared.Contracts/Utilities for enums/constants to keep Web aligned with backend/shared code.


49-57: Add defensive null check for deserialized array elements.

If the JSON array contains null or whitespace elements (e.g., ["admin", null, ""]), these would be added as invalid role claims. Adding a guard prevents potential authorization issues.

♻️ Suggested refactor
                         if (roles != null)
                         {
                             foreach (var role in roles)
                             {
-                                // Adicionar cada role como um claim individual do tipo "role"
-                                // ClaimTypes.Role = http://schemas.microsoft.com/ws/2008/06/identity/claims/role
-                                newIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
+                                // Adicionar cada role como um claim individual do tipo "role"
+                                // ClaimTypes.Role = http://schemas.microsoft.com/ws/2008/06/identity/claims/role
+                                if (!string.IsNullOrWhiteSpace(role))
+                                {
+                                    newIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
+                                }
                             }
                         }
src/Web/MeAjudaAi.Web.Admin/Services/ErrorHandlingService.cs (2)

140-159: Consider reusing GetMessageFromHttpStatus to reduce duplication.

The hardcoded messages in lines 152-154 duplicate the mappings in GetMessageFromHttpStatus (lines 188-190). Additionally, the log at line 146 says "Unexpected exception" but ApiException is a specific, expected error type.

♻️ Suggested refactor
         catch (Refit.ApiException apiEx)
         {
-            // Preserva o status code original da API (especialmente 401 para race condition)
             var statusCode = (int)apiEx.StatusCode;
             
             logger.LogError(apiEx,
-                "Unexpected exception in operation '{Operation}' [CorrelationId: {CorrelationId}]",
+                "API exception in operation '{Operation}': StatusCode={StatusCode} [CorrelationId: {CorrelationId}]",
-                operation, correlationId);
+                operation, statusCode, correlationId);
 
-            // Cria erro com statusCode original preservado
-            var error = statusCode switch
-            {
-                401 => Error.Unauthorized("Você não está autenticado. Faça login novamente."),
-                403 => Error.Forbidden("Você não tem permissão para realizar esta ação."),
-                404 => Error.NotFound("Recurso não encontrado."),
-                _ => Error.Internal(GetMessageFromHttpStatus(statusCode))
-            };
+            var message = GetMessageFromHttpStatus(statusCode);
+            var error = statusCode switch
+            {
+                401 => Error.Unauthorized(message),
+                403 => Error.Forbidden(message),
+                404 => Error.NotFound(message),
+                _ => Error.Internal(message)
+            };
 
             return Result<T>.Failure(error);
         }

183-203: LGTM!

Comprehensive HTTP status mapping with appropriate Portuguese user-facing messages. The fallback logic cleanly distinguishes server errors (5xx) from other unexpected codes.

Note: Similar message mappings exist in ErrorLoggingService.GetUserFriendlyMessage and ValidationMessages.cs. Consider consolidating these into a shared utility in the future to ensure consistency. Based on learnings, prefer reuse of Shared.Contracts for shared constants.

Keycloak configuration:
- Add frontchannelLogout and post-logout redirect URIs to customer-app client (mirrors admin-portal config)
- Add realm-roles protocol mapper to customer-app for consistent role claim handling across clients

CustomAccountClaimsPrincipalFactory:
- Use AuthConstants.Claims.Roles constant instead of hardcoded string for consistency
- Add null/whitespace check before adding role claims to prevent invalid authorization

ProvidersEffects:
- Remove unused CancellationTokenSource in HandleLoadProvidersAction (no cancellation logic implemented)
- Discard unused result variable in HandleDeleteProviderAction (all logic handled via callbacks)

ErrorHandlingService:
- Improve logging message for API exceptions (include StatusCode in log for better diagnostics)
- Refactor to reuse GetMessageFromHttpStatus for consistent error messages (eliminates duplication)

These changes improve code consistency, defensive programming, and maintainability.

Co-Authored-By: Warp <agent@warp.dev>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@src/Web/MeAjudaAi.Web.Admin/Authentication/CustomAccountClaimsPrincipalFactory.cs`:
- Line 3: The build fails because CustomAccountClaimsPrincipalFactory.cs imports
MeAjudaAi.Shared.Utilities.Constants but the MeAjudaAi.Shared project isn't
referenced; update MeAjudaAi.Web.Admin.csproj to add a project (or package)
reference to the MeAjudaAi.Shared assembly so the namespace
MeAjudaAi.Shared.Utilities.Constants resolves, or alternatively move/alias the
required constants into an already-referenced assembly used by
CustomAccountClaimsPrincipalFactory (or expose them via a shared package) —
locate uses in CustomAccountClaimsPrincipalFactory and ensure the referenced
symbol(s) in MeAjudaAi.Shared (the Constants class/namespace) are available at
compile time.
- Around line 45-73: In CustomAccountClaimsPrincipalFactory, guard and trim
rolesValue before JSON detection and before creating claims: first null-check
and do rolesValue = rolesValue?.Trim(); then use StartsWith('[') on the trimmed
value; when deserializing in the block for JsonSerializer.Deserialize<string[]>,
trim each role and skip null/empty/whitespace entries before AddClaim; also when
falling back in the catch or the non-array branch, only add the single Claim if
the trimmed rolesValue is not null/empty/whitespace. This ensures leading
whitespace doesn't break StartsWith and prevents empty claims from being added.

In `@src/Web/MeAjudaAi.Web.Admin/Features/Modules/Providers/ProvidersEffects.cs`:
- Around line 58-60: The lambda passed to ExecuteWithErrorHandlingAsync in
ProvidersEffects.cs is receiving a CancellationToken (ct) but not forwarding it
to GetProvidersAsync; update the call inside the lambda to pass ct into
_providersApi.GetProvidersAsync (e.g., change the delegate to call
GetProvidersAsync(action.PageNumber, action.PageSize, ct)) so cancellation is
propagated properly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Web/MeAjudaAi.Web.Admin/Features/Modules/Providers/ProvidersEffects.cs`:
- Around line 58-60: Replace Portuguese operation strings passed to
ExecuteWithErrorHandlingAsync with English equivalents: change the operation
argument for the call wrapping
_providersApi.GetProvidersAsync(action.PageNumber, action.PageSize, ct) from
"carregar provedores" to "Load providers", and update any other
ExecuteWithErrorHandlingAsync calls in ProvidersEffects.cs that use Portuguese
(e.g., the call around the block invoking _providersApi.* at lines ~131-133) to
their English counterparts so logged operation names are in English; leave
user-facing operationName strings in ExecuteApiCallAsync unchanged.
🧹 Nitpick comments (1)
src/Web/MeAjudaAi.Web.Admin/Features/Modules/Providers/ProvidersEffects.cs (1)

80-84: Consider logging when 401 snackbar is suppressed.

This will help diagnose real auth issues without showing a toast.

♻️ Suggested tweak
             if (result.Error?.StatusCode != 401)
             {
                 _snackbar.Add(errorMessage, Severity.Error);
             }
+            else
+            {
+                _logger.LogDebug("Suppressing providers snackbar for 401 during initialization");
+            }

@github-actions
Copy link

📊 Code Coverage Report

Coverage: 90.29% (extracted from Cobertura (Aggregated Direct))

📈 Coverage Details

  • Coverage badges: Coverage
  • Minimum threshold: 80% (warning) / 90% (good)
  • Report format: Auto-detected from OpenCover/Cobertura XML files
  • Coverage source: Cobertura (Aggregated Direct)

📋 Coverage Analysis

  • Line Coverage: Shows percentage of code lines executed during tests
  • Branch Coverage: Shows percentage of code branches/conditions tested
  • Complexity: Code complexity metrics for maintainability

🎯 Quality Gates

  • Pass: Coverage ≥ 90%
  • ⚠️ Warning: Coverage 80-89%
  • Fail: Coverage < 80%

📁 Artifacts

  • Coverage reports: Available in workflow artifacts
  • Test results: TRX files with detailed test execution data

This comment is updated automatically on each push to track coverage trends.

@frigini frigini merged commit fd23789 into master Jan 22, 2026
11 checks passed
@frigini frigini deleted the feature/keycloak-client-automation branch January 22, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant