docs: setup, hosting, API, architecture and roadmap
- SETUP: local dev guide (env vars, DB migrate, backend/frontend, troubleshooting) - HOSTING: bare-metal guide (systemd + Nginx + TLS + backups) and Docker Compose guide (deploy, reverse proxy, updates, backup/restore) - API: REST contract with curl examples and Socket.IO event protocol - ARCHITECTURE: stack, data model, auth model, realtime design, theming - ROADMAP: webapp MVP/next steps plus Tauri desktop clients for Windows, macOS and Linux with release-binary plan
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# Architecture
|
||||
|
||||
## Stack
|
||||
|
||||
- **Frontend:** Vue 3 (Composition API + `<script setup>`), Vite, Vue Router, Pinia,
|
||||
Axios, Socket.IO client, TipTap editor. Theme via CSS variables (`data-theme`).
|
||||
- **Backend:** Node.js 20, Express 4, Socket.IO 4, `pg` (node-postgres), JWT, bcryptjs.
|
||||
- **DB:** PostgreSQL 14+. Single schema file (`backend/src/db/schema.sql`), applied via
|
||||
`npm run migrate` or `psql`.
|
||||
|
||||
## Data model
|
||||
|
||||
```text
|
||||
users (id, email unique, name, password_hash)
|
||||
└─< workspace_members (workspace_id, user_id, role) >─┐
|
||||
workspaces (id, name, owner_id -> users) <───────────────┘
|
||||
└─< pages (id, workspace_id, parent_id self-FK, title, icon, cover,
|
||||
content_json JSONB, content_html TEXT, position, is_archived)
|
||||
└─< comments (id, page_id, author_id, body)
|
||||
```
|
||||
|
||||
- Nesting via `parent_id` self-reference (`ON DELETE CASCADE` removes subtrees).
|
||||
- Owner auto-added as `workspace_members(role=owner)` via trigger.
|
||||
- `updated_at` maintained by trigger.
|
||||
|
||||
## Auth & authorization
|
||||
|
||||
- Register/login return a signed JWT (`sub=user.id`). Client stores it in
|
||||
`localStorage` and sends `Authorization: Bearer`.
|
||||
- Every workspace/page route resolves the caller's membership role server-side;
|
||||
viewers are blocked from mutations (`403`).
|
||||
- Socket.IO handshake verifies JWT; `page:join` and `page:edit` re-check membership
|
||||
and role against the DB (never trust client role).
|
||||
|
||||
## Realtime design (MVP)
|
||||
|
||||
- One Socket.IO room per page (`page:<id>`). Edits are debounced client-side (~800ms),
|
||||
persisted via REST `PATCH /pages/:id`, then broadcast `page:updated`.
|
||||
- `page:edit` socket events also persist server-side for clients that only use sockets.
|
||||
- Presence: server keeps `room -> socketId -> user` map, emits `presence:update`.
|
||||
- No CRDT/OT in MVP — last-write-wins. Concurrent edits converge on the last saved
|
||||
version; remote updates are ignored while the local user is the sender (`from`).
|
||||
See ROADMAP for planned Yjs-based conflict-free editing.
|
||||
|
||||
## Theming
|
||||
|
||||
- `useThemeStore` (`light`/`dark`/`system`), persisted in `localStorage`,
|
||||
applied as `document.documentElement.dataset.theme`. All colors are CSS variables.
|
||||
Reference in New Issue
Block a user