Files
summercms/.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-DISCUSSION-LOG.md
2026-09-19 14:04:36 +02:00

6.2 KiB

Phase 6: HTTP routing, auth groups and rate limiting - Discussion Log

Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.

Date: 2026-09-19 Phase: 6-HTTP routing, auth groups and rate limiting Areas discussed: Bucket scope & limiter, Token guard depth, Outbound fetch guard, Route surface & OAuth exempt


Bucket scope & limiter

Which buckets does Phase 6 define and test?

Option Description Selected
Fonoteka 5 + mechanism Five fonoteka named buckets plus inline throttle form; other plugins' buckets land with those plugins; roadmap "seven" corrected ✓
All 11 now Every named bucket of every ported plugin declared in Phase 6
Fonoteka 5 + user 3 Add the user stub's three buckets now

Wire behavior

Option Description Selected
Exact Laravel parity Fixed window, X-RateLimit-* headers, Retry-After/Reset on 429, same 429 body ✓
Same limits, Go-native algorithm Token bucket/sliding window, same headers, edge bursts may differ
You decide Researcher picks cheapest faithful option

Counter store

Option Description Selected
In-process, stdlib Mutex map + sweep behind surf.Limiter, Store interface for later ✓
In-process via otter (cooler) Adds otter and the cooler package now
Postgres-backed Survives restarts, DB write per limited request

Client IP

Option Description Selected
Trusted-proxy config XFF honored only from trusted CIDRs, rightmost untrusted hop ✓
RemoteAddr only Ignore forwarding headers
Always trust X-Forwarded-For Spoofable if directly reachable

Notes: Scouting found five named buckets in fonoteka/routes.php, not seven; eight more live in user, feedback, websockets and journal plugins.


Token guard depth

How real is the personal-token guard?

Option Description Selected
Real verifier, test-only minting ApiToken lookup with PHP rules; tokens inserted by tests/seed hooks; Phase 7 adds CRUD ✓
Interface + fake guard Real lookup waits for AUTH-03

Where does inv.scope land?

Option Description Selected
Phase 6, in golem15.fonoteka It is the token group's auth step; exact 401/403 bodies; parameterized names in surf ✓
Phase 7 with AUTH-03 Guard-only auth in Phase 6

Guard registry shape

Option Description Selected
Named guards in bouncer Registry by name, Guard interface, single user accessor plus credential accessor, fail boot on duplicates ✓
Just named middleware Convention only
You decide Planner picks

OAuth bearer guard slot

Option Description Selected
Name reserved, no implementation Registry proven with two real guards ✓
Stub that always 401s Mount /oauth/mcp behind a rejecting guard

Outbound fetch guard

Host policy

Option Description Selected
Per-caller policy, both modes AllowHosts and/or PublicOnly; private-IP block always on ✓
Allow-list only Manual cover URL would need an allow-list (behavior change)

DNS rebinding

Option Description Selected
Dial-time IP check net.Dialer Control validates the connected IP ✓
Match PHP: pre-resolve only Keep the gap, note the risk

Scope

Option Description Selected
Framework helper + tests only Fetcher ports are Phase 12/14 ✓
Helper + both fonoteka fetchers Port ManualCoverUrlFetcher and CoverImporter now

Limits source

Option Description Selected
Caller passes them; no framework default-open Zero value fails construction
Framework defaults in config http.fetch.* defaults, overridable per call ✓

Notes: User chose framework config defaults over the recommended caller-required values. Recorded with the constraint that an effective limit can never be unlimited.


Route surface & OAuth exempt

Route surface

Option Description Selected
Groups + proving routes only All groups as builders; only real handlers mounted; genres under both prefixes; no 501 shells ✓
All 154 as 501 shells Whole surface registered now
Shells for auth-sensitive routes only Public, token and OAuth groups fully registered

OAuth exemption

Option Description Selected
Group flag + boot-time inspection Raw group refuses house middleware, bare 500 on recover, route table + route:list ✓
Separate mux mounted beside the pipeline Own ServeMux and minimal chain
You decide Planner picks

Response conventions

Option Description Selected
Framework helpers + types, no envelope middleware JSON writer, Carbon time, nullable bool, never-nil slice ✓
Helpers live in fonoteka.go Framework stays neutral

CORS and body limits

Option Description Selected
Path-scoped CORS from config, exact parity Reproduce cors.php, no CORS on /_fonoteka/api; body limits from real deployment values ✓
CORS on everything Header difference on the JWT group

Claude's Discretion

Package homes and names, sweep interval and Store shape, inline throttle key composition (must match Laravel), swag/openapi-typescript workflow and drift check, locale stage depth, how group mutual exclusivity is asserted, plan count and split.

Deferred Ideas

User/feedback/websockets buckets with their plugins; shared limiter store after v1; cooler/otter cache when needed; cover fetcher ports in Phase 12/14; OAuth guard and handlers in Phase 8; token CRUD in Phase 7.