@contractspec/example.saas-boilerplate 3.7.5 → 3.7.7

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 (115) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/AGENTS.md +50 -27
  3. package/CHANGELOG.md +16 -0
  4. package/README.md +64 -144
  5. package/dist/billing/billing.event.js +1 -1
  6. package/dist/billing/index.d.ts +6 -6
  7. package/dist/billing/index.js +1 -1
  8. package/dist/browser/billing/billing.event.js +1 -1
  9. package/dist/browser/billing/index.js +1 -1
  10. package/dist/browser/index.js +931 -932
  11. package/dist/browser/project/index.js +209 -209
  12. package/dist/browser/project/project.event.js +1 -1
  13. package/dist/browser/ui/SaasDashboard.js +45 -45
  14. package/dist/browser/ui/SaasProjectList.js +7 -7
  15. package/dist/browser/ui/SaasSettingsPanel.js +12 -12
  16. package/dist/browser/ui/hooks/index.js +2 -2
  17. package/dist/browser/ui/hooks/useProjectList.js +1 -1
  18. package/dist/browser/ui/hooks/useProjectMutations.js +1 -1
  19. package/dist/browser/ui/index.js +483 -484
  20. package/dist/browser/ui/modals/CreateProjectModal.js +10 -10
  21. package/dist/browser/ui/modals/ProjectActionsModal.js +13 -13
  22. package/dist/browser/ui/modals/index.js +23 -23
  23. package/dist/browser/ui/renderers/index.js +112 -112
  24. package/dist/browser/ui/renderers/project-list.renderer.js +7 -7
  25. package/dist/handlers/index.d.ts +2 -2
  26. package/dist/index.d.ts +4 -4
  27. package/dist/index.js +931 -932
  28. package/dist/node/billing/billing.event.js +1 -1
  29. package/dist/node/billing/index.js +1 -1
  30. package/dist/node/index.js +931 -932
  31. package/dist/node/project/index.js +209 -209
  32. package/dist/node/project/project.event.js +1 -1
  33. package/dist/node/ui/SaasDashboard.js +45 -45
  34. package/dist/node/ui/SaasProjectList.js +7 -7
  35. package/dist/node/ui/SaasSettingsPanel.js +12 -12
  36. package/dist/node/ui/hooks/index.js +2 -2
  37. package/dist/node/ui/hooks/useProjectList.js +1 -1
  38. package/dist/node/ui/hooks/useProjectMutations.js +1 -1
  39. package/dist/node/ui/index.js +483 -484
  40. package/dist/node/ui/modals/CreateProjectModal.js +10 -10
  41. package/dist/node/ui/modals/ProjectActionsModal.js +13 -13
  42. package/dist/node/ui/modals/index.js +23 -23
  43. package/dist/node/ui/renderers/index.js +112 -112
  44. package/dist/node/ui/renderers/project-list.renderer.js +7 -7
  45. package/dist/presentations/index.d.ts +1 -1
  46. package/dist/project/index.d.ts +7 -7
  47. package/dist/project/index.js +209 -209
  48. package/dist/project/project.event.js +1 -1
  49. package/dist/settings/index.d.ts +1 -1
  50. package/dist/ui/SaasDashboard.js +45 -45
  51. package/dist/ui/SaasProjectList.js +7 -7
  52. package/dist/ui/SaasSettingsPanel.js +12 -12
  53. package/dist/ui/hooks/index.d.ts +2 -2
  54. package/dist/ui/hooks/index.js +2 -2
  55. package/dist/ui/hooks/useProjectList.d.ts +5 -0
  56. package/dist/ui/hooks/useProjectList.js +1 -1
  57. package/dist/ui/hooks/useProjectMutations.d.ts +8 -0
  58. package/dist/ui/hooks/useProjectMutations.js +1 -1
  59. package/dist/ui/index.d.ts +4 -4
  60. package/dist/ui/index.js +483 -484
  61. package/dist/ui/modals/CreateProjectModal.js +10 -10
  62. package/dist/ui/modals/ProjectActionsModal.js +13 -13
  63. package/dist/ui/modals/index.js +23 -23
  64. package/dist/ui/renderers/index.d.ts +1 -1
  65. package/dist/ui/renderers/index.js +112 -112
  66. package/dist/ui/renderers/project-list.renderer.d.ts +1 -1
  67. package/dist/ui/renderers/project-list.renderer.js +7 -7
  68. package/package.json +14 -14
  69. package/src/billing/billing.entity.ts +132 -132
  70. package/src/billing/billing.enum.ts +9 -9
  71. package/src/billing/billing.event.ts +71 -71
  72. package/src/billing/billing.handler.ts +87 -87
  73. package/src/billing/billing.operations.ts +158 -158
  74. package/src/billing/billing.presentation.ts +45 -45
  75. package/src/billing/billing.schema.ts +76 -76
  76. package/src/billing/index.ts +43 -48
  77. package/src/dashboard/dashboard.presentation.ts +45 -45
  78. package/src/dashboard/index.ts +2 -2
  79. package/src/docs/saas-boilerplate.docblock.ts +43 -43
  80. package/src/example.ts +32 -32
  81. package/src/handlers/index.ts +9 -9
  82. package/src/handlers/saas.handlers.ts +250 -249
  83. package/src/index.ts +40 -41
  84. package/src/presentations/index.ts +18 -20
  85. package/src/project/index.ts +45 -50
  86. package/src/project/project.entity.ts +68 -68
  87. package/src/project/project.enum.ts +8 -8
  88. package/src/project/project.event.ts +79 -79
  89. package/src/project/project.handler.ts +103 -103
  90. package/src/project/project.operations.ts +236 -236
  91. package/src/project/project.presentation.ts +46 -46
  92. package/src/project/project.schema.ts +90 -90
  93. package/src/saas-boilerplate.feature.ts +100 -100
  94. package/src/seeders/index.ts +20 -20
  95. package/src/settings/index.ts +2 -3
  96. package/src/settings/settings.entity.ts +65 -65
  97. package/src/settings/settings.enum.ts +4 -4
  98. package/src/shared/mock-data.ts +92 -92
  99. package/src/shared/overlay-types.ts +23 -23
  100. package/src/tests/operations.test-spec.ts +96 -96
  101. package/src/ui/SaasDashboard.tsx +270 -270
  102. package/src/ui/SaasProjectList.tsx +90 -90
  103. package/src/ui/SaasSettingsPanel.tsx +84 -84
  104. package/src/ui/hooks/index.ts +3 -3
  105. package/src/ui/hooks/useProjectList.ts +69 -68
  106. package/src/ui/hooks/useProjectMutations.ts +144 -143
  107. package/src/ui/index.ts +8 -12
  108. package/src/ui/modals/CreateProjectModal.tsx +154 -154
  109. package/src/ui/modals/ProjectActionsModal.tsx +321 -321
  110. package/src/ui/overlays/demo-overlays.ts +49 -49
  111. package/src/ui/renderers/index.ts +5 -4
  112. package/src/ui/renderers/project-list.markdown.ts +204 -204
  113. package/src/ui/renderers/project-list.renderer.tsx +14 -13
  114. package/tsconfig.json +7 -8
  115. package/tsdown.config.js +7 -3
