Files
modbison/docs/planning/social.md
T

8.2 KiB
Raw Blame History

Social — Friends, Chat & Groups — Plan

Status: Planned Owner: Platform team Feature ID: social Godot version: 4.6.2 stable Backend: FastAPI + SQLAlchemy (async) + PostgreSQL + Redis

1. Overview

This document breaks the Social feature into user stories and right-sized implementation tasks. The feature delivers:

  • Friends & following — a friend request/accept model plus a one-way follow relationship, with block lists.
  • Presence & status — online/offline, custom status message, last-seen.
  • Chat — direct messages (DM) and in-experience (world/room) chat with first-class safety: server-side text filtering, report-message, and rate limiting.
  • Groups — named groups with roles (owner/admin/member) and a simple group page.
  • Public profiles — avatar, bio, favorite experiences, and a friends list that respects privacy settings.

2. Why chat safety is the differentiator

The platform is explicitly meant to pull adults away from a youth-oriented competitor. Chat is the highest-risk surface: it is real-time, user-generated, and where abuse happens fastest. Safety is therefore treated as a blocking requirement, not an add-on:

  • Every message passes a server-side text filter before it is stored or delivered. The client filter is cosmetic only; the server is authoritative.
  • Every message can be reported; reports flow into a moderation queue with actor + reason + audit trail (mirroring content_moderation.md).
  • Sending is rate limited per user (Redis token bucket) to stop flooding and harassment-by-volume.
  • Report and block are always reachable from a message context in the UI.

3. Existing constraints (do not re-build)

  • Auth: JWT bearer tokens; get_current_user / CurrentUser dependency in app/dependencies.py. All social endpoints reuse this.
  • DB: async SQLAlchemy + Alembic; migration 0001_initial is the head.
  • Redis: configured (REDIS_URL) but unused so far; adopted here for presence and rate limiting.
  • Models: User, World (owner_id), Asset (owner_id, is_public). Avatars and favorite-experience references point at existing rows.
  • Client: Godot 4.6.2, minimal main_menu.gd; no social UI yet.

4. Key design decisions

Concern Decision
Message transport REST for send/history; WebSocket gateway for real-time delivery + presence (matches networking.md's "WebSocket as secondary transport" for chat)
Presence store Redis (TTL heartbeat) + persisted last_seen_at on the user record
Text filtering Pluggable TextFilter interface with a deterministic default (profanity list + normalization) so it runs without external services; third-party hook later
Rate limiting Redis token-bucket dependency, reusable across all social endpoints
Reports message_reports table + moderation endpoints (list/review/resolve) with audit fields
Friends vs. follow Friends = mutual (request→accept). Follow = one-way (no approval). Block = hard deny that also hides content and prevents DMs
Privacy Per-user settings JSON (profile_visibility, friends_list_visibility, favorites_visibility) enforced server-side on every read
Groups groups + group_members (role: owner/admin/member) + group page aggregate endpoint
Real-time One WebSocket endpoint multiplexing presence, DM, and world-chat messages via Redis pub/sub

5. User stories

US-1 Friends & following

As a player, I can send a friend request, accept/decline incoming requests, unfriend, follow/unfollow other players, and block users so they can't interact with me.

Acceptance criteria

  • Friend requests are one-directional until accepted; accepted friendships are mutual.
  • Follow is one-way and requires no approval.
  • Block prevents DMs, hides the blocked user's profile/friends interactions, and removes any existing friendship/follow between the two.
  • Duplicate/self requests are rejected idempotently.

US-2 Presence & status

As a player, I can see whether my friends are online, their custom status, and when they were last seen.

Acceptance criteria

  • Online/offline is derived from a server-side heartbeat (Redis TTL), not client claims.
  • last_seen_at persists and is visible (subject to privacy settings).
  • Custom status text is optional and length-limited.

US-3 Public profiles

As a player, I can view a public profile page showing avatar, bio, favorite experiences, and a friends list that respects the owner's privacy settings.

Acceptance criteria

  • Avatar and bio are editable by the owner only.
  • Favorite experiences reference existing World rows.
  • A viewer sees only the sections the owner's privacy settings allow; blocked users see a restricted view.

US-4 Chat (DM + in-experience) with safety

As a player, I can send direct messages and chat inside a world/room. Messages are filtered, rate limited, and reportable.

Acceptance criteria

  • Server filters message text before storing/delivering; filtered content is either rejected (blocking) or redacted (configurable per filter policy).
  • Send rate is limited per user (token bucket); excess sends get 429.
  • Every message has a stable id, author, timestamp, and conversation/world scope.
  • Any message can be reported with a reason; reports are stored and reviewable.
  • Real-time delivery over WebSocket with REST fallback for history.

US-5 Groups

As a player, I can create a group, join/leave groups, and (as owner/admin) manage roles and view a simple group page.

Acceptance criteria

  • Each group has exactly one owner and any number of admins/members.
  • Role transitions are authorized (only owner can transfer ownership or promote/demote admins).
  • Group page lists name, description, member list with roles, and member count.

US-6 Godot client

As a player, I can access friends, presence, chat, profiles, and groups from the game UI.

Acceptance criteria

  • An API client handles JWT auth, HTTP, and WebSocket for all social calls.
  • Dedicated screens/panels: friends+presence, DM & world chat (with report), profile page, group page.
  • Client-side filtering is cosmetic; server responses remain authoritative.

6. Task breakdown

Right-sized to 1–3 files / one coherent piece of functionality each. Task IDs are sequential for dependency chaining.

# Task Story Depends on
1 Friends/follow/block models + Alembic migration US-1 —
2 Friends & follow API router US-1 1
3 Presence & status model + endpoints (Redis heartbeat) US-2 —
4 Profile model + migration + own-profile endpoints US-3 1
5 Public profile view + favorites + privacy enforcement US-3 2, 4
6 Chat data models + migration (conversations, messages, reports) US-4 —
7 Text filtering service + profanity config US-4 —
8 Redis rate-limiting dependency US-4 —
9 DM chat send/list endpoints (filter + rate limit) US-4 6, 7, 8
10 Report-message endpoint + moderation queue US-4 6, 9
11 In-experience (world/room) chat endpoints US-4 9
12 Real-time WebSocket gateway (presence + DM + world chat) US-4 3, 9, 11
13 Group + membership models + migration US-5 —
14 Groups API (CRUD, join/leave, roles, group page) US-5 13
15 Godot API client (auth + HTTP + WebSocket) US-6 2
16 Godot friends & presence UI US-6 3, 15
17 Godot chat UI (DM + world chat + report) US-6 12, 15
18 Godot profile page UI US-6 5, 15
19 Godot groups UI + group page US-6 14, 15

7. Phasing

  • Phase 1 (data + core APIs): tasks 1–5 (friends, presence, profiles).
  • Phase 2 (chat safety — the differentiator): tasks 6–12 (chat + safety + realtime). This is the critical path and highest priority.
  • Phase 3 (groups): tasks 13–14.
  • Phase 4 (client): tasks 15–19, each landing after its backend dependency.

8. Out of scope for this feature

  • Age verification / maturity gating (covered by content_moderation.md).
  • Voice chat, media/image messages, message editing/deletion history.
  • Third-party profanity/toxicity vendors (the TextFilter interface leaves a hook, but the default is deterministic and dependency-free).
  • Mobile push notifications.