@digimuza/saas-core 0.0.2

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 (474) hide show
  1. package/CLAUDE.md +1165 -0
  2. package/LICENSE +21 -0
  3. package/README.md +234 -0
  4. package/dist/api-keys/index.d.ts +9 -0
  5. package/dist/api-keys/index.d.ts.map +1 -0
  6. package/dist/api-keys/index.js +37 -0
  7. package/dist/api-keys/index.js.map +1 -0
  8. package/dist/api-keys/keys.d.ts +55 -0
  9. package/dist/api-keys/keys.d.ts.map +1 -0
  10. package/dist/api-keys/keys.js +92 -0
  11. package/dist/api-keys/keys.js.map +1 -0
  12. package/dist/api-keys/service.d.ts +111 -0
  13. package/dist/api-keys/service.d.ts.map +1 -0
  14. package/dist/api-keys/service.js +210 -0
  15. package/dist/api-keys/service.js.map +1 -0
  16. package/dist/audit/index.d.ts +5 -0
  17. package/dist/audit/index.d.ts.map +1 -0
  18. package/dist/audit/index.js +44 -0
  19. package/dist/audit/index.js.map +1 -0
  20. package/dist/audit/service.d.ts +88 -0
  21. package/dist/audit/service.d.ts.map +1 -0
  22. package/dist/audit/service.js +128 -0
  23. package/dist/audit/service.js.map +1 -0
  24. package/dist/auth/client.d.ts +5 -0
  25. package/dist/auth/client.d.ts.map +1 -0
  26. package/dist/auth/client.js +26 -0
  27. package/dist/auth/client.js.map +1 -0
  28. package/dist/auth/cookies.d.ts +51 -0
  29. package/dist/auth/cookies.d.ts.map +1 -0
  30. package/dist/auth/cookies.js +58 -0
  31. package/dist/auth/cookies.js.map +1 -0
  32. package/dist/auth/index.d.ts +14 -0
  33. package/dist/auth/index.d.ts.map +1 -0
  34. package/dist/auth/index.js +46 -0
  35. package/dist/auth/index.js.map +1 -0
  36. package/dist/auth/service.d.ts +67 -0
  37. package/dist/auth/service.d.ts.map +1 -0
  38. package/dist/auth/service.js +275 -0
  39. package/dist/auth/service.js.map +1 -0
  40. package/dist/auth/types.d.ts +56 -0
  41. package/dist/auth/types.d.ts.map +1 -0
  42. package/dist/auth/types.js +2 -0
  43. package/dist/auth/types.js.map +1 -0
  44. package/dist/authorization/index.d.ts +4 -0
  45. package/dist/authorization/index.d.ts.map +1 -0
  46. package/dist/authorization/index.js +24 -0
  47. package/dist/authorization/index.js.map +1 -0
  48. package/dist/authorization/service.d.ts +92 -0
  49. package/dist/authorization/service.d.ts.map +1 -0
  50. package/dist/authorization/service.js +254 -0
  51. package/dist/authorization/service.js.map +1 -0
  52. package/dist/billing/index.d.ts +16 -0
  53. package/dist/billing/index.d.ts.map +1 -0
  54. package/dist/billing/index.js +47 -0
  55. package/dist/billing/index.js.map +1 -0
  56. package/dist/billing/provider.d.ts +114 -0
  57. package/dist/billing/provider.d.ts.map +1 -0
  58. package/dist/billing/provider.js +2 -0
  59. package/dist/billing/provider.js.map +1 -0
  60. package/dist/billing/revolut.d.ts +68 -0
  61. package/dist/billing/revolut.d.ts.map +1 -0
  62. package/dist/billing/revolut.js +181 -0
  63. package/dist/billing/revolut.js.map +1 -0
  64. package/dist/billing/service.d.ts +124 -0
  65. package/dist/billing/service.d.ts.map +1 -0
  66. package/dist/billing/service.js +470 -0
  67. package/dist/billing/service.js.map +1 -0
  68. package/dist/cli/commands/dev.d.ts +43 -0
  69. package/dist/cli/commands/dev.d.ts.map +1 -0
  70. package/dist/cli/commands/dev.js +212 -0
  71. package/dist/cli/commands/dev.js.map +1 -0
  72. package/dist/cli/commands/project.d.ts +12 -0
  73. package/dist/cli/commands/project.d.ts.map +1 -0
  74. package/dist/cli/commands/project.js +49 -0
  75. package/dist/cli/commands/project.js.map +1 -0
  76. package/dist/cli/docker.d.ts +50 -0
  77. package/dist/cli/docker.d.ts.map +1 -0
  78. package/dist/cli/docker.js +84 -0
  79. package/dist/cli/docker.js.map +1 -0
  80. package/dist/cli/index.d.ts +6 -0
  81. package/dist/cli/index.d.ts.map +1 -0
  82. package/dist/cli/index.js +198 -0
  83. package/dist/cli/index.js.map +1 -0
  84. package/dist/cli/output.d.ts +30 -0
  85. package/dist/cli/output.d.ts.map +1 -0
  86. package/dist/cli/output.js +66 -0
  87. package/dist/cli/output.js.map +1 -0
  88. package/dist/cli/templates.d.ts +52 -0
  89. package/dist/cli/templates.d.ts.map +1 -0
  90. package/dist/cli/templates.js +225 -0
  91. package/dist/cli/templates.js.map +1 -0
  92. package/dist/config/client.d.ts +60 -0
  93. package/dist/config/client.d.ts.map +1 -0
  94. package/dist/config/client.js +94 -0
  95. package/dist/config/client.js.map +1 -0
  96. package/dist/config/config-loader.d.ts +2 -0
  97. package/dist/config/config-loader.d.ts.map +1 -0
  98. package/dist/config/config-loader.js +2 -0
  99. package/dist/config/config-loader.js.map +1 -0
  100. package/dist/config/env.d.ts +24 -0
  101. package/dist/config/env.d.ts.map +1 -0
  102. package/dist/config/env.js +40 -0
  103. package/dist/config/env.js.map +1 -0
  104. package/dist/config/errors.d.ts +17 -0
  105. package/dist/config/errors.d.ts.map +1 -0
  106. package/dist/config/errors.js +26 -0
  107. package/dist/config/errors.js.map +1 -0
  108. package/dist/config/index.d.ts +72 -0
  109. package/dist/config/index.d.ts.map +1 -0
  110. package/dist/config/index.js +106 -0
  111. package/dist/config/index.js.map +1 -0
  112. package/dist/config/runtime.d.ts +15 -0
  113. package/dist/config/runtime.d.ts.map +1 -0
  114. package/dist/config/runtime.js +22 -0
  115. package/dist/config/runtime.js.map +1 -0
  116. package/dist/config/sections.d.ts +226 -0
  117. package/dist/config/sections.d.ts.map +1 -0
  118. package/dist/config/sections.js +141 -0
  119. package/dist/config/sections.js.map +1 -0
  120. package/dist/db/client.d.ts +43 -0
  121. package/dist/db/client.d.ts.map +1 -0
  122. package/dist/db/client.js +77 -0
  123. package/dist/db/client.js.map +1 -0
  124. package/dist/db/errors.d.ts +39 -0
  125. package/dist/db/errors.d.ts.map +1 -0
  126. package/dist/db/errors.js +67 -0
  127. package/dist/db/errors.js.map +1 -0
  128. package/dist/db/index.d.ts +10 -0
  129. package/dist/db/index.d.ts.map +1 -0
  130. package/dist/db/index.js +10 -0
  131. package/dist/db/index.js.map +1 -0
  132. package/dist/db/migrate.d.ts +21 -0
  133. package/dist/db/migrate.d.ts.map +1 -0
  134. package/dist/db/migrate.js +28 -0
  135. package/dist/db/migrate.js.map +1 -0
  136. package/dist/db/schema/_shared.d.ts +30 -0
  137. package/dist/db/schema/_shared.d.ts.map +1 -0
  138. package/dist/db/schema/_shared.js +36 -0
  139. package/dist/db/schema/_shared.js.map +1 -0
  140. package/dist/db/schema/apikeys.d.ts +263 -0
  141. package/dist/db/schema/apikeys.d.ts.map +1 -0
  142. package/dist/db/schema/apikeys.js +70 -0
  143. package/dist/db/schema/apikeys.js.map +1 -0
  144. package/dist/db/schema/authorization.d.ts +465 -0
  145. package/dist/db/schema/authorization.d.ts.map +1 -0
  146. package/dist/db/schema/authorization.js +134 -0
  147. package/dist/db/schema/authorization.js.map +1 -0
  148. package/dist/db/schema/billing.d.ts +1100 -0
  149. package/dist/db/schema/billing.d.ts.map +1 -0
  150. package/dist/db/schema/billing.js +223 -0
  151. package/dist/db/schema/billing.js.map +1 -0
  152. package/dist/db/schema/events.d.ts +161 -0
  153. package/dist/db/schema/events.d.ts.map +1 -0
  154. package/dist/db/schema/events.js +66 -0
  155. package/dist/db/schema/events.js.map +1 -0
  156. package/dist/db/schema/features.d.ts +243 -0
  157. package/dist/db/schema/features.d.ts.map +1 -0
  158. package/dist/db/schema/features.js +87 -0
  159. package/dist/db/schema/features.js.map +1 -0
  160. package/dist/db/schema/files.d.ts +253 -0
  161. package/dist/db/schema/files.d.ts.map +1 -0
  162. package/dist/db/schema/files.js +74 -0
  163. package/dist/db/schema/files.js.map +1 -0
  164. package/dist/db/schema/index.d.ts +38 -0
  165. package/dist/db/schema/index.d.ts.map +1 -0
  166. package/dist/db/schema/index.js +38 -0
  167. package/dist/db/schema/index.js.map +1 -0
  168. package/dist/db/schema/invitations.d.ts +214 -0
  169. package/dist/db/schema/invitations.d.ts.map +1 -0
  170. package/dist/db/schema/invitations.js +80 -0
  171. package/dist/db/schema/invitations.js.map +1 -0
  172. package/dist/db/schema/messaging.d.ts +442 -0
  173. package/dist/db/schema/messaging.d.ts.map +1 -0
  174. package/dist/db/schema/messaging.js +120 -0
  175. package/dist/db/schema/messaging.js.map +1 -0
  176. package/dist/db/schema/users.d.ts +246 -0
  177. package/dist/db/schema/users.d.ts.map +1 -0
  178. package/dist/db/schema/users.js +60 -0
  179. package/dist/db/schema/users.js.map +1 -0
  180. package/dist/db/schema/webhooks.d.ts +693 -0
  181. package/dist/db/schema/webhooks.d.ts.map +1 -0
  182. package/dist/db/schema/webhooks.js +147 -0
  183. package/dist/db/schema/webhooks.js.map +1 -0
  184. package/dist/db/schema/workspaces.d.ts +196 -0
  185. package/dist/db/schema/workspaces.d.ts.map +1 -0
  186. package/dist/db/schema/workspaces.js +57 -0
  187. package/dist/db/schema/workspaces.js.map +1 -0
  188. package/dist/db/types.d.ts +18 -0
  189. package/dist/db/types.d.ts.map +1 -0
  190. package/dist/db/types.js +2 -0
  191. package/dist/db/types.js.map +1 -0
  192. package/dist/email/adapters.d.ts +29 -0
  193. package/dist/email/adapters.d.ts.map +1 -0
  194. package/dist/email/adapters.js +60 -0
  195. package/dist/email/adapters.js.map +1 -0
  196. package/dist/email/index.d.ts +20 -0
  197. package/dist/email/index.d.ts.map +1 -0
  198. package/dist/email/index.js +79 -0
  199. package/dist/email/index.js.map +1 -0
  200. package/dist/email/provider.d.ts +47 -0
  201. package/dist/email/provider.d.ts.map +1 -0
  202. package/dist/email/provider.js +7 -0
  203. package/dist/email/provider.js.map +1 -0
  204. package/dist/email/resend.d.ts +22 -0
  205. package/dist/email/resend.d.ts.map +1 -0
  206. package/dist/email/resend.js +51 -0
  207. package/dist/email/resend.js.map +1 -0
  208. package/dist/email/service.d.ts +55 -0
  209. package/dist/email/service.d.ts.map +1 -0
  210. package/dist/email/service.js +87 -0
  211. package/dist/email/service.js.map +1 -0
  212. package/dist/email/templates.d.ts +81 -0
  213. package/dist/email/templates.d.ts.map +1 -0
  214. package/dist/email/templates.js +84 -0
  215. package/dist/email/templates.js.map +1 -0
  216. package/dist/entitlements/index.d.ts +10 -0
  217. package/dist/entitlements/index.d.ts.map +1 -0
  218. package/dist/entitlements/index.js +28 -0
  219. package/dist/entitlements/index.js.map +1 -0
  220. package/dist/entitlements/service.d.ts +83 -0
  221. package/dist/entitlements/service.d.ts.map +1 -0
  222. package/dist/entitlements/service.js +158 -0
  223. package/dist/entitlements/service.js.map +1 -0
  224. package/dist/errors.d.ts +85 -0
  225. package/dist/errors.d.ts.map +1 -0
  226. package/dist/errors.js +95 -0
  227. package/dist/errors.js.map +1 -0
  228. package/dist/events/core-events.d.ts +120 -0
  229. package/dist/events/core-events.d.ts.map +1 -0
  230. package/dist/events/core-events.js +109 -0
  231. package/dist/events/core-events.js.map +1 -0
  232. package/dist/events/index.d.ts +15 -0
  233. package/dist/events/index.d.ts.map +1 -0
  234. package/dist/events/index.js +58 -0
  235. package/dist/events/index.js.map +1 -0
  236. package/dist/events/publisher.d.ts +46 -0
  237. package/dist/events/publisher.d.ts.map +1 -0
  238. package/dist/events/publisher.js +54 -0
  239. package/dist/events/publisher.js.map +1 -0
  240. package/dist/events/registry.d.ts +87 -0
  241. package/dist/events/registry.d.ts.map +1 -0
  242. package/dist/events/registry.js +34 -0
  243. package/dist/events/registry.js.map +1 -0
  244. package/dist/events/service.d.ts +78 -0
  245. package/dist/events/service.d.ts.map +1 -0
  246. package/dist/events/service.js +182 -0
  247. package/dist/events/service.js.map +1 -0
  248. package/dist/features/bucket.d.ts +22 -0
  249. package/dist/features/bucket.d.ts.map +1 -0
  250. package/dist/features/bucket.js +42 -0
  251. package/dist/features/bucket.js.map +1 -0
  252. package/dist/features/index.d.ts +15 -0
  253. package/dist/features/index.d.ts.map +1 -0
  254. package/dist/features/index.js +78 -0
  255. package/dist/features/index.js.map +1 -0
  256. package/dist/features/registry.d.ts +51 -0
  257. package/dist/features/registry.d.ts.map +1 -0
  258. package/dist/features/registry.js +52 -0
  259. package/dist/features/registry.js.map +1 -0
  260. package/dist/features/service.d.ts +78 -0
  261. package/dist/features/service.d.ts.map +1 -0
  262. package/dist/features/service.js +207 -0
  263. package/dist/features/service.js.map +1 -0
  264. package/dist/files/index.d.ts +6 -0
  265. package/dist/files/index.d.ts.map +1 -0
  266. package/dist/files/index.js +64 -0
  267. package/dist/files/index.js.map +1 -0
  268. package/dist/files/service.d.ts +92 -0
  269. package/dist/files/service.d.ts.map +1 -0
  270. package/dist/files/service.js +303 -0
  271. package/dist/files/service.js.map +1 -0
  272. package/dist/index.d.ts +33 -0
  273. package/dist/index.d.ts.map +1 -0
  274. package/dist/index.js +33 -0
  275. package/dist/index.js.map +1 -0
  276. package/dist/jobs/backend.d.ts +23 -0
  277. package/dist/jobs/backend.d.ts.map +1 -0
  278. package/dist/jobs/backend.js +23 -0
  279. package/dist/jobs/backend.js.map +1 -0
  280. package/dist/jobs/index.d.ts +29 -0
  281. package/dist/jobs/index.d.ts.map +1 -0
  282. package/dist/jobs/index.js +114 -0
  283. package/dist/jobs/index.js.map +1 -0
  284. package/dist/jobs/service.d.ts +67 -0
  285. package/dist/jobs/service.d.ts.map +1 -0
  286. package/dist/jobs/service.js +139 -0
  287. package/dist/jobs/service.js.map +1 -0
  288. package/dist/jobs/types.d.ts +78 -0
  289. package/dist/jobs/types.d.ts.map +1 -0
  290. package/dist/jobs/types.js +4 -0
  291. package/dist/jobs/types.js.map +1 -0
  292. package/dist/logger/default.d.ts +7 -0
  293. package/dist/logger/default.d.ts.map +1 -0
  294. package/dist/logger/default.js +28 -0
  295. package/dist/logger/default.js.map +1 -0
  296. package/dist/logger/index.d.ts +24 -0
  297. package/dist/logger/index.d.ts.map +1 -0
  298. package/dist/logger/index.js +90 -0
  299. package/dist/logger/index.js.map +1 -0
  300. package/dist/logger/redact.d.ts +40 -0
  301. package/dist/logger/redact.d.ts.map +1 -0
  302. package/dist/logger/redact.js +178 -0
  303. package/dist/logger/redact.js.map +1 -0
  304. package/dist/logger/service.d.ts +14 -0
  305. package/dist/logger/service.d.ts.map +1 -0
  306. package/dist/logger/service.js +56 -0
  307. package/dist/logger/service.js.map +1 -0
  308. package/dist/logger/sinks.d.ts +37 -0
  309. package/dist/logger/sinks.d.ts.map +1 -0
  310. package/dist/logger/sinks.js +135 -0
  311. package/dist/logger/sinks.js.map +1 -0
  312. package/dist/logger/types.d.ts +47 -0
  313. package/dist/logger/types.d.ts.map +1 -0
  314. package/dist/logger/types.js +8 -0
  315. package/dist/logger/types.js.map +1 -0
  316. package/dist/notifications/index.d.ts +8 -0
  317. package/dist/notifications/index.d.ts.map +1 -0
  318. package/dist/notifications/index.js +72 -0
  319. package/dist/notifications/index.js.map +1 -0
  320. package/dist/notifications/service.d.ts +79 -0
  321. package/dist/notifications/service.d.ts.map +1 -0
  322. package/dist/notifications/service.js +164 -0
  323. package/dist/notifications/service.js.map +1 -0
  324. package/dist/realtime/channels.d.ts +37 -0
  325. package/dist/realtime/channels.d.ts.map +1 -0
  326. package/dist/realtime/channels.js +58 -0
  327. package/dist/realtime/channels.js.map +1 -0
  328. package/dist/realtime/index.d.ts +19 -0
  329. package/dist/realtime/index.d.ts.map +1 -0
  330. package/dist/realtime/index.js +118 -0
  331. package/dist/realtime/index.js.map +1 -0
  332. package/dist/realtime/postgres.d.ts +48 -0
  333. package/dist/realtime/postgres.d.ts.map +1 -0
  334. package/dist/realtime/postgres.js +151 -0
  335. package/dist/realtime/postgres.js.map +1 -0
  336. package/dist/realtime/service.d.ts +75 -0
  337. package/dist/realtime/service.d.ts.map +1 -0
  338. package/dist/realtime/service.js +103 -0
  339. package/dist/realtime/service.js.map +1 -0
  340. package/dist/realtime/sse.d.ts +55 -0
  341. package/dist/realtime/sse.d.ts.map +1 -0
  342. package/dist/realtime/sse.js +123 -0
  343. package/dist/realtime/sse.js.map +1 -0
  344. package/dist/realtime/transport.d.ts +52 -0
  345. package/dist/realtime/transport.d.ts.map +1 -0
  346. package/dist/realtime/transport.js +2 -0
  347. package/dist/realtime/transport.js.map +1 -0
  348. package/dist/storage/index.d.ts +18 -0
  349. package/dist/storage/index.d.ts.map +1 -0
  350. package/dist/storage/index.js +89 -0
  351. package/dist/storage/index.js.map +1 -0
  352. package/dist/storage/keys.d.ts +50 -0
  353. package/dist/storage/keys.d.ts.map +1 -0
  354. package/dist/storage/keys.js +120 -0
  355. package/dist/storage/keys.js.map +1 -0
  356. package/dist/storage/memory.d.ts +32 -0
  357. package/dist/storage/memory.d.ts.map +1 -0
  358. package/dist/storage/memory.js +84 -0
  359. package/dist/storage/memory.js.map +1 -0
  360. package/dist/storage/provider.d.ts +93 -0
  361. package/dist/storage/provider.d.ts.map +1 -0
  362. package/dist/storage/provider.js +2 -0
  363. package/dist/storage/provider.js.map +1 -0
  364. package/dist/storage/s3.d.ts +34 -0
  365. package/dist/storage/s3.d.ts.map +1 -0
  366. package/dist/storage/s3.js +175 -0
  367. package/dist/storage/s3.js.map +1 -0
  368. package/dist/storage/service.d.ts +86 -0
  369. package/dist/storage/service.d.ts.map +1 -0
  370. package/dist/storage/service.js +107 -0
  371. package/dist/storage/service.js.map +1 -0
  372. package/dist/storage/sigv4.d.ts +58 -0
  373. package/dist/storage/sigv4.d.ts.map +1 -0
  374. package/dist/storage/sigv4.js +114 -0
  375. package/dist/storage/sigv4.js.map +1 -0
  376. package/dist/streams/client.d.ts +91 -0
  377. package/dist/streams/client.d.ts.map +1 -0
  378. package/dist/streams/client.js +128 -0
  379. package/dist/streams/client.js.map +1 -0
  380. package/dist/streams/events.d.ts +68 -0
  381. package/dist/streams/events.d.ts.map +1 -0
  382. package/dist/streams/events.js +81 -0
  383. package/dist/streams/events.js.map +1 -0
  384. package/dist/streams/index.d.ts +47 -0
  385. package/dist/streams/index.d.ts.map +1 -0
  386. package/dist/streams/index.js +47 -0
  387. package/dist/streams/index.js.map +1 -0
  388. package/dist/streams/realtime.d.ts +27 -0
  389. package/dist/streams/realtime.d.ts.map +1 -0
  390. package/dist/streams/realtime.js +50 -0
  391. package/dist/streams/realtime.js.map +1 -0
  392. package/dist/streams/state.d.ts +26 -0
  393. package/dist/streams/state.d.ts.map +1 -0
  394. package/dist/streams/state.js +34 -0
  395. package/dist/streams/state.js.map +1 -0
  396. package/dist/users/index.d.ts +9 -0
  397. package/dist/users/index.d.ts.map +1 -0
  398. package/dist/users/index.js +23 -0
  399. package/dist/users/index.js.map +1 -0
  400. package/dist/users/service.d.ts +43 -0
  401. package/dist/users/service.d.ts.map +1 -0
  402. package/dist/users/service.js +113 -0
  403. package/dist/users/service.js.map +1 -0
  404. package/dist/webhooks/inbound.d.ts +70 -0
  405. package/dist/webhooks/inbound.d.ts.map +1 -0
  406. package/dist/webhooks/inbound.js +146 -0
  407. package/dist/webhooks/inbound.js.map +1 -0
  408. package/dist/webhooks/index.d.ts +12 -0
  409. package/dist/webhooks/index.d.ts.map +1 -0
  410. package/dist/webhooks/index.js +65 -0
  411. package/dist/webhooks/index.js.map +1 -0
  412. package/dist/webhooks/outgoing.d.ts +89 -0
  413. package/dist/webhooks/outgoing.d.ts.map +1 -0
  414. package/dist/webhooks/outgoing.js +375 -0
  415. package/dist/webhooks/outgoing.js.map +1 -0
  416. package/dist/webhooks/signature.d.ts +40 -0
  417. package/dist/webhooks/signature.d.ts.map +1 -0
  418. package/dist/webhooks/signature.js +77 -0
  419. package/dist/webhooks/signature.js.map +1 -0
  420. package/dist/workspaces/context.d.ts +30 -0
  421. package/dist/workspaces/context.d.ts.map +1 -0
  422. package/dist/workspaces/context.js +12 -0
  423. package/dist/workspaces/context.js.map +1 -0
  424. package/dist/workspaces/index.d.ts +5 -0
  425. package/dist/workspaces/index.d.ts.map +1 -0
  426. package/dist/workspaces/index.js +21 -0
  427. package/dist/workspaces/index.js.map +1 -0
  428. package/dist/workspaces/service.d.ts +126 -0
  429. package/dist/workspaces/service.d.ts.map +1 -0
  430. package/dist/workspaces/service.js +495 -0
  431. package/dist/workspaces/service.js.map +1 -0
  432. package/docs/README.md +71 -0
  433. package/docs/api-keys.md +184 -0
  434. package/docs/audit.md +198 -0
  435. package/docs/auth.md +196 -0
  436. package/docs/authorization.md +225 -0
  437. package/docs/billing.md +293 -0
  438. package/docs/cli.md +238 -0
  439. package/docs/config.md +163 -0
  440. package/docs/db.md +219 -0
  441. package/docs/email.md +222 -0
  442. package/docs/entitlements.md +194 -0
  443. package/docs/errors.md +158 -0
  444. package/docs/events.md +279 -0
  445. package/docs/feature-flags.md +237 -0
  446. package/docs/files.md +229 -0
  447. package/docs/jobs.md +288 -0
  448. package/docs/logger.md +269 -0
  449. package/docs/notifications.md +179 -0
  450. package/docs/publishing.md +128 -0
  451. package/docs/realtime.md +360 -0
  452. package/docs/storage.md +279 -0
  453. package/docs/streams.md +296 -0
  454. package/docs/users.md +117 -0
  455. package/docs/webhooks.md +272 -0
  456. package/docs/workspaces.md +269 -0
  457. package/drizzle/0000_init_users.sql +21 -0
  458. package/drizzle/0001_workspaces_roles_permissions.sql +86 -0
  459. package/drizzle/0002_billing_entitlements.sql +97 -0
  460. package/drizzle/0003_events.sql +17 -0
  461. package/drizzle/0004_notifications_audit.sql +64 -0
  462. package/drizzle/0005_api_keys_webhooks.sql +77 -0
  463. package/drizzle/0006_feature_flags.sql +22 -0
  464. package/drizzle/0007_files.sql +23 -0
  465. package/drizzle/meta/0000_snapshot.json +160 -0
  466. package/drizzle/meta/0001_snapshot.json +837 -0
  467. package/drizzle/meta/0002_snapshot.json +1580 -0
  468. package/drizzle/meta/0003_snapshot.json +1751 -0
  469. package/drizzle/meta/0004_snapshot.json +2109 -0
  470. package/drizzle/meta/0005_snapshot.json +2719 -0
  471. package/drizzle/meta/0006_snapshot.json +2909 -0
  472. package/drizzle/meta/0007_snapshot.json +3113 -0
  473. package/drizzle/meta/_journal.json +62 -0
  474. package/package.json +180 -0
