@beechcms/api 0.6.0-preview.1 → 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 (222) hide show
  1. package/assets/dashboard/BeechLogo.svg +18 -18
  2. package/assets/dashboard/BeechLogoLIght.svg +48 -48
  3. package/assets/dashboard/assets/chart-BrJFdsGZ.js +39 -0
  4. package/assets/dashboard/assets/index-CIaoMxuB.css +1 -0
  5. package/assets/dashboard/assets/index-wTKgygsg.js +636 -0
  6. package/assets/dashboard/assets/pie-chart-recharts-BEaE1FOE.js +1 -0
  7. package/assets/dashboard/assets/timeseries-chart-recharts-DmWM6imF.js +1 -0
  8. package/assets/dashboard/beechLogoDark.svg +48 -48
  9. package/assets/dashboard/index.html +18 -18
  10. package/assets/dashboard/noResult.svg +42 -42
  11. package/assets/dashboard/sol.svg +3 -3
  12. package/assets/dashboard/undraw_enter_nwx3.svg +36 -36
  13. package/migrations/0000_v040_base.sql +265 -265
  14. package/migrations/0029_automations.sql +14 -14
  15. package/migrations/0030_test_seeds.sql +125 -125
  16. package/package.json +2 -2
  17. package/src/auth/__fixtures__/in-memory-hash-provider.ts +17 -17
  18. package/src/auth/__fixtures__/static-token-service.ts +22 -22
  19. package/src/auth/bcrypt-hash-provider.ts +24 -24
  20. package/src/auth/constants.ts +14 -14
  21. package/src/auth/generate-refresh-token.test.ts +23 -23
  22. package/src/auth/hash-provider.test.ts +55 -55
  23. package/src/auth/jose-token-service.ts +62 -62
  24. package/src/auth/jwt-claims-passthrough.test.ts +87 -87
  25. package/src/auth/login.test.ts +100 -100
  26. package/src/auth/login.ts +78 -78
  27. package/src/auth/refresh.ts +11 -11
  28. package/src/auth/token-service.test.ts +90 -90
  29. package/src/factory.ts +370 -368
  30. package/src/features/automations/__tests__/action-executors.test.ts +255 -255
  31. package/src/features/automations/__tests__/automation-runner.test.ts +196 -196
  32. package/src/features/automations/__tests__/automation-runner.utils.test.ts +60 -60
  33. package/src/features/automations/__tests__/automations.handler.test.ts +264 -264
  34. package/src/features/automations/__tests__/automations.repository.test.ts +163 -163
  35. package/src/features/automations/__tests__/automations.schema.test.ts +224 -224
  36. package/src/features/automations/__tests__/context-resolver.test.ts +126 -126
  37. package/src/features/automations/__tests__/cron-runner.test.ts +267 -267
  38. package/src/features/automations/__tests__/cron-runner.utils.test.ts +144 -144
  39. package/src/features/automations/__tests__/set-variable.executor.test.ts +383 -383
  40. package/src/features/automations/__tests__/template-grammar.test.ts +308 -308
  41. package/src/features/automations/__tests__/webhook.executor.test.ts +142 -142
  42. package/src/features/automations/__tests__/when-evaluator.test.ts +274 -274
  43. package/src/features/automations/__tests__/when-pushdown.test.ts +281 -281
  44. package/src/features/automations/action-executors/create-entry.executor.ts +27 -27
  45. package/src/features/automations/action-executors/edit-field.executor.ts +26 -26
  46. package/src/features/automations/action-executors/index.ts +37 -37
  47. package/src/features/automations/action-executors/send-mail.executor.ts +53 -53
  48. package/src/features/automations/action-executors/set-variable.executor.ts +159 -159
  49. package/src/features/automations/action-executors/webhook.executor.ts +67 -67
  50. package/src/features/automations/automation-runner.ts +85 -85
  51. package/src/features/automations/automation-runner.utils.ts +47 -47
  52. package/src/features/automations/automations.handler.ts +197 -197
  53. package/src/features/automations/automations.schema.ts +177 -177
  54. package/src/features/automations/context-resolver.ts +152 -152
  55. package/src/features/automations/cron-runner.ts +140 -140
  56. package/src/features/automations/cron-runner.utils.ts +44 -44
  57. package/src/features/automations/filter-translation.ts +46 -46
  58. package/src/features/automations/index.ts +16 -16
  59. package/src/features/automations/template-grammar.ts +245 -245
  60. package/src/features/automations/var-access-resolver.ts +140 -140
  61. package/src/features/automations/when-evaluator.ts +87 -87
  62. package/src/features/automations/when-pushdown.ts +57 -57
  63. package/src/features/backrefs/__tests__/backrefs.handler.test.ts +359 -359
  64. package/src/features/backrefs/backrefs.handler.ts +168 -168
  65. package/src/features/backrefs/d1-backref.repository.ts +84 -84
  66. package/src/features/backrefs/index.ts +5 -5
  67. package/src/features/content/constants.ts +16 -16
  68. package/src/features/content/handlers/bulk.handler.ts +185 -185
  69. package/src/features/content/handlers/create.ts +129 -129
  70. package/src/features/content/handlers/delete.ts +62 -62
  71. package/src/features/content/handlers/facets.ts +49 -49
  72. package/src/features/content/handlers/get.ts +120 -120
  73. package/src/features/content/handlers/helpers.test.ts +180 -180
  74. package/src/features/content/handlers/helpers.ts +93 -93
  75. package/src/features/content/handlers/list.ts +174 -174
  76. package/src/features/content/handlers/update.ts +174 -174
  77. package/src/features/content/index.ts +26 -26
  78. package/src/features/dashboard-layout/__tests__/dashboard-layout.handler.test.ts +388 -0
  79. package/src/features/dashboard-layout/dashboard-layout.handler.ts +206 -0
  80. package/src/features/dashboard-layout/index.ts +5 -0
  81. package/src/features/draft/draft.handler.ts +195 -195
  82. package/src/features/draft/draft.middleware.ts +66 -66
  83. package/src/features/draft/index.ts +5 -5
  84. package/src/features/email/email.provider.ts +42 -42
  85. package/src/features/email/email.service.ts +98 -98
  86. package/src/features/email/email.types.ts +119 -119
  87. package/src/features/email/index.ts +33 -33
  88. package/src/features/email/providers/resend.ts +67 -67
  89. package/src/features/email/providers/smtp.ts +55 -55
  90. package/src/features/email/templates/automation-mail.ts +19 -19
  91. package/src/features/email/templates/password-changed.ts +63 -63
  92. package/src/features/email/templates/password-reset.ts +68 -68
  93. package/src/features/email/templates/shell.ts +96 -96
  94. package/src/features/notifications/index.ts +5 -5
  95. package/src/features/notifications/notifications.handler.ts +105 -105
  96. package/src/features/password-reset/index.ts +19 -19
  97. package/src/features/password-reset/request.ts +92 -92
  98. package/src/features/password-reset/reset.ts +102 -102
  99. package/src/features/rotate-field/index.ts +5 -5
  100. package/src/features/rotate-field/rotate-field.handler.ts +132 -132
  101. package/src/features/rotate-field/rotate-field.schema.ts +17 -17
  102. package/src/features/schema/schema.handler.ts +131 -131
  103. package/src/features/seeds/index.ts +5 -5
  104. package/src/features/seeds/seeds.handler.test.ts +1199 -632
  105. package/src/features/seeds/seeds.handler.ts +558 -693
  106. package/src/features/settings/__tests__/settings.handler.test.ts +555 -555
  107. package/src/features/settings/settings.handler.ts +392 -392
  108. package/src/features/setup/index.ts +288 -204
  109. package/src/features/stats/index.ts +5 -5
  110. package/src/features/stats/stats.handler.ts +420 -420
  111. package/src/features/webhooks/index.ts +63 -63
  112. package/src/index.ts +65 -65
  113. package/src/media-utils.ts +82 -82
  114. package/src/middleware/auth-providers.middleware.test.ts +85 -0
  115. package/src/middleware/auth-providers.middleware.ts +45 -45
  116. package/src/middleware/observability.middleware.test.ts +93 -0
  117. package/src/middleware/observability.middleware.ts +70 -70
  118. package/src/middleware/rate-limit.middleware.ts +45 -45
  119. package/src/middleware/repository.middleware.ts +117 -114
  120. package/src/middleware/seed-registry.middleware.test.ts +97 -97
  121. package/src/middleware/seed-registry.middleware.ts +21 -21
  122. package/src/middleware/storage.middleware.ts +25 -25
  123. package/src/middleware.ts +45 -45
  124. package/src/public/access-policy.ts +27 -27
  125. package/src/public/api-key-middleware.ts +57 -57
  126. package/src/public/cache-utils.ts +38 -38
  127. package/src/public/entry-projection.ts +46 -46
  128. package/src/public/idempotency.ts +23 -23
  129. package/src/public/index.ts +16 -16
  130. package/src/public/problem-details.ts +124 -124
  131. package/src/public/public-add.ts +114 -114
  132. package/src/public/public-edit.ts +163 -163
  133. package/src/public/public-errors.ts +19 -19
  134. package/src/public/public-read.ts +63 -63
  135. package/src/public/public-routes.ts +88 -88
  136. package/src/public/query-builder.test.ts +224 -224
  137. package/src/public/query-builder.ts +156 -156
  138. package/src/public/rate-limit-middleware.ts +34 -34
  139. package/src/public/read-list.ts +54 -54
  140. package/src/public/read-single.ts +48 -48
  141. package/src/public/response-builder.ts +30 -30
  142. package/src/public/sanitize.ts +69 -69
  143. package/src/public/slug-utils.ts +18 -18
  144. package/src/rate-limit/cloudflare-rate-limiter.test.ts +30 -30
  145. package/src/rate-limit/cloudflare-rate-limiter.ts +15 -15
  146. package/src/rate-limit/in-memory-rate-limiter.test.ts +37 -37
  147. package/src/rate-limit/in-memory-rate-limiter.ts +17 -17
  148. package/src/rate-limit/no-op-rate-limiter.test.ts +22 -22
  149. package/src/rate-limit/no-op-rate-limiter.ts +11 -11
  150. package/src/search-utils.test.ts +211 -211
  151. package/src/search-utils.ts +213 -213
  152. package/src/search.ts +65 -65
  153. package/src/shared/apply-policies.test.ts +81 -81
  154. package/src/shared/apply-policies.ts +67 -67
  155. package/src/shared/automations.repository.d1.ts +150 -150
  156. package/src/shared/background-notification-service.test.ts +62 -62
  157. package/src/shared/background-notification-service.ts +52 -52
  158. package/src/shared/base.repository.d1.ts +32 -32
  159. package/src/shared/content-utils.test.ts +165 -165
  160. package/src/shared/content-utils.ts +86 -86
  161. package/src/shared/content.repository.d1.test.ts +507 -458
  162. package/src/shared/content.repository.d1.ts +851 -851
  163. package/src/shared/d1-activity-log.repository.test.ts +140 -140
  164. package/src/shared/d1-activity-log.repository.ts +105 -105
  165. package/src/shared/d1-activity-logger.test.ts +86 -86
  166. package/src/shared/d1-activity-logger.ts +67 -67
  167. package/src/shared/d1-analytics.repository.test.ts +78 -78
  168. package/src/shared/d1-analytics.repository.ts +85 -85
  169. package/src/shared/d1-content-scan.repository.test.ts +80 -80
  170. package/src/shared/d1-content-scan.repository.ts +37 -37
  171. package/src/shared/d1-notification.repository.test.ts +128 -128
  172. package/src/shared/d1-notification.repository.ts +118 -118
  173. package/src/shared/d1-password-reset-token.repository.test.ts +81 -81
  174. package/src/shared/d1-password-reset-token.repository.ts +56 -56
  175. package/src/shared/d1-search.repository.test.ts +87 -87
  176. package/src/shared/d1-search.repository.ts +88 -88
  177. package/src/shared/d1-session.repository.test.ts +125 -125
  178. package/src/shared/d1-session.repository.ts +102 -102
  179. package/src/shared/d1-setup-checklist.repository.ts +36 -36
  180. package/src/shared/d1-user.repository.test.ts +151 -151
  181. package/src/shared/d1-user.repository.ts +119 -119
  182. package/src/shared/d1-widget.repository.test.ts +267 -221
  183. package/src/shared/d1-widget.repository.ts +385 -341
  184. package/src/shared/dashboard-layout.repository.d1.test.ts +135 -0
  185. package/src/shared/dashboard-layout.repository.d1.ts +58 -0
  186. package/src/shared/demo-data-sql.ts +216 -54
  187. package/src/shared/demo-data.repository.d1.ts +20 -20
  188. package/src/shared/execution-context-scheduler.ts +13 -13
  189. package/src/shared/fixed-clock.ts +25 -25
  190. package/src/shared/fts-sync.ts +8 -8
  191. package/src/shared/idempotency.repository.d1.test.ts +83 -83
  192. package/src/shared/idempotency.repository.d1.ts +60 -60
  193. package/src/shared/in-memory-activity-logger.ts +19 -19
  194. package/src/shared/in-memory-notification-service.ts +19 -19
  195. package/src/shared/in-memory-seed.repository.ts +58 -51
  196. package/src/shared/media.repository.d1.test.ts +107 -107
  197. package/src/shared/media.repository.d1.ts +68 -68
  198. package/src/shared/qstash-notification-service.test.ts +67 -67
  199. package/src/shared/qstash-notification-service.ts +55 -55
  200. package/src/shared/query-utils.ts +141 -141
  201. package/src/shared/request-utils.ts +26 -26
  202. package/src/shared/schema-mutator.d1.test.ts +142 -0
  203. package/src/shared/schema-mutator.d1.ts +64 -64
  204. package/src/shared/seed-layout.repository.d1.test.ts +114 -114
  205. package/src/shared/seed-layout.repository.d1.ts +62 -62
  206. package/src/shared/seed-registry-cache.test.ts +68 -68
  207. package/src/shared/seed-registry-cache.ts +49 -49
  208. package/src/shared/seed.repository.d1.test.ts +143 -143
  209. package/src/shared/seed.repository.d1.ts +98 -98
  210. package/src/shared/sequential-id-generator.ts +33 -33
  211. package/src/shared/site-settings.repository.d1.ts +53 -53
  212. package/src/shared/storage/factory.ts +41 -41
  213. package/src/shared/storage/s3-bucket.ts +195 -195
  214. package/src/shared/storage-utils.ts +40 -40
  215. package/src/shared/system-stats.repository.d1.test.ts +58 -58
  216. package/src/shared/system-stats.repository.d1.ts +48 -48
  217. package/src/types.ts +90 -87
  218. package/src/upload.ts +198 -198
  219. package/src/widget.test.ts +85 -0
  220. package/src/widget.ts +251 -212
  221. package/assets/dashboard/assets/index-BSjk0Sx9.js +0 -634
  222. package/assets/dashboard/assets/index-kRCYVN2B.css +0 -1
