sovrium 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 (527) hide show
  1. package/CHANGELOG.md +3497 -0
  2. package/LICENSE.md +147 -0
  3. package/LICENSE_EE.md +297 -0
  4. package/README.md +321 -0
  5. package/drizzle/0000_melted_kabuki.sql +163 -0
  6. package/drizzle/meta/0000_snapshot.json +1216 -0
  7. package/drizzle/meta/_journal.json +13 -0
  8. package/package.json +167 -0
  9. package/schemas/0.0.1/app.openapi.json +70 -0
  10. package/schemas/0.0.1/app.schema.json +7961 -0
  11. package/schemas/0.0.2/app.openapi.json +80 -0
  12. package/schemas/0.0.2/app.schema.json +8829 -0
  13. package/schemas/development/app.openapi.json +70 -0
  14. package/schemas/development/app.schema.json +7456 -0
  15. package/src/application/errors/app-validation-error.ts +14 -0
  16. package/src/application/errors/static-generation-error.ts +16 -0
  17. package/src/application/metadata/favicon-transformer.ts +127 -0
  18. package/src/application/models/server.ts +27 -0
  19. package/src/application/ports/models/user-metadata.ts +36 -0
  20. package/src/application/ports/models/user-session.ts +34 -0
  21. package/src/application/ports/repositories/activity-log-repository.ts +68 -0
  22. package/src/application/ports/repositories/activity-repository.ts +49 -0
  23. package/src/application/ports/repositories/analytics-repository.ts +164 -0
  24. package/src/application/ports/repositories/auth-repository.ts +33 -0
  25. package/src/application/ports/repositories/batch-repository.ts +86 -0
  26. package/src/application/ports/repositories/comment-repository.ts +150 -0
  27. package/src/application/ports/repositories/index.ts +41 -0
  28. package/src/application/ports/repositories/table-repository.ts +139 -0
  29. package/src/application/ports/services/css-compiler.ts +55 -0
  30. package/src/application/ports/services/index.ts +16 -0
  31. package/src/application/ports/services/page-renderer.ts +79 -0
  32. package/src/application/ports/services/server-factory.ts +80 -0
  33. package/src/application/ports/services/static-site-generator.ts +82 -0
  34. package/src/application/use-cases/activity/programs.ts +66 -0
  35. package/src/application/use-cases/analytics/collect-page-view.ts +114 -0
  36. package/src/application/use-cases/analytics/purge-old-data.ts +40 -0
  37. package/src/application/use-cases/analytics/query-campaigns.ts +43 -0
  38. package/src/application/use-cases/analytics/query-devices.ts +36 -0
  39. package/src/application/use-cases/analytics/query-overview.ts +50 -0
  40. package/src/application/use-cases/analytics/query-pages.ts +40 -0
  41. package/src/application/use-cases/analytics/query-referrers.ts +43 -0
  42. package/src/application/use-cases/analytics/ua-parser.ts +89 -0
  43. package/src/application/use-cases/analytics/visitor-hash.ts +77 -0
  44. package/src/application/use-cases/auth/bootstrap-admin.ts +270 -0
  45. package/src/application/use-cases/list-activity-logs.ts +123 -0
  46. package/src/application/use-cases/server/generate-static-helpers.ts +374 -0
  47. package/src/application/use-cases/server/generate-static.ts +287 -0
  48. package/src/application/use-cases/server/start-server.ts +118 -0
  49. package/src/application/use-cases/server/startup-error-handler.ts +69 -0
  50. package/src/application/use-cases/server/static-content-generators.ts +182 -0
  51. package/src/application/use-cases/server/static-language-generators.ts +181 -0
  52. package/src/application/use-cases/server/static-url-rewriter.ts +237 -0
  53. package/src/application/use-cases/server/translation-replacer.ts +164 -0
  54. package/src/application/use-cases/tables/activity-programs.ts +93 -0
  55. package/src/application/use-cases/tables/batch-operations.ts +156 -0
  56. package/src/application/use-cases/tables/comment-programs.ts +436 -0
  57. package/src/application/use-cases/tables/permissions/permissions.ts +25 -0
  58. package/src/application/use-cases/tables/programs.ts +435 -0
  59. package/src/application/use-cases/tables/table-operations.ts +412 -0
  60. package/src/application/use-cases/tables/user-role.ts +52 -0
  61. package/src/application/use-cases/tables/utils/display-formatter.ts +471 -0
  62. package/src/application/use-cases/tables/utils/field-read-filter.ts +189 -0
  63. package/src/application/use-cases/tables/utils/list-helpers.ts +122 -0
  64. package/src/application/use-cases/tables/utils/record-transformer.ts +319 -0
  65. package/src/cli.ts +370 -0
  66. package/src/domain/errors/create-tagged-error.ts +36 -0
  67. package/src/domain/errors/index.ts +78 -0
  68. package/src/domain/models/api/analytics.ts +179 -0
  69. package/src/domain/models/api/auth.ts +231 -0
  70. package/src/domain/models/api/common.ts +60 -0
  71. package/src/domain/models/api/error.ts +89 -0
  72. package/src/domain/models/api/health.ts +38 -0
  73. package/src/domain/models/api/index.ts +42 -0
  74. package/src/domain/models/api/request.ts +132 -0
  75. package/src/domain/models/api/tables.ts +444 -0
  76. package/src/domain/models/app/analytics/index.ts +129 -0
  77. package/src/domain/models/app/auth/config.ts +116 -0
  78. package/src/domain/models/app/auth/index.ts +230 -0
  79. package/src/domain/models/app/auth/methods/email-and-password.ts +67 -0
  80. package/src/domain/models/app/auth/methods/index.ts +11 -0
  81. package/src/domain/models/app/auth/methods/magic-link.ts +54 -0
  82. package/src/domain/models/app/auth/oauth/index.ts +8 -0
  83. package/src/domain/models/app/auth/oauth/providers.ts +105 -0
  84. package/src/domain/models/app/auth/plugins/admin.ts +130 -0
  85. package/src/domain/models/app/auth/plugins/index.ts +74 -0
  86. package/src/domain/models/app/auth/plugins/two-factor.ts +63 -0
  87. package/src/domain/models/app/auth/roles.ts +179 -0
  88. package/src/domain/models/app/auth/strategies.ts +191 -0
  89. package/src/domain/models/app/auth/validation.ts +127 -0
  90. package/src/domain/models/app/common/branded-ids.ts +200 -0
  91. package/src/domain/models/app/common/definitions.ts +187 -0
  92. package/src/domain/models/app/component/common/component-children.ts +119 -0
  93. package/src/domain/models/app/component/common/component-props.ts +89 -0
  94. package/src/domain/models/app/component/common/component-reference.ts +170 -0
  95. package/src/domain/models/app/component/component.ts +81 -0
  96. package/src/domain/models/app/components.ts +65 -0
  97. package/src/domain/models/app/description.ts +83 -0
  98. package/src/domain/models/app/index.ts +258 -0
  99. package/src/domain/models/app/language/language-config.ts +200 -0
  100. package/src/domain/models/app/languages.ts +205 -0
  101. package/src/domain/models/app/name.ts +66 -0
  102. package/src/domain/models/app/page/common/interactions/click-interaction.ts +116 -0
  103. package/src/domain/models/app/page/common/interactions/entrance-animation.ts +84 -0
  104. package/src/domain/models/app/page/common/interactions/hover-interaction.ts +144 -0
  105. package/src/domain/models/app/page/common/interactions/interactions.ts +64 -0
  106. package/src/domain/models/app/page/common/interactions/scroll-interaction.ts +93 -0
  107. package/src/domain/models/app/page/common/responsive.ts +114 -0
  108. package/src/domain/models/app/page/common/url.ts +35 -0
  109. package/src/domain/models/app/page/common/variable-reference.ts +53 -0
  110. package/src/domain/models/app/page/id.ts +44 -0
  111. package/src/domain/models/app/page/index.ts +270 -0
  112. package/src/domain/models/app/page/meta/analytics.ts +248 -0
  113. package/src/domain/models/app/page/meta/custom-elements.ts +180 -0
  114. package/src/domain/models/app/page/meta/dns-prefetch.ts +77 -0
  115. package/src/domain/models/app/page/meta/favicon-set.ts +203 -0
  116. package/src/domain/models/app/page/meta/favicon.ts +50 -0
  117. package/src/domain/models/app/page/meta/favicons-config.ts +73 -0
  118. package/src/domain/models/app/page/meta/index.ts +278 -0
  119. package/src/domain/models/app/page/meta/open-graph.ts +166 -0
  120. package/src/domain/models/app/page/meta/preload.ts +190 -0
  121. package/src/domain/models/app/page/meta/structured-data/article.ts +211 -0
  122. package/src/domain/models/app/page/meta/structured-data/breadcrumb.ts +115 -0
  123. package/src/domain/models/app/page/meta/structured-data/common-fields.ts +201 -0
  124. package/src/domain/models/app/page/meta/structured-data/education-event.ts +256 -0
  125. package/src/domain/models/app/page/meta/structured-data/faq-page.ts +127 -0
  126. package/src/domain/models/app/page/meta/structured-data/index.ts +95 -0
  127. package/src/domain/models/app/page/meta/structured-data/local-business.ts +247 -0
  128. package/src/domain/models/app/page/meta/structured-data/organization.ts +171 -0
  129. package/src/domain/models/app/page/meta/structured-data/person.ts +138 -0
  130. package/src/domain/models/app/page/meta/structured-data/postal-address.ts +106 -0
  131. package/src/domain/models/app/page/meta/structured-data/product.ts +214 -0
  132. package/src/domain/models/app/page/meta/twitter-card.ts +217 -0
  133. package/src/domain/models/app/page/name.ts +38 -0
  134. package/src/domain/models/app/page/path.ts +21 -0
  135. package/src/domain/models/app/page/scripts/external-scripts.ts +163 -0
  136. package/src/domain/models/app/page/scripts/features.ts +135 -0
  137. package/src/domain/models/app/page/scripts/inline-scripts.ts +114 -0
  138. package/src/domain/models/app/page/scripts/scripts.ts +102 -0
  139. package/src/domain/models/app/page/sections.ts +298 -0
  140. package/src/domain/models/app/pages.ts +61 -0
  141. package/src/domain/models/app/permissions/index.ts +61 -0
  142. package/src/domain/models/app/permissions/resource-action.ts +114 -0
  143. package/src/domain/models/app/permissions/roles.ts +120 -0
  144. package/src/domain/models/app/table/check-constraints.ts +105 -0
  145. package/src/domain/models/app/table/cycle-detection.ts +124 -0
  146. package/src/domain/models/app/table/database-identifier.ts +153 -0
  147. package/src/domain/models/app/table/field-name.ts +36 -0
  148. package/src/domain/models/app/table/field-types/advanced/array-field.ts +33 -0
  149. package/src/domain/models/app/table/field-types/advanced/autonumber-field.ts +54 -0
  150. package/src/domain/models/app/table/field-types/advanced/button-field.ts +56 -0
  151. package/src/domain/models/app/table/field-types/advanced/color-field.ts +57 -0
  152. package/src/domain/models/app/table/field-types/advanced/count-field.ts +54 -0
  153. package/src/domain/models/app/table/field-types/advanced/formula-field.ts +58 -0
  154. package/src/domain/models/app/table/field-types/advanced/geolocation-field.ts +49 -0
  155. package/src/domain/models/app/table/field-types/advanced/index.ts +16 -0
  156. package/src/domain/models/app/table/field-types/advanced/json-field.ts +25 -0
  157. package/src/domain/models/app/table/field-types/advanced/unknown-field.ts +85 -0
  158. package/src/domain/models/app/table/field-types/base-field.ts +42 -0
  159. package/src/domain/models/app/table/field-types/date-time/created-at-field.ts +49 -0
  160. package/src/domain/models/app/table/field-types/date-time/date-field.ts +95 -0
  161. package/src/domain/models/app/table/field-types/date-time/deleted-at-field.ts +56 -0
  162. package/src/domain/models/app/table/field-types/date-time/duration-field.ts +73 -0
  163. package/src/domain/models/app/table/field-types/date-time/index.ts +12 -0
  164. package/src/domain/models/app/table/field-types/date-time/updated-at-field.ts +50 -0
  165. package/src/domain/models/app/table/field-types/index.ts +19 -0
  166. package/src/domain/models/app/table/field-types/media/barcode-field.ts +58 -0
  167. package/src/domain/models/app/table/field-types/media/index.ts +10 -0
  168. package/src/domain/models/app/table/field-types/media/multiple-attachments-field.ts +80 -0
  169. package/src/domain/models/app/table/field-types/media/single-attachment-field.ts +81 -0
  170. package/src/domain/models/app/table/field-types/numeric/currency-field.ts +144 -0
  171. package/src/domain/models/app/table/field-types/numeric/decimal-field.ts +113 -0
  172. package/src/domain/models/app/table/field-types/numeric/index.ts +13 -0
  173. package/src/domain/models/app/table/field-types/numeric/integer-field.ts +98 -0
  174. package/src/domain/models/app/table/field-types/numeric/percentage-field.ts +115 -0
  175. package/src/domain/models/app/table/field-types/numeric/progress-field.ts +71 -0
  176. package/src/domain/models/app/table/field-types/numeric/rating-field.ts +74 -0
  177. package/src/domain/models/app/table/field-types/relational/index.ts +10 -0
  178. package/src/domain/models/app/table/field-types/relational/lookup-field.ts +46 -0
  179. package/src/domain/models/app/table/field-types/relational/relationship-field.ts +112 -0
  180. package/src/domain/models/app/table/field-types/relational/rollup-field.ts +58 -0
  181. package/src/domain/models/app/table/field-types/selection/checkbox-field.ts +51 -0
  182. package/src/domain/models/app/table/field-types/selection/index.ts +11 -0
  183. package/src/domain/models/app/table/field-types/selection/multi-select-field.ts +68 -0
  184. package/src/domain/models/app/table/field-types/selection/single-select-field.ts +54 -0
  185. package/src/domain/models/app/table/field-types/selection/status-field.ts +37 -0
  186. package/src/domain/models/app/table/field-types/text/email-field.ts +80 -0
  187. package/src/domain/models/app/table/field-types/text/index.ts +13 -0
  188. package/src/domain/models/app/table/field-types/text/long-text-field.ts +77 -0
  189. package/src/domain/models/app/table/field-types/text/phone-number-field.ts +82 -0
  190. package/src/domain/models/app/table/field-types/text/rich-text-field.ts +66 -0
  191. package/src/domain/models/app/table/field-types/text/single-line-text-field.ts +79 -0
  192. package/src/domain/models/app/table/field-types/text/url-field.ts +81 -0
  193. package/src/domain/models/app/table/field-types/user/created-by-field.ts +50 -0
  194. package/src/domain/models/app/table/field-types/user/deleted-by-field.ts +57 -0
  195. package/src/domain/models/app/table/field-types/user/index.ts +11 -0
  196. package/src/domain/models/app/table/field-types/user/updated-by-field.ts +51 -0
  197. package/src/domain/models/app/table/field-types/user/user-field.ts +52 -0
  198. package/src/domain/models/app/table/field-types/validation-utils.ts +166 -0
  199. package/src/domain/models/app/table/fields.ts +216 -0
  200. package/src/domain/models/app/table/foreign-keys.ts +111 -0
  201. package/src/domain/models/app/table/formula-keywords.ts +326 -0
  202. package/src/domain/models/app/table/id.ts +31 -0
  203. package/src/domain/models/app/table/index.ts +290 -0
  204. package/src/domain/models/app/table/indexes.ts +80 -0
  205. package/src/domain/models/app/table/name.ts +37 -0
  206. package/src/domain/models/app/table/permissions/field-permission.ts +83 -0
  207. package/src/domain/models/app/table/permissions/index.ts +167 -0
  208. package/src/domain/models/app/table/permissions/permission-evaluator.ts +372 -0
  209. package/src/domain/models/app/table/permissions/permission.ts +49 -0
  210. package/src/domain/models/app/table/primary-key.ts +62 -0
  211. package/src/domain/models/app/table/table-formula-validation.ts +168 -0
  212. package/src/domain/models/app/table/table-indexes-validation.ts +38 -0
  213. package/src/domain/models/app/table/table-permissions-validation.ts +77 -0
  214. package/src/domain/models/app/table/table-primary-key-validation.ts +49 -0
  215. package/src/domain/models/app/table/table-views-validation.ts +408 -0
  216. package/src/domain/models/app/table/unique-constraints.ts +79 -0
  217. package/src/domain/models/app/table/views/fields.ts +28 -0
  218. package/src/domain/models/app/table/views/filters.ts +162 -0
  219. package/src/domain/models/app/table/views/group-by.ts +32 -0
  220. package/src/domain/models/app/table/views/id.ts +50 -0
  221. package/src/domain/models/app/table/views/index.ts +177 -0
  222. package/src/domain/models/app/table/views/name.ts +32 -0
  223. package/src/domain/models/app/table/views/permissions.ts +98 -0
  224. package/src/domain/models/app/table/views/sorts.ts +31 -0
  225. package/src/domain/models/app/tables.ts +695 -0
  226. package/src/domain/models/app/theme/animations.ts +208 -0
  227. package/src/domain/models/app/theme/border-radius.ts +58 -0
  228. package/src/domain/models/app/theme/breakpoints.ts +62 -0
  229. package/src/domain/models/app/theme/colors.ts +110 -0
  230. package/src/domain/models/app/theme/fonts.ts +164 -0
  231. package/src/domain/models/app/theme/shadows.ts +61 -0
  232. package/src/domain/models/app/theme/spacing.ts +115 -0
  233. package/src/domain/models/app/theme.ts +66 -0
  234. package/src/domain/models/app/version.ts +87 -0
  235. package/src/domain/models/record-comment.ts +91 -0
  236. package/src/domain/utils/content-parsing.ts +49 -0
  237. package/src/domain/utils/format-detection.ts +69 -0
  238. package/src/domain/utils/index.ts +9 -0
  239. package/src/domain/utils/route-matcher.ts +184 -0
  240. package/src/domain/utils/translation-resolver.ts +170 -0
  241. package/src/index.ts +208 -0
  242. package/src/infrastructure/analytics/tracking-script.ts +48 -0
  243. package/src/infrastructure/auth/better-auth/auth.ts +216 -0
  244. package/src/infrastructure/auth/better-auth/email-handlers.ts +162 -0
  245. package/src/infrastructure/auth/better-auth/index.ts +16 -0
  246. package/src/infrastructure/auth/better-auth/layer.ts +97 -0
  247. package/src/infrastructure/auth/better-auth/plugins/admin.ts +56 -0
  248. package/src/infrastructure/auth/better-auth/plugins/magic-link.ts +31 -0
  249. package/src/infrastructure/auth/better-auth/plugins/two-factor.ts +19 -0
  250. package/src/infrastructure/auth/better-auth/schema.ts +152 -0
  251. package/src/infrastructure/auth/index.ts +27 -0
  252. package/src/infrastructure/css/cache/css-cache-service.ts +130 -0
  253. package/src/infrastructure/css/compiler.ts +210 -0
  254. package/src/infrastructure/css/css-compiler-live.ts +20 -0
  255. package/src/infrastructure/css/index.ts +25 -0
  256. package/src/infrastructure/css/styles/animation-styles-generator.ts +177 -0
  257. package/src/infrastructure/css/styles/click-animations.ts +147 -0
  258. package/src/infrastructure/css/styles/component-layer-generators.ts +147 -0
  259. package/src/infrastructure/css/theme/theme-generators.ts +130 -0
  260. package/src/infrastructure/css/theme/theme-layer-generators.ts +219 -0
  261. package/src/infrastructure/css/theme/theme-token-resolver.ts +76 -0
  262. package/src/infrastructure/database/activity-queries.ts +111 -0
  263. package/src/infrastructure/database/auth/auth-validation.ts +101 -0
  264. package/src/infrastructure/database/drizzle/db-bun.ts +17 -0
  265. package/src/infrastructure/database/drizzle/db.ts +17 -0
  266. package/src/infrastructure/database/drizzle/index.ts +16 -0
  267. package/src/infrastructure/database/drizzle/layer.ts +34 -0
  268. package/src/infrastructure/database/drizzle/migrate.ts +77 -0
  269. package/src/infrastructure/database/drizzle/schema/activity-log.ts +111 -0
  270. package/src/infrastructure/database/drizzle/schema/analytics-page-views.ts +116 -0
  271. package/src/infrastructure/database/drizzle/schema/migration-audit.ts +68 -0
  272. package/src/infrastructure/database/drizzle/schema/record-comments.ts +79 -0
  273. package/src/infrastructure/database/drizzle/schema.ts +12 -0
  274. package/src/infrastructure/database/field-utils.ts +87 -0
  275. package/src/infrastructure/database/filter-operators.ts +136 -0
  276. package/src/infrastructure/database/formula/formula-trigger-generators.ts +114 -0
  277. package/src/infrastructure/database/formula/formula-utils.ts +440 -0
  278. package/src/infrastructure/database/generators/index-generators.ts +152 -0
  279. package/src/infrastructure/database/generators/trigger-generators.ts +154 -0
  280. package/src/infrastructure/database/index.ts +35 -0
  281. package/src/infrastructure/database/lookup/lookup-expression-generators.ts +356 -0
  282. package/src/infrastructure/database/lookup/lookup-expressions.ts +116 -0
  283. package/src/infrastructure/database/lookup/lookup-view-generators.ts +403 -0
  284. package/src/infrastructure/database/lookup/lookup-view-helpers.ts +65 -0
  285. package/src/infrastructure/database/lookup/lookup-view-triggers.ts +121 -0
  286. package/src/infrastructure/database/migration-audit-trail.ts +375 -0
  287. package/src/infrastructure/database/repositories/activity-log-repository-live.ts +99 -0
  288. package/src/infrastructure/database/repositories/activity-repository-live.ts +21 -0
  289. package/src/infrastructure/database/repositories/analytics-repository-live.ts +316 -0
  290. package/src/infrastructure/database/repositories/auth-repository-live.ts +42 -0
  291. package/src/infrastructure/database/repositories/batch-repository-live.ts +29 -0
  292. package/src/infrastructure/database/repositories/comment-repository-live.ts +39 -0
  293. package/src/infrastructure/database/repositories/table-repository-live.ts +38 -0
  294. package/src/infrastructure/database/schema/schema-dependency-sorting.ts +142 -0
  295. package/src/infrastructure/database/schema/schema-initializer.ts +598 -0
  296. package/src/infrastructure/database/schema-migration/column-detection.ts +286 -0
  297. package/src/infrastructure/database/schema-migration/constants.ts +31 -0
  298. package/src/infrastructure/database/schema-migration/constraint-sync.ts +288 -0
  299. package/src/infrastructure/database/schema-migration/index-sync.ts +108 -0
  300. package/src/infrastructure/database/schema-migration/index.ts +66 -0
  301. package/src/infrastructure/database/schema-migration/migration-statements.ts +106 -0
  302. package/src/infrastructure/database/schema-migration/rename-detection.ts +87 -0
  303. package/src/infrastructure/database/schema-migration/table-operations.ts +65 -0
  304. package/src/infrastructure/database/schema-migration/type-utils.ts +98 -0
  305. package/src/infrastructure/database/schema-migration/types.ts +14 -0
  306. package/src/infrastructure/database/schema-migration-helpers.ts +53 -0
  307. package/src/infrastructure/database/session-context.ts +20 -0
  308. package/src/infrastructure/database/sql/sql-check-constraints.ts +252 -0
  309. package/src/infrastructure/database/sql/sql-column-generators.ts +174 -0
  310. package/src/infrastructure/database/sql/sql-execution.ts +245 -0
  311. package/src/infrastructure/database/sql/sql-field-predicates.ts +81 -0
  312. package/src/infrastructure/database/sql/sql-generators.ts +91 -0
  313. package/src/infrastructure/database/sql/sql-junction-tables.ts +79 -0
  314. package/src/infrastructure/database/sql/sql-key-constraints.ts +210 -0
  315. package/src/infrastructure/database/sql/sql-type-mappings.ts +106 -0
  316. package/src/infrastructure/database/sql/sql-utils.ts +53 -0
  317. package/src/infrastructure/database/table-live-layers.ts +30 -0
  318. package/src/infrastructure/database/table-operations/column-generators.ts +82 -0
  319. package/src/infrastructure/database/table-operations/create-table-sql.ts +81 -0
  320. package/src/infrastructure/database/table-operations/index.ts +55 -0
  321. package/src/infrastructure/database/table-operations/migration-utils.ts +157 -0
  322. package/src/infrastructure/database/table-operations/table-effects.ts +234 -0
  323. package/src/infrastructure/database/table-operations/table-features.ts +96 -0
  324. package/src/infrastructure/database/table-operations/type-compatibility.ts +58 -0
  325. package/src/infrastructure/database/table-operations.ts +47 -0
  326. package/src/infrastructure/database/table-queries/batch/batch-create.ts +80 -0
  327. package/src/infrastructure/database/table-queries/batch/batch-delete.ts +212 -0
  328. package/src/infrastructure/database/table-queries/batch/batch-helpers.ts +124 -0
  329. package/src/infrastructure/database/table-queries/batch/batch-restore.ts +161 -0
  330. package/src/infrastructure/database/table-queries/batch/batch-update.ts +146 -0
  331. package/src/infrastructure/database/table-queries/batch/batch-upsert.ts +357 -0
  332. package/src/infrastructure/database/table-queries/batch/batch.ts +14 -0
  333. package/src/infrastructure/database/table-queries/crud/crud-read.ts +351 -0
  334. package/src/infrastructure/database/table-queries/crud/crud-write.ts +399 -0
  335. package/src/infrastructure/database/table-queries/crud/crud.ts +16 -0
  336. package/src/infrastructure/database/table-queries/index.ts +11 -0
  337. package/src/infrastructure/database/table-queries/mutation-helpers/authorship-helpers.ts +152 -0
  338. package/src/infrastructure/database/table-queries/mutation-helpers/create-record-helpers.ts +90 -0
  339. package/src/infrastructure/database/table-queries/mutation-helpers/delete-helpers.ts +163 -0
  340. package/src/infrastructure/database/table-queries/mutation-helpers/record-fetch-helpers.ts +79 -0
  341. package/src/infrastructure/database/table-queries/mutation-helpers/update-helpers.ts +74 -0
  342. package/src/infrastructure/database/table-queries/query-helpers/activity-log-helpers.ts +53 -0
  343. package/src/infrastructure/database/table-queries/query-helpers/activity-queries.ts +106 -0
  344. package/src/infrastructure/database/table-queries/query-helpers/aggregation-helpers.ts +314 -0
  345. package/src/infrastructure/database/table-queries/query-helpers/comment-queries.ts +414 -0
  346. package/src/infrastructure/database/table-queries/query-helpers/record-validation-queries.ts +126 -0
  347. package/src/infrastructure/database/table-queries/query-helpers/trash-helpers.ts +58 -0
  348. package/src/infrastructure/database/table-queries/shared/error-handling.ts +47 -0
  349. package/src/infrastructure/database/table-queries/shared/typed-execute.ts +27 -0
  350. package/src/infrastructure/database/table-queries/shared/user-join-helpers.ts +38 -0
  351. package/src/infrastructure/database/table-queries/shared/validation.ts +39 -0
  352. package/src/infrastructure/database/views/view-generators.ts +258 -0
  353. package/src/infrastructure/devtools/devtools-layer.ts +43 -0
  354. package/src/infrastructure/devtools/index.ts +8 -0
  355. package/src/infrastructure/email/email-config.ts +103 -0
  356. package/src/infrastructure/email/email-service.ts +152 -0
  357. package/src/infrastructure/email/index.ts +107 -0
  358. package/src/infrastructure/email/nodemailer.ts +125 -0
  359. package/src/infrastructure/email/templates.ts +244 -0
  360. package/src/infrastructure/errors/auth-config-required-error.ts +21 -0
  361. package/src/infrastructure/errors/auth-error.ts +16 -0
  362. package/src/infrastructure/errors/css-compilation-error.ts +14 -0
  363. package/src/infrastructure/errors/index.ts +26 -0
  364. package/src/infrastructure/errors/schema-initialization-error.ts +19 -0
  365. package/src/infrastructure/errors/server-creation-error.ts +14 -0
  366. package/src/infrastructure/filesystem/copy-directory.ts +136 -0
  367. package/src/infrastructure/layers/app-layer.ts +61 -0
  368. package/src/infrastructure/layers/page-renderer-layer.ts +41 -0
  369. package/src/infrastructure/logging/index.ts +8 -0
  370. package/src/infrastructure/logging/logger.ts +204 -0
  371. package/src/infrastructure/schema/file-loader.ts +53 -0
  372. package/src/infrastructure/schema/index.ts +15 -0
  373. package/src/infrastructure/schema/remote-loader.ts +48 -0
  374. package/src/infrastructure/server/index.ts +26 -0
  375. package/src/infrastructure/server/language-detection.ts +87 -0
  376. package/src/infrastructure/server/lifecycle.ts +67 -0
  377. package/src/infrastructure/server/route-setup/api-routes.ts +310 -0
  378. package/src/infrastructure/server/route-setup/auth-route-utils.ts +399 -0
  379. package/src/infrastructure/server/route-setup/auth-routes.ts +245 -0
  380. package/src/infrastructure/server/route-setup/openapi-routes.ts +45 -0
  381. package/src/infrastructure/server/route-setup/openapi-schema.ts +120 -0
  382. package/src/infrastructure/server/route-setup/page-routes.ts +219 -0
  383. package/src/infrastructure/server/route-setup/static-assets.ts +191 -0
  384. package/src/infrastructure/server/server-factory-live.ts +45 -0
  385. package/src/infrastructure/server/server.ts +275 -0
  386. package/src/infrastructure/server/ssg-adapter.ts +196 -0
  387. package/src/infrastructure/server/static-site-generator-live.ts +20 -0
  388. package/src/infrastructure/utils/accept-language-parser.ts +106 -0
  389. package/src/infrastructure/utils/glob-matcher.ts +50 -0
  390. package/src/presentation/api/client.ts +114 -0
  391. package/src/presentation/api/middleware/auth.ts +233 -0
  392. package/src/presentation/api/middleware/table.ts +155 -0
  393. package/src/presentation/api/middleware/validation.ts +88 -0
  394. package/src/presentation/api/routes/activity/get-activity-by-id-handler.ts +77 -0
  395. package/src/presentation/api/routes/activity/index.ts +28 -0
  396. package/src/presentation/api/routes/activity.ts +339 -0
  397. package/src/presentation/api/routes/analytics.ts +328 -0
  398. package/src/presentation/api/routes/auth.ts +169 -0
  399. package/src/presentation/api/routes/index.ts +11 -0
  400. package/src/presentation/api/routes/tables/activity-handlers.ts +57 -0
  401. package/src/presentation/api/routes/tables/batch-permission-helpers.ts +163 -0
  402. package/src/presentation/api/routes/tables/batch-routes.ts +355 -0
  403. package/src/presentation/api/routes/tables/comment-handlers.ts +377 -0
  404. package/src/presentation/api/routes/tables/create-record-helpers.ts +179 -0
  405. package/src/presentation/api/routes/tables/effect-runner.ts +58 -0
  406. package/src/presentation/api/routes/tables/error-handlers.ts +53 -0
  407. package/src/presentation/api/routes/tables/field-permission-validation.ts +167 -0
  408. package/src/presentation/api/routes/tables/filter-parser.ts +75 -0
  409. package/src/presentation/api/routes/tables/formula-parser.ts +118 -0
  410. package/src/presentation/api/routes/tables/index.ts +113 -0
  411. package/src/presentation/api/routes/tables/list-records-filter.ts +54 -0
  412. package/src/presentation/api/routes/tables/param-parsers.ts +59 -0
  413. package/src/presentation/api/routes/tables/record-handlers.ts +484 -0
  414. package/src/presentation/api/routes/tables/record-routes.ts +53 -0
  415. package/src/presentation/api/routes/tables/record-update-handler.ts +200 -0
  416. package/src/presentation/api/routes/tables/sort-validation.ts +85 -0
  417. package/src/presentation/api/routes/tables/table-routes.ts +76 -0
  418. package/src/presentation/api/routes/tables/timezone-validation.ts +41 -0
  419. package/src/presentation/api/routes/tables/upsert-helpers.ts +471 -0
  420. package/src/presentation/api/routes/tables/utils.ts +159 -0
  421. package/src/presentation/api/routes/tables/view-routes.ts +51 -0
  422. package/src/presentation/api/routes/tables.ts +9 -0
  423. package/src/presentation/api/utils/context-helpers.ts +43 -0
  424. package/src/presentation/api/utils/error-sanitizer.ts +235 -0
  425. package/src/presentation/api/utils/field-permission-validator.ts +53 -0
  426. package/src/presentation/api/utils/filter-field-validator.ts +90 -0
  427. package/src/presentation/api/utils/index.ts +13 -0
  428. package/src/presentation/api/utils/run-effect.ts +94 -0
  429. package/src/presentation/api/utils/validate-request.ts +89 -0
  430. package/src/presentation/api/validation/index.ts +29 -0
  431. package/src/presentation/api/validation/rules/field-rules.ts +158 -0
  432. package/src/presentation/api/validation/rules/record-rules.ts +73 -0
  433. package/src/presentation/cli/index.ts +19 -0
  434. package/src/presentation/cli/schema-loader.ts +172 -0
  435. package/src/presentation/hooks/use-breakpoint.ts +155 -0
  436. package/src/presentation/rendering/render-error-pages.tsx +60 -0
  437. package/src/presentation/rendering/render-homepage.tsx +137 -0
  438. package/src/presentation/scripts/script-renderers.ts +112 -0
  439. package/src/presentation/styling/animation-composer.ts +117 -0
  440. package/src/presentation/styling/index.ts +13 -0
  441. package/src/presentation/styling/parse-style.ts +243 -0
  442. package/src/presentation/styling/style-utils.ts +50 -0
  443. package/src/presentation/styling/theme-colors.ts +53 -0
  444. package/src/presentation/translations/component-utils.ts +54 -0
  445. package/src/presentation/translations/index.ts +16 -0
  446. package/src/presentation/translations/translation-resolver.ts +22 -0
  447. package/src/presentation/ui/languages/language-switcher.tsx +119 -0
  448. package/src/presentation/ui/metadata/analytics-builders.tsx +174 -0
  449. package/src/presentation/ui/metadata/analytics-head.tsx +39 -0
  450. package/src/presentation/ui/metadata/custom-elements-builders.tsx +157 -0
  451. package/src/presentation/ui/metadata/extract-component-meta.ts +108 -0
  452. package/src/presentation/ui/metadata/head-elements.tsx +164 -0
  453. package/src/presentation/ui/metadata/index.tsx +35 -0
  454. package/src/presentation/ui/metadata/meta-utils.tsx +42 -0
  455. package/src/presentation/ui/metadata/open-graph-meta.tsx +57 -0
  456. package/src/presentation/ui/metadata/structured-data-from-component.tsx +134 -0
  457. package/src/presentation/ui/metadata/structured-data.tsx +88 -0
  458. package/src/presentation/ui/metadata/twitter-card-meta.tsx +80 -0
  459. package/src/presentation/ui/pages/DefaultHomePage.tsx +43 -0
  460. package/src/presentation/ui/pages/DefaultPageConfigs.ts +220 -0
  461. package/src/presentation/ui/pages/DynamicPage.tsx +307 -0
  462. package/src/presentation/ui/pages/ErrorPage.tsx +25 -0
  463. package/src/presentation/ui/pages/NotFoundPage.tsx +25 -0
  464. package/src/presentation/ui/pages/PageBodyScripts.tsx +242 -0
  465. package/src/presentation/ui/pages/PageBodyStyles.ts +52 -0
  466. package/src/presentation/ui/pages/PageHead.tsx +380 -0
  467. package/src/presentation/ui/pages/PageLangResolver.ts +58 -0
  468. package/src/presentation/ui/pages/PageMain.tsx +58 -0
  469. package/src/presentation/ui/pages/PageMetadata.ts +168 -0
  470. package/src/presentation/ui/pages/PageMetadataI18n.ts +169 -0
  471. package/src/presentation/ui/pages/PageScripts.ts +78 -0
  472. package/src/presentation/ui/pages/SectionRenderer.tsx +67 -0
  473. package/src/presentation/ui/pages/SectionSpacing.tsx +131 -0
  474. package/src/presentation/ui/sections/component-renderer.tsx +426 -0
  475. package/src/presentation/ui/sections/component-renderer.types.ts +33 -0
  476. package/src/presentation/ui/sections/components/component-reference-handler.tsx +74 -0
  477. package/src/presentation/ui/sections/components/component-resolution.ts +65 -0
  478. package/src/presentation/ui/sections/components/index.ts +9 -0
  479. package/src/presentation/ui/sections/hero.tsx +394 -0
  480. package/src/presentation/ui/sections/props/component-builder.ts +183 -0
  481. package/src/presentation/ui/sections/props/element-props.ts +179 -0
  482. package/src/presentation/ui/sections/props/index.ts +9 -0
  483. package/src/presentation/ui/sections/props/prop-conversion.ts +171 -0
  484. package/src/presentation/ui/sections/props/props-builder-config.ts +42 -0
  485. package/src/presentation/ui/sections/props/props-builder.ts +296 -0
  486. package/src/presentation/ui/sections/renderers/element-renderers/html-element-renderer.tsx +124 -0
  487. package/src/presentation/ui/sections/renderers/element-renderers/index.ts +59 -0
  488. package/src/presentation/ui/sections/renderers/element-renderers/interactive-renderers.tsx +231 -0
  489. package/src/presentation/ui/sections/renderers/element-renderers/media-renderers.tsx +102 -0
  490. package/src/presentation/ui/sections/renderers/element-renderers/text-content-renderers.tsx +42 -0
  491. package/src/presentation/ui/sections/renderers/element-renderers.ts +53 -0
  492. package/src/presentation/ui/sections/renderers/html-element-helpers.ts +100 -0
  493. package/src/presentation/ui/sections/renderers/specialized-renderers.tsx +212 -0
  494. package/src/presentation/ui/sections/rendering/component-dispatch-config.ts +31 -0
  495. package/src/presentation/ui/sections/rendering/component-registry/index.ts +39 -0
  496. package/src/presentation/ui/sections/rendering/component-registry/interactive-components.ts +54 -0
  497. package/src/presentation/ui/sections/rendering/component-registry/media-components.ts +36 -0
  498. package/src/presentation/ui/sections/rendering/component-registry/special-components.tsx +153 -0
  499. package/src/presentation/ui/sections/rendering/component-registry/structural-components.ts +215 -0
  500. package/src/presentation/ui/sections/rendering/component-registry/text-components.ts +57 -0
  501. package/src/presentation/ui/sections/rendering/component-registry-helpers.tsx +29 -0
  502. package/src/presentation/ui/sections/rendering/component-registry.tsx +21 -0
  503. package/src/presentation/ui/sections/rendering/component-type-dispatcher.tsx +33 -0
  504. package/src/presentation/ui/sections/rendering/index.ts +9 -0
  505. package/src/presentation/ui/sections/responsive/responsive-children-builder.tsx +96 -0
  506. package/src/presentation/ui/sections/responsive/responsive-content-builder.tsx +95 -0
  507. package/src/presentation/ui/sections/responsive/responsive-props-merger.ts +195 -0
  508. package/src/presentation/ui/sections/responsive/responsive-resolver.ts +213 -0
  509. package/src/presentation/ui/sections/styling/animation-composer-wrapper.ts +65 -0
  510. package/src/presentation/ui/sections/styling/class-builders.ts +45 -0
  511. package/src/presentation/ui/sections/styling/color-resolver.ts +43 -0
  512. package/src/presentation/ui/sections/styling/hover-interaction-handler.ts +107 -0
  513. package/src/presentation/ui/sections/styling/index.ts +9 -0
  514. package/src/presentation/ui/sections/styling/interaction-props-builder.ts +55 -0
  515. package/src/presentation/ui/sections/styling/shadow-resolver.ts +83 -0
  516. package/src/presentation/ui/sections/styling/spacing-resolver.ts +104 -0
  517. package/src/presentation/ui/sections/styling/style-processor.ts +170 -0
  518. package/src/presentation/ui/sections/styling/theme-tokens.ts +184 -0
  519. package/src/presentation/ui/sections/translations/i18n-content-resolver.ts +198 -0
  520. package/src/presentation/ui/sections/translations/index.ts +9 -0
  521. package/src/presentation/ui/sections/translations/translation-handler.ts +143 -0
  522. package/src/presentation/ui/sections/translations/variable-substitution.ts +225 -0
  523. package/src/presentation/ui/sections/utils/time-parser.ts +82 -0
  524. package/src/presentation/utils/link-attributes.ts +50 -0
  525. package/src/presentation/utils/string-utils.ts +58 -0
  526. package/src/presentation/utils/styles.ts +50 -0
  527. package/tsconfig.json +46 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { Data } from 'effect'