@@ -1,133 +1,133 @@
1
1
  import { defineSchemaModel, ScalarTypeEnum } from '@contractspec/lib.schema';
2
2
  import {
3
- SubscriptionStatusSchemaEnum,
4
- FeatureAccessReasonEnum,
3
+ FeatureAccessReasonEnum,
4
+ SubscriptionStatusSchemaEnum,
5
5
  } from './billing.enum';
6
6
 
7
7
  /**
8
8
  * Organization subscription details schema.
9
9
  */
10
10
  export const SubscriptionModel = defineSchemaModel({
11
- name: 'Subscription',
12
- description: 'Organization subscription details',
13
- fields: {
14
- id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
15
- organizationId: {
16
- type: ScalarTypeEnum.String_unsecure(),
17
- isOptional: false,
18
- },
19
- planId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
20
- planName: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
21
- status: { type: SubscriptionStatusSchemaEnum, isOptional: false },
22
- currentPeriodStart: { type: ScalarTypeEnum.DateTime(), isOptional: false },
23
- currentPeriodEnd: { type: ScalarTypeEnum.DateTime(), isOptional: false },
24
- trialEndsAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
25
- cancelAtPeriodEnd: { type: ScalarTypeEnum.Boolean(), isOptional: false },
26
- },
11
+ name: 'Subscription',
12
+ description: 'Organization subscription details',
13
+ fields: {
14
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
15
+ organizationId: {
16
+ type: ScalarTypeEnum.String_unsecure(),
17
+ isOptional: false,
18
+ },
19
+ planId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
20
+ planName: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
21
+ status: { type: SubscriptionStatusSchemaEnum, isOptional: false },
22
+ currentPeriodStart: { type: ScalarTypeEnum.DateTime(), isOptional: false },
23
+ currentPeriodEnd: { type: ScalarTypeEnum.DateTime(), isOptional: false },
24
+ trialEndsAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
25
+ cancelAtPeriodEnd: { type: ScalarTypeEnum.Boolean(), isOptional: false },
26
+ },
27
27
  });
