@contractspec/example.saas-boilerplate 3.8.9 → 3.8.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.
Files changed (156) hide show
  1. package/.turbo/turbo-build.log +156 -156
  2. package/CHANGELOG.md +20 -0
  3. package/dist/billing/billing.entity.js +1 -113
  4. package/dist/billing/billing.enum.js +1 -19
  5. package/dist/billing/billing.event.js +1 -90
  6. package/dist/billing/billing.handler.js +1 -148
  7. package/dist/billing/billing.operations.js +1 -278
  8. package/dist/billing/billing.presentation.js +1 -55
  9. package/dist/billing/billing.schema.js +1 -121
  10. package/dist/billing/index.js +1 -691
  11. package/dist/browser/billing/billing.entity.js +1 -113
  12. package/dist/browser/billing/billing.enum.js +1 -19
  13. package/dist/browser/billing/billing.event.js +1 -90
  14. package/dist/browser/billing/billing.handler.js +1 -148
  15. package/dist/browser/billing/billing.operations.js +1 -278
  16. package/dist/browser/billing/billing.presentation.js +1 -55
  17. package/dist/browser/billing/billing.schema.js +1 -121
  18. package/dist/browser/billing/index.js +1 -691
  19. package/dist/browser/dashboard/dashboard.presentation.js +1 -55
  20. package/dist/browser/dashboard/index.js +1 -55
  21. package/dist/browser/docs/index.js +5 -49
  22. package/dist/browser/docs/saas-boilerplate.docblock.js +5 -49
  23. package/dist/browser/example.js +1 -39
  24. package/dist/browser/handlers/index.js +2 -358
  25. package/dist/browser/handlers/saas.handlers.js +2 -134
  26. package/dist/browser/index.js +9 -3591
  27. package/dist/browser/presentations/index.js +1 -299
  28. package/dist/browser/project/index.js +1 -793
  29. package/dist/browser/project/project.entity.js +1 -77
  30. package/dist/browser/project/project.enum.js +1 -18
  31. package/dist/browser/project/project.event.js +1 -103
  32. package/dist/browser/project/project.handler.js +1 -178
  33. package/dist/browser/project/project.operations.js +1 -372
  34. package/dist/browser/project/project.presentation.js +1 -180
  35. package/dist/browser/project/project.schema.js +1 -134
  36. package/dist/browser/saas-boilerplate.feature.js +1 -304
  37. package/dist/browser/seeders/index.js +2 -20
  38. package/dist/browser/settings/index.js +1 -75
  39. package/dist/browser/settings/settings.entity.js +1 -74
  40. package/dist/browser/settings/settings.enum.js +1 -11
  41. package/dist/browser/shared/mock-data.js +1 -104
  42. package/dist/browser/tests/operations.test-spec.js +1 -112
  43. package/dist/browser/ui/SaasDashboard.js +1 -1239
  44. package/dist/browser/ui/SaasDashboard.visualizations.js +1 -249
  45. package/dist/browser/ui/SaasProjectList.js +1 -162
  46. package/dist/browser/ui/SaasSettingsPanel.js +1 -145
  47. package/dist/browser/ui/hooks/index.js +1 -159
  48. package/dist/browser/ui/hooks/useProjectList.js +1 -66
  49. package/dist/browser/ui/hooks/useProjectMutations.js +1 -91
  50. package/dist/browser/ui/index.js +5 -2077
  51. package/dist/browser/ui/modals/CreateProjectModal.js +1 -153
  52. package/dist/browser/ui/modals/ProjectActionsModal.js +1 -335
  53. package/dist/browser/ui/modals/index.js +1 -487
  54. package/dist/browser/ui/overlays/demo-overlays.js +1 -61
  55. package/dist/browser/ui/overlays/index.js +1 -61
  56. package/dist/browser/ui/renderers/index.js +5 -901
  57. package/dist/browser/ui/renderers/project-list.markdown.js +5 -725
  58. package/dist/browser/ui/renderers/project-list.renderer.js +1 -177
  59. package/dist/browser/visualizations/catalog.js +1 -155
  60. package/dist/browser/visualizations/index.js +1 -217
  61. package/dist/browser/visualizations/selectors.js +1 -210
  62. package/dist/dashboard/dashboard.presentation.js +1 -55
  63. package/dist/dashboard/index.js +1 -55
  64. package/dist/docs/index.js +5 -49
  65. package/dist/docs/saas-boilerplate.docblock.js +5 -49
  66. package/dist/example.js +1 -39
  67. package/dist/handlers/index.js +2 -358
  68. package/dist/handlers/saas.handlers.js +2 -134
  69. package/dist/index.js +9 -3591
  70. package/dist/node/billing/billing.entity.js +1 -113
  71. package/dist/node/billing/billing.enum.js +1 -19
  72. package/dist/node/billing/billing.event.js +1 -90
  73. package/dist/node/billing/billing.handler.js +1 -148
  74. package/dist/node/billing/billing.operations.js +1 -278
  75. package/dist/node/billing/billing.presentation.js +1 -55
  76. package/dist/node/billing/billing.schema.js +1 -121
  77. package/dist/node/billing/index.js +1 -691
  78. package/dist/node/dashboard/dashboard.presentation.js +1 -55
  79. package/dist/node/dashboard/index.js +1 -55
  80. package/dist/node/docs/index.js +5 -49
  81. package/dist/node/docs/saas-boilerplate.docblock.js +5 -49
  82. package/dist/node/example.js +1 -39
  83. package/dist/node/handlers/index.js +2 -358
  84. package/dist/node/handlers/saas.handlers.js +2 -134
  85. package/dist/node/index.js +9 -3591
  86. package/dist/node/presentations/index.js +1 -299
  87. package/dist/node/project/index.js +1 -793
  88. package/dist/node/project/project.entity.js +1 -77
  89. package/dist/node/project/project.enum.js +1 -18
  90. package/dist/node/project/project.event.js +1 -103
  91. package/dist/node/project/project.handler.js +1 -178
  92. package/dist/node/project/project.operations.js +1 -372
  93. package/dist/node/project/project.presentation.js +1 -180
  94. package/dist/node/project/project.schema.js +1 -134
  95. package/dist/node/saas-boilerplate.feature.js +1 -304
  96. package/dist/node/seeders/index.js +2 -20
  97. package/dist/node/settings/index.js +1 -75
  98. package/dist/node/settings/settings.entity.js +1 -74
  99. package/dist/node/settings/settings.enum.js +1 -11
  100. package/dist/node/shared/mock-data.js +1 -104
  101. package/dist/node/tests/operations.test-spec.js +1 -112
  102. package/dist/node/ui/SaasDashboard.js +1 -1239
  103. package/dist/node/ui/SaasDashboard.visualizations.js +1 -249
  104. package/dist/node/ui/SaasProjectList.js +1 -162
  105. package/dist/node/ui/SaasSettingsPanel.js +1 -145
  106. package/dist/node/ui/hooks/index.js +1 -159
  107. package/dist/node/ui/hooks/useProjectList.js +1 -66
  108. package/dist/node/ui/hooks/useProjectMutations.js +1 -91
  109. package/dist/node/ui/index.js +5 -2077
  110. package/dist/node/ui/modals/CreateProjectModal.js +1 -153
  111. package/dist/node/ui/modals/ProjectActionsModal.js +1 -335
  112. package/dist/node/ui/modals/index.js +1 -487
  113. package/dist/node/ui/overlays/demo-overlays.js +1 -61
  114. package/dist/node/ui/overlays/index.js +1 -61
  115. package/dist/node/ui/renderers/index.js +5 -901
  116. package/dist/node/ui/renderers/project-list.markdown.js +5 -725
  117. package/dist/node/ui/renderers/project-list.renderer.js +1 -177
  118. package/dist/node/visualizations/catalog.js +1 -155
  119. package/dist/node/visualizations/index.js +1 -217
  120. package/dist/node/visualizations/selectors.js +1 -210
  121. package/dist/presentations/index.js +1 -299
  122. package/dist/project/index.js +1 -793
  123. package/dist/project/project.entity.js +1 -77
  124. package/dist/project/project.enum.js +1 -18
  125. package/dist/project/project.event.js +1 -103
  126. package/dist/project/project.handler.js +1 -178
  127. package/dist/project/project.operations.js +1 -372
  128. package/dist/project/project.presentation.js +1 -180
  129. package/dist/project/project.schema.js +1 -134
  130. package/dist/saas-boilerplate.feature.js +1 -304
  131. package/dist/seeders/index.js +2 -20
  132. package/dist/settings/index.js +1 -75
  133. package/dist/settings/settings.entity.js +1 -74
  134. package/dist/settings/settings.enum.js +1 -11
  135. package/dist/shared/mock-data.js +1 -104
  136. package/dist/tests/operations.test-spec.js +1 -112
  137. package/dist/ui/SaasDashboard.js +1 -1239
  138. package/dist/ui/SaasDashboard.visualizations.js +1 -249
  139. package/dist/ui/SaasProjectList.js +1 -162
  140. package/dist/ui/SaasSettingsPanel.js +1 -145
  141. package/dist/ui/hooks/index.js +1 -159
  142. package/dist/ui/hooks/useProjectList.js +1 -66
  143. package/dist/ui/hooks/useProjectMutations.js +1 -91
  144. package/dist/ui/index.js +5 -2077
  145. package/dist/ui/modals/CreateProjectModal.js +1 -153
  146. package/dist/ui/modals/ProjectActionsModal.js +1 -335
  147. package/dist/ui/modals/index.js +1 -487
  148. package/dist/ui/overlays/demo-overlays.js +1 -61
  149. package/dist/ui/overlays/index.js +1 -61
  150. package/dist/ui/renderers/index.js +5 -901
  151. package/dist/ui/renderers/project-list.markdown.js +5 -725
  152. package/dist/ui/renderers/project-list.renderer.js +1 -177
  153. package/dist/visualizations/catalog.js +1 -155
  154. package/dist/visualizations/index.js +1 -217
  155. package/dist/visualizations/selectors.js +1 -210
  156. package/package.json +12 -12
