@useatlas/create 0.0.2 → 0.0.4

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 (296) hide show
  1. package/README.md +4 -18
  2. package/index.ts +191 -31
  3. package/package.json +1 -1
  4. package/templates/docker/.env.example +3 -3
  5. package/templates/docker/Dockerfile.sidecar +28 -0
  6. package/templates/docker/bin/__tests__/plugin-cli.test.ts +9 -9
  7. package/templates/docker/bin/atlas.ts +108 -44
  8. package/templates/docker/data/demo-semantic/catalog.yml +51 -27
  9. package/templates/docker/data/demo-semantic/entities/accounts.yml +95 -103
  10. package/templates/docker/data/demo-semantic/entities/companies.yml +88 -152
  11. package/templates/docker/data/demo-semantic/entities/people.yml +82 -95
  12. package/templates/docker/data/demo-semantic/glossary.yml +104 -8
  13. package/templates/docker/data/demo-semantic/metrics/accounts.yml +62 -23
  14. package/templates/docker/data/demo-semantic/metrics/companies.yml +52 -78
  15. package/templates/docker/docker-compose.yml +1 -1
  16. package/templates/docker/docs/deploy.md +2 -39
  17. package/templates/docker/package.json +17 -1
  18. package/templates/docker/semantic/catalog.yml +62 -3
  19. package/templates/docker/semantic/entities/accounts.yml +162 -0
  20. package/templates/docker/semantic/entities/companies.yml +143 -0
  21. package/templates/docker/semantic/entities/people.yml +132 -0
  22. package/templates/docker/semantic/glossary.yml +116 -4
  23. package/templates/docker/semantic/metrics/accounts.yml +77 -0
  24. package/templates/docker/semantic/metrics/companies.yml +63 -0
  25. package/templates/docker/sidecar/Dockerfile +5 -6
  26. package/templates/docker/sidecar/railway.json +1 -2
  27. package/templates/docker/src/api/__tests__/admin.test.ts +7 -7
  28. package/templates/docker/src/api/__tests__/health-plugin.test.ts +7 -0
  29. package/templates/docker/src/api/__tests__/health.test.ts +30 -8
  30. package/templates/docker/src/api/routes/admin.ts +549 -8
  31. package/templates/docker/src/api/routes/chat.ts +5 -20
  32. package/templates/docker/src/api/routes/health.ts +39 -27
  33. package/templates/docker/src/api/routes/openapi.ts +1329 -74
  34. package/templates/docker/src/api/routes/query.ts +2 -1
  35. package/templates/docker/src/api/server.ts +27 -0
  36. package/templates/docker/src/app/api/[...route]/route.ts +2 -2
  37. package/templates/docker/src/app/globals.css +13 -12
  38. package/templates/docker/src/app/layout.tsx +9 -2
  39. package/templates/docker/src/components/ui/alert-dialog.tsx +196 -0
  40. package/templates/docker/src/components/ui/badge.tsx +48 -0
  41. package/templates/docker/src/components/ui/button.tsx +64 -0
  42. package/templates/docker/src/components/ui/card.tsx +92 -0
  43. package/templates/docker/src/components/ui/collapsible.tsx +33 -0
  44. package/templates/docker/src/components/ui/command.tsx +184 -0
  45. package/templates/docker/src/components/ui/dialog.tsx +158 -0
  46. package/templates/docker/src/components/ui/dropdown-menu.tsx +257 -0
  47. package/templates/docker/src/components/ui/input.tsx +21 -0
  48. package/templates/docker/src/components/ui/scroll-area.tsx +58 -0
  49. package/templates/docker/src/components/ui/select.tsx +190 -0
  50. package/templates/docker/src/components/ui/separator.tsx +28 -0
  51. package/templates/docker/src/components/ui/sheet.tsx +143 -0
  52. package/templates/docker/src/components/ui/sidebar.tsx +726 -0
  53. package/templates/docker/src/components/ui/skeleton.tsx +13 -0
  54. package/templates/docker/src/components/ui/table.tsx +116 -0
  55. package/templates/docker/src/components/ui/tabs.tsx +91 -0
  56. package/templates/docker/src/components/ui/toggle-group.tsx +83 -0
  57. package/templates/docker/src/components/ui/toggle.tsx +47 -0
  58. package/templates/docker/src/components/ui/tooltip.tsx +57 -0
  59. package/templates/docker/src/hooks/use-mobile.ts +19 -0
  60. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +2 -0
  61. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +17 -0
  62. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  63. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +2 -0
  64. package/templates/docker/src/lib/__tests__/config.test.ts +69 -19
  65. package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  66. package/templates/docker/src/lib/__tests__/providers.test.ts +32 -1
  67. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +9 -0
  68. package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +429 -0
  69. package/templates/docker/src/lib/__tests__/startup.test.ts +5 -0
  70. package/templates/docker/src/lib/agent-query.ts +5 -23
  71. package/templates/docker/src/lib/agent.ts +32 -112
  72. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +5 -3
  73. package/templates/docker/src/lib/auth/middleware.ts +30 -4
  74. package/templates/docker/src/lib/auth/migrate.ts +97 -0
  75. package/templates/docker/src/lib/auth/server.ts +12 -1
  76. package/templates/docker/src/lib/config.ts +37 -39
  77. package/templates/docker/src/lib/db/__tests__/connection.test.ts +89 -14
  78. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +1 -18
  79. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  80. package/templates/docker/src/lib/db/__tests__/registry.test.ts +11 -208
  81. package/templates/docker/src/lib/db/connection.ts +87 -265
  82. package/templates/docker/src/lib/db/internal.ts +6 -1
  83. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  84. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  85. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  86. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +32 -5
  87. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  88. package/templates/docker/src/lib/plugins/index.ts +4 -1
  89. package/templates/docker/src/lib/plugins/migrate.ts +103 -0
  90. package/templates/docker/src/lib/plugins/registry.ts +12 -6
  91. package/templates/docker/src/lib/plugins/wiring.ts +113 -4
  92. package/templates/docker/src/lib/providers.ts +6 -1
  93. package/templates/docker/src/lib/security.ts +24 -0
  94. package/templates/docker/src/lib/semantic.ts +2 -0
  95. package/templates/docker/src/lib/sidecar-types.ts +12 -1
  96. package/templates/docker/src/lib/startup.ts +71 -101
  97. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  98. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  99. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  100. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  101. package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  102. package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  103. package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  104. package/templates/docker/src/lib/tools/__tests__/python.test.ts +331 -0
  105. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  106. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +38 -31
  107. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  108. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  109. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  110. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +5 -308
  111. package/templates/docker/src/lib/tools/explore-nsjail.ts +17 -12
  112. package/templates/docker/src/lib/tools/explore-sidecar.ts +25 -0
  113. package/templates/docker/src/lib/tools/explore.ts +28 -32
  114. package/templates/docker/src/lib/tools/python-nsjail.ts +396 -0
  115. package/templates/docker/src/lib/tools/python-sandbox.ts +476 -0
  116. package/templates/docker/src/lib/tools/python-sidecar.ts +150 -0
  117. package/templates/docker/src/lib/tools/python.ts +367 -0
  118. package/templates/docker/src/lib/tools/registry.ts +49 -22
  119. package/templates/docker/src/lib/tools/sql.ts +88 -88
  120. package/templates/docker/src/types/vercel-sandbox.d.ts +7 -0
  121. package/templates/docker/src/ui/components/admin/admin-layout.tsx +77 -8
  122. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +25 -17
  123. package/templates/docker/src/ui/components/admin/change-password-dialog.tsx +128 -0
  124. package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -3
  125. package/templates/docker/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  126. package/templates/docker/src/ui/components/atlas-chat.tsx +64 -12
  127. package/templates/docker/src/ui/components/chart/result-chart.tsx +25 -15
  128. package/templates/docker/src/ui/components/chat/markdown.tsx +88 -42
  129. package/templates/docker/src/ui/components/chat/python-result-card.tsx +244 -0
  130. package/templates/docker/src/ui/components/chat/sql-block.tsx +39 -15
  131. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +6 -1
  132. package/templates/docker/src/ui/components/chat/tool-part.tsx +12 -3
  133. package/templates/docker/src/ui/components/chat/typing-indicator.tsx +5 -2
  134. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +25 -20
  135. package/templates/docker/src/ui/context.tsx +1 -1
  136. package/templates/docker/src/ui/hooks/use-conversations.ts +3 -3
  137. package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -10
  138. package/templates/docker/tsconfig.json +2 -2
  139. package/templates/nextjs-standalone/.env.example +1 -1
  140. package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +9 -9
  141. package/templates/nextjs-standalone/bin/atlas.ts +108 -44
  142. package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +51 -27
  143. package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +95 -103
  144. package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +88 -152
  145. package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +82 -95
  146. package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +104 -8
  147. package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +62 -23
  148. package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +52 -78
  149. package/templates/nextjs-standalone/docs/deploy.md +2 -39
  150. package/templates/nextjs-standalone/package.json +11 -2
  151. package/templates/nextjs-standalone/scripts/migrate-auth.ts +25 -0
  152. package/templates/nextjs-standalone/scripts/seed-demo.ts +94 -0
  153. package/templates/nextjs-standalone/semantic/catalog.yml +62 -3
  154. package/templates/nextjs-standalone/semantic/entities/accounts.yml +162 -0
  155. package/templates/nextjs-standalone/semantic/entities/companies.yml +143 -0
  156. package/templates/nextjs-standalone/semantic/entities/people.yml +132 -0
  157. package/templates/nextjs-standalone/semantic/glossary.yml +116 -4
  158. package/templates/nextjs-standalone/semantic/metrics/accounts.yml +77 -0
  159. package/templates/nextjs-standalone/semantic/metrics/companies.yml +63 -0
  160. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +7 -7
  161. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +7 -0
  162. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +30 -8
  163. package/templates/nextjs-standalone/src/api/routes/admin.ts +549 -8
  164. package/templates/nextjs-standalone/src/api/routes/chat.ts +5 -20
  165. package/templates/nextjs-standalone/src/api/routes/health.ts +39 -27
  166. package/templates/nextjs-standalone/src/api/routes/openapi.ts +1329 -74
  167. package/templates/nextjs-standalone/src/api/routes/query.ts +2 -1
  168. package/templates/nextjs-standalone/src/api/server.ts +27 -0
  169. package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +2 -2
  170. package/templates/nextjs-standalone/src/app/globals.css +13 -12
  171. package/templates/nextjs-standalone/src/app/layout.tsx +9 -2
  172. package/templates/nextjs-standalone/src/components/ui/alert-dialog.tsx +196 -0
  173. package/templates/nextjs-standalone/src/components/ui/badge.tsx +48 -0
  174. package/templates/nextjs-standalone/src/components/ui/button.tsx +64 -0
  175. package/templates/nextjs-standalone/src/components/ui/card.tsx +92 -0
  176. package/templates/nextjs-standalone/src/components/ui/collapsible.tsx +33 -0
  177. package/templates/nextjs-standalone/src/components/ui/command.tsx +184 -0
  178. package/templates/nextjs-standalone/src/components/ui/dialog.tsx +158 -0
  179. package/templates/nextjs-standalone/src/components/ui/dropdown-menu.tsx +257 -0
  180. package/templates/nextjs-standalone/src/components/ui/input.tsx +21 -0
  181. package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +58 -0
  182. package/templates/nextjs-standalone/src/components/ui/select.tsx +190 -0
  183. package/templates/nextjs-standalone/src/components/ui/separator.tsx +28 -0
  184. package/templates/nextjs-standalone/src/components/ui/sheet.tsx +143 -0
  185. package/templates/nextjs-standalone/src/components/ui/sidebar.tsx +726 -0
  186. package/templates/nextjs-standalone/src/components/ui/skeleton.tsx +13 -0
  187. package/templates/nextjs-standalone/src/components/ui/table.tsx +116 -0
  188. package/templates/nextjs-standalone/src/components/ui/tabs.tsx +91 -0
  189. package/templates/nextjs-standalone/src/components/ui/toggle-group.tsx +83 -0
  190. package/templates/nextjs-standalone/src/components/ui/toggle.tsx +47 -0
  191. package/templates/nextjs-standalone/src/components/ui/tooltip.tsx +57 -0
  192. package/templates/nextjs-standalone/src/hooks/use-mobile.ts +19 -0
  193. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +2 -0
  194. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +17 -0
  195. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  196. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +2 -0
  197. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +69 -19
  198. package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  199. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +32 -1
  200. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +9 -0
  201. package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +429 -0
  202. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +5 -0
  203. package/templates/nextjs-standalone/src/lib/agent-query.ts +5 -23
  204. package/templates/nextjs-standalone/src/lib/agent.ts +32 -112
  205. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +5 -3
  206. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +30 -4
  207. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +97 -0
  208. package/templates/nextjs-standalone/src/lib/auth/server.ts +12 -1
  209. package/templates/nextjs-standalone/src/lib/config.ts +37 -39
  210. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +89 -14
  211. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +1 -18
  212. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  213. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +11 -208
  214. package/templates/nextjs-standalone/src/lib/db/connection.ts +87 -265
  215. package/templates/nextjs-standalone/src/lib/db/internal.ts +6 -1
  216. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  217. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  218. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  219. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +32 -5
  220. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  221. package/templates/nextjs-standalone/src/lib/plugins/index.ts +4 -1
  222. package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +103 -0
  223. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +12 -6
  224. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +113 -4
  225. package/templates/nextjs-standalone/src/lib/providers.ts +6 -1
  226. package/templates/nextjs-standalone/src/lib/security.ts +24 -0
  227. package/templates/nextjs-standalone/src/lib/semantic.ts +2 -0
  228. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +12 -1
  229. package/templates/nextjs-standalone/src/lib/startup.ts +71 -101
  230. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  231. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  232. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  233. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  234. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  235. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  236. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  237. package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +331 -0
  238. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  239. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +38 -31
  240. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  241. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  242. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  243. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +5 -308
  244. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +17 -12
  245. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +25 -0
  246. package/templates/nextjs-standalone/src/lib/tools/explore.ts +28 -32
  247. package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +396 -0
  248. package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +476 -0
  249. package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +150 -0
  250. package/templates/nextjs-standalone/src/lib/tools/python.ts +367 -0
  251. package/templates/nextjs-standalone/src/lib/tools/registry.ts +49 -22
  252. package/templates/nextjs-standalone/src/lib/tools/sql.ts +88 -88
  253. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +77 -8
  254. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +25 -17
  255. package/templates/nextjs-standalone/src/ui/components/admin/change-password-dialog.tsx +128 -0
  256. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -3
  257. package/templates/nextjs-standalone/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  258. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +64 -12
  259. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +25 -15
  260. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +88 -42
  261. package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +244 -0
  262. package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +39 -15
  263. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +6 -1
  264. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +12 -3
  265. package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +5 -2
  266. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +25 -20
  267. package/templates/nextjs-standalone/src/ui/context.tsx +1 -1
  268. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +3 -3
  269. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -10
  270. package/templates/nextjs-standalone/tsconfig.json +0 -1
  271. package/templates/nextjs-standalone/vercel.json +4 -1
  272. package/templates/docker/render.yaml +0 -34
  273. package/templates/docker/semantic/entities/.gitkeep +0 -0
  274. package/templates/docker/semantic/metrics/.gitkeep +0 -0
  275. package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +0 -141
  276. package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +0 -339
  277. package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +0 -217
  278. package/templates/docker/src/lib/db/duckdb.ts +0 -122
  279. package/templates/docker/src/lib/db/salesforce.ts +0 -342
  280. package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  281. package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  282. package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  283. package/templates/docker/src/lib/tools/salesforce.ts +0 -138
  284. package/templates/docker/src/lib/tools/soql-validation.ts +0 -172
  285. package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
  286. package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
  287. package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +0 -141
  288. package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +0 -339
  289. package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +0 -217
  290. package/templates/nextjs-standalone/src/lib/db/duckdb.ts +0 -122
  291. package/templates/nextjs-standalone/src/lib/db/salesforce.ts +0 -342
  292. package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  293. package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  294. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  295. package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +0 -138
  296. package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +0 -172