28
28
 
29
29
  /**
30
30
  * Usage summary for a feature schema.
31
31
  */
32
32
  export const UsageSummaryModel = defineSchemaModel({
33
- name: 'UsageSummary',
34
- description: 'Usage summary for a feature',
35
- fields: {
36
- feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
37
- used: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
38
- limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
39
- unit: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
40
- percentage: { type: ScalarTypeEnum.Float_unsecure(), isOptional: true },
41
- },
33
+ name: 'UsageSummary',
34
+ description: 'Usage summary for a feature',
35
+ fields: {
36
+ feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
37
+ used: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
38
+ limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
39
+ unit: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
40
+ percentage: { type: ScalarTypeEnum.Float_unsecure(), isOptional: true },
41
+ },
42
42
  });
43
43
 
44
44
  /**
45
45
  * Input for recording feature usage.
46
46
  */
47
47
  export const RecordUsageInputModel = defineSchemaModel({
48
- name: 'RecordUsageInput',
49
- description: 'Input for recording feature usage',
50
- fields: {
51
- feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
52
- quantity: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
53
- sourceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
54
- sourceType: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
55
- metadata: { type: ScalarTypeEnum.JSONObject(), isOptional: true },
56
- },
48
+ name: 'RecordUsageInput',
49
+ description: 'Input for recording feature usage',
50
+ fields: {
51
+ feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
52
+ quantity: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
53
+ sourceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
54
+ sourceType: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
55
+ metadata: { type: ScalarTypeEnum.JSONObject(), isOptional: true },
56
+ },
57
57
  });
58
58
 
59
59
  /**
60
60
  * Output for recording feature usage.
61
61
  */
62
62
  export const RecordUsageOutputModel = defineSchemaModel({
63
- name: 'RecordUsageOutput',
64
- description: 'Output for recording feature usage',
65
- fields: {
66
- recorded: { type: ScalarTypeEnum.Boolean(), isOptional: false },
67
- currentUsage: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
68
- limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
69
- limitReached: { type: ScalarTypeEnum.Boolean(), isOptional: false },
70
- },
63
+ name: 'RecordUsageOutput',
64
+ description: 'Output for recording feature usage',
65
+ fields: {
66
+ recorded: { type: ScalarTypeEnum.Boolean(), isOptional: false },
67
+ currentUsage: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
68
+ limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
69
+ limitReached: { type: ScalarTypeEnum.Boolean(), isOptional: false },
70
+ },
71
71
  });
72
72
 
73
73
  /**
74
74
  * Payload for usage.recorded event.
75
75
  */
76
76
  export const UsageRecordedPayloadModel = defineSchemaModel({
77
- name: 'UsageRecordedPayload',
78
- description: 'Payload for usage.recorded event',
79
- fields: {
80
- feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
81
- quantity: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
82
- },
77
+ name: 'UsageRecordedPayload',
78
+ description: 'Payload for usage.recorded event',
79
+ fields: {
80
+ feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
81
+ quantity: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
82
+ },
83
83
  });
84
84
 