@@ -1,134 +1 @@
1
- // src/project/project.enum.ts
2
- import { defineEnum } from "@contractspec/lib.schema";
3
- var ProjectStatusSchemaEnum = defineEnum("ProjectStatus", [
4
- "DRAFT",
5
- "ACTIVE",
6
- "ARCHIVED",
7
- "DELETED"
8
- ]);
9
- var ProjectStatusFilterEnum = defineEnum("ProjectStatusFilter", [
10
- "DRAFT",
11
- "ACTIVE",
12
- "ARCHIVED",
13
- "all"
14
- ]);
15
-
16
- // src/project/project.schema.ts
17
- import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
18
- var ProjectModel = defineSchemaModel({
19
- name: "Project",
20
- description: "A project within an organization",
21
- fields: {
22
- id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
23
- name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
24
- description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
25
- slug: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
26
- organizationId: {
27
- type: ScalarTypeEnum.String_unsecure(),
28
- isOptional: false
29
- },
30
- createdBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
31
- status: { type: ProjectStatusSchemaEnum, isOptional: false },
32
- isPublic: { type: ScalarTypeEnum.Boolean(), isOptional: false },
33
- tags: {
34
- type: ScalarTypeEnum.String_unsecure(),
35
- isArray: true,
36
- isOptional: false
37
- },
38
- createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
39
- updatedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
40
- }
41
- });
42
- var CreateProjectInputModel = defineSchemaModel({
43
- name: "CreateProjectInput",
44
- description: "Input for creating a project",
45
- fields: {
46
- name: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
47
- description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
48
- slug: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
49
- isPublic: { type: ScalarTypeEnum.Boolean(), isOptional: true },
50
- tags: {
51
- type: ScalarTypeEnum.String_unsecure(),
52
- isArray: true,
53
- isOptional: true
54
- }
55
- }
56
- });
57
- var UpdateProjectInputModel = defineSchemaModel({
58
- name: "UpdateProjectInput",
59
- description: "Input for updating a project",
60
- fields: {
61
- projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
62
- name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
63
- description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
64
- slug: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
65
- isPublic: { type: ScalarTypeEnum.Boolean(), isOptional: true },
66
- tags: {
67
- type: ScalarTypeEnum.String_unsecure(),
68
- isArray: true,
69
- isOptional: true
70
- },
71
- status: { type: ProjectStatusSchemaEnum, isOptional: true }
72
- }
73
- });
74
- var GetProjectInputModel = defineSchemaModel({
75
- name: "GetProjectInput",
76
- fields: {
77
- projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
78
- }
79
- });
80
- var DeleteProjectInputModel = defineSchemaModel({
81
- name: "DeleteProjectInput",
82
- fields: {
83
- projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
84
- }
85
- });
86
- var DeleteProjectOutputModel = defineSchemaModel({
87
- name: "DeleteProjectOutput",
88
- fields: {
89
- success: { type: ScalarTypeEnum.Boolean(), isOptional: false }
90
- }
91
- });
92
- var ProjectDeletedPayloadModel = defineSchemaModel({
93
- name: "ProjectDeletedPayload",
94
- fields: {
95
- projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
96
- }
97
- });
98
- var ListProjectsInputModel = defineSchemaModel({
99
- name: "ListProjectsInput",
100
- description: "Input for listing projects",
101
- fields: {
102
- status: { type: ProjectStatusFilterEnum, isOptional: true },
103
- search: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
104
- limit: {
105
- type: ScalarTypeEnum.Int_unsecure(),
106
- isOptional: true,
107
- defaultValue: 20
108
- },
109
- offset: {
110
- type: ScalarTypeEnum.Int_unsecure(),
111
- isOptional: true,
112
- defaultValue: 0
113
- }
114
- }
115
- });
116
- var ListProjectsOutputModel = defineSchemaModel({
117
- name: "ListProjectsOutput",
118
- description: "Output for listing projects",
119
- fields: {
120
- projects: { type: ProjectModel, isArray: true, isOptional: false },
121
- total: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
122
- }
123
- });
124
- export {
125
- UpdateProjectInputModel,
126
- ProjectModel,
127
- ProjectDeletedPayloadModel,
128
- ListProjectsOutputModel,
129
- ListProjectsInputModel,
130
- GetProjectInputModel,
131
- DeleteProjectOutputModel,
132
- DeleteProjectInputModel,
133
- CreateProjectInputModel
134
- };
1
+ import{defineEnum as w}from"@contractspec/lib.schema";var v=w("ProjectStatus",["DRAFT","ACTIVE","ARCHIVED","DELETED"]),x=w("ProjectStatusFilter",["DRAFT","ACTIVE","ARCHIVED","all"]);import{defineSchemaModel as q,ScalarTypeEnum as k}from"@contractspec/lib.schema";var z=q({name:"Project",description:"A project within an organization",fields:{id:{type:k.String_unsecure(),isOptional:!1},name:{type:k.String_unsecure(),isOptional:!1},description:{type:k.String_unsecure(),isOptional:!0},slug:{type:k.String_unsecure(),isOptional:!0},organizationId:{type:k.String_unsecure(),isOptional:!1},createdBy:{type:k.String_unsecure(),isOptional:!1},status:{type:v,isOptional:!1},isPublic:{type:k.Boolean(),isOptional:!1},tags:{type:k.String_unsecure(),isArray:!0,isOptional:!1},createdAt:{type:k.DateTime(),isOptional:!1},updatedAt:{type:k.DateTime(),isOptional:!1}}}),G=q({name:"CreateProjectInput",description:"Input for creating a project",fields:{name:{type:k.NonEmptyString(),isOptional:!1},description:{type:k.String_unsecure(),isOptional:!0},slug:{type:k.String_unsecure(),isOptional:!0},isPublic:{type:k.Boolean(),isOptional:!0},tags:{type:k.String_unsecure(),isArray:!0,isOptional:!0}}}),H=q({name:"UpdateProjectInput",description:"Input for updating a project",fields:{projectId:{type:k.String_unsecure(),isOptional:!1},name:{type:k.String_unsecure(),isOptional:!0},description:{type:k.String_unsecure(),isOptional:!0},slug:{type:k.String_unsecure(),isOptional:!0},isPublic:{type:k.Boolean(),isOptional:!0},tags:{type:k.String_unsecure(),isArray:!0,isOptional:!0},status:{type:v,isOptional:!0}}}),I=q({name:"GetProjectInput",fields:{projectId:{type:k.String_unsecure(),isOptional:!1}}}),J=q({name:"DeleteProjectInput",fields:{projectId:{type:k.String_unsecure(),isOptional:!1}}}),K=q({name:"DeleteProjectOutput",fields:{success:{type:k.Boolean(),isOptional:!1}}}),L=q({name:"ProjectDeletedPayload",fields:{projectId:{type:k.String_unsecure(),isOptional:!1}}}),N=q({name:"ListProjectsInput",description:"Input for listing projects",fields:{status:{type:x,isOptional:!0},search:{type:k.String_unsecure(),isOptional:!0},limit:{type:k.Int_unsecure(),isOptional:!0,defaultValue:20},offset:{type:k.Int_unsecure(),isOptional:!0,defaultValue:0}}}),Q=q({name:"ListProjectsOutput",description:"Output for listing projects",fields:{projects:{type:z,isArray:!0,isOptional:!1},total:{type:k.Int_unsecure(),isOptional:!1}}});export{H as UpdateProjectInputModel,z as ProjectModel,L as ProjectDeletedPayloadModel,Q as ListProjectsOutputModel,N as ListProjectsInputModel,I as GetProjectInputModel,K as DeleteProjectOutputModel,J as DeleteProjectInputModel,G as CreateProjectInputModel};
@@ -1,304 +1 @@
1
- // src/visualizations/catalog.ts
2
- import {
3
- defineVisualization,
4
- VisualizationRegistry
5
- } from "@contractspec/lib.contracts-spec/visualizations";
6
- var PROJECT_LIST_REF = {
7
- key: "saas.project.list",
8
- version: "1.0.0"
9
- };
10
- var META = {
11
- version: "1.0.0",
12
- domain: "saas",
13
- stability: "experimental",
14
- owners: ["@example.saas-boilerplate"],
15
- tags: ["saas", "visualization", "projects"]
16
- };
17
- var SaasProjectUsageVisualization = defineVisualization({
18
- meta: {
19
- ...META,
20
- key: "saas-boilerplate.visualization.project-usage",
21
- title: "Project Capacity",
22
- description: "Current project count against the current plan limit.",
23
- goal: "Show usage against the active plan allowance.",
24
- context: "SaaS account overview."
25
- },
26
- source: { primary: PROJECT_LIST_REF, resultPath: "data" },
27
- visualization: {
28
- kind: "metric",
29
- measure: "totalProjects",
30
- comparisonMeasure: "projectLimit",
31
- measures: [
32
- {
33
- key: "totalProjects",
34
- label: "Projects",
35
- dataPath: "totalProjects",
36
- format: "number"
37
- },
38
- {
39
- key: "projectLimit",
40
- label: "Plan Limit",
41
- dataPath: "projectLimit",
42
- format: "number"
43
- }
44
- ],
45
- table: { caption: "Current project count and plan limit." }
46
- }
47
- });
48
- var SaasProjectStatusVisualization = defineVisualization({
49
- meta: {
50
- ...META,
51
- key: "saas-boilerplate.visualization.project-status",
52
- title: "Project Status",
53
- description: "Distribution of project states.",
54
- goal: "Show the mix of active, draft, and archived projects.",
55
- context: "Project portfolio overview."
56
- },
57
- source: { primary: PROJECT_LIST_REF, resultPath: "data" },
58
- visualization: {
59
- kind: "pie",
60
- nameDimension: "status",
61
- valueMeasure: "projects",
62
- dimensions: [
63
- { key: "status", label: "Status", dataPath: "status", type: "category" }
64
- ],
65
- measures: [
66
- {
67
- key: "projects",
68
- label: "Projects",
69
- dataPath: "projects",
70
- format: "number"
71
- }
72
- ],
73
- table: { caption: "Project counts by status." }
74
- }
75
- });
76
- var SaasProjectTierVisualization = defineVisualization({
77
- meta: {
78
- ...META,
79
- key: "saas-boilerplate.visualization.project-tiers",
80
- title: "Tier Comparison",
81
- description: "Distribution of projects across tiers.",
82
- goal: "Compare how the current portfolio is distributed by tier.",
83
- context: "Plan and packaging overview."
84
- },
85
- source: { primary: PROJECT_LIST_REF, resultPath: "data" },
86
- visualization: {
87
- kind: "cartesian",
88
- variant: "bar",
89
- xDimension: "tier",
90
- yMeasures: ["projects"],
91
- dimensions: [
92
- { key: "tier", label: "Tier", dataPath: "tier", type: "category" }
93
- ],
94
- measures: [
95
- {
96
- key: "projects",
97
- label: "Projects",
98
- dataPath: "projects",
99
- format: "number",
100
- color: "#1d4ed8"
101
- }
102
- ],
103
- table: { caption: "Project counts by tier." }
104
- }
105
- });
106
- var SaasProjectActivityVisualization = defineVisualization({
107
- meta: {
108
- ...META,
109
- key: "saas-boilerplate.visualization.project-activity",
110
- title: "Recent Project Activity",
111
- description: "Daily project creation activity.",
112
- goal: "Show recent project activity over time.",
113
- context: "Project portfolio trend view."
114
- },
115
- source: { primary: PROJECT_LIST_REF, resultPath: "data" },
116
- visualization: {
117
- kind: "cartesian",
118
- variant: "line",
119
- xDimension: "day",
120
- yMeasures: ["projects"],
121
- dimensions: [{ key: "day", label: "Day", dataPath: "day", type: "time" }],
122
- measures: [
123
- {
124
- key: "projects",
125
- label: "Projects",
126
- dataPath: "projects",
127
- format: "number",
128
- color: "#0f766e"
129
- }
130
- ],
131
- table: { caption: "Daily project creation counts." }
132
- }
133
- });
134
- var SaasVisualizationSpecs = [
135
- SaasProjectUsageVisualization,
136
- SaasProjectStatusVisualization,
137
- SaasProjectTierVisualization,
138
- SaasProjectActivityVisualization
139
- ];
140
- var SaasVisualizationRegistry = new VisualizationRegistry([
141
- ...SaasVisualizationSpecs
142
- ]);
143
- var SaasVisualizationRefs = SaasVisualizationSpecs.map((spec) => ({
144
- key: spec.meta.key,
145
- version: spec.meta.version
146
- }));
147
-
148
- // src/visualizations/selectors.ts
149
- function toDayKey(value) {
150
- const date = value instanceof Date ? value : new Date(value);
151
- return date.toISOString().slice(0, 10);
152
- }
153
- function createSaasVisualizationItems(projects, projectLimit = 10) {
154
- const statusCounts = new Map;
155
- const tierCounts = new Map;
156
- const activityCounts = new Map;
157
- for (const project of projects) {
158
- statusCounts.set(project.status, (statusCounts.get(project.status) ?? 0) + 1);
159
- tierCounts.set(project.tier, (tierCounts.get(project.tier) ?? 0) + 1);
160
- const day = toDayKey(project.createdAt);
161
- activityCounts.set(day, (activityCounts.get(day) ?? 0) + 1);
162
- }
163
- return [
164
- {
165
- key: "saas-capacity",
166
- spec: SaasProjectUsageVisualization,
167
- data: { data: [{ totalProjects: projects.length, projectLimit }] },
168
- title: "Project Capacity",
169
- description: "Current project count compared to the active limit.",
170
- height: 220
171
- },
172
- {
173
- key: "saas-status",
174
- spec: SaasProjectStatusVisualization,
175
- data: {
176
- data: Array.from(statusCounts.entries()).map(([status, count]) => ({
177
- status,
178
- projects: count
179
- }))
180
- },
181
- title: "Project Status",
182
- description: "Status mix across the current project portfolio.",
183
- height: 260
184
- },
185
- {
186
- key: "saas-tier",
187
- spec: SaasProjectTierVisualization,
188
- data: {
189
- data: Array.from(tierCounts.entries()).map(([tier, count]) => ({
190
- tier,
191
- projects: count
192
- }))
193
- },
194
- title: "Tier Comparison",
195
- description: "How projects are distributed across tiers."
196
- },
197
- {
198
- key: "saas-activity",
199
- spec: SaasProjectActivityVisualization,
200
- data: {
201
- data: Array.from(activityCounts.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([day, count]) => ({ day, projects: count }))
202
- },
203
- title: "Recent Project Activity",
204
- description: "Daily project creation activity."
205
- }
206
- ];
207
- }
208
- // src/saas-boilerplate.feature.ts
209
- import { defineFeature } from "@contractspec/lib.contracts-spec";
210
- var SaasBoilerplateFeature = defineFeature({
211
- meta: {
212
- key: "saas-boilerplate",
213
- title: "SaaS Boilerplate",
214
- description: "SaaS application foundation with projects, billing, and settings",
215
- domain: "saas",
216
- owners: ["@saas-team"],
217
- tags: ["saas", "projects", "billing"],
218
- stability: "experimental",
219
- version: "1.0.0"
220
- },
221
- operations: [
222
- { key: "saas.project.create", version: "1.0.0" },
223
- { key: "saas.project.get", version: "1.0.0" },
224
- { key: "saas.project.update", version: "1.0.0" },
225
- { key: "saas.project.delete", version: "1.0.0" },
226
- { key: "saas.project.list", version: "1.0.0" },
227
- { key: "saas.billing.subscription.get", version: "1.0.0" },
228
- { key: "saas.billing.usage.record", version: "1.0.0" },
229
- { key: "saas.billing.usage.summary", version: "1.0.0" },
230
- { key: "saas.billing.feature.check", version: "1.0.0" }
231
- ],
232
- events: [
233
- { key: "project.created", version: "1.0.0" },
234
- { key: "project.updated", version: "1.0.0" },
235
- { key: "project.deleted", version: "1.0.0" },
236
- { key: "project.archived", version: "1.0.0" },
237
- { key: "billing.usage.recorded", version: "1.0.0" },
238
- { key: "billing.subscription.changed", version: "1.0.0" },
239
- { key: "billing.limit.reached", version: "1.0.0" }
240
- ],
241
- presentations: [
242
- { key: "saas.dashboard", version: "1.0.0" },
243
- { key: "saas.project.list", version: "1.0.0" },
244
- { key: "saas.project.detail", version: "1.0.0" },
245
- { key: "saas.billing.subscription", version: "1.0.0" },
246
- { key: "saas.billing.usage", version: "1.0.0" },
247
- { key: "saas.settings", version: "1.0.0" }
248
- ],
249
- opToPresentation: [
250
- {
251
- op: { key: "saas.project.list", version: "1.0.0" },
252
- pres: { key: "saas.project.list", version: "1.0.0" }
253
- },
254
- {
255
- op: { key: "saas.project.get", version: "1.0.0" },
256
- pres: { key: "saas.project.detail", version: "1.0.0" }
257
- },
258
- {
259
- op: { key: "saas.billing.subscription.get", version: "1.0.0" },
260
- pres: { key: "saas.billing.subscription", version: "1.0.0" }
261
- },
262
- {
263
- op: { key: "saas.billing.usage.summary", version: "1.0.0" },
264
- pres: { key: "saas.billing.usage", version: "1.0.0" }
265
- }
266
- ],
267
- presentationsTargets: [
268
- { key: "saas.dashboard", version: "1.0.0", targets: ["react", "markdown"] },
269
- {
270
- key: "saas.project.list",
271
- version: "1.0.0",
272
- targets: ["react", "markdown", "application/json"]
273
- },
274
- {
275
- key: "saas.billing.subscription",
276
- version: "1.0.0",
277
- targets: ["react", "markdown"]
278
- },
279
- {
280
- key: "saas.billing.usage",
281
- version: "1.0.0",
282
- targets: ["react", "markdown"]
283
- }
284
- ],
285
- visualizations: SaasVisualizationRefs,
286
- capabilities: {
287
- requires: [
288
- { key: "identity", version: "1.0.0" },
289
- { key: "audit-trail", version: "1.0.0" },
290
- { key: "notifications", version: "1.0.0" }
291
- ]
292
- },
293
- telemetry: [{ key: "saas-boilerplate.telemetry", version: "1.0.0" }],
294
- jobs: [{ key: "saas-boilerplate.job.usage-recording", version: "1.0.0" }],
295
- docs: [
296
- "docs.examples.saas-boilerplate.goal",
297
- "docs.examples.saas-boilerplate.usage",
298
- "docs.examples.saas-boilerplate.reference",
299
- "docs.examples.saas-boilerplate.constraints"
300
- ]
301
- });
302
- export {
303
- SaasBoilerplateFeature
304
- };
1
+ import{defineVisualization as q,VisualizationRegistry as D}from"@contractspec/lib.contracts-spec/visualizations";var w={key:"saas.project.list",version:"1.0.0"},B={version:"1.0.0",domain:"saas",stability:"experimental",owners:["@example.saas-boilerplate"],tags:["saas","visualization","projects"]},Q=q({meta:{...B,key:"saas-boilerplate.visualization.project-usage",title:"Project Capacity",description:"Current project count against the current plan limit.",goal:"Show usage against the active plan allowance.",context:"SaaS account overview."},source:{primary:w,resultPath:"data"},visualization:{kind:"metric",measure:"totalProjects",comparisonMeasure:"projectLimit",measures:[{key:"totalProjects",label:"Projects",dataPath:"totalProjects",format:"number"},{key:"projectLimit",label:"Plan Limit",dataPath:"projectLimit",format:"number"}],table:{caption:"Current project count and plan limit."}}}),W=q({meta:{...B,key:"saas-boilerplate.visualization.project-status",title:"Project Status",description:"Distribution of project states.",goal:"Show the mix of active, draft, and archived projects.",context:"Project portfolio overview."},source:{primary:w,resultPath:"data"},visualization:{kind:"pie",nameDimension:"status",valueMeasure:"projects",dimensions:[{key:"status",label:"Status",dataPath:"status",type:"category"}],measures:[{key:"projects",label:"Projects",dataPath:"projects",format:"number"}],table:{caption:"Project counts by status."}}}),X=q({meta:{...B,key:"saas-boilerplate.visualization.project-tiers",title:"Tier Comparison",description:"Distribution of projects across tiers.",goal:"Compare how the current portfolio is distributed by tier.",context:"Plan and packaging overview."},source:{primary:w,resultPath:"data"},visualization:{kind:"cartesian",variant:"bar",xDimension:"tier",yMeasures:["projects"],dimensions:[{key:"tier",label:"Tier",dataPath:"tier",type:"category"}],measures:[{key:"projects",label:"Projects",dataPath:"projects",format:"number",color:"#1d4ed8"}],table:{caption:"Project counts by tier."}}}),Y=q({meta:{...B,key:"saas-boilerplate.visualization.project-activity",title:"Recent Project Activity",description:"Daily project creation activity.",goal:"Show recent project activity over time.",context:"Project portfolio trend view."},source:{primary:w,resultPath:"data"},visualization:{kind:"cartesian",variant:"line",xDimension:"day",yMeasures:["projects"],dimensions:[{key:"day",label:"Day",dataPath:"day",type:"time"}],measures:[{key:"projects",label:"Projects",dataPath:"projects",format:"number",color:"#0f766e"}],table:{caption:"Daily project creation counts."}}}),$=[Q,W,X,Y],I=new D([...$]),b=$.map((m)=>({key:m.meta.key,version:m.meta.version}));function K(m){return(m instanceof Date?m:new Date(m)).toISOString().slice(0,10)}function O(m,Z=10){let G=new Map,H=new Map,N=new Map;for(let x of m){G.set(x.status,(G.get(x.status)??0)+1),H.set(x.tier,(H.get(x.tier)??0)+1);let k=K(x.createdAt);N.set(k,(N.get(k)??0)+1)}return[{key:"saas-capacity",spec:Q,data:{data:[{totalProjects:m.length,projectLimit:Z}]},title:"Project Capacity",description:"Current project count compared to the active limit.",height:220},{key:"saas-status",spec:W,data:{data:Array.from(G.entries()).map(([x,k])=>({status:x,projects:k}))},title:"Project Status",description:"Status mix across the current project portfolio.",height:260},{key:"saas-tier",spec:X,data:{data:Array.from(H.entries()).map(([x,k])=>({tier:x,projects:k}))},title:"Tier Comparison",description:"How projects are distributed across tiers."},{key:"saas-activity",spec:Y,data:{data:Array.from(N.entries()).sort(([x],[k])=>x.localeCompare(k)).map(([x,k])=>({day:x,projects:k}))},title:"Recent Project Activity",description:"Daily project creation activity."}]}import{defineFeature as h}from"@contractspec/lib.contracts-spec";var d=h({meta:{key:"saas-boilerplate",title:"SaaS Boilerplate",description:"SaaS application foundation with projects, billing, and settings",domain:"saas",owners:["@saas-team"],tags:["saas","projects","billing"],stability:"experimental",version:"1.0.0"},operations:[{key:"saas.project.create",version:"1.0.0"},{key:"saas.project.get",version:"1.0.0"},{key:"saas.project.update",version:"1.0.0"},{key:"saas.project.delete",version:"1.0.0"},{key:"saas.project.list",version:"1.0.0"},{key:"saas.billing.subscription.get",version:"1.0.0"},{key:"saas.billing.usage.record",version:"1.0.0"},{key:"saas.billing.usage.summary",version:"1.0.0"},{key:"saas.billing.feature.check",version:"1.0.0"}],events:[{key:"project.created",version:"1.0.0"},{key:"project.updated",version:"1.0.0"},{key:"project.deleted",version:"1.0.0"},{key:"project.archived",version:"1.0.0"},{key:"billing.usage.recorded",version:"1.0.0"},{key:"billing.subscription.changed",version:"1.0.0"},{key:"billing.limit.reached",version:"1.0.0"}],presentations:[{key:"saas.dashboard",version:"1.0.0"},{key:"saas.project.list",version:"1.0.0"},{key:"saas.project.detail",version:"1.0.0"},{key:"saas.billing.subscription",version:"1.0.0"},{key:"saas.billing.usage",version:"1.0.0"},{key:"saas.settings",version:"1.0.0"}],opToPresentation:[{op:{key:"saas.project.list",version:"1.0.0"},pres:{key:"saas.project.list",version:"1.0.0"}},{op:{key:"saas.project.get",version:"1.0.0"},pres:{key:"saas.project.detail",version:"1.0.0"}},{op:{key:"saas.billing.subscription.get",version:"1.0.0"},pres:{key:"saas.billing.subscription",version:"1.0.0"}},{op:{key:"saas.billing.usage.summary",version:"1.0.0"},pres:{key:"saas.billing.usage",version:"1.0.0"}}],presentationsTargets:[{key:"saas.dashboard",version:"1.0.0",targets:["react","markdown"]},{key:"saas.project.list",version:"1.0.0",targets:["react","markdown","application/json"]},{key:"saas.billing.subscription",version:"1.0.0",targets:["react","markdown"]},{key:"saas.billing.usage",version:"1.0.0",targets:["react","markdown"]}],visualizations:b,capabilities:{requires:[{key:"identity",version:"1.0.0"},{key:"audit-trail",version:"1.0.0"},{key:"notifications",version:"1.0.0"}]},telemetry:[{key:"saas-boilerplate.telemetry",version:"1.0.0"}],jobs:[{key:"saas-boilerplate.job.usage-recording",version:"1.0.0"}],docs:["docs.examples.saas-boilerplate.goal","docs.examples.saas-boilerplate.usage","docs.examples.saas-boilerplate.reference","docs.examples.saas-boilerplate.constraints"]});export{d as SaasBoilerplateFeature};
@@ -1,20 +1,2 @@
1
- // src/seeders/index.ts
2
- async function seedSaasBoilerplate(params) {
3
- const { projectId, db } = params;
4
- const existing = await db.query(`SELECT COUNT(*) as count FROM saas_project WHERE "projectId" = $1`, [projectId]);
5
- if (existing.rows[0]?.count > 0)
6
- return;
7
- await db.execute(`INSERT INTO saas_project (id, "projectId", "organizationId", name, description, status, tier)
8
- VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
9
- "saas_proj_1",
10
- projectId,
11
- "org_demo",
12
- "Demo Project",
13
- "A demo SaaS project",
14
- "ACTIVE",
15
- "PRO"
16
- ]);
17
- }
18
- export {
19
- seedSaasBoilerplate
20
- };
1
+ async function r(a){let{projectId:t,db:e}=a;if((await e.query('SELECT COUNT(*) as count FROM saas_project WHERE "projectId" = $1',[t])).rows[0]?.count>0)return;await e.execute(`INSERT INTO saas_project (id, "projectId", "organizationId", name, description, status, tier)
2
+ VALUES ($1, $2, $3, $4, $5, $6, $7)`,["saas_proj_1",t,"org_demo","Demo Project","A demo SaaS project","ACTIVE","PRO"])}export{r as seedSaasBoilerplate};
@@ -1,75 +1 @@
1
- // src/settings/settings.enum.ts
2
- import { defineEntityEnum } from "@contractspec/lib.schema";
3
- var SettingsScopeEnum = defineEntityEnum({
4
- name: "SettingsScope",
5
- values: ["APP", "ORG", "USER", "PROJECT"],
6
- schema: "saas_app",
7
- description: "Scope of a setting."
8
- });
9
-
10
- // src/settings/settings.entity.ts
11
- import { defineEntity, field, index } from "@contractspec/lib.schema";
12
- var SettingsEntity = defineEntity({
13
- name: "Settings",
14
- description: "Application, organization, or user settings.",
15
- schema: "saas_app",
16
- map: "settings",
17
- fields: {
18
- id: field.id(),
19
- key: field.string({
20
- description: 'Setting key (e.g., "theme", "notifications.email")'
21
- }),
22
- scope: field.enum("SettingsScope"),
23
- scopeId: field.string({
24
- isOptional: true,
25
- description: "ID of scoped entity (org, user, project)"
26
- }),
27
- value: field.json({ description: "Setting value" }),
28
- valueType: field.string({
29
- default: '"string"',
30
- description: "Type hint for value"
31
- }),
32
- schema: field.json({
33
- isOptional: true,
34
- description: "JSON schema for validation"
35
- }),
36
- description: field.string({ isOptional: true }),
37
- isSecret: field.boolean({
38
- default: false,
39
- description: "Whether value should be encrypted"
40
- }),
41
- createdAt: field.createdAt(),
42
- updatedAt: field.updatedAt()
43
- },
44
- indexes: [
45
- index.unique(["scope", "scopeId", "key"]),
46
- index.on(["scope", "key"])
47
- ],
48
- enums: [SettingsScopeEnum]
49
- });
50
- var FeatureFlagEntity = defineEntity({
51
- name: "FeatureFlag",
52
- description: "Feature flags for progressive rollout.",
53
- schema: "saas_app",
54
- map: "feature_flag",
55
- fields: {
56
- id: field.id(),
57
- key: field.string({ isUnique: true, description: "Feature flag key" }),
58
- name: field.string({ description: "Human-readable name" }),
59
- description: field.string({ isOptional: true }),
60
- enabled: field.boolean({ default: false }),
61
- defaultValue: field.boolean({ default: false }),
62
- rules: field.json({ isOptional: true, description: "Targeting rules" }),
63
- rolloutPercentage: field.int({
64
- default: 0,
65
- description: "Percentage rollout (0-100)"
66
- }),
67
- createdAt: field.createdAt(),
68
- updatedAt: field.updatedAt()
69
- }
70
- });
71
- export {
72
- SettingsScopeEnum,
73
- SettingsEntity,
74
- FeatureFlagEntity
75
- };
1
+ import{defineEntityEnum as s}from"@contractspec/lib.schema";var t=s({name:"SettingsScope",values:["APP","ORG","USER","PROJECT"],schema:"saas_app",description:"Scope of a setting."});import{defineEntity as p,field as o,index as n}from"@contractspec/lib.schema";var a=p({name:"Settings",description:"Application, organization, or user settings.",schema:"saas_app",map:"settings",fields:{id:o.id(),key:o.string({description:'Setting key (e.g., "theme", "notifications.email")'}),scope:o.enum("SettingsScope"),scopeId:o.string({isOptional:!0,description:"ID of scoped entity (org, user, project)"}),value:o.json({description:"Setting value"}),valueType:o.string({default:'"string"',description:"Type hint for value"}),schema:o.json({isOptional:!0,description:"JSON schema for validation"}),description:o.string({isOptional:!0}),isSecret:o.boolean({default:!1,description:"Whether value should be encrypted"}),createdAt:o.createdAt(),updatedAt:o.updatedAt()},indexes:[n.unique(["scope","scopeId","key"]),n.on(["scope","key"])],enums:[t]}),r=p({name:"FeatureFlag",description:"Feature flags for progressive rollout.",schema:"saas_app",map:"feature_flag",fields:{id:o.id(),key:o.string({isUnique:!0,description:"Feature flag key"}),name:o.string({description:"Human-readable name"}),description:o.string({isOptional:!0}),enabled:o.boolean({default:!1}),defaultValue:o.boolean({default:!1}),rules:o.json({isOptional:!0,description:"Targeting rules"}),rolloutPercentage:o.int({default:0,description:"Percentage rollout (0-100)"}),createdAt:o.createdAt(),updatedAt:o.updatedAt()}});export{t as SettingsScopeEnum,a as SettingsEntity,r as FeatureFlagEntity};
@@ -1,74 +1 @@
1
- // src/settings/settings.enum.ts
2
- import { defineEntityEnum } from "@contractspec/lib.schema";
3
- var SettingsScopeEnum = defineEntityEnum({
4
- name: "SettingsScope",
5
- values: ["APP", "ORG", "USER", "PROJECT"],
6
- schema: "saas_app",
7
- description: "Scope of a setting."
8
- });
9
-
10
- // src/settings/settings.entity.ts
11
- import { defineEntity, field, index } from "@contractspec/lib.schema";
12
- var SettingsEntity = defineEntity({
13
- name: "Settings",
14
- description: "Application, organization, or user settings.",
15
- schema: "saas_app",
16
- map: "settings",
17
- fields: {
18
- id: field.id(),
19
- key: field.string({
20
- description: 'Setting key (e.g., "theme", "notifications.email")'
21
- }),
22
- scope: field.enum("SettingsScope"),
23
- scopeId: field.string({
24
- isOptional: true,
25
- description: "ID of scoped entity (org, user, project)"
26
- }),
27
- value: field.json({ description: "Setting value" }),
28
- valueType: field.string({
29
- default: '"string"',
30
- description: "Type hint for value"
31
- }),
32
- schema: field.json({
33
- isOptional: true,
34
- description: "JSON schema for validation"
35
- }),
36
- description: field.string({ isOptional: true }),
37
- isSecret: field.boolean({
38
- default: false,
39
- description: "Whether value should be encrypted"
40
- }),
41
- createdAt: field.createdAt(),
42
- updatedAt: field.updatedAt()
43
- },
44
- indexes: [
45
- index.unique(["scope", "scopeId", "key"]),
46
- index.on(["scope", "key"])
47
- ],
48
- enums: [SettingsScopeEnum]
49
- });
50
- var FeatureFlagEntity = defineEntity({
51
- name: "FeatureFlag",
52
- description: "Feature flags for progressive rollout.",
53
- schema: "saas_app",
54
- map: "feature_flag",
55
- fields: {
56
- id: field.id(),
57
- key: field.string({ isUnique: true, description: "Feature flag key" }),
58
- name: field.string({ description: "Human-readable name" }),
59
- description: field.string({ isOptional: true }),
60
- enabled: field.boolean({ default: false }),
61
- defaultValue: field.boolean({ default: false }),
62
- rules: field.json({ isOptional: true, description: "Targeting rules" }),
63
- rolloutPercentage: field.int({
64
- default: 0,
65
- description: "Percentage rollout (0-100)"
66
- }),
67
- createdAt: field.createdAt(),
68
- updatedAt: field.updatedAt()
69
- }
70
- });
71
- export {
72
- SettingsEntity,
73
- FeatureFlagEntity
74
- };
1
+ import{defineEntityEnum as c}from"@contractspec/lib.schema";var p=c({name:"SettingsScope",values:["APP","ORG","USER","PROJECT"],schema:"saas_app",description:"Scope of a setting."});import{defineEntity as S,field as o,index as P}from"@contractspec/lib.schema";var m=S({name:"Settings",description:"Application, organization, or user settings.",schema:"saas_app",map:"settings",fields:{id:o.id(),key:o.string({description:'Setting key (e.g., "theme", "notifications.email")'}),scope:o.enum("SettingsScope"),scopeId:o.string({isOptional:!0,description:"ID of scoped entity (org, user, project)"}),value:o.json({description:"Setting value"}),valueType:o.string({default:'"string"',description:"Type hint for value"}),schema:o.json({isOptional:!0,description:"JSON schema for validation"}),description:o.string({isOptional:!0}),isSecret:o.boolean({default:!1,description:"Whether value should be encrypted"}),createdAt:o.createdAt(),updatedAt:o.updatedAt()},indexes:[P.unique(["scope","scopeId","key"]),P.on(["scope","key"])],enums:[p]}),v=S({name:"FeatureFlag",description:"Feature flags for progressive rollout.",schema:"saas_app",map:"feature_flag",fields:{id:o.id(),key:o.string({isUnique:!0,description:"Feature flag key"}),name:o.string({description:"Human-readable name"}),description:o.string({isOptional:!0}),enabled:o.boolean({default:!1}),defaultValue:o.boolean({default:!1}),rules:o.json({isOptional:!0,description:"Targeting rules"}),rolloutPercentage:o.int({default:0,description:"Percentage rollout (0-100)"}),createdAt:o.createdAt(),updatedAt:o.updatedAt()}});export{m as SettingsEntity,v as FeatureFlagEntity};
@@ -1,11 +1 @@
1
- // src/settings/settings.enum.ts
2
- import { defineEntityEnum } from "@contractspec/lib.schema";
3
- var SettingsScopeEnum = defineEntityEnum({
4
- name: "SettingsScope",
5
- values: ["APP", "ORG", "USER", "PROJECT"],
6
- schema: "saas_app",
7
- description: "Scope of a setting."
8
- });
9
- export {
10
- SettingsScopeEnum
11
- };
1
+ import{defineEntityEnum as e}from"@contractspec/lib.schema";var n=e({name:"SettingsScope",values:["APP","ORG","USER","PROJECT"],schema:"saas_app",description:"Scope of a setting."});export{n as SettingsScopeEnum};