55a2af4756ba44c7c858dadbd96d792ee8be0e20
Eleven resolved decision tickets plus two research notes, produced with /wayfinder before any code was written. They live next to the code they explain rather than in the issue tracker: they are reasoning documents, not open work, and in a tracker they would drift from the code with no diff and no review. The value is in the rejected alternatives. Why a counter under a row lock and not BIGSERIAL, why an event log and not a column on messages, why resync is a 200 with a discriminated body and not a 4xx, why the fan-out trait was deleted again, why voice is peer-to-peer with a hard six-person cap and no speculative SFU seam, and why Linux needs a native media stack while the other three platforms do not. Two entries record where the spec was wrong and got corrected: created_at was never a safe sort key, and an unread count cannot be derived without fetching because seq counts events rather than messages. Open work is tracked as issues, not here.
rustification-server
REST API backend for Rustification, a chat application. Built with Axum, SQLx, and PostgreSQL.
Tech stack
| Layer | Technology |
|---|---|
| HTTP framework | Axum 0.8 |
| Database | PostgreSQL 17 via SQLx 0.9 |
| Auth | JWT (jsonwebtoken) + Argon2 password hashing |
| Runtime | Tokio |
| Migrations | SQLx built-in |
Features
- Auth — register, login, logout, JWT refresh via bearer tokens
- Workspaces — create and manage workspaces with owner/admin/member roles and invite tokens
- Conversations — DMs, group chats, and channels; public or private
- Messages — send, edit, soft-delete; per-conversation history
- Attachments — link files to messages (URL-based)
- Reactions — emoji reactions per message
- Soft deletes on users, workspaces, conversations, and messages (excluded from all list/get responses)
Prerequisites
- Rust (edition 2024)
- PostgreSQL 17, or Docker + Docker Compose
Getting started
1. Configure environment
cp .env.example .env
# Edit .env — set POSTGRES_*, DATABASE_URL, API_URL, API_PORT, JWT_SECRET
2a. Run with Docker Compose (recommended)
Starts PostgreSQL and the server together:
docker compose up --build
The server will be available at http://localhost:3000. Migrations run automatically on startup — no manual step needed.
2b. Run locally
Requires a running PostgreSQL instance matching your DATABASE_URL.
cargo run
Migrations are embedded in the binary and run automatically when the server starts.
Environment variables
| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
Postgres connection string | postgres://admin:password@localhost:5432/rustification |
POSTGRES_DB |
Database name (used by Docker) | rustification |
POSTGRES_USER |
Postgres user (used by Docker) | admin |
POSTGRES_PASSWORD |
Postgres password (used by Docker) | password |
API_URL |
Bind address | 0.0.0.0 |
API_PORT |
Bind port | 3000 |
JWT_SECRET |
Secret for signing JWTs | any random string |
API
Base URL: http://localhost:3000/api/v1
All routes except /auth/* require a Authorization: Bearer <token> header.
Auth
| Method | Path | Description |
|---|---|---|
| POST | /auth/register |
Register a new user |
| POST | /auth/login |
Login, returns JWT |
| POST | /auth/refresh |
Refresh access token |
| POST | /auth/logout |
Logout (invalidates refresh token) |
Users
| Method | Path | Description |
|---|---|---|
| GET | /users |
List all users |
| POST | /users |
Create a user |
| GET | /users/{id} |
Get a user |
| PUT | /users/{id} |
Update display_name / avatar_url / bio |
| DELETE | /users/{id} |
Soft-delete a user |
Workspaces
| Method | Path | Description |
|---|---|---|
| GET | /workspaces |
List workspaces |
| POST | /workspaces |
Create a workspace |
| GET | /workspaces/{id} |
Get a workspace |
| PUT | /workspaces/{id} |
Update name / slug |
| DELETE | /workspaces/{id} |
Soft-delete |
| GET | /workspaces/{id}/members |
List members |
| POST | /workspaces/{id}/members |
Add member (role: owner | admin | member) |
| PUT | /workspaces/{workspace_id}/members/{user_id} |
Update role / display name |
| DELETE | /workspaces/{workspace_id}/members/{user_id} |
Remove member |
| GET | /workspaces/{id}/invitations |
List invite tokens |
| POST | /workspaces/{id}/invitations |
Create invite token |
| DELETE | /invitations/{id} |
Delete invite token |
Conversations
| Method | Path | Description |
|---|---|---|
| GET | /conversations |
List conversations (filter: ?workspace_id=uuid) |
| POST | /conversations |
Create (kind: dm | group | channel) |
| GET | /conversations/{id} |
Get a conversation |
| PUT | /conversations/{id} |
Update name / is_public |
| DELETE | /conversations/{id} |
Soft-delete |
| GET | /conversations/{id}/members |
List members |
| POST | /conversations/{id}/members |
Add member |
| DELETE | /conversations/{conversation_id}/members/{user_id} |
Remove member |
Messages
| Method | Path | Description |
|---|---|---|
| GET | /conversations/{id}/messages |
List messages (chronological) |
| POST | /messages |
Send a message |
| GET | /messages/{id} |
Get a message |
| PUT | /messages/{id} |
Edit content |
| DELETE | /messages/{id} |
Soft-delete |
Attachments & Reactions
| Method | Path | Description |
|---|---|---|
| GET | /messages/{id}/attachments |
List attachments |
| POST | /attachments |
Create attachment |
| DELETE | /attachments/{id} |
Delete attachment |
| GET | /messages/{id}/reactions |
List reactions |
| POST | /reactions |
Add reaction |
| DELETE | /reactions/{id} |
Remove reaction |
Full request/response shapes are documented in docs/api.md.
Response codes
| Status | Meaning |
|---|---|
| 200 | OK |
| 201 | Created |
| 204 | Deleted (no body) |
| 404 | Not found |
| 500 | Internal server error |
Project structure
src/
├── main.rs # Server setup, env, DB pool
├── route.rs # Route definitions (public + protected)
├── middleware.rs # JWT auth middleware
├── model.rs # SQLx types and response structs
├── schema.rs # Request body structs
└── handlers/ # One file per resource
├── auth.rs
├── auth_token.rs
├── user.rs
├── workspace.rs
├── workspace_member.rs
├── workspace_invitation.rs
├── conversation.rs
├── conversation_member.rs
├── message.rs
├── attachment.rs
└── reaction.rs
migrations/ # SQLx migration files
Description
Languages
Rust
98.7%
Dockerfile
1.3%