85
85
  /**
86
86
  * Input for getting usage summary.
87
87
  */
88
88
  export const GetUsageSummaryInputModel = defineSchemaModel({
89
- name: 'GetUsageSummaryInput',
90
- description: 'Input for getting usage summary',
91
- fields: {
92
- billingPeriod: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
93
- },
89
+ name: 'GetUsageSummaryInput',
90
+ description: 'Input for getting usage summary',
91
+ fields: {
92
+ billingPeriod: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
93
+ },
94
94
  });
95
95
 
96
96
  /**
97
97
  * Output for usage summary.
98
98
  */
99
99
  export const GetUsageSummaryOutputModel = defineSchemaModel({
100
- name: 'GetUsageSummaryOutput',
101
- description: 'Output for usage summary',
102
- fields: {
103
- billingPeriod: {
104
- type: ScalarTypeEnum.String_unsecure(),
105
- isOptional: false,
106
- },
107
- usage: { type: UsageSummaryModel, isArray: true, isOptional: false },
108
- },
100
+ name: 'GetUsageSummaryOutput',
101
+ description: 'Output for usage summary',
102
+ fields: {
103
+ billingPeriod: {
104
+ type: ScalarTypeEnum.String_unsecure(),
105
+ isOptional: false,
106
+ },
107
+ usage: { type: UsageSummaryModel, isArray: true, isOptional: false },
108
+ },
109
109
  });
110
110
 
111
111
  /**
112
112
  * Input for checking feature access.
113
113
  */
114
114
  export const CheckFeatureAccessInputModel = defineSchemaModel({
115
- name: 'CheckFeatureAccessInput',
116
- description: 'Input for checking feature access',
117
- fields: {
118
- feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
119
- },
115
+ name: 'CheckFeatureAccessInput',
116
+ description: 'Input for checking feature access',
117
+ fields: {
118
+ feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
119
+ },
120
120
  });
121
121
 
122
122
  /**
123
123
  * Output for feature access check.
124
124
  */
125
125
  export const CheckFeatureAccessOutputModel = defineSchemaModel({
126
- name: 'CheckFeatureAccessOutput',
127
- description: 'Output for feature access check',
128
- fields: {
129
- hasAccess: { type: ScalarTypeEnum.Boolean(), isOptional: false },
130
- reason: { type: FeatureAccessReasonEnum, isOptional: true },
131
- upgradeUrl: { type: ScalarTypeEnum.URL(), isOptional: true },
132
- },
126
+ name: 'CheckFeatureAccessOutput',
127
+ description: 'Output for feature access check',
128
+ fields: {
129
+ hasAccess: { type: ScalarTypeEnum.Boolean(), isOptional: false },
130
+ reason: { type: FeatureAccessReasonEnum, isOptional: true },
131
+ upgradeUrl: { type: ScalarTypeEnum.URL(), isOptional: true },
132
+ },
133
133
  });
@@ -2,63 +2,58 @@
2
2
  * Billing domain - subscription, usage tracking, and feature access.
3
3
  */
4
4
 
5
+ // Entities
6
+ export {
7
+ BillingUsageEntity,
8
+ SubscriptionEntity,
9
+ SubscriptionStatusEnum,
10
+ UsageLimitEntity,
11
+ } from './billing.entity';
5
12
  // Enums
6
13
  export {
7
- SubscriptionStatusSchemaEnum,
8
- FeatureAccessReasonEnum,
14
+ FeatureAccessReasonEnum,
15
+ SubscriptionStatusSchemaEnum,
9
16
  } from './billing.enum';
10
-
11
- // Schema models
12
- export {
13
- SubscriptionModel,
14
- UsageSummaryModel,
15
- RecordUsageInputModel,
16
- RecordUsageOutputModel,
17
- UsageRecordedPayloadModel,
18
- GetUsageSummaryInputModel,
19
- GetUsageSummaryOutputModel,
20
- CheckFeatureAccessInputModel,
21
- CheckFeatureAccessOutputModel,
22
- } from './billing.schema';
23
-
24
- // Contracts
25
- export {
26
- GetSubscriptionContract,
27
- RecordUsageContract,
28
- GetUsageSummaryContract,
29
- CheckFeatureAccessContract,
30
- } from './billing.operations';
31
-
32
17
  // Events
