@hiai-gg/hiai-docs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/.all-contributorsrc +18 -0
  2. package/.claude/settings.local.json +61 -0
  3. package/.dockerignore +113 -0
  4. package/.env.example +68 -0
  5. package/.github/FUNDING.yml +5 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +74 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +78 -0
  8. package/.github/dependabot.yml +136 -0
  9. package/.github/pull_request_template.md +96 -0
  10. package/.github/workflows/ci.yml +283 -0
  11. package/AGENTS.md +237 -0
  12. package/CODE_OF_CONDUCT.md +134 -0
  13. package/CONTRIBUTING.md +77 -0
  14. package/Caddyfile +50 -0
  15. package/Dockerfile.backend +60 -0
  16. package/LICENSE +21 -0
  17. package/README.md +284 -0
  18. package/RELEASE_CHECKLIST.md +34 -0
  19. package/SECURITY.md +60 -0
  20. package/backend/package.json +43 -0
  21. package/backend/src/__tests__/auth-helpers.test.ts +51 -0
  22. package/backend/src/__tests__/chunker.test.ts +65 -0
  23. package/backend/src/__tests__/config.test.ts +91 -0
  24. package/backend/src/__tests__/csrf.test.ts +91 -0
  25. package/backend/src/__tests__/embedding.test.ts +48 -0
  26. package/backend/src/__tests__/rate-limit.test.ts +46 -0
  27. package/backend/src/__tests__/routes.test.ts +38 -0
  28. package/backend/src/__tests__/schema.test.ts +31 -0
  29. package/backend/src/__tests__/validation.test.ts +556 -0
  30. package/backend/src/api/middleware/auth.ts +56 -0
  31. package/backend/src/api/middleware/csrf.ts +91 -0
  32. package/backend/src/api/middleware/rate-limit.ts +77 -0
  33. package/backend/src/api/middleware/webhook-verify.ts +22 -0
  34. package/backend/src/api/routes/attachments.ts +280 -0
  35. package/backend/src/api/routes/auth.ts +52 -0
  36. package/backend/src/api/routes/collaboration.ts +121 -0
  37. package/backend/src/api/routes/documents.ts +664 -0
  38. package/backend/src/api/routes/folders.ts +226 -0
  39. package/backend/src/api/routes/search.ts +354 -0
  40. package/backend/src/api/routes/share.ts +512 -0
  41. package/backend/src/api/routes/tags.ts +247 -0
  42. package/backend/src/api/routes/versions.ts +99 -0
  43. package/backend/src/api/routes/webhooks.ts +43 -0
  44. package/backend/src/embedding/chunker.ts +74 -0
  45. package/backend/src/embedding/index.ts +117 -0
  46. package/backend/src/embedding/providers/ollama.ts +63 -0
  47. package/backend/src/embedding/providers/openrouter.ts +71 -0
  48. package/backend/src/embedding/utils.ts +13 -0
  49. package/backend/src/embedding/worker.ts +89 -0
  50. package/backend/src/index.ts +147 -0
  51. package/backend/src/lib/auth-helpers.ts +27 -0
  52. package/backend/src/lib/auth.ts +35 -0
  53. package/backend/src/lib/config.ts +73 -0
  54. package/backend/src/lib/db.ts +7 -0
  55. package/backend/src/lib/embedding-queue.ts +12 -0
  56. package/backend/src/lib/logger.ts +18 -0
  57. package/backend/src/lib/markdown-to-doc.ts +45 -0
  58. package/backend/src/lib/minio.ts +46 -0
  59. package/backend/src/lib/redis.ts +19 -0
  60. package/backend/src/lib/yjs-provider.ts +182 -0
  61. package/backend/tests/integration/_harness.ts +754 -0
  62. package/backend/tests/integration/auth.test.ts +296 -0
  63. package/backend/tests/integration/routes.documents.test.ts +459 -0
  64. package/backend/tests/integration/routes.folders.test.ts +337 -0
  65. package/backend/tests/integration/routes.search.test.ts +322 -0
  66. package/backend/tests/integration/routes.share.test.ts +773 -0
  67. package/backend/tests/integration/routes.tags.test.ts +425 -0
  68. package/backend/tests/integration/routes.versions.test.ts +233 -0
  69. package/backend/tsconfig.json +18 -0
  70. package/docker-compose.yml +218 -0
  71. package/docs/API.md +328 -0
  72. package/docs/ARCHITECTURE.md +75 -0
  73. package/docs/DEPLOYMENT.md +113 -0
  74. package/docs/PRODUCTION_STATUS.md +61 -0
  75. package/docs/openapi.json +385 -0
  76. package/frontend/.svelte-kit.old/ambient.d.ts +230 -0
  77. package/frontend/.svelte-kit.old/env.d.ts +1 -0
  78. package/frontend/.svelte-kit.old/generated/client/app.js +46 -0
  79. package/frontend/.svelte-kit.old/generated/client/matchers.js +1 -0
  80. package/frontend/.svelte-kit.old/generated/client/nodes/0.js +3 -0
  81. package/frontend/.svelte-kit.old/generated/client/nodes/1.js +1 -0
  82. package/frontend/.svelte-kit.old/generated/client/nodes/10.js +3 -0
  83. package/frontend/.svelte-kit.old/generated/client/nodes/2.js +1 -0
  84. package/frontend/.svelte-kit.old/generated/client/nodes/3.js +1 -0
  85. package/frontend/.svelte-kit.old/generated/client/nodes/4.js +1 -0
  86. package/frontend/.svelte-kit.old/generated/client/nodes/5.js +3 -0
  87. package/frontend/.svelte-kit.old/generated/client/nodes/6.js +1 -0
  88. package/frontend/.svelte-kit.old/generated/client/nodes/7.js +3 -0
  89. package/frontend/.svelte-kit.old/generated/client/nodes/8.js +1 -0
  90. package/frontend/.svelte-kit.old/generated/client/nodes/9.js +3 -0
  91. package/frontend/.svelte-kit.old/generated/root.js +3 -0
  92. package/frontend/.svelte-kit.old/generated/root.svelte +80 -0
  93. package/frontend/.svelte-kit.old/generated/server/internal.js +55 -0
  94. package/frontend/.svelte-kit.old/non-ambient.d.ts +59 -0
  95. package/frontend/.svelte-kit.old/tsconfig.json +59 -0
  96. package/frontend/.svelte-kit.old/types/route_meta_data.json +40 -0
  97. package/frontend/.svelte-kit.old/types/src/routes/$types.d.ts +21 -0
  98. package/frontend/.svelte-kit.old/types/src/routes/(app)/$types.d.ts +30 -0
  99. package/frontend/.svelte-kit.old/types/src/routes/(app)/docs/[id]/$types.d.ts +27 -0
  100. package/frontend/.svelte-kit.old/types/src/routes/(app)/docs/[id]/proxy+page.ts +25 -0
  101. package/frontend/.svelte-kit.old/types/src/routes/api/[...path]/$types.d.ts +10 -0
  102. package/frontend/.svelte-kit.old/types/src/routes/folders/[id]/$types.d.ts +27 -0
  103. package/frontend/.svelte-kit.old/types/src/routes/folders/[id]/proxy+page.ts +15 -0
  104. package/frontend/.svelte-kit.old/types/src/routes/login/$types.d.ts +17 -0
  105. package/frontend/.svelte-kit.old/types/src/routes/register/$types.d.ts +17 -0
  106. package/frontend/.svelte-kit.old/types/src/routes/s/[token]/$types.d.ts +20 -0
  107. package/frontend/.svelte-kit.old/types/src/routes/s/[token]/proxy+page.ts +6 -0
  108. package/frontend/.svelte-kit.old/types/src/routes/search/$types.d.ts +19 -0
  109. package/frontend/.svelte-kit.old/types/src/routes/search/proxy+page.ts +26 -0
  110. package/frontend/.svelte-kit.old/types/src/routes/settings/$types.d.ts +17 -0
  111. package/frontend/Dockerfile +44 -0
  112. package/frontend/biome.json +40 -0
  113. package/frontend/components.json +18 -0
  114. package/frontend/messages/en.json +434 -0
  115. package/frontend/package.json +70 -0
  116. package/frontend/project.inlang/settings.json +12 -0
  117. package/frontend/src/app.css +6 -0
  118. package/frontend/src/app.d.ts +13 -0
  119. package/frontend/src/app.html +30 -0
  120. package/frontend/src/hooks.server.ts +10 -0
  121. package/frontend/src/hooks.ts +10 -0
  122. package/frontend/src/lib/api/attachments.ts +45 -0
  123. package/frontend/src/lib/api/client.test.ts +15 -0
  124. package/frontend/src/lib/api/client.ts +57 -0
  125. package/frontend/src/lib/api/documents.ts +83 -0
  126. package/frontend/src/lib/api/folders.ts +180 -0
  127. package/frontend/src/lib/api/search.test.ts +52 -0
  128. package/frontend/src/lib/api/search.ts +128 -0
  129. package/frontend/src/lib/api/settings.ts +95 -0
  130. package/frontend/src/lib/api/share.ts +71 -0
  131. package/frontend/src/lib/api/tags.test.ts +91 -0
  132. package/frontend/src/lib/api/tags.ts +87 -0
  133. package/frontend/src/lib/auth-client.ts +10 -0
  134. package/frontend/src/lib/collaboration.ts +63 -0
  135. package/frontend/src/lib/components/AttachmentUpload.svelte +110 -0
  136. package/frontend/src/lib/components/DatePicker.svelte +322 -0
  137. package/frontend/src/lib/components/DocumentCard.svelte +166 -0
  138. package/frontend/src/lib/components/EmptyState.svelte +49 -0
  139. package/frontend/src/lib/components/FolderCard.svelte +93 -0
  140. package/frontend/src/lib/components/ScrollToTop.svelte +72 -0
  141. package/frontend/src/lib/components/SearchBar.svelte +47 -0
  142. package/frontend/src/lib/components/SearchResult.svelte +115 -0
  143. package/frontend/src/lib/components/SettingsDialog.svelte +271 -0
  144. package/frontend/src/lib/components/ShareDialog.svelte +158 -0
  145. package/frontend/src/lib/components/ShareLink.svelte +98 -0
  146. package/frontend/src/lib/components/TagCreateDialog.svelte +284 -0
  147. package/frontend/src/lib/components/VersionDiff.svelte +55 -0
  148. package/frontend/src/lib/components/VersionHistory.svelte +96 -0
  149. package/frontend/src/lib/components/editor/DocumentTitle.svelte +87 -0
  150. package/frontend/src/lib/components/editor/EditorToolbar.svelte +1367 -0
  151. package/frontend/src/lib/components/editor/HiAiEditor.svelte +531 -0
  152. package/frontend/src/lib/components/editor/LinkDialog.svelte +134 -0
  153. package/frontend/src/lib/components/editor/MarkdownToggle.svelte +88 -0
  154. package/frontend/src/lib/components/editor/editorExtensions.ts +53 -0
  155. package/frontend/src/lib/components/editor/markdown.ts +38 -0
  156. package/frontend/src/lib/components/sidebar/FolderTree.svelte +731 -0
  157. package/frontend/src/lib/components/sidebar/RecentDocs.svelte +311 -0
  158. package/frontend/src/lib/components/sidebar/Sidebar.svelte +156 -0
  159. package/frontend/src/lib/components/sidebar/TagList.svelte +200 -0
  160. package/frontend/src/lib/components/ui/confirm-dialog/ConfirmDialog.svelte +76 -0
  161. package/frontend/src/lib/components/ui/confirm-dialog/index.ts +1 -0
  162. package/frontend/src/lib/stores/tag-store.svelte.ts +56 -0
  163. package/frontend/src/lib/stores/theme.svelte.ts +97 -0
  164. package/frontend/src/lib/svelte.d.ts +6 -0
  165. package/frontend/src/lib/types.ts +44 -0
  166. package/frontend/src/lib/utils/clipboard.ts +17 -0
  167. package/frontend/src/lib/utils/strip-markdown.ts +59 -0
  168. package/frontend/src/lib/utils.ts +33 -0
  169. package/frontend/src/routes/(app)/+layout.svelte +17 -0
  170. package/frontend/src/routes/(app)/+page.server.ts +10 -0
  171. package/frontend/src/routes/(app)/+page.svelte +303 -0
  172. package/frontend/src/routes/(app)/docs/[id]/+page.server.ts +10 -0
  173. package/frontend/src/routes/(app)/docs/[id]/+page.svelte +1108 -0
  174. package/frontend/src/routes/(app)/docs/[id]/+page.ts +24 -0
  175. package/frontend/src/routes/(app)/search/+page.svelte +593 -0
  176. package/frontend/src/routes/(app)/search/+page.ts +25 -0
  177. package/frontend/src/routes/+error.svelte +12 -0
  178. package/frontend/src/routes/+layout.svelte +18 -0
  179. package/frontend/src/routes/+layout.ts +2 -0
  180. package/frontend/src/routes/api/[...path]/+server.ts +111 -0
  181. package/frontend/src/routes/folders/[id]/+page.server.ts +10 -0
  182. package/frontend/src/routes/folders/[id]/+page.svelte +319 -0
  183. package/frontend/src/routes/folders/[id]/+page.ts +14 -0
  184. package/frontend/src/routes/login/+page.svelte +90 -0
  185. package/frontend/src/routes/register/+page.svelte +97 -0
  186. package/frontend/src/routes/s/[token]/+page.svelte +496 -0
  187. package/frontend/src/routes/s/[token]/+page.ts +5 -0
  188. package/frontend/src/routes/settings/+page.svelte +175 -0
  189. package/frontend/static/favicon.png +0 -0
  190. package/frontend/static/logo.png +0 -0
  191. package/frontend/svelte.config.js +15 -0
  192. package/frontend/tsconfig.json +15 -0
  193. package/frontend/vite.config.ts +25 -0
  194. package/init.sql +9 -0
  195. package/logo.png +0 -0
  196. package/package.json +39 -0
  197. package/package.public.json +39 -0
  198. package/packages/db/drizzle.config.ts +10 -0
  199. package/packages/db/package.json +30 -0
  200. package/packages/db/src/client.ts +9 -0
  201. package/packages/db/src/index.ts +2 -0
  202. package/packages/db/src/migrations/0000_nice_bedlam.sql +165 -0
  203. package/packages/db/src/migrations/0001_w2_3_test.sql +5 -0
  204. package/packages/db/src/migrations/0002_rename_content_json.sql +2 -0
  205. package/packages/db/src/migrations/meta/0000_snapshot.json +1331 -0
  206. package/packages/db/src/migrations/meta/0001_snapshot.json +1399 -0
  207. package/packages/db/src/migrations/meta/0002_snapshot.json +1399 -0
  208. package/packages/db/src/migrations/meta/_journal.json +27 -0
  209. package/packages/db/src/schema.ts +378 -0
  210. package/packages/db/tsconfig.json +17 -0
  211. package/scripts/export-openapi.ts +37 -0
  212. package/scripts/health-check.sh +75 -0
  213. package/scripts/migrate.sh +135 -0
  214. package/scripts/prework_backup.sh +25 -0
  215. package/scripts/release.sh +83 -0
  216. package/tsconfig.json +25 -0
