Context: From the anonymous-vs-authenticated architecture discussion. Design intent: an unregistered visitor can explore the site much like a member, without anonymous access to anything requiring a user or exposing other users' data. The house pattern already exists (api-conventions.md#312: controller [Authorize] + [AllowAnonymous] on public actions; TrailsController / PreRegistrationHub as examples) but is applied inconsistently — and [AllowAnonymous] alone controls access, not response shape.
Three-layer model to implement:
Transport — [Authorize] by default + explicit [AllowAnonymous] on the explore surface + a FallbackPolicy safety net so omissions fail closed (CR-2, this batch).
Contract — public vs enriched DTO projections (dual queries) for anything touching user data, so a guest response physically cannot carry user fields; a single anonymous endpoint is fine for pure public content. Also resolves "persistence entities leaked across the API boundary."
Application — optional MediatR authorization behavior keyed on a marker (IPublicRequest / default-deny), enforced regardless of dispatcher. Note the caching trap: an auth-aware cache key must include identity/anonymity, and the pipeline order is load-bearing.
**Context:** From the anonymous-vs-authenticated architecture discussion. Design intent: an unregistered visitor can *explore* the site much like a member, without anonymous access to anything requiring a user or exposing other users' data. The house pattern already exists (`api-conventions.md` #312: controller `[Authorize]` + `[AllowAnonymous]` on public actions; `TrailsController` / `PreRegistrationHub` as examples) but is applied inconsistently — and `[AllowAnonymous]` alone controls *access*, not *response shape*.
**Three-layer model to implement:**
1. **Transport** — `[Authorize]` by default + explicit `[AllowAnonymous]` on the explore surface + a `FallbackPolicy` safety net so omissions fail closed (CR-2, this batch).
2. **Contract** — public vs enriched DTO projections (dual queries) for anything touching user data, so a guest response *physically* cannot carry user fields; a single anonymous endpoint is fine for pure public content. Also resolves "persistence entities leaked across the API boundary."
3. **Application** — optional MediatR authorization behavior keyed on a marker (`IPublicRequest` / default-deny), enforced regardless of dispatcher. Note the caching trap: an auth-aware cache key must include identity/anonymity, and the pipeline order is load-bearing.
**Work items:**
- Per-controller classification: protect / explore / decide
- Characterize-first: make the anonymous Playwright walk comprehensive (#314 / #307) as the regression net BEFORE tightening
- SignalR: a curated public read-model for the "our hardware" showcase instead of exposing the raw telemetry hubs (#401)
- Children: CR-2 (transport layer), Trails anonymous-delete (specific instance)
**Acceptance criteria:**
- Every controller/hub explicitly classified; the anonymous surface is greppable (`[AllowAnonymous]`)
- Guest responses use public projections; no member data reachable anonymously
- Anonymous walk green throughout
**Effort:** L (epic) · Related: #401, #314, #307, #312, #298.
spikerj
added the agentic label 2026-07-05 20:24:45 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context: From the anonymous-vs-authenticated architecture discussion. Design intent: an unregistered visitor can explore the site much like a member, without anonymous access to anything requiring a user or exposing other users' data. The house pattern already exists (
api-conventions.md#312: controller[Authorize]+[AllowAnonymous]on public actions;TrailsController/PreRegistrationHubas examples) but is applied inconsistently — and[AllowAnonymous]alone controls access, not response shape.Three-layer model to implement:
[Authorize]by default + explicit[AllowAnonymous]on the explore surface + aFallbackPolicysafety net so omissions fail closed (CR-2, this batch).IPublicRequest/ default-deny), enforced regardless of dispatcher. Note the caching trap: an auth-aware cache key must include identity/anonymity, and the pipeline order is load-bearing.Work items:
Acceptance criteria:
[AllowAnonymous])Effort: L (epic) · Related: #401, #314, #307, #312, #298.
Children (this batch): CR-2 transport layer #415, Trails anonymous-delete #416. Related: #401 (SignalR hubs), #314 / #307 (anonymous Playwright walk — the regression net), #312, #298.