spine-framework 0.1.60 → 0.2.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.
Files changed (246) hide show
  1. package/.framework/cli/commands/create-app.ts +1 -1
  2. package/.framework/cli/commands/dev.ts +215 -33
  3. package/.framework/cli/index.ts +37 -63
  4. package/.framework/functions/_shared/app-manifest.ts +8 -15
  5. package/.framework/functions/_shared/db.ts +11 -15
  6. package/.framework/functions/_shared/index.ts +0 -9
  7. package/.framework/functions/_shared/principal.ts +4 -62
  8. package/.framework/functions/_shared/resolve-ids.ts +6 -6
  9. package/.framework/functions/_shared/webhook-registry.ts +1 -1
  10. package/.framework/functions/admin-funnel.ts +104 -0
  11. package/.framework/functions/admin-install-funnel.ts +225 -0
  12. package/.framework/functions/admin-signals.ts +241 -0
  13. package/.framework/migrations/001_schema.sql +406 -0
  14. package/.framework/migrations/002_rls_and_functions.sql +710 -0
  15. package/.framework/migrations/003_system_data.sql +520 -0
  16. package/.framework/migrations/004_enhancements.sql +43 -0
  17. package/.framework/public/_redirects +3 -0
  18. package/.framework/public/spine-logo.jpg +0 -0
  19. package/.framework/public/spine-logo.svg +3 -0
  20. package/{scripts → .framework/scripts}/assemble-frontend.sh +1 -1
  21. package/{scripts → .framework/scripts}/assemble-functions.sh +1 -1
  22. package/{scripts → .framework/scripts}/assemble.sh +2 -8
  23. package/{scripts → .framework/scripts}/check-core-integrity.sh +0 -0
  24. package/.framework/seeds/link_types/account_cli_instances.json +9 -0
  25. package/.framework/seeds/types/funnel_signal_use.json +98 -0
  26. package/.framework/seeds/types/spine_instance.json +109 -0
  27. package/.framework/src/App.tsx +6 -4
  28. package/.framework/src/components/ui/accordion.tsx +1 -1
  29. package/.framework/src/components/ui/alert-dialog.tsx +1 -1
  30. package/.framework/src/components/ui/aspect-ratio.tsx +1 -1
  31. package/.framework/src/components/ui/avatar.tsx +1 -1
  32. package/.framework/src/components/ui/badge.tsx +2 -2
  33. package/.framework/src/components/ui/breadcrumb.tsx +2 -2
  34. package/.framework/src/components/ui/button-group.tsx +2 -2
  35. package/.framework/src/components/ui/button.tsx +2 -2
  36. package/.framework/src/components/ui/chart.tsx +6 -1
  37. package/.framework/src/components/ui/checkbox.tsx +1 -1
  38. package/.framework/src/components/ui/collapsible.tsx +1 -1
  39. package/.framework/src/components/ui/context-menu.tsx +1 -1
  40. package/.framework/src/components/ui/dialog.tsx +1 -1
  41. package/.framework/src/components/ui/direction.tsx +17 -1
  42. package/.framework/src/components/ui/dropdown-menu.tsx +1 -1
  43. package/.framework/src/components/ui/hover-card.tsx +1 -1
  44. package/.framework/src/components/ui/item.tsx +2 -2
  45. package/.framework/src/components/ui/label.tsx +1 -1
  46. package/.framework/src/components/ui/menubar.tsx +1 -1
  47. package/.framework/src/components/ui/navigation-menu.tsx +1 -1
  48. package/.framework/src/components/ui/popover.tsx +1 -1
  49. package/.framework/src/components/ui/progress.tsx +1 -1
  50. package/.framework/src/components/ui/radio-group.tsx +1 -1
  51. package/.framework/src/components/ui/scroll-area.tsx +1 -1
  52. package/.framework/src/components/ui/select.tsx +1 -1
  53. package/.framework/src/components/ui/separator.tsx +1 -1
  54. package/.framework/src/components/ui/sheet.tsx +1 -1
  55. package/.framework/src/components/ui/sidebar.tsx +6 -6
  56. package/.framework/src/components/ui/slider.tsx +1 -1
  57. package/.framework/src/components/ui/switch.tsx +1 -1
  58. package/.framework/src/components/ui/tabs.tsx +1 -1
  59. package/.framework/src/components/ui/toggle-group.tsx +1 -1
  60. package/.framework/src/components/ui/toggle.tsx +1 -1
  61. package/.framework/src/components/ui/tooltip.tsx +1 -1
  62. package/.framework/src/pages/auth/LoginPage.tsx +10 -9
  63. package/LICENSE.md +193 -0
  64. package/README.md +254 -0
  65. package/custom/.devin/skills/install-app/SKILL.md +39 -0
  66. package/custom/.devin/workflows/app-install.yaml +83 -0
  67. package/custom/README.md +79 -0
  68. package/docs/APPS.md +232 -0
  69. package/docs/ARCHITECTURE.md +246 -0
  70. package/docs/INSTALL.md +155 -0
  71. package/docs/README.md +170 -0
  72. package/docs/design-schema-spec.md +1837 -0
  73. package/docs/dev-guides/01-create-an-app.md +183 -0
  74. package/docs/dev-guides/02-create-a-function.md +178 -0
  75. package/docs/dev-guides/03-create-a-component.md +178 -0
  76. package/docs/dev-guides/04-webhook-handlers.md +129 -0
  77. package/docs/dev-guides/05-testing.md +168 -0
  78. package/docs/dev-guides/README.md +40 -0
  79. package/docs/npm-packages-plan.md +288 -0
  80. package/docs/spine-core--api-reference.md +822 -0
  81. package/package.json +78 -144
  82. package/.framework/cli/bin.cjs +0 -14
  83. package/.framework/cli/commands/init.ts +0 -186
  84. package/.framework/cli/commands/install-app.ts +0 -560
  85. package/.framework/cli/commands/migrate.ts +0 -139
  86. package/.framework/cli/commands/status.ts +0 -197
  87. package/.framework/cli/commands/uninstall-app.ts +0 -166
  88. package/.framework/cli/welcome.cjs +0 -45
  89. package/.framework/docs/STABILITY.md +0 -52
  90. package/.framework/docs/examples/custom-app/README.md +0 -77
  91. package/.framework/docs/examples/custom-function/README.md +0 -27
  92. package/.framework/docs/examples/custom-function/handler.ts +0 -48
  93. package/.framework/docs/examples/custom-webhook/README.md +0 -68
  94. package/.framework/migrations/000_foundation.sql +0 -1265
  95. package/.framework/migrations/001_seed.sql +0 -163
  96. package/.framework/migrations/002_seed_constraints.sql +0 -19
  97. package/.framework/migrations/003_auth_user_trigger.sql +0 -67
  98. package/.framework/src/pages/auth/RegisterPage.tsx +0 -163
  99. package/STRUCTURE.md +0 -150
  100. package/bin/spine-framework.cjs +0 -62
  101. package/bin/welcome.cjs +0 -45
  102. package/bin/ws-shim.cjs +0 -8
  103. package/bin/ws-shim.ts +0 -10
  104. package/config/components.json +0 -25
  105. package/config/deno.lock +0 -108
  106. package/config/package-lock.json +0 -17183
  107. package/config/postcss.config.cjs +0 -10
  108. package/config/tailwind.config.cjs +0 -78
  109. package/config/tsconfig.build.json +0 -32
  110. package/config/tsconfig.cli.json +0 -18
  111. package/config/tsconfig.json +0 -41
  112. package/config/tsconfig.node.json +0 -17
  113. package/config/tsconfig.node.tsbuildinfo +0 -1
  114. package/config/tsconfig.tsbuildinfo +0 -1
  115. package/config/typedoc.json +0 -16
  116. package/config/vite.config.d.ts +0 -2
  117. package/config/vite.config.ts +0 -72
  118. package/dist/cli/commands/agents.d.ts +0 -39
  119. package/dist/cli/commands/agents.d.ts.map +0 -1
  120. package/dist/cli/commands/auth.d.ts +0 -36
  121. package/dist/cli/commands/auth.d.ts.map +0 -1
  122. package/dist/cli/commands/create-app.d.ts +0 -23
  123. package/dist/cli/commands/create-app.d.ts.map +0 -1
  124. package/dist/cli/commands/dev.d.ts +0 -24
  125. package/dist/cli/commands/dev.d.ts.map +0 -1
  126. package/dist/cli/commands/doctor.d.ts +0 -42
  127. package/dist/cli/commands/doctor.d.ts.map +0 -1
  128. package/dist/cli/commands/generate.d.ts +0 -36
  129. package/dist/cli/commands/generate.d.ts.map +0 -1
  130. package/dist/cli/commands/init.d.ts +0 -20
  131. package/dist/cli/commands/init.d.ts.map +0 -1
  132. package/dist/cli/commands/install-app.d.ts +0 -30
  133. package/dist/cli/commands/install-app.d.ts.map +0 -1
  134. package/dist/cli/commands/items.d.ts +0 -45
  135. package/dist/cli/commands/items.d.ts.map +0 -1
  136. package/dist/cli/commands/migrate.d.ts +0 -21
  137. package/dist/cli/commands/migrate.d.ts.map +0 -1
  138. package/dist/cli/commands/migrations.d.ts +0 -41
  139. package/dist/cli/commands/migrations.d.ts.map +0 -1
  140. package/dist/cli/commands/pipelines.d.ts +0 -40
  141. package/dist/cli/commands/pipelines.d.ts.map +0 -1
  142. package/dist/cli/commands/status.d.ts +0 -23
  143. package/dist/cli/commands/status.d.ts.map +0 -1
  144. package/dist/cli/commands/system.d.ts +0 -29
  145. package/dist/cli/commands/system.d.ts.map +0 -1
  146. package/dist/cli/commands/test.d.ts +0 -46
  147. package/dist/cli/commands/test.d.ts.map +0 -1
  148. package/dist/cli/commands/uninstall-app.d.ts +0 -23
  149. package/dist/cli/commands/uninstall-app.d.ts.map +0 -1
  150. package/dist/cli/context.d.ts +0 -88
  151. package/dist/cli/context.d.ts.map +0 -1
  152. package/dist/cli/env-loader.d.ts +0 -14
  153. package/dist/cli/env-loader.d.ts.map +0 -1
  154. package/dist/cli/index.d.ts +0 -41
  155. package/dist/cli/index.d.ts.map +0 -1
  156. package/dist/functions/_shared/agent-runner.d.ts +0 -156
  157. package/dist/functions/_shared/agent-runner.d.ts.map +0 -1
  158. package/dist/functions/_shared/app-manifest.d.ts +0 -68
  159. package/dist/functions/_shared/app-manifest.d.ts.map +0 -1
  160. package/dist/functions/_shared/audit.d.ts +0 -91
  161. package/dist/functions/_shared/audit.d.ts.map +0 -1
  162. package/dist/functions/_shared/db.d.ts +0 -125
  163. package/dist/functions/_shared/db.d.ts.map +0 -1
  164. package/dist/functions/_shared/index.d.ts +0 -299
  165. package/dist/functions/_shared/index.d.ts.map +0 -1
  166. package/dist/functions/_shared/middleware.d.ts +0 -315
  167. package/dist/functions/_shared/middleware.d.ts.map +0 -1
  168. package/dist/functions/_shared/permissions.d.ts +0 -626
  169. package/dist/functions/_shared/permissions.d.ts.map +0 -1
  170. package/dist/functions/_shared/pipeline-runner.d.ts +0 -124
  171. package/dist/functions/_shared/pipeline-runner.d.ts.map +0 -1
  172. package/dist/functions/_shared/principal.d.ts +0 -284
  173. package/dist/functions/_shared/principal.d.ts.map +0 -1
  174. package/dist/functions/_shared/resolve-ids.d.ts +0 -10
  175. package/dist/functions/_shared/resolve-ids.d.ts.map +0 -1
  176. package/dist/functions/_shared/schema-utils.d.ts +0 -181
  177. package/dist/functions/_shared/schema-utils.d.ts.map +0 -1
  178. package/dist/functions/_shared/testing.d.ts +0 -172
  179. package/dist/functions/_shared/testing.d.ts.map +0 -1
  180. package/dist/functions/_shared/trigger-engine.d.ts +0 -140
  181. package/dist/functions/_shared/trigger-engine.d.ts.map +0 -1
  182. package/dist/functions/_shared/webhook-registration.d.ts +0 -81
  183. package/dist/functions/_shared/webhook-registration.d.ts.map +0 -1
  184. package/dist/functions/_shared/webhook-registry.d.ts +0 -57
  185. package/dist/functions/_shared/webhook-registry.d.ts.map +0 -1
  186. package/dist/functions/account-nodes.d.ts +0 -48
  187. package/dist/functions/account-nodes.d.ts.map +0 -1
  188. package/dist/functions/admin-data.d.ts +0 -178
  189. package/dist/functions/admin-data.d.ts.map +0 -1
  190. package/dist/functions/ai-agents.d.ts +0 -125
  191. package/dist/functions/ai-agents.d.ts.map +0 -1
  192. package/dist/functions/api-keys.d.ts +0 -140
  193. package/dist/functions/api-keys.d.ts.map +0 -1
  194. package/dist/functions/apps.d.ts +0 -163
  195. package/dist/functions/apps.d.ts.map +0 -1
  196. package/dist/functions/auth.d.ts +0 -74
  197. package/dist/functions/auth.d.ts.map +0 -1
  198. package/dist/functions/debug-auth.d.ts +0 -33
  199. package/dist/functions/debug-auth.d.ts.map +0 -1
  200. package/dist/functions/embeddings.d.ts +0 -205
  201. package/dist/functions/embeddings.d.ts.map +0 -1
  202. package/dist/functions/integration-routes.d.ts +0 -45
  203. package/dist/functions/integration-routes.d.ts.map +0 -1
  204. package/dist/functions/integrations.d.ts +0 -124
  205. package/dist/functions/integrations.d.ts.map +0 -1
  206. package/dist/functions/item-progress.d.ts +0 -41
  207. package/dist/functions/item-progress.d.ts.map +0 -1
  208. package/dist/functions/logs.d.ts +0 -162
  209. package/dist/functions/logs.d.ts.map +0 -1
  210. package/dist/functions/observability.d.ts +0 -123
  211. package/dist/functions/observability.d.ts.map +0 -1
  212. package/dist/functions/pipeline-executions.d.ts +0 -190
  213. package/dist/functions/pipeline-executions.d.ts.map +0 -1
  214. package/dist/functions/pipelines.d.ts +0 -171
  215. package/dist/functions/pipelines.d.ts.map +0 -1
  216. package/dist/functions/prompt-configs.d.ts +0 -125
  217. package/dist/functions/prompt-configs.d.ts.map +0 -1
  218. package/dist/functions/roles.d.ts +0 -118
  219. package/dist/functions/roles.d.ts.map +0 -1
  220. package/dist/functions/system-cron.d.ts +0 -65
  221. package/dist/functions/system-cron.d.ts.map +0 -1
  222. package/dist/functions/system.d.ts +0 -29
  223. package/dist/functions/system.d.ts.map +0 -1
  224. package/dist/functions/tests.d.ts +0 -28
  225. package/dist/functions/tests.d.ts.map +0 -1
  226. package/dist/functions/timers.d.ts +0 -139
  227. package/dist/functions/timers.d.ts.map +0 -1
  228. package/dist/functions/triggers.d.ts +0 -203
  229. package/dist/functions/triggers.d.ts.map +0 -1
  230. package/dist/functions/types.d.ts +0 -151
  231. package/dist/functions/types.d.ts.map +0 -1
  232. package/dist/src/types/types.d.ts +0 -364
  233. package/dist/src/types/types.d.ts.map +0 -1
  234. package/index.html +0 -13
  235. package/netlify.toml +0 -36
  236. package/package-project.json +0 -64
  237. package/scripts/ingest-chunks.cjs +0 -202
  238. package/scripts/kb-chunk-parser.cjs +0 -312
  239. package/scripts/kb-chunk-parser.ts +0 -330
  240. package/scripts/load-test-app-install.ts +0 -484
  241. package/scripts/netlify-dev-wrapper.sh +0 -22
  242. package/vitest.config.ts +0 -45
  243. /package/{scripts → .framework/scripts}/app-install-cli.ts +0 -0
  244. /package/{scripts → .framework/scripts}/boundary-check.sh +0 -0
  245. /package/{scripts → .framework/scripts}/build-manifest.sh +0 -0
  246. /package/{scripts → .framework/scripts}/verify-integrity.sh +0 -0
