66 lines
2.7 KiB
Markdown
66 lines
2.7 KiB
Markdown
# Invites & Join Requests
|
|
|
|
> **Status:** Active
|
|
> **Last updated:** 2026-07-05
|
|
|
|
## Overview
|
|
|
|
Invite links and join-request approval let users join private or moderated chat-servers without public listing. Spans signaling **server** REST + HTML invite pages and the product **client** `server-directory` invite feature.
|
|
|
|
## Responsibilities
|
|
|
|
- Server: create time-limited invites, resolve invite metadata, record join requests, notify requesters on moderation decisions.
|
|
- Client: create/copy invite links, render invite landing UX, call join API with invite codes/passwords.
|
|
- It does NOT own: WebSocket room membership (`join_server` after REST join succeeds).
|
|
|
|
## Key concepts
|
|
|
|
- **Invite:** opaque id mapping to a server; may expire.
|
|
- **Join request:** pending membership when server requires approval.
|
|
- **request_update:** server-pushed WebSocket notification when a moderator approves/denies.
|
|
|
|
## REST API
|
|
|
|
### Invites
|
|
|
|
| Method | Path | Auth | Purpose |
|
|
|--------|------|------|---------|
|
|
| POST | `/api/servers/:id/invites` | Bearer | Create invite (moderator) |
|
|
| GET | `/api/invites/:id` | Public | Resolve invite metadata + server card |
|
|
| GET | `/invite/:id` | Public | HTML invite landing page (browser) |
|
|
|
|
### Join
|
|
|
|
| Method | Path | Auth | Purpose |
|
|
|--------|------|------|---------|
|
|
| POST | `/api/servers/:id/join` | Bearer | Join with password, invite id, or public access; may create join request |
|
|
|
|
### Join requests (moderation)
|
|
|
|
| Method | Path | Auth | Purpose |
|
|
|--------|------|------|---------|
|
|
| GET | `/api/servers/:id/requests` | Bearer (`manageServer`) | List pending requests |
|
|
| PUT | `/api/requests/:id` | Bearer (`manageServer`) | Approve or deny; body `{ status }` |
|
|
|
|
`PUT /api/requests/:id` validates optional `ownerId` matches authenticated user, checks `manageServer` permission, updates status, and sends `notifyUser(request.userId, { type: 'request_update', request })`.
|
|
|
|
## Client flow
|
|
|
|
1. Moderator creates invite via `ServerDirectoryFacade.createInvite()`.
|
|
2. Recipient opens `/invite/:id` or deep link; client resolves `GET /api/invites/:id`.
|
|
3. Authenticated user calls `POST /api/servers/:id/join` with invite payload.
|
|
4. On approval-required servers, user waits for `request_update` or polls requests list (moderator UI).
|
|
|
|
## Related
|
|
|
|
- [server-directory.md](server-directory.md) — join/leave REST
|
|
- [authentication.md](authentication.md) — bearer on mutations
|
|
- [signaling.md](signaling.md) — `join_server` after join
|
|
- Domain README: [`toju-app/src/app/domains/server-directory/README.md`](../../toju-app/src/app/domains/server-directory/README.md)
|
|
|
|
## Changelog
|
|
|
|
| Date | Change |
|
|
|------|--------|
|
|
| 2026-07-05 | Initial cross-context invite/join-request contract |
|