- Settings window with tabs: profile (name, email, avatar, password), appearance (light/dark/system), language (de/en/zh), background (gradient presets, custom URL, blur toggle); persisted server-side - i18n dictionaries (de/en/zh) applied across nav, sidebar, tasks, calendar, time tracking, admin, invites and comments - Greeting header with time-of-day message, live clock and date; cooler theme, cards, kanban, calendar grid and data-table styling - Shared sidebar: nav, collapsible books with per-book pages, top-level pages, search; user chip opens settings - Tasks kanban with priorities, overdue flags and book/page links; calendar month view fed by task deadlines; time view with entries, durations and totals; top-right live timer with optional book link - User discovery autocomplete in the invite card; editor gains tables and checklists; standalone theme buttons removed
3.8 KiB
3.8 KiB
API Reference
Base URL: http://localhost:3000/api. Auth: Authorization: Bearer <jwt>.
Auth
POST /auth/register
{ "email": "a@example.com", "name": "Ada", "password": "secret123" }
-> 201 { user, token }. Errors: 400 validation, 409 email taken.
POST /auth/login
{ "email": "a@example.com", "password": "secret123" }
-> 200 { user, token }. Errors: 401 invalid credentials.
GET /auth/me
-> 200 { user }.
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 ondue_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}→ setsended_at+duration_secondsPATCH /time/:id,DELETE /time/:id(own or admin+)
Admin (requires is_admin)
GET /admin/overview→ counts + recent usersGET /admin/users,PATCH /admin/users/:id {is_admin},DELETE /admin/users/:id
Health
GET /health->{ok:true, db:'up'}or503 {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 }.