spine-framework-cortex 0.1.7 → 0.1.10

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/LICENSE.md ADDED
@@ -0,0 +1,13 @@
1
+ # Spine Framework Internal Use License 1.0.0
2
+
3
+ **Source-available. Free for internal use. Commercial rights reserved.**
4
+
5
+ Copyright © 2026 Dahl Ventures Inc. All rights reserved.
6
+
7
+ This software is licensed under the Spine Framework Internal Use License 1.0.0.
8
+
9
+ For full license terms, see: https://github.com/spine-framework/spine-framework/blob/main/LICENSE.md
10
+
11
+ **Summary:** You may use this software for internal business use only. Commercial use, resale, SaaS offering, white-labeling, and distribution require a separate Commercial License.
12
+
13
+ Contact: webmaster@spine-framework.com
package/README.md CHANGED
@@ -1,27 +1,69 @@
1
1
  # spine-framework-cortex
2
2
 
3
- AI-powered support, CRM, and knowledge base app for Spine Framework.
3
+ **We're building Spine in the open.** The source is visible, the roadmap is public, and we share what we learn along the way. That said, Spine is not open source — commercial use requires a license. See [LICENSE.md](./LICENSE.md) for details.
4
+
5
+ ---
6
+
7
+ Cortex is an AI-powered internal workspace app for Spine Framework. It gives your team a unified interface for CRM, customer support, knowledge base management, community, and AI-assisted intelligence — all wired into the same data model your portal customers interact with.
8
+
9
+ ## Requirements
10
+
11
+ - [Spine Framework](https://www.npmjs.com/package/spine-framework) `>=0.1.0`
12
+ - A Spine project initialized with `npx spine-framework init`
4
13
 
5
14
  ## Installation
6
15
 
7
16
  ```bash
8
- npm install spine-framework-cortex
17
+ npx spine-framework install-app spine-framework-cortex@latest
9
18
  ```
10
19
 
11
- ## Usage
20
+ This seeds the required roles, types, and configuration into your database and registers the app with Spine's navigation system.
21
+
22
+ ## Features
23
+
24
+ - **CRM** — accounts, contacts, deals, health scoring, and activity tracking
25
+ - **Support** — ticket queue with AI triage and case resolution tracking
26
+ - **Knowledge base** — article management with AI-powered generation and ingestion
27
+ - **Community** — internal view of discussion threads and Q&A
28
+ - **Courses** — course and lesson content management
29
+ - **Intelligence** — visitor tracking, funnel signal processing, and opportunity queue
30
+
31
+ ## Routes
32
+
33
+ | Path | Description |
34
+ |------|-------------|
35
+ | `/cortex/dashboard` | Cortex home |
36
+ | `/cortex/crm` | CRM overview |
37
+ | `/cortex/crm/accounts` | Account list |
38
+ | `/cortex/crm/accounts/:id` | Account detail |
39
+ | `/cortex/crm/contacts` | Contacts |
40
+ | `/cortex/crm/deals` | Deals |
41
+ | `/cortex/crm/deals/:id` | Deal detail |
42
+ | `/cortex/crm/health` | Health scores |
43
+ | `/cortex/crm/activity` | Activity feed |
44
+ | `/cortex/support` | Support queue |
45
+ | `/cortex/support/:id` | Ticket detail |
46
+ | `/cortex/community` | Community |
47
+ | `/cortex/kb` | Knowledge base |
48
+ | `/cortex/kb/editor` | KB editor |
49
+ | `/cortex/kb/ingestion` | KB ingestion |
50
+ | `/cortex/courses` | Courses |
51
+ | `/cortex/intelligence` | Intelligence |
52
+
53
+ ## Uninstalling
12
54
 
13
55
  ```bash
14
- npx spine-framework install-app cortex
56
+ npx spine-framework uninstall-app spine-framework-cortex
15
57
  ```
16
58
 
17
- ## Features
59
+ ## License
18
60
 
19
- - Knowledge Base (KB) management with AI-powered article generation
20
- - Support ticket routing with AI triage
21
- - Anonymous visitor tracking and funnel signal processing
22
- - Opportunity queue for high-engagement prospects
23
- - Case analysis and resolution tracking
61
+ Spine Framework Cortex is **source-available, free for internal use**. Commercial use requires a separate license.
24
62
 
25
- ## License
63
+ See [LICENSE.md](./LICENSE.md) for full terms.
64
+
65
+ For commercial licensing: [spine-framework.com](https://spine-framework.com) · webmaster@spine-framework.com
66
+
67
+ ---
26
68
 
27
- MIT
69
+ Copyright © 2026 Dahl Ventures Inc. All rights reserved.
@@ -8,8 +8,9 @@
8
8
  */
9
9
 
10
10
  import * as React from "react"
11
- import { useNavigate, useLocation } from "react-router-dom"
11
+ import { Link, useNavigate, useLocation } from "react-router-dom"
12
12
  import { useAuth } from "@core/contexts/AuthContext"
13
+ import { useCurrentApp } from "@core/contexts/AppContext"
13
14
  import {
14
15
  LayoutDashboard,
15
16
  Building2,
@@ -35,26 +36,30 @@ import {
35
36
  SidebarRail,
36
37
  } from "@core/components/ui/sidebar"
37
38
 
38
- const crmItems = [
39
- { title: "Dashboard", url: "/cortex/dashboard", icon: LayoutDashboard },
40
- { title: "Accounts", url: "/cortex/crm/accounts", icon: Building2 },
41
- { title: "Contacts", url: "/cortex/crm/contacts", icon: Users },
42
- { title: "Deals", url: "/cortex/crm/deals", icon: Handshake },
43
- { title: "Health", url: "/cortex/crm/health", icon: Heart },
44
- { title: "Activity", url: "/cortex/crm/activity", icon: Activity },
45
- ]
46
-
47
- const opsItems = [
48
- { title: "Support", url: "/cortex/support", icon: Headphones },
49
- { title: "Community", url: "/cortex/community", icon: Users },
50
- { title: "Knowledge Base", url: "/cortex/kb", icon: BookOpen },
51
- { title: "Courses", url: "/cortex/courses", icon: GraduationCap },
52
- ]
53
-
54
39
  export function CortexSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
55
40
  const navigate = useNavigate()
56
41
  const location = useLocation()
57
42
  const { user } = useAuth()
43
+ const app = useCurrentApp()
44
+
45
+ // Normalize route_prefix: '/' becomes '' so all paths are /dashboard, /crm/accounts, etc.
46
+ const base = app.route_prefix === '/' ? '' : (app.route_prefix || '')
47
+
48
+ const crmItems = [
49
+ { title: "Dashboard", url: `${base}/dashboard`, icon: LayoutDashboard },
50
+ { title: "Accounts", url: `${base}/crm/accounts`, icon: Building2 },
51
+ { title: "Contacts", url: `${base}/crm/contacts`, icon: Users },
52
+ { title: "Deals", url: `${base}/crm/deals`, icon: Handshake },
53
+ { title: "Health", url: `${base}/crm/health`, icon: Heart },
54
+ { title: "Activity", url: `${base}/crm/activity`, icon: Activity },
55
+ ]
56
+
57
+ const opsItems = [
58
+ { title: "Support", url: `${base}/support`, icon: Headphones },
59
+ { title: "Community", url: `${base}/community`, icon: Users },
60
+ { title: "Knowledge Base", url: `${base}/kb`, icon: BookOpen },
61
+ { title: "Courses", url: `${base}/courses`, icon: GraduationCap },
62
+ ]
58
63
 
59
64
  const isActive = (url: string) => location.pathname.startsWith(url)
60
65
 
@@ -63,7 +68,7 @@ export function CortexSidebar({ ...props }: React.ComponentProps<typeof Sidebar>
63
68
  <SidebarHeader>
64
69
  <SidebarMenu>
65
70
  <SidebarMenuItem>
66
- <SidebarMenuButton size="lg" onClick={() => navigate("/cortex/dashboard")}>
71
+ <SidebarMenuButton size="lg" onClick={() => navigate(`${base}/dashboard`)}>
67
72
  <div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-primary text-primary-foreground">
68
73
  <span className="text-sm font-bold">Cx</span>
69
74
  </div>
@@ -87,10 +92,10 @@ export function CortexSidebar({ ...props }: React.ComponentProps<typeof Sidebar>
87
92
  asChild
88
93
  isActive={isActive(item.url)}
89
94
  >
90
- <a href={item.url}>
95
+ <Link to={item.url}>
91
96
  <item.icon className="h-4 w-4" />
92
97
  <span>{item.title}</span>
93
- </a>
98
+ </Link>
94
99
  </SidebarMenuButton>
95
100
  </SidebarMenuItem>
96
101
  ))}
@@ -108,10 +113,10 @@ export function CortexSidebar({ ...props }: React.ComponentProps<typeof Sidebar>
108
113
  asChild
109
114
  isActive={isActive(item.url)}
110
115
  >
111
- <a href={item.url}>
116
+ <Link to={item.url}>
112
117
  <item.icon className="h-4 w-4" />
113
118
  <span>{item.title}</span>
114
- </a>
119
+ </Link>
115
120
  </SidebarMenuButton>
116
121
  </SidebarMenuItem>
117
122
  ))}