@@ -0,0 +1,520 @@
1
+ -- Migration 003: System Data
2
+ -- Seeds for day-zero operation including system role, system account, spine-core app,
3
+ -- runtime types, admin app, and RPC functions.
4
+
5
+ -- ============================================
6
+ -- 1. SYSTEM ROLE (system_admin)
7
+ -- ============================================
8
+
9
+ INSERT INTO public.roles (id, slug, name, description, permissions, is_system, is_active, is_protected, app_id, account_id)
10
+ VALUES (
11
+ gen_random_uuid(),
12
+ 'system_admin',
13
+ 'System Admin',
14
+ 'Full system access - can manage all accounts, types, and system configuration',
15
+ '["*"]'::jsonb,
16
+ true,
17
+ true,
18
+ true,
19
+ NULL,
20
+ NULL
21
+ );
22
+
23
+ -- ============================================
24
+ -- 2. MASTER SYSTEM ACCOUNT
25
+ -- ============================================
26
+
27
+ INSERT INTO public.accounts (id, slug, display_name, description, data, is_active, design_schema, validation_schema, type_id)
28
+ VALUES (
29
+ gen_random_uuid(),
30
+ 'spine-system',
31
+ 'Spine System',
32
+ 'Master system account for internal Spine operations',
33
+ '{}'::jsonb,
34
+ true,
35
+ '{}'::jsonb,
36
+ '{}'::jsonb,
37
+ gen_random_uuid() -- placeholder, will update after types seeded
38
+ );
39
+
40
+ -- ============================================
41
+ -- 3. SYSTEM APP (spine-core)
42
+ -- ============================================
43
+
44
+ INSERT INTO public.apps (id, slug, name, description, version, app_type, source, is_active, is_system, renderer, route_prefix)
45
+ VALUES (
46
+ gen_random_uuid(),
47
+ 'spine-core',
48
+ 'Spine Core',
49
+ 'Core Spine runtime - provides accounts, people, items, threads, messages, links, attachments, watchers',
50
+ '1.0.0',
51
+ 'system',
52
+ 'builtin',
53
+ true,
54
+ true,
55
+ 'none',
56
+ NULL
57
+ );
58
+
59
+ -- ============================================
60
+ -- 4. ADMIN APP
61
+ -- ============================================
62
+
63
+ INSERT INTO public.apps (
64
+ id, slug, name, description, icon, color, version,
65
+ app_type, source, config, nav_items, min_role,
66
+ is_active, is_system, route_prefix, renderer
67
+ )
68
+ VALUES (
69
+ gen_random_uuid(),
70
+ 'admin',
71
+ 'Admin',
72
+ 'Spine system administration interface',
73
+ 'settings',
74
+ 'slate',
75
+ '1.0.0',
76
+ 'system',
77
+ 'builtin',
78
+ '{}'::jsonb,
79
+ '[]'::jsonb,
80
+ 'system_admin',
81
+ true,
82
+ true,
83
+ '/admin',
84
+ 'custom'
85
+ )
86
+ ON CONFLICT (slug) DO UPDATE SET
87
+ route_prefix = EXCLUDED.route_prefix,
88
+ renderer = EXCLUDED.renderer,
89
+ min_role = EXCLUDED.min_role,
90
+ is_system = EXCLUDED.is_system,
91
+ app_type = EXCLUDED.app_type;
92
+
93
+ -- ============================================
94
+ -- 5. RUNTIME ENTITY TYPES (8 core types)
95
+ -- ============================================
96
+
97
+ DO $$
98
+ DECLARE
99
+ v_spine_core_app_id uuid;
100
+ v_system_account_id uuid;
101
+ BEGIN
102
+ SELECT id INTO v_spine_core_app_id FROM public.apps WHERE slug = 'spine-core' LIMIT 1;
103
+ SELECT id INTO v_system_account_id FROM public.accounts WHERE slug = 'spine-system' LIMIT 1;
104
+
105
+ -- 5.1 accounts type
106
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
107
+ VALUES (
108
+ gen_random_uuid(),
109
+ v_spine_core_app_id,
110
+ 'account',
111
+ 'account',
112
+ 'Account',
113
+ 'Organization or tenant account',
114
+ jsonb_build_object(
115
+ 'scope', 'account',
116
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
117
+ 'fields', jsonb_build_object(
118
+ 'slug', jsonb_build_object('data_type', 'text', 'label', 'Slug', 'required', true, 'system', true, 'validation', null),
119
+ 'display_name', jsonb_build_object('data_type', 'text', 'label', 'Display Name', 'required', true, 'system', true, 'validation', null),
120
+ 'description', jsonb_build_object('data_type', 'textarea', 'label', 'Description', 'required', false, 'system', true, 'validation', null),
121
+ 'is_active', jsonb_build_object('data_type', 'boolean', 'label', 'Active', 'required', true, 'system', true, 'validation', null),
122
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
123
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
124
+ ),
125
+ 'views', jsonb_build_object(
126
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Accounts',
127
+ 'fields', jsonb_build_object(
128
+ 'display_name', jsonb_build_object('sortable', true, 'display_type', 'text'),
129
+ 'slug', jsonb_build_object('sortable', true, 'display_type', 'text'),
130
+ 'is_active', jsonb_build_object('sortable', true, 'display_type', 'badge')
131
+ )
132
+ ),
133
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Account',
134
+ 'sections', jsonb_build_array(
135
+ jsonb_build_object('title', 'Overview', 'fields', jsonb_build_array('slug', 'display_name', 'description', 'is_active')),
136
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
137
+ )
138
+ )
139
+ )
140
+ ),
141
+ '{}'::jsonb,
142
+ 'pack',
143
+ true
144
+ );
145
+
146
+ -- 5.2 people type
147
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
148
+ VALUES (
149
+ gen_random_uuid(),
150
+ v_spine_core_app_id,
151
+ 'person',
152
+ 'person',
153
+ 'Person',
154
+ 'User or contact person',
155
+ jsonb_build_object(
156
+ 'scope', 'account',
157
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
158
+ 'fields', jsonb_build_object(
159
+ 'full_name', jsonb_build_object('data_type', 'text', 'label', 'Full Name', 'required', true, 'system', true, 'validation', null),
160
+ 'email', jsonb_build_object('data_type', 'email', 'label', 'Email', 'required', true, 'system', true, 'validation', null),
161
+ 'phone', jsonb_build_object('data_type', 'phone', 'label', 'Phone', 'required', false, 'system', true, 'validation', null),
162
+ 'avatar_url', jsonb_build_object('data_type', 'url', 'label', 'Avatar URL', 'required', false, 'system', true, 'validation', null),
163
+ 'status', jsonb_build_object('data_type', 'text', 'label', 'Status', 'required', true, 'system', true, 'validation', null),
164
+ 'is_active', jsonb_build_object('data_type', 'boolean', 'label', 'Active', 'required', true, 'system', true, 'validation', null),
165
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
166
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
167
+ ),
168
+ 'views', jsonb_build_object(
169
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'People',
170
+ 'fields', jsonb_build_object(
171
+ 'full_name', jsonb_build_object('sortable', true, 'display_type', 'text'),
172
+ 'email', jsonb_build_object('sortable', true, 'display_type', 'text'),
173
+ 'status', jsonb_build_object('sortable', true, 'display_type', 'badge'),
174
+ 'is_active', jsonb_build_object('sortable', true, 'display_type', 'badge')
175
+ )
176
+ ),
177
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Person',
178
+ 'sections', jsonb_build_array(
179
+ jsonb_build_object('title', 'Profile', 'fields', jsonb_build_array('full_name', 'email', 'phone', 'avatar_url')),
180
+ jsonb_build_object('title', 'Status', 'fields', jsonb_build_array('status', 'is_active')),
181
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
182
+ )
183
+ )
184
+ )
185
+ ),
186
+ '{}'::jsonb,
187
+ 'pack',
188
+ true
189
+ );
190
+
191
+ -- 5.3 items type
192
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
193
+ VALUES (
194
+ gen_random_uuid(),
195
+ v_spine_core_app_id,
196
+ 'item',
197
+ 'item',
198
+ 'Item',
199
+ 'Generic item - tickets, tasks, records',
200
+ jsonb_build_object(
201
+ 'scope', 'account',
202
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
203
+ 'fields', jsonb_build_object(
204
+ 'title', jsonb_build_object('data_type', 'text', 'label', 'Title', 'required', true, 'system', true, 'validation', null),
205
+ 'description', jsonb_build_object('data_type', 'textarea', 'label', 'Description', 'required', false, 'system', true, 'validation', null),
206
+ 'status', jsonb_build_object('data_type', 'text', 'label', 'Status', 'required', true, 'system', true, 'validation', null),
207
+ 'is_active', jsonb_build_object('data_type', 'boolean', 'label', 'Active', 'required', true, 'system', true, 'validation', null),
208
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
209
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
210
+ ),
211
+ 'views', jsonb_build_object(
212
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Items',
213
+ 'fields', jsonb_build_object(
214
+ 'title', jsonb_build_object('sortable', true, 'display_type', 'text'),
215
+ 'status', jsonb_build_object('sortable', true, 'display_type', 'badge'),
216
+ 'is_active', jsonb_build_object('sortable', true, 'display_type', 'badge'),
217
+ 'created_at', jsonb_build_object('sortable', true, 'display_type', 'datetime')
218
+ )
219
+ ),
220
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Item',
221
+ 'sections', jsonb_build_array(
222
+ jsonb_build_object('title', 'Overview', 'fields', jsonb_build_array('title', 'description', 'status', 'is_active')),
223
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
224
+ )
225
+ )
226
+ )
227
+ ),
228
+ '{}'::jsonb,
229
+ 'pack',
230
+ true
231
+ );
232
+
233
+ -- 5.4 threads type
234
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
235
+ VALUES (
236
+ gen_random_uuid(),
237
+ v_spine_core_app_id,
238
+ 'thread',
239
+ 'thread',
240
+ 'Thread',
241
+ 'Discussion thread for items or accounts',
242
+ jsonb_build_object(
243
+ 'scope', 'account',
244
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
245
+ 'fields', jsonb_build_object(
246
+ 'title', jsonb_build_object('data_type', 'text', 'label', 'Title', 'required', false, 'system', true, 'validation', null),
247
+ 'target_type', jsonb_build_object('data_type', 'text', 'label', 'Target Type', 'required', true, 'system', true, 'validation', null),
248
+ 'target_id', jsonb_build_object('data_type', 'uuid', 'label', 'Target ID', 'required', true, 'system', true, 'validation', null),
249
+ 'visibility', jsonb_build_object('data_type', 'text', 'label', 'Visibility', 'required', true, 'system', true, 'validation', null),
250
+ 'status', jsonb_build_object('data_type', 'text', 'label', 'Status', 'required', true, 'system', true, 'validation', null),
251
+ 'is_active', jsonb_build_object('data_type', 'boolean', 'label', 'Active', 'required', true, 'system', true, 'validation', null),
252
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
253
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
254
+ ),
255
+ 'views', jsonb_build_object(
256
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Threads',
257
+ 'fields', jsonb_build_object(
258
+ 'title', jsonb_build_object('sortable', true, 'display_type', 'text'),
259
+ 'target_type', jsonb_build_object('sortable', true, 'display_type', 'text'),
260
+ 'visibility', jsonb_build_object('sortable', true, 'display_type', 'badge'),
261
+ 'status', jsonb_build_object('sortable', true, 'display_type', 'badge')
262
+ )
263
+ ),
264
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Thread',
265
+ 'sections', jsonb_build_array(
266
+ jsonb_build_object('title', 'Overview', 'fields', jsonb_build_array('title', 'target_type', 'target_id', 'visibility', 'status')),
267
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
268
+ )
269
+ )
270
+ )
271
+ ),
272
+ '{}'::jsonb,
273
+ 'pack',
274
+ true
275
+ );
276
+
277
+ -- 5.5 messages type
278
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
279
+ VALUES (
280
+ gen_random_uuid(),
281
+ v_spine_core_app_id,
282
+ 'message',
283
+ 'message',
284
+ 'Message',
285
+ 'Individual message within a thread',
286
+ jsonb_build_object(
287
+ 'scope', 'account',
288
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
289
+ 'fields', jsonb_build_object(
290
+ 'content', jsonb_build_object('data_type', 'textarea', 'label', 'Content', 'required', true, 'system', true, 'validation', null),
291
+ 'direction', jsonb_build_object('data_type', 'text', 'label', 'Direction', 'required', true, 'system', true, 'validation', null),
292
+ 'sequence', jsonb_build_object('data_type', 'number', 'label', 'Sequence', 'required', true, 'system', true, 'validation', null),
293
+ 'visibility', jsonb_build_object('data_type', 'text', 'label', 'Visibility', 'required', true, 'system', true, 'validation', null),
294
+ 'is_active', jsonb_build_object('data_type', 'boolean', 'label', 'Active', 'required', true, 'system', true, 'validation', null),
295
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
296
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
297
+ ),
298
+ 'views', jsonb_build_object(
299
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Messages',
300
+ 'fields', jsonb_build_object(
301
+ 'content', jsonb_build_object('sortable', false, 'display_type', 'text'),
302
+ 'direction', jsonb_build_object('sortable', true, 'display_type', 'badge'),
303
+ 'visibility', jsonb_build_object('sortable', true, 'display_type', 'badge'),
304
+ 'created_at', jsonb_build_object('sortable', true, 'display_type', 'datetime')
305
+ )
306
+ ),
307
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Message',
308
+ 'sections', jsonb_build_array(
309
+ jsonb_build_object('title', 'Content', 'fields', jsonb_build_array('content', 'direction', 'visibility')),
310
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('sequence', 'created_at', 'updated_at'))
311
+ )
312
+ )
313
+ )
314
+ ),
315
+ '{}'::jsonb,
316
+ 'pack',
317
+ true
318
+ );
319
+
320
+ -- 5.6 links type
321
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
322
+ VALUES (
323
+ gen_random_uuid(),
324
+ v_spine_core_app_id,
325
+ 'link',
326
+ 'link',
327
+ 'Link',
328
+ 'Relationship between two entities',
329
+ jsonb_build_object(
330
+ 'scope', 'account',
331
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
332
+ 'fields', jsonb_build_object(
333
+ 'source_type', jsonb_build_object('data_type', 'text', 'label', 'Source Type', 'required', true, 'system', true, 'validation', null),
334
+ 'source_id', jsonb_build_object('data_type', 'uuid', 'label', 'Source ID', 'required', true, 'system', true, 'validation', null),
335
+ 'target_type', jsonb_build_object('data_type', 'text', 'label', 'Target Type', 'required', true, 'system', true, 'validation', null),
336
+ 'target_id', jsonb_build_object('data_type', 'uuid', 'label', 'Target ID', 'required', true, 'system', true, 'validation', null),
337
+ 'link_type', jsonb_build_object('data_type', 'text', 'label', 'Link Type', 'required', false, 'system', true, 'validation', null),
338
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
339
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
340
+ ),
341
+ 'views', jsonb_build_object(
342
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Links',
343
+ 'fields', jsonb_build_object(
344
+ 'source_type', jsonb_build_object('sortable', true, 'display_type', 'text'),
345
+ 'target_type', jsonb_build_object('sortable', true, 'display_type', 'text'),
346
+ 'link_type', jsonb_build_object('sortable', true, 'display_type', 'text'),
347
+ 'created_at', jsonb_build_object('sortable', true, 'display_type', 'datetime')
348
+ )
349
+ ),
350
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Link',
351
+ 'sections', jsonb_build_array(
352
+ jsonb_build_object('title', 'Connection', 'fields', jsonb_build_array('source_type', 'source_id', 'target_type', 'target_id', 'link_type')),
353
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
354
+ )
355
+ )
356
+ )
357
+ ),
358
+ '{}'::jsonb,
359
+ 'pack',
360
+ true
361
+ );
362
+
363
+ -- 5.7 attachments type
364
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
365
+ VALUES (
366
+ gen_random_uuid(),
367
+ v_spine_core_app_id,
368
+ 'attachment',
369
+ 'attachment',
370
+ 'Attachment',
371
+ 'File attachment with storage reference',
372
+ jsonb_build_object(
373
+ 'scope', 'account',
374
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
375
+ 'fields', jsonb_build_object(
376
+ 'filename', jsonb_build_object('data_type', 'text', 'label', 'Filename', 'required', true, 'system', true, 'validation', null),
377
+ 'file_size', jsonb_build_object('data_type', 'number', 'label', 'File Size', 'required', false, 'system', true, 'validation', null),
378
+ 'mime_type', jsonb_build_object('data_type', 'text', 'label', 'MIME Type', 'required', false, 'system', true, 'validation', null),
379
+ 'storage_path', jsonb_build_object('data_type', 'text', 'label', 'Storage Path', 'required', false, 'system', true, 'validation', null),
380
+ 'storage_provider', jsonb_build_object('data_type', 'text', 'label', 'Storage Provider', 'required', true, 'system', true, 'validation', null),
381
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
382
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
383
+ ),
384
+ 'views', jsonb_build_object(
385
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Attachments',
386
+ 'fields', jsonb_build_object(
387
+ 'filename', jsonb_build_object('sortable', true, 'display_type', 'text'),
388
+ 'file_size', jsonb_build_object('sortable', true, 'display_type', 'number'),
389
+ 'mime_type', jsonb_build_object('sortable', true, 'display_type', 'text'),
390
+ 'created_at', jsonb_build_object('sortable', true, 'display_type', 'datetime')
391
+ )
392
+ ),
393
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Attachment',
394
+ 'sections', jsonb_build_array(
395
+ jsonb_build_object('title', 'File', 'fields', jsonb_build_array('filename', 'file_size', 'mime_type', 'storage_provider')),
396
+ jsonb_build_object('title', 'Storage', 'fields', jsonb_build_array('storage_path')),
397
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
398
+ )
399
+ )
400
+ )
401
+ ),
402
+ '{}'::jsonb,
403
+ 'pack',
404
+ true
405
+ );
406
+
407
+ -- 5.8 watchers type
408
+ INSERT INTO public.types (id, app_id, kind, slug, name, description, design_schema, validation_schema, ownership, is_active)
409
+ VALUES (
410
+ gen_random_uuid(),
411
+ v_spine_core_app_id,
412
+ 'watcher',
413
+ 'watcher',
414
+ 'Watcher',
415
+ 'Person watching an entity for notifications',
416
+ jsonb_build_object(
417
+ 'scope', 'account',
418
+ 'record_permissions', jsonb_build_object('system_admin', ARRAY['create', 'read', 'update', 'delete']),
419
+ 'fields', jsonb_build_object(
420
+ 'target_type', jsonb_build_object('data_type', 'text', 'label', 'Target Type', 'required', true, 'system', true, 'validation', null),
421
+ 'target_id', jsonb_build_object('data_type', 'uuid', 'label', 'Target ID', 'required', true, 'system', true, 'validation', null),
422
+ 'person_id', jsonb_build_object('data_type', 'uuid', 'label', 'Person', 'required', true, 'system', true, 'validation', null),
423
+ 'watch_type', jsonb_build_object('data_type', 'text', 'label', 'Watch Type', 'required', true, 'system', true, 'validation', null),
424
+ 'notification_level', jsonb_build_object('data_type', 'text', 'label', 'Notification Level', 'required', true, 'system', true, 'validation', null),
425
+ 'created_at', jsonb_build_object('data_type', 'datetime', 'label', 'Created', 'required', false, 'system', true, 'readonly', true, 'validation', null),
426
+ 'updated_at', jsonb_build_object('data_type', 'datetime', 'label', 'Updated', 'required', false, 'system', true, 'readonly', true, 'validation', null)
427
+ ),
428
+ 'views', jsonb_build_object(
429
+ 'default_list', jsonb_build_object('type', 'list', 'display', 'table', 'label', 'Watchers',
430
+ 'fields', jsonb_build_object(
431
+ 'target_type', jsonb_build_object('sortable', true, 'display_type', 'text'),
432
+ 'watch_type', jsonb_build_object('sortable', true, 'display_type', 'badge'),
433
+ 'notification_level', jsonb_build_object('sortable', true, 'display_type', 'badge'),
434
+ 'created_at', jsonb_build_object('sortable', true, 'display_type', 'datetime')
435
+ )
436
+ ),
437
+ 'default_detail', jsonb_build_object('type', 'detail', 'label', 'Watcher',
438
+ 'sections', jsonb_build_array(
439
+ jsonb_build_object('title', 'Target', 'fields', jsonb_build_array('target_type', 'target_id')),
440
+ jsonb_build_object('title', 'Settings', 'fields', jsonb_build_array('person_id', 'watch_type', 'notification_level')),
441
+ jsonb_build_object('title', 'Metadata', 'fields', jsonb_build_array('created_at', 'updated_at'))
442
+ )
443
+ )
444
+ )
445
+ ),
446
+ '{}'::jsonb,
447
+ 'pack',
448
+ true
449
+ );
450
+
451
+ -- Update the spine-system account with the actual accounts type_id
452
+ UPDATE public.accounts
453
+ SET type_id = (SELECT id FROM public.types WHERE slug = 'account' AND app_id = v_spine_core_app_id LIMIT 1)
454
+ WHERE slug = 'spine-system';
455
+
456
+ END $$;
457
+
458
+ -- ============================================
459
+ -- 6. RPC FUNCTION: get_account_apps
460
+ -- ============================================
461
+
462
+ CREATE OR REPLACE FUNCTION public.get_account_apps(
463
+ account_id uuid,
464
+ include_system boolean DEFAULT true,
465
+ include_inactive boolean DEFAULT false
466
+ )
467
+ RETURNS TABLE(
468
+ id uuid,
469
+ slug text,
470
+ name text,
471
+ description text,
472
+ icon text,
473
+ color text,
474
+ version text,
475
+ app_type text,
476
+ source text,
477
+ owner_account_id uuid,
478
+ is_active boolean,
479
+ is_system boolean,
480
+ min_role text,
481
+ config jsonb,
482
+ nav_items jsonb,
483
+ route_prefix text,
484
+ renderer text,
485
+ created_at timestamptz
486
+ )
487
+ LANGUAGE plpgsql
488
+ AS $function$
489
+ BEGIN
490
+ RETURN QUERY
491
+ SELECT
492
+ a.id,
493
+ a.slug,
494
+ a.name,
495
+ a.description,
496
+ a.icon,
497
+ a.color,
498
+ a.version,
499
+ a.app_type,
500
+ a.source,
501
+ a.owner_account_id,
502
+ a.is_active,
503
+ a.is_system,
504
+ a.min_role,
505
+ a.config,
506
+ a.nav_items,
507
+ a.route_prefix,
508
+ a.renderer,
509
+ a.created_at
510
+ FROM public.apps a
511
+ WHERE
512
+ (include_system OR a.is_system = false)
513
+ AND (include_inactive OR a.is_active = true)
514
+ AND (a.is_system OR a.owner_account_id = get_account_apps.account_id)
515
+ ORDER BY
516
+ a.is_system DESC,
517
+ a.app_type,
518
+ a.name;
519
+ END;
520
+ $function$;
@@ -0,0 +1,43 @@
1
+ -- Migration 004: Enhancements
2
+ -- Additional enhancements and refinements to the Spine schema
3
+
4
+ -- ============================================
5
+ -- TYPE SCOPE STAMPING (from 012_type_scope.sql)
6
+ -- ============================================
7
+ -- Platform-scoped types: owned by spine-system, any authenticated user can read
8
+ UPDATE public.types
9
+ SET design_schema = design_schema || '{"scope":"platform"}'::jsonb
10
+ WHERE slug IN ('kb_article', 'course_lesson', 'community_post', 'community_question');
11
+
12
+ -- Customer-scoped types: owned by the customer's account
13
+ UPDATE public.types
14
+ SET design_schema = design_schema || '{"scope":"customer"}'::jsonb
15
+ WHERE slug IN ('support_ticket');
16
+
17
+ -- Account-scoped types: owned by the calling account (default, explicit for clarity)
18
+ UPDATE public.types
19
+ SET design_schema = design_schema || '{"scope":"account"}'::jsonb
20
+ WHERE design_schema->>'scope' IS NULL;
21
+
22
+ -- ============================================
23
+ -- TABLE COMMENTS
24
+ -- ============================================
25
+
26
+ COMMENT ON TABLE public.account_paths IS
27
+ 'Stores ancestor-descendant relationships for account hierarchy traversal';
28
+
29
+ COMMENT ON TABLE public.webhook_handlers IS
30
+ 'Dynamic registry for webhook handlers. Custom functions self-register here to be discoverable by the integration-routes handler without static imports.';
31
+
32
+ -- ============================================
33
+ -- ENHANCEMENT NOTES
34
+ -- ============================================
35
+ -- This file contains miscellaneous enhancements that refine the core schema:
36
+ --
37
+ -- 1. Type scope stamping: Ensures all types have an explicit scope field
38
+ -- in their design_schema for proper RLS and visibility control.
39
+ --
40
+ -- 2. Table comments: Documentation for key infrastructure tables.
41
+ --
42
+ -- Future enhancements should be added here as ALTER statements or
43
+ -- configuration updates that don't require new table creation.
@@ -0,0 +1,3 @@
1
+ /api/* /.netlify/functions/:splat 200
2
+ /v2/* /.netlify/v2/functions/:splat 200
3
+ /* /index.html 200
Binary file
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
2
+ <rect width="32" height="32" rx="5" fill="#1e2a4a"/>
3
+ </svg>
@@ -17,7 +17,7 @@
17
17
  set -euo pipefail
18
18
 
19
19
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
- PROJECT_ROOT="${PROJECT_ROOT:-$(dirname "$SCRIPT_DIR")}"
20
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
21
21
 
22
22
  CORE_SRC_DIR="$PROJECT_ROOT/.framework/src"
23
23
  CUSTOM_SRC_DIR="$PROJECT_ROOT/custom/apps"
@@ -18,7 +18,7 @@
18
18
  set -euo pipefail
19
19
 
20
20
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
21
- PROJECT_ROOT="${PROJECT_ROOT:-$(dirname "$SCRIPT_DIR")}"
21
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
22
22
 
23
23
  CORE_DIR="$PROJECT_ROOT/.framework/functions"
24
24
  CUSTOM_DIR="$PROJECT_ROOT/custom"
@@ -19,12 +19,6 @@ set -euo pipefail
19
19
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
20
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
21
21
 
22
- # Detect if running inside node_modules (consumer project install)
23
- # If so, output to actual project root (3 levels up from scripts/)
24
- if [[ "$SCRIPT_DIR" == *"/node_modules/spine-framework/"* ]]; then
25
- PROJECT_ROOT="$(dirname "$(dirname "$(dirname "$SCRIPT_DIR")")")"
26
- fi
27
-
28
22
  echo "Assembling Spine..."
29
23
 
30
24
  # Remove stale dist/ so Netlify CLI never reads its _redirects during dev
@@ -32,10 +26,10 @@ rm -rf "$PROJECT_ROOT/dist"
32
26
 
33
27
  # Step 1: Assemble functions
34
28
  echo "Assembling functions..."
35
- PROJECT_ROOT="$PROJECT_ROOT" bash "$SCRIPT_DIR/assemble-functions.sh"
29
+ bash "$SCRIPT_DIR/assemble-functions.sh"
36
30
 
37
31
  # Step 2: Assemble frontend
38
32
  echo "Assembling frontend..."
39
- PROJECT_ROOT="$PROJECT_ROOT" bash "$SCRIPT_DIR/assemble-frontend.sh"
33
+ bash "$SCRIPT_DIR/assemble-frontend.sh"
40
34
 
41
35
  echo "Spine assembly complete"
@@ -0,0 +1,9 @@
1
+ {
2
+ "slug": "account_cli_instances",
3
+ "source_kind": "account",
4
+ "target_kind": "item",
5
+ "target_type_slug": "spine_instance",
6
+ "name": "Account CLI Instances",
7
+ "description": "Links accounts to their CLI installations",
8
+ "is_active": true
9
+ }