3.**Ban / suspension** — apply a temporary suspension or permanent ban to a
user, with enforcement at the auth boundary.
4.**Appeals** — a sanctioned user can appeal; staff can uphold or overturn.
The userbase being 18+ does **not** shrink the moderation need — harassment,
hate speech, spam, griefing, and CSAM/policy violations still require real
enforcement. Safety is a **blocking requirement**, not an add-on.
## 2. Existing constraints (do not re-build)
- **Auth:** JWT bearer; `get_current_user` / `CurrentUser` in
`app/dependencies.py`. Every new endpoint reuses it.
- **DB:** async SQLAlchemy + Alembic. Current head is `0002_add_date_of_birth_to_users`.
- **Models:** `User`, `World` (owner_id), `Asset` (owner_id, is_public). There
is no `role` field yet, and no chat/message table yet (social.md is planned,
not built).
- **Redis:** configured (`REDIS_URL`) but unused; not required by this feature.
- **Client:** Godot 4.6.2, minimal `main_menu.gd`; no report/chat UI yet.
## 3. Key design decisions
| Concern | Decision |
|---|---|
| Report target addressing | Generic `target_type` + `target_id` (string) so user/world/asset/message all flow through one report path; router resolves target existence via a small registry |
| Enforcement | Denormalized `banned_until` / `suspended_until` timestamps on `User` (kept in sync by moderation actions); `get_current_user` rejects sanctioned users with `403` so enforcement applies to **all** existing endpoints |
| Ban vs. suspension | Suspension = temporary (`expires_at`); ban = permanent (`expires_at IS NULL`). Both are rows in `moderation_actions` for auditability |
| Appeals | Appeal references the specific `moderation_action`; approving an appeal revokes the action and clears the user's sanction |
| Audit | Every moderation action is an append-only row with `moderator_id`, `reason`, `created_at`, `revoked_at`; reports record `resolved_by` + `resolution` |
## 4. Data model (target shape)
```
users
+ role ENUM(user, moderator, admin) default 'user'
+ banned_until TIMESTAMPTZ NULL
+ suspended_until TIMESTAMPTZ NULL
reports
id, reporter_id FK users, target_type ENUM(user,world,asset,chat_message),
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.