FastAPI scaffold + GroupMe webhook handler #4

Closed
opened 2026-03-28 19:14:59 +00:00 by forgejo_admin · 1 comment

Type

Feature

Lineage

Standalone — scoped from westside-ai-assistant design spec (2026-03-28).

Repo

forgejo_admin/westside-ai-assistant

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

Context

GroupMe's bot API POSTs a JSON payload to a registered callback URL whenever a message is sent in the group. This ticket scaffolds the entire FastAPI app and implements the webhook handler with safety checks (group allowlist, bot self-ignore). The callback just logs and returns 200 for now — the AI engine is wired in ticket #6.

File Targets

Files the agent should create:

  • app/__init__.py — empty
  • app/main.py — FastAPI app with lifespan, include routers
  • app/groupme.py — POST /groupme/callback router: parse body, validate group_id against GROUPME_ALLOWED_GROUP_IDS, ignore sender_type=="bot", extract sender_name + text, log, return 200
  • app/health.py — GET /healthz (200), GET /health/ready (check config loaded)
  • app/config.py — pydantic BaseSettings: BASKETBALL_API_URL, GROUPME_ALLOWED_GROUP_IDS (comma-separated str → list), GROUPME_BOT_ID, GROUPME_BOT_TOKEN, ANTHROPIC_API_KEY, ANTHROPIC_MODEL, KEYCLOAK_REALM_URL, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET
  • Dockerfile — multi-stage: python:3.12-slim, EXPOSE 8000, gunicorn with uvicorn workers
  • .woodpecker.yaml — test on push/PR, build+push on main, internal Harbor URL, exclude .argocd-source-*
  • requirements.txt — fastapi, uvicorn, gunicorn, httpx, anthropic, pydantic-settings, pytest, pytest-asyncio
  • tests/__init__.py — empty
  • tests/test_groupme.py — test valid message parsed, test bot message ignored, test wrong group ignored, test missing fields returns 200 (don't crash on malformed)

Files the agent should NOT touch:

  • No other repos

Acceptance Criteria

  • POST /groupme/callback with valid payload returns 200 and logs message
  • Bot messages (sender_type=="bot") are silently ignored (200, no processing)
  • Messages from non-allowlisted groups are silently ignored (200, no processing)
  • GET /healthz returns 200
  • GET /health/ready returns 200 when config is loaded
  • Docker image builds successfully
  • All tests pass

Test Expectations

  • Unit test: valid GroupMe payload → message extracted correctly
  • Unit test: bot sender_type → ignored
  • Unit test: wrong group_id → ignored
  • Unit test: malformed payload → 200 (graceful, no crash)
  • Run command: pytest tests/ -v

Constraints

  • Follow basketball-api Dockerfile pattern for multi-stage build
  • Use internal Harbor URL in .woodpecker.yaml
  • Port 8000 for container and health probes
  • No AI logic in this ticket — callback just logs for now

Checklist

  • PR opened
  • Tests pass
  • Docker builds
  • No unrelated changes
  • project-westside-ai-assistant — parent project
  • arch-domain-westside-ai-assistant — A1: GroupMe Webhook Handler
### Type Feature ### Lineage Standalone — scoped from westside-ai-assistant design spec (2026-03-28). ### Repo `forgejo_admin/westside-ai-assistant` ### 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 ### Context GroupMe's bot API POSTs a JSON payload to a registered callback URL whenever a message is sent in the group. This ticket scaffolds the entire FastAPI app and implements the webhook handler with safety checks (group allowlist, bot self-ignore). The callback just logs and returns 200 for now — the AI engine is wired in ticket #6. ### File Targets Files the agent should create: - `app/__init__.py` — empty - `app/main.py` — FastAPI app with lifespan, include routers - `app/groupme.py` — POST /groupme/callback router: parse body, validate group_id against GROUPME_ALLOWED_GROUP_IDS, ignore sender_type=="bot", extract sender_name + text, log, return 200 - `app/health.py` — GET /healthz (200), GET /health/ready (check config loaded) - `app/config.py` — pydantic BaseSettings: BASKETBALL_API_URL, GROUPME_ALLOWED_GROUP_IDS (comma-separated str → list), GROUPME_BOT_ID, GROUPME_BOT_TOKEN, ANTHROPIC_API_KEY, ANTHROPIC_MODEL, KEYCLOAK_REALM_URL, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET - `Dockerfile` — multi-stage: python:3.12-slim, EXPOSE 8000, gunicorn with uvicorn workers - `.woodpecker.yaml` — test on push/PR, build+push on main, internal Harbor URL, exclude .argocd-source-* - `requirements.txt` — fastapi, uvicorn, gunicorn, httpx, anthropic, pydantic-settings, pytest, pytest-asyncio - `tests/__init__.py` — empty - `tests/test_groupme.py` — test valid message parsed, test bot message ignored, test wrong group ignored, test missing fields returns 200 (don't crash on malformed) Files the agent should NOT touch: - No other repos ### Acceptance Criteria - [ ] `POST /groupme/callback` with valid payload returns 200 and logs message - [ ] Bot messages (sender_type=="bot") are silently ignored (200, no processing) - [ ] Messages from non-allowlisted groups are silently ignored (200, no processing) - [ ] `GET /healthz` returns 200 - [ ] `GET /health/ready` returns 200 when config is loaded - [ ] Docker image builds successfully - [ ] All tests pass ### Test Expectations - [ ] Unit test: valid GroupMe payload → message extracted correctly - [ ] Unit test: bot sender_type → ignored - [ ] Unit test: wrong group_id → ignored - [ ] Unit test: malformed payload → 200 (graceful, no crash) - Run command: `pytest tests/ -v` ### Constraints - Follow basketball-api Dockerfile pattern for multi-stage build - Use internal Harbor URL in .woodpecker.yaml - Port 8000 for container and health probes - No AI logic in this ticket — callback just logs for now ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] Docker builds - [ ] No unrelated changes ### Related - `project-westside-ai-assistant` — parent project - `arch-domain-westside-ai-assistant` — A1: GroupMe Webhook Handler
Author
Owner

Scope Review: READY

Review note: review-596-2026-03-28
Greenfield scaffold with well-specified file targets, complete template, full traceability (story:read-ops, story:safety, arch:A1), and testable acceptance criteria. 7 AC exceeds the >5 decomposition threshold but all are tightly coupled to a single coherent feature — no meaningful split possible. No upstream blockers. Clear to move to next_up.

## Scope Review: READY Review note: `review-596-2026-03-28` Greenfield scaffold with well-specified file targets, complete template, full traceability (story:read-ops, story:safety, arch:A1), and testable acceptance criteria. 7 AC exceeds the >5 decomposition threshold but all are tightly coupled to a single coherent feature — no meaningful split possible. No upstream blockers. Clear to move to next_up.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/westside-ai-assistant#4
No description provided.