@@ -12,6 +12,7 @@ import { ChatRequestSchema } from "./chat";
12
12
  import {
13
13
  ConversationWithMessagesSchema,
14
14
  ListConversationsResponseSchema,
15
+ StarConversationBodySchema,
15
16
  } from "./conversations";
16
17
  import { HealthResponseSchema } from "./health";
17
18
 
@@ -21,6 +22,40 @@ function toJsonSchema(schema: z.ZodType): Record<string, unknown> {
21
22
  return z.toJSONSchema(schema) as Record<string, unknown>;
22
23
  }
23
24
 
25
+ // ---------------------------------------------------------------------------
26
+ // Reusable parameter definitions
27
+ // ---------------------------------------------------------------------------
28
+
29
+ const uuidPathParam = (name: string, description: string) => ({
30
+ name,
31
+ in: "path" as const,
32
+ description,
33
+ required: true,
34
+ schema: { type: "string", format: "uuid" },
35
+ });
36
+
37
+ const paginationParams = (defaults?: { limit?: number; maxLimit?: number }) => [
38
+ {
39
+ name: "limit",
40
+ in: "query" as const,
41
+ description: `Maximum number of items to return (1-${defaults?.maxLimit ?? 100}, default ${defaults?.limit ?? 20}).`,
42
+ required: false,
43
+ schema: {
44
+ type: "integer",
45
+ minimum: 1,
46
+ maximum: defaults?.maxLimit ?? 100,
47
+ default: defaults?.limit ?? 20,
48
+ },
49
+ },
50
+ {
51
+ name: "offset",
52
+ in: "query" as const,
53
+ description: "Number of items to skip (default 0).",
54
+ required: false,
55
+ schema: { type: "integer", minimum: 0, default: 0 },
56
+ },
57
+ ];
58
+
24
59
  function buildSpec(): Record<string, unknown> {
25
60
  const ErrorSchema = z.object({
26
61
  error: z.string(),
@@ -45,14 +80,32 @@ function buildSpec(): Record<string, unknown> {
45
80
  content: { "application/json": { schema: toJsonSchema(schema) } },
46
81
  });
47
82
 
83
+ // Common error responses shared across most routes
84
+ const authErrors = {
85
+ "401": errorResponse("Authentication required"),
86
+ "403": errorResponse("Forbidden — insufficient permissions"),
87
+ "429": errorResponse("Rate limit exceeded", RateLimitErrorSchema),
88
+ "500": errorResponse("Internal server error"),
89
+ };
90
+
48
91
  return {
49
92
  openapi: "3.1.0",
50
93
  info: {
51
94
  title: "Atlas API",
52
- version: "1.0.0",
95
+ version: "0.1.0",
53
96
  description:
54
97
  "Text-to-SQL data analyst agent. Ask natural-language questions about your data and receive structured answers.",
55
98
  },
99
+ servers: [
100
+ {
101
+ url: "http://localhost:3001",
102
+ description: "Standalone API (development)",
103
+ },
104
+ {
105
+ url: "http://localhost:3000",
106
+ description: "Same-origin via Next.js rewrites",
107
+ },
108
+ ],
56
109
  paths: {
57
110
  // -----------------------------------------------------------------
58
111
  // POST /api/chat — Streaming chat (SSE)
@@ -106,6 +159,10 @@ function buildSpec(): Record<string, unknown> {
106
159
  "404": errorResponse(
107
160
  "Conversation not found (invalid conversationId)",
108
161
  ),
162
+ "422": errorResponse(
163
+ "Validation error (invalid request body)",
164
+ ValidationErrorSchema,
165
+ ),
109
166
  "429": errorResponse(
110
167
  "Rate limit exceeded",
111
168
  RateLimitErrorSchema,
@@ -183,30 +240,13 @@ function buildSpec(): Record<string, unknown> {
183
240
  tags: ["Conversations"],
184
241
  security: [{ bearerAuth: [] }, {}],
185
242
  parameters: [
243
+ ...paginationParams(),
186
244
  {
187
- name: "limit",
188
- in: "query",
189
- description:
190
- "Maximum number of conversations to return (1-100, default 20).",
191
- required: false,
192
- schema: {
193
- type: "integer",
194
- minimum: 1,
195
- maximum: 100,
196
- default: 20,
197
- },
198
- },
199
- {
200
- name: "offset",
245
+ name: "starred",
201
246
  in: "query",
202
- description:
203
- "Number of conversations to skip (default 0).",
247
+ description: "Filter by starred status.",
204
248
  required: false,
205
- schema: {
206
- type: "integer",
207
- minimum: 0,
208
- default: 0,
209
- },
249
+ schema: { type: "boolean" },
210
250
  },
211
251
  ],
212
252
  responses: {
@@ -218,22 +258,16 @@ function buildSpec(): Record<string, unknown> {
218
258
  },
219
259
  },
220
260
  },
221
- "401": errorResponse("Authentication required"),
222
- "403": errorResponse("Forbidden — insufficient permissions"),
261
+ ...authErrors,
223
262
  "404": errorResponse(
224
263
  "Not available (no internal database configured)",
225
264
  ),
226
- "429": errorResponse(
227
- "Rate limit exceeded",
228
- RateLimitErrorSchema,
229
- ),
230
- "500": errorResponse("Internal server error"),
231
265
  },
232
266
  },
233
267
  },
234
268
 
235
269
  // -----------------------------------------------------------------
236
- // GET /api/v1/conversations/{id} — Get conversation with messages
270
+ // GET/DELETE /api/v1/conversations/{id}
237
271
  // -----------------------------------------------------------------
238
272
  "/api/v1/conversations/{id}": {
239
273
  get: {
@@ -244,13 +278,7 @@ function buildSpec(): Record<string, unknown> {
244
278
  tags: ["Conversations"],
245
279
  security: [{ bearerAuth: [] }, {}],
246
280
  parameters: [
247
- {
248
- name: "id",
249
- in: "path",
250
- description: "Conversation UUID.",
251
- required: true,
252
- schema: { type: "string", format: "uuid" },
253
- },
281
+ uuidPathParam("id", "Conversation UUID."),
254
282
  ],
255
283
  responses: {
256
284
  "200": {
@@ -262,16 +290,10 @@ function buildSpec(): Record<string, unknown> {
262
290
  },
263
291
  },
264
292
  "400": errorResponse("Invalid conversation ID format"),
265
- "401": errorResponse("Authentication required"),
266
- "403": errorResponse("Forbidden — insufficient permissions"),
293
+ ...authErrors,
267
294
  "404": errorResponse(
268
295
  "Conversation not found or not available",
269
296
  ),
270
- "429": errorResponse(
271
- "Rate limit exceeded",
272
- RateLimitErrorSchema,
273
- ),
274
- "500": errorResponse("Internal server error"),
275
297
  },
276
298
  },
277
299
  delete: {
@@ -282,29 +304,60 @@ function buildSpec(): Record<string, unknown> {
282
304
  tags: ["Conversations"],
283
305
  security: [{ bearerAuth: [] }, {}],
284
306
  parameters: [
285
- {
286
- name: "id",
287
- in: "path",
288
- description: "Conversation UUID.",
289
- required: true,
290
- schema: { type: "string", format: "uuid" },
291
- },
307
+ uuidPathParam("id", "Conversation UUID."),
292
308
  ],
293
309
  responses: {
294
310
  "204": {
295
311
  description: "Conversation deleted successfully",
296
312
  },
297
313
  "400": errorResponse("Invalid conversation ID format"),
298
- "401": errorResponse("Authentication required"),
299
- "403": errorResponse("Forbidden — insufficient permissions"),
314
+ ...authErrors,
300
315
  "404": errorResponse(
301
316
  "Conversation not found or not available",
302
317
  ),
303
- "429": errorResponse(
304
- "Rate limit exceeded",
305
- RateLimitErrorSchema,
306
- ),
307
- "500": errorResponse("Internal server error"),
318
+ },
319
+ },
320
+ },
321
+
322
+ // -----------------------------------------------------------------
323
+ // PATCH /api/v1/conversations/{id}/star
324
+ // -----------------------------------------------------------------
325
+ "/api/v1/conversations/{id}/star": {
326
+ patch: {
327
+ operationId: "starConversation",
328
+ summary: "Star or unstar a conversation",
329
+ description: "Sets the starred status of a conversation.",
330
+ tags: ["Conversations"],
331
+ security: [{ bearerAuth: [] }, {}],
332
+ parameters: [
333
+ uuidPathParam("id", "Conversation UUID."),
334
+ ],
335
+ requestBody: {
336
+ required: true,
337
+ content: {
338
+ "application/json": {
339
+ schema: toJsonSchema(StarConversationBodySchema),
340
+ },
341
+ },
342
+ },
343
+ responses: {
344
+ "200": {
345
+ description: "Star status updated",
346
+ content: {
347
+ "application/json": {
348
+ schema: {
349
+ type: "object",
350
+ properties: {
351
+ id: { type: "string", format: "uuid" },
352
+ starred: { type: "boolean" },
353
+ },
354
+ },
355
+ },
356
+ },
357
+ },
358
+ "400": errorResponse("Invalid conversation ID or request body"),
359
+ ...authErrors,
360
+ "404": errorResponse("Conversation not found or not available"),
308
361
  },
309
362
  },
310
363
  },
@@ -352,28 +405,1230 @@ function buildSpec(): Record<string, unknown> {
352
405
  },
353
406
  },
354
407
  },
355
- },
356
- components: {
357
- securitySchemes: {
358
- bearerAuth: {
359
- type: "http",
360
- scheme: "bearer",
408
+
409
+ // -----------------------------------------------------------------
410
+ // Actions — approval-gated write operations
411
+ // -----------------------------------------------------------------
412
+ "/api/v1/actions": {
413
+ get: {
414
+ operationId: "listActions",
415
+ summary: "List actions",
361
416
  description:
362
- "API key or JWT token. Pass via Authorization: Bearer <token>.",
417
+ "Returns actions filtered by status. Requires ATLAS_ACTIONS_ENABLED=true and an internal database.",
418
+ tags: ["Actions"],
419
+ security: [{ bearerAuth: [] }, {}],
420
+ parameters: [
421
+ {
422
+ name: "status",
423
+ in: "query",
424
+ description: "Filter by action status (default: pending).",
425
+ required: false,
426
+ schema: {
427
+ type: "string",
428
+ enum: ["pending", "approved", "denied", "executed", "failed", "timed_out", "auto_approved"],
429
+ default: "pending",
430
+ },
431
+ },
432
+ {
433
+ name: "limit",
434
+ in: "query",
435
+ description: "Maximum number of actions to return (1-100, default 50).",
436
+ required: false,
437
+ schema: { type: "integer", minimum: 1, maximum: 100, default: 50 },
438
+ },
439
+ ],
440
+ responses: {
441
+ "200": {
442
+ description: "List of actions",
443
+ content: {
444
+ "application/json": {
445
+ schema: {
446
+ type: "object",
447
+ properties: {
448
+ actions: {
449
+ type: "array",
450
+ items: {
451
+ type: "object",
452
+ properties: {
453
+ id: { type: "string", format: "uuid" },
454
+ action_type: { type: "string" },
455
+ target: { type: "string" },
456
+ summary: { type: "string" },
457
+ status: { type: "string", enum: ["pending", "approved", "denied", "executed", "failed", "timed_out", "auto_approved"] },
458
+ requested_by: { type: "string" },
459
+ created_at: { type: "string", format: "date-time" },
460
+ },
461
+ },
462
+ },
463
+ },
464
+ },
465
+ },
466
+ },
467
+ },
468
+ ...authErrors,
469
+ "404": errorResponse("Actions not available (no internal database or feature disabled)"),
470
+ },
363
471
  },
364
472
  },
365
- },
366
- tags: [
367
- { name: "Chat", description: "Streaming chat with the Atlas agent" },
368
- {
369
- name: "Query",
370
- description: "Synchronous JSON query endpoint",
473
+
474
+ "/api/v1/actions/{id}": {
475
+ get: {
476
+ operationId: "getAction",
477
+ summary: "Get action by ID",
478
+ description: "Returns a single action. Only returns actions requested by the authenticated user.",
479
+ tags: ["Actions"],
480
+ security: [{ bearerAuth: [] }, {}],
481
+ parameters: [uuidPathParam("id", "Action UUID.")],
482
+ responses: {
483
+ "200": {
484
+ description: "Action details",
485
+ content: { "application/json": { schema: { type: "object" } } },
486
+ },
487
+ "400": errorResponse("Invalid action ID format"),
488
+ ...authErrors,
489
+ "404": errorResponse("Action not found"),
490
+ },
491
+ },
371
492
  },
372
- {
373
- name: "Conversations",
374
- description: "Conversation history CRUD operations",
493
+
494
+ "/api/v1/actions/{id}/approve": {
495
+ post: {
496
+ operationId: "approveAction",
497
+ summary: "Approve a pending action",
498
+ description:
499
+ "Approves a pending action and triggers execution. Returns the updated action with results. " +
500
+ "For admin-only approval mode, the requester cannot approve their own action (separation of duties).",
501
+ tags: ["Actions"],
502
+ security: [{ bearerAuth: [] }],
503
+ parameters: [uuidPathParam("id", "Action UUID.")],
504
+ responses: {
505
+ "200": {
506
+ description: "Action approved and execution result",
507
+ content: { "application/json": { schema: { type: "object" } } },
508
+ },
509
+ "400": errorResponse("Invalid action ID format"),
510
+ ...authErrors,
511
+ "404": errorResponse("Action not found"),
512
+ "409": errorResponse("Action has already been resolved"),
513
+ },
514
+ },
515
+ },
516
+
517
+ "/api/v1/actions/{id}/deny": {
518
+ post: {
519
+ operationId: "denyAction",
520
+ summary: "Deny a pending action",
521
+ description:
522
+ "Denies a pending action. Optionally provide a reason in the request body. " +
523
+ "For admin-only approval mode, the requester cannot deny their own action.",
524
+ tags: ["Actions"],
525
+ security: [{ bearerAuth: [] }],
526
+ parameters: [uuidPathParam("id", "Action UUID.")],
527
+ requestBody: {
528
+ required: false,
529
+ content: {
530
+ "application/json": {
531
+ schema: {
532
+ type: "object",
533
+ properties: {
534
+ reason: { type: "string", description: "Optional denial reason." },
535
+ },
536
+ },
537
+ },
538
+ },
539
+ },
540
+ responses: {
541
+ "200": {
542
+ description: "Action denied",
543
+ content: { "application/json": { schema: { type: "object" } } },
544
+ },
545
+ "400": errorResponse("Invalid action ID or request body"),
546
+ ...authErrors,
547
+ "404": errorResponse("Action not found"),
548
+ "409": errorResponse("Action has already been resolved"),
549
+ },
550
+ },
551
+ },
552
+
553
+ // -----------------------------------------------------------------
554
+ // Scheduled Tasks
555
+ // -----------------------------------------------------------------
556
+ "/api/v1/scheduled-tasks": {
557
+ get: {
558
+ operationId: "listScheduledTasks",
559
+ summary: "List scheduled tasks",
560
+ description:
561
+ "Returns scheduled tasks owned by the authenticated user. Requires ATLAS_SCHEDULER_ENABLED=true and an internal database.",
562
+ tags: ["Scheduled Tasks"],
563
+ security: [{ bearerAuth: [] }, {}],
564
+ parameters: [
565
+ ...paginationParams(),
566
+ {
567
+ name: "enabled",
568
+ in: "query",
569
+ description: "Filter by enabled status.",
570
+ required: false,
571
+ schema: { type: "boolean" },
572
+ },
573
+ ],
574
+ responses: {
575
+ "200": {
576
+ description: "Paginated list of scheduled tasks",
577
+ content: { "application/json": { schema: { type: "object" } } },
578
+ },
579
+ ...authErrors,
580
+ "404": errorResponse("Scheduled tasks not available (no internal database or feature disabled)"),
581
+ },
582
+ },
583
+ post: {
584
+ operationId: "createScheduledTask",
585
+ summary: "Create a scheduled task",
586
+ description:
587
+ "Creates a recurring query task with a cron schedule and delivery channel.",
588
+ tags: ["Scheduled Tasks"],
589
+ security: [{ bearerAuth: [] }],
590
+ requestBody: {
591
+ required: true,
592
+ content: {
593
+ "application/json": {
594
+ schema: {
595
+ type: "object",
596
+ required: ["name", "question", "cronExpression"],
597
+ properties: {
598
+ name: { type: "string", minLength: 1, maxLength: 200, description: "Task name." },
599
+ question: { type: "string", minLength: 1, maxLength: 2000, description: "Natural language question." },
600
+ cronExpression: { type: "string", description: "Cron schedule (e.g. '0 9 * * *')." },
601
+ deliveryChannel: { type: "string", enum: ["email", "slack", "webhook"], default: "webhook", description: "Delivery channel." },
602
+ recipients: {
603
+ type: "array",
604
+ description: "Delivery targets.",
605
+ items: {
606
+ type: "object",
607
+ properties: {
608
+ type: { type: "string", enum: ["email", "slack", "webhook"] },
609
+ address: { type: "string", description: "Email address (for email type)." },
610
+ channel: { type: "string", description: "Slack channel (for slack type)." },
611
+ teamId: { type: "string", description: "Slack team ID (for slack type)." },
612
+ url: { type: "string", description: "Webhook URL (for webhook type)." },
613
+ headers: { type: "object", additionalProperties: { type: "string" }, description: "Custom headers (for webhook type)." },
614
+ },
615
+ },
616
+ },
617
+ connectionId: { type: "string", nullable: true, description: "Target datasource connection." },
618
+ approvalMode: { type: "string", enum: ["auto", "manual", "admin-only"], default: "auto", description: "Action approval mode." },
619
+ },
620
+ },
621
+ },
622
+ },
623
+ },
624
+ responses: {
625
+ "201": {
626
+ description: "Scheduled task created",
627
+ content: { "application/json": { schema: { type: "object" } } },
628
+ },
629
+ "400": errorResponse("Invalid request body or cron expression"),
630
+ ...authErrors,
631
+ "404": errorResponse("Feature not available"),
632
+ },
633
+ },
634
+ },
635
+
636
+ "/api/v1/scheduled-tasks/tick": {
637
+ post: {
638
+ operationId: "schedulerTick",
639
+ summary: "Trigger scheduler tick",
640
+ description:
641
+ "Serverless scheduler tick endpoint for Vercel Cron or external cron services. " +
642
+ "Checks for due tasks and executes them. Requires CRON_SECRET or ATLAS_SCHEDULER_SECRET.",
643
+ tags: ["Scheduled Tasks"],
644
+ security: [{ bearerAuth: [] }],
645
+ responses: {
646
+ "200": {
647
+ description: "Tick completed",
648
+ content: { "application/json": { schema: { type: "object" } } },
649
+ },
650
+ "401": errorResponse("Invalid or missing cron secret"),
651
+ "500": errorResponse("Tick execution failed"),
652
+ },
653
+ },
654
+ },
655
+
656
+ "/api/v1/scheduled-tasks/{id}": {
657
+ get: {
658
+ operationId: "getScheduledTask",
659
+ summary: "Get scheduled task",
660
+ description: "Returns a scheduled task with its 10 most recent runs.",
661
+ tags: ["Scheduled Tasks"],
662
+ security: [{ bearerAuth: [] }, {}],
663
+ parameters: [uuidPathParam("id", "Task UUID.")],
664
+ responses: {
665
+ "200": {
666
+ description: "Scheduled task with recent runs",
667
+ content: { "application/json": { schema: { type: "object" } } },
668
+ },
669
+ "400": errorResponse("Invalid task ID format"),
670
+ ...authErrors,
671
+ "404": errorResponse("Task not found"),
672
+ },
673
+ },
674
+ put: {
675
+ operationId: "updateScheduledTask",
676
+ summary: "Update a scheduled task",
677
+ description: "Updates a scheduled task. All fields are optional.",
678
+ tags: ["Scheduled Tasks"],
679
+ security: [{ bearerAuth: [] }],
680
+ parameters: [uuidPathParam("id", "Task UUID.")],
681
+ requestBody: {
682
+ required: true,
683
+ content: {
684
+ "application/json": {
685
+ schema: {
686
+ type: "object",
687
+ properties: {
688
+ name: { type: "string", minLength: 1, maxLength: 200 },
689
+ question: { type: "string", minLength: 1, maxLength: 2000 },
690
+ cronExpression: { type: "string" },
691
+ deliveryChannel: { type: "string", enum: ["email", "slack", "webhook"] },
692
+ recipients: { type: "array", items: { type: "object" } },
693
+ connectionId: { type: "string", nullable: true },
694
+ approvalMode: { type: "string", enum: ["auto", "manual", "admin-only"] },
695
+ enabled: { type: "boolean" },
696
+ },
697
+ },
698
+ },
699
+ },
700
+ },
701
+ responses: {
702
+ "200": {
703
+ description: "Updated scheduled task",
704
+ content: { "application/json": { schema: { type: "object" } } },
705
+ },
706
+ "400": errorResponse("Invalid request body or cron expression"),
707
+ ...authErrors,
708
+ "404": errorResponse("Task not found"),
709
+ },
710
+ },
711
+ delete: {
712
+ operationId: "deleteScheduledTask",
713
+ summary: "Delete a scheduled task",
714
+ description: "Soft-deletes (disables) a scheduled task.",
715
+ tags: ["Scheduled Tasks"],
716
+ security: [{ bearerAuth: [] }],
717
+ parameters: [uuidPathParam("id", "Task UUID.")],
718
+ responses: {
719
+ "204": { description: "Task deleted successfully" },
720
+ "400": errorResponse("Invalid task ID format"),
721
+ ...authErrors,
722
+ "404": errorResponse("Task not found"),
723
+ },
724
+ },
375
725
  },
726
+
727
+ "/api/v1/scheduled-tasks/{id}/run": {
728
+ post: {
729
+ operationId: "triggerScheduledTask",
730
+ summary: "Trigger immediate execution",
731
+ description: "Triggers an immediate execution of a scheduled task.",
732
+ tags: ["Scheduled Tasks"],
733
+ security: [{ bearerAuth: [] }],
734
+ parameters: [uuidPathParam("id", "Task UUID.")],
735
+ responses: {
736
+ "200": {
737
+ description: "Task triggered",
738
+ content: {
739
+ "application/json": {
740
+ schema: {
741
+ type: "object",
742
+ properties: {
743
+ message: { type: "string" },
744
+ taskId: { type: "string", format: "uuid" },
745
+ },
746
+ },
747
+ },
748
+ },
749
+ },
750
+ "400": errorResponse("Invalid task ID format"),
751
+ ...authErrors,
752
+ "404": errorResponse("Task not found"),
753
+ },
754
+ },
755
+ },
756
+
757
+ "/api/v1/scheduled-tasks/{id}/runs": {
758
+ get: {
759
+ operationId: "listTaskRuns",
760
+ summary: "List task runs",
761
+ description: "Returns past execution runs for a scheduled task.",
762
+ tags: ["Scheduled Tasks"],
763
+ security: [{ bearerAuth: [] }, {}],
764
+ parameters: [
765
+ uuidPathParam("id", "Task UUID."),
766
+ {
767
+ name: "limit",
768
+ in: "query",
769
+ description: "Maximum number of runs to return (1-100, default 20).",
770
+ required: false,
771
+ schema: { type: "integer", minimum: 1, maximum: 100, default: 20 },
772
+ },
773
+ ],
774
+ responses: {
775
+ "200": {
776
+ description: "List of task runs",
777
+ content: {
778
+ "application/json": {
779
+ schema: {
780
+ type: "object",
781
+ properties: {
782
+ runs: { type: "array", items: { type: "object" } },
783
+ },
784
+ },
785
+ },
786
+ },
787
+ },
788
+ "400": errorResponse("Invalid task ID format"),
789
+ ...authErrors,
790
+ "404": errorResponse("Task not found"),
791
+ },
792
+ },
793
+ },
794
+
795
+ // -----------------------------------------------------------------
796
+ // Auth — Better Auth routes (key endpoints)
797
+ // -----------------------------------------------------------------
798
+ "/api/auth/sign-up/email": {
799
+ post: {
800
+ operationId: "signUpEmail",
801
+ summary: "Sign up with email",
802
+ description:
803
+ "Creates a new user account with email and password. Only available when auth mode is 'managed' (Better Auth).",
804
+ tags: ["Auth"],
805
+ requestBody: {
806
+ required: true,
807
+ content: {
808
+ "application/json": {
809
+ schema: {
810
+ type: "object",
811
+ required: ["email", "password", "name"],
812
+ properties: {
813
+ email: { type: "string", format: "email" },
814
+ password: { type: "string", minLength: 8 },
815
+ name: { type: "string" },
816
+ },
817
+ },
818
+ },
819
+ },
820
+ },
821
+ responses: {
822
+ "200": {
823
+ description: "User created successfully",
824
+ content: { "application/json": { schema: { type: "object" } } },
825
+ },
826
+ "400": errorResponse("Invalid request"),
827
+ "404": errorResponse("Auth routes not enabled (not in managed mode)"),
828
+ },
829
+ },
830
+ },
831
+
832
+ "/api/auth/sign-in/email": {
833
+ post: {
834
+ operationId: "signInEmail",
835
+ summary: "Sign in with email",
836
+ description:
837
+ "Authenticates a user with email and password. Returns a session token. Only available when auth mode is 'managed'.",
838
+ tags: ["Auth"],
839
+ requestBody: {
840
+ required: true,
841
+ content: {
842
+ "application/json": {
843
+ schema: {
844
+ type: "object",
845
+ required: ["email", "password"],
846
+ properties: {
847
+ email: { type: "string", format: "email" },
848
+ password: { type: "string" },
849
+ },
850
+ },
851
+ },
852
+ },
853
+ },
854
+ responses: {
855
+ "200": {
856
+ description: "Session created",
857
+ content: { "application/json": { schema: { type: "object" } } },
858
+ },
859
+ "401": errorResponse("Invalid credentials"),
860
+ "404": errorResponse("Auth routes not enabled"),
861
+ },
862
+ },
863
+ },
864
+
865
+ "/api/auth/get-session": {
866
+ get: {
867
+ operationId: "getSession",
868
+ summary: "Get current session",
869
+ description:
870
+ "Returns the current session and user info. Requires a valid session cookie or Authorization header.",
871
+ tags: ["Auth"],
872
+ security: [{ bearerAuth: [] }],
873
+ responses: {
874
+ "200": {
875
+ description: "Current session",
876
+ content: { "application/json": { schema: { type: "object" } } },
877
+ },
878
+ "401": errorResponse("Not authenticated"),
879
+ "404": errorResponse("Auth routes not enabled"),
880
+ },
881
+ },
882
+ },
883
+
884
+ "/api/auth/sign-out": {
885
+ post: {
886
+ operationId: "signOut",
887
+ summary: "Sign out",
888
+ description: "Destroys the current session.",
889
+ tags: ["Auth"],
890
+ security: [{ bearerAuth: [] }],
891
+ responses: {
892
+ "200": { description: "Session destroyed" },
893
+ "404": errorResponse("Auth routes not enabled"),
894
+ },
895
+ },
896
+ },
897
+
898
+ // -----------------------------------------------------------------
899
+ // Slack integration
900
+ // -----------------------------------------------------------------
901
+ "/api/slack/commands": {
902
+ post: {
903
+ operationId: "slackCommand",
904
+ summary: "Slack slash command",
905
+ description:
906
+ "Handles Slack slash commands (/atlas). Acks within 3 seconds and processes the query asynchronously. " +
907
+ "Requires SLACK_SIGNING_SECRET. Request signature is verified.",
908
+ tags: ["Slack"],
909
+ requestBody: {
910
+ required: true,
911
+ content: {
912
+ "application/x-www-form-urlencoded": {
913
+ schema: {
914
+ type: "object",
915
+ properties: {
916
+ text: { type: "string", description: "The question text." },
917
+ channel_id: { type: "string" },
918
+ user_id: { type: "string" },
919
+ team_id: { type: "string" },
920
+ response_url: { type: "string" },
921
+ },
922
+ },
923
+ },
924
+ },
925
+ },
926
+ responses: {
927
+ "200": {
928
+ description: "Immediate acknowledgment (processing continues asynchronously)",
929
+ content: {
930
+ "application/json": {
931
+ schema: {
932
+ type: "object",
933
+ properties: {
934
+ response_type: { type: "string" },
935
+ text: { type: "string" },
936
+ },
937
+ },
938
+ },
939
+ },
940
+ },
941
+ "401": errorResponse("Invalid Slack signature"),
942
+ },
943
+ },
944
+ },
945
+
946
+ "/api/slack/events": {
947
+ post: {
948
+ operationId: "slackEvents",
949
+ summary: "Slack Events API",
950
+ description:
951
+ "Handles Slack Events API callbacks including url_verification challenges and thread follow-up messages. " +
952
+ "Bot messages are ignored to prevent loops.",
953
+ tags: ["Slack"],
954
+ requestBody: {
955
+ required: true,
956
+ content: {
957
+ "application/json": {
958
+ schema: {
959
+ type: "object",
960
+ properties: {
961
+ type: { type: "string", enum: ["url_verification", "event_callback"] },
962
+ challenge: { type: "string", description: "Verification challenge (url_verification only)." },
963
+ event: { type: "object", description: "The Slack event payload." },
964
+ },
965
+ },
966
+ },
967
+ },
968
+ },
969
+ responses: {
970
+ "200": {
971
+ description: "Event acknowledged",
972
+ content: {
973
+ "application/json": {
974
+ schema: {
975
+ type: "object",
976
+ properties: {
977
+ ok: { type: "boolean" },
978
+ challenge: { type: "string", description: "Echoed challenge (url_verification only)." },
979
+ },
980
+ },
981
+ },
982
+ },
983
+ },
984
+ "401": errorResponse("Invalid Slack signature"),
985
+ },
986
+ },
987
+ },
988
+
989
+ "/api/slack/install": {
990
+ get: {
991
+ operationId: "slackInstall",
992
+ summary: "Slack OAuth install",
993
+ description:
994
+ "Redirects to the Slack OAuth authorization page. Requires SLACK_CLIENT_ID to be configured.",
995
+ tags: ["Slack"],
996
+ responses: {
997
+ "302": { description: "Redirect to Slack OAuth authorization page" },
998
+ "501": errorResponse("OAuth not configured"),
999
+ },
1000
+ },
1001
+ },
1002
+
1003
+ "/api/slack/callback": {
1004
+ get: {
1005
+ operationId: "slackCallback",
1006
+ summary: "Slack OAuth callback",
1007
+ description:
1008
+ "Handles the OAuth callback from Slack, exchanges the code for a bot token, and saves the installation.",
1009
+ tags: ["Slack"],
1010
+ parameters: [
1011
+ { name: "code", in: "query", required: true, schema: { type: "string" }, description: "OAuth authorization code." },
1012
+ { name: "state", in: "query", required: true, schema: { type: "string" }, description: "CSRF state parameter." },
1013
+ ],
1014
+ responses: {
1015
+ "200": {
1016
+ description: "Installation successful (HTML response)",
1017
+ content: { "text/html": { schema: { type: "string" } } },
1018
+ },
1019
+ "400": errorResponse("Invalid or expired state, or missing code"),
1020
+ "500": { description: "Installation failed (HTML response)", content: { "text/html": { schema: { type: "string" } } } },
1021
+ "501": errorResponse("OAuth not configured"),
1022
+ },
1023
+ },
1024
+ },
1025
+
1026
+ // -----------------------------------------------------------------
1027
+ // Admin — admin console routes
1028
+ // -----------------------------------------------------------------
1029
+ "/api/v1/admin/overview": {
1030
+ get: {
1031
+ operationId: "adminOverview",
1032
+ summary: "Dashboard overview",
1033
+ description:
1034
+ "Returns counts of connections, entities, metrics, glossary terms, and plugins. Requires admin role.",
1035
+ tags: ["Admin"],
1036
+ security: [{ bearerAuth: [] }],
1037
+ responses: {
1038
+ "200": {
1039
+ description: "Dashboard summary",
1040
+ content: {
1041
+ "application/json": {
1042
+ schema: {
1043
+ type: "object",
1044
+ properties: {
1045
+ connections: { type: "integer" },
1046
+ entities: { type: "integer" },
1047
+ metrics: { type: "integer" },
1048
+ glossaryTerms: { type: "integer" },
1049
+ plugins: { type: "integer" },
1050
+ pluginHealth: {
1051
+ type: "array",
1052
+ items: {
1053
+ type: "object",
1054
+ properties: {
1055
+ id: { type: "string" },
1056
+ name: { type: "string" },
1057
+ type: { type: "string" },
1058
+ status: { type: "string" },
1059
+ },
1060
+ },
1061
+ },
1062
+ },
1063
+ },
1064
+ },
1065
+ },
1066
+ },
1067
+ ...authErrors,
1068
+ },
1069
+ },
1070
+ },
1071
+
1072
+ "/api/v1/admin/semantic/entities": {
1073
+ get: {
1074
+ operationId: "adminListEntities",
1075
+ summary: "List semantic entities",
1076
+ description: "Lists all entity YAML files with summary info. Requires admin role.",
1077
+ tags: ["Admin"],
1078
+ security: [{ bearerAuth: [] }],
1079
+ responses: {
1080
+ "200": {
1081
+ description: "List of entities",
1082
+ content: { "application/json": { schema: { type: "object" } } },
1083
+ },
1084
+ ...authErrors,
1085
+ },
1086
+ },
1087
+ },
1088
+
1089
+ "/api/v1/admin/semantic/entities/{name}": {
1090
+ get: {
1091
+ operationId: "adminGetEntity",
1092
+ summary: "Get entity details",
1093
+ description: "Returns the full parsed YAML for a specific entity. Requires admin role.",
1094
+ tags: ["Admin"],
1095
+ security: [{ bearerAuth: [] }],
1096
+ parameters: [
1097
+ { name: "name", in: "path", required: true, schema: { type: "string" }, description: "Entity name (e.g. 'orders')." },
1098
+ ],
1099
+ responses: {
1100
+ "200": {
1101
+ description: "Entity YAML content",
1102
+ content: { "application/json": { schema: { type: "object" } } },
1103
+ },
1104
+ "400": errorResponse("Invalid entity name"),
1105
+ ...authErrors,
1106
+ "404": errorResponse("Entity not found"),
1107
+ },
1108
+ },
1109
+ },
1110
+
1111
+ "/api/v1/admin/semantic/metrics": {
1112
+ get: {
1113
+ operationId: "adminListMetrics",
1114
+ summary: "List metrics",
1115
+ description: "Lists all metric YAML files grouped by source. Requires admin role.",
1116
+ tags: ["Admin"],
1117
+ security: [{ bearerAuth: [] }],
1118
+ responses: {
1119
+ "200": {
1120
+ description: "List of metrics",
1121
+ content: { "application/json": { schema: { type: "object" } } },
1122
+ },
1123
+ ...authErrors,
1124
+ },
1125
+ },
1126
+ },
1127
+
1128
+ "/api/v1/admin/semantic/glossary": {
1129
+ get: {
1130
+ operationId: "adminGetGlossary",
1131
+ summary: "Get glossary",
1132
+ description: "Returns all glossary files (default and per-source). Requires admin role.",
1133
+ tags: ["Admin"],
1134
+ security: [{ bearerAuth: [] }],
1135
+ responses: {
1136
+ "200": {
1137
+ description: "Glossary content",
1138
+ content: { "application/json": { schema: { type: "object" } } },
1139
+ },
1140
+ ...authErrors,
1141
+ },
1142
+ },
1143
+ },
1144
+
1145
+ "/api/v1/admin/semantic/catalog": {
1146
+ get: {
1147
+ operationId: "adminGetCatalog",
1148
+ summary: "Get catalog",
1149
+ description: "Returns the parsed catalog.yml. Returns an object with a null catalog field if no catalog exists. Requires admin role.",
1150
+ tags: ["Admin"],
1151
+ security: [{ bearerAuth: [] }],
1152
+ responses: {
1153
+ "200": {
1154
+ description: "Catalog content",
1155
+ content: { "application/json": { schema: { type: "object" } } },
1156
+ },
1157
+ ...authErrors,
1158
+ },
1159
+ },
1160
+ },
1161
+
1162
+ "/api/v1/admin/semantic/raw/{file}": {
1163
+ get: {
1164
+ operationId: "adminGetRawFile",
1165
+ summary: "Get raw YAML file",
1166
+ description:
1167
+ "Serves a raw top-level YAML file from the semantic layer (e.g. catalog.yml, glossary.yml). " +
1168
+ "Only .yml files matching the allowed pattern are served. Requires admin role.",
1169
+ tags: ["Admin"],
1170
+ security: [{ bearerAuth: [] }],
1171
+ parameters: [
1172
+ {
1173
+ name: "file",
1174
+ in: "path",
1175
+ required: true,
1176
+ schema: { type: "string", pattern: "^(catalog|glossary)\\.yml$" },
1177
+ description: "Top-level YAML filename (e.g. 'catalog.yml').",
1178
+ },
1179
+ ],
1180
+ responses: {
1181
+ "200": {
1182
+ description: "Raw YAML content",
1183
+ content: { "text/plain": { schema: { type: "string" } } },
1184
+ },
1185
+ "400": errorResponse("Invalid file path"),
1186
+ ...authErrors,
1187
+ "404": errorResponse("File not found"),
1188
+ },
1189
+ },
1190
+ },
1191
+
1192
+ "/api/v1/admin/semantic/raw/{dir}/{file}": {
1193
+ get: {
1194
+ operationId: "adminGetRawDirFile",
1195
+ summary: "Get raw YAML file from subdirectory",
1196
+ description:
1197
+ "Serves a raw YAML file from a semantic layer subdirectory (e.g. entities/orders.yml, metrics/revenue.yml). " +
1198
+ "Only .yml files in entities/ or metrics/ are allowed. Requires admin role.",
1199
+ tags: ["Admin"],
1200
+ security: [{ bearerAuth: [] }],
1201
+ parameters: [
1202
+ {
1203
+ name: "dir",
1204
+ in: "path",
1205
+ required: true,
1206
+ schema: { type: "string", enum: ["entities", "metrics"] },
1207
+ description: "Subdirectory name.",
1208
+ },
1209
+ {
1210
+ name: "file",
1211
+ in: "path",
1212
+ required: true,
1213
+ schema: { type: "string", pattern: "^[a-zA-Z0-9_-]+\\.yml$" },
1214
+ description: "YAML filename (e.g. 'orders.yml').",
1215
+ },
1216
+ ],
1217
+ responses: {
1218
+ "200": {
1219
+ description: "Raw YAML content",
1220
+ content: { "text/plain": { schema: { type: "string" } } },
1221
+ },
1222
+ "400": errorResponse("Invalid file path"),
1223
+ ...authErrors,
1224
+ "404": errorResponse("File not found"),
1225
+ },
1226
+ },
1227
+ },
1228
+
1229
+ "/api/v1/admin/semantic/stats": {
1230
+ get: {
1231
+ operationId: "adminSemanticStats",
1232
+ summary: "Semantic layer statistics",
1233
+ description: "Aggregate statistics across the semantic layer. Requires admin role.",
1234
+ tags: ["Admin"],
1235
+ security: [{ bearerAuth: [] }],
1236
+ responses: {
1237
+ "200": {
1238
+ description: "Semantic layer stats",
1239
+ content: {
1240
+ "application/json": {
1241
+ schema: {
1242
+ type: "object",
1243
+ properties: {
1244
+ totalEntities: { type: "integer" },
1245
+ totalColumns: { type: "integer" },
1246
+ totalJoins: { type: "integer" },
1247
+ totalMeasures: { type: "integer" },
1248
+ coverageGaps: {
1249
+ type: "object",
1250
+ properties: {
1251
+ noDescription: { type: "integer" },
1252
+ noColumns: { type: "integer" },
1253
+ noJoins: { type: "integer" },
1254
+ },
1255
+ },
1256
+ },
1257
+ },
1258
+ },
1259
+ },
1260
+ },
1261
+ ...authErrors,
1262
+ },
1263
+ },
1264
+ },
1265
+
1266
+ "/api/v1/admin/connections": {
1267
+ get: {
1268
+ operationId: "adminListConnections",
1269
+ summary: "List connections",
1270
+ description: "Lists all registered database connections with type and cached health status. Requires admin role.",
1271
+ tags: ["Admin"],
1272
+ security: [{ bearerAuth: [] }],
1273
+ responses: {
1274
+ "200": {
1275
+ description: "List of connections",
1276
+ content: { "application/json": { schema: { type: "object" } } },
1277
+ },
1278
+ ...authErrors,
1279
+ },
1280
+ },
1281
+ },
1282
+
1283
+ "/api/v1/admin/connections/{id}/test": {
1284
+ post: {
1285
+ operationId: "adminTestConnection",
1286
+ summary: "Test a connection",
1287
+ description: "Triggers a live health check for a specific connection. Requires admin role.",
1288
+ tags: ["Admin"],
1289
+ security: [{ bearerAuth: [] }],
1290
+ parameters: [
1291
+ { name: "id", in: "path", required: true, schema: { type: "string" }, description: "Connection ID (e.g. 'default')." },
1292
+ ],
1293
+ responses: {
1294
+ "200": {
1295
+ description: "Connection health check result",
1296
+ content: {
1297
+ "application/json": {
1298
+ schema: {
1299
+ type: "object",
1300
+ properties: {
1301
+ status: { type: "string", enum: ["healthy", "unhealthy"] },
1302
+ latencyMs: { type: "integer" },
1303
+ checkedAt: { type: "string", format: "date-time" },
1304
+ },
1305
+ },
1306
+ },
1307
+ },
1308
+ },
1309
+ ...authErrors,
1310
+ "404": errorResponse("Connection not found"),
1311
+ },
1312
+ },
1313
+ },
1314
+
1315
+ "/api/v1/admin/users": {
1316
+ get: {
1317
+ operationId: "adminListUsers",
1318
+ summary: "List users",
1319
+ description: "Lists users with pagination, search, and role filtering. Requires admin role and managed auth.",
1320
+ tags: ["Admin"],
1321
+ security: [{ bearerAuth: [] }],
1322
+ parameters: [
1323
+ ...paginationParams({ limit: 50, maxLimit: 200 }),
1324
+ { name: "search", in: "query", required: false, schema: { type: "string" }, description: "Search by email (contains match)." },
1325
+ { name: "role", in: "query", required: false, schema: { type: "string", enum: ["viewer", "analyst", "admin"] }, description: "Filter by role." },
1326
+ ],
1327
+ responses: {
1328
+ "200": {
1329
+ description: "Paginated list of users",
1330
+ content: { "application/json": { schema: { type: "object" } } },
1331
+ },
1332
+ ...authErrors,
1333
+ },
1334
+ },
1335
+ },
1336
+
1337
+ "/api/v1/admin/users/stats": {
1338
+ get: {
1339
+ operationId: "adminUserStats",
1340
+ summary: "User statistics",
1341
+ description: "Aggregate user statistics: total count, banned count, and breakdown by role. Requires admin role.",
1342
+ tags: ["Admin"],
1343
+ security: [{ bearerAuth: [] }],
1344
+ responses: {
1345
+ "200": {
1346
+ description: "User stats",
1347
+ content: {
1348
+ "application/json": {
1349
+ schema: {
1350
+ type: "object",
1351
+ properties: {
1352
+ total: { type: "integer" },
1353
+ banned: { type: "integer" },
1354
+ byRole: {
1355
+ type: "object",
1356
+ properties: {
1357
+ admin: { type: "integer" },
1358
+ analyst: { type: "integer" },
1359
+ viewer: { type: "integer" },
1360
+ },
1361
+ },
1362
+ },
1363
+ },
1364
+ },
1365
+ },
1366
+ },
1367
+ ...authErrors,
1368
+ },
1369
+ },
1370
+ },
1371
+
1372
+ "/api/v1/admin/users/{id}/role": {
1373
+ patch: {
1374
+ operationId: "adminChangeUserRole",
1375
+ summary: "Change user role",
1376
+ description: "Updates a user's role. Cannot change your own role or demote the last admin. Requires admin role.",
1377
+ tags: ["Admin"],
1378
+ security: [{ bearerAuth: [] }],
1379
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID." }],
1380
+ requestBody: {
1381
+ required: true,
1382
+ content: {
1383
+ "application/json": {
1384
+ schema: {
1385
+ type: "object",
1386
+ required: ["role"],
1387
+ properties: {
1388
+ role: { type: "string", enum: ["viewer", "analyst", "admin"] },
1389
+ },
1390
+ },
1391
+ },
1392
+ },
1393
+ },
1394
+ responses: {
1395
+ "200": { description: "Role updated", content: { "application/json": { schema: { type: "object" } } } },
1396
+ "400": errorResponse("Invalid role or cannot change own role"),
1397
+ ...authErrors,
1398
+ },
1399
+ },
1400
+ },
1401
+
1402
+ "/api/v1/admin/users/{id}/ban": {
1403
+ post: {
1404
+ operationId: "adminBanUser",
1405
+ summary: "Ban a user",
1406
+ description: "Bans a user with optional reason and expiration. Requires admin role.",
1407
+ tags: ["Admin"],
1408
+ security: [{ bearerAuth: [] }],
1409
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID." }],
1410
+ requestBody: {
1411
+ required: false,
1412
+ content: {
1413
+ "application/json": {
1414
+ schema: {
1415
+ type: "object",
1416
+ properties: {
1417
+ reason: { type: "string" },
1418
+ expiresIn: { type: "integer", description: "Ban duration in seconds." },
1419
+ },
1420
+ },
1421
+ },
1422
+ },
1423
+ },
1424
+ responses: {
1425
+ "200": { description: "User banned", content: { "application/json": { schema: { type: "object" } } } },
1426
+ ...authErrors,
1427
+ },
1428
+ },
1429
+ },
1430
+
1431
+ "/api/v1/admin/users/{id}/unban": {
1432
+ post: {
1433
+ operationId: "adminUnbanUser",
1434
+ summary: "Unban a user",
1435
+ description: "Removes a ban from a user. Requires admin role.",
1436
+ tags: ["Admin"],
1437
+ security: [{ bearerAuth: [] }],
1438
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID." }],
1439
+ responses: {
1440
+ "200": { description: "User unbanned", content: { "application/json": { schema: { type: "object" } } } },
1441
+ ...authErrors,
1442
+ },
1443
+ },
1444
+ },
1445
+
1446
+ "/api/v1/admin/users/{id}": {
1447
+ delete: {
1448
+ operationId: "adminDeleteUser",
1449
+ summary: "Delete a user",
1450
+ description: "Permanently deletes a user. Cannot delete yourself or the last admin. Requires admin role.",
1451
+ tags: ["Admin"],
1452
+ security: [{ bearerAuth: [] }],
1453
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID." }],
1454
+ responses: {
1455
+ "204": { description: "User deleted" },
1456
+ "400": errorResponse("Cannot delete yourself or last admin"),
1457
+ ...authErrors,
1458
+ },
1459
+ },
1460
+ },
1461
+
1462
+ "/api/v1/admin/users/{id}/revoke": {
1463
+ post: {
1464
+ operationId: "adminRevokeUserSessions",
1465
+ summary: "Revoke user sessions",
1466
+ description: "Revokes all sessions for a user (force logout). Requires admin role.",
1467
+ tags: ["Admin"],
1468
+ security: [{ bearerAuth: [] }],
1469
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID." }],
1470
+ responses: {
1471
+ "200": { description: "Sessions revoked", content: { "application/json": { schema: { type: "object" } } } },
1472
+ ...authErrors,
1473
+ },
1474
+ },
1475
+ },
1476
+
1477
+ "/api/v1/admin/audit": {
1478
+ get: {
1479
+ operationId: "adminListAuditLog",
1480
+ summary: "Query audit log",
1481
+ description: "Returns paginated audit log entries with optional filters. Requires admin role and internal database.",
1482
+ tags: ["Admin"],
1483
+ security: [{ bearerAuth: [] }],
1484
+ parameters: [
1485
+ ...paginationParams({ limit: 50, maxLimit: 200 }),
1486
+ { name: "user", in: "query", required: false, schema: { type: "string" }, description: "Filter by user ID." },
1487
+ { name: "success", in: "query", required: false, schema: { type: "boolean" }, description: "Filter by success/failure." },
1488
+ { name: "from", in: "query", required: false, schema: { type: "string", format: "date-time" }, description: "ISO 8601 start date." },
1489
+ { name: "to", in: "query", required: false, schema: { type: "string", format: "date-time" }, description: "ISO 8601 end date." },
1490
+ ],
1491
+ responses: {
1492
+ "200": {
1493
+ description: "Paginated audit log",
1494
+ content: { "application/json": { schema: { type: "object" } } },
1495
+ },
1496
+ ...authErrors,
1497
+ },
1498
+ },
1499
+ },
1500
+
1501
+ "/api/v1/admin/audit/stats": {
1502
+ get: {
1503
+ operationId: "adminAuditStats",
1504
+ summary: "Audit statistics",
1505
+ description: "Aggregate audit statistics: total queries, error count, error rate, and queries per day. Requires admin role.",
1506
+ tags: ["Admin"],
1507
+ security: [{ bearerAuth: [] }],
1508
+ responses: {
1509
+ "200": {
1510
+ description: "Audit stats",
1511
+ content: { "application/json": { schema: { type: "object" } } },
1512
+ },
1513
+ ...authErrors,
1514
+ },
1515
+ },
1516
+ },
1517
+
1518
+ "/api/v1/admin/plugins": {
1519
+ get: {
1520
+ operationId: "adminListPlugins",
1521
+ summary: "List plugins",
1522
+ description: "Lists all installed plugins with type, version, and status. Requires admin role.",
1523
+ tags: ["Admin"],
1524
+ security: [{ bearerAuth: [] }],
1525
+ responses: {
1526
+ "200": {
1527
+ description: "List of plugins",
1528
+ content: { "application/json": { schema: { type: "object" } } },
1529
+ },
1530
+ ...authErrors,
1531
+ },
1532
+ },
1533
+ },
1534
+
1535
+ "/api/v1/admin/plugins/{id}/health": {
1536
+ post: {
1537
+ operationId: "adminPluginHealth",
1538
+ summary: "Check plugin health",
1539
+ description: "Triggers a health check for a specific plugin. Requires admin role.",
1540
+ tags: ["Admin"],
1541
+ security: [{ bearerAuth: [] }],
1542
+ parameters: [
1543
+ { name: "id", in: "path", required: true, schema: { type: "string" }, description: "Plugin ID." },
1544
+ ],
1545
+ responses: {
1546
+ "200": {
1547
+ description: "Plugin health check result",
1548
+ content: { "application/json": { schema: { type: "object" } } },
1549
+ },
1550
+ ...authErrors,
1551
+ "404": errorResponse("Plugin not found"),
1552
+ },
1553
+ },
1554
+ },
1555
+
1556
+ "/api/v1/admin/me/password-status": {
1557
+ get: {
1558
+ operationId: "adminPasswordStatus",
1559
+ summary: "Check password change requirement",
1560
+ description: "Checks if the current user must change their password. Available to any authenticated managed-auth user.",
1561
+ tags: ["Admin"],
1562
+ security: [{ bearerAuth: [] }],
1563
+ responses: {
1564
+ "200": {
1565
+ description: "Password status",
1566
+ content: {
1567
+ "application/json": {
1568
+ schema: {
1569
+ type: "object",
1570
+ properties: {
1571
+ mustChange: { type: "boolean" },
1572
+ },
1573
+ },
1574
+ },
1575
+ },
1576
+ },
1577
+ ...authErrors,
1578
+ },
1579
+ },
1580
+ },
1581
+
1582
+ "/api/v1/admin/me/password": {
1583
+ post: {
1584
+ operationId: "adminChangePassword",
1585
+ summary: "Change password",
1586
+ description: "Changes the current user's password. Available to any authenticated managed-auth user.",
1587
+ tags: ["Admin"],
1588
+ security: [{ bearerAuth: [] }],
1589
+ requestBody: {
1590
+ required: true,
1591
+ content: {
1592
+ "application/json": {
1593
+ schema: {
1594
+ type: "object",
1595
+ required: ["currentPassword", "newPassword"],
1596
+ properties: {
1597
+ currentPassword: { type: "string" },
1598
+ newPassword: { type: "string", minLength: 8 },
1599
+ },
1600
+ },
1601
+ },
1602
+ },
1603
+ },
1604
+ responses: {
1605
+ "200": { description: "Password changed", content: { "application/json": { schema: { type: "object" } } } },
1606
+ "400": errorResponse("Invalid current password or weak new password"),
1607
+ ...authErrors,
1608
+ },
1609
+ },
1610
+ },
1611
+ },
1612
+ components: {
1613
+ securitySchemes: {
1614
+ bearerAuth: {
1615
+ type: "http",
1616
+ scheme: "bearer",
1617
+ description:
1618
+ "API key or JWT token. Pass via Authorization: Bearer <token>.",
1619
+ },
1620
+ },
1621
+ },
1622
+ tags: [
1623
+ { name: "Chat", description: "Streaming chat with the Atlas agent" },
1624
+ { name: "Query", description: "Synchronous JSON query endpoint" },
1625
+ { name: "Conversations", description: "Conversation history CRUD operations" },
376
1626
  { name: "Health", description: "Service health checks" },
1627
+ { name: "Actions", description: "Approval-gated write operations (requires ATLAS_ACTIONS_ENABLED=true)" },
1628
+ { name: "Scheduled Tasks", description: "Recurring query tasks with cron scheduling (requires ATLAS_SCHEDULER_ENABLED=true)" },
1629
+ { name: "Auth", description: "Authentication routes (managed auth via Better Auth)" },
1630
+ { name: "Slack", description: "Slack integration (requires SLACK_SIGNING_SECRET)" },
1631
+ { name: "Admin", description: "Admin console API (requires admin role)" },
377
1632
  ],
378
1633
  };
379
1634
  }