API orientada a território + curadoria comunitária.
A API da Araponga cria um núcleo confiável para território, vínculos, feed e mapa. Ela prioriza regras explícitas (visibilidade, validação e moderação) para que experiências locais sejam auditáveis e evoluam com segurança.
Por que território?
Território é o recorte geográfico base. Ele separa o “onde” do “quem” e do “o quê”. Isso evita que conteúdo social distorça o mapa e mantém o contexto local como primeira-class.
Governança em camadas
Vínculos (visitor/resident), validações comunitárias e moderação (reports/bloqueios) formam as camadas que definem o que aparece no feed e no mapa.
Do visitante ao morador validado
Visitante
Visitantes declaram vínculo com role=Visitor. O status já nasce como
VALIDATED, permitindo participação básica e acesso a conteúdo público.
Pedido de moradia
Para virar morador, o usuário declara role=Resident. O vínculo fica
PENDING até passar pela aprovação comunitária.
Aprovação comunitária
Apenas moradores VALIDATED do território podem aprovar pedidos via
PATCH /api/v1/territories/{territoryId}/membership/{membershipId}/validation.
Fundador
Se ainda não existe nenhum morador validado no território, o primeiro residente é autoaprovado e se torna o fundador.
Unidade primária com vínculo estrutural
Estado atual
Territórios continuam sendo a unidade primária de organização. Todo conteúdo e governança são ancorados diretamente no território selecionado.
ParentTerritoryId
O campo ParentTerritoryId existe apenas para modelar hierarquia estrutural
(ex.: bairro → município). Ele ainda não gera herança de permissões, feeds ou validações.
Roadmap (não implementado)
Herança de permissões, feeds agregados e regras automáticas por hierarquia permanecem como roadmap e não fazem parte do backend atual.
Semântica de negócio
Territory-first
Território é uma célula geográfica neutra. Não carrega conteúdo social embutido; ele apenas organiza contexto, priorização e governança.
Memberships
Vínculos entre usuário e território podem ser VISITOR ou RESIDENT. O status de verificação segue PENDING, VALIDATED ou REJECTED e influencia visibilidade e autorização.
Feature flags por território
Cada território pode habilitar flags como AlertPosts e EventPosts
em /api/v1/territories/{territoryId}/features. Elas controlam quais tipos de post são aceitos.
Curadoria/Validação
A validação de vínculos de moradia é comunitária: apenas moradores VALIDATED aprovam pedidos. Curadores continuam responsáveis por validação de entidades do mapa e alertas ambientais.
Moderação & segurança
Reports e bloqueios moldam o que aparece no feed e no mapa. Bloqueios filtram o conteúdo de usuários bloqueados tanto no feed quanto em entidades do mapa criadas por eles. Limiares automáticos ainda não estão implementados no backend atual.
Entidades principais e relacionamentos
O que liga com o quê
- User cria identidade autenticada e recebe role (Visitor/Resident/Curator).
- TerritoryMembership conecta User ↔ Territory e define role/status.
- CommunityPost pertence ao Territory e pode referenciar MapEntity.
- PostGeoAnchor ancora posts no mapa.
- MapEntity pertence ao Territory, começa como sugerida e pode ser validada.
- Reports e Blocks modulam visibilidade e segurança.
- Feature Flags habilitam tipos de post por território (AlertPosts/EventPosts).
Por que existe
- Separar território de identidade evita acoplamento social no mapa.
- Vínculos explicitam presença local e governança comunitária.
- Posts + geo anchors conectam feed e mapa sem confundir o domínio.
- Moderação mantém confiança com regras auditáveis.
Sequências orientadas a produto e API
1. Autenticação social → JWT
Use POST /api/v1/auth/social com Provider, ExternalId, DisplayName
e CPF ou ForeignDocument. A resposta traz o token JWT.
curl -X POST http://localhost:8080/api/v1/auth/social \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"externalId": "abc-123",
"displayName": "Ana Souza",
"cpf": "12345678900",
"email": "ana@exemplo.com"
}'
2. Descoberta de território
GET /api/v1/territories lista territórios disponíveis. Para busca, use
/search ou /nearby com lat e lng.
curl "http://localhost:8080/api/v1/territories/nearby?lat=-23.55&lng=-46.63&radiusKm=10"
3. Seleção de território (sessão)
Defina o território ativo com POST /api/v1/territories/selection usando
X-Session-Id. Esse header substitui o territoryId em várias rotas.
curl -X POST http://localhost:8080/api/v1/territories/selection \
-H "Content-Type: application/json" \
-H "X-Session-Id: session-123" \
-d '{"territoryId": "11111111-1111-1111-1111-111111111111"}'
4. Feed territorial
GET /api/v1/feed retorna posts filtrados pelo território ativo. Visitantes veem
apenas posts públicos publicados. Moradores veem conteúdo ampliado.
curl http://localhost:8080/api/v1/feed \
-H "Authorization: Bearer <token>" \
-H "X-Session-Id: session-123"
5. Criar post + âncoras geográficas
Para criar post use POST /api/v1/feed. É obrigatório enviar
X-Geo-Latitude/X-Geo-Longitude e ao menos uma âncora geográfica.
Visitantes só podem criar posts do tipo Event (eventos pendentes de aprovação).
curl -X POST http://localhost:8080/api/v1/feed \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "X-Session-Id: session-123" \
-H "X-Geo-Latitude: -23.55" \
-H "X-Geo-Longitude: -46.63" \
-d '{
"title": "Mutirão de limpeza",
"content": "Encontro sábado 9h.",
"type": "Event",
"visibility": "Public",
"mapEntityId": null,
"geoAnchors": [{"latitude": -23.55, "longitude": -46.63, "type": "EVENT"}]
}'
6. Mapa: entidades, pins e validação
Use GET /api/v1/map/entities e /pins para visualizar. Sugestões usam
POST /api/v1/map/entities (categorias: estabelecimento, órgão do governo, espaço público,
espaço natural). Confirmações usam /confirmations e validações /validation
são exclusivas para curadores.
curl -X POST http://localhost:8080/api/v1/map/entities \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "X-Session-Id: session-123" \
-d '{
"name": "Praça Central",
"category": "espaço público",
"latitude": -23.55,
"longitude": -46.63
}'
7. Membership: visitor → resident
POST /api/v1/territories/{territoryId}/membership declara vínculo. A validação
(morador) é feita por moradores validados em /validation. O status atual está em
GET /api/v1/territories/{territoryId}/membership/me. Se não houver morador validado,
o primeiro residente é autoaprovado como fundador.
Quando a policy exige presença, envie X-Geo-Latitude/X-Geo-Longitude.
8. Moderação: reports e bloqueios
Reports podem ser enviados para posts e usuários. Bloqueios removem conteúdo do feed e do mapa
de quem foi bloqueado. Use POST /api/v1/reports/posts/{postId},
POST /api/v1/reports/users/{userId} e POST /api/v1/blocks/users/{userId}.
JWT (HS256)
O token é emitido pelo endpoint /api/v1/auth/social. Ele utiliza algoritmo HS256 e
valida issuer e audience conforme configuração em appsettings.json.
| Configuração | Chave | Local |
|---|---|---|
| Issuer | Jwt:Issuer | backend/Araponga.Api/appsettings.json |
| Audience | Jwt:Audience | backend/Araponga.Api/appsettings.json |
| SigningKey | Jwt:SigningKey | backend/Araponga.Api/appsettings.json |
Território, sessão e geolocalização
Várias rotas aceitam o território via territoryId na query ou via sessão com
X-Session-Id. Além disso, algumas operações exigem presença geográfica.
| Header | Uso | Onde é obrigatório |
|---|---|---|
| X-Session-Id | Seleciona território ativo da sessão. | Feed, Mapa, Health, Moderação quando territoryId não está na query. |
| X-Geo-Latitude / X-Geo-Longitude | Comprova presença no território. | Criação de posts e declaração de membership conforme policy. |
PresencePolicy:Policy. O valor padrão atual é ResidentOnly.
API Explorer (Swagger UI local)
O explorer usa a especificação real da API. Ele tenta carregar o Swagger dinâmico em
/swagger/v1/swagger.json (quando o backend roda em Development) e usa
fallback para ./openapi.json. A navegação é feita por tags, endpoints e schemas.
Explorer pronto para carregar.
Como interpretar respostas
Formato de erro
Erros de validação costumam retornar {"error": "mensagem"}. Exceções não tratadas
retornam ProblemDetails com title, status, detail,
traceId e path.
Códigos comuns
- 400 dados inválidos ou headers obrigatórios ausentes.
- 401 token ausente/ inválido ou falta de permissão.
- 404 recurso inexistente (territory, post, user).
- 409 não usado atualmente.
- 500 exceções não tratadas (ProblemDetails).
GET /health responde {"status": "ok"} e
GET /api/v1/health/indicators exibe indicadores do território ativo. Logs seguem a
configuração padrão de Logging no appsettings.json.
Copie e cole (5–10 comandos)
# 1) Rodar API
ASPNETCORE_ENVIRONMENT=Development dotnet run --project backend/Araponga.Api --urls http://localhost:8080
# 2) Autenticação social (gera token)
curl -X POST http://localhost:8080/api/v1/auth/social \
-H "Content-Type: application/json" \
-d '{"provider":"google","externalId":"abc-123","displayName":"Ana","cpf":"12345678900"}'
# 3) Descobrir território
curl http://localhost:8080/api/v1/territories
# 4) Selecionar território (X-Session-Id)
curl -X POST http://localhost:8080/api/v1/territories/selection \
-H "Content-Type: application/json" \
-H "X-Session-Id: session-123" \
-d '{"territoryId":"11111111-1111-1111-1111-111111111111"}'
# 5) Listar feed
curl http://localhost:8080/api/v1/feed \
-H "Authorization: Bearer <token>" \
-H "X-Session-Id: session-123"
# 6) Listar pins do mapa
curl http://localhost:8080/api/v1/map/pins \
-H "Authorization: Bearer <token>" \
-H "X-Session-Id: session-123"
Versionamento
A API atual utiliza prefixo /api/v1. Mudanças compatíveis devem manter o contrato dentro
dessa versão. Para evolução maior, a estratégia recomendada é introduzir um novo prefixo.