33
18
  export {
34
- UsageRecordedEvent,
35
- UsageLimitReachedEvent,
36
- SubscriptionChangedEvent,
19
+ SubscriptionChangedEvent,
20
+ UsageLimitReachedEvent,
21
+ UsageRecordedEvent,
37
22
  } from './billing.event';
38
-
39
- // Entities
23
+ // Handlers
40
24
  export {
41
- SubscriptionStatusEnum,
42
- SubscriptionEntity,
43
- BillingUsageEntity,
44
- UsageLimitEntity,
45
- } from './billing.entity';
25
+ type CheckFeatureAccessInput,
26
+ type CheckFeatureAccessOutput,
27
+ mockCheckFeatureAccessHandler,
28
+ mockGetSubscriptionHandler,
29
+ mockGetUsageSummaryHandler,
30
+ mockRecordUsageHandler,
31
+ type RecordUsageInput,
32
+ type Subscription,
33
+ type UsageSummary,
34
+ } from './billing.handler';
35
+ // Contracts
36
+ export {
37
+ CheckFeatureAccessContract,
38
+ GetSubscriptionContract,
39
+ GetUsageSummaryContract,
40
+ RecordUsageContract,
41
+ } from './billing.operations';
46
42
 
47
43
  // Presentations
48
44
  export {
49
- SubscriptionPresentation,
50
- UsageDashboardPresentation,
45
+ SubscriptionPresentation,
46
+ UsageDashboardPresentation,
51
47
  } from './billing.presentation';
52
-
53
- // Handlers
48
+ // Schema models
54
49
  export {
55
- mockGetSubscriptionHandler,
56
- mockGetUsageSummaryHandler,
57
- mockRecordUsageHandler,
58
- mockCheckFeatureAccessHandler,
59
- type Subscription,
60
- type UsageSummary,
61
- type RecordUsageInput,
62
- type CheckFeatureAccessInput,
63
- type CheckFeatureAccessOutput,
64
- } from './billing.handler';
50
+ CheckFeatureAccessInputModel,
51
+ CheckFeatureAccessOutputModel,
52
+ GetUsageSummaryInputModel,
53
+ GetUsageSummaryOutputModel,
54
+ RecordUsageInputModel,
55
+ RecordUsageOutputModel,
56
+ SubscriptionModel,
57
+ UsageRecordedPayloadModel,
58
+ UsageSummaryModel,
59
+ } from './billing.schema';
@@ -1,59 +1,59 @@
1
1
  import {
2
- definePresentation,
3
- StabilityEnum,
2
+ definePresentation,
3
+ StabilityEnum,
4
4
  } from '@contractspec/lib.contracts-spec';
5
5
 
6
6
  /**
7
7
  * Main dashboard presentation for the SaaS application.
8
8
  */
9
9
  export const SaasDashboardPresentation = definePresentation({
10
- meta: {
11
- key: 'saas.dashboard',
12
- version: '1.0.0',
13
- title: 'SaaS Dashboard',
14
- description:
15
- 'Main SaaS dashboard with project overview, usage stats, and quick actions',
16
- domain: 'saas-boilerplate',
17
- owners: ['@saas-team'],
18
- tags: ['dashboard', 'overview'],
19
- stability: StabilityEnum.Beta,
20
- goal: 'Overview of SaaS activity and metrics',
21
- context: 'Main dashboard',
22
- },
23
- source: {
24
- type: 'component',
25
- framework: 'react',
26
- componentKey: 'SaasDashboard',
27
- },
28
- targets: ['react', 'markdown'],
29
- policy: {
30
- flags: ['saas.enabled'],
31
- },
10
+ meta: {
11
+ key: 'saas.dashboard',
12
+ version: '1.0.0',
13
+ title: 'SaaS Dashboard',
14
+ description:
15
+ 'Main SaaS dashboard with project overview, usage stats, and quick actions',
16
+ domain: 'saas-boilerplate',
17
+ owners: ['@saas-team'],
18
+ tags: ['dashboard', 'overview'],
19
+ stability: StabilityEnum.Beta,
20
+ goal: 'Overview of SaaS activity and metrics',
21
+ context: 'Main dashboard',
22
+ },
23
+ source: {
24
+ type: 'component',
25
+ framework: 'react',
26
+ componentKey: 'SaasDashboard',
27
+ },
28
+ targets: ['react', 'markdown'],
29
+ policy: {
30
+ flags: ['saas.enabled'],
31
+ },
32
32
  });