@@ -0,0 +1,113 @@
1
+ # Deployment Guide
2
+
3
+ ## Quick Start (Docker Compose)
4
+
5
+ ```bash
6
+ git clone https://github.com/hiai-gg/hiai-docs.git
7
+ cd hiai-docs
8
+ cp .env.example .env
9
+ # Edit .env with your values (see Environment Variables below)
10
+
11
+ docker compose up -d
12
+ ```
13
+
14
+ The app will be available at:
15
+ - Frontend: `http://localhost:50701`
16
+ - API: `http://localhost:50700`
17
+ - API Docs: `http://localhost:50700/api/docs`
18
+ - MinIO Console: `http://localhost:9001`
19
+
20
+ ## Local Development
21
+
22
+ ```bash
23
+ bun install
24
+
25
+ # Start infrastructure only (use shared ai-core services or local docker)
26
+ docker compose -f docker-compose.dev.yml up -d
27
+
28
+ # Push database schema
29
+ cd packages/db && bun run db:push && cd ../..
30
+
31
+ # Start backend and frontend in separate terminals
32
+ cd backend && bun run dev # → localhost:50700
33
+ cd frontend && bun run dev # → localhost:50701
34
+ ```
35
+
36
+ ## Environment Variables
37
+
38
+ Copy `.env.example` and fill in:
39
+
40
+ | Variable | Required | Default | Description |
41
+ |----------|----------|---------|-------------|
42
+ | `DB_USER` | Yes | `aiuser` | PostgreSQL username |
43
+ | `DB_PASSWORD` | Yes | `changeme` | PostgreSQL password |
44
+ | `DB_NAME` | Yes | `hiai_docs` | Database name |
45
+ | `DB_HOST` | Yes | `localhost` | PostgreSQL host |
46
+ | `DB_PORT` | Yes | `5433` | PostgreSQL port |
47
+ | `BETTER_AUTH_SECRET` | **Yes** | — | Random 32+ char string |
48
+ | `BETTER_AUTH_URL` | Yes | `http://localhost:50700` | Public API URL |
49
+ | `MINIO_ACCESS_KEY` | Yes | `minioadmin` | MinIO access key |
50
+ | `MINIO_SECRET_KEY` | Yes | `minioadmin` | MinIO secret key |
51
+ | `MINIO_BUCKET` | Yes | `hiai-docs` | MinIO bucket name |
52
+ | `EMBEDDING_PROVIDER` | No | `ollama` | `ollama`, `openrouter`, or `voyage` |
53
+ | `EMBEDDING_MODEL` | No | `nomic-embed-text` | Model name |
54
+ | `OPENROUTER_API_KEY` | If fallback | — | OpenRouter API key |
55
+ | `API_PORT` | No | `50700` | Backend port |
56
+ | `WEB_PORT` | No | `50701` | Frontend port |
57
+ | `NODE_ENV` | No | `development` | `development` or `production` |
58
+ | `LOG_LEVEL` | No | `info` | `trace`/`debug`/`info`/`warn`/`error`/`fatal` |
59
+
60
+ ## Production Considerations
61
+
62
+ ### TLS
63
+
64
+ Use Caddy (included) or a reverse proxy. The default Caddyfile routes:
65
+ - `/api/*` → backend
66
+ - `/*` → frontend
67
+
68
+ For custom domains, update `Caddyfile` with your domain.
69
+
70
+ ### Backups
71
+
72
+ ```bash
73
+ # Database
74
+ docker compose exec postgres pg_dump -U aiuser hiai_docs > backup.sql
75
+
76
+ # Restore
77
+ cat backup.sql | docker compose exec -T postgres psql -U aiuser -d hiai_docs
78
+
79
+ # MinIO attachments
80
+ docker compose exec minio mc mirror /data ./backup-minio/
81
+ ```
82
+
83
+ ### Health Checks
84
+
85
+ ```bash
86
+ curl -fsS http://localhost:50700/api/health
87
+ # → {"status":"ok","timestamp":"..."}
88
+ ```
89
+
90
+ ## Database Migrations
91
+
92
+ ```bash
93
+ # Generate migration from schema changes
94
+ cd packages/db && bun run db:generate
95
+
96
+ # Apply migration
97
+ bun run db:migrate
98
+
99
+ # Push schema directly (dev only)
100
+ bun run db:push
101
+ ```
102
+
103
+ ## Services
104
+
105
+ | Container | Port | Purpose |
106
+ |-----------|------|---------|
107
+ | postgres | 5433 | PostgreSQL 18 + pgvector |
108
+ | redis | 6380 | Cache/queue |
109
+ | ollama | 11434 | Embedding provider |
110
+ | minio | 9000/9001 | S3-compatible file storage |
111
+ | api | 50700 | Elysia REST API |
112
+ | web | 50701 | SvelteKit frontend |
113
+ | caddy | 80/443 | Reverse proxy |
@@ -0,0 +1,61 @@
1
+ # Production Status Report
2
+
3
+ > **Status:** ✅ READY FOR DEPLOYMENT
4
+ > **Last verified:** 2026-06-14
5
+
6
+ ---
7
+
8
+ ## 1. Verification Results
9
+
10
+ | Check | Status |
11
+ |-------|--------|
12
+ | Typecheck | ✅ PASS — 0 errors across all packages |
13
+ | Tests | ✅ PASS — 178/178 passing |
14
+ | Build | ✅ PASS — Docker multi-stage builds |
15
+ | Health checks | ✅ PASS |
16
+
17
+ ## 2. Architecture
18
+
19
+ 10 route files: auth, documents, folders, search, share, tags, attachments, versions, webhooks, collaboration.
20
+
21
+ Security: rate limiting, Zod validation, owner_id scoping, CSRF protection, CORS, security headers.
22
+
23
+ ## 3. Deployment
24
+
25
+ ```bash
26
+ git clone https://github.com/hiai-gg/hiai-docs.git && cd hiai-docs
27
+ cp .env.example .env
28
+ docker compose pull && docker compose up -d
29
+ docker compose exec api bun run db:migrate
30
+ ```
31
+
32
+ ### Ports
33
+
34
+ | Port | Service |
35
+ |------|---------|
36
+ | 50700 | API |
37
+ | 50701 | Frontend |
38
+ | 5433 | PostgreSQL |
39
+ | 6384 | Redis |
40
+ | 9020 | MinIO S3 |
41
+ | 80/443 | Caddy |
42
+
43
+ ## 4. Testing
44
+
45
+ 178 tests passing. Run: `bun test`, `cd backend && bun test`, `cd frontend && bun test`.
46
+
47
+ ## 5. Security Checklist
48
+
49
+ Authentication, CSRF, rate limiting, Zod validation, owner scoping, CORS, HSTS, CSP, X-Frame-Options, password hashing (Argon2id), API key auth, non-root containers, parameterized queries — all in place.
50
+
51
+ ## 6. Known Issues
52
+
53
+ - **Biome/Svelte 5:** 44 false-positive lint errors on Svelte 5 runes (non-blocking)
54
+ - **Typebox pin:** required for Elysia 1.4.28 compatibility
55
+ - **OPENROUTER_API_KEY:** placeholder, replace before production
56
+ - **No E2E tests:** tracked in todo.md T6.3
57
+ - **No automated backups:** operator responsibility
58
+
59
+ ---
60
+
61
+ *Status: ✅ READY FOR DEPLOYMENT*
@@ -0,0 +1,385 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "hiai-docs API",
5
+ "version": "0.1.0",
6
+ "description": "Self-hosted AI-first documentation platform. Full-text + semantic search, version history, sharing, and folder organization.",
7
+ "contact": {
8
+ "name": "hiai-gg",
9
+ "url": "https://github.com/hiai-gg/hiai-docs"
10
+ },
11
+ "license": {
12
+ "name": "MIT",
13
+ "url": "https://opensource.org/licenses/MIT"
14
+ }
15
+ },
16
+ "servers": [
17
+ { "url": "http://localhost:50700", "description": "Local development" }
18
+ ],
19
+ "tags": [
20
+ { "name": "Health", "description": "Health check" },
21
+ { "name": "Auth", "description": "Authentication" },
22
+ { "name": "Documents", "description": "Document CRUD" },
23
+ { "name": "Folders", "description": "Folder management" },
24
+ { "name": "Tags", "description": "Tag management" },
25
+ { "name": "Versions", "description": "Document version history" },
26
+ { "name": "Search", "description": "Hybrid full-text + semantic search" },
27
+ { "name": "Share", "description": "Sharing and guest access" }
28
+ ],
29
+ "paths": {
30
+ "/api/health": {
31
+ "get": {
32
+ "tags": ["Health"],
33
+ "summary": "Health check",
34
+ "operationId": "getHealth",
35
+ "responses": {
36
+ "200": {
37
+ "description": "Service is healthy",
38
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } }
39
+ }
40
+ }
41
+ }
42
+ },
43
+ "/api/documents": {
44
+ "get": {
45
+ "tags": ["Documents"],
46
+ "summary": "List documents",
47
+ "operationId": "listDocuments",
48
+ "security": [{ "sessionAuth": [] }],
49
+ "parameters": [
50
+ { "name": "folderId", "in": "query", "schema": { "type": "string", "format": "uuid" } },
51
+ { "name": "tag", "in": "query", "schema": { "type": "string", "format": "uuid" } },
52
+ { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1, "minimum": 1 } },
53
+ { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 } }
54
+ ],
55
+ "responses": {
56
+ "200": {
57
+ "description": "Paginated list of documents",
58
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DocumentListResponse" } } }
59
+ },
60
+ "401": { "$ref": "#/components/responses/Unauthorized" }
61
+ }
62
+ },
63
+ "post": {
64
+ "tags": ["Documents"],
65
+ "summary": "Create document",
66
+ "operationId": "createDocument",
67
+ "security": [{ "sessionAuth": [] }],
68
+ "requestBody": {
69
+ "required": true,
70
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDocument" } } }
71
+ },
72
+ "responses": {
73
+ "201": { "description": "Document created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Document" } } } },
74
+ "400": { "$ref": "#/components/responses/BadRequest" },
75
+ "401": { "$ref": "#/components/responses/Unauthorized" }
76
+ }
77
+ }
78
+ },
79
+ "/api/documents/{id}": {
80
+ "get": {
81
+ "tags": ["Documents"],
82
+ "summary": "Get document with tags",
83
+ "operationId": "getDocument",
84
+ "security": [{ "sessionAuth": [] }],
85
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
86
+ "responses": {
87
+ "200": { "description": "Document details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DocumentWithTags" } } } },
88
+ "401": { "$ref": "#/components/responses/Unauthorized" },
89
+ "404": { "$ref": "#/components/responses/NotFound" }
90
+ }
91
+ },
92
+ "patch": {
93
+ "tags": ["Documents"],
94
+ "summary": "Update document (auto-saves version)",
95
+ "operationId": "updateDocument",
96
+ "security": [{ "sessionAuth": [] }],
97
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
98
+ "requestBody": {
99
+ "required": true,
100
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateDocument" } } }
101
+ },
102
+ "responses": {
103
+ "200": { "description": "Document updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Document" } } } },
104
+ "400": { "$ref": "#/components/responses/BadRequest" },
105
+ "401": { "$ref": "#/components/responses/Unauthorized" },
106
+ "404": { "$ref": "#/components/responses/NotFound" }
107
+ }
108
+ },
109
+ "delete": {
110
+ "tags": ["Documents"],
111
+ "summary": "Delete document",
112
+ "operationId": "deleteDocument",
113
+ "security": [{ "sessionAuth": [] }],
114
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
115
+ "responses": {
116
+ "200": { "description": "Document deleted" },
117
+ "401": { "$ref": "#/components/responses/Unauthorized" },
118
+ "404": { "$ref": "#/components/responses/NotFound" }
119
+ }
120
+ }
121
+ },
122
+ "/api/folders": {
123
+ "get": {
124
+ "tags": ["Folders"],
125
+ "summary": "List folders",
126
+ "operationId": "listFolders",
127
+ "security": [{ "sessionAuth": [] }],
128
+ "parameters": [{ "name": "parentId", "in": "query", "schema": { "type": "string", "format": "uuid" } }],
129
+ "responses": {
130
+ "200": { "description": "List of folders", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Folder" } } } } },
131
+ "401": { "$ref": "#/components/responses/Unauthorized" }
132
+ }
133
+ },
134
+ "post": {
135
+ "tags": ["Folders"],
136
+ "summary": "Create folder",
137
+ "operationId": "createFolder",
138
+ "security": [{ "sessionAuth": [] }],
139
+ "requestBody": {
140
+ "required": true,
141
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateFolder" } } }
142
+ },
143
+ "responses": {
144
+ "201": { "description": "Folder created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Folder" } } } },
145
+ "400": { "$ref": "#/components/responses/BadRequest" },
146
+ "401": { "$ref": "#/components/responses/Unauthorized" }
147
+ }
148
+ }
149
+ },
150
+ "/api/folders/{id}": {
151
+ "patch": {
152
+ "tags": ["Folders"],
153
+ "summary": "Update folder",
154
+ "operationId": "updateFolder",
155
+ "security": [{ "sessionAuth": [] }],
156
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
157
+ "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateFolder" } } } },
158
+ "responses": {
159
+ "200": { "description": "Folder updated" },
160
+ "401": { "$ref": "#/components/responses/Unauthorized" },
161
+ "404": { "$ref": "#/components/responses/NotFound" }
162
+ }
163
+ },
164
+ "delete": {
165
+ "tags": ["Folders"],
166
+ "summary": "Delete folder",
167
+ "operationId": "deleteFolder",
168
+ "security": [{ "sessionAuth": [] }],
169
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
170
+ "responses": {
171
+ "200": { "description": "Folder deleted" },
172
+ "401": { "$ref": "#/components/responses/Unauthorized" },
173
+ "404": { "$ref": "#/components/responses/NotFound" }
174
+ }
175
+ }
176
+ },
177
+ "/api/tags": {
178
+ "get": {
179
+ "tags": ["Tags"],
180
+ "summary": "List tags with document counts",
181
+ "operationId": "listTags",
182
+ "security": [{ "sessionAuth": [] }],
183
+ "responses": {
184
+ "200": { "description": "List of tags", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TagWithCount" } } } } },
185
+ "401": { "$ref": "#/components/responses/Unauthorized" }
186
+ }
187
+ },
188
+ "post": {
189
+ "tags": ["Tags"],
190
+ "summary": "Create tag",
191
+ "operationId": "createTag",
192
+ "security": [{ "sessionAuth": [] }],
193
+ "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTag" } } } },
194
+ "responses": {
195
+ "201": { "description": "Tag created" },
196
+ "401": { "$ref": "#/components/responses/Unauthorized" },
197
+ "409": { "description": "Tag name already exists" }
198
+ }
199
+ }
200
+ },
201
+ "/api/tags/{id}": {
202
+ "patch": {
203
+ "tags": ["Tags"],
204
+ "summary": "Update tag",
205
+ "operationId": "updateTag",
206
+ "security": [{ "sessionAuth": [] }],
207
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
208
+ "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTag" } } } },
209
+ "responses": {
210
+ "200": { "description": "Tag updated" },
211
+ "401": { "$ref": "#/components/responses/Unauthorized" },
212
+ "404": { "$ref": "#/components/responses/NotFound" }
213
+ }
214
+ },
215
+ "delete": {
216
+ "tags": ["Tags"],
217
+ "summary": "Delete tag",
218
+ "operationId": "deleteTag",
219
+ "security": [{ "sessionAuth": [] }],
220
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
221
+ "responses": {
222
+ "200": { "description": "Tag deleted" },
223
+ "401": { "$ref": "#/components/responses/Unauthorized" }
224
+ }
225
+ }
226
+ },
227
+ "/api/documents/{id}/tags": {
228
+ "post": {
229
+ "tags": ["Tags"],
230
+ "summary": "Add tag to document",
231
+ "operationId": "addTagToDocument",
232
+ "security": [{ "sessionAuth": [] }],
233
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
234
+ "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "tagId": { "type": "string", "format": "uuid" } }, "required": ["tagId"] } } } },
235
+ "responses": {
236
+ "201": { "description": "Tag added" },
237
+ "401": { "$ref": "#/components/responses/Unauthorized" },
238
+ "404": { "$ref": "#/components/responses/NotFound" }
239
+ }
240
+ }
241
+ },
242
+ "/api/documents/{id}/tags/{tagId}": {
243
+ "delete": {
244
+ "tags": ["Tags"],
245
+ "summary": "Remove tag from document",
246
+ "operationId": "removeTagFromDocument",
247
+ "security": [{ "sessionAuth": [] }],
248
+ "parameters": [
249
+ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
250
+ { "name": "tagId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
251
+ ],
252
+ "responses": {
253
+ "200": { "description": "Tag removed" },
254
+ "401": { "$ref": "#/components/responses/Unauthorized" }
255
+ }
256
+ }
257
+ },
258
+ "/api/documents/{id}/versions": {
259
+ "get": {
260
+ "tags": ["Versions"],
261
+ "summary": "List document versions",
262
+ "operationId": "listVersions",
263
+ "security": [{ "sessionAuth": [] }],
264
+ "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
265
+ "responses": {
266
+ "200": { "description": "List of versions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Version" } } } } },
267
+ "401": { "$ref": "#/components/responses/Unauthorized" },
268
+ "404": { "$ref": "#/components/responses/NotFound" }
269
+ }
270
+ }
271
+ },
272
+ "/api/documents/{id}/versions/{vid}": {
273
+ "get": {
274
+ "tags": ["Versions"],
275
+ "summary": "Get specific version",
276
+ "operationId": "getVersion",
277
+ "security": [{ "sessionAuth": [] }],
278
+ "parameters": [
279
+ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
280
+ { "name": "vid", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
281
+ ],
282
+ "responses": {
283
+ "200": { "description": "Version details" },
284
+ "401": { "$ref": "#/components/responses/Unauthorized" },
285
+ "404": { "$ref": "#/components/responses/NotFound" }
286
+ }
287
+ }
288
+ },
289
+ "/api/search": {
290
+ "get": {
291
+ "tags": ["Search"],
292
+ "summary": "Hybrid full-text + semantic search",
293
+ "operationId": "search",
294
+ "security": [{ "sessionAuth": [] }],
295
+ "parameters": [
296
+ { "name": "q", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Search query" },
297
+ { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
298
+ { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } }
299
+ ],
300
+ "responses": {
301
+ "200": { "description": "Search results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResponse" } } } },
302
+ "401": { "$ref": "#/components/responses/Unauthorized" }
303
+ }
304
+ }
305
+ },
306
+ "/api/search/suggest": {
307
+ "get": {
308
+ "tags": ["Search"],
309
+ "summary": "Title autocomplete suggestions",
310
+ "operationId": "searchSuggest",
311
+ "security": [{ "sessionAuth": [] }],
312
+ "parameters": [{ "name": "q", "in": "query", "required": true, "schema": { "type": "string" } }],
313
+ "responses": {
314
+ "200": { "description": "Suggestions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/SearchSuggestion" } } } } },
315
+ "401": { "$ref": "#/components/responses/Unauthorized" }
316
+ }
317
+ }
318
+ },
319
+ "/api/share/link": {
320
+ "post": {
321
+ "tags": ["Share"],
322
+ "summary": "Create share link",
323
+ "operationId": "createShareLink",
324
+ "security": [{ "sessionAuth": [] }],
325
+ "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateShareLink" } } } },
326
+ "responses": {
327
+ "201": { "description": "Share link created" },
328
+ "401": { "$ref": "#/components/responses/Unauthorized" }
329
+ }
330
+ }
331
+ },
332
+ "/api/share/{token}": {
333
+ "get": {
334
+ "tags": ["Share"],
335
+ "summary": "Access shared document/folder (public)",
336
+ "operationId": "accessShareLink",
337
+ "parameters": [
338
+ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } },
339
+ { "name": "password", "in": "query", "schema": { "type": "string" } }
340
+ ],
341
+ "responses": {
342
+ "200": { "description": "Shared content" },
343
+ "401": { "description": "Password required or invalid" },
344
+ "404": { "$ref": "#/components/responses/NotFound" },
345
+ "429": { "description": "Rate limited" }
346
+ }
347
+ }
348
+ }
349
+ },
350
+ "components": {
351
+ "securitySchemes": {
352
+ "sessionAuth": {
353
+ "type": "apiKey",
354
+ "in": "cookie",
355
+ "name": "better-auth.session_token",
356
+ "description": "Session cookie from Better Auth"
357
+ }
358
+ },
359
+ "responses": {
360
+ "Unauthorized": { "description": "Authentication required", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "example": "Unauthorized" } } } } } },
361
+ "BadRequest": { "description": "Invalid input", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" }, "details": { "type": "object" } } } } } },
362
+ "NotFound": { "description": "Resource not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "example": "Document not found" } } } } } }
363
+ },
364
+ "schemas": {
365
+ "HealthResponse": { "type": "object", "properties": { "status": { "type": "string", "example": "ok" }, "timestamp": { "type": "string", "format": "date-time" } } },
366
+ "Document": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "ownerId": { "type": "string", "format": "uuid" }, "folderId": { "type": "string", "format": "uuid", "nullable": true }, "title": { "type": "string" }, "content": { "type": "string" }, "contentJson": { "nullable": true }, "metadata": { "nullable": true }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } },
367
+ "DocumentWithTags": { "allOf": [{ "$ref": "#/components/schemas/Document" }, { "type": "object", "properties": { "tags": { "type": "array", "items": { "$ref": "#/components/schemas/Tag" } } } }] },
368
+ "DocumentListResponse": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Document" } }, "total": { "type": "integer" }, "page": { "type": "integer" }, "limit": { "type": "integer" } } },
369
+ "CreateDocument": { "type": "object", "properties": { "title": { "type": "string", "default": "Untitled" }, "content": { "type": "string" }, "folderId": { "type": "string", "format": "uuid" } } },
370
+ "UpdateDocument": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" }, "contentJson": {}, "metadata": {}, "folderId": { "type": "string", "format": "uuid", "nullable": true } } },
371
+ "Folder": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "ownerId": { "type": "string", "format": "uuid" }, "parentId": { "type": "string", "format": "uuid", "nullable": true }, "name": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } },
372
+ "CreateFolder": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "parentId": { "type": "string", "format": "uuid" } } },
373
+ "UpdateFolder": { "type": "object", "properties": { "name": { "type": "string" }, "parentId": { "type": "string", "format": "uuid", "nullable": true } } },
374
+ "Tag": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "color": { "type": "string", "nullable": true }, "createdAt": { "type": "string", "format": "date-time" } } },
375
+ "TagWithCount": { "allOf": [{ "$ref": "#/components/schemas/Tag" }, { "type": "object", "properties": { "documentCount": { "type": "integer" } } }] },
376
+ "CreateTag": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "color": { "type": "string" } } },
377
+ "UpdateTag": { "type": "object", "properties": { "name": { "type": "string" }, "color": { "type": "string" } } },
378
+ "Version": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "documentId": { "type": "string", "format": "uuid" }, "content": { "type": "string" }, "contentJson": { "nullable": true }, "createdBy": { "type": "string", "format": "uuid" }, "createdAt": { "type": "string", "format": "date-time" } } },
379
+ "SearchResponse": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/SearchResult" } }, "total": { "type": "integer" }, "page": { "type": "integer" }, "limit": { "type": "integer" } } },
380
+ "SearchResult": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "title": { "type": "string" }, "snippet": { "type": "string" }, "score": { "type": "number" }, "folder_id": { "type": "string", "format": "uuid", "nullable": true }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } },
381
+ "SearchSuggestion": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "title": { "type": "string" }, "score": { "type": "number" } } },
382
+ "CreateShareLink": { "type": "object", "properties": { "documentId": { "type": "string", "format": "uuid" }, "folderId": { "type": "string", "format": "uuid" }, "password": { "type": "string" }, "expiresIn": { "type": "integer", "description": "Seconds until expiration" } } }
383
+ }
384
+ }
385
+ }