package/index.tsx CHANGED
@@ -4,6 +4,7 @@ import { LoadingSpinner } from '@core/components/ui/LoadingSpinner'
4
4
  import { AppShell } from '@core/components/layout/AppShell'
5
5
  import { CortexSidebar } from './components/CortexSidebar'
6
6
  import { TooltipProvider } from '@core/components/ui/tooltip'
7
+ import { useCurrentApp } from '@core/contexts/AppContext'
7
8
 
8
9
  const CortexDashboard = lazy(() => import('./pages/CortexDashboard'))
9
10
 
@@ -40,13 +41,21 @@ const Fallback = <div className="min-h-[400px] flex items-center justify-center"
40
41
 
41
42
  function CortexLayout() {
42
43
  const location = useLocation()
44
+ const app = useCurrentApp()
45
+
46
+ // Normalize route_prefix: '/' → '' so paths are /dashboard, /crm/accounts, etc.
47
+ const base = app.route_prefix === '/' ? '' : (app.route_prefix || '')
48
+ const prefixDepth = base.split('/').filter(Boolean).length
49
+
43
50
  const segments = location.pathname.split('/').filter(Boolean)
44
- const breadcrumbs: { title: string; url?: string }[] = [{ title: 'Cortex', url: '/cortex/dashboard' }]
45
- if (segments[1] && segments[1] !== 'dashboard') {
46
- breadcrumbs.push({ title: segments[1].charAt(0).toUpperCase() + segments[1].slice(1) })
51
+ const appSegments = segments.slice(prefixDepth) // strips the prefix segments
52
+
53
+ const breadcrumbs: { title: string; url?: string }[] = [{ title: 'Cortex', url: `${base}/dashboard` }]
54
+ if (appSegments[0] && appSegments[0] !== 'dashboard') {
55
+ breadcrumbs.push({ title: appSegments[0].charAt(0).toUpperCase() + appSegments[0].slice(1) })
47
56
  }
48
- if (segments[2]) {
49
- breadcrumbs.push({ title: segments[2].charAt(0).toUpperCase() + segments[2].slice(1) })
57
+ if (appSegments[1]) {
58
+ breadcrumbs.push({ title: appSegments[1].charAt(0).toUpperCase() + appSegments[1].slice(1) })
50
59
  }
51
60
 
52
61
  return (
package/manifest.json CHANGED
@@ -5,7 +5,6 @@
5
5
  "version": "1.0.0",
6
6
  "required_roles": ["support"],
7
7
  "routes": [
8
- "/cortex",
9
8
  "/cortex/dashboard",
10
9
  "/cortex/crm",
11
10
  "/cortex/crm/accounts",
@@ -75,6 +74,18 @@
75
74
  "order": 7
76
75
  }
77
76
  ],
77
+ "changelog": [
78
+ {
79
+ "version": "1.0.0",
80
+ "notes": [
81
+ "Root-relative nav paths for subdomain deployment model",
82
+ "Prefix-aware sidebar navigation via useCurrentApp()",
83
+ "Prefix-aware breadcrumbs with Navigate index redirect",
84
+ "FilterTab replaces FunnelTab (lucide Filter icon)",
85
+ "Initial release"
86
+ ]
87
+ }
88
+ ],
78
89
  "features": ["crm", "support", "community", "kb", "courses", "intelligence"],
79
90
  "dependencies": ["items", "accounts", "pipelines", "integrations"],
80
91
  "entry_point": "./index.tsx",
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "spine-framework-cortex",
3
- "version": "0.1.7",
3
+ "version": "0.1.10",
4
4
  "description": "Cortex — AI-powered support, CRM, and knowledge base app for Spine Framework",
5
5
  "type": "module",
6
- "license": "MIT",
6
+ "license": "SEE LICENSE IN LICENSE.md",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/art-mojo-admin/spine",
9
+ "url": "https://github.com/spine-framework/cortex",
10
10
  "directory": "custom/apps/cortex"
11
11
  },
12
12
  "peerDependencies": {
@@ -20,7 +20,8 @@
20
20
  "components/",
21
21
  "functions/",
22
22
  "lib/",
23
- "README.md"
23
+ "README.md",
24
+ "LICENSE.md"
24
25
  ],
25
26
  "spine": {
26
27
  "type": "app",
@@ -7,7 +7,7 @@ import { Skeleton } from '@core/components/ui/skeleton'
7
7
  import { Button } from '@core/components/ui/button'
8
8
  import { ScrollArea } from '@core/components/ui/scroll-area'
9
9
  import { Separator } from '@core/components/ui/separator'
10
- import { ArrowLeft, User, Ticket, Handshake, Activity, Heart, Funnel, TrendingUp, Target, Clock } from 'lucide-react'
10
+ import { ArrowLeft, User, Ticket, Handshake, Activity, Heart, Filter, TrendingUp, Target, Clock } from 'lucide-react'
11
11
 
12
12
  interface Account {
13
13
  id: string
@@ -140,7 +140,7 @@ function ActivityTab({ accountId }: { accountId: string }) {
140
140
  )
141
141
  }
142
142
 
143
- function FunnelTab({ account }: { account: Account }) {
143
+ function FilterTab({ account }: { account: Account }) {
144
144
  const stage = account.data?.lifecycle_stage
145
145
  const score = account.data?.lead_score ?? 0
146
146
  const temp = account.data?.temperature
@@ -217,7 +217,7 @@ function FunnelTab({ account }: { account: Account }) {
217
217
  {queue?.pending_opportunity_id && (
218
218
  <div className="border rounded-lg p-4 bg-yellow-50 border-yellow-200">
219
219
  <div className="flex items-center gap-2">
220
- <Funnel className="h-4 w-4 text-yellow-600" />
220
+ <Filter className="h-4 w-4 text-yellow-600" />
221
221
  <span className="font-medium text-sm">Opportunity in Queue</span>
222
222
  </div>
223
223
  <p className="text-xs text-muted-foreground mt-1">
@@ -317,7 +317,7 @@ function FunnelTab({ account }: { account: Account }) {
317
317
  {/* Empty State */}
318
318
  {!stage && !score && !temp && !ratings && !queue?.pending_opportunity_id && (
319
319
  <div className="text-center py-12 text-muted-foreground">
320
- <Funnel className="h-10 w-10 mx-auto mb-3 opacity-30" />
320
+ <Filter className="h-10 w-10 mx-auto mb-3 opacity-30" />
321
321
  <p className="text-sm">No funnel data yet.</p>
322
322
  <p className="text-xs mt-1">Signals will appear here as they are processed.</p>
323
323
  </div>
@@ -364,7 +364,7 @@ export default function AccountDetailPage() {
364
364
  <TabsList className="h-9 bg-transparent p-0 gap-4">
365
365
  {[
366
366
  { value: 'people', label: 'People', icon: User },
367
- { value: 'funnel', label: 'Funnel', icon: Funnel },
367
+ { value: 'funnel', label: 'Funnel', icon: Filter },
368
368
  { value: 'tickets', label: 'Tickets', icon: Ticket },
369
369
  { value: 'deals', label: 'Deals', icon: Handshake },
370
370
  { value: 'health', label: 'Health', icon: Heart },
@@ -381,7 +381,7 @@ export default function AccountDetailPage() {
381
381
 
382
382
  <ScrollArea className="flex-1">
383
383
  <TabsContent value="people" className="mt-0"><PeopleTab accountId={id!} /></TabsContent>
384
- <TabsContent value="funnel" className="mt-0"><FunnelTab account={account} /></TabsContent>
384
+ <TabsContent value="funnel" className="mt-0"><FilterTab account={account} /></TabsContent>
385
385
  <TabsContent value="tickets" className="mt-0"><ItemsTab accountId={id!} typeSlug="support_ticket" emptyText="No tickets." /></TabsContent>
386
386
  <TabsContent value="deals" className="mt-0"><ItemsTab accountId={id!} typeSlug="deal" emptyText="No deals." /></TabsContent>
387
387
  <TabsContent value="health" className="mt-0"><ItemsTab accountId={id!} typeSlug="csm_health" emptyText="No health records." /></TabsContent>