docs: update README for new endpoints, fix config name, remove dead field
All checks were successful
check / check (push) Successful in 1m24s
All checks were successful
check / check (push) Successful in 1m24s
- Document POST /api/v1/logout endpoint - Document GET /api/v1/users/me endpoint - Add 'users' field to GET /api/v1/server response docs - Fix config: SESSION_TIMEOUT -> SESSION_IDLE_TIMEOUT - Update storage section: session expiry is implemented - Update roadmap: move session expiry to implemented - Remove dead SessionTimeout config field from Go code
This commit is contained in:
73
README.md
73
README.md
@@ -1158,6 +1158,55 @@ curl -s http://localhost:8080/api/v1/channels/general/members \
|
|||||||
-H "Authorization: Bearer $TOKEN" | jq .
|
-H "Authorization: Bearer $TOKEN" | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### POST /api/v1/logout — Logout
|
||||||
|
|
||||||
|
Destroy the current client's auth token. If no other clients remain on the
|
||||||
|
session, the user is fully cleaned up: parted from all channels (with QUIT
|
||||||
|
broadcast to members), session deleted, nick released.
|
||||||
|
|
||||||
|
**Request:** No body. Requires auth.
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{"status": "ok"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
|
||||||
|
| Status | Error | When |
|
||||||
|
|--------|-------|------|
|
||||||
|
| 401 | `unauthorized` | Missing or invalid auth token |
|
||||||
|
|
||||||
|
**curl example:**
|
||||||
|
```bash
|
||||||
|
curl -s -X POST http://localhost:8080/api/v1/logout \
|
||||||
|
-H "Authorization: Bearer $TOKEN" | jq .
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /api/v1/users/me — Current User Info
|
||||||
|
|
||||||
|
Return the current user's session state. This is an alias for
|
||||||
|
`GET /api/v1/state`.
|
||||||
|
|
||||||
|
**Request:** No body. Requires auth.
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"nick": "alice",
|
||||||
|
"channels": [
|
||||||
|
{"id": 1, "name": "#general", "topic": "Welcome!"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**curl example:**
|
||||||
|
```bash
|
||||||
|
curl -s http://localhost:8080/api/v1/users/me \
|
||||||
|
-H "Authorization: Bearer $TOKEN" | jq .
|
||||||
|
```
|
||||||
|
|
||||||
### GET /api/v1/server — Server Info
|
### GET /api/v1/server — Server Info
|
||||||
|
|
||||||
Return server metadata. No authentication required.
|
Return server metadata. No authentication required.
|
||||||
@@ -1166,10 +1215,17 @@ Return server metadata. No authentication required.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "My Chat Server",
|
"name": "My Chat Server",
|
||||||
"motd": "Welcome! Be nice."
|
"motd": "Welcome! Be nice.",
|
||||||
|
"users": 42
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| `name` | string | Server display name |
|
||||||
|
| `motd` | string | Message of the day |
|
||||||
|
| `users` | integer | Number of currently active user sessions |
|
||||||
|
|
||||||
### GET /.well-known/healthcheck.json — Health Check
|
### GET /.well-known/healthcheck.json — Health Check
|
||||||
|
|
||||||
Standard health check endpoint. No authentication required.
|
Standard health check endpoint. No authentication required.
|
||||||
@@ -1572,8 +1628,10 @@ skew issues) and simpler than UUIDs (integer comparison vs. string comparison).
|
|||||||
- **Queue entries**: Stored until pruned. Pruning by `QUEUE_MAX_AGE` is
|
- **Queue entries**: Stored until pruned. Pruning by `QUEUE_MAX_AGE` is
|
||||||
planned.
|
planned.
|
||||||
- **Channels**: Deleted when the last member leaves (ephemeral).
|
- **Channels**: Deleted when the last member leaves (ephemeral).
|
||||||
- **Users/sessions**: Deleted on `QUIT`. Session expiry by `SESSION_TIMEOUT`
|
- **Users/sessions**: Deleted on `QUIT` or `POST /api/v1/logout`. Idle
|
||||||
is planned.
|
sessions are automatically expired after `SESSION_IDLE_TIMEOUT` (default
|
||||||
|
24h) — the server runs a background cleanup loop that parts idle users
|
||||||
|
from all channels, broadcasts QUIT, and releases their nicks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1590,7 +1648,7 @@ directory is also loaded automatically via
|
|||||||
| `DBURL` | string | `file:./data.db?_journal_mode=WAL` | SQLite connection string. For file-based: `file:./path.db?_journal_mode=WAL`. For in-memory (testing): `file::memory:?cache=shared`. |
|
| `DBURL` | string | `file:./data.db?_journal_mode=WAL` | SQLite connection string. For file-based: `file:./path.db?_journal_mode=WAL`. For in-memory (testing): `file::memory:?cache=shared`. |
|
||||||
| `DEBUG` | bool | `false` | Enable debug logging (verbose request/response logging) |
|
| `DEBUG` | bool | `false` | Enable debug logging (verbose request/response logging) |
|
||||||
| `MAX_HISTORY` | int | `10000` | Maximum messages retained per channel before rotation (planned) |
|
| `MAX_HISTORY` | int | `10000` | Maximum messages retained per channel before rotation (planned) |
|
||||||
| `SESSION_TIMEOUT` | int | `86400` | Session idle timeout in seconds (planned). Sessions with no activity for this long are expired and the nick is released. |
|
| `SESSION_IDLE_TIMEOUT` | string | `24h` | Session idle timeout as a Go duration string (e.g. `24h`, `30m`). Sessions with no activity for this long are expired and the nick is released. |
|
||||||
| `QUEUE_MAX_AGE` | int | `172800` | Maximum age of client queue entries in seconds (48h). Entries older than this are pruned (planned). |
|
| `QUEUE_MAX_AGE` | int | `172800` | Maximum age of client queue entries in seconds (48h). Entries older than this are pruned (planned). |
|
||||||
| `MAX_MESSAGE_SIZE` | int | `4096` | Maximum message body size in bytes (planned enforcement) |
|
| `MAX_MESSAGE_SIZE` | int | `4096` | Maximum message body size in bytes (planned enforcement) |
|
||||||
| `LONG_POLL_TIMEOUT`| int | `15` | Default long-poll timeout in seconds (client can override via query param, server caps at 30) |
|
| `LONG_POLL_TIMEOUT`| int | `15` | Default long-poll timeout in seconds (client can override via query param, server caps at 30) |
|
||||||
@@ -1610,7 +1668,7 @@ SERVER_NAME=My Chat Server
|
|||||||
MOTD=Welcome! Be excellent to each other.
|
MOTD=Welcome! Be excellent to each other.
|
||||||
DEBUG=false
|
DEBUG=false
|
||||||
DBURL=file:./data.db?_journal_mode=WAL
|
DBURL=file:./data.db?_journal_mode=WAL
|
||||||
SESSION_TIMEOUT=86400
|
SESSION_IDLE_TIMEOUT=24h
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -2008,11 +2066,14 @@ GET /api/v1/challenge
|
|||||||
- [x] Docker deployment
|
- [x] Docker deployment
|
||||||
- [x] Prometheus metrics endpoint
|
- [x] Prometheus metrics endpoint
|
||||||
- [x] Health check endpoint
|
- [x] Health check endpoint
|
||||||
|
- [x] Session expiry — auto-expire idle sessions, release nicks
|
||||||
|
- [x] Logout endpoint (`POST /api/v1/logout`)
|
||||||
|
- [x] Current user endpoint (`GET /api/v1/users/me`)
|
||||||
|
- [x] User count in server info (`GET /api/v1/server`)
|
||||||
|
|
||||||
### Post-MVP (Planned)
|
### Post-MVP (Planned)
|
||||||
|
|
||||||
- [ ] **Hashcash proof-of-work** for session creation (abuse prevention)
|
- [ ] **Hashcash proof-of-work** for session creation (abuse prevention)
|
||||||
- [ ] **Session expiry** — auto-expire idle sessions, release nicks
|
|
||||||
- [ ] **Queue pruning** — delete old queue entries per `QUEUE_MAX_AGE`
|
- [ ] **Queue pruning** — delete old queue entries per `QUEUE_MAX_AGE`
|
||||||
- [ ] **Message rotation** — enforce `MAX_HISTORY` per channel
|
- [ ] **Message rotation** — enforce `MAX_HISTORY` per channel
|
||||||
- [ ] **Channel modes** — enforce `+i`, `+m`, `+s`, `+t`, `+n`
|
- [ ] **Channel modes** — enforce `+i`, `+m`, `+s`, `+t`, `+n`
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ type Config struct {
|
|||||||
Port int
|
Port int
|
||||||
SentryDSN string
|
SentryDSN string
|
||||||
MaxHistory int
|
MaxHistory int
|
||||||
SessionTimeout int
|
|
||||||
MaxMessageSize int
|
MaxMessageSize int
|
||||||
MOTD string
|
MOTD string
|
||||||
ServerName string
|
ServerName string
|
||||||
@@ -62,7 +61,6 @@ func New(
|
|||||||
viper.SetDefault("METRICS_USERNAME", "")
|
viper.SetDefault("METRICS_USERNAME", "")
|
||||||
viper.SetDefault("METRICS_PASSWORD", "")
|
viper.SetDefault("METRICS_PASSWORD", "")
|
||||||
viper.SetDefault("MAX_HISTORY", "10000")
|
viper.SetDefault("MAX_HISTORY", "10000")
|
||||||
viper.SetDefault("SESSION_TIMEOUT", "86400")
|
|
||||||
viper.SetDefault("MAX_MESSAGE_SIZE", "4096")
|
viper.SetDefault("MAX_MESSAGE_SIZE", "4096")
|
||||||
viper.SetDefault("MOTD", "")
|
viper.SetDefault("MOTD", "")
|
||||||
viper.SetDefault("SERVER_NAME", "")
|
viper.SetDefault("SERVER_NAME", "")
|
||||||
@@ -87,7 +85,6 @@ func New(
|
|||||||
MetricsUsername: viper.GetString("METRICS_USERNAME"),
|
MetricsUsername: viper.GetString("METRICS_USERNAME"),
|
||||||
MetricsPassword: viper.GetString("METRICS_PASSWORD"),
|
MetricsPassword: viper.GetString("METRICS_PASSWORD"),
|
||||||
MaxHistory: viper.GetInt("MAX_HISTORY"),
|
MaxHistory: viper.GetInt("MAX_HISTORY"),
|
||||||
SessionTimeout: viper.GetInt("SESSION_TIMEOUT"),
|
|
||||||
MaxMessageSize: viper.GetInt("MAX_MESSAGE_SIZE"),
|
MaxMessageSize: viper.GetInt("MAX_MESSAGE_SIZE"),
|
||||||
MOTD: viper.GetString("MOTD"),
|
MOTD: viper.GetString("MOTD"),
|
||||||
ServerName: viper.GetString("SERVER_NAME"),
|
ServerName: viper.GetString("SERVER_NAME"),
|
||||||
|
|||||||
Reference in New Issue
Block a user