- Notification bell with invites (accept/decline refreshes workspaces) and unread badge (polling + socket push); team chat view realtime - Avatar/background uploads in settings + glassmorphism widgets toggle; background layer resolves /uploads URLs; full-bleed blurred backdrop - Sidebar: visible creation errors, working sub-pages (parent_id), TEAM badge workspaces, refresh button, chat nav; admin creates users - Tasks: per-team boards, assignee select with avatars; admin tabs for users/teams/groups (team workspaces, permission checkboxes) - Register view removed (admin-only accounts); login localized; prettier emoji set; scaling/overflow + mobile fixes
122 lines
4.7 KiB
Markdown
122 lines
4.7 KiB
Markdown
# API Reference
|
|
|
|
Base URL: `http://localhost:3000/api`. Auth: `Authorization: Bearer <jwt>`.
|
|
|
|
## Auth
|
|
|
|
### POST /auth/register
|
|
```json
|
|
{ "email": "a@example.com", "name": "Ada", "password": "secret123" }
|
|
```
|
|
-> `201 { user, token }`. Errors: `400` validation, `409` email taken.
|
|
|
|
### POST /auth/login
|
|
```json
|
|
{ "email": "a@example.com", "password": "secret123" }
|
|
```
|
|
-> `200 { user, token }`. Errors: `401` invalid credentials.
|
|
|
|
### GET /auth/me
|
|
-> `200 { user }`.
|
|
|
|
```bash
|
|
curl -X POST localhost:3000/api/auth/register \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"email":"a@example.com","name":"Ada","password":"secret123"}'
|
|
```
|
|
|
|
## Workspaces
|
|
|
|
| Method | Path | Role | Description |
|
|
|--------|------|------|-------------|
|
|
| GET | `/workspaces` | member | List my workspaces |
|
|
| POST | `/workspaces` | any logged-in | Create workspace (caller becomes owner) |
|
|
| GET | `/workspaces/:id` | viewer+ | Get workspace |
|
|
| PATCH | `/workspaces/:id` | admin+ | Rename |
|
|
| DELETE | `/workspaces/:id` | owner | Delete |
|
|
| GET | `/workspaces/:id/members` | viewer+ | List members |
|
|
| POST | `/workspaces/:id/members` | admin+ | Invite `{email, role}` (role: admin/member/viewer) |
|
|
| PATCH | `/workspaces/:id/members/:userId` | admin+ | Change role |
|
|
| DELETE | `/workspaces/:id/members/:userId` | admin+ | Remove member |
|
|
|
|
Roles rank: `viewer < member < admin < owner`. Viewers read only.
|
|
|
|
## Pages
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/pages/by-workspace/:workspaceId` | List pages (flat, client builds tree) |
|
|
| POST | `/pages` | Create `{workspace_id, parent_id?, title?}` (member+) |
|
|
| GET | `/pages/:id` | Get page + comments |
|
|
| PATCH | `/pages/:id` | Update title/icon/cover/content/position/parent/archive (member+) |
|
|
| DELETE | `/pages/:id` | Delete incl. children via FK cascade |
|
|
| GET | `/pages/search/query?q=&workspace_id=` | Title search |
|
|
| POST | `/pages/:id/comments` | Add comment `{body}` |
|
|
| DELETE | `/pages/:pageId/comments/:commentId` | Delete (author or admin+) |
|
|
|
|
Content fields: `content_json` (TipTap JSON), `content_html` (rendered HTML).
|
|
|
|
## Users
|
|
|
|
- `GET /users/search?email=` — lookup for invites (auth required).
|
|
- `GET /users/discover?q=` — fuzzy discovery (min 2 chars, max 10 hits, no hashes).
|
|
- `PATCH /users/me` — profile/appearance (`name, email, avatar, locale, theme, bg_image, bg_blur`).
|
|
- `PATCH /users/me/password` — `{ currentPassword, newPassword }`.
|
|
|
|
## Books
|
|
|
|
- `GET /books/by-workspace/:workspaceId`, `POST /books {workspace_id,title?,icon?}`
|
|
- `PATCH /books/:id`, `DELETE /books/:id` (pages inside cascade).
|
|
|
|
## Tasks
|
|
|
|
- `GET /tasks/by-workspace/:workspaceId?status=&from=&to=` (calendar range on `due_at`)
|
|
- `POST /tasks {workspace_id, book_id?, page_id?, title, status?, priority?, due_at?}`
|
|
- `PATCH /tasks/:id`, `DELETE /tasks/:id`
|
|
|
|
## Time tracking
|
|
|
|
- `GET /time/by-workspace/:workspaceId` → `{ entries, open }`
|
|
- `POST /time/start {workspace_id, book_id?, page_id?, description?}` (409 if running)
|
|
- `POST /time/stop {workspace_id}` → sets `ended_at` + `duration_seconds`
|
|
- `PATCH /time/:id`, `DELETE /time/:id` (own or admin+)
|
|
|
|
## Admin (requires `is_admin`)
|
|
|
|
- `GET /admin/overview` → counts + recent users
|
|
- `GET /admin/users`, `POST /admin/users {name,email,password,is_admin?}` (admins create
|
|
accounts; public registration is disabled once installed), `PATCH /admin/users/:id`,
|
|
`DELETE /admin/users/:id`
|
|
|
|
## Invites & notifications
|
|
|
|
- `POST /workspaces/:id/members {email,role}` → pending invite + notification
|
|
(workspace admin+ or `workspace.invite` permission)
|
|
- `GET /invites/mine`, `POST /invites/:id/accept`, `POST /invites/:id/decline`
|
|
- `GET /notifications/mine?unread=1` → `{ notifications, unread }`
|
|
- `PATCH /notifications/:id/read`, `POST /notifications/read-all`
|
|
|
|
## Chat / teams / groups / upload
|
|
|
|
- `GET /chat/:workspaceId`, `POST /chat/:workspaceId {body}`, `DELETE /chat/message/:id`
|
|
- `GET /teams/by-workspace/:id`, `POST /teams`, `PATCH/DELETE /teams/:id`,
|
|
team members CRUD, `POST /teams/:id/workspace {name}` (team workspace + badge)
|
|
- `GET /groups/by-workspace/:id` (seeds `Team Creators`), groups CRUD + members
|
|
- `POST /upload` (multipart image ≤5MB) → `{ url: /uploads/... }`
|
|
|
|
## Health
|
|
|
|
- `GET /health` -> `{ok:true, db:'up'}` or `503 {ok:false, db:'down'}`.
|
|
|
|
## Real-time (Socket.IO)
|
|
|
|
Connect: `io(url, { auth: { token } })`.
|
|
|
|
- `page:join { pageId }` — join room; server checks workspace membership.
|
|
- `page:edit { pageId, content_json, content_html }` — persist + broadcast to others.
|
|
Viewers are ignored server-side.
|
|
- `typing { pageId, name }` — broadcast typing indicator.
|
|
- Server events: `page:updated { page, from? }`, `page:deleted { id }`,
|
|
`comment:added { comment }`, `presence:update { members: [{userId,email,name}] }`,
|
|
`error:message { error }`.
|