@lssm/example.learning-journey-crm-onboarding 0.0.0-canary-20251213172311

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,19 @@
1
+ $ bun build:bundle && bun build:types
2
+ $ tsdown
3
+ ℹ tsdown v0.17.0 powered by rolldown v1.0.0-beta.53
4
+ ℹ config file: /home/runner/work/contractspec/contractspec/packages/examples/learning-journey-crm-onboarding/tsdown.config.js
5
+ ℹ entry: src/example.ts, src/index.ts, src/track.ts, src/contracts/index.ts, src/docs/crm-onboarding.docblock.ts, src/docs/index.ts, src/handlers/demo.handlers.ts, src/presentations/index.ts
6
+ ℹ target: esnext
7
+ ℹ tsconfig: tsconfig.json
8
+ ℹ Build start
9
+ ℹ dist/contracts/index.js 2.79 kB │ gzip: 0.92 kB
10
+ ℹ dist/track.js 1.94 kB │ gzip: 0.69 kB
11
+ ℹ dist/docs/crm-onboarding.docblock.js 1.27 kB │ gzip: 0.67 kB
12
+ ℹ dist/index.js 0.91 kB │ gzip: 0.31 kB
13
+ ℹ dist/presentations/index.js 0.77 kB │ gzip: 0.37 kB
14
+ ℹ dist/example.js 0.55 kB │ gzip: 0.35 kB
15
+ ℹ dist/handlers/demo.handlers.js 0.41 kB │ gzip: 0.26 kB
16
+ ℹ dist/docs/index.js 0.04 kB │ gzip: 0.06 kB
17
+ ℹ 8 files, total: 8.68 kB
18
+ ✔ Build complete in 42ms
19
+ $ tsc --noEmit
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # @lssm/example.learning-journey-crm-onboarding
2
+
3
+ ## 0.0.0-canary-20251213172311
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [3086383]
8
+ - @lssm/example.crm-pipeline@0.0.0-canary-20251213172311
9
+ - @lssm/lib.contracts@0.0.0-canary-20251213172311
10
+ - @lssm/lib.schema@0.0.0-canary-20251213172311
11
+ - @lssm/module.learning-journey@0.0.0-canary-20251213172311
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @lssm/example.learning-journey-crm-onboarding
2
+
3
+ Learning Journey example that guides a CRM user to first closed-won deal.
4
+
5
+ ## Track
6
+
7
+ - **Key**: `crm_first_win`
8
+ - **Persona**: CRM adopter
9
+ - **XP**: 15/20/20/20/30/30 + 25 bonus
10
+ - **Badge**: `crm_first_win`
11
+
12
+ ## Steps & Events
13
+
14
+ 1. `create_pipeline` → `pipeline.created`
15
+ 2. `create_contact_and_company` → `contact.created`
16
+ 3. `create_first_deal` → `deal.created`
17
+ 4. `move_deal_in_pipeline` → `deal.moved`
18
+ 5. `close_deal_won` → `deal.won`
19
+ 6. `setup_follow_up` → `task.completed` (type: follow_up)
20
+
21
+ ## Usage
22
+
23
+ - Import track specs:
24
+ `import { crmLearningTracks } from '@lssm/example.learning-journey-crm-onboarding/track'`
25
+ - Contracts/handlers for demos:
26
+ `import { GetCrmOnboardingTrack, RecordCrmOnboardingEvent } from '@lssm/example.learning-journey-crm-onboarding/contracts'`
27
+ `import { emitCrmOnboardingEvent } from '@lssm/example.learning-journey-crm-onboarding/handlers/demo.handlers'`
28
+ - Presentations (react/markdown/json targets):
29
+ `import { crmOnboardingPresentations } from '@lssm/example.learning-journey-crm-onboarding/presentations'`
30
+ - Register via onboarding API:
31
+ - `learning.onboarding.listTracks`
32
+ - `learning.onboarding.getProgress`
33
+ - `learning.onboarding.recordEvent` wired from CRM events
34
+ - Requires CRM pipeline example events to be emitted for completion.
35
+
36
+ ## Docs
37
+
38
+ - Docblock: `src/docs/crm-onboarding.docblock.ts`
39
+ - Route suggestion: `/docs/learning-journey/crm-onboarding`
@@ -0,0 +1 @@
1
+ import{crmFirstWinTrack as e}from"../track.js";import{ScalarTypeEnum as t,defineSchemaModel as n}from"@lssm/lib.schema";import{defineCommand as r,defineQuery as i}from"@lssm/lib.contracts";const a=[`examples.learning-journey.crm-onboarding`],o=n({name:`CrmOnboardingStep`,description:`Step metadata for CRM first win journey`,fields:{id:{type:t.String_unsecure(),isOptional:!1},title:{type:t.String_unsecure(),isOptional:!1},description:{type:t.String_unsecure(),isOptional:!0},completionEvent:{type:t.String_unsecure(),isOptional:!1},sourceModule:{type:t.String_unsecure(),isOptional:!0},xpReward:{type:t.Int_unsecure(),isOptional:!0},order:{type:t.Int_unsecure(),isOptional:!0}}}),s=n({name:`CrmOnboardingTrack`,description:`CRM onboarding track definition`,fields:{id:{type:t.String_unsecure(),isOptional:!1},name:{type:t.String_unsecure(),isOptional:!1},description:{type:t.String_unsecure(),isOptional:!0},totalXp:{type:t.Int_unsecure(),isOptional:!0},completionXpBonus:{type:t.Int_unsecure(),isOptional:!0},completionBadgeKey:{type:t.String_unsecure(),isOptional:!0},streakHoursWindow:{type:t.Int_unsecure(),isOptional:!0},streakBonusXp:{type:t.Int_unsecure(),isOptional:!0},steps:{type:o,isArray:!0,isOptional:!1}}}),c=n({name:`CrmOnboardingTrackResponse`,description:`Response wrapper for CRM onboarding track`,fields:{track:{type:s,isOptional:!1}}}),l=n({name:`CrmOnboardingRecordEventInput`,description:`Emit a demo event to advance CRM onboarding steps`,fields:{learnerId:{type:t.String_unsecure(),isOptional:!1},eventName:{type:t.String_unsecure(),isOptional:!1},payload:{type:t.JSON(),isOptional:!0},occurredAt:{type:t.DateTime(),isOptional:!0}}}),u=n({name:`CrmOnboardingSuccess`,description:`Generic success response`,fields:{success:{type:t.Boolean(),isOptional:!1}}}),d=i({meta:{name:`learningJourney.crmOnboarding.getTrack`,version:1,stability:`experimental`,owners:[...a],tags:[`learning`,`crm`,`onboarding`],description:`Fetch CRM first win track definition.`,goal:`Expose track metadata to UIs and templates.`,context:`Called by Studio/Playground to render journey steps.`},io:{input:n({name:`CrmOnboardingTrackInput`,description:`Track input`,fields:{}}),output:c},policy:{auth:`user`}}),f=r({meta:{name:`learningJourney.crmOnboarding.recordEvent`,version:1,stability:`experimental`,owners:[...a],tags:[`learning`,`crm`,`onboarding`],description:`Record an event to advance CRM onboarding progress.`,goal:`Advance steps via domain events in demo/sandbox contexts.`,context:`Called by handlers or demo scripts to emit step completion events.`},io:{input:l,output:u},policy:{auth:`user`}}),p={GetCrmOnboardingTrack:d,RecordCrmOnboardingEvent:f,track:e};export{s as CrmOnboardingTrackModel,d as GetCrmOnboardingTrack,f as RecordCrmOnboardingEvent,p as crmOnboardingContracts};
@@ -0,0 +1 @@
1
+ import{registerDocBlocks as e}from"@lssm/lib.contracts/docs";e([{id:`docs.learning-journey.crm-onboarding`,title:`Learning Journey — CRM First Win`,summary:`Onboarding track for the CRM Pipeline example that drives users to first closed-won deal.`,kind:`reference`,visibility:`public`,route:`/docs/learning-journey/crm-onboarding`,tags:[`learning`,`crm`,`onboarding`],body:"## Track\n- **Key**: `crm_first_win`\n- **Persona**: CRM adopter\n- **Goal**: From empty CRM to first closed-won deal with follow-up\n\n## Steps & Events\n1) `create_pipeline` → `pipeline.created`\n2) `create_contact_and_company` → `contact.created`\n3) `create_first_deal` → `deal.created`\n4) `move_deal_in_pipeline` → `deal.moved`\n5) `close_deal_won` → `deal.won`\n6) `setup_follow_up` → `task.completed` (type: follow_up)\n\nXP: 15/20/20/20/30/30 with 25 bonus within 72h. Badge: `crm_first_win`.\n\n## Wiring\n- Depends on `@lssm/example.crm-pipeline` events.\n- Tracks export from `@lssm/example.learning-journey-crm-onboarding/track`.\n- Use onboarding API:\n - `learning.onboarding.listTracks`\n - `learning.onboarding.getProgress`\n - `learning.onboarding.recordEvent` wired from CRM event bus handlers.\n- Surface in CRM dashboard/pipeline UI to guide new users."}]);
@@ -0,0 +1 @@
1
+ import"./crm-onboarding.docblock.js";
@@ -0,0 +1 @@
1
+ var e={id:`learning-journey-crm-onboarding`,title:`Learning Journey — CRM First Win`,summary:`Onboarding track for CRM Pipeline driving users from empty CRM to first closed-won deal.`,tags:[`learning`,`crm`,`onboarding`],kind:`template`,visibility:`public`,docs:{rootDocId:`docs.learning-journey.crm-onboarding`},entrypoints:{packageName:`@lssm/example.learning-journey-crm-onboarding`,docs:`./docs`},surfaces:{templates:!0,sandbox:{enabled:!0,modes:[`playground`,`markdown`]},studio:{enabled:!0,installable:!0},mcp:{enabled:!0}}};export{e as default};
@@ -0,0 +1 @@
1
+ import{crmFirstWinTrack as e}from"../track.js";const t=[`pipeline.created`,`contact.created`,`deal.created`,`deal.moved`,`deal.won`,`task.completed`],n=(t,{learnerId:n,occurredAt:r=new Date,payload:i},a)=>{let o={learnerId:n,name:t,occurredAt:r,payload:i,trackId:e.id};return a?a(o):o},r=(e,r)=>t.map(t=>n(t,e,r));export{t as crmOnboardingEvents,r as emitAllCrmOnboardingEvents,n as emitCrmOnboardingEvent};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import e from"./example.js";import{crmFirstWinTrack as t,crmLearningTracks as n}from"./track.js";import"./docs/index.js";import{CrmOnboardingTrackModel as r,GetCrmOnboardingTrack as i,RecordCrmOnboardingEvent as a,crmOnboardingContracts as o}from"./contracts/index.js";import{crmOnboardingEvents as s,emitAllCrmOnboardingEvents as c,emitCrmOnboardingEvent as l}from"./handlers/demo.handlers.js";import{CrmOnboardingTrackPresentation as u,CrmOnboardingWidgetPresentation as d,crmOnboardingPresentations as f}from"./presentations/index.js";export{r as CrmOnboardingTrackModel,u as CrmOnboardingTrackPresentation,d as CrmOnboardingWidgetPresentation,i as GetCrmOnboardingTrack,a as RecordCrmOnboardingEvent,t as crmFirstWinTrack,n as crmLearningTracks,o as crmOnboardingContracts,s as crmOnboardingEvents,f as crmOnboardingPresentations,c as emitAllCrmOnboardingEvents,l as emitCrmOnboardingEvent,e as example};
@@ -0,0 +1 @@
1
+ import{CrmOnboardingTrackModel as e}from"../contracts/index.js";const t={domain:`learning-journey`,owners:[`examples.learning-journey.crm-onboarding`],tags:[`learning`,`crm`,`onboarding`]},n={meta:{name:`learning.journey.crm.track`,version:1,description:`CRM first win track detail`,...t},source:{type:`component`,framework:`react`,componentKey:`LearningTrackDetail`,props:e},targets:[`react`,`markdown`,`application/json`]},r={meta:{name:`learning.journey.crm.widget`,version:1,description:`Compact widget for CRM onboarding progress`,...t},source:{type:`component`,framework:`react`,componentKey:`LearningTrackProgressWidget`},targets:[`react`]},i=[n,r];export{n as CrmOnboardingTrackPresentation,r as CrmOnboardingWidgetPresentation,i as crmOnboardingPresentations};
package/dist/track.js ADDED
@@ -0,0 +1 @@
1
+ const e={id:`crm_first_win`,productId:`crm-pipeline`,name:`CRM First Win`,description:`Guide a new CRM user from empty pipeline to first closed-won deal.`,targetUserSegment:`crm_adopter`,targetRole:`sales`,totalXp:135,streakRule:{hoursWindow:72,bonusXp:25},completionRewards:{xpBonus:25,badgeKey:`crm_first_win`},steps:[{id:`create_pipeline`,title:`Create pipeline & stages`,description:`Create a pipeline with baseline stages.`,order:1,completion:{eventName:`pipeline.created`,sourceModule:`@lssm/example.crm-pipeline`},xpReward:15,metadata:{surface:`pipeline`}},{id:`create_contact_and_company`,title:`Create contact and company`,description:`Add your first contact and associated company.`,order:2,completion:{eventName:`contact.created`,sourceModule:`@lssm/example.crm-pipeline`},xpReward:20,metadata:{surface:`contacts`}},{id:`create_first_deal`,title:`Log first deal`,description:`Create your first deal in the pipeline.`,order:3,completion:{eventName:`deal.created`,sourceModule:`@lssm/example.crm-pipeline`},xpReward:20,metadata:{surface:`deals`}},{id:`move_deal_in_pipeline`,title:`Move a deal across stages`,description:`Move a deal across at least three stages.`,order:4,completion:{eventName:`deal.moved`,sourceModule:`@lssm/example.crm-pipeline`},xpReward:20,metadata:{surface:`deals`}},{id:`close_deal_won`,title:`Close a deal as won`,description:`Close a deal as won to hit first revenue.`,order:5,completion:{eventName:`deal.won`,sourceModule:`@lssm/example.crm-pipeline`},xpReward:30,metadata:{surface:`deals`}},{id:`setup_follow_up`,title:`Create follow-up task`,description:`Create a follow-up task and notification for a contact or deal.`,order:6,completion:{eventName:`task.completed`,sourceModule:`@lssm/example.crm-pipeline`,payloadFilter:{type:`follow_up`}},xpReward:30,metadata:{surface:`tasks`}}],metadata:{surfacedIn:[`crm/dashboard`,`crm/pipeline`]}},t=[e];export{e as crmFirstWinTrack,t as crmLearningTracks};
package/example.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from './src/example';
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@lssm/example.learning-journey-crm-onboarding",
3
+ "version": "0.0.0-canary-20251213172311",
4
+ "description": "Learning journey track that onboards users to the CRM pipeline example.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./contracts": "./src/contracts/index.ts",
11
+ "./docs": "./src/docs/index.ts",
12
+ "./docs/crm-onboarding.docblock": "./src/docs/crm-onboarding.docblock.ts",
13
+ "./example": "./src/example.ts",
14
+ "./handlers/demo.handlers": "./src/handlers/demo.handlers.ts",
15
+ "./presentations": "./src/presentations/index.ts",
16
+ "./track": "./src/track.ts",
17
+ "./*": "./*"
18
+ },
19
+ "scripts": {
20
+ "build": "bun build:bundle && bun build:types",
21
+ "build:bundle": "tsdown",
22
+ "build:types": "tsc --noEmit",
23
+ "dev": "bun build:bundle --watch",
24
+ "clean": "rimraf dist .turbo",
25
+ "lint": "bun lint:fix",
26
+ "lint:fix": "eslint src --fix",
27
+ "lint:check": "eslint src"
28
+ },
29
+ "dependencies": {
30
+ "@lssm/lib.contracts": "workspace:*",
31
+ "@lssm/lib.schema": "workspace:*",
32
+ "@lssm/module.learning-journey": "workspace:*",
33
+ "@lssm/example.crm-pipeline": "workspace:*"
34
+ },
35
+ "devDependencies": {
36
+ "@lssm/tool.tsdown": "workspace:*",
37
+ "@lssm/tool.typescript": "workspace:*",
38
+ "tsdown": "^0.17.0",
39
+ "typescript": "^5.9.3"
40
+ },
41
+ "module": "./dist/index.js",
42
+ "publishConfig": {
43
+ "exports": {
44
+ ".": "./dist/index.js",
45
+ "./contracts": "./dist/contracts/index.js",
46
+ "./docs": "./dist/docs/index.js",
47
+ "./docs/crm-onboarding.docblock": "./dist/docs/crm-onboarding.docblock.js",
48
+ "./example": "./dist/example.js",
49
+ "./handlers/demo.handlers": "./dist/handlers/demo.handlers.js",
50
+ "./presentations": "./dist/presentations/index.js",
51
+ "./track": "./dist/track.js",
52
+ "./*": "./*"
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,49 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+
3
+ import {
4
+ GetCrmOnboardingTrack,
5
+ RecordCrmOnboardingEvent,
6
+ crmOnboardingContracts,
7
+ } from './index';
8
+ import { crmFirstWinTrack } from '../track';
9
+ import {
10
+ crmOnboardingEvents,
11
+ emitCrmOnboardingEvent,
12
+ } from '../handlers/demo.handlers';
13
+ import type { CrmEvent } from '../handlers/demo.handlers';
14
+
15
+ describe('crm onboarding contracts', () => {
16
+ it('exposes track metadata', () => {
17
+ expect(crmOnboardingContracts.track.id).toBe('crm_first_win');
18
+ expect(crmOnboardingContracts.track.steps.length).toBeGreaterThan(0);
19
+ expect(GetCrmOnboardingTrack.meta.name).toBe(
20
+ 'learningJourney.crmOnboarding.getTrack'
21
+ );
22
+ });
23
+
24
+ it('allows recording events via demo handler', async () => {
25
+ const [step] = crmFirstWinTrack.steps;
26
+ expect(step).toBeDefined();
27
+ if (!step) throw new Error('Expected at least one CRM onboarding step');
28
+
29
+ const eventName = step.completion.eventName;
30
+ const isCrmEvent = (value: string): value is CrmEvent =>
31
+ crmOnboardingEvents.includes(value as CrmEvent);
32
+
33
+ expect(isCrmEvent(eventName)).toBe(true);
34
+ if (!isCrmEvent(eventName)) {
35
+ throw new Error(`Unexpected event name: ${eventName}`);
36
+ }
37
+
38
+ const result = await emitCrmOnboardingEvent(eventName, {
39
+ learnerId: 'demo-learner',
40
+ });
41
+ expect(result).toBeDefined();
42
+ });
43
+
44
+ it('exposes record event contract', () => {
45
+ expect(RecordCrmOnboardingEvent.meta.name).toBe(
46
+ 'learningJourney.crmOnboarding.recordEvent'
47
+ );
48
+ });
49
+ });
@@ -0,0 +1,122 @@
1
+ import { ScalarTypeEnum, defineSchemaModel } from '@lssm/lib.schema';
2
+ import { defineCommand, defineQuery } from '@lssm/lib.contracts';
3
+
4
+ import { crmFirstWinTrack } from '../track';
5
+
6
+ const OWNERS = ['examples.learning-journey.crm-onboarding'] as const;
7
+
8
+ const StepModel = defineSchemaModel({
9
+ name: 'CrmOnboardingStep',
10
+ description: 'Step metadata for CRM first win journey',
11
+ fields: {
12
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
13
+ title: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
14
+ description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
15
+ completionEvent: {
16
+ type: ScalarTypeEnum.String_unsecure(),
17
+ isOptional: false,
18
+ },
19
+ sourceModule: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
20
+ xpReward: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
21
+ order: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
22
+ },
23
+ });
24
+
25
+ export const CrmOnboardingTrackModel = defineSchemaModel({
26
+ name: 'CrmOnboardingTrack',
27
+ description: 'CRM onboarding track definition',
28
+ fields: {
29
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
30
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
31
+ description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
32
+ totalXp: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
33
+ completionXpBonus: {
34
+ type: ScalarTypeEnum.Int_unsecure(),
35
+ isOptional: true,
36
+ },
37
+ completionBadgeKey: {
38
+ type: ScalarTypeEnum.String_unsecure(),
39
+ isOptional: true,
40
+ },
41
+ streakHoursWindow: {
42
+ type: ScalarTypeEnum.Int_unsecure(),
43
+ isOptional: true,
44
+ },
45
+ streakBonusXp: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
46
+ steps: { type: StepModel, isArray: true, isOptional: false },
47
+ },
48
+ });
49
+
50
+ const TrackResponseModel = defineSchemaModel({
51
+ name: 'CrmOnboardingTrackResponse',
52
+ description: 'Response wrapper for CRM onboarding track',
53
+ fields: {
54
+ track: { type: CrmOnboardingTrackModel, isOptional: false },
55
+ },
56
+ });
57
+
58
+ const RecordDemoEventInput = defineSchemaModel({
59
+ name: 'CrmOnboardingRecordEventInput',
60
+ description: 'Emit a demo event to advance CRM onboarding steps',
61
+ fields: {
62
+ learnerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
63
+ eventName: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
64
+ payload: { type: ScalarTypeEnum.JSON(), isOptional: true },
65
+ occurredAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
66
+ },
67
+ });
68
+
69
+ const SuccessModel = defineSchemaModel({
70
+ name: 'CrmOnboardingSuccess',
71
+ description: 'Generic success response',
72
+ fields: {
73
+ success: { type: ScalarTypeEnum.Boolean(), isOptional: false },
74
+ },
75
+ });
76
+
77
+ export const GetCrmOnboardingTrack = defineQuery({
78
+ meta: {
79
+ name: 'learningJourney.crmOnboarding.getTrack',
80
+ version: 1,
81
+ stability: 'experimental',
82
+ owners: [...OWNERS],
83
+ tags: ['learning', 'crm', 'onboarding'],
84
+ description: 'Fetch CRM first win track definition.',
85
+ goal: 'Expose track metadata to UIs and templates.',
86
+ context: 'Called by Studio/Playground to render journey steps.',
87
+ },
88
+ io: {
89
+ input: defineSchemaModel({
90
+ name: 'CrmOnboardingTrackInput',
91
+ description: 'Track input',
92
+ fields: {},
93
+ }),
94
+ output: TrackResponseModel,
95
+ },
96
+ policy: { auth: 'user' },
97
+ });
98
+
99
+ export const RecordCrmOnboardingEvent = defineCommand({
100
+ meta: {
101
+ name: 'learningJourney.crmOnboarding.recordEvent',
102
+ version: 1,
103
+ stability: 'experimental',
104
+ owners: [...OWNERS],
105
+ tags: ['learning', 'crm', 'onboarding'],
106
+ description: 'Record an event to advance CRM onboarding progress.',
107
+ goal: 'Advance steps via domain events in demo/sandbox contexts.',
108
+ context:
109
+ 'Called by handlers or demo scripts to emit step completion events.',
110
+ },
111
+ io: {
112
+ input: RecordDemoEventInput,
113
+ output: SuccessModel,
114
+ },
115
+ policy: { auth: 'user' },
116
+ });
117
+
118
+ export const crmOnboardingContracts = {
119
+ GetCrmOnboardingTrack,
120
+ RecordCrmOnboardingEvent,
121
+ track: crmFirstWinTrack,
122
+ };
@@ -0,0 +1,40 @@
1
+ import type { DocBlock } from '@lssm/lib.contracts/docs';
2
+ import { registerDocBlocks } from '@lssm/lib.contracts/docs';
3
+
4
+ const crmOnboardingDocBlocks: DocBlock[] = [
5
+ {
6
+ id: 'docs.learning-journey.crm-onboarding',
7
+ title: 'Learning Journey — CRM First Win',
8
+ summary:
9
+ 'Onboarding track for the CRM Pipeline example that drives users to first closed-won deal.',
10
+ kind: 'reference',
11
+ visibility: 'public',
12
+ route: '/docs/learning-journey/crm-onboarding',
13
+ tags: ['learning', 'crm', 'onboarding'],
14
+ body: `## Track
15
+ - **Key**: \`crm_first_win\`
16
+ - **Persona**: CRM adopter
17
+ - **Goal**: From empty CRM to first closed-won deal with follow-up
18
+
19
+ ## Steps & Events
20
+ 1) \`create_pipeline\` → \`pipeline.created\`
21
+ 2) \`create_contact_and_company\` → \`contact.created\`
22
+ 3) \`create_first_deal\` → \`deal.created\`
23
+ 4) \`move_deal_in_pipeline\` → \`deal.moved\`
24
+ 5) \`close_deal_won\` → \`deal.won\`
25
+ 6) \`setup_follow_up\` → \`task.completed\` (type: follow_up)
26
+
27
+ XP: 15/20/20/20/30/30 with 25 bonus within 72h. Badge: \`crm_first_win\`.
28
+
29
+ ## Wiring
30
+ - Depends on \`@lssm/example.crm-pipeline\` events.
31
+ - Tracks export from \`@lssm/example.learning-journey-crm-onboarding/track\`.
32
+ - Use onboarding API:
33
+ - \`learning.onboarding.listTracks\`
34
+ - \`learning.onboarding.getProgress\`
35
+ - \`learning.onboarding.recordEvent\` wired from CRM event bus handlers.
36
+ - Surface in CRM dashboard/pipeline UI to guide new users.`,
37
+ },
38
+ ];
39
+
40
+ registerDocBlocks(crmOnboardingDocBlocks);
@@ -0,0 +1 @@
1
+ import './crm-onboarding.docblock';
package/src/example.ts ADDED
@@ -0,0 +1,26 @@
1
+ const example = {
2
+ id: 'learning-journey-crm-onboarding',
3
+ title: 'Learning Journey — CRM First Win',
4
+ summary:
5
+ 'Onboarding track for CRM Pipeline driving users from empty CRM to first closed-won deal.',
6
+ tags: ['learning', 'crm', 'onboarding'],
7
+ kind: 'template',
8
+ visibility: 'public',
9
+ docs: {
10
+ rootDocId: 'docs.learning-journey.crm-onboarding',
11
+ },
12
+ entrypoints: {
13
+ packageName: '@lssm/example.learning-journey-crm-onboarding',
14
+ docs: './docs',
15
+ },
16
+ surfaces: {
17
+ templates: true,
18
+ sandbox: { enabled: true, modes: ['playground', 'markdown'] },
19
+ studio: { enabled: true, installable: true },
20
+ mcp: { enabled: true },
21
+ },
22
+ } as const;
23
+
24
+ export default example;
25
+
26
+
@@ -0,0 +1,51 @@
1
+ import { crmFirstWinTrack } from '../track';
2
+
3
+ interface EmitParams {
4
+ learnerId: string;
5
+ occurredAt?: Date;
6
+ payload?: Record<string, unknown>;
7
+ }
8
+
9
+ interface LearningJourneyEvent {
10
+ learnerId: string;
11
+ name: string;
12
+ occurredAt: Date;
13
+ trackId: string;
14
+ payload?: Record<string, unknown>;
15
+ }
16
+
17
+ type RecordEvent = (event: LearningJourneyEvent) => unknown;
18
+
19
+ export const crmOnboardingEvents = [
20
+ 'pipeline.created',
21
+ 'contact.created',
22
+ 'deal.created',
23
+ 'deal.moved',
24
+ 'deal.won',
25
+ 'task.completed',
26
+ ] as const;
27
+
28
+ export type CrmEvent = (typeof crmOnboardingEvents)[number];
29
+
30
+ export const emitCrmOnboardingEvent = (
31
+ eventName: CrmEvent,
32
+ { learnerId, occurredAt = new Date(), payload }: EmitParams,
33
+ record?: RecordEvent
34
+ ) => {
35
+ const event: LearningJourneyEvent = {
36
+ learnerId,
37
+ name: eventName,
38
+ occurredAt,
39
+ payload,
40
+ trackId: crmFirstWinTrack.id,
41
+ };
42
+ return record ? record(event) : event;
43
+ };
44
+
45
+ export const emitAllCrmOnboardingEvents = (
46
+ params: EmitParams,
47
+ record?: RecordEvent
48
+ ) =>
49
+ crmOnboardingEvents.map((name) =>
50
+ emitCrmOnboardingEvent(name, params, record)
51
+ );
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './track';
2
+ export * from './docs';
3
+ export * from './contracts';
4
+ export * from './handlers/demo.handlers';
5
+ export * from './presentations';
6
+ export { default as example } from './example';
@@ -0,0 +1,47 @@
1
+ import type {
2
+ PresentationDescriptorV2,
3
+ PresentationV2Meta,
4
+ } from '@lssm/lib.contracts';
5
+ import { CrmOnboardingTrackModel } from '../contracts';
6
+
7
+ const baseMeta: Pick<PresentationV2Meta, 'domain' | 'owners' | 'tags'> = {
8
+ domain: 'learning-journey',
9
+ owners: ['examples.learning-journey.crm-onboarding'],
10
+ tags: ['learning', 'crm', 'onboarding'],
11
+ };
12
+
13
+ export const CrmOnboardingTrackPresentation: PresentationDescriptorV2 = {
14
+ meta: {
15
+ name: 'learning.journey.crm.track',
16
+ version: 1,
17
+ description: 'CRM first win track detail',
18
+ ...baseMeta,
19
+ },
20
+ source: {
21
+ type: 'component',
22
+ framework: 'react',
23
+ componentKey: 'LearningTrackDetail',
24
+ props: CrmOnboardingTrackModel,
25
+ },
26
+ targets: ['react', 'markdown', 'application/json'],
27
+ };
28
+
29
+ export const CrmOnboardingWidgetPresentation: PresentationDescriptorV2 = {
30
+ meta: {
31
+ name: 'learning.journey.crm.widget',
32
+ version: 1,
33
+ description: 'Compact widget for CRM onboarding progress',
34
+ ...baseMeta,
35
+ },
36
+ source: {
37
+ type: 'component',
38
+ framework: 'react',
39
+ componentKey: 'LearningTrackProgressWidget',
40
+ },
41
+ targets: ['react'],
42
+ };
43
+
44
+ export const crmOnboardingPresentations = [
45
+ CrmOnboardingTrackPresentation,
46
+ CrmOnboardingWidgetPresentation,
47
+ ];
package/src/track.ts ADDED
@@ -0,0 +1,95 @@
1
+ import type { LearningJourneyTrackSpec } from '@lssm/module.learning-journey/track-spec';
2
+
3
+ export const crmFirstWinTrack: LearningJourneyTrackSpec = {
4
+ id: 'crm_first_win',
5
+ productId: 'crm-pipeline',
6
+ name: 'CRM First Win',
7
+ description:
8
+ 'Guide a new CRM user from empty pipeline to first closed-won deal.',
9
+ targetUserSegment: 'crm_adopter',
10
+ targetRole: 'sales',
11
+ totalXp: 135,
12
+ streakRule: { hoursWindow: 72, bonusXp: 25 },
13
+ completionRewards: { xpBonus: 25, badgeKey: 'crm_first_win' },
14
+ steps: [
15
+ {
16
+ id: 'create_pipeline',
17
+ title: 'Create pipeline & stages',
18
+ description: 'Create a pipeline with baseline stages.',
19
+ order: 1,
20
+ completion: {
21
+ eventName: 'pipeline.created',
22
+ sourceModule: '@lssm/example.crm-pipeline',
23
+ },
24
+ xpReward: 15,
25
+ metadata: { surface: 'pipeline' },
26
+ },
27
+ {
28
+ id: 'create_contact_and_company',
29
+ title: 'Create contact and company',
30
+ description: 'Add your first contact and associated company.',
31
+ order: 2,
32
+ completion: {
33
+ eventName: 'contact.created',
34
+ sourceModule: '@lssm/example.crm-pipeline',
35
+ },
36
+ xpReward: 20,
37
+ metadata: { surface: 'contacts' },
38
+ },
39
+ {
40
+ id: 'create_first_deal',
41
+ title: 'Log first deal',
42
+ description: 'Create your first deal in the pipeline.',
43
+ order: 3,
44
+ completion: {
45
+ eventName: 'deal.created',
46
+ sourceModule: '@lssm/example.crm-pipeline',
47
+ },
48
+ xpReward: 20,
49
+ metadata: { surface: 'deals' },
50
+ },
51
+ {
52
+ id: 'move_deal_in_pipeline',
53
+ title: 'Move a deal across stages',
54
+ description: 'Move a deal across at least three stages.',
55
+ order: 4,
56
+ completion: {
57
+ eventName: 'deal.moved',
58
+ sourceModule: '@lssm/example.crm-pipeline',
59
+ },
60
+ xpReward: 20,
61
+ metadata: { surface: 'deals' },
62
+ },
63
+ {
64
+ id: 'close_deal_won',
65
+ title: 'Close a deal as won',
66
+ description: 'Close a deal as won to hit first revenue.',
67
+ order: 5,
68
+ completion: {
69
+ eventName: 'deal.won',
70
+ sourceModule: '@lssm/example.crm-pipeline',
71
+ },
72
+ xpReward: 30,
73
+ metadata: { surface: 'deals' },
74
+ },
75
+ {
76
+ id: 'setup_follow_up',
77
+ title: 'Create follow-up task',
78
+ description:
79
+ 'Create a follow-up task and notification for a contact or deal.',
80
+ order: 6,
81
+ completion: {
82
+ eventName: 'task.completed',
83
+ sourceModule: '@lssm/example.crm-pipeline',
84
+ payloadFilter: { type: 'follow_up' },
85
+ },
86
+ xpReward: 30,
87
+ metadata: { surface: 'tasks' },
88
+ },
89
+ ],
90
+ metadata: {
91
+ surfacedIn: ['crm/dashboard', 'crm/pipeline'],
92
+ },
93
+ };
94
+
95
+ export const crmLearningTracks: LearningJourneyTrackSpec[] = [crmFirstWinTrack];
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "@lssm/tool.typescript/react-library.json",
3
+ "include": ["src"],
4
+ "exclude": ["node_modules"],
5
+ "compilerOptions": {
6
+ "rootDir": "src",
7
+ "outDir": "dist"
8
+ }
9
+ }