33
33
 
34
34
  /**
35
35
  * Settings panel presentation.
36
36
  */
37
37
  export const SettingsPanelPresentation = definePresentation({
38
- meta: {
39
- key: 'saas.settings',
40
- version: '1.0.0',
41
- title: 'Settings Panel',
42
- description: 'Organization and user settings panel',
43
- domain: 'saas-boilerplate',
44
- owners: ['@saas-team'],
45
- tags: ['settings', 'config'],
46
- stability: StabilityEnum.Beta,
47
- goal: 'Configure organization and user settings',
48
- context: 'Settings section',
49
- },
50
- source: {
51
- type: 'component',
52
- framework: 'react',
53
- componentKey: 'SettingsPanel',
54
- },
55
- targets: ['react'],
56
- policy: {
57
- flags: ['saas.enabled'],
58
- },
38
+ meta: {
39
+ key: 'saas.settings',
40
+ version: '1.0.0',
41
+ title: 'Settings Panel',
42
+ description: 'Organization and user settings panel',
43
+ domain: 'saas-boilerplate',
44
+ owners: ['@saas-team'],
45
+ tags: ['settings', 'config'],
46
+ stability: StabilityEnum.Beta,
47
+ goal: 'Configure organization and user settings',
48
+ context: 'Settings section',
49
+ },
50
+ source: {
51
+ type: 'component',
52
+ framework: 'react',
53
+ componentKey: 'SettingsPanel',
54
+ },
55
+ targets: ['react'],
56
+ policy: {
57
+ flags: ['saas.enabled'],
58
+ },
59
59
  });
@@ -3,6 +3,6 @@
3
3
  */
4
4
 
5
5
  export {
6
- SaasDashboardPresentation,
7
- SettingsPanelPresentation,
6
+ SaasDashboardPresentation,
7
+ SettingsPanelPresentation,
8
8
  } from './dashboard.presentation';
@@ -2,16 +2,16 @@ import type { DocBlock } from '@contractspec/lib.contracts-spec/docs';
2
2
  import { registerDocBlocks } from '@contractspec/lib.contracts-spec/docs';
3
3
 