package/CLAUDE.md ADDED
@@ -0,0 +1,1165 @@
1
+ # @digimuza/saas-core
2
+
3
+ ## Purpose
4
+
5
+ @digimuza/saas-core is a reusable SaaS foundation for building multiple SaaS applications.
6
+
7
+ The goal is to eliminate repeatedly rebuilding SaaS infrastructure while keeping product-specific business logic outside the core.
8
+
9
+ The package must provide a simple, strongly typed foundation for:
10
+
11
+ - Authentication
12
+ - Users and profiles
13
+ - Workspaces / multi-tenancy
14
+ - Workspace memberships
15
+ - Customizable roles
16
+ - Multiple roles per user
17
+ - Permissions
18
+ - Environment configuration
19
+ - Runtime configuration
20
+ - Billing
21
+ - Entitlements
22
+ - Background jobs
23
+ - Durable workflows
24
+ - Application events
25
+ - Realtime communication
26
+ - RxJS-based reactive behaviors
27
+ - Email
28
+ - Notifications
29
+ - Audit logs
30
+ - API keys
31
+ - Webhooks
32
+ - Feature flags
33
+ - Storage
34
+
35
+ The primary design principle is:
36
+
37
+ "Use the simplest infrastructure that reliably solves the problem."
38
+
39
+ ---
40
+
41
+ # Technology
42
+
43
+ Use:
44
+
45
+ - TypeScript
46
+ - Next.js
47
+ - PostgreSQL
48
+ - Drizzle ORM
49
+ - Zod
50
+ - RxJS
51
+ - Vitest
52
+ - Playwright when UI testing is required
53
+
54
+ External services:
55
+
56
+ - WorkOS -> authentication and identity
57
+ - Infisical -> environment configuration and secrets
58
+ - Revolut -> billing/payments
59
+ - Trigger.dev -> durable background execution
60
+ - Open-source realtime infrastructure -> realtime transport when required
61
+
62
+ Do not introduce additional infrastructure without a concrete requirement.
63
+
64
+ ---
65
+
66
+ # Core Philosophy
67
+
68
+ ## Simplicity
69
+
70
+ Prefer:
71
+
72
+ PostgreSQL over Redis when PostgreSQL is sufficient.
73
+
74
+ Next.js over a separate backend when Next.js is sufficient.
75
+
76
+ Managed infrastructure over infrastructure that must be manually operated.
77
+
78
+ Explicit APIs over magic.
79
+
80
+ Small abstractions over generic frameworks.
81
+
82
+ Do not introduce microservices.
83
+
84
+ Do not build custom infrastructure when a mature service already solves the problem.
85
+
86
+ Do not optimize for hypothetical scale.
87
+
88
+ Optimize for:
89
+
90
+ - simplicity
91
+ - maintainability
92
+ - security
93
+ - developer experience
94
+ - reliability
95
+
96
+ ---
97
+
98
+ # Package
99
+
100
+ Everything belongs to ONE npm package:
101
+
102
+ @digimuza/saas-core
103
+
104
+ Use subpath exports:
105
+
106
+ @digimuza/saas-core/auth
107
+ @digimuza/saas-core/db
108
+ @digimuza/saas-core/users
109
+ @digimuza/saas-core/workspaces
110
+ @digimuza/saas-core/authorization
111
+ @digimuza/saas-core/config
112
+ @digimuza/saas-core/billing
113
+ @digimuza/saas-core/entitlements
114
+ @digimuza/saas-core/jobs
115
+ @digimuza/saas-core/events
116
+ @digimuza/saas-core/realtime
117
+ @digimuza/saas-core/email
118
+ @digimuza/saas-core/notifications
119
+ @digimuza/saas-core/audit
120
+ @digimuza/saas-core/api-keys
121
+ @digimuza/saas-core/webhooks
122
+ @digimuza/saas-core/feature-flags
123
+ @digimuza/saas-core/storage
124
+
125
+ Do NOT create separate npm packages.
126
+
127
+ ---
128
+
129
+ # Database
130
+
131
+ Use PostgreSQL + Drizzle ORM.
132
+
133
+ Do NOT use Prisma.
134
+
135
+ Database schema definitions are part of the public package.
136
+
137
+ Export them from:
138
+
139
+ @digimuza/saas-core/db/schema
140
+
141
+ Applications must be able to import core tables and reference them from product-specific tables.
142
+
143
+ Example:
144
+
145
+ import { workspaces } from "@digimuza/saas-core/db/schema";
146
+
147
+ export const projects = pgTable("projects", {
148
+ id: uuid("id").defaultRandom().primaryKey(),
149
+
150
+ workspaceId: uuid("workspace_id")
151
+ .notNull()
152
+ .references(() => workspaces.id),
153
+
154
+ name: text("name").notNull(),
155
+ });
156
+
157
+ The core owns platform tables.
158
+
159
+ Individual SaaS applications own product-specific tables.
160
+
161
+ ---
162
+
163
+ # Database Ownership
164
+
165
+ Core-owned tables include:
166
+
167
+ users
168
+ user_profiles
169
+ workspaces
170
+ workspace_members
171
+ roles
172
+ permissions
173
+ workspace_member_roles
174
+ role_permissions
175
+ plans
176
+ billing_customers
177
+ subscriptions
178
+ billing_events
179
+ entitlements
180
+ audit_logs
181
+ notifications
182
+ api_keys
183
+ webhooks
184
+ feature_flags
185
+ events
186
+ usage_records where appropriate
187
+
188
+ Product applications own:
189
+
190
+ projects
191
+ documents
192
+ messages
193
+ AI-specific entities
194
+ product-specific configuration
195
+ product-specific business logic
196
+
197
+ Never put product-specific domain models into the core unless they clearly apply to multiple SaaS products.
198
+
199
+ ---
200
+
201
+ # Users
202
+
203
+ Separate authentication identity from user profile.
204
+
205
+ users:
206
+
207
+ - id
208
+ - workos_user_id
209
+ - created_at
210
+ - updated_at
211
+
212
+ user_profiles:
213
+
214
+ - user_id
215
+ - email
216
+ - first_name
217
+ - last_name
218
+ - display_name
219
+ - avatar_url
220
+ - created_at
221
+ - updated_at
222
+
223
+ Email belongs to user_profiles.
224
+
225
+ Do not duplicate email in users.
226
+
227
+ Do not store passwords.
228
+
229
+ ---
230
+
231
+ # Authentication
232
+
233
+ Use WorkOS.
234
+
235
+ Do not implement OAuth, SAML or OIDC manually.
236
+
237
+ Application code should use:
238
+
239
+ auth.getCurrentUser()
240
+ auth.requireUser()
241
+ auth.getSession()
242
+ auth.signOut()
243
+
244
+ Do not expose WorkOS implementation details throughout application code.
245
+
246
+ Support WorkOS capabilities where applicable:
247
+
248
+ - Google/social login
249
+ - Email authentication
250
+ - Passkeys
251
+ - MFA
252
+ - SAML
253
+ - OIDC
254
+ - Account linking
255
+ - Sessions
256
+
257
+ ---
258
+
259
+ # Workspaces
260
+
261
+ Users can belong to multiple workspaces.
262
+
263
+ Never put workspace_id on users.
264
+
265
+ Use:
266
+
267
+ users
268
+ -> workspace_members
269
+ -> workspaces
270
+
271
+ A workspace membership represents the user's relationship with a workspace.
272
+
273
+ Expose:
274
+
275
+ workspaces.create()
276
+ workspaces.get()
277
+ workspaces.update()
278
+ workspaces.delete()
279
+ workspaces.getCurrent()
280
+ workspaces.members.list()
281
+ workspaces.members.invite()
282
+ workspaces.members.remove()
283
+
284
+ All tenant-sensitive operations must verify workspace membership.
285
+
286
+ Never trust workspace_id supplied by a client.
287
+
288
+ ---
289
+
290
+ # Roles
291
+
292
+ Roles are workspace-scoped.
293
+
294
+ roles:
295
+
296
+ - id
297
+ - workspace_id
298
+ - name
299
+ - description
300
+ - created_at
301
+ - updated_at
302
+
303
+ Users may have multiple roles.
304
+
305
+ workspace_member_roles:
306
+
307
+ - workspace_id
308
+ - user_id
309
+ - role_id
310
+
311
+ PostgreSQL constraints must prevent cross-workspace role assignments.
312
+
313
+ Support:
314
+
315
+ - system roles
316
+ - default roles
317
+ - custom roles
318
+
319
+ Do not hard-code role names into authorization logic.
320
+
321
+ ---
322
+
323
+ # Permissions
324
+
325
+ Permissions are application-defined.
326
+
327
+ Examples:
328
+
329
+ workspace.read
330
+ workspace.update
331
+ members.read
332
+ members.invite
333
+ members.remove
334
+ projects.read
335
+ projects.create
336
+ projects.update
337
+ projects.delete
338
+ billing.read
339
+ billing.update
340
+
341
+ Roles receive permissions through:
342
+
343
+ role_permissions
344
+
345
+ Effective permissions are the UNION of permissions from all roles assigned to the user within the workspace.
346
+
347
+ Expose:
348
+
349
+ authorization.can()
350
+ authorization.require()
351
+ authorization.hasRole()
352
+
353
+ Authorization always requires workspace context.
354
+
355
+ ---
356
+
357
+ # Configuration
358
+
359
+ Do NOT use .env files as the project's configuration management strategy.
360
+
361
+ Use Infisical.
362
+
363
+ Infisical is responsible for injecting secrets and environment configuration into the application runtime.
364
+
365
+ The core must not depend directly on the Infisical API during normal application execution.
366
+
367
+ Only the configuration module may access process.env.
368
+
369
+ Application code must never access process.env directly.
370
+
371
+ Provide typed configuration:
372
+
373
+ config.app
374
+ config.database
375
+ config.auth
376
+ config.billing
377
+ config.email
378
+ config.storage
379
+ config.realtime
380
+ config.jobs
381
+
382
+ Configuration must:
383
+
384
+ - be strongly typed
385
+ - be validated with Zod
386
+ - fail fast
387
+ - separate server and client configuration
388
+ - prevent server secrets from entering client bundles
389
+
390
+ Infrastructure secrets must never be stored in PostgreSQL.
391
+
392
+ Runtime application configuration may be stored in PostgreSQL.
393
+
394
+ Examples:
395
+
396
+ - workspace timezone
397
+ - locale
398
+ - branding
399
+ - workspace settings
400
+ - product configuration
401
+
402
+ ---
403
+
404
+ # Billing
405
+
406
+ Use Revolut initially.
407
+
408
+ Do not expose Revolut-specific APIs throughout the application.
409
+
410
+ Expose:
411
+
412
+ billing.getCustomer()
413
+ billing.createCheckout()
414
+ billing.getSubscription()
415
+ billing.cancelSubscription()
416
+ billing.getPortal()
417
+
418
+ Database entities:
419
+
420
+ plans
421
+ billing_customers
422
+ subscriptions
423
+ billing_events
424
+
425
+ Billing state is updated from verified webhook events.
426
+
427
+ Keep the billing abstraction provider-independent enough to support another provider later.
428
+
429
+ Do not implement payment processing.
430
+
431
+ ---
432
+
433
+ # Entitlements
434
+
435
+ Billing and authorization are separate.
436
+
437
+ Model:
438
+
439
+ Subscription
440
+ -> Plan
441
+ -> Entitlements
442
+ -> Features and limits
443
+
444
+ Examples:
445
+
446
+ advanced_analytics
447
+ ai_generation
448
+ api_access
449
+ custom_domains
450
+
451
+ Limits:
452
+
453
+ ai_generations
454
+ team_members
455
+ storage_bytes
456
+ api_requests
457
+
458
+ Expose:
459
+
460
+ entitlements.has()
461
+ entitlements.require()
462
+ entitlements.getLimit()
463
+ entitlements.checkLimit()
464
+
465
+ Product code must not inspect subscription plan names directly.
466
+
467
+ Use entitlements.
468
+
469
+ ---
470
+
471
+ # Background Jobs
472
+
473
+ Use Trigger.dev for durable execution.
474
+
475
+ Do not implement a custom durable execution engine.
476
+
477
+ Use Trigger.dev for:
478
+
479
+ - long-running jobs
480
+ - retries
481
+ - scheduling
482
+ - cron
483
+ - durable workflows
484
+ - multi-step workflows
485
+ - waits
486
+ - concurrency
487
+ - task observability
488
+
489
+ Expose a thin integration:
490
+
491
+ jobs.trigger()
492
+
493
+ Do not unnecessarily hide Trigger.dev functionality.
494
+
495
+ The core should allow advanced applications to access Trigger.dev capabilities when required.
496
+
497
+ Do not introduce Redis solely for background jobs.
498
+
499
+ ---
500
+
501
+ # Events
502
+
503
+ Create a unified application event model.
504
+
505
+ An event represents something that happened in the application.
506
+
507
+ Example:
508
+
509
+ events.publish({
510
+ type: "project.created",
511
+ workspaceId,
512
+ actorId,
513
+ data: {
514
+ projectId
515
+ }
516
+ })
517
+
518
+ Events must contain:
519
+
520
+ - id
521
+ - type
522
+ - timestamp
523
+ - workspace context when applicable
524
+ - actor context when applicable
525
+ - typed payload
526
+
527
+ Events may feed:
528
+
529
+ - realtime
530
+ - RxJS streams
531
+ - notifications
532
+ - audit logs
533
+ - webhooks
534
+ - Trigger.dev tasks
535
+
536
+ Events should be strongly typed.
537
+
538
+ Avoid a generic "anything JSON" event API when a typed event registry can be used.
539
+
540
+ ---
541
+
542
+ # Realtime
543
+
544
+ Realtime is responsible for delivering events to connected clients.
545
+
546
+ It is NOT the durable source of truth.
547
+
548
+ The architecture is:
549
+
550
+ PostgreSQL
551
+ -> Application events
552
+ -> Realtime transport
553
+ -> Browser
554
+
555
+ The realtime layer must support:
556
+
557
+ - channels
558
+ - workspace-scoped channels
559
+ - user-scoped channels
560
+ - authentication
561
+ - authorization
562
+ - reconnect
563
+ - event delivery
564
+
565
+ Clients must never be able to subscribe to unauthorized workspace channels.
566
+
567
+ Do not expose PostgreSQL LISTEN/NOTIFY directly to browsers.
568
+
569
+ PostgreSQL may be used internally as part of the event pipeline.
570
+
571
+ The realtime implementation should be replaceable.
572
+
573
+ ---
574
+
575
+ # RxJS Reactive Behavior Layer
576
+
577
+ RxJS is a first-class dependency.
578
+
579
+ RxJS is used for application-level reactive behavior.
580
+
581
+ It is NOT the database.
582
+
583
+ It is NOT the durable job system.
584
+
585
+ It is NOT the realtime transport.
586
+
587
+ Its responsibility is to:
588
+
589
+ - consume realtime events
590
+ - combine event streams
591
+ - filter events
592
+ - transform events
593
+ - debounce events
594
+ - throttle events
595
+ - aggregate events
596
+ - maintain reactive state
597
+ - coordinate reactive behavior
598
+
599
+ The conceptual architecture is:
600
+
601
+ Event sources
602
+ -> Realtime / application events
603
+ -> RxJS Observable
604
+ -> Reactor
605
+ -> Application / client
606
+
607
+ Expose a typed stream API.
608
+
609
+ Example:
610
+
611
+ const events$ = events.stream({
612
+ workspaceId
613
+ });
614
+
615
+ events$ returns:
616
+
617
+ Observable<SaaSEvent>
618
+
619
+ Example:
620
+
621
+ const projectUpdates$ = events$
622
+ .pipe(
623
+ filter(event => event.type === "project.updated"),
624
+ map(event => event.data),
625
+ distinctUntilChanged()
626
+ );
627
+
628
+ ---
629
+
630
+ # RxJS Rules
631
+
632
+ Do not expose RxJS unnecessarily.
633
+
634
+ Use Observable where streaming/reactive behavior provides clear value.
635
+
636
+ Do not convert every synchronous API into an Observable.
637
+
638
+ Prefer:
639
+
640
+ Promise -> one-time asynchronous operation.
641
+
642
+ Observable -> stream of values/events.
643
+
644
+ Do not use RxJS for database access merely because RxJS exists.
645
+
646
+ Do not use RxJS as a replacement for Trigger.dev.
647
+
648
+ Do not use RxJS as a replacement for PostgreSQL persistence.
649
+
650
+ Do not create infinite subscriptions without lifecycle management.
651
+
652
+ Every subscription must have a clear lifecycle.
653
+
654
+ Prefer operators such as:
655
+
656
+ - map
657
+ - filter
658
+ - merge
659
+ - switchMap
660
+ - concatMap
661
+ - exhaustMap
662
+ - debounceTime
663
+ - throttleTime
664
+ - distinctUntilChanged
665
+ - scan
666
+ - share
667
+ - shareReplay
668
+ - takeUntil
669
+
670
+ Use operators intentionally.
671
+
672
+ Avoid deeply nested RxJS pipelines that become difficult to understand.
673
+
674
+ ---
675
+
676
+ # Realtime + RxJS
677
+
678
+ Realtime transport should feed RxJS.
679
+
680
+ Example:
681
+
682
+ realtime.subscribe(...)
683
+ -> Observable<SaaSEvent>
684
+ -> RxJS operators
685
+ -> Application behavior
686
+
687
+ Do not make every UI component independently implement WebSocket behavior.
688
+
689
+ Prefer a shared event abstraction.
690
+
691
+ Example:
692
+
693
+ const workspaceEvents$ =
694
+ realtime.events.workspace(workspaceId);
695
+
696
+ Then:
697
+
698
+ workspaceEvents$
699
+ .pipe(
700
+ filter(event => event.type === "notification.created")
701
+ )
702
+ .subscribe(...)
703
+
704
+ The transport should be replaceable without changing the RxJS application API.
705
+
706
+ ---
707
+
708
+ # Trigger.dev + RxJS
709
+
710
+ Trigger.dev owns durable execution.
711
+
712
+ RxJS owns reactive observation and behavior.
713
+
714
+ Example:
715
+
716
+ Trigger.dev task
717
+ -> job progress event
718
+ -> application event
719
+ -> realtime
720
+ -> RxJS Observable
721
+ -> browser UI
722
+
723
+ Do not attempt to make RxJS durable.
724
+
725
+ Do not keep state only in an Observable.
726
+
727
+ If state must survive process restart, persist it in PostgreSQL.
728
+
729
+ ---
730
+
731
+ # Realtime Event Examples
732
+
733
+ Support patterns such as:
734
+
735
+ job.started
736
+ job.progress
737
+ job.completed
738
+ job.failed
739
+
740
+ project.created
741
+ project.updated
742
+ project.deleted
743
+
744
+ notification.created
745
+
746
+ workspace.member.created
747
+ workspace.member.removed
748
+ workspace.member.role.updated
749
+
750
+ billing.subscription.updated
751
+
752
+ The event registry should provide compile-time type safety.
753
+
754
+ ---
755
+
756
+ # Email
757
+
758
+ Provide:
759
+
760
+ email.send()
761
+ email.sendTemplate()
762
+
763
+ Keep provider-specific implementation behind an adapter.
764
+
765
+ Templates may include:
766
+
767
+ - welcome
768
+ - invitation
769
+ - security
770
+ - billing
771
+ - notifications
772
+
773
+ ---
774
+
775
+ # Notifications
776
+
777
+ Provide:
778
+
779
+ notifications.create()
780
+ notifications.list()
781
+ notifications.markRead()
782
+
783
+ Support:
784
+
785
+ - in-app notifications
786
+ - email notifications
787
+
788
+ Notifications may consume application events.
789
+
790
+ ---
791
+
792
+ # Audit
793
+
794
+ Audit logs are durable and immutable.
795
+
796
+ Example:
797
+
798
+ audit.log({
799
+ action: "member.role.updated",
800
+ actorId,
801
+ workspaceId,
802
+ targetId,
803
+ metadata
804
+ })
805
+
806
+ Audit records include:
807
+
808
+ - actor
809
+ - workspace
810
+ - action
811
+ - target
812
+ - metadata
813
+ - timestamp
814
+ - request ID where available
815
+
816
+ Audit data must not be dependent on realtime delivery.
817
+
818
+ If an audit event is important, it must be persisted.
819
+
820
+ ---
821
+
822
+ # API Keys
823
+
824
+ Workspace-scoped API keys.
825
+
826
+ Requirements:
827
+
828
+ - secure random generation
829
+ - hash secrets
830
+ - reveal secret only once
831
+ - revoke
832
+ - expiration
833
+ - scopes
834
+ - last-used timestamp
835
+
836
+ Expose:
837
+
838
+ apiKeys.create()
839
+ apiKeys.revoke()
840
+ apiKeys.validate()
841
+
842
+ API key validation must resolve the workspace securely.
843
+
844
+ ---
845
+
846
+ # Webhooks
847
+
848
+ Support:
849
+
850
+ - incoming webhooks
851
+ - outgoing webhooks
852
+
853
+ Outgoing webhook infrastructure should support:
854
+
855
+ - endpoints
856
+ - secrets
857
+ - event subscriptions
858
+ - delivery records
859
+ - retries
860
+ - failures
861
+
862
+ Incoming webhooks must support:
863
+
864
+ - signature verification
865
+ - idempotency
866
+ - event IDs
867
+ - processing status
868
+
869
+ ---
870
+
871
+ # Feature Flags
872
+
873
+ Provide simple feature flags.
874
+
875
+ Scopes:
876
+
877
+ - global
878
+ - application
879
+ - workspace
880
+ - user
881
+
882
+ Expose:
883
+
884
+ features.isEnabled()
885
+ features.getVariant()
886
+
887
+ Do not implement a complete feature management platform.
888
+
889
+ ---
890
+
891
+ # Storage
892
+
893
+ Provide:
894
+
895
+ storage.upload()
896
+ storage.delete()
897
+ storage.getUrl()
898
+
899
+ Use adapters.
900
+
901
+ Do not couple product code to a specific storage provider.
902
+
903
+ ---
904
+
905
+ # Security
906
+
907
+ Security is a first-class requirement.
908
+
909
+ Always enforce:
910
+
911
+ - tenant isolation
912
+ - authorization
913
+ - input validation
914
+ - API key security
915
+ - webhook signatures
916
+ - secret isolation
917
+ - session security
918
+ - realtime channel authorization
919
+ - idempotency
920
+ - auditability
921
+
922
+ Never trust client-provided:
923
+
924
+ userId
925
+ workspaceId
926
+ roleId
927
+ permission information
928
+
929
+ Resolve identity from authenticated context.
930
+
931
+ ---
932
+
933
+ # Next.js
934
+
935
+ First-class Next.js support.
936
+
937
+ Support:
938
+
939
+ - App Router
940
+ - Server Components
941
+ - Server Actions
942
+ - Route Handlers
943
+ - Middleware where appropriate
944
+
945
+ Server-only modules must not be imported into client components.
946
+
947
+ Never expose server secrets to the client.
948
+
949
+ Prefer server-side operations.
950
+
951
+ ---
952
+
953
+ # Testing
954
+
955
+ Use Vitest for unit and integration tests.
956
+
957
+ Use Playwright for end-to-end browser tests.
958
+
959
+ Test:
960
+
961
+ - workspace isolation
962
+ - role assignment
963
+ - multiple roles
964
+ - permission resolution
965
+ - authorization
966
+ - billing webhook idempotency
967
+ - API key validation
968
+ - realtime authorization
969
+ - event typing
970
+ - RxJS stream behavior
971
+ - RxJS subscription cleanup
972
+ - reconnect behavior
973
+ - Trigger.dev integration
974
+ - entitlement checks
975
+
976
+ Realtime tests must verify that users cannot receive events from unauthorized workspaces.
977
+
978
+ RxJS tests should verify:
979
+
980
+ - filtering
981
+ - transformation
982
+ - aggregation
983
+ - debouncing/throttling
984
+ - completion
985
+ - error behavior
986
+ - subscription cleanup
987
+
988
+ ---
989
+
990
+ # Database Migration
991
+
992
+ Use Drizzle migrations.
993
+
994
+ Core schema definitions are exported publicly.
995
+
996
+ Product applications may reference core tables.
997
+
998
+ Core migrations must be versioned.
999
+
1000
+ Never modify production schemas manually.
1001
+
1002
+ Destructive changes require a migration strategy.
1003
+
1004
+ ---
1005
+
1006
+ # Dependency Rules
1007
+
1008
+ Do not add a dependency unless:
1009
+
1010
+ 1. It solves a real problem.
1011
+ 2. The problem cannot be solved simply with existing infrastructure.
1012
+ 3. The dependency is actively maintained.
1013
+ 4. The operational complexity is justified.
1014
+
1015
+ Current infrastructure:
1016
+
1017
+ PostgreSQL -> durable state
1018
+
1019
+ Drizzle -> database access/schema
1020
+
1021
+ WorkOS -> authentication
1022
+
1023
+ Infisical -> secrets/configuration
1024
+
1025
+ Revolut -> payments
1026
+
1027
+ Trigger.dev -> durable execution
1028
+
1029
+ RxJS -> reactive behavior
1030
+
1031
+ Realtime transport -> event delivery
1032
+
1033
+ Next.js -> application runtime
1034
+
1035
+ Do not add Redis by default.
1036
+
1037
+ ---
1038
+
1039
+ # Implementation Strategy
1040
+
1041
+ Implement incrementally.
1042
+
1043
+ For every feature:
1044
+
1045
+ 1. Define the problem.
1046
+ 2. Determine whether it belongs in the core.
1047
+ 3. Define the public API.
1048
+ 4. Define the database schema.
1049
+ 5. Define security boundaries.
1050
+ 6. Define failure modes.
1051
+ 7. Write tests.
1052
+ 8. Implement the smallest useful solution.
1053
+ 9. Document the API.
1054
+
1055
+ Do not implement future features speculatively.
1056
+
1057
+ ---
1058
+
1059
+ # Recommended Implementation Order
1060
+
1061
+ Phase 1:
1062
+ - Drizzle
1063
+ - PostgreSQL
1064
+ - schema architecture
1065
+ - migrations
1066
+ - configuration
1067
+ - package exports
1068
+
1069
+ Phase 2:
1070
+ - WorkOS
1071
+ - users
1072
+ - profiles
1073
+
1074
+ Phase 3:
1075
+ - workspaces
1076
+ - memberships
1077
+ - invitations
1078
+
1079
+ Phase 4:
1080
+ - roles
1081
+ - permissions
1082
+ - authorization
1083
+
1084
+ Phase 5:
1085
+ - billing
1086
+ - plans
1087
+ - subscriptions
1088
+ - entitlements
1089
+
1090
+ Phase 6:
1091
+ - application events
1092
+ - typed event registry
1093
+
1094
+ Phase 7:
1095
+ - Trigger.dev
1096
+ - durable jobs
1097
+ - scheduled jobs
1098
+
1099
+ Phase 8:
1100
+ - realtime transport
1101
+ - authenticated channels
1102
+
1103
+ Phase 9:
1104
+ - RxJS reactive event streams
1105
+ - client subscriptions
1106
+ - event composition
1107
+
1108
+ Phase 10:
1109
+ - email
1110
+ - notifications
1111
+ - audit logs
1112
+
1113
+ Phase 11:
1114
+ - API keys
1115
+ - webhooks
1116
+
1117
+ Phase 12:
1118
+ - feature flags
1119
+ - storage
1120
+ - observability
1121
+
1122
+ ---
1123
+
1124
+ # Definition of Done
1125
+
1126
+ A feature is not complete until:
1127
+
1128
+ - TypeScript passes
1129
+ - tests pass
1130
+ - database migrations are included
1131
+ - security boundaries are tested
1132
+ - public APIs are documented
1133
+ - server/client boundaries are correct
1134
+ - no unnecessary infrastructure was introduced
1135
+ - the implementation is reusable across multiple SaaS applications
1136
+
1137
+ ---
1138
+
1139
+ # Golden Rule
1140
+
1141
+ @digimuza/saas-core should answer:
1142
+
1143
+ Who is this user?
1144
+
1145
+ What workspace are they in?
1146
+
1147
+ What can they do?
1148
+
1149
+ What are they entitled to?
1150
+
1151
+ What have they paid for?
1152
+
1153
+ What is happening?
1154
+
1155
+ How do we react to what is happening?
1156
+
1157
+ How do we notify the user?
1158
+
1159
+ How do we run long-running work?
1160
+
1161
+ How do we deliver realtime events?
1162
+
1163
+ How do we audit important actions?
1164
+
1165
+ Everything else belongs to the individual SaaS application.