Files
rustification-server/README.md

182 lines
5.9 KiB
Markdown

# rustification-server
REST API backend for Rustification, a chat application. Built with Axum, SQLx, and PostgreSQL.
## Tech stack
| Layer | Technology |
|-------|-----------|
| HTTP framework | [Axum](https://github.com/tokio-rs/axum) 0.8 |
| Database | PostgreSQL 17 via [SQLx](https://github.com/launchbadge/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
```bash
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:
```bash
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`.
```bash
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`](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
```