@beechcms/api 0.5.0 → 0.6.0-preview.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 (225) hide show
  1. package/assets/dashboard/BeechLogo.svg +18 -18
  2. package/assets/dashboard/BeechLogoLIght.svg +48 -48
  3. package/assets/dashboard/Searching.svg +1 -0
  4. package/assets/dashboard/assets/chart-BrJFdsGZ.js +39 -0
  5. package/assets/dashboard/assets/index-CIaoMxuB.css +1 -0
  6. package/assets/dashboard/assets/index-wTKgygsg.js +636 -0
  7. package/assets/dashboard/assets/pie-chart-recharts-BEaE1FOE.js +1 -0
  8. package/assets/dashboard/assets/timeseries-chart-recharts-DmWM6imF.js +1 -0
  9. package/assets/dashboard/beechLogoDark.svg +48 -48
  10. package/assets/dashboard/index.html +18 -18
  11. package/assets/dashboard/noResult.svg +43 -0
  12. package/assets/dashboard/sol.svg +3 -3
  13. package/assets/dashboard/undraw_enter_nwx3.svg +36 -36
  14. package/assets/dashboard/working.svg +1 -0
  15. package/migrations/0000_v040_base.sql +265 -238
  16. package/migrations/0029_automations.sql +14 -14
  17. package/migrations/0030_test_seeds.sql +125 -125
  18. package/package.json +13 -9
  19. package/src/auth/{in-memory-hash-provider.ts → __fixtures__/in-memory-hash-provider.ts} +17 -13
  20. package/src/auth/{static-token-service.ts → __fixtures__/static-token-service.ts} +22 -18
  21. package/src/auth/bcrypt-hash-provider.ts +24 -20
  22. package/src/auth/constants.ts +14 -10
  23. package/src/auth/generate-refresh-token.test.ts +23 -19
  24. package/src/auth/hash-provider.test.ts +55 -46
  25. package/src/auth/jose-token-service.ts +62 -55
  26. package/src/auth/jwt-claims-passthrough.test.ts +87 -0
  27. package/src/auth/login.test.ts +100 -92
  28. package/src/auth/login.ts +78 -74
  29. package/src/auth/refresh.ts +11 -5
  30. package/src/auth/token-service.test.ts +90 -82
  31. package/src/factory.ts +370 -347
  32. package/src/features/automations/__tests__/action-executors.test.ts +255 -268
  33. package/src/features/automations/__tests__/automation-runner.test.ts +196 -192
  34. package/src/features/automations/__tests__/automation-runner.utils.test.ts +60 -56
  35. package/src/features/automations/__tests__/automations.handler.test.ts +264 -260
  36. package/src/features/automations/__tests__/automations.repository.test.ts +163 -159
  37. package/src/features/automations/__tests__/automations.schema.test.ts +224 -134
  38. package/src/features/automations/__tests__/context-resolver.test.ts +126 -122
  39. package/src/features/automations/__tests__/cron-runner.test.ts +267 -263
  40. package/src/features/automations/__tests__/cron-runner.utils.test.ts +144 -140
  41. package/src/features/automations/__tests__/set-variable.executor.test.ts +383 -306
  42. package/src/features/automations/__tests__/template-grammar.test.ts +308 -304
  43. package/src/features/automations/__tests__/webhook.executor.test.ts +142 -0
  44. package/src/features/automations/__tests__/when-evaluator.test.ts +274 -270
  45. package/src/features/automations/__tests__/when-pushdown.test.ts +281 -277
  46. package/src/features/automations/action-executors/create-entry.executor.ts +27 -23
  47. package/src/features/automations/action-executors/edit-field.executor.ts +26 -22
  48. package/src/features/automations/action-executors/index.ts +37 -33
  49. package/src/features/automations/action-executors/send-mail.executor.ts +53 -42
  50. package/src/features/automations/action-executors/set-variable.executor.ts +159 -146
  51. package/src/features/automations/action-executors/webhook.executor.ts +67 -25
  52. package/src/features/automations/automation-runner.ts +85 -81
  53. package/src/features/automations/automation-runner.utils.ts +47 -43
  54. package/src/features/automations/automations.handler.ts +197 -193
  55. package/src/features/automations/automations.schema.ts +177 -160
  56. package/src/features/automations/context-resolver.ts +152 -148
  57. package/src/features/automations/cron-runner.ts +140 -136
  58. package/src/features/automations/cron-runner.utils.ts +44 -40
  59. package/src/features/automations/filter-translation.ts +46 -42
  60. package/src/features/automations/index.ts +16 -12
  61. package/src/features/automations/template-grammar.ts +245 -241
  62. package/src/features/automations/var-access-resolver.ts +140 -136
  63. package/src/features/automations/when-evaluator.ts +87 -83
  64. package/src/features/automations/when-pushdown.ts +57 -53
  65. package/src/features/backrefs/__tests__/backrefs.handler.test.ts +359 -0
  66. package/src/features/backrefs/backrefs.handler.ts +168 -0
  67. package/src/features/backrefs/d1-backref.repository.ts +84 -0
  68. package/src/features/backrefs/index.ts +5 -0
  69. package/src/features/content/constants.ts +16 -10
  70. package/src/features/content/handlers/bulk.handler.ts +185 -0
  71. package/src/features/content/handlers/create.ts +129 -165
  72. package/src/features/content/handlers/delete.ts +62 -87
  73. package/src/features/content/handlers/facets.ts +49 -45
  74. package/src/features/content/handlers/get.ts +120 -116
  75. package/src/features/content/handlers/helpers.test.ts +180 -0
  76. package/src/features/content/handlers/helpers.ts +93 -0
  77. package/src/features/content/handlers/list.ts +174 -88
  78. package/src/features/content/handlers/update.ts +174 -219
  79. package/src/features/content/index.ts +26 -20
  80. package/src/features/dashboard-layout/__tests__/dashboard-layout.handler.test.ts +388 -0
  81. package/src/features/dashboard-layout/dashboard-layout.handler.ts +206 -0
  82. package/src/features/dashboard-layout/index.ts +5 -0
  83. package/src/features/draft/draft.handler.ts +195 -170
  84. package/src/features/draft/draft.middleware.ts +66 -62
  85. package/src/features/draft/index.ts +5 -1
  86. package/src/features/email/email.provider.ts +42 -38
  87. package/src/features/email/email.service.ts +98 -93
  88. package/src/features/email/email.types.ts +119 -108
  89. package/src/features/email/index.ts +33 -29
  90. package/src/features/email/providers/resend.ts +67 -63
  91. package/src/features/email/providers/smtp.ts +55 -0
  92. package/src/features/email/templates/automation-mail.ts +19 -15
  93. package/src/features/email/templates/password-changed.ts +63 -59
  94. package/src/features/email/templates/password-reset.ts +68 -64
  95. package/src/features/email/templates/shell.ts +96 -92
  96. package/src/features/notifications/index.ts +5 -1
  97. package/src/features/notifications/notifications.handler.ts +105 -101
  98. package/src/features/password-reset/index.ts +19 -15
  99. package/src/features/password-reset/request.ts +92 -82
  100. package/src/features/password-reset/reset.ts +102 -92
  101. package/src/features/rotate-field/index.ts +5 -1
  102. package/src/features/rotate-field/rotate-field.handler.ts +132 -128
  103. package/src/features/rotate-field/rotate-field.schema.ts +17 -13
  104. package/src/features/schema/schema.handler.ts +131 -16
  105. package/src/features/seeds/index.ts +5 -0
  106. package/src/features/seeds/seeds.handler.test.ts +1199 -0
  107. package/src/features/seeds/seeds.handler.ts +558 -0
  108. package/src/features/settings/__tests__/settings.handler.test.ts +555 -0
  109. package/src/features/settings/settings.handler.ts +392 -302
  110. package/src/features/setup/index.ts +288 -91
  111. package/src/features/stats/index.ts +5 -1
  112. package/src/features/stats/stats.handler.ts +420 -430
  113. package/src/features/webhooks/index.ts +63 -0
  114. package/src/index.ts +65 -56
  115. package/src/media-utils.ts +82 -78
  116. package/src/middleware/auth-providers.middleware.test.ts +85 -0
  117. package/src/middleware/auth-providers.middleware.ts +45 -32
  118. package/src/middleware/observability.middleware.test.ts +93 -0
  119. package/src/middleware/observability.middleware.ts +70 -52
  120. package/src/middleware/rate-limit.middleware.ts +45 -41
  121. package/src/middleware/repository.middleware.ts +117 -91
  122. package/src/middleware/seed-registry.middleware.test.ts +97 -0
  123. package/src/middleware/seed-registry.middleware.ts +21 -0
  124. package/src/middleware/storage.middleware.ts +25 -21
  125. package/src/middleware.ts +45 -47
  126. package/src/public/access-policy.ts +27 -23
  127. package/src/public/api-key-middleware.ts +57 -53
  128. package/src/public/cache-utils.ts +38 -34
  129. package/src/public/entry-projection.ts +46 -42
  130. package/src/public/idempotency.ts +23 -19
  131. package/src/public/index.ts +16 -12
  132. package/src/public/problem-details.ts +124 -53
  133. package/src/public/public-add.ts +114 -110
  134. package/src/public/public-edit.ts +163 -159
  135. package/src/public/public-errors.ts +19 -15
  136. package/src/public/public-read.ts +63 -59
  137. package/src/public/public-routes.ts +88 -84
  138. package/src/public/query-builder.test.ts +224 -220
  139. package/src/public/query-builder.ts +156 -152
  140. package/src/public/rate-limit-middleware.ts +34 -30
  141. package/src/public/read-list.ts +54 -50
  142. package/src/public/read-single.ts +48 -44
  143. package/src/public/response-builder.ts +30 -26
  144. package/src/public/sanitize.ts +69 -65
  145. package/src/public/slug-utils.ts +18 -14
  146. package/src/rate-limit/cloudflare-rate-limiter.test.ts +30 -26
  147. package/src/rate-limit/cloudflare-rate-limiter.ts +15 -11
  148. package/src/rate-limit/in-memory-rate-limiter.test.ts +37 -33
  149. package/src/rate-limit/in-memory-rate-limiter.ts +17 -13
  150. package/src/rate-limit/no-op-rate-limiter.test.ts +22 -18
  151. package/src/rate-limit/no-op-rate-limiter.ts +11 -7
  152. package/src/search-utils.test.ts +211 -207
  153. package/src/search-utils.ts +213 -209
  154. package/src/search.ts +65 -61
  155. package/src/shared/apply-policies.test.ts +81 -77
  156. package/src/shared/apply-policies.ts +67 -63
  157. package/src/shared/automations.repository.d1.ts +150 -146
  158. package/src/shared/background-notification-service.test.ts +62 -58
  159. package/src/shared/background-notification-service.ts +52 -48
  160. package/src/shared/base.repository.d1.ts +32 -28
  161. package/src/shared/content-utils.test.ts +165 -161
  162. package/src/shared/content-utils.ts +86 -82
  163. package/src/shared/content.repository.d1.test.ts +507 -312
  164. package/src/shared/content.repository.d1.ts +851 -382
  165. package/src/shared/d1-activity-log.repository.test.ts +140 -136
  166. package/src/shared/d1-activity-log.repository.ts +105 -101
  167. package/src/shared/d1-activity-logger.test.ts +86 -82
  168. package/src/shared/d1-activity-logger.ts +67 -63
  169. package/src/shared/d1-analytics.repository.test.ts +78 -74
  170. package/src/shared/d1-analytics.repository.ts +85 -81
  171. package/src/shared/d1-content-scan.repository.test.ts +80 -76
  172. package/src/shared/d1-content-scan.repository.ts +37 -29
  173. package/src/shared/d1-notification.repository.test.ts +128 -124
  174. package/src/shared/d1-notification.repository.ts +118 -114
  175. package/src/shared/d1-password-reset-token.repository.test.ts +81 -77
  176. package/src/shared/d1-password-reset-token.repository.ts +56 -52
  177. package/src/shared/d1-search.repository.test.ts +87 -83
  178. package/src/shared/d1-search.repository.ts +88 -84
  179. package/src/shared/d1-session.repository.test.ts +125 -121
  180. package/src/shared/d1-session.repository.ts +102 -98
  181. package/src/shared/d1-setup-checklist.repository.ts +36 -0
  182. package/src/shared/d1-user.repository.test.ts +151 -147
  183. package/src/shared/d1-user.repository.ts +119 -109
  184. package/src/shared/d1-widget.repository.test.ts +267 -217
  185. package/src/shared/d1-widget.repository.ts +385 -337
  186. package/src/shared/dashboard-layout.repository.d1.test.ts +135 -0
  187. package/src/shared/dashboard-layout.repository.d1.ts +58 -0
  188. package/src/shared/demo-data-sql.ts +216 -0
  189. package/src/shared/demo-data.repository.d1.ts +20 -0
  190. package/src/shared/execution-context-scheduler.ts +13 -9
  191. package/src/shared/fixed-clock.ts +25 -21
  192. package/src/shared/fts-sync.ts +8 -4
  193. package/src/shared/idempotency.repository.d1.test.ts +83 -79
  194. package/src/shared/idempotency.repository.d1.ts +60 -56
  195. package/src/shared/in-memory-activity-logger.ts +19 -15
  196. package/src/shared/in-memory-notification-service.ts +19 -15
  197. package/src/shared/in-memory-seed.repository.ts +58 -0
  198. package/src/shared/media.repository.d1.test.ts +107 -103
  199. package/src/shared/media.repository.d1.ts +68 -64
  200. package/src/shared/qstash-notification-service.test.ts +67 -0
  201. package/src/shared/qstash-notification-service.ts +55 -0
  202. package/src/shared/query-utils.ts +141 -137
  203. package/src/shared/request-utils.ts +26 -22
  204. package/src/shared/schema-mutator.d1.test.ts +142 -0
  205. package/src/shared/schema-mutator.d1.ts +64 -0
  206. package/src/shared/seed-layout.repository.d1.test.ts +114 -0
  207. package/src/shared/seed-layout.repository.d1.ts +62 -0
  208. package/src/shared/seed-registry-cache.test.ts +68 -0
  209. package/src/shared/seed-registry-cache.ts +49 -0
  210. package/src/shared/seed.repository.d1.test.ts +143 -0
  211. package/src/shared/seed.repository.d1.ts +98 -0
  212. package/src/shared/sequential-id-generator.ts +33 -22
  213. package/src/shared/site-settings.repository.d1.ts +53 -0
  214. package/src/shared/storage/factory.ts +41 -40
  215. package/src/shared/storage/s3-bucket.ts +195 -163
  216. package/src/shared/storage-utils.ts +40 -36
  217. package/src/shared/system-stats.repository.d1.test.ts +58 -54
  218. package/src/shared/system-stats.repository.d1.ts +48 -44
  219. package/src/types.ts +90 -67
  220. package/src/upload.ts +198 -187
  221. package/src/widget.test.ts +85 -0
  222. package/src/widget.ts +251 -208
  223. package/assets/dashboard/assets/index-B1mUfgiK.css +0 -1
  224. package/assets/dashboard/assets/index-CHxxc_id.js +0 -629
  225. package/src/shared/storage/r2-binding-bucket.ts +0 -81
