Skip to content

feat(moderation): a DevDogs moderation receiver with user.delete (A6) - #892

Open
sloanfinger wants to merge 1 commit into
mainfrom
df/a6-moderation-receiver
Open

sloanfinger wants to merge 1 commit into
mainfrom
df/a6-moderation-receiver

Conversation

@sloanfinger

Copy link
Copy Markdown
Contributor

Stage A6 (TASK-528) of the DevDogs deferred-features plan. It pairs with DevDogsUGA #215 (A1, the user.delete type) and #218 (A2, the job that sends it), and mirrors DogPack #135 (A5). Decision: devdogs-plan/account-deletion-decisions.md §14 (Q48) and §15.

What it delivers

DogDays had no moderation receiver. This adds one:

  • POST /platform-moderation, a Worker route. DogDays has no Edge Functions deploy, so this goes on the Worker rather than in a Supabase function.
    • Signatures are checked with the sdk's verifyMessage: constant-time compare, ±300 s tolerance, and several secrets accepted during a rotation.
    • Replays are recorded as duplicates.
  • moderation schema. events, decisions and user_states are server-only: RLS on, no grants to anyone but service_role. dogdays.apply_moderation_event is SECURITY DEFINER with an empty search path.
  • user.delete.
    • Finds the DogDays user linked to the DevDogs identity and deletes them through the admin API. DogDays' foreign keys cascade, and rows keyed by the platform id are deleted explicitly.
    • An unknown user or a repeat returns 2xx. An admin failure returns 500, and the platform retries.
    • A stale user.delete still deletes, because deletion is final, and it leaves a deleted tombstone so a replay can't touch a later account.
  • Other messages. Suspensions and bans lock the user out (banned_until, sessions removed). content.* messages are recorded only.
  • The user.delete type is accepted locally, pointing at DevDogsUGA Move configs to one file #215, because no published sdk has it yet.

New secrets for Sloan (staging and production GitHub environments)

  • PLATFORM_MODERATION_SECRET (whsec_...):
    1. Create DogDays' production OAuth client on the platform.
    2. Register it under Apps Outside the Platform with slug dogdays, endpoint https://dogdays.dev/platform-moderation (staging: https://staging.dogdays.dev/platform-moderation) and one placeholder content type. Registration refuses an empty list.
    3. Copy the secret it shows once.
  • SECRET_KEY: this Supabase project's sb_secret_... key. This is the first server secret DogDays' Worker has.

Push both with pnpm backstage env push --repo dogdays --target <target> and redeploy. Until both exist, the route answers 503 and nothing else changes.

Please confirm

  1. A Worker route, not a Supabase function. The cost is a server key on the Worker.
  2. A ban for someone who has never signed in is recorded but doesn't stop their first sign-in. DogDays has no restriction check like DogPack's, and a trigger on auth.identities could add one.
  3. The placeholder content type. Alternatively, the platform could allow an empty list for receive-only apps.
  4. The deleted tombstone stays forever, as it does in DogPack.

Not verified

  • The pgTAP file (35 assertions) runs for the first time in CI.
  • No vinext build has confirmed that /platform-moderation routes.
  • No real signed delivery has been sent end to end. Once it's deployed, run pnpm devtools moderation send user.delete --to https://staging.dogdays.dev/platform-moderation.

Checks run locally: vitest src/server/moderation (23 tests pass), tsc for the app and cloudflare/, and eslint on the touched files.

🤖 Generated with Claude Code

@sloanfinger
sloanfinger requested review from a team, SidhantDash and kquakk as code owners October 24, 2026 01:01
@sloanfinger

Copy link
Copy Markdown
Contributor Author

Reviewed signed moderation delivery, replay handling, and local account deletion against main at b99dbf34e788.

No additional confirmed correctness issue identified in the inspected changes.

Existing CI results were inspected; the complete repository test suite was not rerun for this review.

…#892)

One signed commit for the whole pull request: main requires verified signatures, and the build-session commits predate the signing key. Same files as the 3 commits it replaces (previous head b99dbf3).
@sloanfinger
sloanfinger force-pushed the df/a6-moderation-receiver branch from b99dbf3 to e9e4a0e Compare October 27, 2026 08:17

This branch has not been deployed

No deployments
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