@contractspec/example.saas-boilerplate 0.0.0-canary-20260113170453
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$bundle.log +188 -0
- package/.turbo/turbo-build.log +189 -0
- package/CHANGELOG.md +440 -0
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/billing/billing.entity.d.ts +61 -0
- package/dist/billing/billing.entity.d.ts.map +1 -0
- package/dist/billing/billing.entity.js +122 -0
- package/dist/billing/billing.entity.js.map +1 -0
- package/dist/billing/billing.enum.d.ts +16 -0
- package/dist/billing/billing.enum.d.ts.map +1 -0
- package/dist/billing/billing.enum.js +27 -0
- package/dist/billing/billing.enum.js.map +1 -0
- package/dist/billing/billing.event.d.ts +86 -0
- package/dist/billing/billing.event.d.ts.map +1 -0
- package/dist/billing/billing.event.js +153 -0
- package/dist/billing/billing.event.js.map +1 -0
- package/dist/billing/billing.handler.d.ts +82 -0
- package/dist/billing/billing.handler.d.ts.map +1 -0
- package/dist/billing/billing.handler.js +58 -0
- package/dist/billing/billing.handler.js.map +1 -0
- package/dist/billing/billing.operations.d.ts +166 -0
- package/dist/billing/billing.operations.d.ts.map +1 -0
- package/dist/billing/billing.operations.js +181 -0
- package/dist/billing/billing.operations.js.map +1 -0
- package/dist/billing/billing.presentation.d.ts +14 -0
- package/dist/billing/billing.presentation.d.ts.map +1 -0
- package/dist/billing/billing.presentation.js +59 -0
- package/dist/billing/billing.presentation.js.map +1 -0
- package/dist/billing/billing.schema.d.ts +201 -0
- package/dist/billing/billing.schema.d.ts.map +1 -0
- package/dist/billing/billing.schema.js +214 -0
- package/dist/billing/billing.schema.js.map +1 -0
- package/dist/billing/index.d.ts +8 -0
- package/dist/billing/index.js +9 -0
- package/dist/dashboard/dashboard.presentation.d.ts +14 -0
- package/dist/dashboard/dashboard.presentation.d.ts.map +1 -0
- package/dist/dashboard/dashboard.presentation.js +55 -0
- package/dist/dashboard/dashboard.presentation.js.map +1 -0
- package/dist/dashboard/index.d.ts +2 -0
- package/dist/dashboard/index.js +3 -0
- package/dist/docs/index.d.ts +1 -0
- package/dist/docs/index.js +1 -0
- package/dist/docs/saas-boilerplate.docblock.d.ts +1 -0
- package/dist/docs/saas-boilerplate.docblock.js +100 -0
- package/dist/docs/saas-boilerplate.docblock.js.map +1 -0
- package/dist/example.d.ts +7 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +53 -0
- package/dist/example.js.map +1 -0
- package/dist/handlers/index.d.ts +4 -0
- package/dist/handlers/index.js +5 -0
- package/dist/handlers/saas.handlers.d.ts +68 -0
- package/dist/handlers/saas.handlers.d.ts.map +1 -0
- package/dist/handlers/saas.handlers.js +148 -0
- package/dist/handlers/saas.handlers.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/presentations/index.d.ts +17 -0
- package/dist/presentations/index.d.ts.map +1 -0
- package/dist/presentations/index.js +17 -0
- package/dist/presentations/index.js.map +1 -0
- package/dist/project/index.d.ts +8 -0
- package/dist/project/index.js +9 -0
- package/dist/project/project.entity.d.ts +40 -0
- package/dist/project/project.entity.d.ts.map +1 -0
- package/dist/project/project.entity.js +85 -0
- package/dist/project/project.entity.js.map +1 -0
- package/dist/project/project.enum.d.ts +16 -0
- package/dist/project/project.enum.d.ts.map +1 -0
- package/dist/project/project.enum.js +26 -0
- package/dist/project/project.enum.js.map +1 -0
- package/dist/project/project.event.d.ts +92 -0
- package/dist/project/project.event.d.ts.map +1 -0
- package/dist/project/project.event.js +165 -0
- package/dist/project/project.event.js.map +1 -0
- package/dist/project/project.handler.d.ts +72 -0
- package/dist/project/project.handler.d.ts.map +1 -0
- package/dist/project/project.handler.js +82 -0
- package/dist/project/project.handler.js.map +1 -0
- package/dist/project/project.operations.d.ts +419 -0
- package/dist/project/project.operations.d.ts.map +1 -0
- package/dist/project/project.operations.js +260 -0
- package/dist/project/project.operations.js.map +1 -0
- package/dist/project/project.presentation.d.ts +14 -0
- package/dist/project/project.presentation.d.ts.map +1 -0
- package/dist/project/project.presentation.js +65 -0
- package/dist/project/project.presentation.js.map +1 -0
- package/dist/project/project.schema.d.ts +235 -0
- package/dist/project/project.schema.d.ts.map +1 -0
- package/dist/project/project.schema.js +215 -0
- package/dist/project/project.schema.js.map +1 -0
- package/dist/saas-boilerplate.feature.d.ts +12 -0
- package/dist/saas-boilerplate.feature.d.ts.map +1 -0
- package/dist/saas-boilerplate.feature.js +208 -0
- package/dist/saas-boilerplate.feature.js.map +1 -0
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +19 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/settings/index.d.ts +3 -0
- package/dist/settings/index.js +4 -0
- package/dist/settings/settings.entity.d.ts +37 -0
- package/dist/settings/settings.entity.d.ts.map +1 -0
- package/dist/settings/settings.entity.js +78 -0
- package/dist/settings/settings.entity.js.map +1 -0
- package/dist/settings/settings.enum.d.ts +10 -0
- package/dist/settings/settings.enum.d.ts.map +1 -0
- package/dist/settings/settings.enum.js +21 -0
- package/dist/settings/settings.enum.js.map +1 -0
- package/dist/shared/mock-data.d.ts +86 -0
- package/dist/shared/mock-data.d.ts.map +1 -0
- package/dist/shared/mock-data.js +138 -0
- package/dist/shared/mock-data.js.map +1 -0
- package/dist/shared/overlay-types.d.ts +34 -0
- package/dist/shared/overlay-types.d.ts.map +1 -0
- package/dist/shared/overlay-types.js +0 -0
- package/dist/tests/operations.test-spec.d.ts +10 -0
- package/dist/tests/operations.test-spec.d.ts.map +1 -0
- package/dist/tests/operations.test-spec.js +123 -0
- package/dist/tests/operations.test-spec.js.map +1 -0
- package/dist/ui/SaasDashboard.d.ts +7 -0
- package/dist/ui/SaasDashboard.d.ts.map +1 -0
- package/dist/ui/SaasDashboard.js +298 -0
- package/dist/ui/SaasDashboard.js.map +1 -0
- package/dist/ui/SaasProjectList.d.ts +14 -0
- package/dist/ui/SaasProjectList.d.ts.map +1 -0
- package/dist/ui/SaasProjectList.js +76 -0
- package/dist/ui/SaasProjectList.js.map +1 -0
- package/dist/ui/SaasSettingsPanel.d.ts +7 -0
- package/dist/ui/SaasSettingsPanel.d.ts.map +1 -0
- package/dist/ui/SaasSettingsPanel.js +138 -0
- package/dist/ui/SaasSettingsPanel.js.map +1 -0
- package/dist/ui/hooks/index.d.ts +3 -0
- package/dist/ui/hooks/index.js +6 -0
- package/dist/ui/hooks/useProjectList.d.ts +34 -0
- package/dist/ui/hooks/useProjectList.d.ts.map +1 -0
- package/dist/ui/hooks/useProjectList.js +75 -0
- package/dist/ui/hooks/useProjectList.js.map +1 -0
- package/dist/ui/hooks/useProjectMutations.d.ts +28 -0
- package/dist/ui/hooks/useProjectMutations.d.ts.map +1 -0
- package/dist/ui/hooks/useProjectMutations.js +146 -0
- package/dist/ui/hooks/useProjectMutations.js.map +1 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/modals/CreateProjectModal.d.ts +23 -0
- package/dist/ui/modals/CreateProjectModal.d.ts.map +1 -0
- package/dist/ui/modals/CreateProjectModal.js +139 -0
- package/dist/ui/modals/CreateProjectModal.js.map +1 -0
- package/dist/ui/modals/ProjectActionsModal.d.ts +38 -0
- package/dist/ui/modals/ProjectActionsModal.d.ts.map +1 -0
- package/dist/ui/modals/ProjectActionsModal.js +292 -0
- package/dist/ui/modals/ProjectActionsModal.js.map +1 -0
- package/dist/ui/modals/index.d.ts +3 -0
- package/dist/ui/modals/index.js +4 -0
- package/dist/ui/overlays/demo-overlays.d.ts +19 -0
- package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
- package/dist/ui/overlays/demo-overlays.js +70 -0
- package/dist/ui/overlays/demo-overlays.js.map +1 -0
- package/dist/ui/overlays/index.d.ts +2 -0
- package/dist/ui/overlays/index.js +3 -0
- package/dist/ui/renderers/index.d.ts +3 -0
- package/dist/ui/renderers/index.js +4 -0
- package/dist/ui/renderers/project-list.markdown.d.ts +31 -0
- package/dist/ui/renderers/project-list.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/project-list.markdown.js +148 -0
- package/dist/ui/renderers/project-list.markdown.js.map +1 -0
- package/dist/ui/renderers/project-list.renderer.d.ts +9 -0
- package/dist/ui/renderers/project-list.renderer.d.ts.map +1 -0
- package/dist/ui/renderers/project-list.renderer.js +17 -0
- package/dist/ui/renderers/project-list.renderer.js.map +1 -0
- package/example.ts +1 -0
- package/package.json +135 -0
- package/src/billing/billing.entity.ts +158 -0
- package/src/billing/billing.enum.ts +23 -0
- package/src/billing/billing.event.ts +108 -0
- package/src/billing/billing.handler.ts +137 -0
- package/src/billing/billing.operations.ts +187 -0
- package/src/billing/billing.presentation.ts +56 -0
- package/src/billing/billing.schema.ts +133 -0
- package/src/billing/index.ts +64 -0
- package/src/dashboard/dashboard.presentation.ts +56 -0
- package/src/dashboard/index.ts +8 -0
- package/src/docs/index.ts +1 -0
- package/src/docs/saas-boilerplate.docblock.ts +98 -0
- package/src/example.ts +38 -0
- package/src/handlers/index.ts +23 -0
- package/src/handlers/saas.handlers.ts +300 -0
- package/src/index.ts +76 -0
- package/src/presentations/index.ts +36 -0
- package/src/project/index.ts +66 -0
- package/src/project/project.entity.ts +93 -0
- package/src/project/project.enum.ts +22 -0
- package/src/project/project.event.ts +128 -0
- package/src/project/project.handler.ts +168 -0
- package/src/project/project.operations.ts +272 -0
- package/src/project/project.presentation.ts +58 -0
- package/src/project/project.schema.ts +147 -0
- package/src/saas-boilerplate.feature.ts +113 -0
- package/src/seeders/index.ts +28 -0
- package/src/settings/index.ts +9 -0
- package/src/settings/settings.entity.ts +89 -0
- package/src/settings/settings.enum.ts +11 -0
- package/src/shared/mock-data.ts +110 -0
- package/src/shared/overlay-types.ts +39 -0
- package/src/tests/operations.test-spec.ts +109 -0
- package/src/ui/SaasDashboard.tsx +325 -0
- package/src/ui/SaasProjectList.tsx +113 -0
- package/src/ui/SaasSettingsPanel.tsx +96 -0
- package/src/ui/hooks/index.ts +10 -0
- package/src/ui/hooks/useProjectList.ts +95 -0
- package/src/ui/hooks/useProjectMutations.ts +166 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/modals/CreateProjectModal.tsx +176 -0
- package/src/ui/modals/ProjectActionsModal.tsx +346 -0
- package/src/ui/modals/index.ts +2 -0
- package/src/ui/overlays/demo-overlays.ts +74 -0
- package/src/ui/overlays/index.ts +1 -0
- package/src/ui/renderers/index.ts +7 -0
- package/src/ui/renderers/project-list.markdown.ts +239 -0
- package/src/ui/renderers/project-list.renderer.tsx +22 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.js +7 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project domain - project management within organizations.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Enums
|
|
6
|
+
export {
|
|
7
|
+
ProjectStatusSchemaEnum,
|
|
8
|
+
ProjectStatusFilterEnum,
|
|
9
|
+
} from './project.enum';
|
|
10
|
+
|
|
11
|
+
// Schema models
|
|
12
|
+
export {
|
|
13
|
+
ProjectModel,
|
|
14
|
+
CreateProjectInputModel,
|
|
15
|
+
UpdateProjectInputModel,
|
|
16
|
+
GetProjectInputModel,
|
|
17
|
+
DeleteProjectInputModel,
|
|
18
|
+
DeleteProjectOutputModel,
|
|
19
|
+
ProjectDeletedPayloadModel,
|
|
20
|
+
ListProjectsInputModel,
|
|
21
|
+
ListProjectsOutputModel,
|
|
22
|
+
} from './project.schema';
|
|
23
|
+
|
|
24
|
+
// Contracts
|
|
25
|
+
export {
|
|
26
|
+
CreateProjectContract,
|
|
27
|
+
GetProjectContract,
|
|
28
|
+
UpdateProjectContract,
|
|
29
|
+
DeleteProjectContract,
|
|
30
|
+
ListProjectsContract,
|
|
31
|
+
} from './project.operations';
|
|
32
|
+
|
|
33
|
+
// Events
|
|
34
|
+
export {
|
|
35
|
+
ProjectCreatedEvent,
|
|
36
|
+
ProjectUpdatedEvent,
|
|
37
|
+
ProjectDeletedEvent,
|
|
38
|
+
ProjectArchivedEvent,
|
|
39
|
+
} from './project.event';
|
|
40
|
+
|
|
41
|
+
// Entities
|
|
42
|
+
export {
|
|
43
|
+
ProjectStatusEnum,
|
|
44
|
+
ProjectEntity,
|
|
45
|
+
ProjectMemberEntity,
|
|
46
|
+
} from './project.entity';
|
|
47
|
+
|
|
48
|
+
// Presentations
|
|
49
|
+
export {
|
|
50
|
+
ProjectListPresentation,
|
|
51
|
+
ProjectDetailPresentation,
|
|
52
|
+
} from './project.presentation';
|
|
53
|
+
|
|
54
|
+
// Handlers
|
|
55
|
+
export {
|
|
56
|
+
mockListProjectsHandler,
|
|
57
|
+
mockGetProjectHandler,
|
|
58
|
+
mockCreateProjectHandler,
|
|
59
|
+
mockUpdateProjectHandler,
|
|
60
|
+
mockDeleteProjectHandler,
|
|
61
|
+
type Project,
|
|
62
|
+
type CreateProjectInput,
|
|
63
|
+
type UpdateProjectInput,
|
|
64
|
+
type ListProjectsInput,
|
|
65
|
+
type ListProjectsOutput,
|
|
66
|
+
} from './project.handler';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineEntity,
|
|
3
|
+
defineEntityEnum,
|
|
4
|
+
field,
|
|
5
|
+
index,
|
|
6
|
+
} from '@contractspec/lib.schema';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Project status enum for entities.
|
|
10
|
+
*/
|
|
11
|
+
export const ProjectStatusEnum = defineEntityEnum({
|
|
12
|
+
name: 'ProjectStatus',
|
|
13
|
+
values: ['DRAFT', 'ACTIVE', 'ARCHIVED', 'DELETED'] as const,
|
|
14
|
+
schema: 'saas_app',
|
|
15
|
+
description: 'Status of a project.',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Project entity - team-scoped work container.
|
|
20
|
+
*/
|
|
21
|
+
export const ProjectEntity = defineEntity({
|
|
22
|
+
name: 'Project',
|
|
23
|
+
description: 'A project belonging to an organization.',
|
|
24
|
+
schema: 'saas_app',
|
|
25
|
+
map: 'project',
|
|
26
|
+
fields: {
|
|
27
|
+
id: field.id({ description: 'Unique project ID' }),
|
|
28
|
+
name: field.string({ description: 'Project name' }),
|
|
29
|
+
description: field.string({
|
|
30
|
+
isOptional: true,
|
|
31
|
+
description: 'Project description',
|
|
32
|
+
}),
|
|
33
|
+
slug: field.string({
|
|
34
|
+
isOptional: true,
|
|
35
|
+
description: 'URL-friendly identifier',
|
|
36
|
+
}),
|
|
37
|
+
|
|
38
|
+
// Ownership
|
|
39
|
+
organizationId: field.foreignKey({ description: 'Owning organization' }),
|
|
40
|
+
createdBy: field.foreignKey({
|
|
41
|
+
description: 'User who created the project',
|
|
42
|
+
}),
|
|
43
|
+
|
|
44
|
+
// Status
|
|
45
|
+
status: field.enum('ProjectStatus', { default: 'DRAFT' }),
|
|
46
|
+
|
|
47
|
+
// Settings
|
|
48
|
+
isPublic: field.boolean({
|
|
49
|
+
default: false,
|
|
50
|
+
description: 'Whether project is publicly visible',
|
|
51
|
+
}),
|
|
52
|
+
settings: field.json({
|
|
53
|
+
isOptional: true,
|
|
54
|
+
description: 'Project-specific settings',
|
|
55
|
+
}),
|
|
56
|
+
|
|
57
|
+
// Metadata
|
|
58
|
+
tags: field.string({ isArray: true, description: 'Project tags' }),
|
|
59
|
+
metadata: field.json({ isOptional: true }),
|
|
60
|
+
|
|
61
|
+
// Timestamps
|
|
62
|
+
createdAt: field.createdAt(),
|
|
63
|
+
updatedAt: field.updatedAt(),
|
|
64
|
+
archivedAt: field.dateTime({ isOptional: true }),
|
|
65
|
+
},
|
|
66
|
+
indexes: [
|
|
67
|
+
index.on(['organizationId', 'status']),
|
|
68
|
+
index.on(['organizationId', 'createdAt']),
|
|
69
|
+
index.unique(['organizationId', 'slug']),
|
|
70
|
+
],
|
|
71
|
+
enums: [ProjectStatusEnum],
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* ProjectMember entity - project-level access.
|
|
76
|
+
*/
|
|
77
|
+
export const ProjectMemberEntity = defineEntity({
|
|
78
|
+
name: 'ProjectMember',
|
|
79
|
+
description: 'User access to a specific project.',
|
|
80
|
+
schema: 'saas_app',
|
|
81
|
+
map: 'project_member',
|
|
82
|
+
fields: {
|
|
83
|
+
id: field.id(),
|
|
84
|
+
projectId: field.foreignKey(),
|
|
85
|
+
userId: field.foreignKey(),
|
|
86
|
+
role: field.string({
|
|
87
|
+
description: 'Role in project (owner, editor, viewer)',
|
|
88
|
+
}),
|
|
89
|
+
addedBy: field.string({ isOptional: true }),
|
|
90
|
+
createdAt: field.createdAt(),
|
|
91
|
+
},
|
|
92
|
+
indexes: [index.unique(['projectId', 'userId'])],
|
|
93
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineEnum } from '@contractspec/lib.schema';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Project status enum for contract schemas.
|
|
5
|
+
* Note: Entity enum is defined separately in project.entity.ts
|
|
6
|
+
*/
|
|
7
|
+
export const ProjectStatusSchemaEnum = defineEnum('ProjectStatus', [
|
|
8
|
+
'DRAFT',
|
|
9
|
+
'ACTIVE',
|
|
10
|
+
'ARCHIVED',
|
|
11
|
+
'DELETED',
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Project status filter enum (includes 'all' option).
|
|
16
|
+
*/
|
|
17
|
+
export const ProjectStatusFilterEnum = defineEnum('ProjectStatusFilter', [
|
|
18
|
+
'DRAFT',
|
|
19
|
+
'ACTIVE',
|
|
20
|
+
'ARCHIVED',
|
|
21
|
+
'all',
|
|
22
|
+
]);
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { ScalarTypeEnum, defineSchemaModel } from '@contractspec/lib.schema';
|
|
2
|
+
import { defineEvent } from '@contractspec/lib.contracts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Payload when a project is created.
|
|
6
|
+
*/
|
|
7
|
+
const ProjectCreatedPayload = defineSchemaModel({
|
|
8
|
+
name: 'ProjectCreatedPayload',
|
|
9
|
+
description: 'Payload when a project is created',
|
|
10
|
+
fields: {
|
|
11
|
+
projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
12
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
13
|
+
organizationId: {
|
|
14
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
15
|
+
isOptional: false,
|
|
16
|
+
},
|
|
17
|
+
createdBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
18
|
+
createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Payload when a project is updated.
|
|
24
|
+
*/
|
|
25
|
+
const ProjectUpdatedPayload = defineSchemaModel({
|
|
26
|
+
name: 'ProjectUpdatedPayload',
|
|
27
|
+
description: 'Payload when a project is updated',
|
|
28
|
+
fields: {
|
|
29
|
+
projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
30
|
+
updatedFields: {
|
|
31
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
32
|
+
isArray: true,
|
|
33
|
+
isOptional: false,
|
|
34
|
+
},
|
|
35
|
+
updatedBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
36
|
+
updatedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Payload when a project is deleted.
|
|
42
|
+
*/
|
|
43
|
+
const ProjectDeletedPayload = defineSchemaModel({
|
|
44
|
+
name: 'ProjectDeletedPayload',
|
|
45
|
+
description: 'Payload when a project is deleted',
|
|
46
|
+
fields: {
|
|
47
|
+
projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
48
|
+
organizationId: {
|
|
49
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
50
|
+
isOptional: false,
|
|
51
|
+
},
|
|
52
|
+
deletedBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
53
|
+
deletedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Payload when a project is archived.
|
|
59
|
+
*/
|
|
60
|
+
const ProjectArchivedPayload = defineSchemaModel({
|
|
61
|
+
name: 'ProjectArchivedPayload',
|
|
62
|
+
description: 'Payload when a project is archived',
|
|
63
|
+
fields: {
|
|
64
|
+
projectId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
65
|
+
archivedBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
66
|
+
archivedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Event: A new project has been created.
|
|
72
|
+
*/
|
|
73
|
+
export const ProjectCreatedEvent = defineEvent({
|
|
74
|
+
meta: {
|
|
75
|
+
key: 'project.created',
|
|
76
|
+
version: '1.0.0',
|
|
77
|
+
description: 'A new project has been created.',
|
|
78
|
+
stability: 'stable',
|
|
79
|
+
owners: ['@saas-team'],
|
|
80
|
+
tags: ['project', 'created'],
|
|
81
|
+
},
|
|
82
|
+
payload: ProjectCreatedPayload,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Event: A project has been updated.
|
|
87
|
+
*/
|
|
88
|
+
export const ProjectUpdatedEvent = defineEvent({
|
|
89
|
+
meta: {
|
|
90
|
+
key: 'project.updated',
|
|
91
|
+
version: '1.0.0',
|
|
92
|
+
description: 'A project has been updated.',
|
|
93
|
+
stability: 'stable',
|
|
94
|
+
owners: ['@saas-team'],
|
|
95
|
+
tags: ['project', 'updated'],
|
|
96
|
+
},
|
|
97
|
+
payload: ProjectUpdatedPayload,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Event: A project has been deleted.
|
|
102
|
+
*/
|
|
103
|
+
export const ProjectDeletedEvent = defineEvent({
|
|
104
|
+
meta: {
|
|
105
|
+
key: 'project.deleted',
|
|
106
|
+
version: '1.0.0',
|
|
107
|
+
description: 'A project has been deleted.',
|
|
108
|
+
stability: 'stable',
|
|
109
|
+
owners: ['@saas-team'],
|
|
110
|
+
tags: ['project', 'deleted'],
|
|
111
|
+
},
|
|
112
|
+
payload: ProjectDeletedPayload,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Event: A project has been archived.
|
|
117
|
+
*/
|
|
118
|
+
export const ProjectArchivedEvent = defineEvent({
|
|
119
|
+
meta: {
|
|
120
|
+
key: 'project.archived',
|
|
121
|
+
version: '1.0.0',
|
|
122
|
+
description: 'A project has been archived.',
|
|
123
|
+
stability: 'stable',
|
|
124
|
+
owners: ['@saas-team'],
|
|
125
|
+
tags: ['project', 'archived'],
|
|
126
|
+
},
|
|
127
|
+
payload: ProjectArchivedPayload,
|
|
128
|
+
});
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock handlers for Project contracts.
|
|
3
|
+
*/
|
|
4
|
+
import { MOCK_PROJECTS } from '../shared/mock-data';
|
|
5
|
+
|
|
6
|
+
// Types inferred from contract schemas
|
|
7
|
+
export interface Project {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
slug?: string;
|
|
12
|
+
organizationId: string;
|
|
13
|
+
createdBy: string;
|
|
14
|
+
status: 'DRAFT' | 'ACTIVE' | 'ARCHIVED' | 'DELETED';
|
|
15
|
+
isPublic: boolean;
|
|
16
|
+
tags: string[];
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
updatedAt: Date;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface CreateProjectInput {
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
slug?: string;
|
|
25
|
+
isPublic?: boolean;
|
|
26
|
+
tags?: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface UpdateProjectInput {
|
|
30
|
+
projectId: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
slug?: string;
|
|
34
|
+
isPublic?: boolean;
|
|
35
|
+
tags?: string[];
|
|
36
|
+
status?: 'DRAFT' | 'ACTIVE' | 'ARCHIVED' | 'DELETED';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ListProjectsInput {
|
|
40
|
+
status?: 'DRAFT' | 'ACTIVE' | 'ARCHIVED' | 'all';
|
|
41
|
+
search?: string;
|
|
42
|
+
limit?: number;
|
|
43
|
+
offset?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ListProjectsOutput {
|
|
47
|
+
projects: Project[];
|
|
48
|
+
total: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Mock handler for ListProjectsContract.
|
|
53
|
+
*/
|
|
54
|
+
export async function mockListProjectsHandler(
|
|
55
|
+
input: ListProjectsInput
|
|
56
|
+
): Promise<ListProjectsOutput> {
|
|
57
|
+
const { status, search, limit = 20, offset = 0 } = input;
|
|
58
|
+
|
|
59
|
+
let filtered = [...MOCK_PROJECTS];
|
|
60
|
+
|
|
61
|
+
if (status && status !== 'all') {
|
|
62
|
+
filtered = filtered.filter((p) => p.status === status);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (search) {
|
|
66
|
+
const q = search.toLowerCase();
|
|
67
|
+
filtered = filtered.filter(
|
|
68
|
+
(p) =>
|
|
69
|
+
p.name.toLowerCase().includes(q) ||
|
|
70
|
+
p.description?.toLowerCase().includes(q) ||
|
|
71
|
+
p.tags.some((t) => t.toLowerCase().includes(q))
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
filtered.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
|
|
76
|
+
|
|
77
|
+
const total = filtered.length;
|
|
78
|
+
const projects = filtered.slice(offset, offset + limit);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
projects,
|
|
82
|
+
total,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Mock handler for GetProjectContract.
|
|
88
|
+
*/
|
|
89
|
+
export async function mockGetProjectHandler(input: {
|
|
90
|
+
projectId: string;
|
|
91
|
+
}): Promise<Project> {
|
|
92
|
+
const project = MOCK_PROJECTS.find((p) => p.id === input.projectId);
|
|
93
|
+
|
|
94
|
+
if (!project) {
|
|
95
|
+
throw new Error('NOT_FOUND');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return project;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Mock handler for CreateProjectContract.
|
|
103
|
+
*/
|
|
104
|
+
export async function mockCreateProjectHandler(
|
|
105
|
+
input: CreateProjectInput,
|
|
106
|
+
context: { organizationId: string; userId: string }
|
|
107
|
+
): Promise<Project> {
|
|
108
|
+
if (input.slug) {
|
|
109
|
+
const exists = MOCK_PROJECTS.some((p) => p.slug === input.slug);
|
|
110
|
+
if (exists) {
|
|
111
|
+
throw new Error('SLUG_EXISTS');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const now = new Date();
|
|
116
|
+
return {
|
|
117
|
+
id: `proj-${Date.now()}`,
|
|
118
|
+
name: input.name,
|
|
119
|
+
description: input.description,
|
|
120
|
+
slug: input.slug ?? input.name.toLowerCase().replace(/\s+/g, '-'),
|
|
121
|
+
organizationId: context.organizationId,
|
|
122
|
+
createdBy: context.userId,
|
|
123
|
+
status: 'DRAFT',
|
|
124
|
+
isPublic: input.isPublic ?? false,
|
|
125
|
+
tags: input.tags ?? [],
|
|
126
|
+
createdAt: now,
|
|
127
|
+
updatedAt: now,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Mock handler for UpdateProjectContract.
|
|
133
|
+
*/
|
|
134
|
+
export async function mockUpdateProjectHandler(
|
|
135
|
+
input: UpdateProjectInput
|
|
136
|
+
): Promise<Project> {
|
|
137
|
+
const project = MOCK_PROJECTS.find((p) => p.id === input.projectId);
|
|
138
|
+
|
|
139
|
+
if (!project) {
|
|
140
|
+
throw new Error('NOT_FOUND');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
...project,
|
|
145
|
+
name: input.name ?? project.name,
|
|
146
|
+
description: input.description ?? project.description,
|
|
147
|
+
slug: input.slug ?? project.slug,
|
|
148
|
+
isPublic: input.isPublic ?? project.isPublic,
|
|
149
|
+
tags: input.tags ?? project.tags,
|
|
150
|
+
status: input.status ?? project.status,
|
|
151
|
+
updatedAt: new Date(),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Mock handler for DeleteProjectContract.
|
|
157
|
+
*/
|
|
158
|
+
export async function mockDeleteProjectHandler(input: {
|
|
159
|
+
projectId: string;
|
|
160
|
+
}): Promise<{ success: boolean }> {
|
|
161
|
+
const project = MOCK_PROJECTS.find((p) => p.id === input.projectId);
|
|
162
|
+
|
|
163
|
+
if (!project) {
|
|
164
|
+
throw new Error('NOT_FOUND');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { success: true };
|
|
168
|
+
}
|