Skip to content

Phase 1: backend core (models, sinks, mountable ingest router)#10

Merged
thorwhalen merged 1 commit into
mainfrom
phase-1-backend-core
Jun 21, 2026
Merged

Phase 1: backend core (models, sinks, mountable ingest router)#10
thorwhalen merged 1 commit into
mainfrom
phase-1-backend-core

Conversation

@thorwhalen

Copy link
Copy Markdown
Member

Implements the Phase 1 deterministic backend spine — the testable, framework-free core plus a mountable FastAPI surface. Closes the backend portion of #2, #3, #4 and the seam-level part of #5.

What's in

  • base.py — Pydantic SSOT: Report/ReportSubmission/Identity/Environment/Category/Status/Attachment/LogEntry/NetEntry. ([P1] Report data model (Pydantic SSOT in base.py) #2)
  • sinks/Sink protocol + BaseSink; StoreSink (dol/dict default) and GitHubIssuesSink with a dependency-injected create_issue (testable, no network), lazy ghapi factory, and image-attachment-aware markdown rendering (no GitHub attach API → embed a URL). ([P1] Sink protocol + GitHubIssuesSink #3)
  • ingest.pyprocess_submission (pure core; server owns id/created_at/identity/origin/status) + make_router (mountable APIRouter, include_router into enlace, user_dependency seam for enlace_auth) + make_app. ([P1] Mountable FastAPI ingest router #4)
  • security.py — origin allow-list + in-memory fixed-window rate limiter behind a RateLimiter protocol. ([P1] Public-endpoint hardening (unauthenticated ingest) #5 seams; Turnstile/Redis still open)
  • config.py / storage.pyHeedConfig + dol-backed report/attachment stores.
  • CI — wads uv reusable-workflow stub; [tool.wads.ci.publish] enabled = false (design phase, no PyPI publish on merge).

Design adherence

Standalone (no enlace import at load), pluggable sinks (strategy), privacy-by-default (opt-in console/network dropped unless HeedConfig enables), no secrets in the browser (server brokers GitHub). See misc/docs/design.md and Discussion #1.

Tests

9 tests pass (model round-trip, both sinks, ingest core + router happy-path, origin-block); ruff format + lint clean.

Deferred (follow-ups)

Widget #6 · opt-in capture + masking + consent #6/#7 · AI triage + dedup + MCP #7 · full hardening (Turnstile/Redis/payload moderation) #5 · unified-inbox UX #9.

https://claude.ai/code/session_01TH3XxQ8qW36Dh3eCVjX1PA

…ing seams)

Deterministic, dependency-injected backend spine:
- base.py: Pydantic SSOT (Report/ReportSubmission/Identity/Environment/Status/...)
- sinks/: Sink protocol + StoreSink (default) + GitHubIssuesSink (injected
  create_issue, lazy ghapi, image-attachment-aware markdown body)
- ingest.py: process_submission core + mountable FastAPI router + make_app
- security.py: origin allow-list + in-memory rate-limiter seams
- storage.py / config.py: dol-backed stores + HeedConfig
- 9 tests (model round-trip, sinks, ingest core + router, origin block); ruff-clean
- CI workflow stub (wads uv reusable); publish disabled during design phase

Privacy by default: opt-in console/network dropped unless config enables.
Refs #2 #3 #4 #5

Claude-Session: https://claude.ai/code/session_01TH3XxQ8qW36Dh3eCVjX1PA
@thorwhalen thorwhalen merged commit 256abc9 into main Jun 21, 2026
2 checks passed
@thorwhalen thorwhalen deleted the phase-1-backend-core branch June 21, 2026 17:00
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