9
+ import { logInfo } from '@/infrastructure/logging/logger'
10
+ import { isUserReferenceField, isUserField } from '../sql/sql-generators'
11
+ import type { Table } from '@/domain/models/app/table'
12
+
13
+ export class BetterAuthUsersTableRequired extends Data.TaggedError('BetterAuthUsersTableRequired')<{
14
+ readonly message: string
15
+ }> {}
16
+
17
+ /**
18
+ * Check if any table needs the users table for foreign keys
19
+ */
20
+ export const needsUsersTable = (tables: readonly Table[]): boolean =>
21
+ tables.some((table) =>
22
+ table.fields.some((field) => isUserReferenceField(field) || isUserField(field))
23
+ )
24
+
25
+ /**
26
+ * Check if any table has updated-by fields that need the trigger function
27
+ */
28
+ export const needsUpdatedByTrigger = (tables: readonly Table[]): boolean =>
29
+ tables.some((table) => table.fields.some((field) => field.type === 'updated-by'))
30
+
31
+ /**
32
+ * Verify Better Auth users table exists for foreign key references
33
+ *
34
+ * User fields (user, created-by, updated-by, deleted-by) require Better Auth's users table.
35
+ * Better Auth uses TEXT ids, so user fields store TEXT foreign keys.
36
+ *
37
+ * @throws BetterAuthUsersTableRequired if users table doesn't exist or lacks required columns
38
+ */
39
+ /* eslint-disable functional/no-throw-statements */
40
+ export const ensureBetterAuthUsersTable = async (tx: {
41
+ unsafe: (sql: string) => Promise<unknown>
42
+ }): Promise<void> => {
43
+ logInfo('[ensureBetterAuthUsersTable] Verifying Better Auth users table exists...')
44
+
45
+ // Check if users table exists (in auth schema)
46
+ const tableExistsResult = (await tx.unsafe(`
47
+ SELECT EXISTS (
48
+ SELECT 1 FROM information_schema.tables
49
+ WHERE table_schema = 'auth' AND table_name = 'user'
50
+ ) as exists
51
+ `)) as readonly { exists: boolean }[]
52
+
53
+ if (!tableExistsResult[0]?.exists) {
54
+ throw new BetterAuthUsersTableRequired({
55
+ message:
56
+ 'User fields require Better Auth users table. Please configure Better Auth authentication before using user, created-by, updated-by, or deleted-by field types.',
57
+ })
58
+ }
59
+
60
+ // Verify Better Auth schema (TEXT id column)
61
+ const idColumnResult = (await tx.unsafe(`
62
+ SELECT data_type FROM information_schema.columns
63
+ WHERE table_schema = 'auth' AND table_name = 'user' AND column_name = 'id'
64
+ `)) as readonly { data_type: string }[]
65
+
66
+ if (!idColumnResult[0]) {
67
+ throw new BetterAuthUsersTableRequired({
68
+ message:
69
+ 'Users table exists but lacks id column. Please ensure Better Auth is properly configured.',
70
+ })
71
+ }
72
+
73
+ const idType = idColumnResult[0].data_type.toLowerCase()
74
+ if (idType !== 'text' && idType !== 'character varying') {
75
+ throw new BetterAuthUsersTableRequired({
76
+ message: `Users table has incompatible id column type '${idType}'. Better Auth uses TEXT ids. Please configure Better Auth authentication.`,
77
+ })
78
+ }
79
+
80
+ logInfo('[ensureBetterAuthUsersTable] Better Auth users table verified successfully')
81
+ }
82
+ /* eslint-enable functional/no-throw-statements */
83
+
84
+ /**
85
+ * Ensure global set_updated_by trigger function exists
86
+ * This function is shared across all tables with updated-by fields
87
+ */
88
+ /* eslint-disable functional/no-expression-statements */
89
+ export const ensureUpdatedByTriggerFunction = async (tx: {
90
+ unsafe: (sql: string) => Promise<unknown>
91
+ }): Promise<void> => {
92
+ await tx.unsafe(`
93
+ CREATE OR REPLACE FUNCTION set_updated_by()
94
+ RETURNS TRIGGER AS $$
95
+ BEGIN
96
+ RETURN NEW;
97
+ END;
98
+ $$ LANGUAGE plpgsql
99
+ `)
100
+ }
101
+ /* eslint-enable functional/no-expression-statements */
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { drizzle } from 'drizzle-orm/bun-sql'
9
+ import * as schema from './schema'
10
+
11
+ // Bun-specific database driver using native bun:sql
12
+ export const db = drizzle({
13
+ connection: { url: process.env.DATABASE_URL! },
14
+ schema,
15
+ })
16
+
17
+ export type DrizzleDB = typeof db
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import type { DrizzleDB } from './db-bun'
9
+
10
+ export { db } from './db-bun'
11
+ export type { DrizzleDB } from './db-bun'
12
+
13
+ /**
14
+ * Type for Drizzle transaction callback parameter
15
+ * Extracts the transaction type from the db.transaction method
16
+ */
17
+ export type DrizzleTransaction = Parameters<Parameters<DrizzleDB['transaction']>[0]>[0]
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ /**
9
+ * Drizzle Database Module
10
+ *
11
+ * Provides database functionality using Drizzle ORM with Bun SQL.
12
+ * Re-exports all database-related services, schema, and types.
13
+ */
14
+ export { db, type DrizzleDB } from './db'
15
+ export { Database, DatabaseLive } from './layer'
16
+ export * from './schema'
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { Context, Layer } from 'effect'
9
+ import { db, type DrizzleDB } from './db.js'
10
+
11
+ /**
12
+ * Database Effect Context
13
+ *
14
+ * Provides Drizzle database instance for dependency injection in Effect programs.
15
+ * Use this in Application layer to access database without direct imports.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const program = Effect.gen(function* () {
20
+ * const db = yield* Database
21
+ * const users = yield* Effect.tryPromise(() => db.select().from(usersTable))
22
+ * return users
23
+ * })
24
+ * ```
25
+ */
26
+ export class Database extends Context.Tag('Database')<Database, DrizzleDB>() {}
27
+
28
+ /**
29
+ * Live Database Layer
30
+ *
31
+ * Provides the production Drizzle database instance.
32
+ * Uses DATABASE_URL environment variable for connection.
33
+ */
34
+ export const DatabaseLive = Layer.succeed(Database, db)
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { SQL } from 'bun'
9
+ import { drizzle } from 'drizzle-orm/bun-sql'
10
+ import { migrate } from 'drizzle-orm/bun-sql/migrator'
11
+ import { Effect, Console, Data } from 'effect'
12
+ import * as schema from './schema'
13
+
14
+ /**
15
+ * Error when database connection fails
16
+ */
17
+ export class DatabaseConnectionError extends Data.TaggedError('DatabaseConnectionError')<{
18
+ readonly message: string
19
+ readonly cause?: unknown
20
+ }> {}
21
+
22
+ /**
23
+ * Error when migration fails
24
+ */
25
+ export class MigrationError extends Data.TaggedError('MigrationError')<{
26
+ readonly message: string
27
+ readonly cause?: unknown
28
+ }> {}
29
+
30
+ /**
31
+ * Run Drizzle migrations to create/update database schema
32
+ *
33
+ * This applies all migrations from the ./drizzle folder:
34
+ * - Better Auth tables (users, sessions, accounts, etc.)
35
+ * - Migration audit tables (system.migration_history, etc.)
36
+ * - Auth schema with helper functions (auth.is_authenticated, auth.user_has_role)
37
+ *
38
+ * CRITICAL: Must run BEFORE initializeSchema() because:
39
+ * 1. User fields (created-by, updated-by, user) need users table to exist
40
+ * 2. The users table must be created before app-specific tables
41
+ * 3. initializeSchema() creates app-specific tables that reference users
42
+ *
43
+ * @param databaseUrl - PostgreSQL connection URL
44
+ * @returns Effect that completes when migrations are applied
45
+ */
46
+ export const runMigrations = (
47
+ databaseUrl: string
48
+ ): Effect.Effect<void, DatabaseConnectionError | MigrationError> =>
49
+ Effect.gen(function* () {
50
+ yield* Console.log('[runMigrations] Running Drizzle migrations...')
51
+
52
+ const client = new SQL(databaseUrl)
53
+ const db = drizzle({ client, schema })
54
+
55
+ // Test database connection first to fail fast on connection errors
56
+ yield* Effect.tryPromise({
57
+ try: () => client.unsafe('SELECT 1'),
58
+ catch: (error) =>
59
+ new DatabaseConnectionError({
60
+ message: `Database connection failed: ${String(error)}`,
61
+ cause: error,
62
+ }),
63
+ })
64
+
65
+ yield* Effect.tryPromise({
66
+ try: () => migrate(db, { migrationsFolder: './drizzle' }),
67
+ catch: (error) =>
68
+ new MigrationError({
69
+ message: `Migration failed: ${String(error)}`,
70
+ cause: error,
71
+ }),
72
+ })
73
+
74
+ yield* Effect.promise(() => client.close())
75
+
76
+ yield* Console.log('[runMigrations] ✓ Drizzle migrations completed')
77
+ })
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { sql } from 'drizzle-orm'
9
+ import { text, timestamp, jsonb, index } from 'drizzle-orm/pg-core'
10
+ import { users } from '../../../auth/better-auth/schema'
11
+ import { systemSchema } from './migration-audit'
12
+
13
+ /**
14
+ * Activity Action Type
15
+ *
16
+ * Defines the types of actions that can be recorded in the activity log.
17
+ * - create: A new record was created
18
+ * - update: An existing record was modified
19
+ * - delete: A record was soft-deleted or hard-deleted
20
+ * - restore: A soft-deleted record was restored
21
+ */
22
+ export type ActivityAction = 'create' | 'update' | 'delete' | 'restore'
23
+
24
+ /**
25
+ * Activity Log Changes Type
26
+ *
27
+ * Captures the before/after state of record modifications.
28
+ * - For 'create': only 'after' is populated
29
+ * - For 'update': both 'before' and 'after' are populated with changed fields
30
+ * - For 'delete': only 'before' is populated (or null for hard deletes)
31
+ * - For 'restore': both 'before' and 'after' are populated
32
+ */
33
+ export type ActivityLogChanges = {
34
+ readonly before?: Record<string, unknown>
35
+ readonly after?: Record<string, unknown>
36
+ }
37
+
38
+ /**
39
+ * Activity Log Table Schema
40
+ *
41
+ * Central audit log tracking all data modifications across the application.
42
+ * Optimized for:
43
+ * - Time-range queries (recent activity)
44
+ * - User activity lookups (user audit trail)
45
+ * - Record history queries (record-specific changes)
46
+ *
47
+ * Retention: 1 year (compliance requirement)
48
+ *
49
+ * Authentication Optional:
50
+ * - userId is nullable to support anonymous activity logging
51
+ * - When Better Auth is not configured, activities are logged without user context
52
+ */
53
+ export const activityLogs = systemSchema.table(
54
+ 'activity_logs',
55
+ {
56
+ // Primary key - UUID for distributed systems compatibility
57
+ // Default generates UUID automatically via PostgreSQL gen_random_uuid()
58
+ id: text('id')
59
+ .primaryKey()
60
+ .default(sql`gen_random_uuid()`),
61
+
62
+ // Event metadata
63
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
64
+
65
+ // User who performed the action (null when auth disabled)
66
+ userId: text('user_id').references(() => users.id, { onDelete: 'set null' }),
67
+
68
+ // Optional session tracking for additional context
69
+ sessionId: text('session_id'),
70
+
71
+ // Action type: create, update, delete, restore
72
+ action: text('action').notNull().$type<ActivityAction>(),
73
+
74
+ // Table identification
75
+ tableName: text('table_name').notNull(),
76
+ // tableId is optional - not all activity sources have a table schema ID
77
+ tableId: text('table_id'),
78
+
79
+ // Record identification within the table
80
+ recordId: text('record_id').notNull(),
81
+
82
+ // Change tracking - JSONB for efficient storage and querying
83
+ // Contains { before?: {...}, after?: {...} }
84
+ changes: jsonb('changes').$type<ActivityLogChanges>(),
85
+
86
+ // Request context for security auditing
87
+ ipAddress: text('ip_address'),
88
+ userAgent: text('user_agent'),
89
+ },
90
+ (table) => [
91
+ // Index for recent activity queries (most common)
92
+ // Supports: GET /api/activity (sorted by createdAt DESC)
93
+ index('activity_logs_created_at_idx').on(table.createdAt),
94
+
95
+ // Composite index for user activity queries
96
+ // Supports: GET /api/users/:userId/activity
97
+ index('activity_logs_user_created_at_idx').on(table.userId, table.createdAt),
98
+
99
+ // Composite index for record history queries
100
+ // Supports: GET /api/tables/:tableId/records/:recordId/history
101
+ index('activity_logs_table_record_idx').on(table.tableName, table.recordId),
102
+
103
+ // Index for filtering by action type
104
+ // Supports: GET /api/activity?action=create
105
+ index('activity_logs_action_idx').on(table.action),
106
+ ]
107
+ )
108
+
109
+ // Type exports for consumers
110
+ export type ActivityLog = typeof activityLogs.$inferSelect
111
+ export type NewActivityLog = typeof activityLogs.$inferInsert
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { sql } from 'drizzle-orm'
9
+ import { boolean, index, smallint, text, timestamp } from 'drizzle-orm/pg-core'
10
+ import { systemSchema } from './migration-audit'
11
+
12
+ /**
13
+ * Analytics Page Views Table Schema
14
+ *
15
+ * Stores individual page view events for the built-in analytics engine.
16
+ * Designed for privacy-first tracking without cookies or PII.
17
+ *
18
+ * Key design decisions:
19
+ * - visitorHash: SHA-256(date + IP + UA + salt) — rotates daily, no PII stored
20
+ * - sessionHash: SHA-256(visitorHash + time-window) — groups views into sessions
21
+ * - No foreign keys to users table — analytics is anonymous
22
+ * - All device/browser/OS data parsed server-side from User-Agent
23
+ * - UTM parameters captured from tracking script payload
24
+ *
25
+ * Indexes optimized for:
26
+ * - Time-series queries (overview, trends)
27
+ * - Unique visitor counting
28
+ * - Per-page analytics
29
+ * - Referrer analysis
30
+ * - UTM campaign analysis
31
+ * - Device breakdown queries
32
+ */
33
+ export const analyticsPageViews = systemSchema.table(
34
+ 'analytics_page_views',
35
+ {
36
+ // Primary key - UUID for distributed systems compatibility
37
+ id: text('id')
38
+ .primaryKey()
39
+ .default(sql`gen_random_uuid()`),
40
+
41
+ // Event timestamp
42
+ timestamp: timestamp('timestamp', { withTimezone: true }).notNull().defaultNow(),
43
+
44
+ // Application identifier (supports multi-app deployments)
45
+ // Default 'default' enables direct INSERTs via system.page_views view without explicit app_name
46
+ appName: text('app_name').notNull().default('default'),
47
+
48
+ // Page information
49
+ pagePath: text('page_path').notNull(),
50
+ pageTitle: text('page_title'),
51
+
52
+ // Privacy-safe visitor identification (no cookies, no PII)
53
+ // SHA-256(date + IP + UA + salt) — rotates daily
54
+ visitorHash: text('visitor_hash').notNull(),
55
+
56
+ // Session identification
57
+ // SHA-256(visitorHash + time-window) — groups views into sessions
58
+ // Default gen_random_uuid() enables direct INSERTs via system.page_views view without explicit session_hash
59
+ sessionHash: text('session_hash')
60
+ .notNull()
61
+ .default(sql`gen_random_uuid()`),
62
+
63
+ // Whether this is the first page view in a session
64
+ isEntrance: boolean('is_entrance').notNull().default(false),
65
+
66
+ // Referrer information
67
+ referrerUrl: text('referrer_url'),
68
+ referrerDomain: text('referrer_domain'),
69
+
70
+ // UTM campaign parameters
71
+ utmSource: text('utm_source'),
72
+ utmMedium: text('utm_medium'),
73
+ utmCampaign: text('utm_campaign'),
74
+ utmContent: text('utm_content'),
75
+ utmTerm: text('utm_term'),
76
+
77
+ // Device information (parsed from User-Agent server-side)
78
+ deviceType: text('device_type'), // 'desktop' | 'mobile' | 'tablet'
79
+ browserName: text('browser_name'),
80
+ osName: text('os_name'),
81
+
82
+ // Visitor locale (from Accept-Language header)
83
+ language: text('language'),
84
+
85
+ // Screen dimensions (from tracking script)
86
+ screenWidth: smallint('screen_width'),
87
+ screenHeight: smallint('screen_height'),
88
+ },
89
+ (table) => [
90
+ // Primary time-series index (overview queries, date range filtering)
91
+ index('analytics_pv_app_timestamp_idx').on(table.appName, table.timestamp),
92
+
93
+ // Unique visitor counting
94
+ index('analytics_pv_app_visitor_timestamp_idx').on(
95
+ table.appName,
96
+ table.visitorHash,
97
+ table.timestamp
98
+ ),
99
+
100
+ // Per-page analytics (top pages queries)
101
+ index('analytics_pv_app_path_timestamp_idx').on(table.appName, table.pagePath, table.timestamp),
102
+
103
+ // Referrer analysis (traffic sources queries)
104
+ index('analytics_pv_app_referrer_idx').on(table.appName, table.referrerDomain),
105
+
106
+ // UTM campaign analysis
107
+ index('analytics_pv_app_utm_source_idx').on(table.appName, table.utmSource),
108
+
109
+ // Device breakdown queries
110
+ index('analytics_pv_app_device_idx').on(table.appName, table.deviceType),
111
+ ]
112
+ )
113
+
114
+ // Type exports for consumers
115
+ export type AnalyticsPageView = typeof analyticsPageViews.$inferSelect
116
+ export type NewAnalyticsPageView = typeof analyticsPageViews.$inferInsert
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { pgSchema, serial, integer, text, timestamp, jsonb } from 'drizzle-orm/pg-core'
9
+
10
+ /**
11
+ * System Schema
12
+ *
13
+ * Dedicated PostgreSQL schema for internal Sovrium tables.
14
+ * Isolates system tables from user data tables.
15
+ */
16
+ export const systemSchema = pgSchema('system')
17
+
18
+ /**
19
+ * Migration History Table Schema
20
+ *
21
+ * Tracks all schema migrations with timestamps and checksums.
22
+ * Each migration is recorded with a version number and the complete schema snapshot.
23
+ */
24
+ export const sovriumMigrationHistory = systemSchema.table('migration_history', {
25
+ id: serial('id').primaryKey(),
26
+ version: integer('version').notNull(),
27
+ checksum: text('checksum').notNull(),
28
+ schema: jsonb('schema'),
29
+ appliedAt: timestamp('applied_at').defaultNow(),
30
+ rolledBackAt: timestamp('rolled_back_at'),
31
+ })
32
+
33
+ /**
34
+ * Migration Log Table Schema
35
+ *
36
+ * Tracks migration operations including rollbacks with status and reason.
37
+ * Used for debugging and audit trail of schema changes.
38
+ */
39
+ export const sovriumMigrationLog = systemSchema.table('migration_log', {
40
+ id: serial('id').primaryKey(),
41
+ operation: text('operation').notNull(),
42
+ fromVersion: integer('from_version'),
43
+ toVersion: integer('to_version'),
44
+ reason: text('reason'),
45
+ status: text('status').notNull(),
46
+ createdAt: timestamp('created_at').defaultNow(),
47
+ })
48
+
49
+ /**
50
+ * Schema Checksum Table Schema
51
+ *
52
+ * Singleton table storing current schema checksum for change detection.
53
+ * Uses a single row with id='singleton' to track the current state.
54
+ */
55
+ export const sovriumSchemaChecksum = systemSchema.table('schema_checksum', {
56
+ id: text('id').primaryKey(),
57
+ checksum: text('checksum').notNull(),
58
+ schema: jsonb('schema').notNull(),
59
+ updatedAt: timestamp('updated_at').defaultNow(),
60
+ })
61
+
62
+ // Type exports for consumers
63
+ export type SovriumMigrationHistory = typeof sovriumMigrationHistory.$inferSelect
64
+ export type NewSovriumMigrationHistory = typeof sovriumMigrationHistory.$inferInsert
65
+ export type SovriumMigrationLog = typeof sovriumMigrationLog.$inferSelect
66
+ export type NewSovriumMigrationLog = typeof sovriumMigrationLog.$inferInsert
67
+ export type SovriumSchemaChecksum = typeof sovriumSchemaChecksum.$inferSelect
68
+ export type NewSovriumSchemaChecksum = typeof sovriumSchemaChecksum.$inferInsert
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ import { text, timestamp, index } from 'drizzle-orm/pg-core'
9
+ import { users } from '../../../auth/better-auth/schema'
10
+ import { systemSchema } from './migration-audit'
11
+
12
+ /**
13
+ * Record Comments Table Schema
14
+ *
15
+ * Enables users to add comments to records in any table, similar to Airtable/Notion.
16
+ * Comments are flat (no threading), chronological, and support @mentions.
17
+ *
18
+ * Features:
19
+ * - Authentication required: Comments must have a user_id (no anonymous comments)
20
+ * - Soft delete: deleted_at for restoration capability
21
+ * - @mentions: Stored as user IDs in content (e.g., @[user_123])
22
+ * - Table validation: Comments tied to specific table_id for validation
23
+ *
24
+ * Authorization:
25
+ * - Read: Same permissions as the record itself (if you can read the record, you can read comments)
26
+ * - Create: Any authenticated user who can read the record can comment
27
+ * - Update: Only comment author can edit their own comments
28
+ * - Delete: Comment author OR admins can delete comments
29
+ *
30
+ * Optimized for:
31
+ * - Fetching all comments for a record (most common query)
32
+ * - User activity lookups (all comments by a user)
33
+ * - Soft delete filtering (excluding deleted comments by default)
34
+ */
35
+ export const recordComments = systemSchema.table(
36
+ 'record_comments',
37
+ {
38
+ // Primary key - UUID for distributed systems compatibility
39
+ id: text('id').primaryKey(),
40
+
41
+ // Record identification
42
+ recordId: text('record_id').notNull(),
43
+ tableId: text('table_id').notNull(),
44
+
45
+ // User who created the comment (required - no anonymous comments)
46
+ userId: text('user_id')
47
+ .notNull()
48
+ .references(() => users.id, { onDelete: 'cascade' }),
49
+
50
+ // Comment content - supports @mentions as @[user_id] format
51
+ // Max length enforced at application layer
52
+ content: text('content').notNull(),
53
+
54
+ // Timestamps
55
+ createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
56
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
57
+
58
+ // Soft delete support
59
+ deletedAt: timestamp('deleted_at', { withTimezone: true }),
60
+ },
61
+ (table) => [
62
+ // Composite index for fetching all comments on a record (most common query)
63
+ // Supports: GET /api/tables/:tableId/records/:recordId/comments
64
+ // Ordered by createdAt for chronological display
65
+ index('record_comments_record_created_idx').on(table.tableId, table.recordId, table.createdAt),
66
+
67
+ // Composite index for user activity queries
68
+ // Supports: GET /api/users/:userId/comments
69
+ index('record_comments_user_created_idx').on(table.userId, table.createdAt),
70
+
71
+ // Index for soft delete filtering
72
+ // Supports: WHERE deleted_at IS NULL (default query behavior)
73
+ index('record_comments_deleted_at_idx').on(table.deletedAt),
74
+ ]
75
+ )
76
+
77
+ // Type exports for consumers
78
+ export type RecordComment = typeof recordComments.$inferSelect
79
+ export type NewRecordComment = typeof recordComments.$inferInsert
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 ESSENTIAL SERVICES
3
+ *
4
+ * This source code is licensed under the Business Source License 1.1
5
+ * found in the LICENSE.md file in the root directory of this source tree.
6
+ */
7
+
8
+ export * from '../../auth/better-auth/schema'
9
+ export * from './schema/migration-audit'
10
+ export * from './schema/activity-log'
11
+ export * from './schema/analytics-page-views'
12
+ export * from './schema/record-comments'