4
4
  const saasBoilerplateDocBlocks: DocBlock[] = [
5
- {
6
- id: 'docs.examples.saas-boilerplate.goal',
7
- title: 'SaaS Boilerplate — Goal',
8
- summary:
9
- 'Multi-tenant SaaS foundation with orgs, members, projects, settings, and usage.',
10
- kind: 'goal',
11
- visibility: 'public',
12
- route: '/docs/examples/saas-boilerplate/goal',
13
- tags: ['saas', 'goal'],
14
- body: `## Why it matters
5
+ {
6
+ id: 'docs.examples.saas-boilerplate.goal',
7
+ title: 'SaaS Boilerplate — Goal',
8
+ summary:
9
+ 'Multi-tenant SaaS foundation with orgs, members, projects, settings, and usage.',
10
+ kind: 'goal',
11
+ visibility: 'public',
12
+ route: '/docs/examples/saas-boilerplate/goal',
13
+ tags: ['saas', 'goal'],
14
+ body: `## Why it matters
15
15
  - Provides a regenerable SaaS base: orgs, members, projects, settings, usage/billing.
16
16
  - Avoids drift across identity, settings, and usage capture.
17
17
 
@@ -22,16 +22,16 @@ const saasBoilerplateDocBlocks: DocBlock[] = [
22
22
  ## Success criteria
23
23
  - Spec changes to org/project/settings/usage regenerate UI/API/events cleanly.
24
24
  - Tenant isolation and RBAC stay enforced; usage data is captured with PII scopes.`,
25
- },
26
- {
27
- id: 'docs.examples.saas-boilerplate.usage',
28
- title: 'SaaS Boilerplate — Usage',
29
- summary: 'How to seed, extend, and regenerate the SaaS base.',
30
- kind: 'usage',
31
- visibility: 'public',
32
- route: '/docs/examples/saas-boilerplate/usage',
33
- tags: ['saas', 'usage'],
34
- body: `## Setup
25
+ },
26
+ {
27
+ id: 'docs.examples.saas-boilerplate.usage',
28
+ title: 'SaaS Boilerplate — Usage',
29
+ summary: 'How to seed, extend, and regenerate the SaaS base.',
30
+ kind: 'usage',
31
+ visibility: 'public',
32
+ route: '/docs/examples/saas-boilerplate/usage',
33
+ tags: ['saas', 'usage'],
34
+ body: `## Setup
35
35
  1) Seed (if available) or create orgs, members, and projects via UI.
36
36
  2) Configure Notifications for invites and project events; set policy.pii for sensitive fields.
37
37
 
@@ -44,17 +44,17 @@ const saasBoilerplateDocBlocks: DocBlock[] = [
44
44
  - Keep tenant/role context explicit in contracts and presentations.
45
45
  - Emit events for invites, project changes, and usage records; log in Audit Trail.
46
46
  - Redact sensitive user/org data in markdown/JSON outputs.`,
47
- },
48
- {
49
- id: 'docs.examples.saas-boilerplate.reference',
50
- title: 'SaaS Boilerplate — Reference',
51
- summary:
52
- 'Entities, contracts, events, and presentations for the SaaS starter.',
53
- kind: 'reference',
54
- visibility: 'public',
55
- route: '/docs/examples/saas-boilerplate',
56
- tags: ['saas', 'reference'],
57
- body: `## Entities
47
+ },
48
+ {
49
+ id: 'docs.examples.saas-boilerplate.reference',
50
+ title: 'SaaS Boilerplate — Reference',
51
+ summary:
52
+ 'Entities, contracts, events, and presentations for the SaaS starter.',
53
+ kind: 'reference',
54
+ visibility: 'public',
55
+ route: '/docs/examples/saas-boilerplate',
56
+ tags: ['saas', 'reference'],
57
+ body: `## Entities
58
58
  - Organization, Member, Role, Project, AppSettings, UserSettings, BillingUsage.
59
59
 
60
60
  ## Contracts
@@ -69,17 +69,17 @@ const saasBoilerplateDocBlocks: DocBlock[] = [
69
69
  ## Notes
70
70
  - Tenant isolation is mandatory; enforce via RBAC/policies.
71
71
  - Usage/Metering drives billing/limits; keep units explicit.`,
72
- },
73
- {
74
- id: 'docs.examples.saas-boilerplate.constraints',
75
- title: 'SaaS Boilerplate — Constraints & Safety',
76
- summary:
77
- 'Internal guardrails for tenancy, RBAC, usage metering, and regeneration.',
78
- kind: 'reference',
79
- visibility: 'internal',
80
- route: '/docs/examples/saas-boilerplate/constraints',
81
- tags: ['saas', 'constraints', 'internal'],
82
- body: `## Constraints
72
+ },
73
+ {
74
+ id: 'docs.examples.saas-boilerplate.constraints',
75
+ title: 'SaaS Boilerplate — Constraints & Safety',
76
+ summary:
77
+ 'Internal guardrails for tenancy, RBAC, usage metering, and regeneration.',
78
+ kind: 'reference',
79
+ visibility: 'internal',
80
+ route: '/docs/examples/saas-boilerplate/constraints',
81
+ tags: ['saas', 'constraints', 'internal'],
82
+ body: `## Constraints
83
83
  - Tenant isolation and RBAC must remain explicit in spec; no implicit defaults in code.
84
84
  - Events to emit: org.created, member.invited/accepted, project.created/updated, usage.recorded.
85
85
  - Regeneration must not change billing/usage semantics without spec diffs.
@@ -92,7 +92,7 @@ const saasBoilerplateDocBlocks: DocBlock[] = [
92
92
  - Add fixtures for usage recording and role changes.
93
93
  - Ensure Audit/Notifications remain wired for invites/project updates.
94
94
  - Use Feature Flags for new settings/billing fields; default safe/off.`,
95
- },
95
+ },
96
96
  ];
97
97
 
98
98
  registerDocBlocks(saasBoilerplateDocBlocks);
package/src/example.ts CHANGED
@@ -1,38 +1,38 @@
1
1
  import { defineExample } from '@contractspec/lib.contracts-spec';
2
2
 
3
3
  const example = defineExample({
4
- meta: {
5
- key: 'saas-boilerplate',
6
- version: '1.0.0',
7
- title: 'SaaS Boilerplate',
8
- description:
9
- 'Multi-tenant SaaS foundation with orgs, projects, settings, billing usage, and RBAC.',
10
- kind: 'template',
11
- visibility: 'public',
12
- stability: 'experimental',
13
- owners: ['@platform.core'],
14
- tags: ['saas', 'multi-tenant', 'billing', 'rbac'],
15
- },
16
- docs: {
17
- rootDocId: 'docs.examples.saas-boilerplate',
18
- },
19
- entrypoints: {
20
- packageName: '@contractspec/example.saas-boilerplate',
21
- feature: './feature',
22
- contracts: './contracts',
23
- presentations: './presentations',
24
- handlers: './handlers',
25
- docs: './docs',
26
- },
27
- surfaces: {
28
- templates: true,
29
- sandbox: {
30
- enabled: true,
31
- modes: ['playground', 'specs', 'builder', 'markdown', 'evolution'],
32
- },
33
- studio: { enabled: true, installable: true },
34
- mcp: { enabled: true },
35
- },
4
+ meta: {
5
+ key: 'saas-boilerplate',
6
+ version: '1.0.0',
7
+ title: 'SaaS Boilerplate',
8
+ description:
9
+ 'Multi-tenant SaaS foundation with orgs, projects, settings, billing usage, and RBAC.',
10
+ kind: 'template',
11
+ visibility: 'public',
12
+ stability: 'experimental',
13
+ owners: ['@platform.core'],
14
+ tags: ['saas', 'multi-tenant', 'billing', 'rbac'],
15
+ },
16
+ docs: {
17
+ rootDocId: 'docs.examples.saas-boilerplate',
18
+ },
19
+ entrypoints: {
20
+ packageName: '@contractspec/example.saas-boilerplate',
21
+ feature: './feature',
22
+ contracts: './contracts',
23
+ presentations: './presentations',
24
+ handlers: './handlers',
25
+ docs: './docs',
26
+ },
27
+ surfaces: {
28
+ templates: true,
29
+ sandbox: {
30
+ enabled: true,
31
+ modes: ['playground', 'specs', 'builder', 'markdown', 'evolution'],
32
+ },
33
+ studio: { enabled: true, installable: true },
34
+ mcp: { enabled: true },
35
+ },
36
36
  });
37
37
 
38
38
  export default example;
@@ -4,19 +4,19 @@
4
4
 
5
5
  // Billing handlers
6
6
  export {
7
- mockGetSubscriptionHandler,
8
- mockRecordUsageHandler,
9
- mockGetUsageSummaryHandler,
10
- mockCheckFeatureAccessHandler,
7
+ mockCheckFeatureAccessHandler,
8
+ mockGetSubscriptionHandler,
9
+ mockGetUsageSummaryHandler,
10
+ mockRecordUsageHandler,
11
11
  } from '../billing/billing.handler';
12
12
 
13
13
  // Project handlers
14
14
  export {
15
- mockCreateProjectHandler,
16
- mockGetProjectHandler,
17
- mockListProjectsHandler,
18
- mockUpdateProjectHandler,
19
- mockDeleteProjectHandler,
15
+ mockCreateProjectHandler,
16
+ mockDeleteProjectHandler,
17
+ mockGetProjectHandler,
18
+ mockListProjectsHandler,
19
+ mockUpdateProjectHandler,
20
20
  } from '../project/project.handler';
21
21
 
22
22
  // Runtime handlers (PGLite)