Review: FastAPI scaffold + GroupMe webhook handler

review-596-2026-03-28 Doc

review ready

Verdict: READY

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — Standalone, scoped from westside-ai-assistant design spec (2026-03-28)
  • [x] Repo — forgejo_admin/westside-ai-assistant
  • [x] User Story — As Marcus (admin) I want the AI service to receive GroupMe messages via webhook callback so that every message I send in the approved group reaches the AI engine
  • [x] Context — GroupMe bot callback explanation, scope boundary (no AI logic, just log and 200)
  • [x] File Targets — 10 files to create, explicit "don't touch" section (no other repos)
  • [x] Acceptance Criteria — 7 testable items
  • [x] Test Expectations — 4 unit tests + run command (pytest tests/ -v)
  • [x] Constraints — Follow basketball-api Dockerfile pattern, internal Harbor URL, port 8000, no AI logic
  • [x] Checklist — PR opened, tests pass, Docker builds, no unrelated changes
  • [x] Related — project-westside-ai-assistant + arch-domain-westside-ai-assistant referenced

Traceability

  • [x] story:read-ops — Marcus can query player/team/payment data via GroupMe (webhook is the entry point for all read queries)
  • [x] story:safety — Bot locked to approved group via GROUPME_ALLOWED_GROUP_IDS allowlist, bot self-ignore via sender_type check
  • [x] arch:A1 — GroupMe Webhook Handler per arch-domain-westside-ai-assistant domain model
  • [x] Forgejo issue — forgejo_admin/westside-ai-assistant#4, open

File Targets

All 10 files are to be created in a greenfield repo. Verified repo state via Forgejo API — only README.md exists. Parent directories (app/, tests/) will be created by the agent.
  • [x] app/__init__.py — empty, standard Python package init
  • [x] app/main.py — FastAPI app with lifespan, router includes
  • [x] app/groupme.py — POST /groupme/callback with group allowlist + bot self-ignore
  • [x] app/health.py — GET /healthz (200) + GET /health/ready (config check)
  • [x] app/config.py — pydantic BaseSettings with 8 env vars specified
  • [x] Dockerfile — multi-stage python:3.12-slim, gunicorn+uvicorn, EXPOSE 8000
  • [x] .woodpecker.yaml — test on push/PR, build+push on main, Harbor URL
  • [x] requirements.txt — fastapi, uvicorn, gunicorn, httpx, anthropic, pydantic-settings, pytest, pytest-asyncio
  • [x] tests/__init__.py — empty
  • [x] tests/test_groupme.py — 4 test cases covering valid, bot-ignore, wrong-group, malformed
Targets are specific enough for an agent to act without guessing. basketball-api Dockerfile pattern verified at ~/basketball-api/Dockerfile — multi-stage with python:3.12-slim base confirmed.

Repo Placement

Correct. Issue filed on forgejo_admin/westside-ai-assistant, all file targets within that repo. No cross-repo scope. "Files the agent should NOT touch: No other repos" is explicitly stated.

Dependencies

  • [x] No upstream code dependencies — greenfield scaffold, first code in the repo (satisfied)
  • [x] basketball-api Dockerfile pattern — exists at ~/basketball-api/Dockerfile (satisfied, reference only)
Downstream items depend on this ticket:
  • #597 (Basketball-API client with Keycloak auth) — needs scaffold
  • #598 (Anthropic AI engine) — needs scaffold + client
  • #599 (GroupMe bot registration + go-live) — needs deployed app
No unresolved dependencies blocking execution.

Acceptance Criteria

All 7 AC are testable and specific:
  • [x] POST /groupme/callback returns 200 and logs — verifiable via pytest TestClient + caplog
  • [x] Bot messages ignored (sender_type=="bot") — verifiable via pytest with bot payload
  • [x] Non-allowlisted groups ignored — verifiable via pytest with wrong group_id
  • [x] GET /healthz returns 200 — verifiable via pytest TestClient
  • [x] GET /health/ready returns 200 when config loaded — verifiable via pytest TestClient
  • [x] Docker image builds successfully — verifiable via docker build
  • [x] All tests pass — verifiable via pytest tests/ -v
No ambiguous language. Each criterion maps directly to a verification command.

Blast Radius

  • Touches 1 repo (westside-ai-assistant) with 10 new files, 0 modifications
  • groupme-sdk (~/groupme-sdk) is outbound-only — no conflict with this inbound webhook handler
  • basketball-api has its own GroupMe integration (outbox service) — completely separate concern
  • groupme-mcp is a separate MCP tool service — no overlap
  • Rollback: trivial — delete the branch or revert the single PR
No blast radius. Isolated greenfield service with no shared state or cross-service dependencies at this stage.

Decomposition Assessment

Three-thing limit: 10 file targets, but all are boilerplate for a single FastAPI scaffold. The "things" are: (1) app scaffold with config, (2) webhook handler + tests, (3) Dockerfile + CI. Borderline 3 discrete changes.
Five-minute rule: Estimated 3-5 minutes for a skilled agent. Patterns are well-specified (follow basketball-api). All files are boilerplate generation, not complex logic.
7 AC exceeds the >5 threshold, but the AC are all facets of the same feature — they cannot be meaningfully split without creating two PRs that depend on each other. Splitting "handler code" from "Dockerfile + CI" would produce PRs that can't be independently validated.
No independent subtasks that could be parallelized — all files must ship in one PR for the scaffold to be functional.
No decomposition needed.

Recommendation

No action needed. Ticket is ready for agent dispatch.