spine-framework 0.2.9 → 0.3.1
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.
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module config/signals
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* Signal endpoint configuration for framework install tracking and engagement.
|
|
9
|
+
*
|
|
10
|
+
* The public framework sends anonymous signals to a configurable endpoint.
|
|
11
|
+
* Private Cortex instances receive and process these signals.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface SignalConfig {
|
|
15
|
+
endpoint: string
|
|
16
|
+
timeout: number
|
|
17
|
+
retryAttempts: number
|
|
18
|
+
batchSize: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const signalConfig: SignalConfig = {
|
|
22
|
+
endpoint: process.env.SPINE_SIGNAL_ENDPOINT || 'https://cortex.spine-framework.com',
|
|
23
|
+
timeout: 5000,
|
|
24
|
+
retryAttempts: 3,
|
|
25
|
+
batchSize: 10,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Engagement signal types with scores
|
|
29
|
+
export const engagementSignals = {
|
|
30
|
+
framework_installed: { score: 1, description: 'Framework npm install completion' },
|
|
31
|
+
framework_initialized: { score: 3, description: 'First successful startup' },
|
|
32
|
+
framework_connected_db: { score: 5, description: 'Database connection success' },
|
|
33
|
+
app_install: { score: 4, description: 'App installation' },
|
|
34
|
+
app_initialized: { score: 4, description: 'App first load' },
|
|
35
|
+
app_first_action: { score: 6, description: 'First feature usage' },
|
|
36
|
+
account_created: { score: 8, description: 'Anonymous → identified migration' },
|
|
37
|
+
first_deploy: { score: 10, description: 'Production deployment' },
|
|
38
|
+
team_collaboration: { score: 12, description: 'Multi-user usage' },
|
|
39
|
+
} as const
|
|
40
|
+
|
|
41
|
+
export type EngagementSignalType = keyof typeof engagementSignals
|
|
42
|
+
|
|
43
|
+
// Claim trigger thresholds
|
|
44
|
+
export const claimTriggers = {
|
|
45
|
+
immediate: 0, // User explicitly runs `spine-framework claim`
|
|
46
|
+
gentle_nudge: 3, // After first successful startup
|
|
47
|
+
value_realized: 5, // After database connection
|
|
48
|
+
ecosystem_engaged: 8, // After app installation
|
|
49
|
+
power_user: 10, // After regular usage patterns
|
|
50
|
+
} as const
|
|
51
|
+
|
|
52
|
+
export interface EngagementEntry {
|
|
53
|
+
type: EngagementSignalType
|
|
54
|
+
timestamp: string
|
|
55
|
+
score: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface EngagementData {
|
|
59
|
+
framework_install_serial: string
|
|
60
|
+
engagement_score: number
|
|
61
|
+
signals: EngagementEntry[]
|
|
62
|
+
claim_status: 'anonymous' | 'claimed' | 'pending'
|
|
63
|
+
last_claim_prompt?: string
|
|
64
|
+
account_id?: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ClaimPrompt {
|
|
68
|
+
timing: keyof typeof claimTriggers
|
|
69
|
+
message: string
|
|
70
|
+
}
|
|
@@ -862,6 +862,15 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_roles_slug_no_app
|
|
|
862
862
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_roles_slug_with_app
|
|
863
863
|
ON public.roles (app_id, slug)
|
|
864
864
|
WHERE app_id IS NOT NULL;
|
|
865
|
+
-- Non-partial unique constraint required for PostgREST ON CONFLICT upsert on (app_id, slug)
|
|
866
|
+
DO $$ BEGIN
|
|
867
|
+
IF NOT EXISTS (
|
|
868
|
+
SELECT 1 FROM pg_constraint
|
|
869
|
+
WHERE conname = 'roles_app_id_slug_key' AND conrelid = 'public.roles'::regclass
|
|
870
|
+
) THEN
|
|
871
|
+
ALTER TABLE public.roles ADD CONSTRAINT roles_app_id_slug_key UNIQUE (app_id, slug);
|
|
872
|
+
END IF;
|
|
873
|
+
END $$;
|
|
865
874
|
|
|
866
875
|
CREATE INDEX IF NOT EXISTS idx_se_account ON public.schedule_executions (account_id);
|
|
867
876
|
CREATE INDEX IF NOT EXISTS idx_se_schedule ON public.schedule_executions (schedule_id);
|
|
@@ -1279,6 +1288,22 @@ BEGIN
|
|
|
1279
1288
|
END;
|
|
1280
1289
|
$$;
|
|
1281
1290
|
|
|
1291
|
+
-- ---------------------------------------------------------------------------
|
|
1292
|
+
-- App Installations
|
|
1293
|
+
-- Tracks which apps have been installed via `spine-framework install-app`
|
|
1294
|
+
-- ---------------------------------------------------------------------------
|
|
1295
|
+
CREATE TABLE IF NOT EXISTS public.app_installations (
|
|
1296
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1297
|
+
app_slug text NOT NULL,
|
|
1298
|
+
account_id uuid,
|
|
1299
|
+
is_enabled boolean DEFAULT true,
|
|
1300
|
+
installed_version text,
|
|
1301
|
+
package_name text,
|
|
1302
|
+
created_at timestamptz DEFAULT now(),
|
|
1303
|
+
updated_at timestamptz DEFAULT now(),
|
|
1304
|
+
UNIQUE (app_slug, account_id)
|
|
1305
|
+
);
|
|
1306
|
+
|
|
1282
1307
|
-- ---------------------------------------------------------------------------
|
|
1283
1308
|
-- Role Grants
|
|
1284
1309
|
-- Raw SQL migrations bypass Supabase's automatic grant setup. These grants
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Spine — enterprise application framework built on Supabase + Netlify + React",
|
|
6
6
|
"type": "module",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"bin/",
|
|
52
52
|
"dist/",
|
|
53
53
|
".framework/cli/",
|
|
54
|
+
".framework/config/",
|
|
54
55
|
".framework/functions/",
|
|
55
56
|
".framework/migrations/",
|
|
56
57
|
".framework/docs/",
|