@beechcms/api 0.6.7 → 0.8.0
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.
- package/assets/dashboard/0auth_mcp.svg +1 -0
- package/assets/dashboard/assets/{chart-D_uST30B.js → chart-CYgKoF6U.js} +6 -6
- package/assets/dashboard/assets/dist-DHabpZqA.js +140 -0
- package/assets/dashboard/assets/index-BZMSpYrl.js +3613 -0
- package/assets/dashboard/assets/index-Dex2YZcC.css +1 -0
- package/assets/dashboard/assets/json-code-editor-DtZpKDXm.js +12 -0
- package/assets/dashboard/assets/pie-chart-recharts-C7WAhcCk.js +1 -0
- package/assets/dashboard/assets/richtext-render-x0TT0116.js +258 -0
- package/assets/dashboard/assets/timeseries-chart-recharts-B9RquiY6.js +1 -0
- package/assets/dashboard/assets/w3c-keyname-BOAvb0qz.js +1 -0
- package/assets/dashboard/index.html +4 -2
- package/dist/auth/auth.app.d.ts +13 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/factory.d.ts +14 -1
- package/dist/features/oauth/authorization-request.d.ts +127 -0
- package/dist/features/oauth/authorize.d.ts +97 -0
- package/dist/features/oauth/consents.d.ts +75 -0
- package/dist/features/oauth/constants.d.ts +48 -0
- package/dist/features/oauth/index.d.ts +31 -0
- package/dist/features/oauth/revoke.d.ts +29 -0
- package/dist/features/oauth/token-issuance.d.ts +49 -0
- package/dist/features/oauth/token.d.ts +38 -0
- package/dist/features/search/constants.d.ts +43 -0
- package/dist/features/search/handlers/embed.d.ts +31 -0
- package/dist/features/search/handlers/full-text-search.d.ts +28 -0
- package/dist/features/search/index.d.ts +20 -0
- package/dist/features/search/jobs/semantic-search.hooks.d.ts +21 -0
- package/dist/features/search/jobs/semantic-search.worker.d.ts +101 -0
- package/dist/features/search/public-search.router.d.ts +15 -0
- package/dist/features/search/search.d.ts +14 -6
- package/dist/features/search/semantic-search.hooks.d.ts +2 -0
- package/dist/features/search/semantic-search.worker.d.ts +21 -0
- package/dist/features/search/types.d.ts +100 -0
- package/dist/features/search/utils/search-utils.d.ts +56 -0
- package/dist/features/seeds/seeds.destructive.d.ts +6 -0
- package/dist/features/seeds/seeds.handler.d.ts +14 -0
- package/dist/features/seeds/seeds.helpers.d.ts +118 -0
- package/dist/features/seeds/seeds.mcp.d.ts +37 -0
- package/dist/features/upload/index.d.ts +2 -2
- package/dist/index.js +3544 -1368
- package/dist/middleware/auth.middleware.d.ts +34 -4
- package/dist/middleware/oauth-scope.middleware.d.ts +60 -0
- package/dist/middleware/rate-limit.middleware.d.ts +4 -2
- package/dist/middleware/repository.middleware.d.ts +9 -1
- package/dist/public/api-key-middleware.d.ts +0 -4
- package/dist/public/public-add.d.ts +1 -1
- package/dist/rate-limit/in-memory-rate-limiter.d.ts +1 -8
- package/dist/shared/db/repositories/content.repository.d1.d.ts +4 -2
- package/dist/shared/db/repositories/d1-oauth-authorization-code.repository.d.ts +9 -0
- package/dist/shared/db/repositories/d1-oauth-client.repository.d.ts +6 -0
- package/dist/shared/db/repositories/d1-oauth-consent.repository.d.ts +10 -0
- package/dist/shared/db/repositories/d1-oauth-token.repository.d.ts +12 -0
- package/dist/shared/db/repositories/d1-search.query.d.ts +54 -0
- package/dist/shared/db/repositories/d1-vector.repository.d.ts +11 -0
- package/dist/shared/db/repositories/in-memory-seed.repository.d.ts +2 -1
- package/dist/shared/db/repositories/seed.repository.d1.d.ts +3 -1
- package/dist/shared/db/repositories/time-trap-token.repository.d1.d.ts +7 -0
- package/dist/shared/storage/factory.d.ts +84 -4
- package/dist/shared/storage/r2-bucket.d.ts +127 -0
- package/dist/shared/storage/s3-bucket.d.ts +104 -10
- package/dist/shared/storage/upload.d.ts +33 -5
- package/dist/shared/utils/dual-key-rate-limiter.d.ts +21 -0
- package/dist/shared/utils/media-utils.d.ts +3 -3
- package/dist/shared/utils/opaque-token.d.ts +13 -0
- package/dist/types.d.ts +49 -1
- package/migrations/0000_v040_base.sql +184 -1
- package/migrations/_archive/0000_schema_init.sql +257 -0
- package/migrations/_archive/0001_init.sql +25 -0
- package/migrations/_archive/0002_seed_admin.sql +10 -0
- package/migrations/_archive/0003_refresh_tokens.sql +17 -0
- package/migrations/_archive/0004_seed_projects.sql +18 -0
- package/migrations/_archive/0005_update_projects.sql +56 -0
- package/migrations/_archive/0006_add_slug_and_unique_index.sql +7 -0
- package/migrations/_archive/0007_cleanup_test_data.sql +4 -0
- package/migrations/_archive/0008_seed_content_entries.sql +104 -0
- package/migrations/_archive/0009_public_idempotency.sql +11 -0
- package/migrations/_archive/0010_seed_real_data.sql +31 -0
- package/migrations/_archive/0010_testsite_data.sql +31 -0
- package/migrations/_archive/0011_analytics.sql +10 -0
- package/migrations/_archive/0012_seed_analytics.sql +17 -0
- package/migrations/_archive/0013_system_stats.sql +8 -0
- package/migrations/_archive/0014_activity_logs.sql +15 -0
- package/migrations/_archive/0015_notifications.sql +12 -0
- package/migrations/_archive/0016_fts5_global_search.sql +81 -0
- package/migrations/_archive/0017_seed_clienti.sql +90 -0
- package/migrations/_archive/0018_draft_data.sql +3 -0
- package/migrations/_archive/0019_drop_fts_triggers.sql +7 -0
- package/migrations/_archive/0020_composite_indexes.sql +15 -0
- package/migrations/_archive/0021_media_objects.sql +15 -0
- package/migrations/_archive/0022_analytics_seed.sql +23 -0
- package/migrations/_archive/0023_user_profile.sql +4 -0
- package/migrations/_archive/0024_activity_user_name.sql +3 -0
- package/migrations/_archive/0025_password_reset_tokens.sql +11 -0
- package/migrations/_archive/0026_remove_dev_admin.sql +4 -0
- package/migrations/_archive/0027_v040_doctype_architecture.sql +51 -0
- package/migrations/_archive/0029_fts_all_text_branches.sql +281 -0
- package/migrations/_archive/0031_site_settings.sql +9 -0
- package/migrations/_archive/0032_seeds.sql +28 -0
- package/migrations/_archive/0033_dashboard_layouts.sql +14 -0
- package/migrations/_archive/0034_kanban_foundation.sql +24 -0
- package/migrations/_archive/0035_setup_lock.sql +10 -0
- package/migrations/_archive/0036_notification_type_success.sql +23 -0
- package/migrations/_archive/0037_time_trap_tokens.sql +13 -0
- package/migrations/_archive/0038_oauth_authorization.sql +95 -0
- package/migrations/_archive/0039_oauth_client_beech_mcp.sql +20 -0
- package/package.json +3 -5
- package/assets/dashboard/assets/index-B58kBLrh.css +0 -1
- package/assets/dashboard/assets/index-DjniT5Z9.js +0 -745
- package/assets/dashboard/assets/pie-chart-recharts-CnVomiSi.js +0 -1
- package/assets/dashboard/assets/timeseries-chart-recharts-CTqi8qnV.js +0 -1
- /package/migrations/{0029_automations.sql → _archive/0029_automations.sql} +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Beech CMS — Initial Schema Migration
|
|
3
|
+
-- Version: 0.2.0
|
|
4
|
+
--
|
|
5
|
+
-- This is the ONLY migration new installations need to run.
|
|
6
|
+
-- It creates the complete database schema from scratch with no seed data.
|
|
7
|
+
-- No sample content, no dev users — all zeroes, ready for production.
|
|
8
|
+
--
|
|
9
|
+
-- Usage:
|
|
10
|
+
-- npx wrangler d1 execute beech-db --file=migrations/0000_schema_init.sql (remote)
|
|
11
|
+
-- npx wrangler d1 execute beech-db --local --file=migrations/0000_schema_init.sql (local)
|
|
12
|
+
--
|
|
13
|
+
-- After running this migration, create your first admin user via:
|
|
14
|
+
-- POST /auth/setup { email, password, name }
|
|
15
|
+
-- =============================================================================
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
-- =============================================================================
|
|
19
|
+
-- 1. USERS
|
|
20
|
+
-- Stores dashboard users (admins and editors).
|
|
21
|
+
-- Passwords are stored as bcrypt hashes — never plaintext.
|
|
22
|
+
-- Profile columns (name, avatar_url, notification_prefs) are included
|
|
23
|
+
-- from the start (merged from migrations 0001 + 0023).
|
|
24
|
+
-- =============================================================================
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
27
|
+
id TEXT PRIMARY KEY, -- UUID v4
|
|
28
|
+
email TEXT UNIQUE NOT NULL,
|
|
29
|
+
password_hash TEXT NOT NULL, -- bcrypt
|
|
30
|
+
role TEXT DEFAULT 'editor', -- 'admin' | 'editor'
|
|
31
|
+
name TEXT,
|
|
32
|
+
avatar_url TEXT,
|
|
33
|
+
notification_prefs TEXT NOT NULL DEFAULT '{}', -- JSON
|
|
34
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
-- =============================================================================
|
|
39
|
+
-- 2. CONTENT ENTRIES
|
|
40
|
+
-- The single atomic table for all content types.
|
|
41
|
+
-- Field data is stored as a JSON blob keyed by Botanical IDs (br01, br02…).
|
|
42
|
+
-- slug and status are top-level columns for high-performance SQL indexing.
|
|
43
|
+
-- draft_data mirrors data format — NULL means no pending draft.
|
|
44
|
+
-- =============================================================================
|
|
45
|
+
|
|
46
|
+
CREATE TABLE IF NOT EXISTS content_entries (
|
|
47
|
+
id TEXT PRIMARY KEY, -- UUID v4
|
|
48
|
+
schema_slug TEXT NOT NULL, -- e.g. "articoli"
|
|
49
|
+
slug TEXT, -- URL identifier (unique per schema_slug)
|
|
50
|
+
status TEXT NOT NULL DEFAULT 'draft', -- 'draft' | 'published'
|
|
51
|
+
data TEXT NOT NULL DEFAULT '{}', -- JSON blob (Botanical IDs)
|
|
52
|
+
draft_data TEXT, -- Pending draft JSON (NULL = no draft)
|
|
53
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
54
|
+
updated_at INTEGER DEFAULT (unixepoch())
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
-- Unique constraint: one slug per content type
|
|
58
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_ce_schema_slug
|
|
59
|
+
ON content_entries(schema_slug, slug);
|
|
60
|
+
|
|
61
|
+
-- Primary query pattern: filtered list + chronological sort
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_ce_slug_status_created
|
|
63
|
+
ON content_entries(schema_slug, status, created_at DESC);
|
|
64
|
+
|
|
65
|
+
-- Dashboard "recently updated" widget
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_ce_slug_updated
|
|
67
|
+
ON content_entries(schema_slug, updated_at DESC);
|
|
68
|
+
|
|
69
|
+
-- Pending drafts filter (partial index — only rows with a draft)
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_ce_draft_pending
|
|
71
|
+
ON content_entries(schema_slug) WHERE draft_data IS NOT NULL;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
-- =============================================================================
|
|
75
|
+
-- 3. REFRESH TOKENS
|
|
76
|
+
-- JWT refresh token rotation. Tokens are stored as SHA-256 hashes.
|
|
77
|
+
-- Revoked tokens are kept (revoked_at IS NOT NULL) for audit purposes
|
|
78
|
+
-- and pruned by a background job or on next login.
|
|
79
|
+
-- =============================================================================
|
|
80
|
+
|
|
81
|
+
CREATE TABLE IF NOT EXISTS refresh_tokens (
|
|
82
|
+
id TEXT PRIMARY KEY, -- UUID v4
|
|
83
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
84
|
+
token_hash TEXT NOT NULL, -- SHA-256 of the raw token
|
|
85
|
+
expires_at INTEGER NOT NULL, -- Unix timestamp (7-day TTL)
|
|
86
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
87
|
+
revoked_at INTEGER DEFAULT NULL -- NULL = active
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
CREATE INDEX IF NOT EXISTS idx_refresh_user ON refresh_tokens(user_id);
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_refresh_hash ON refresh_tokens(token_hash);
|
|
92
|
+
CREATE INDEX IF NOT EXISTS idx_refresh_expires ON refresh_tokens(expires_at);
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
-- =============================================================================
|
|
96
|
+
-- 4. PASSWORD RESET TOKENS
|
|
97
|
+
-- Single-use, 30-minute TTL, stored as SHA-256 hashes.
|
|
98
|
+
-- used_at is set on redemption to prevent replay attacks.
|
|
99
|
+
-- =============================================================================
|
|
100
|
+
|
|
101
|
+
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
|
102
|
+
id TEXT PRIMARY KEY,
|
|
103
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
104
|
+
token_hash TEXT NOT NULL,
|
|
105
|
+
expires_at INTEGER NOT NULL,
|
|
106
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
107
|
+
used_at INTEGER DEFAULT NULL
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_prt_hash ON password_reset_tokens(token_hash);
|
|
111
|
+
CREATE INDEX IF NOT EXISTS idx_prt_user ON password_reset_tokens(user_id);
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
-- =============================================================================
|
|
115
|
+
-- 5. PUBLIC API — IDEMPOTENCY KEYS
|
|
116
|
+
-- Deduplicates POST requests from public consumers (e.g. contact forms).
|
|
117
|
+
-- expired_at-based pruning keeps the table small.
|
|
118
|
+
-- =============================================================================
|
|
119
|
+
|
|
120
|
+
CREATE TABLE IF NOT EXISTS public_idempotency_keys (
|
|
121
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
122
|
+
request_fingerprint TEXT NOT NULL,
|
|
123
|
+
response_status INTEGER NOT NULL,
|
|
124
|
+
response_body TEXT NOT NULL,
|
|
125
|
+
created_at INTEGER NOT NULL,
|
|
126
|
+
expires_at INTEGER NOT NULL
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
CREATE INDEX IF NOT EXISTS idx_public_idempotency_expires
|
|
130
|
+
ON public_idempotency_keys(expires_at);
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
-- =============================================================================
|
|
134
|
+
-- 6. ANALYTICS
|
|
135
|
+
-- Daily metric counters per seed (content type) and global (seed = '').
|
|
136
|
+
-- The empty string sentinel for global metrics avoids SQLite's NULL ≠ NULL
|
|
137
|
+
-- behavior in UNIQUE indexes.
|
|
138
|
+
-- Metrics: 'requests' | 'visitors' | 'bandwidth_mb'
|
|
139
|
+
-- =============================================================================
|
|
140
|
+
|
|
141
|
+
CREATE TABLE IF NOT EXISTS analytics (
|
|
142
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143
|
+
day_ts INTEGER NOT NULL,
|
|
144
|
+
metric TEXT NOT NULL,
|
|
145
|
+
seed TEXT NOT NULL DEFAULT '', -- '' = global metric, 'articoli' = per-seed
|
|
146
|
+
value INTEGER DEFAULT 0,
|
|
147
|
+
UNIQUE(day_ts, metric, seed)
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
CREATE INDEX IF NOT EXISTS idx_analytics_day ON analytics(day_ts);
|
|
151
|
+
CREATE INDEX IF NOT EXISTS idx_analytics_seed ON analytics(seed, day_ts);
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
-- =============================================================================
|
|
155
|
+
-- 7. SYSTEM STATS
|
|
156
|
+
-- Persistent key-value store for system-level counters.
|
|
157
|
+
-- The 'total_storage_bytes' key is the canonical record for R2 usage.
|
|
158
|
+
-- SUM(size_bytes) FROM media_objects is the authoritative source;
|
|
159
|
+
-- this row is kept for backward compatibility with dashboard widgets.
|
|
160
|
+
-- =============================================================================
|
|
161
|
+
|
|
162
|
+
CREATE TABLE IF NOT EXISTS system_stats (
|
|
163
|
+
id TEXT PRIMARY KEY,
|
|
164
|
+
value TEXT NOT NULL
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
INSERT OR IGNORE INTO system_stats (id, value) VALUES ('total_storage_bytes', '0');
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
-- =============================================================================
|
|
171
|
+
-- 8. ACTIVITY LOGS (AUDIT LOG)
|
|
172
|
+
-- Append-only log of user actions. No FK on user_id for portability —
|
|
173
|
+
-- deleted users are retained in the log for compliance.
|
|
174
|
+
-- user_name is denormalized to survive user deletions.
|
|
175
|
+
-- Actions: 'create' | 'update' | 'delete' | 'upload'
|
|
176
|
+
-- Entity types: 'content' | 'media'
|
|
177
|
+
-- =============================================================================
|
|
178
|
+
|
|
179
|
+
CREATE TABLE IF NOT EXISTS activity_logs (
|
|
180
|
+
id TEXT PRIMARY KEY,
|
|
181
|
+
user_id TEXT NOT NULL,
|
|
182
|
+
user_email TEXT NOT NULL,
|
|
183
|
+
user_name TEXT, -- denormalized; survives user deletion
|
|
184
|
+
action TEXT NOT NULL,
|
|
185
|
+
entity_type TEXT NOT NULL,
|
|
186
|
+
entity_id TEXT NOT NULL,
|
|
187
|
+
entity_slug TEXT,
|
|
188
|
+
details TEXT, -- JSON metadata blob
|
|
189
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
CREATE INDEX IF NOT EXISTS idx_activity_user ON activity_logs(user_id);
|
|
193
|
+
CREATE INDEX IF NOT EXISTS idx_activity_created ON activity_logs(created_at);
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
-- =============================================================================
|
|
197
|
+
-- 9. NOTIFICATIONS
|
|
198
|
+
-- In-app notification inbox for system events (e.g. new form submission).
|
|
199
|
+
-- is_read uses INTEGER 0/1 (SQLite has no native BOOLEAN).
|
|
200
|
+
-- =============================================================================
|
|
201
|
+
|
|
202
|
+
CREATE TABLE IF NOT EXISTS notifications (
|
|
203
|
+
id TEXT PRIMARY KEY,
|
|
204
|
+
title TEXT NOT NULL,
|
|
205
|
+
message TEXT NOT NULL,
|
|
206
|
+
type TEXT DEFAULT 'info', -- 'info' | 'warning' | 'error'
|
|
207
|
+
is_read INTEGER DEFAULT 0,
|
|
208
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_created ON notifications(created_at);
|
|
212
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_unread ON notifications(is_read);
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
-- =============================================================================
|
|
216
|
+
-- 10. MEDIA OBJECTS
|
|
217
|
+
-- Tracks every file uploaded to R2. Enables media library UI, orphan
|
|
218
|
+
-- detection, and per-user storage reporting.
|
|
219
|
+
-- No FK on uploaded_by (soft reference) for D1 portability.
|
|
220
|
+
-- =============================================================================
|
|
221
|
+
|
|
222
|
+
CREATE TABLE IF NOT EXISTS media_objects (
|
|
223
|
+
key TEXT PRIMARY KEY, -- R2 object key (e.g. "1713600000-img.jpg")
|
|
224
|
+
filename TEXT NOT NULL, -- original filename pre-sanitize
|
|
225
|
+
mime_type TEXT NOT NULL,
|
|
226
|
+
size_bytes INTEGER NOT NULL,
|
|
227
|
+
uploaded_by TEXT NOT NULL DEFAULT '', -- users.id soft reference
|
|
228
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
CREATE INDEX IF NOT EXISTS idx_media_user ON media_objects(uploaded_by);
|
|
232
|
+
CREATE INDEX IF NOT EXISTS idx_media_created ON media_objects(created_at DESC);
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
-- =============================================================================
|
|
236
|
+
-- 11. FTS5 — FULL TEXT SEARCH
|
|
237
|
+
-- Virtual table for global content search across all seeds.
|
|
238
|
+
-- entry_id, schema_slug and status are UNINDEXED (used for filtering,
|
|
239
|
+
-- not full-text matching).
|
|
240
|
+
-- FTS sync is handled at the application layer by shared/fts-sync.ts
|
|
241
|
+
-- using the Botanical Engine — no hardcoded branch IDs, works for any seed.
|
|
242
|
+
-- Tokenizer: unicode61 with diacritic removal for accent-insensitive search.
|
|
243
|
+
-- =============================================================================
|
|
244
|
+
|
|
245
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS content_fts USING fts5(
|
|
246
|
+
entry_id UNINDEXED, -- PK of content_entries
|
|
247
|
+
schema_slug UNINDEXED, -- for filtering by content type
|
|
248
|
+
title, -- displayNameAlias field value
|
|
249
|
+
body, -- richtext / text secondary field
|
|
250
|
+
tags, -- tags array (JSON array → flat string)
|
|
251
|
+
status UNINDEXED, -- for filtering by publication status
|
|
252
|
+
tokenize = 'unicode61 remove_diacritics 1'
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
-- No FTS triggers — sync is application-layer only (see shared/fts-sync.ts).
|
|
256
|
+
-- SQL triggers were removed because they hardcoded branch IDs from sample seeds
|
|
257
|
+
-- and silently broke indexing for custom seeds (see architecture.md §10).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- Migrazione iniziale: Struttura Base Beech CMS
|
|
2
|
+
|
|
3
|
+
-- 1. Tabella UTENTI (Per il login)
|
|
4
|
+
DROP TABLE IF EXISTS users;
|
|
5
|
+
CREATE TABLE users (
|
|
6
|
+
id TEXT PRIMARY KEY, -- UUID generato via codice
|
|
7
|
+
email TEXT UNIQUE NOT NULL, -- Email di login
|
|
8
|
+
password_hash TEXT NOT NULL, -- Password criptata
|
|
9
|
+
role TEXT DEFAULT 'editor', -- Ruolo: 'admin' o 'editor'
|
|
10
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
-- 2. Tabella CONTENUTI (Per i dati flessibili JSON)
|
|
14
|
+
DROP TABLE IF EXISTS content_entries;
|
|
15
|
+
CREATE TABLE content_entries (
|
|
16
|
+
id TEXT PRIMARY KEY, -- UUID
|
|
17
|
+
schema_slug TEXT NOT NULL, -- Tipo contenuto (es. 'progetti', 'blog')
|
|
18
|
+
status TEXT DEFAULT 'draft', -- Stato: 'draft' | 'published'
|
|
19
|
+
data TEXT, -- IL JSON: Qui dentro salviamo tutto il resto
|
|
20
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
21
|
+
updated_at INTEGER DEFAULT (unixepoch())
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
-- 3. Indici per velocizzare le ricerche
|
|
25
|
+
CREATE INDEX idx_content_schema ON content_entries(schema_slug);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- Utente admin di test per sviluppo
|
|
2
|
+
-- Email: admin@beech.local
|
|
3
|
+
-- Password: password123
|
|
4
|
+
INSERT OR IGNORE INTO users (id, email, password_hash, role)
|
|
5
|
+
VALUES (
|
|
6
|
+
'admin-seed-001',
|
|
7
|
+
'admin@beech.local',
|
|
8
|
+
'$2a$10$L28S3Fy29jhsCE40e/eMu.0BBj6bkMvHsT0yvZAh9weGiGko1jAf2',
|
|
9
|
+
'admin'
|
|
10
|
+
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Migrazione: Tabella Refresh Tokens per JWT rotation
|
|
2
|
+
-- Salva refresh tokens con hash SHA-256 per sicurezza e possibilità di revoca
|
|
3
|
+
-- Idempotente: IF NOT EXISTS per esecuzioni ripetute
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS refresh_tokens (
|
|
6
|
+
id TEXT PRIMARY KEY, -- UUID del token
|
|
7
|
+
user_id TEXT NOT NULL, -- Riferimento a users.id
|
|
8
|
+
token_hash TEXT NOT NULL, -- Hash SHA-256 del token (non salvare in chiaro)
|
|
9
|
+
expires_at INTEGER NOT NULL, -- Unix timestamp scadenza (7 giorni)
|
|
10
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
11
|
+
revoked_at INTEGER DEFAULT NULL, -- NULL = attivo, timestamp = revocato
|
|
12
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_refresh_user ON refresh_tokens(user_id);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_refresh_hash ON refresh_tokens(token_hash);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_refresh_expires ON refresh_tokens(expires_at);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Migration 0003: Seed Projects - Dati di esempio per testare tutti i tipi di Branch
|
|
2
|
+
-- Inserisce 5 progetti con tutti i tipi di campo: text, number, boolean, date, json
|
|
3
|
+
|
|
4
|
+
INSERT INTO content_entries (id, schema_slug, data, created_at, updated_at) VALUES
|
|
5
|
+
-- Progetto 1: Tutti i campi popolati - Tags con colori blu/cyan/viola
|
|
6
|
+
('550e8400-e29b-41d4-a716-446655440001', 'progetti', '{"br_01":"Beech CMS","br_02":"Sistema di gestione contenuti modulare e schema-driven","br_03":156000,"br_04":75.5,"br_05":true,"br_06":true,"br_07":"2024-01-15","br_08":"2024-12-31","br_09":"{\"client\":\"Acme Corp\",\"priority\":\"high\",\"team\":[\"Mario\",\"Luigi\"]}","br_10":"{\"cms\":\"#3b82f6\",\"react\":\"#06b6d4\",\"cloudflare\":\"#f97316\"}"}', 1705276800, 1705276800),
|
|
7
|
+
|
|
8
|
+
-- Progetto 2: Mix di valori - Tags con colori rosa/verde/giallo
|
|
9
|
+
('550e8400-e29b-41d4-a716-446655440002', 'progetti', '{"br_01":"Beech Studio","br_02":"Applicazione web per gestione progetti creativi","br_03":450000,"br_04":33.3,"br_05":true,"br_06":false,"br_07":"2024-03-01","br_08":"2025-06-30","br_09":"{\"client\":\"Studio X\",\"priority\":\"medium\"}","br_10":"{\"design\":\"#ec4899\",\"web\":\"#10b981\",\"mobile\":\"#f59e0b\"}"}', 1709251200, 1709251200),
|
|
10
|
+
|
|
11
|
+
-- Progetto 3: Progetto inattivo - Tags con colori viola/lime
|
|
12
|
+
('550e8400-e29b-41d4-a716-446655440003', 'progetti', '{"br_01":"Beech Website","br_02":"Sito istituzionale aziendale con landing pages","br_03":89000,"br_04":100,"br_05":false,"br_06":true,"br_07":"2023-06-15","br_08":"2023-12-20","br_09":"{\"client\":\"BeechCo\",\"priority\":\"low\"}","br_10":"{\"website\":\"#8b5cf6\",\"landing\":\"#84cc16\"}"}', 1686787200, 1702944000),
|
|
13
|
+
|
|
14
|
+
-- Progetto 4: Appena iniziato (0%) - Tags con colori rosso/giallo/indaco
|
|
15
|
+
('550e8400-e29b-41d4-a716-446655440004', 'progetti', '{"br_01":"E-commerce Platform","br_02":"Piattaforma completa per vendita online multi-tenant","br_03":1250000,"br_04":0,"br_05":true,"br_06":false,"br_07":"2026-02-01","br_08":"2027-01-31","br_09":"{\"client\":\"ShopCo\",\"priority\":\"high\",\"technologies\":[\"Next.js\",\"Stripe\"]}","br_10":"{\"e-commerce\":\"#ef4444\",\"payments\":\"#eab308\",\"saas\":\"#6366f1\"}"}', 1738368000, 1738368000),
|
|
16
|
+
|
|
17
|
+
-- Progetto 5: Grande progetto con JSON complesso - Tags con colori viola/verde/rosa
|
|
18
|
+
('550e8400-e29b-41d4-a716-446655440005', 'progetti', '{"br_01":"Mobile App","br_02":"Applicazione mobile iOS/Android per tracciamento fitness","br_03":680000,"br_04":42.8,"br_05":true,"br_06":false,"br_07":"2024-09-01","br_08":"2025-03-31","br_09":"{\"client\":\"FitTech Inc\",\"priority\":\"high\",\"platforms\":[\"iOS\",\"Android\"],\"features\":[\"tracking\",\"gamification\",\"social\"]}","br_10":"{\"mobile\":\"#a855f7\",\"fitness\":\"#22c55e\",\"react-native\":\"#f472b6\"}"}', 1725148800, 1725148800);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
-- Migration 0003 UPDATE: Progetti con tags formato {tag: colore}
|
|
2
|
+
-- Dataset esteso (25 progetti) per testare paginazione e funzionalità tabella
|
|
3
|
+
|
|
4
|
+
DELETE FROM content_entries WHERE schema_slug = 'progetti';
|
|
5
|
+
|
|
6
|
+
INSERT INTO content_entries (id, schema_slug, data, created_at, updated_at) VALUES
|
|
7
|
+
-- Progetto 1
|
|
8
|
+
('550e8400-e29b-41d4-a716-446655440001', 'progetti', '{"br_01":"Beech CMS","br_02":"Sistema di gestione contenuti modulare e schema-driven","br_03":156000,"br_04":75.5,"br_05":true,"br_06":true,"br_07":"2024-01-15","br_08":"2024-12-31","br_09":"{\"client\":\"Acme Corp\",\"priority\":\"high\",\"team\":[\"Mario\",\"Luigi\"]}","br_10":"{\"cms\":\"#3b82f6\",\"react\":\"#06b6d4\",\"cloudflare\":\"#f97316\"}"}', 1705276800, 1705276800),
|
|
9
|
+
-- Progetto 2
|
|
10
|
+
('550e8400-e29b-41d4-a716-446655440002', 'progetti', '{"br_01":"Beech Studio","br_02":"Applicazione web per gestione progetti creativi","br_03":450000,"br_04":33.3,"br_05":true,"br_06":false,"br_07":"2024-03-01","br_08":"2025-06-30","br_09":"{\"client\":\"Studio X\",\"priority\":\"medium\"}","br_10":"{\"design\":\"#ec4899\",\"web\":\"#10b981\",\"mobile\":\"#f59e0b\"}"}', 1709251200, 1709251200),
|
|
11
|
+
-- Progetto 3
|
|
12
|
+
('550e8400-e29b-41d4-a716-446655440003', 'progetti', '{"br_01":"Beech Website","br_02":"Sito istituzionale aziendale con landing pages","br_03":89000,"br_04":100,"br_05":false,"br_06":true,"br_07":"2023-06-15","br_08":"2023-12-20","br_09":"{\"client\":\"BeechCo\",\"priority\":\"low\"}","br_10":"{\"website\":\"#8b5cf6\",\"landing\":\"#84cc16\"}"}', 1686787200, 1702944000),
|
|
13
|
+
-- Progetto 4
|
|
14
|
+
('550e8400-e29b-41d4-a716-446655440004', 'progetti', '{"br_01":"E-commerce Platform","br_02":"Piattaforma completa per vendita online multi-tenant","br_03":1250000,"br_04":0,"br_05":true,"br_06":false,"br_07":"2026-02-01","br_08":"2027-01-31","br_09":"{\"client\":\"ShopCo\",\"priority\":\"high\",\"technologies\":[\"Next.js\",\"Stripe\"]}","br_10":"{\"e-commerce\":\"#ef4444\",\"payments\":\"#eab308\",\"saas\":\"#6366f1\"}"}', 1738368000, 1738368000),
|
|
15
|
+
-- Progetto 5
|
|
16
|
+
('550e8400-e29b-41d4-a716-446655440005', 'progetti', '{"br_01":"Mobile App","br_02":"Applicazione mobile iOS/Android per tracciamento fitness","br_03":680000,"br_04":42.8,"br_05":true,"br_06":false,"br_07":"2024-09-01","br_08":"2025-03-31","br_09":"{\"client\":\"FitTech Inc\",\"priority\":\"high\",\"platforms\":[\"iOS\",\"Android\"],\"features\":[\"tracking\",\"gamification\",\"social\"]}","br_10":"{\"mobile\":\"#a855f7\",\"fitness\":\"#22c55e\",\"react-native\":\"#f472b6\"}"}', 1725148800, 1725148800),
|
|
17
|
+
-- Progetto 6
|
|
18
|
+
('550e8400-e29b-41d4-a716-446655440006', 'progetti', '{"br_01":"Portale B2B","br_02":"Portale aziendale per ordini e gestione fornitori","br_03":320000,"br_04":88,"br_05":true,"br_06":true,"br_07":"2024-02-10","br_08":"2025-02-28","br_09":"{\"client\":\"LogiCorp\",\"priority\":\"high\"}","br_10":"{\"b2b\":\"#0ea5e9\",\"portal\":\"#14b8a6\",\"enterprise\":\"#64748b\"}"}', 1707523200, 1735689600),
|
|
19
|
+
-- Progetto 7
|
|
20
|
+
('550e8400-e29b-41d4-a716-446655440007', 'progetti', '{"br_01":"Dashboard Analytics","br_02":"Dashboard real-time per metriche di business e KPI","br_03":185000,"br_04":100,"br_05":true,"br_06":true,"br_07":"2023-11-01","br_08":"2024-05-15","br_09":"{\"client\":\"DataFlow\",\"priority\":\"medium\"}","br_10":"{\"analytics\":\"#8b5cf6\",\"charts\":\"#06b6d4\",\"real-time\":\"#22c55e\"}"}', 1698796800, 1715731200),
|
|
21
|
+
-- Progetto 8
|
|
22
|
+
('550e8400-e29b-41d4-a716-446655440008', 'progetti', '{"br_01":"Blog Redesign","br_02":"Restyling completo del blog aziendale con nuovo CMS","br_03":45000,"br_04":65,"br_05":true,"br_06":false,"br_07":"2024-07-01","br_08":"2024-12-15","br_09":"{\"client\":\"MediaHub\",\"priority\":\"low\"}","br_10":"{\"blog\":\"#f59e0b\",\"cms\":\"#3b82f6\",\"design\":\"#ec4899\"}"}', 1719792000, 1734048000),
|
|
23
|
+
-- Progetto 9
|
|
24
|
+
('550e8400-e29b-41d4-a716-446655440009', 'progetti', '{"br_01":"API Gateway","br_02":"Gateway centralizzato per microservizi con rate limiting","br_03":220000,"br_04":55,"br_05":true,"br_06":false,"br_07":"2024-05-15","br_08":"2025-08-30","br_09":"{\"client\":\"TechScale\",\"priority\":\"high\"}","br_10":"{\"api\":\"#6366f1\",\"microservices\":\"#a855f7\",\"gateway\":\"#0ea5e9\"}"}', 1715731200, 1725148800),
|
|
25
|
+
-- Progetto 10
|
|
26
|
+
('550e8400-e29b-41d4-a716-446655440010', 'progetti', '{"br_01":"Intranet Aziendale","br_02":"Portale interno per documenti e comunicazioni","br_03":95000,"br_04":92,"br_05":true,"br_06":true,"br_07":"2023-09-01","br_08":"2024-06-30","br_09":"{\"client\":\"BigCorp\",\"priority\":\"medium\"}","br_10":"{\"intranet\":\"#64748b\",\"documents\":\"#14b8a6\",\"internal\":\"#f97316\"}"}', 1693526400, 1719792000),
|
|
27
|
+
-- Progetto 11
|
|
28
|
+
('550e8400-e29b-41d4-a716-446655440011', 'progetti', '{"br_01":"App Prenotazioni","br_02":"App per prenotazione ristoranti e gestione tavoli","br_03":78000,"br_04":28,"br_05":true,"br_06":false,"br_07":"2024-10-01","br_08":"2025-04-30","br_09":"{\"client\":\"RestoApp\",\"priority\":\"medium\"}","br_10":"{\"booking\":\"#22c55e\",\"restaurant\":\"#ef4444\",\"mobile\":\"#a855f7\"}"}', 1727740800, 1735689600),
|
|
29
|
+
-- Progetto 12
|
|
30
|
+
('550e8400-e29b-41d4-a716-446655440012', 'progetti', '{"br_01":"Marketplace NFT","br_02":"Piattaforma per acquisto e vendita di NFT con wallet integrato","br_03":890000,"br_04":15,"br_05":true,"br_06":false,"br_07":"2025-01-15","br_08":"2026-01-31","br_09":"{\"client\":\"CryptoArt\",\"priority\":\"high\"}","br_10":"{\"nft\":\"#f59e0b\",\"blockchain\":\"#6366f1\",\"web3\":\"#22c55e\"}"}', 1736899200, 1736899200),
|
|
31
|
+
-- Progetto 13
|
|
32
|
+
('550e8400-e29b-41d4-a716-446655440013', 'progetti', '{"br_01":"Sistema Ticketing","br_02":"Sistema di gestione ticket e supporto clienti","br_03":125000,"br_04":78,"br_05":true,"br_06":true,"br_07":"2024-01-20","br_08":"2024-11-30","br_09":"{\"client\":\"SupportPro\",\"priority\":\"high\"}","br_10":"{\"ticketing\":\"#0ea5e9\",\"support\":\"#14b8a6\",\"helpdesk\":\"#64748b\"}"}', 1705622400, 1732924800),
|
|
33
|
+
-- Progetto 14
|
|
34
|
+
('550e8400-e29b-41d4-a716-446655440014', 'progetti', '{"br_01":"LMS Educativo","br_02":"Piattaforma di apprendimento online con corsi e quiz","br_03":340000,"br_04":45,"br_05":true,"br_06":false,"br_07":"2024-04-01","br_08":"2025-09-30","br_09":"{\"client\":\"EduTech\",\"priority\":\"medium\"}","br_10":"{\"lms\":\"#8b5cf6\",\"education\":\"#06b6d4\",\"courses\":\"#22c55e\"}"}', 1711929600, 1725148800),
|
|
35
|
+
-- Progetto 15
|
|
36
|
+
('550e8400-e29b-41d4-a716-446655440015', 'progetti', '{"br_01":"Chat in tempo reale","br_02":"Sistema di messaggistica con WebSocket e notifiche push","br_03":195000,"br_04":60,"br_05":true,"br_06":false,"br_07":"2024-06-01","br_08":"2025-02-28","br_09":"{\"client\":\"ConnectApp\",\"priority\":\"high\"}","br_10":"{\"chat\":\"#0ea5e9\",\"websocket\":\"#6366f1\",\"realtime\":\"#22c55e\"}"}', 1717200000, 1730419200),
|
|
37
|
+
-- Progetto 16
|
|
38
|
+
('550e8400-e29b-41d4-a716-446655440016', 'progetti', '{"br_01":"Portfolio Fotografico","br_02":"Sito portfolio per fotografi con galleria e lightbox","br_03":28000,"br_04":100,"br_05":true,"br_06":true,"br_07":"2023-08-01","br_08":"2023-12-15","br_09":"{\"client\":\"PhotoStudio\",\"priority\":\"low\"}","br_10":"{\"portfolio\":\"#ec4899\",\"photography\":\"#64748b\",\"gallery\":\"#f59e0b\"}"}', 1690848000, 1702684800),
|
|
39
|
+
-- Progetto 17
|
|
40
|
+
('550e8400-e29b-41d4-a716-446655440017', 'progetti', '{"br_01":"ERP Custom","br_02":"Sistema ERP su misura per industria manifatturiera","br_03":750000,"br_04":22,"br_05":true,"br_06":false,"br_07":"2024-11-01","br_08":"2026-06-30","br_09":"{\"client\":\"ManuCorp\",\"priority\":\"high\"}","br_10":"{\"erp\":\"#6366f1\",\"manufacturing\":\"#64748b\",\"enterprise\":\"#0ea5e9\"}"}', 1730419200, 1730419200),
|
|
41
|
+
-- Progetto 18
|
|
42
|
+
('550e8400-e29b-41d4-a716-446655440018', 'progetti', '{"br_01":"App Meteo","br_02":"Applicazione meteo con previsioni e mappe interattive","br_03":52000,"br_04":95,"br_05":true,"br_06":true,"br_07":"2024-02-01","br_08":"2024-08-31","br_09":"{\"client\":\"WeatherPro\",\"priority\":\"medium\"}","br_10":"{\"weather\":\"#0ea5e9\",\"maps\":\"#22c55e\",\"mobile\":\"#a855f7\"}"}', 1706745600, 1725148800),
|
|
43
|
+
-- Progetto 19
|
|
44
|
+
('550e8400-e29b-41d4-a716-446655440019', 'progetti', '{"br_01":"Sistema Prenotazione Hotel","br_02":"Piattaforma per prenotazioni alberghiere con disponibilità in tempo reale","br_03":265000,"br_04":70,"br_05":true,"br_06":false,"br_07":"2024-03-15","br_08":"2025-03-31","br_09":"{\"client\":\"HotelChain\",\"priority\":\"high\"}","br_10":"{\"booking\":\"#22c55e\",\"hotel\":\"#ef4444\",\"hospitality\":\"#f59e0b\"}"}', 1710460800, 1732924800),
|
|
45
|
+
-- Progetto 20
|
|
46
|
+
('550e8400-e29b-41d4-a716-446655440020', 'progetti', '{"br_01":"Social Network Niche","br_02":"Rete sociale verticale per professionisti del settore medico","br_03":420000,"br_04":38,"br_05":true,"br_06":false,"br_07":"2024-08-01","br_08":"2025-12-31","br_09":"{\"client\":\"MedConnect\",\"priority\":\"high\"}","br_10":"{\"social\":\"#ec4899\",\"healthcare\":\"#22c55e\",\"professional\":\"#6366f1\"}"}', 1722470400, 1735689600),
|
|
47
|
+
-- Progetto 21
|
|
48
|
+
('550e8400-e29b-41d4-a716-446655440021', 'progetti', '{"br_01":"Automazione Marketing","br_02":"Tool per email marketing e automazione campagne","br_03":158000,"br_04":82,"br_05":true,"br_06":true,"br_07":"2023-12-01","br_08":"2024-09-30","br_09":"{\"client\":\"MarketPro\",\"priority\":\"medium\"}","br_10":"{\"marketing\":\"#ec4899\",\"automation\":\"#8b5cf6\",\"email\":\"#0ea5e9\"}"}', 1701388800, 1727740800),
|
|
49
|
+
-- Progetto 22
|
|
50
|
+
('550e8400-e29b-41d4-a716-446655440022', 'progetti', '{"br_01":"Gestione Magazzino","br_02":"Sistema WMS per inventario e logistica","br_03":189000,"br_04":58,"br_05":true,"br_06":false,"br_07":"2024-05-01","br_08":"2025-04-30","br_09":"{\"client\":\"LogiWare\",\"priority\":\"high\"}","br_10":"{\"wms\":\"#f97316\",\"logistics\":\"#64748b\",\"inventory\":\"#22c55e\"}"}', 1714521600, 1732924800),
|
|
51
|
+
-- Progetto 23
|
|
52
|
+
('550e8400-e29b-41d4-a716-446655440023', 'progetti', '{"br_01":"Streaming Video","br_02":"Piattaforma video on-demand con transcoding","br_03":580000,"br_04":25,"br_05":true,"br_06":false,"br_07":"2025-02-01","br_08":"2026-06-30","br_09":"{\"client\":\"StreamHub\",\"priority\":\"high\"}","br_10":"{\"streaming\":\"#ef4444\",\"video\":\"#8b5cf6\",\"transcoding\":\"#06b6d4\"}"}', 1738368000, 1738368000),
|
|
53
|
+
-- Progetto 24
|
|
54
|
+
('550e8400-e29b-41d4-a716-446655440024', 'progetti', '{"br_01":"App Delivery","br_02":"App per consegne a domicilio con tracking GPS","br_03":235000,"br_04":67,"br_05":true,"br_06":false,"br_07":"2024-04-15","br_08":"2025-05-31","br_09":"{\"client\":\"QuickDeliver\",\"priority\":\"high\"}","br_10":"{\"delivery\":\"#f97316\",\"gps\":\"#22c55e\",\"mobile\":\"#a855f7\"}"}', 1713139200, 1732924800),
|
|
55
|
+
-- Progetto 25
|
|
56
|
+
('550e8400-e29b-41d4-a716-446655440025', 'progetti', '{"br_01":"Dashboard Amministrativa","br_02":"Pannello admin per gestione utenti e configurazioni","br_03":72000,"br_04":100,"br_05":true,"br_06":true,"br_07":"2023-10-01","br_08":"2024-03-31","br_09":"{\"client\":\"AdminSuite\",\"priority\":\"medium\"}","br_10":"{\"admin\":\"#64748b\",\"dashboard\":\"#6366f1\",\"config\":\"#14b8a6\"}"}', 1696118400, 1711929600);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- Migrazione 0006: Colonna slug e indice univoco (schema_slug, slug)
|
|
2
|
+
-- Retrocompatibile: slug nullable; entry esistenti restano con slug = NULL.
|
|
3
|
+
-- SQLite: UNIQUE su colonna nullable permette più righe con NULL.
|
|
4
|
+
|
|
5
|
+
ALTER TABLE content_entries ADD COLUMN slug TEXT;
|
|
6
|
+
|
|
7
|
+
CREATE UNIQUE INDEX idx_content_entries_schema_slug_slug ON content_entries(schema_slug, slug);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
-- Migrazione 0008: Seed contenuti demo per tutti i Seed registrati
|
|
2
|
+
-- Slug supportati (vedi SEED_REGISTRY in @beechcms/core):
|
|
3
|
+
-- - articoli
|
|
4
|
+
-- - prodotti
|
|
5
|
+
-- - team
|
|
6
|
+
-- - testimonianze
|
|
7
|
+
-- - pagine
|
|
8
|
+
--
|
|
9
|
+
-- Inseriamo tra 5 e 10 record per ciascun seed, con:
|
|
10
|
+
-- - schema_slug = slug del Seed
|
|
11
|
+
-- - slug leggibile per la URL
|
|
12
|
+
-- - status = 'published'
|
|
13
|
+
-- - data = JSON con chiavi = ID dei Branch (art_*, prd_*, tm_*, tes_*, pag_*)
|
|
14
|
+
|
|
15
|
+
-- Articoli (5)
|
|
16
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
17
|
+
('art-0001', 'articoli', 'benvenuto-nel-blog', 'published',
|
|
18
|
+
'{"art_01":"Benvenuto nel blog Beech","art_02":"2026-01-10","art_03":"/media/blog/cover-welcome.jpg","art_04":"{\"news\":\"#3b82f6\",\"annuncio\":\"#06b6d4\"}","art_05":"<p>Scopri come Beech CMS gestisce contenuti schema-driven.</p>","art_06":"Benvenuto nel blog Beech","art_07":"Introduzione al CMS ibrido SQL/JSON."}',
|
|
19
|
+
unixepoch(), unixepoch()),
|
|
20
|
+
('art-0002', 'articoli', 'roadmap-2026', 'published',
|
|
21
|
+
'{"art_01":"Roadmap prodotto 2026","art_02":"2026-02-05","art_03":"/media/blog/cover-roadmap.jpg","art_04":"{\"release\":\"#8b5cf6\",\"aggiornamento\":\"#10b981\"}","art_05":"<p>Tutte le novità in arrivo per Beech CMS.</p>","art_06":"Roadmap Beech CMS 2026","art_07":"Piano di sviluppo delle funzionalità per il 2026."}',
|
|
22
|
+
unixepoch(), unixepoch()),
|
|
23
|
+
('art-0003', 'articoli', 'migrare-da-wordpress', 'published',
|
|
24
|
+
'{"art_01":"Migrare da WordPress a Beech","art_02":"2026-02-20","art_03":"/media/blog/cover-migration.jpg","art_04":"{\"guida\":\"#f59e0b\",\"cms\":\"#3b82f6\"}","art_05":"<p>Guida pratica per migrare contenuti senza downtime.</p>","art_06":"Migrazione da WordPress","art_07":"Strategie per migrare contenuti in sicurezza."}',
|
|
25
|
+
unixepoch(), unixepoch()),
|
|
26
|
+
('art-0004', 'articoli', 'pattern-registry-ui', 'published',
|
|
27
|
+
'{"art_01":"Il Pattern Registry della UI","art_02":"2026-03-01","art_03":"/media/blog/cover-registry.jpg","art_04":"{\"tutorial\":\"#ec4899\",\"guida\":\"#64748b\"}","art_05":"<p>Come il registry dei field semplifica la dashboard.</p>","art_06":"Pattern Registry UI","art_07":"Architettura dei componenti field-driven."}',
|
|
28
|
+
unixepoch(), unixepoch()),
|
|
29
|
+
('art-0005', 'articoli', 'edge-first-architecture', 'published',
|
|
30
|
+
'{"art_01":"Architettura edge-first con Cloudflare","art_02":"2026-03-05","art_03":"/media/blog/cover-edge.jpg","art_04":"{\"news\":\"#ef4444\",\"aggiornamento\":\"#06b6d4\"}","art_05":"<p>Perché Beech nasce per l'edge.</p>","art_06":"Architettura edge-first","art_07":"Vantaggi di un CMS progettato per l'edge."}',
|
|
31
|
+
unixepoch(), unixepoch());
|
|
32
|
+
|
|
33
|
+
-- Prodotti (5)
|
|
34
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
35
|
+
('prd-0001', 'prodotti', 'beech-starter', 'published',
|
|
36
|
+
'{"prd_01":"Beech Starter","prd_02":490,"prd_03":50,"prd_04":true,"prd_05":"/media/products/starter.png","prd_06":"[\"/media/products/starter-1.png\",\"/media/products/starter-2.png\"]","prd_07":"Piano entry-level per piccoli siti e landing.","prd_08":"Beech Starter","prd_09":"Piano starter per progetti piccoli e medi."}',
|
|
37
|
+
unixepoch(), unixepoch()),
|
|
38
|
+
('prd-0002', 'prodotti', 'beech-pro', 'published',
|
|
39
|
+
'{"prd_01":"Beech Pro","prd_02":1290,"prd_03":30,"prd_04":true,"prd_05":"/media/products/pro.png","prd_06":"[\"/media/products/pro-1.png\",\"/media/products/pro-2.png\"]","prd_07":"Tutte le feature avanzate per team strutturati.","prd_08":"Beech Pro","prd_09":"Piano professionale per agenzie e team marketing."}',
|
|
40
|
+
unixepoch(), unixepoch()),
|
|
41
|
+
('prd-0003', 'prodotti', 'beech-enterprise', 'published',
|
|
42
|
+
'{"prd_01":"Beech Enterprise","prd_02":3990,"prd_03":10,"prd_04":true,"prd_05":"/media/products/enterprise.png","prd_06":"[\"/media/products/enterprise-1.png\"]","prd_07":"Funzionalità enterprise, audit log e multi-ambiente.","prd_08":"Beech Enterprise","prd_09":"Soluzione enterprise per grandi organizzazioni."}',
|
|
43
|
+
unixepoch(), unixepoch()),
|
|
44
|
+
('prd-0004', 'prodotti', 'implementazione-custom', 'published',
|
|
45
|
+
'{"prd_01":"Implementazione custom","prd_02":15000,"prd_03":3,"prd_04":true,"prd_05":"/media/products/custom.png","prd_06":"[]","prd_07":"Servizio di implementazione su misura di Beech CMS.","prd_08":"Implementazione custom Beech","prd_09":"Servizio di onboarding e integrazione personalizzata."}',
|
|
46
|
+
unixepoch(), unixepoch()),
|
|
47
|
+
('prd-0005', 'prodotti', 'workshop-botanical-engine', 'published',
|
|
48
|
+
'{"prd_01":"Workshop Botanical Engine","prd_02":990,"prd_03":20,"prd_04":true,"prd_05":"/media/products/workshop.png","prd_06":"[]","prd_07":"Workshop avanzato sul Botanical Engine e sul registry dei seed.","prd_08":"Workshop Botanical Engine","prd_09":"Formazione per team tecnici su Beech CMS."}',
|
|
49
|
+
unixepoch(), unixepoch());
|
|
50
|
+
|
|
51
|
+
-- Team (5)
|
|
52
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
53
|
+
('tm-0001', 'team', 'flavio-de-musso', 'published',
|
|
54
|
+
'{"tm_01":"Flavio De Musso","tm_02":"Founder & Principal Engineer","tm_03":"Progetta architetture moderne per CMS headless e prodotti digitali.","tm_04":"/media/team/flavio.jpg","tm_05":"https://www.linkedin.com/in/flaviodemusso","tm_06":true,"tm_07":"Flavio De Musso","tm_08":"Founder e creatore di Beech CMS."}',
|
|
55
|
+
unixepoch(), unixepoch()),
|
|
56
|
+
('tm-0002', 'team', 'product-designer', 'published',
|
|
57
|
+
'{"tm_01":"Laura Rossi","tm_02":"Product Designer","tm_03":"Cura la UX della dashboard e dei workflow editoriali.","tm_04":"/media/team/laura.jpg","tm_05":"https://www.linkedin.com","tm_06":true,"tm_07":"Product Designer Beech","tm_08":"UX designer focalizzata su strumenti per content team."}',
|
|
58
|
+
unixepoch(), unixepoch()),
|
|
59
|
+
('tm-0003', 'team', 'frontend-engineer', 'published',
|
|
60
|
+
'{"tm_01":"Marco Bianchi","tm_02":"Frontend Engineer","tm_03":"Sviluppa i field renderer React e il registry della UI.","tm_04":"/media/team/marco.jpg","tm_05":"https://www.linkedin.com","tm_06":true,"tm_07":"Frontend Engineer","tm_08":"Sviluppatore frontend specializzato in React e UX."}',
|
|
61
|
+
unixepoch(), unixepoch()),
|
|
62
|
+
('tm-0004', 'team', 'devrel', 'published',
|
|
63
|
+
'{"tm_01":"Giulia Verdi","tm_02":"Developer Relations","tm_03":"Aiuta i team a integrare Beech CMS nelle loro pipeline.","tm_04":"/media/team/giulia.jpg","tm_05":"https://www.linkedin.com","tm_06":true,"tm_07":"DevRel Beech","tm_08":"Developer advocate per la community Beech."}',
|
|
64
|
+
unixepoch(), unixepoch()),
|
|
65
|
+
('tm-0005', 'team', 'support-specialist', 'published',
|
|
66
|
+
'{"tm_01":"Andrea Neri","tm_02":"Support Specialist","tm_03":"Supporto di primo livello per clienti enterprise.","tm_04":"/media/team/andrea.jpg","tm_05":"https://www.linkedin.com","tm_06":true,"tm_07":"Support Specialist","tm_08":"Supporto tecnico e customer success."}',
|
|
67
|
+
unixepoch(), unixepoch());
|
|
68
|
+
|
|
69
|
+
-- Testimonianze (5)
|
|
70
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
71
|
+
('tes-0001', 'testimonianze', 'acme-corp', 'published',
|
|
72
|
+
'{"tes_01":"Chiara Conti","tes_02":"Acme Corp","tes_03":"Con Beech CMS abbiamo ridotto del 60% il tempo di pubblicazione dei contenuti.","tes_04":5,"tes_05":"2026-01-20","tes_06":"/media/testimonials/acme.jpg","tes_07":true,"tes_08":"Caso studio Acme","tes_09":"Come Acme ha accelerato i workflow editoriali."}',
|
|
73
|
+
unixepoch(), unixepoch()),
|
|
74
|
+
('tes-0002', 'testimonianze', 'studio-x', 'published',
|
|
75
|
+
'{"tes_01":"Luca Ferri","tes_02":"Studio X","tes_03":"La flessibilità degli schema ci ha permesso di iterare velocemente sul design.","tes_04":4,"tes_05":"2026-02-02","tes_06":"/media/testimonials/studiox.jpg","tes_07":true,"tes_08":"Testimonianza Studio X","tes_09":"Feedback di un'agenzia digital sul CMS."}',
|
|
76
|
+
unixepoch(), unixepoch()),
|
|
77
|
+
('tes-0003', 'testimonianze', 'media-hub', 'published',
|
|
78
|
+
'{"tes_01":"Sara Galli","tes_02":"MediaHub","tes_03":"Finalmente un CMS pensato per il contenuto, non per il database.","tes_04":5,"tes_05":"2026-02-15","tes_06":"/media/testimonials/mediahub.jpg","tes_07":true,"tes_08":"Testimonianza MediaHub","tes_09":"Perché i content team amano Beech."}',
|
|
79
|
+
unixepoch(), unixepoch()),
|
|
80
|
+
('tes-0004', 'testimonianze', 'shop-co', 'published',
|
|
81
|
+
'{"tes_01":"Davide Rizzi","tes_02":"ShopCo","tes_03":"Gestire landing e pagine prodotto è diventato molto più semplice.","tes_04":4,"tes_05":"2026-02-25","tes_06":"/media/testimonials/shopco.jpg","tes_07":true,"tes_08":"Testimonianza ShopCo","tes_09":"Beech CMS per e-commerce moderni."}',
|
|
82
|
+
unixepoch(), unixepoch()),
|
|
83
|
+
('tes-0005', 'testimonianze', 'fit-tech', 'published',
|
|
84
|
+
'{"tes_01":"Elena Santi","tes_02":"FitTech Inc","tes_03":"La dashboard è così intuitiva che il team marketing la usa senza training.","tes_04":5,"tes_05":"2026-03-03","tes_06":"/media/testimonials/fittech.jpg","tes_07":true,"tes_08":"Testimonianza FitTech","tes_09":"Esperienza di un team marketing su Beech CMS."}',
|
|
85
|
+
unixepoch(), unixepoch());
|
|
86
|
+
|
|
87
|
+
-- Pagine (5)
|
|
88
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
89
|
+
('pag-0001', 'pagine', 'home', 'published',
|
|
90
|
+
'{"pag_01":"Homepage","pag_02":"/media/pages/home-hero.jpg","pag_03":"<h1>Beech CMS</h1><p>Il CMS schema-driven per l'era edge.</p>","pag_04":"Beech CMS - Homepage","pag_05":"CMS moderno schema-driven per deployment edge."}',
|
|
91
|
+
unixepoch(), unixepoch()),
|
|
92
|
+
('pag-0002', 'pagine', 'prodotto', 'published',
|
|
93
|
+
'{"pag_01":"Il prodotto","pag_02":"/media/pages/product-hero.jpg","pag_03":"<h1>Perché Beech</h1><p>Architettura ibrida SQL/JSON, seed e Botanical Engine.</p>","pag_04":"Perché scegliere Beech","pag_05":"Scopri le funzionalità chiave di Beech CMS."}',
|
|
94
|
+
unixepoch(), unixepoch()),
|
|
95
|
+
('pag-0003', 'pagine', 'casi-studio', 'published',
|
|
96
|
+
'{"pag_01":"Casi studio","pag_02":"/media/pages/cases-hero.jpg","pag_03":"<h1>Storie di successo</h1><p>Come i team usano Beech ogni giorno.</p>","pag_04":"Casi studio Beech","pag_05":"Raccolta di case study su Beech CMS."}',
|
|
97
|
+
unixepoch(), unixepoch()),
|
|
98
|
+
('pag-0004', 'pagine', 'pricing', 'published',
|
|
99
|
+
'{"pag_01":"Pricing","pag_02":"/media/pages/pricing-hero.jpg","pag_03":"<h1>Piani e prezzi</h1><p>Scegli il piano adatto al tuo team.</p>","pag_04":"Pricing Beech CMS","pag_05":"Confronta i piani Starter, Pro ed Enterprise."}',
|
|
100
|
+
unixepoch(), unixepoch()),
|
|
101
|
+
('pag-0005', 'pagine', 'contatti', 'published',
|
|
102
|
+
'{"pag_01":"Contatti","pag_02":"/media/pages/contact-hero.jpg","pag_03":"<h1>Parliamo del tuo progetto</h1><p>Compila il form per una demo.</p>","pag_04":"Contatta Beech","pag_05":"Richiedi una demo o una consulenza su Beech CMS."}',
|
|
103
|
+
unixepoch(), unixepoch());
|
|
104
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS public_idempotency_keys (
|
|
2
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
3
|
+
request_fingerprint TEXT NOT NULL,
|
|
4
|
+
response_status INTEGER NOT NULL,
|
|
5
|
+
response_body TEXT NOT NULL,
|
|
6
|
+
created_at INTEGER NOT NULL,
|
|
7
|
+
expires_at INTEGER NOT NULL
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_public_idempotency_expires_at
|
|
11
|
+
ON public_idempotency_keys (expires_at);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- Svuotiamo le tabelle prima di inserire i nuovi seed di test reali
|
|
2
|
+
DELETE FROM content_entries;
|
|
3
|
+
|
|
4
|
+
-- Articoli presi da risorse tech e resi perfetti per la visualizzazione
|
|
5
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
6
|
+
('art-test-1', 'articoli', 'evoluzione-react-19', 'published',
|
|
7
|
+
'{"art_01":"L''evoluzione di React 19","art_02":"2026-04-10","art_03":"https://images.unsplash.com/photo-1633356122544-f134324a6cee?ixlib=rb-4.0.3&auto=format&fit=crop&w=1000&q=80","art_04":"{\"news\":\"#3b82f6\",\"tutorial\":\"#06b6d4\"}","art_05":"<p>React 19 introduce fondamentali miglioramenti come il React Compiler che automatizza gran parte delle ottimizzazioni che prima richiedevano useMemo e useCallback. Oltre a questo, i Server Components sono ormai diventati il fulcro della User Experience moderna. Nel futuro del Web Design vedremo framework basati su Rust, e il frontend diventerà sempre più veloce e performante.</p><h3>Server Components</h3><p>Una vera rivoluzione prestazionale. Invece di inviare gigabyte di javascript, i nostri server elaborano l''interfaccia spedendo al client solo ciò che serve.</p>","art_06":"Evoluzione di React 19 - News","art_07":"Le ultime novità nel mondo di React 19, Compiler e Server Components."}',
|
|
8
|
+
unixepoch(), unixepoch()),
|
|
9
|
+
|
|
10
|
+
('art-test-2', 'articoli', 'tailwind-v4-novita', 'published',
|
|
11
|
+
'{"art_01":"Tutte le Novità di Tailwind CSS v4","art_02":"2026-04-12","art_03":"https://images.unsplash.com/photo-1542831371-29b0f74f9713?ixlib=rb-4.0.3&auto=format&fit=crop&w=1000&q=80","art_04":"{\"aggiornamento\":\"#10b981\",\"guida\":\"#f59e0b\"}","art_05":"<p>Con Tailwind v4 diciamo addio alle lunghe configurazioni JS e abbracciamo il nuovo paradigma CSS-first. Finalmente, la flessibilità dei framework utility-first si incontra con la potenza delle Custom Properties di CSS. Oltre a compilation time incredibilmente bassi, Tailwind v4 offre un sistema di design token nativo fantastico.</p>","art_06":"Tailwind CSS v4 - Novità","art_07":"Un approfondimento sulle features della nuova major version di Tailwind CSS."}',
|
|
12
|
+
unixepoch(), unixepoch()),
|
|
13
|
+
|
|
14
|
+
('art-test-3', 'articoli', 'design-system-nel-2026', 'published',
|
|
15
|
+
'{"art_01":"Design System nel 2026","art_02":"2026-04-13","art_03":"https://images.unsplash.com/photo-1561070791-2526d30994b5?ixlib=rb-4.0.3&auto=format&fit=crop&w=1000&q=80","art_04":"{\"cms\":\"#ec4899\"}","art_05":"<p>I design system sono maturati enormemente grazie all''integrazione con AI e CMS Headless come Beech CMS. Il pattern schema-driven permette di adattare le UI alle tipologie di dati automaticamente. Addio componenti rigidi, diamo il benvenuto ai field-renderer dinamici e auto-consistenti.</p>","art_06":"Design System del Futuro","art_07":"Come l''automazione sta cambiando l''accessibilità e il design a scala."}',
|
|
16
|
+
unixepoch(), unixepoch());
|
|
17
|
+
|
|
18
|
+
-- Prodotti (visti come Gallery nel sito di Test)
|
|
19
|
+
INSERT INTO content_entries (id, schema_slug, slug, status, data, created_at, updated_at) VALUES
|
|
20
|
+
('gal-test-1', 'prodotti', 'setup-minimalista', 'published',
|
|
21
|
+
'{"prd_01":"Setup Minimalista da Sviluppatore","prd_02":0,"prd_03":0,"prd_04":true,"prd_05":"https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80","prd_06":"[]","prd_07":"L''arte dell''essenziale sulla scrivania.","prd_08":"Setup","prd_09":"Setup desk."}',
|
|
22
|
+
unixepoch(), unixepoch()),
|
|
23
|
+
|
|
24
|
+
('gal-test-2', 'prodotti', 'architettura-server', 'published',
|
|
25
|
+
'{"prd_01":"L''Eleganza dei Datacenter","prd_02":0,"prd_03":0,"prd_04":true,"prd_05":"https://images.unsplash.com/photo-1558494949-ef010cbdcc31?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80","prd_06":"[\"https://images.unsplash.com/photo-1544197150-b99a580bb7a8?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80\"]","prd_07":"Server rack.","prd_08":"Datacenter","prd_09":"Datacenter view."}',
|
|
26
|
+
unixepoch(), unixepoch()),
|
|
27
|
+
|
|
28
|
+
('gal-test-3', 'prodotti', 'lavoro-remoto', 'published',
|
|
29
|
+
'{"prd_01":"Lavoro da Remoto nella Natura","prd_02":0,"prd_03":0,"prd_04":true,"prd_05":"https://images.unsplash.com/photo-1522071820081-009f0129c71c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80","prd_06":"[\"https://images.unsplash.com/photo-1593642532744-d377ab507dc8?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80\", \"https://images.unsplash.com/photo-1498050108023-c5249f4df085?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80\"]","prd_07":"Ibrido vita e lavoro nel 2026.","prd_08":"Remote work","prd_09":"Codice e natura."}',
|
|
30
|
+
unixepoch(), unixepoch());
|
|
31
|
+
|