@@ -0,0 +1,135 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
+ // See LICENSE in the repository root for license terms.
4
+
5
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
6
+ import { D1DashboardLayoutRepository } from './dashboard-layout.repository.d1'
7
+ import type { DashboardLayout } from '@beechcms/core'
8
+
9
+ function makeMockDb(opts: { firstResult?: unknown; allResults?: unknown[] } = {}) {
10
+ const { firstResult = null, allResults = [] } = opts
11
+ const runMock = vi.fn().mockResolvedValue({ success: true })
12
+ const firstMock = vi.fn().mockResolvedValue(firstResult)
13
+ const allMock = vi.fn().mockResolvedValue({ results: allResults })
14
+ const bindMock = vi.fn(() => ({ run: runMock, first: firstMock, all: allMock }))
15
+ const stmt = { bind: bindMock, run: runMock, first: firstMock, all: allMock }
16
+ const prepareMock = vi.fn(() => stmt)
17
+ return { db: { prepare: prepareMock } as any, prepareMock, bindMock, runMock, firstMock, allMock }
18
+ }
19
+
20
+ const sampleLayout: DashboardLayout = {
21
+ version: 1,
22
+ pages: [
23
+ {
24
+ id: 'page-1',
25
+ slug: 'overview',
26
+ label: 'Overview',
27
+ sections: [
28
+ {
29
+ id: 'section-1',
30
+ columns: [{ id: 'col-1', widgets: [] }],
31
+ },
32
+ ],
33
+ },
34
+ ],
35
+ }
36
+
37
+ describe('D1DashboardLayoutRepository', () => {
38
+ beforeEach(() => {
39
+ vi.useFakeTimers()
40
+ })
41
+
42
+ afterEach(() => {
43
+ vi.useRealTimers()
44
+ })
45
+
46
+ describe('get', () => {
47
+ it('returns null when the layout is not found', async () => {
48
+ const { db } = makeMockDb({ firstResult: null })
49
+ const repo = new D1DashboardLayoutRepository(db)
50
+ const res = await repo.get('default')
51
+ expect(res).toBeNull()
52
+ })
53
+
54
+ it('returns mapped record when layout is found and layout JSON is parsed', async () => {
55
+ const row = {
56
+ scope: 'default',
57
+ layout: JSON.stringify(sampleLayout),
58
+ updated_at: 123456,
59
+ updated_by: 'admin-user',
60
+ }
61
+ const { db, prepareMock, bindMock } = makeMockDb({ firstResult: row })
62
+ const repo = new D1DashboardLayoutRepository(db)
63
+
64
+ const res = await repo.get('default')
65
+ expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining('SELECT scope, layout, updated_at, updated_by FROM dashboard_layouts'))
66
+ expect(bindMock).toHaveBeenCalledWith('default')
67
+ expect(res).toEqual({
68
+ scope: 'default',
69
+ layout: sampleLayout,
70
+ updatedAt: 123456,
71
+ updatedBy: 'admin-user',
72
+ })
73
+ })
74
+
75
+ it('returns null without throwing when the stored layout JSON is corrupt', async () => {
76
+ const row = {
77
+ scope: 'default',
78
+ layout: '{invalid-json',
79
+ updated_at: 123456,
80
+ updated_by: 'admin-user',
81
+ }
82
+ const { db } = makeMockDb({ firstResult: row })
83
+ const repo = new D1DashboardLayoutRepository(db)
84
+
85
+ const res = await repo.get('default')
86
+ expect(res).toBeNull()
87
+ })
88
+ })
89
+
90
+ describe('listScopes', () => {
91
+ it('returns an empty array when there are no rows', async () => {
92
+ const { db } = makeMockDb({ allResults: [] })
93
+ const repo = new D1DashboardLayoutRepository(db)
94
+ const scopes = await repo.listScopes()
95
+ expect(scopes).toEqual([])
96
+ })
97
+
98
+ it('returns the stored scopes', async () => {
99
+ const allResults = [{ scope: 'default' }, { scope: 'role:admin' }]
100
+ const { db, prepareMock } = makeMockDb({ allResults })
101
+ const repo = new D1DashboardLayoutRepository(db)
102
+
103
+ const scopes = await repo.listScopes()
104
+ expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining('SELECT scope FROM dashboard_layouts'))
105
+ expect(scopes).toEqual(['default', 'role:admin'])
106
+ })
107
+ })
108
+
109
+ describe('upsert', () => {
110
+ it('prepares and binds the correct layout JSON and timestamp', async () => {
111
+ const mockDate = new Date('2026-06-04T12:00:00Z')
112
+ vi.setSystemTime(mockDate)
113
+ const expectedTimestamp = Math.floor(mockDate.getTime() / 1000)
114
+
115
+ const { db, prepareMock, bindMock } = makeMockDb()
116
+ const repo = new D1DashboardLayoutRepository(db)
117
+
118
+ await repo.upsert('default', sampleLayout, 'admin-1')
119
+
120
+ expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO dashboard_layouts'))
121
+ expect(bindMock).toHaveBeenCalledWith('default', JSON.stringify(sampleLayout), expectedTimestamp, 'admin-1')
122
+ })
123
+ })
124
+
125
+ describe('remove', () => {
126
+ it('deletes the layout by scope', async () => {
127
+ const { db, prepareMock, bindMock } = makeMockDb()
128
+ const repo = new D1DashboardLayoutRepository(db)
129
+
130
+ await repo.remove('default')
131
+ expect(prepareMock).toHaveBeenCalledWith(expect.stringContaining('DELETE FROM dashboard_layouts WHERE scope = ?'))
132
+ expect(bindMock).toHaveBeenCalledWith('default')
133
+ })
134
+ })
135
+ })
@@ -0,0 +1,58 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
+ // See LICENSE in the repository root for license terms.
4
+
5
+ /// <reference types="@cloudflare/workers-types" />
6
+ import type { IDashboardLayoutRepository, DashboardLayoutRecord, DashboardLayout } from '@beechcms/core'
7
+
8
+ export class D1DashboardLayoutRepository implements IDashboardLayoutRepository {
9
+ constructor(private readonly db: D1Database) {}
10
+
11
+ async get(scope: string): Promise<DashboardLayoutRecord | null> {
12
+ const row = await this.db
13
+ .prepare('SELECT scope, layout, updated_at, updated_by FROM dashboard_layouts WHERE scope = ? LIMIT 1')
14
+ .bind(scope)
15
+ .first<{ scope: string; layout: string; updated_at: number; updated_by: string }>()
16
+ if (!row) return null
17
+ try {
18
+ return {
19
+ scope: row.scope,
20
+ layout: JSON.parse(row.layout) as DashboardLayout,
21
+ updatedAt: row.updated_at,
22
+ updatedBy: row.updated_by,
23
+ }
24
+ } catch {
25
+ return null
26
+ }
27
+ }
28
+
29
+ async listScopes(): Promise<string[]> {
30
+ const rs = await this.db
31
+ .prepare('SELECT scope FROM dashboard_layouts')
32
+ .all<{ scope: string }>()
33
+ return (rs.results ?? []).map((r) => r.scope)
34
+ }
35
+
36
+ async upsert(scope: string, layout: DashboardLayout, updatedBy: string): Promise<void> {
37
+ const json = JSON.stringify(layout)
38
+ const now = Math.floor(Date.now() / 1000)
39
+ await this.db
40
+ .prepare(`
41
+ INSERT INTO dashboard_layouts (scope, layout, updated_at, updated_by)
42
+ VALUES (?, ?, ?, ?)
43
+ ON CONFLICT(scope) DO UPDATE SET
44
+ layout = excluded.layout,
45
+ updated_at = excluded.updated_at,
46
+ updated_by = excluded.updated_by
47
+ `)
48
+ .bind(scope, json, now, updatedBy)
49
+ .run()
50
+ }
51
+
52
+ async remove(scope: string): Promise<void> {
53
+ await this.db
54
+ .prepare('DELETE FROM dashboard_layouts WHERE scope = ?')
55
+ .bind(scope)
56
+ .run()
57
+ }
58
+ }
@@ -0,0 +1,216 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+
4
+ export const DEMO_DATA_SQL = `
5
+ INSERT OR IGNORE INTO content_clienti (id, slug, status, name, email, company, tier, account_status, mrr, created_at, updated_at)
6
+ VALUES
7
+ ('clt-0001', 'customer-1', 'published', 'Anna Rossi', 'anna.rossi@example.com', 'Beta Systems', 'free', 'active', 0, 1779795635, 1779795635),
8
+ ('clt-0002', 'customer-2', 'published', 'Marco Bruno', 'marco.bruno@example.com', 'DataSync', 'enterprise', 'active', 551, 1776454206, 1776454206),
9
+ ('clt-0003', 'customer-3', 'published', 'Giulia Rossi', 'giulia.rossi@example.com', 'NextGen IT', 'free', 'active', 0, 1778487018, 1778487018),
10
+ ('clt-0004', 'customer-4', 'published', 'Luca Rossi', 'luca.rossi@example.com', 'Beta Systems', 'free', 'active', 0, 1776735015, 1776735015),
11
+ ('clt-0005', 'customer-5', 'published', 'Luca Colombo', 'luca.colombo@example.com', 'Nova Labs', 'free', 'active', 0, 1779238418, 1779238418),
12
+ ('clt-0006', 'customer-6', 'published', 'Matteo Bruno', 'matteo.bruno@example.com', 'GlobalNet', 'pro', 'active', 94, 1778652671, 1778652671),
13
+ ('clt-0007', 'customer-7', 'published', 'Giulia Marino', 'giulia.marino@example.com', 'TechFlow', 'pro', 'churned', 0, 1778533118, 1778533118),
14
+ ('clt-0008', 'customer-8', 'published', 'Matteo Esposito', 'matteo.esposito@example.com', 'Innova Solutions', 'free', 'active', 0, 1776239680, 1776239680),
15
+ ('clt-0009', 'customer-9', 'published', 'Marco Rossi', 'marco.rossi@example.com', 'Beta Systems', 'pro', 'active', 101, 1777739809, 1777739809),
16
+ ('clt-0010', 'customer-10', 'published', 'Luca Gallo', 'luca.gallo@example.com', 'NextGen IT', 'free', 'active', 0, 1776486131, 1776486131),
17
+ ('clt-0011', 'customer-11', 'published', 'Giulia Bruno', 'giulia.bruno@example.com', 'CloudBase', 'free', 'active', 0, 1780953641, 1780953641),
18
+ ('clt-0012', 'customer-12', 'published', 'Martina Marino', 'martina.marino@example.com', 'GlobalNet', 'free', 'churned', 0, 1778570992, 1778570992),
19
+ ('clt-0013', 'customer-13', 'published', 'Matteo Colombo', 'matteo.colombo@example.com', 'NextGen IT', 'free', 'churned', 0, 1780724573, 1780724573),
20
+ ('clt-0014', 'customer-14', 'published', 'Alessandro Ricci', 'alessandro.ricci@example.com', 'Alpha Dynamics', 'free', 'active', 0, 1776113837, 1776113837),
21
+ ('clt-0015', 'customer-15', 'published', 'Anna Greco', 'anna.greco@example.com', 'Acme Corp', 'pro', 'active', 133, 1780583015, 1780583015),
22
+ ('clt-0016', 'customer-16', 'published', 'Anna Gallo', 'anna.gallo@example.com', 'Nova Labs', 'free', 'churned', 0, 1779981685, 1779981685),
23
+ ('clt-0017', 'customer-17', 'published', 'Giulia Esposito', 'giulia.esposito@example.com', 'CloudBase', 'free', 'active', 0, 1776530341, 1776530341),
24
+ ('clt-0018', 'customer-18', 'published', 'Sofia Romano', 'sofia.romano@example.com', 'Alpha Dynamics', 'pro', 'active', 78, 1778027576, 1778027576),
25
+ ('clt-0019', 'customer-19', 'published', 'Luca Ricci', 'luca.ricci@example.com', 'Nova Labs', 'enterprise', 'active', 1883, 1781250380, 1781250380),
26
+ ('clt-0020', 'customer-20', 'published', 'Marco Bruno', 'marco.bruno@example.com', 'Innova Solutions', 'pro', 'active', 140, 1776541561, 1776541561),
27
+ ('clt-0021', 'customer-21', 'published', 'Giulia Romano', 'giulia.romano@example.com', 'Alpha Dynamics', 'free', 'active', 0, 1781043838, 1781043838),
28
+ ('clt-0022', 'customer-22', 'published', 'Sofia Romano', 'sofia.romano@example.com', 'GlobalNet', 'enterprise', 'active', 1212, 1776576892, 1776576892),
29
+ ('clt-0023', 'customer-23', 'published', 'Marco Esposito', 'marco.esposito@example.com', 'Innova Solutions', 'pro', 'churned', 0, 1777718792, 1777718792),
30
+ ('clt-0024', 'customer-24', 'published', 'Francesca Colombo', 'francesca.colombo@example.com', 'GlobalNet', 'free', 'active', 0, 1778358033, 1778358033),
31
+ ('clt-0025', 'customer-25', 'published', 'Sofia Rossi', 'sofia.rossi@example.com', 'Beta Systems', 'free', 'active', 0, 1780759797, 1780759797),
32
+ ('clt-0026', 'customer-26', 'published', 'Sofia Romano', 'sofia.romano@example.com', 'DataSync', 'enterprise', 'active', 1212, 1776537213, 1776537213),
33
+ ('clt-0027', 'customer-27', 'published', 'Martina Esposito', 'martina.esposito@example.com', 'Beta Systems', 'enterprise', 'active', 809, 1780535965, 1780535965),
34
+ ('clt-0028', 'customer-28', 'published', 'Sofia Gallo', 'sofia.gallo@example.com', 'Beta Systems', 'enterprise', 'active', 570, 1777219375, 1777219375),
35
+ ('clt-0029', 'customer-29', 'published', 'Alessandro Marino', 'alessandro.marino@example.com', 'Acme Corp', 'pro', 'active', 52, 1776762582, 1776762582),
36
+ ('clt-0030', 'customer-30', 'published', 'Anna Gallo', 'anna.gallo@example.com', 'Alpha Dynamics', 'pro', 'active', 143, 1777369926, 1777369926),
37
+ ('clt-0031', 'customer-31', 'published', 'Matteo Bruno', 'matteo.bruno@example.com', 'TechFlow', 'free', 'active', 0, 1778360883, 1778360883),
38
+ ('clt-0032', 'customer-32', 'published', 'Matteo Ricci', 'matteo.ricci@example.com', 'CloudBase', 'pro', 'active', 142, 1776266895, 1776266895),
39
+ ('clt-0033', 'customer-33', 'published', 'Sofia Marino', 'sofia.marino@example.com', 'GlobalNet', 'pro', 'active', 139, 1778387056, 1778387056),
40
+ ('clt-0034', 'customer-34', 'published', 'Lorenzo Colombo', 'lorenzo.colombo@example.com', 'DataSync', 'free', 'active', 0, 1779139259, 1779139259),
41
+ ('clt-0035', 'customer-35', 'published', 'Giulia Marino', 'giulia.marino@example.com', 'CloudBase', 'pro', 'active', 138, 1780593486, 1780593486),
42
+ ('clt-0036', 'customer-36', 'published', 'Sofia Esposito', 'sofia.esposito@example.com', 'GlobalNet', 'enterprise', 'active', 727, 1776372158, 1776372158),
43
+ ('clt-0037', 'customer-37', 'published', 'Martina Bruno', 'martina.bruno@example.com', 'Beta Systems', 'enterprise', 'active', 1628, 1778759491, 1778759491),
44
+ ('clt-0038', 'customer-38', 'published', 'Luca Bruno', 'luca.bruno@example.com', 'NextGen IT', 'enterprise', 'active', 1388, 1780282199, 1780282199),
45
+ ('clt-0039', 'customer-39', 'published', 'Giulia Marino', 'giulia.marino@example.com', 'Beta Systems', 'pro', 'active', 80, 1779589290, 1779589290),
46
+ ('clt-0040', 'customer-40', 'published', 'Luca Bruno', 'luca.bruno@example.com', 'NextGen IT', 'free', 'churned', 0, 1776195866, 1776195866),
47
+ ('clt-0041', 'customer-41', 'published', 'Anna Bruno', 'anna.bruno@example.com', 'Beta Systems', 'pro', 'active', 150, 1779519119, 1779519119),
48
+ ('clt-0042', 'customer-42', 'published', 'Luca Bianchi', 'luca.bianchi@example.com', 'Acme Corp', 'enterprise', 'active', 737, 1780125342, 1780125342),
49
+ ('clt-0043', 'customer-43', 'published', 'Sofia Bruno', 'sofia.bruno@example.com', 'NextGen IT', 'pro', 'active', 119, 1780182487, 1780182487),
50
+ ('clt-0044', 'customer-44', 'published', 'Lorenzo Bruno', 'lorenzo.bruno@example.com', 'Alpha Dynamics', 'free', 'active', 0, 1779137990, 1779137990),
51
+ ('clt-0045', 'customer-45', 'published', 'Matteo Esposito', 'matteo.esposito@example.com', 'DataSync', 'free', 'active', 0, 1780762196, 1780762196),
52
+ ('clt-0046', 'customer-46', 'published', 'Marco Gallo', 'marco.gallo@example.com', 'Nova Labs', 'enterprise', 'active', 1453, 1780405154, 1780405154),
53
+ ('clt-0047', 'customer-47', 'published', 'Luca Romano', 'luca.romano@example.com', 'DataSync', 'free', 'active', 0, 1780954461, 1780954461),
54
+ ('clt-0048', 'customer-48', 'published', 'Marco Ricci', 'marco.ricci@example.com', 'Acme Corp', 'free', 'active', 0, 1778854876, 1778854876),
55
+ ('clt-0049', 'customer-49', 'published', 'Lorenzo Ricci', 'lorenzo.ricci@example.com', 'TechFlow', 'enterprise', 'active', 1889, 1778914952, 1778914952),
56
+ ('clt-0050', 'customer-50', 'published', 'Giulia Ricci', 'giulia.ricci@example.com', 'Beta Systems', 'pro', 'active', 82, 1779858975, 1779858975);
57
+
58
+ INSERT OR IGNORE INTO content_abbonamenti (id, slug, status, customer_id, amount, billing_cycle, payment_status, created_at, updated_at)
59
+ VALUES
60
+ ('sub-0001', 'sub-1', 'published', 'clt-0050', 142, 'monthly', 'active', 1780216609, 1780216609),
61
+ ('sub-0002', 'sub-2', 'published', 'clt-0050', 81, 'monthly', 'active', 1781344231, 1781344231),
62
+ ('sub-0003', 'sub-3', 'published', 'clt-0044', 0, 'annual', 'active', 1779906618, 1779906618),
63
+ ('sub-0004', 'sub-4', 'published', 'clt-0020', 127, 'monthly', 'active', 1776721859, 1776721859),
64
+ ('sub-0005', 'sub-5', 'published', 'clt-0042', 600, 'monthly', 'active', 1780763124, 1780763124),
65
+ ('sub-0006', 'sub-6', 'published', 'clt-0032', 67, 'monthly', 'active', 1776865001, 1776865001),
66
+ ('sub-0007', 'sub-7', 'published', 'clt-0002', 1078, 'monthly', 'active', 1777936327, 1777936327),
67
+ ('sub-0008', 'sub-8', 'published', 'clt-0002', 1757, 'monthly', 'active', 1776735383, 1776735383),
68
+ ('sub-0009', 'sub-9', 'published', 'clt-0021', 0, 'monthly', 'active', 1782738413, 1782738413),
69
+ ('sub-0010', 'sub-10', 'published', 'clt-0049', 1426, 'annual', 'active', 1779618457, 1779618457),
70
+ ('sub-0011', 'sub-11', 'published', 'clt-0038', 1304, 'annual', 'active', 1780843746, 1780843746),
71
+ ('sub-0012', 'sub-12', 'published', 'clt-0035', 106, 'monthly', 'active', 1782023174, 1782023174),
72
+ ('sub-0013', 'sub-13', 'published', 'clt-0013', 0, 'monthly', 'canceled', 1783068575, 1783068575),
73
+ ('sub-0014', 'sub-14', 'published', 'clt-0048', 0, 'monthly', 'active', 1779252007, 1779252007),
74
+ ('sub-0015', 'sub-15', 'published', 'clt-0034', 0, 'monthly', 'active', 1781382334, 1781382334),
75
+ ('sub-0016', 'sub-16', 'published', 'clt-0028', 625, 'monthly', 'active', 1779346600, 1779346600),
76
+ ('sub-0017', 'sub-17', 'published', 'clt-0040', 0, 'monthly', 'canceled', 1777921191, 1777921191),
77
+ ('sub-0018', 'sub-18', 'published', 'clt-0034', 0, 'monthly', 'active', 1779909275, 1779909275),
78
+ ('sub-0019', 'sub-19', 'published', 'clt-0021', 0, 'monthly', 'active', 1783164658, 1783164658),
79
+ ('sub-0020', 'sub-20', 'published', 'clt-0003', 0, 'monthly', 'active', 1779668082, 1779668082),
80
+ ('sub-0021', 'sub-21', 'published', 'clt-0038', 1133, 'annual', 'active', 1780677965, 1780677965),
81
+ ('sub-0022', 'sub-22', 'published', 'clt-0020', 75, 'monthly', 'active', 1776846702, 1776846702),
82
+ ('sub-0023', 'sub-23', 'published', 'clt-0027', 556, 'annual', 'active', 1782404111, 1782404111),
83
+ ('sub-0024', 'sub-24', 'published', 'clt-0023', 98, 'monthly', 'canceled', 1779457981, 1779457981),
84
+ ('sub-0025', 'sub-25', 'published', 'clt-0034', 0, 'monthly', 'active', 1779355311, 1779355311),
85
+ ('sub-0026', 'sub-26', 'published', 'clt-0043', 60, 'annual', 'active', 1782541120, 1782541120),
86
+ ('sub-0027', 'sub-27', 'published', 'clt-0021', 0, 'monthly', 'active', 1782468720, 1782468720),
87
+ ('sub-0028', 'sub-28', 'published', 'clt-0013', 0, 'annual', 'canceled', 1781775638, 1781775638),
88
+ ('sub-0029', 'sub-29', 'published', 'clt-0008', 0, 'monthly', 'active', 1777567668, 1777567668),
89
+ ('sub-0030', 'sub-30', 'published', 'clt-0047', 0, 'annual', 'active', 1782178899, 1782178899),
90
+ ('sub-0031', 'sub-31', 'published', 'clt-0027', 968, 'annual', 'past_due', 1781009528, 1781009528),
91
+ ('sub-0032', 'sub-32', 'published', 'clt-0030', 120, 'monthly', 'active', 1778888661, 1778888661),
92
+ ('sub-0033', 'sub-33', 'published', 'clt-0002', 1534, 'monthly', 'active', 1777236737, 1777236737),
93
+ ('sub-0034', 'sub-34', 'published', 'clt-0028', 844, 'monthly', 'active', 1778929352, 1778929352),
94
+ ('sub-0035', 'sub-35', 'published', 'clt-0021', 0, 'annual', 'active', 1783503541, 1783503541),
95
+ ('sub-0036', 'sub-36', 'published', 'clt-0005', 0, 'monthly', 'active', 1779400054, 1779400054),
96
+ ('sub-0037', 'sub-37', 'published', 'clt-0037', 1314, 'monthly', 'past_due', 1780839395, 1780839395),
97
+ ('sub-0038', 'sub-38', 'published', 'clt-0035', 81, 'monthly', 'active', 1780940050, 1780940050),
98
+ ('sub-0039', 'sub-39', 'published', 'clt-0016', 0, 'annual', 'canceled', 1781058329, 1781058329),
99
+ ('sub-0040', 'sub-40', 'published', 'clt-0005', 0, 'monthly', 'active', 1781557050, 1781557050),
100
+ ('sub-0041', 'sub-41', 'published', 'clt-0012', 0, 'monthly', 'canceled', 1780538305, 1780538305),
101
+ ('sub-0042', 'sub-42', 'published', 'clt-0008', 0, 'monthly', 'active', 1777247422, 1777247422),
102
+ ('sub-0043', 'sub-43', 'published', 'clt-0011', 0, 'monthly', 'active', 1781538412, 1781538412),
103
+ ('sub-0044', 'sub-44', 'published', 'clt-0002', 1450, 'monthly', 'active', 1777735024, 1777735024),
104
+ ('sub-0045', 'sub-45', 'published', 'clt-0011', 0, 'monthly', 'active', 1781429208, 1781429208),
105
+ ('sub-0046', 'sub-46', 'published', 'clt-0026', 1082, 'monthly', 'active', 1778434591, 1778434591),
106
+ ('sub-0047', 'sub-47', 'published', 'clt-0009', 104, 'annual', 'active', 1779420718, 1779420718),
107
+ ('sub-0048', 'sub-48', 'published', 'clt-0034', 0, 'annual', 'active', 1781556102, 1781556102),
108
+ ('sub-0049', 'sub-49', 'published', 'clt-0034', 0, 'monthly', 'active', 1781203450, 1781203450),
109
+ ('sub-0050', 'sub-50', 'published', 'clt-0043', 52, 'monthly', 'active', 1781479399, 1781479399),
110
+ ('sub-0051', 'sub-51', 'published', 'clt-0016', 0, 'annual', 'canceled', 1780395612, 1780395612),
111
+ ('sub-0052', 'sub-52', 'published', 'clt-0031', 0, 'monthly', 'active', 1780819829, 1780819829),
112
+ ('sub-0053', 'sub-53', 'published', 'clt-0016', 0, 'annual', 'canceled', 1780069008, 1780069008),
113
+ ('sub-0054', 'sub-54', 'published', 'clt-0034', 0, 'monthly', 'active', 1781183840, 1781183840),
114
+ ('sub-0055', 'sub-55', 'published', 'clt-0033', 107, 'annual', 'active', 1779357037, 1779357037),
115
+ ('sub-0056', 'sub-56', 'published', 'clt-0012', 0, 'monthly', 'canceled', 1780153989, 1780153989),
116
+ ('sub-0057', 'sub-57', 'published', 'clt-0019', 1202, 'monthly', 'active', 1781693473, 1781693473),
117
+ ('sub-0058', 'sub-58', 'published', 'clt-0048', 0, 'monthly', 'active', 1779719999, 1779719999),
118
+ ('sub-0059', 'sub-59', 'published', 'clt-0043', 134, 'monthly', 'active', 1781338609, 1781338609),
119
+ ('sub-0060', 'sub-60', 'published', 'clt-0015', 129, 'monthly', 'active', 1781057283, 1781057283),
120
+ ('sub-0061', 'sub-61', 'published', 'clt-0037', 1548, 'annual', 'active', 1779314897, 1779314897),
121
+ ('sub-0062', 'sub-62', 'published', 'clt-0014', 0, 'monthly', 'active', 1778027673, 1778027673),
122
+ ('sub-0063', 'sub-63', 'published', 'clt-0002', 1099, 'monthly', 'active', 1778331099, 1778331099),
123
+ ('sub-0064', 'sub-64', 'published', 'clt-0019', 1866, 'monthly', 'active', 1782682061, 1782682061),
124
+ ('sub-0065', 'sub-65', 'published', 'clt-0003', 0, 'annual', 'active', 1778965034, 1778965034),
125
+ ('sub-0066', 'sub-66', 'published', 'clt-0050', 136, 'monthly', 'active', 1780348385, 1780348385),
126
+ ('sub-0067', 'sub-67', 'published', 'clt-0019', 601, 'monthly', 'active', 1782308022, 1782308022),
127
+ ('sub-0068', 'sub-68', 'published', 'clt-0005', 0, 'annual', 'active', 1781034577, 1781034577),
128
+ ('sub-0069', 'sub-69', 'published', 'clt-0044', 0, 'annual', 'active', 1781141942, 1781141942),
129
+ ('sub-0070', 'sub-70', 'published', 'clt-0005', 0, 'annual', 'active', 1781742879, 1781742879),
130
+ ('sub-0071', 'sub-71', 'published', 'clt-0012', 0, 'monthly', 'canceled', 1779159909, 1779159909),
131
+ ('sub-0072', 'sub-72', 'published', 'clt-0039', 84, 'monthly', 'active', 1779966573, 1779966573),
132
+ ('sub-0073', 'sub-73', 'published', 'clt-0018', 64, 'annual', 'active', 1779025613, 1779025613),
133
+ ('sub-0074', 'sub-74', 'published', 'clt-0004', 0, 'monthly', 'active', 1778313010, 1778313010),
134
+ ('sub-0075', 'sub-75', 'published', 'clt-0012', 0, 'annual', 'canceled', 1779234346, 1779234346),
135
+ ('sub-0076', 'sub-76', 'published', 'clt-0026', 1842, 'monthly', 'active', 1778489634, 1778489634),
136
+ ('sub-0077', 'sub-77', 'published', 'clt-0044', 0, 'annual', 'active', 1779293869, 1779293869),
137
+ ('sub-0078', 'sub-78', 'published', 'clt-0018', 95, 'monthly', 'active', 1779243009, 1779243009),
138
+ ('sub-0079', 'sub-79', 'published', 'clt-0004', 0, 'monthly', 'active', 1777792773, 1777792773),
139
+ ('sub-0080', 'sub-80', 'published', 'clt-0034', 0, 'annual', 'active', 1780146104, 1780146104);
140
+
141
+ INSERT OR IGNORE INTO content_ticket (id, slug, status, title, customer_id, priority, category, ticket_status, created_at, updated_at)
142
+ VALUES
143
+ ('tkt-0001', 'tkt-1', 'published', 'Richiesta assistenza billing #1', 'clt-0041', 'medium', 'billing', 'closed', 1778788913, 1778788913),
144
+ ('tkt-0002', 'tkt-2', 'published', 'Richiesta assistenza technical #2', 'clt-0040', 'medium', 'technical', 'closed', 1776630524, 1776630524),
145
+ ('tkt-0003', 'tkt-3', 'published', 'Richiesta assistenza sales #3', 'clt-0015', 'high', 'sales', 'closed', 1780082450, 1780082450),
146
+ ('tkt-0004', 'tkt-4', 'published', 'Richiesta assistenza technical #4', 'clt-0007', 'high', 'technical', 'closed', 1778852958, 1778852958),
147
+ ('tkt-0005', 'tkt-5', 'published', 'Richiesta assistenza technical #5', 'clt-0022', 'medium', 'technical', 'closed', 1781006799, 1781006799),
148
+ ('tkt-0006', 'tkt-6', 'published', 'Richiesta assistenza sales #6', 'clt-0039', 'medium', 'sales', 'open', 1778599394, 1778599394),
149
+ ('tkt-0007', 'tkt-7', 'published', 'Richiesta assistenza billing #7', 'clt-0016', 'high', 'billing', 'closed', 1776731481, 1776731481),
150
+ ('tkt-0008', 'tkt-8', 'published', 'Richiesta assistenza technical #8', 'clt-0007', 'low', 'technical', 'closed', 1776564183, 1776564183),
151
+ ('tkt-0009', 'tkt-9', 'published', 'Richiesta assistenza billing #9', 'clt-0005', 'high', 'billing', 'closed', 1781170065, 1781170065),
152
+ ('tkt-0010', 'tkt-10', 'published', 'Richiesta assistenza technical #10', 'clt-0011', 'medium', 'technical', 'closed', 1779388832, 1779388832),
153
+ ('tkt-0011', 'tkt-11', 'published', 'Richiesta assistenza technical #11', 'clt-0028', 'medium', 'technical', 'closed', 1779409871, 1779409871),
154
+ ('tkt-0012', 'tkt-12', 'published', 'Richiesta assistenza sales #12', 'clt-0008', 'high', 'sales', 'closed', 1780758683, 1780758683),
155
+ ('tkt-0013', 'tkt-13', 'published', 'Richiesta assistenza technical #13', 'clt-0039', 'medium', 'technical', 'closed', 1778168019, 1778168019),
156
+ ('tkt-0014', 'tkt-14', 'published', 'Richiesta assistenza billing #14', 'clt-0029', 'low', 'billing', 'closed', 1779224460, 1779224460),
157
+ ('tkt-0015', 'tkt-15', 'published', 'Richiesta assistenza technical #15', 'clt-0048', 'high', 'technical', 'closed', 1779690426, 1779690426),
158
+ ('tkt-0016', 'tkt-16', 'published', 'Richiesta assistenza billing #16', 'clt-0037', 'low', 'billing', 'closed', 1780087850, 1780087850),
159
+ ('tkt-0017', 'tkt-17', 'published', 'Richiesta assistenza technical #17', 'clt-0012', 'medium', 'technical', 'in_progress', 1780773970, 1780773970),
160
+ ('tkt-0018', 'tkt-18', 'published', 'Richiesta assistenza technical #18', 'clt-0045', 'low', 'technical', 'closed', 1776322635, 1776322635),
161
+ ('tkt-0019', 'tkt-19', 'published', 'Richiesta assistenza billing #19', 'clt-0019', 'high', 'billing', 'closed', 1778531708, 1778531708),
162
+ ('tkt-0020', 'tkt-20', 'published', 'Richiesta assistenza billing #20', 'clt-0002', 'low', 'billing', 'open', 1776326907, 1776326907),
163
+ ('tkt-0021', 'tkt-21', 'published', 'Richiesta assistenza billing #21', 'clt-0008', 'high', 'billing', 'in_progress', 1778318876, 1778318876),
164
+ ('tkt-0022', 'tkt-22', 'published', 'Richiesta assistenza sales #22', 'clt-0040', 'low', 'sales', 'closed', 1778674176, 1778674176),
165
+ ('tkt-0023', 'tkt-23', 'published', 'Richiesta assistenza technical #23', 'clt-0018', 'medium', 'technical', 'closed', 1779583743, 1779583743),
166
+ ('tkt-0024', 'tkt-24', 'published', 'Richiesta assistenza billing #24', 'clt-0050', 'medium', 'billing', 'in_progress', 1780424161, 1780424161),
167
+ ('tkt-0025', 'tkt-25', 'published', 'Richiesta assistenza sales #25', 'clt-0013', 'medium', 'sales', 'open', 1778593601, 1778593601),
168
+ ('tkt-0026', 'tkt-26', 'published', 'Richiesta assistenza billing #26', 'clt-0046', 'medium', 'billing', 'in_progress', 1779404215, 1779404215),
169
+ ('tkt-0027', 'tkt-27', 'published', 'Richiesta assistenza technical #27', 'clt-0021', 'low', 'technical', 'open', 1779885965, 1779885965),
170
+ ('tkt-0028', 'tkt-28', 'published', 'Richiesta assistenza technical #28', 'clt-0030', 'high', 'technical', 'closed', 1779123411, 1779123411),
171
+ ('tkt-0029', 'tkt-29', 'published', 'Richiesta assistenza technical #29', 'clt-0014', 'medium', 'technical', 'closed', 1780061617, 1780061617),
172
+ ('tkt-0030', 'tkt-30', 'published', 'Richiesta assistenza billing #30', 'clt-0033', 'high', 'billing', 'open', 1779904908, 1779904908),
173
+ ('tkt-0031', 'tkt-31', 'published', 'Richiesta assistenza billing #31', 'clt-0012', 'medium', 'billing', 'in_progress', 1781162764, 1781162764),
174
+ ('tkt-0032', 'tkt-32', 'published', 'Richiesta assistenza sales #32', 'clt-0034', 'high', 'sales', 'closed', 1777381333, 1777381333),
175
+ ('tkt-0033', 'tkt-33', 'published', 'Richiesta assistenza sales #33', 'clt-0002', 'medium', 'sales', 'in_progress', 1778900761, 1778900761),
176
+ ('tkt-0034', 'tkt-34', 'published', 'Richiesta assistenza sales #34', 'clt-0004', 'low', 'sales', 'closed', 1778087526, 1778087526),
177
+ ('tkt-0035', 'tkt-35', 'published', 'Richiesta assistenza technical #35', 'clt-0023', 'medium', 'technical', 'closed', 1777275857, 1777275857),
178
+ ('tkt-0036', 'tkt-36', 'published', 'Richiesta assistenza technical #36', 'clt-0042', 'low', 'technical', 'closed', 1776507245, 1776507245),
179
+ ('tkt-0037', 'tkt-37', 'published', 'Richiesta assistenza sales #37', 'clt-0027', 'low', 'sales', 'closed', 1777543170, 1777543170),
180
+ ('tkt-0038', 'tkt-38', 'published', 'Richiesta assistenza billing #38', 'clt-0005', 'low', 'billing', 'closed', 1778883240, 1778883240),
181
+ ('tkt-0039', 'tkt-39', 'published', 'Richiesta assistenza technical #39', 'clt-0048', 'medium', 'technical', 'closed', 1777519024, 1777519024),
182
+ ('tkt-0040', 'tkt-40', 'published', 'Richiesta assistenza billing #40', 'clt-0026', 'high', 'billing', 'closed', 1778062701, 1778062701),
183
+ ('tkt-0041', 'tkt-41', 'published', 'Richiesta assistenza sales #41', 'clt-0034', 'low', 'sales', 'closed', 1778697137, 1778697137),
184
+ ('tkt-0042', 'tkt-42', 'published', 'Richiesta assistenza billing #42', 'clt-0038', 'medium', 'billing', 'open', 1778882032, 1778882032),
185
+ ('tkt-0043', 'tkt-43', 'published', 'Richiesta assistenza billing #43', 'clt-0018', 'low', 'billing', 'closed', 1779110662, 1779110662),
186
+ ('tkt-0044', 'tkt-44', 'published', 'Richiesta assistenza technical #44', 'clt-0034', 'high', 'technical', 'closed', 1779482042, 1779482042),
187
+ ('tkt-0045', 'tkt-45', 'published', 'Richiesta assistenza sales #45', 'clt-0046', 'high', 'sales', 'closed', 1778127285, 1778127285),
188
+ ('tkt-0046', 'tkt-46', 'published', 'Richiesta assistenza technical #46', 'clt-0008', 'low', 'technical', 'in_progress', 1779106002, 1779106002),
189
+ ('tkt-0047', 'tkt-47', 'published', 'Richiesta assistenza technical #47', 'clt-0024', 'low', 'technical', 'closed', 1776116714, 1776116714),
190
+ ('tkt-0048', 'tkt-48', 'published', 'Richiesta assistenza sales #48', 'clt-0004', 'low', 'sales', 'open', 1777758870, 1777758870),
191
+ ('tkt-0049', 'tkt-49', 'published', 'Richiesta assistenza billing #49', 'clt-0038', 'medium', 'billing', 'closed', 1776571565, 1776571565),
192
+ ('tkt-0050', 'tkt-50', 'published', 'Richiesta assistenza billing #50', 'clt-0036', 'medium', 'billing', 'closed', 1776297965, 1776297965),
193
+ ('tkt-0051', 'tkt-51', 'published', 'Richiesta assistenza technical #51', 'clt-0040', 'low', 'technical', 'closed', 1780652147, 1780652147),
194
+ ('tkt-0052', 'tkt-52', 'published', 'Richiesta assistenza sales #52', 'clt-0038', 'high', 'sales', 'closed', 1776108984, 1776108984),
195
+ ('tkt-0053', 'tkt-53', 'published', 'Richiesta assistenza sales #53', 'clt-0015', 'medium', 'sales', 'closed', 1781018077, 1781018077),
196
+ ('tkt-0054', 'tkt-54', 'published', 'Richiesta assistenza sales #54', 'clt-0004', 'medium', 'sales', 'closed', 1776377860, 1776377860),
197
+ ('tkt-0055', 'tkt-55', 'published', 'Richiesta assistenza technical #55', 'clt-0006', 'high', 'technical', 'in_progress', 1780031750, 1780031750),
198
+ ('tkt-0056', 'tkt-56', 'published', 'Richiesta assistenza sales #56', 'clt-0027', 'high', 'sales', 'closed', 1780000311, 1780000311),
199
+ ('tkt-0057', 'tkt-57', 'published', 'Richiesta assistenza billing #57', 'clt-0014', 'high', 'billing', 'in_progress', 1779618019, 1779618019),
200
+ ('tkt-0058', 'tkt-58', 'published', 'Richiesta assistenza technical #58', 'clt-0024', 'low', 'technical', 'closed', 1778045618, 1778045618),
201
+ ('tkt-0059', 'tkt-59', 'published', 'Richiesta assistenza billing #59', 'clt-0045', 'low', 'billing', 'closed', 1780438929, 1780438929),
202
+ ('tkt-0060', 'tkt-60', 'published', 'Richiesta assistenza sales #60', 'clt-0045', 'low', 'sales', 'open', 1779640034, 1779640034);
203
+
204
+ INSERT OR IGNORE INTO content_changelog (id, slug, status, version, release_date, features, created_at, updated_at)
205
+ VALUES
206
+ ('chg-0001', 'v1-0-0', 'published', 'v1.0.0', 1776070983, '<p>Lancio ufficiale della piattaforma con gestione clienti base.</p>', 1776070983, 1776070983),
207
+ ('chg-0002', 'v1-1-0', 'published', 'v1.1.0', 1778662983, '<p>Aggiunti report avanzati e export in CSV.</p>', 1778662983, 1778662983),
208
+ ('chg-0003', 'v1-2-0', 'published', 'v1.2.0', 1779958983, '<p>Integrazione con Slack per notifiche ticket.</p>', 1779958983, 1779958983),
209
+ ('chg-0004', 'v2-0-0', 'published', 'v2.0.0', 1781082183, '<h2>Major Update</h2><p>Nuova dashboard amministrativa e API pubbliche.</p>', 1781082183, 1781082183);
210
+
211
+ INSERT OR IGNORE INTO content_articoli (id, slug, status, title, author, cover_image, body, created_at, updated_at)
212
+ VALUES
213
+ ('art-0001', 'benvenuti', 'published', 'Come ridurre il Churn Rate', 'Luca Rossi', 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&q=80', '<p>Analisi delle migliori strategie per mantenere i clienti SaaS nel 2026.</p>', 1779526983, 1779526983),
214
+ ('art-0002', 'pricing-strategy', 'published', 'Pricing SaaS: Fremium vs Trial', 'Anna Bianchi', 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80', '<p>Cosa scegliere per massimizzare la conversion rate e il Customer Lifetime Value.</p>', 1780822983, 1780822983);
215
+
216
+ `
@@ -0,0 +1,20 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
+ // See LICENSE in the repository root for license terms.
4
+
5
+ /// <reference types="@cloudflare/workers-types" />
6
+ import type { IDemoDataRepository } from '@beechcms/core'
7
+ import { DEMO_DATA_SQL } from './demo-data-sql'
8
+
9
+ export class D1DemoDataRepository implements IDemoDataRepository {
10
+ constructor(private readonly db: D1Database) {}
11
+
12
+ async loadDemoData(): Promise<void> {
13
+ const statements = DEMO_DATA_SQL
14
+ .split(';')
15
+ .map(s => s.trim())
16
+ .filter(s => s.length > 0)
17
+ .map(s => this.db.prepare(s))
18
+ await this.db.batch(statements)
19
+ }
20
+ }
@@ -1,9 +1,13 @@
1
- import type { IScheduler } from '@beechcms/core'
2
-
3
- export class ExecutionContextScheduler implements IScheduler {
4
- constructor(private readonly ctx: ExecutionContext) {}
5
-
6
- waitUntil(promise: Promise<unknown>): void {
7
- this.ctx.waitUntil(promise)
8
- }
9
- }
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
+ // See LICENSE in the repository root for license terms.
4
+
5
+ import type { IScheduler } from '@beechcms/core'
6
+
7
+ export class ExecutionContextScheduler implements IScheduler {
8
+ constructor(private readonly ctx: ExecutionContext) {}
9
+
10
+ waitUntil(promise: Promise<unknown>): void {
11
+ this.ctx.waitUntil(promise)
12
+ }
13
+ }
@@ -1,21 +1,25 @@
1
- import type { IClock } from '@beechcms/core'
2
-
3
- const MILLISECONDS_PER_SECOND = 1000
4
-
5
- /**
6
- * Test-only IClock implementation that returns a frozen timestamp on every
7
- * call. Lets specs assert exact values for `createdAt`, `iat`, and
8
- * day-bucket computations without resorting to vi.useFakeTimers or
9
- * patching the global Date constructor.
10
- */
11
- export class FixedClock implements IClock {
12
- constructor(private readonly fixedNowMs: number) {}
13
-
14
- now(): number {
15
- return this.fixedNowMs
16
- }
17
-
18
- nowSeconds(): number {
19
- return Math.floor(this.fixedNowMs / MILLISECONDS_PER_SECOND)
20
- }
21
- }
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
+ // See LICENSE in the repository root for license terms.
4
+
5
+ import type { IClock } from '@beechcms/core'
6
+
7
+ const MILLISECONDS_PER_SECOND = 1000
8
+
9
+ /**
10
+ * Test-only IClock implementation that returns a frozen timestamp on every
11
+ * call. Lets specs assert exact values for `createdAt`, `iat`, and
12
+ * day-bucket computations without resorting to vi.useFakeTimers or
13
+ * patching the global Date constructor.
14
+ */
15
+ export class FixedClock implements IClock {
16
+ constructor(private readonly fixedNowMs: number) {}
17
+
18
+ now(): number {
19
+ return this.fixedNowMs
20
+ }
21
+
22
+ nowSeconds(): number {
23
+ return Math.floor(this.fixedNowMs / MILLISECONDS_PER_SECOND)
24
+ }
25
+ }
@@ -1,4 +1,8 @@
1
- // v0.4.0: FTS sync handled automatically by SQL triggers (generateFtsTriggers).
2
- // syncFts/deleteFts eliminated. This file kept as empty module to avoid import errors
3
- // during the Phase 4 Phase 6 transition.
4
- export {}
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ // Copyright (c) 2024–2026 Flavio De Musso. All rights reserved.
3
+ // See LICENSE in the repository root for license terms.
4
+
5
+ // v0.4.0: FTS sync handled automatically by SQL triggers (generateFtsTriggers).
6
+ // syncFts/deleteFts eliminated. This file kept as empty module to avoid import errors
7
+ // during the Phase 4 → Phase 6 transition.
8
+ export {}