@@ -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
+ }
@@ -1,54 +1,216 @@
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
- // Compiled-in demo dataset. Workers have no runtime FS so the SQL from
6
- // migrations/0028_v040_seed_data.sql is bundled here as a string constant.
7
- export const DEMO_DATA_SQL = `
8
- INSERT OR IGNORE INTO content_team (id, slug, status, name, role, bio, photo, linkedIn, active, metaTitle, metaDescription, created_at, updated_at) VALUES
9
- ('tm-0001', 'flavio-de-musso', 'published', 'Flavio De Musso', 'Founder & Principal Engineer', 'Progetta architetture moderne per CMS headless e prodotti digitali edge-native.', 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&q=80', 'https://www.linkedin.com/in/flaviodemusso', 1, 'Flavio De Musso', 'Founder e creatore di Beech CMS.', unixepoch(), unixepoch()),
10
- ('tm-0002', 'laura-rossi', 'published', 'Laura Rossi', 'Product Designer', 'Cura la UX della dashboard e dei workflow editoriali. Specializzata in design system a scala.', 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Laura Rossi – Designer', 'UX designer focalizzata su strumenti per content team.', unixepoch(), unixepoch()),
11
- ('tm-0003', 'marco-bianchi', 'published', 'Marco Bianchi', 'Frontend Engineer', 'Sviluppa i field renderer React e il registry della UI. Appassionato di performance web.', 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Marco Bianchi – Engineer', 'Sviluppatore frontend specializzato in React e UX.', unixepoch(), unixepoch()),
12
- ('tm-0004', 'giulia-verdi', 'published', 'Giulia Verdi', 'Developer Relations', 'Aiuta i team a integrare Beech CMS nelle loro pipeline di sviluppo. Developer Advocate.', 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Giulia Verdi – DevRel', 'Developer advocate per la community Beech.', unixepoch(), unixepoch()),
13
- ('tm-0005', 'andrea-neri', 'published', 'Andrea Neri', 'Support Specialist', 'Supporto di primo livello per clienti enterprise e gestione della knowledge base.', 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=400&q=80', 'https://www.linkedin.com/in/', 1, 'Andrea Neri – Support', 'Supporto tecnico e customer success.', unixepoch(), unixepoch());
14
-
15
- INSERT OR IGNORE INTO content_prodotti (id, slug, status, name, price, stock, active, coverImage, images, description, metaTitle, metaDescription, created_at, updated_at) VALUES
16
- ('prd-0001', 'beech-starter', 'published', 'Beech Starter', 490, 50, 1, 'https://images.unsplash.com/photo-1496181133206-80ce9b88a853?w=800&q=80', '[]', '<p>Piano entry-level per piccoli siti e landing page. Include il Botanical Engine, la dashboard, e 1GB di storage R2.</p>', 'Beech Starter', 'Piano starter per progetti piccoli e medi.', unixepoch(), unixepoch()),
17
- ('prd-0002', 'beech-pro', 'published', 'Beech Pro', 1290, 30, 1, 'https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?w=800&q=80', '[]', '<p>Tutte le feature avanzate per team strutturati: draft workflow, analytics per-seed, FTS5 full-text search, 10GB storage R2.</p>', 'Beech Pro', 'Piano professionale per agenzie e team marketing.', unixepoch(), unixepoch()),
18
- ('prd-0003', 'beech-enterprise', 'published', 'Beech Enterprise', 3990, 10, 1, 'https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=800&q=80', '[]', '<p>Funzionalità enterprise, audit log, SLA garantito, multi-ambiente staging/production, e storage R2 illimitato.</p>', 'Beech Enterprise', 'Soluzione enterprise per grandi organizzazioni.', unixepoch(), unixepoch()),
19
- ('prd-0004', 'implementazione-custom', 'published', 'Implementazione custom', 15000, 3, 1, 'https://images.unsplash.com/photo-1593642532744-d377ab507dc8?w=800&q=80', '[]', '<p>Servizio di implementazione su misura di Beech CMS: analisi dei requisiti, definizione dei Seed, deploy su Cloudflare, formazione team.</p>', 'Implementazione custom Beech', 'Servizio di onboarding e integrazione personalizzata.', unixepoch(), unixepoch()),
20
- ('prd-0005', 'workshop-botanical-engine', 'published', 'Workshop Botanical Engine', 990, 20, 1, 'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80', '[]', '<p>Workshop avanzato sul Botanical Engine e sul registry dei seed. Impara a definire Seed ottimali e a usare beech seed:load per deployare schemi.</p>', 'Workshop Botanical Engine', 'Formazione per team tecnici su Beech CMS.', unixepoch(), unixepoch());
21
-
22
- INSERT OR IGNORE INTO content_articoli (id, slug, status, title, publishedAt, coverImage, tags, body, metaTitle, metaDescription, created_at, updated_at) VALUES
23
- ('art-0001', 'benvenuto-nel-blog', 'published', 'Benvenuto nel blog Beech', 1736467200, 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&q=80', '["news","annuncio"]', '<p>Scopri come Beech CMS gestisce contenuti schema-driven con tabelle SQL dedicate per ogni tipo di contenuto.</p><h3>Architettura moderna</h3><p>Beech v0.4.0 elimina il JSON blob e usa colonne reali per ogni Branch del Seed. Il risultato è performance migliorate e query native SQLite.</p>', 'Benvenuto nel blog Beech', 'Introduzione al CMS headless schema-driven.', unixepoch(), unixepoch()),
24
- ('art-0002', 'roadmap-2026', 'published', 'Roadmap prodotto 2026', 1738713600, 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=800&q=80', '["release","aggiornamento"]', '<p>Tutte le novità in arrivo per Beech CMS nel 2026: Doctype Architecture, CLI seed:load, FTS5 per-seed, e molto altro.</p><h3>Fase 1 — Core</h3><p>Il Botanical Engine diventa un compilatore di schema che genera DDL SQL dalla definizione TypeScript dei Seed.</p>', 'Roadmap Beech CMS 2026', 'Piano di sviluppo delle funzionalità per il 2026.', unixepoch(), unixepoch()),
25
- ('art-0003', 'migrare-da-wordpress', 'published', 'Migrare da WordPress a Beech', 1740182400, 'https://images.unsplash.com/photo-1542831371-29b0f74f9713?w=800&q=80', '["guida","cms"]', '<p>Guida pratica per migrare contenuti da WordPress a Beech CMS senza downtime. Esporta, trasforma e importa usando la Public API.</p><h3>Step 1: Esporta da WordPress</h3><p>Usa il plugin WP All Export per ottenere CSV o JSON dai post. Poi mappali alle colonne del tuo Seed.</p>', 'Migrazione da WordPress a Beech', 'Strategie per migrare contenuti in sicurezza.', unixepoch(), unixepoch()),
26
- ('art-0004', 'pattern-registry-ui', 'published', 'Il Pattern Registry della UI', 1740873600, 'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80', '["tutorial","guida"]', '<p>Come il registry dei field renderer semplifica la dashboard: ogni Branch type ha un renderer React dedicato, registrato centralmente e richiamato automaticamente.</p>', 'Pattern Registry UI Beech', 'Architettura dei componenti field-driven.', unixepoch(), unixepoch()),
27
- ('art-0005', 'edge-first-architecture', 'published', 'Architettura edge-first con Cloudflare', 1741132800, 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=800&q=80', '["news","aggiornamento"]', '<p>Perché Beech nasce per l''edge: latenza minima, zero cold start, D1 SQLite replicato globalmente su Cloudflare. Il CMS arriva dove si trovano gli utenti.</p>', 'Architettura edge-first', 'Vantaggi di un CMS progettato per l''edge.', unixepoch(), unixepoch());
28
-
29
- INSERT OR IGNORE INTO content_testimonianze (id, slug, status, author, company, quote, rating, date, photo, active, metaTitle, metaDescription, created_at, updated_at) VALUES
30
- ('tes-0001', 'acme-corp', 'published', 'Chiara Conti', 'Acme Corp', 'Con Beech CMS abbiamo ridotto del 60% il tempo di pubblicazione dei contenuti.', 5, 1737331200, 'https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?w=400&q=80', 1, 'Caso studio Acme', 'Come Acme ha accelerato i workflow editoriali.', unixepoch(), unixepoch()),
31
- ('tes-0002', 'studio-x', 'published', 'Luca Ferri', 'Studio X', 'La flessibilità degli schema ci ha permesso di iterare velocemente sul design del sito.', 4, 1738195200, 'https://images.unsplash.com/photo-1560250097-0b93528c311a?w=400&q=80', 1, 'Testimonianza Studio X', 'Feedback di un''agenzia digital sul CMS.', unixepoch(), unixepoch()),
32
- ('tes-0003', 'media-hub', 'published', 'Sara Galli', 'MediaHub', 'Finalmente un CMS pensato per il contenuto, non per il database. Team felicissimo.', 5, 1739404800, 'https://images.unsplash.com/photo-1580489944761-15a19d654956?w=400&q=80', 1, 'Testimonianza MediaHub', 'Perché i content team amano Beech.', unixepoch(), unixepoch()),
33
- ('tes-0004', 'shop-co', 'published', 'Davide Rizzi', 'ShopCo', 'Gestire landing e pagine prodotto è diventato molto più semplice. Alta raccomandazione.', 4, 1740268800, 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&q=80', 1, 'Testimonianza ShopCo', 'Beech CMS per e-commerce moderni.', unixepoch(), unixepoch()),
34
- ('tes-0005', 'fit-tech', 'published', 'Elena Santi', 'FitTech Inc', 'La dashboard è così intuitiva che il team marketing la usa senza training.', 5, 1741046400, 'https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?w=400&q=80', 1, 'Testimonianza FitTech', 'Esperienza di un team marketing su Beech CMS.', unixepoch(), unixepoch());
35
-
36
- INSERT OR IGNORE INTO content_pagine (id, slug, status, title, coverImage, body, metaTitle, metaDescription, created_at, updated_at) VALUES
37
- ('pag-0001', 'home', 'published', 'Homepage', 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=1200&q=80', '<h1>Beech CMS</h1><p>Il CMS schema-driven per l''era edge. Definisci i tuoi Seed in TypeScript, deploya su Cloudflare, e inizia a pubblicare.</p>', 'Beech CMS - Homepage', 'CMS moderno schema-driven per deployment edge.', unixepoch(), unixepoch()),
38
- ('pag-0002', 'il-prodotto', 'published', 'Il prodotto', 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=1200&q=80', '<h1>Perché Beech</h1><p>Architettura ibrida con tabelle SQL dedicate per Seed, Botanical Engine come compilatore di schema, e CLI per il deploy.</p>', 'Perché scegliere Beech', 'Scopri le funzionalità chiave di Beech CMS.', unixepoch(), unixepoch()),
39
- ('pag-0003', 'casi-studio', 'published', 'Casi studio', 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=1200&q=80', '<h1>Storie di successo</h1><p>Come i team usano Beech ogni giorno per pubblicare contenuti velocemente con la dashboard schema-driven.</p>', 'Casi studio Beech', 'Raccolta di case study su Beech CMS.', unixepoch(), unixepoch()),
40
- ('pag-0004', 'pricing', 'published', 'Pricing', 'https://images.unsplash.com/photo-1554224155-6726b3ff858f?w=1200&q=80', '<h1>Piani e prezzi</h1><p>Scegli il piano adatto al tuo team: Starter, Pro o Enterprise. Tutti includono il Botanical Engine e la dashboard.</p>', 'Pricing Beech CMS', 'Confronta i piani Starter, Pro ed Enterprise.', unixepoch(), unixepoch()),
41
- ('pag-0005', 'contatti', 'published', 'Contatti', 'https://images.unsplash.com/photo-1423666639041-f56000c27a9a?w=1200&q=80', '<h1>Parliamo del tuo progetto</h1><p>Compila il form per una demo gratuita. Il team risponde entro 24 ore lavorative.</p>', 'Contatta Beech', 'Richiedi una demo o una consulenza su Beech CMS.', unixepoch(), unixepoch());
42
-
43
- INSERT OR IGNORE INTO content_clienti (id, slug, status, name, email, passwordHash, tier, phone, internalNote, registeredAt, active, created_at, updated_at) VALUES
44
- ('clt-0001', 'marco-rossi', 'published', 'Marco Rossi', 'marco.rossi@acmecorp.it', '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', 'enterprise', '+39 02 1234 5678', 'Cliente storico. Sconto applicato del 20% su rinnovo annuale.', 1710460800, 1, unixepoch(), unixepoch()),
45
- ('clt-0002', 'laura-bianchi', 'published', 'Laura Bianchi', 'laura.bianchi@studiox.io', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', 'pro', '+39 06 9876 5432', 'Contattare prima del rinnovo per upsell a enterprise.', 1736294400, 1, unixepoch(), unixepoch()),
46
- ('clt-0003', 'davide-ferrari', 'published', 'Davide Ferrari', 'davide@mediahub.eu', '1c8bfe8f801d79745c4631d09fff36c82aa37fc4cce4fc946683d7b336b63032', 'starter', '+39 011 4567 890', 'Ha richiesto supporto per migrazione da WordPress.', 1750550400, 1, unixepoch(), unixepoch()),
47
- ('clt-0004', 'giulia-verdi', 'published', 'Giulia Verdi', 'giulia.verdi@personal.me', '6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090', 'free', '+39 081 3210 987', 'Account free scaduto. Inviare offerta upgrade.', 1756771200, 0, unixepoch(), unixepoch()),
48
- ('clt-0005', 'sofia-costa', 'published', 'Sofia Costa', 'sofia.costa@fittech.com', '65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5', 'pro', NULL, NULL, 1769731200, 1, unixepoch(), unixepoch());
49
-
50
- INSERT OR IGNORE INTO content_messaggi (id, slug, status, name, email, subject, message, read, created_at, updated_at) VALUES
51
- ('msg-0001', 'msg-demo-1', 'published', 'Riccardo Esposito', 'riccardo@example.com', 'Richiesta demo Beech Pro', '<p>Buongiorno, siamo un''agenzia di 8 persone e vorremmo valutare Beech Pro per i nostri clienti. Possiamo fissare una call la prossima settimana?</p>', 0, unixepoch(), unixepoch()),
52
- ('msg-0002', 'msg-demo-2', 'published', 'Anna Marchetti', 'anna@startup.io', 'Domanda su FTS5 e ricerca full-text', '<p>Ciao team! Sto valutando Beech per un progetto di knowledge base. La ricerca full-text FTS5 funziona anche sulla versione Starter? Grazie.</p>', 1, unixepoch(), unixepoch()),
53
- ('msg-0003', 'msg-demo-3', 'published', 'Francesco Lombardi', 'f.lombardi@enterprise.it', 'Beech Enterprise — SLA e uptime', '<p>Siamo interessati al piano Enterprise. Quali SLA garantite? Abbiamo bisogno di 99.9% uptime per un''applicazione mission-critical.</p>', 0, unixepoch(), unixepoch());
54
- `
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
+ `
@@ -1,20 +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
+ // 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
+ }