create-tigra 1.0.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +80 -87
- package/bin/create-tigra.js +242 -309
- package/package.json +49 -41
- package/template/_claude/QUICK_REFERENCE.md +193 -0
- package/template/_claude/README.md +53 -0
- package/template/_claude/commands/create-client.md +881 -0
- package/template/_claude/commands/create-server.md +383 -0
- package/template/_claude/rules/client/01-project-structure.md +133 -0
- package/template/_claude/rules/client/02-components-and-types.md +146 -0
- package/template/_claude/rules/client/03-data-and-state.md +156 -0
- package/template/_claude/rules/client/04-design-system.md +185 -0
- package/template/_claude/rules/client/05-security.md +55 -0
- package/template/_claude/rules/client/06-ux-checklist.md +81 -0
- package/template/_claude/rules/client/core.md +42 -0
- package/template/_claude/rules/global/core.md +77 -0
- package/template/_claude/rules/server/core.md +50 -0
- package/template/_claude/rules/server/database.md +124 -0
- package/template/_claude/rules/server/project-conventions.md +150 -0
- package/template/_claude/rules/server/response-handling.md +144 -0
- package/template/client/.env.example +5 -0
- package/template/client/README.md +36 -0
- package/template/client/components.json +23 -0
- package/template/client/eslint.config.mjs +18 -0
- package/template/client/next.config.ts +34 -0
- package/template/client/package.json +44 -0
- package/template/client/postcss.config.mjs +7 -0
- package/template/client/src/app/(auth)/layout.tsx +18 -0
- package/template/client/src/app/(auth)/login/page.tsx +13 -0
- package/template/client/src/app/(auth)/register/page.tsx +13 -0
- package/template/client/src/app/(main)/dashboard/page.tsx +22 -0
- package/template/client/src/app/(main)/layout.tsx +11 -0
- package/template/client/src/app/error.tsx +27 -0
- package/template/client/src/app/favicon.ico +0 -0
- package/template/client/src/app/globals.css +145 -0
- package/template/client/src/app/layout.tsx +36 -0
- package/template/client/src/app/loading.tsx +11 -0
- package/template/client/src/app/not-found.tsx +23 -0
- package/template/client/src/app/page.tsx +45 -0
- package/template/client/src/app/providers.tsx +43 -0
- package/template/client/src/components/common/ConfirmDialog.tsx +56 -0
- package/template/client/src/components/common/EmptyState.tsx +31 -0
- package/template/client/src/components/common/LoadingSpinner.tsx +30 -0
- package/template/client/src/components/common/Pagination.tsx +55 -0
- package/template/client/src/components/layout/Footer.tsx +17 -0
- package/template/client/src/components/layout/Header.tsx +173 -0
- package/template/client/src/components/layout/MainLayout.tsx +18 -0
- package/template/client/src/components/ui/alert-dialog.tsx +196 -0
- package/template/client/src/components/ui/badge.tsx +48 -0
- package/template/client/src/components/ui/button.tsx +64 -0
- package/template/client/src/components/ui/card.tsx +92 -0
- package/template/client/src/components/ui/input.tsx +21 -0
- package/template/client/src/components/ui/label.tsx +24 -0
- package/template/client/src/components/ui/select.tsx +190 -0
- package/template/client/src/components/ui/skeleton.tsx +13 -0
- package/template/client/src/components/ui/table.tsx +116 -0
- package/template/client/src/features/auth/components/AuthInitializer.tsx +55 -0
- package/template/client/src/features/auth/components/LoginForm.tsx +107 -0
- package/template/client/src/features/auth/components/RegisterForm.tsx +178 -0
- package/template/client/src/features/auth/hooks/useAuth.ts +84 -0
- package/template/client/src/features/auth/services/auth.service.ts +52 -0
- package/template/client/src/features/auth/store/authSlice.ts +38 -0
- package/template/client/src/features/auth/types/auth.types.ts +32 -0
- package/template/client/src/hooks/useDebounce.ts +14 -0
- package/template/client/src/hooks/useLocalStorage.ts +55 -0
- package/template/client/src/hooks/useMediaQuery.ts +27 -0
- package/template/client/src/lib/api/api.types.ts +34 -0
- package/template/client/src/lib/api/axios.config.ts +98 -0
- package/template/client/src/lib/constants/api-endpoints.ts +18 -0
- package/template/client/src/lib/constants/app.constants.ts +12 -0
- package/template/client/src/lib/constants/routes.ts +9 -0
- package/template/client/src/lib/utils/error.ts +32 -0
- package/template/client/src/lib/utils/format.ts +37 -0
- package/template/client/src/lib/utils/security.ts +34 -0
- package/template/client/src/lib/utils.ts +6 -0
- package/template/client/src/middleware.ts +57 -0
- package/template/client/src/store/hooks.ts +7 -0
- package/template/client/src/store/index.ts +12 -0
- package/template/client/src/types/index.ts +3 -0
- package/template/client/tsconfig.json +34 -0
- package/template/gitignore +34 -0
- package/template/server/.dockerignore +66 -0
- package/template/server/.env.example +96 -69
- package/template/server/.env.production.example +90 -0
- package/template/server/Dockerfile +94 -0
- package/template/server/docker-compose.yml +80 -111
- package/template/server/docs/logging.md +62 -0
- package/template/server/eslint.config.mjs +17 -0
- package/template/server/package.json +68 -81
- package/template/server/phpmyadmin-config.php +26 -0
- package/template/server/postman_collection.json +666 -0
- package/template/server/prisma/schema.prisma +77 -93
- package/template/server/prisma/seed.ts +46 -142
- package/template/server/scripts/flush-redis.ts +41 -0
- package/template/server/src/app.ts +243 -71
- package/template/server/src/config/env.ts +67 -94
- package/template/server/src/libs/auth.ts +88 -0
- package/template/server/src/libs/cleanup.ts +35 -0
- package/template/server/src/libs/cookies.ts +46 -0
- package/template/server/src/libs/logger.ts +33 -60
- package/template/server/src/libs/monitoring.ts +205 -0
- package/template/server/src/libs/password.ts +38 -0
- package/template/server/src/libs/prisma.ts +68 -0
- package/template/server/src/libs/redis.ts +60 -79
- package/template/server/src/libs/requestLogger.ts +66 -0
- package/template/server/src/libs/storage/file-storage.service.ts +211 -0
- package/template/server/src/libs/storage/file-validator.ts +97 -0
- package/template/server/src/libs/storage/filename-sanitizer.ts +71 -0
- package/template/server/src/libs/storage/image-optimizer.service.ts +144 -0
- package/template/server/src/modules/auth/__tests__/auth.service.test.ts +365 -0
- package/template/server/src/modules/auth/auth.controller.ts +90 -141
- package/template/server/src/modules/auth/auth.repo.ts +120 -218
- package/template/server/src/modules/auth/auth.routes.ts +96 -83
- package/template/server/src/modules/auth/auth.schemas.ts +35 -137
- package/template/server/src/modules/auth/auth.service.ts +286 -329
- package/template/server/src/modules/auth/session.repo.ts +110 -0
- package/template/server/src/modules/users/users.controller.ts +120 -0
- package/template/server/src/modules/users/users.repo.ts +77 -0
- package/template/server/src/modules/users/users.routes.ts +89 -0
- package/template/server/src/modules/users/users.schemas.ts +21 -0
- package/template/server/src/modules/users/users.service.ts +169 -0
- package/template/server/src/server.ts +58 -139
- package/template/server/src/shared/errors/AppError.ts +21 -0
- package/template/server/src/shared/errors/errors.ts +43 -0
- package/template/server/src/shared/responses/paginatedResponse.ts +38 -0
- package/template/server/src/shared/responses/successResponse.ts +17 -0
- package/template/server/src/shared/schemas/pagination.schema.ts +12 -0
- package/template/server/src/shared/types/index.ts +26 -0
- package/template/server/src/test/setup.ts +74 -38
- package/template/server/tsconfig.json +27 -89
- package/template/server/uploads/avatars/.gitkeep +1 -0
- package/template/server/vitest.config.ts +43 -98
- package/template/.agent/rules/client/01-project-structure.md +0 -326
- package/template/.agent/rules/client/02-component-patterns.md +0 -249
- package/template/.agent/rules/client/03-typescript-rules.md +0 -226
- package/template/.agent/rules/client/04-state-management.md +0 -474
- package/template/.agent/rules/client/05-api-integration.md +0 -129
- package/template/.agent/rules/client/06-forms-validation.md +0 -129
- package/template/.agent/rules/client/07-common-patterns.md +0 -150
- package/template/.agent/rules/client/08-color-system.md +0 -93
- package/template/.agent/rules/client/09-security-rules.md +0 -97
- package/template/.agent/rules/client/10-testing-strategy.md +0 -370
- package/template/.agent/rules/global/ai-edit-safety.md +0 -38
- package/template/.agent/rules/server/01-db-and-migrations.md +0 -242
- package/template/.agent/rules/server/02-general-rules.md +0 -111
- package/template/.agent/rules/server/03-migrations.md +0 -20
- package/template/.agent/rules/server/04-pagination.md +0 -130
- package/template/.agent/rules/server/05-project-conventions.md +0 -71
- package/template/.agent/rules/server/06-response-handling.md +0 -173
- package/template/.agent/rules/server/07-testing-strategy.md +0 -506
- package/template/.agent/rules/server/08-observability.md +0 -180
- package/template/.agent/rules/server/10-background-jobs-v2.md +0 -185
- package/template/.agent/rules/server/11-rate-limiting-v2.md +0 -210
- package/template/.agent/rules/server/12-performance-optimization.md +0 -567
- package/template/.claude/rules/client-01-project-structure.md +0 -327
- package/template/.claude/rules/client-02-component-patterns.md +0 -250
- package/template/.claude/rules/client-03-typescript-rules.md +0 -227
- package/template/.claude/rules/client-04-state-management.md +0 -475
- package/template/.claude/rules/client-05-api-integration.md +0 -130
- package/template/.claude/rules/client-06-forms-validation.md +0 -130
- package/template/.claude/rules/client-07-common-patterns.md +0 -151
- package/template/.claude/rules/client-08-color-system.md +0 -94
- package/template/.claude/rules/client-09-security-rules.md +0 -98
- package/template/.claude/rules/client-10-testing-strategy.md +0 -371
- package/template/.claude/rules/global-ai-edit-safety.md +0 -39
- package/template/.claude/rules/server-01-db-and-migrations.md +0 -243
- package/template/.claude/rules/server-02-general-rules.md +0 -112
- package/template/.claude/rules/server-03-migrations.md +0 -21
- package/template/.claude/rules/server-04-pagination.md +0 -131
- package/template/.claude/rules/server-05-project-conventions.md +0 -72
- package/template/.claude/rules/server-06-response-handling.md +0 -174
- package/template/.claude/rules/server-07-testing-strategy.md +0 -507
- package/template/.claude/rules/server-08-observability.md +0 -181
- package/template/.claude/rules/server-10-background-jobs-v2.md +0 -186
- package/template/.claude/rules/server-11-rate-limiting-v2.md +0 -211
- package/template/.claude/rules/server-12-performance-optimization.md +0 -568
- package/template/.cursor/rules/client-01-project-structure.mdc +0 -327
- package/template/.cursor/rules/client-02-component-patterns.mdc +0 -250
- package/template/.cursor/rules/client-03-typescript-rules.mdc +0 -227
- package/template/.cursor/rules/client-04-state-management.mdc +0 -475
- package/template/.cursor/rules/client-05-api-integration.mdc +0 -130
- package/template/.cursor/rules/client-06-forms-validation.mdc +0 -130
- package/template/.cursor/rules/client-07-common-patterns.mdc +0 -151
- package/template/.cursor/rules/client-08-color-system.mdc +0 -94
- package/template/.cursor/rules/client-09-security-rules.mdc +0 -98
- package/template/.cursor/rules/client-10-testing-strategy.mdc +0 -371
- package/template/.cursor/rules/global-ai-edit-safety.mdc +0 -39
- package/template/.cursor/rules/server-01-db-and-migrations.mdc +0 -243
- package/template/.cursor/rules/server-02-general-rules.mdc +0 -112
- package/template/.cursor/rules/server-03-migrations.mdc +0 -21
- package/template/.cursor/rules/server-04-pagination.mdc +0 -131
- package/template/.cursor/rules/server-05-project-conventions.mdc +0 -72
- package/template/.cursor/rules/server-06-response-handling.mdc +0 -174
- package/template/.cursor/rules/server-07-testing-strategy.mdc +0 -507
- package/template/.cursor/rules/server-08-observability.mdc +0 -181
- package/template/.cursor/rules/server-09-api-documentation-v2.mdc +0 -169
- package/template/.cursor/rules/server-10-background-jobs-v2.mdc +0 -186
- package/template/.cursor/rules/server-11-rate-limiting-v2.mdc +0 -211
- package/template/.cursor/rules/server-12-performance-optimization.mdc +0 -568
- package/template/CLAUDE.md +0 -207
- package/template/server/.tsc-aliasrc.json +0 -12
- package/template/server/README.md +0 -183
- package/template/server/SECURITY.md +0 -190
- package/template/server/Tigra-API.postman_collection.json +0 -733
- package/template/server/biome.json +0 -42
- package/template/server/scripts/setup-env.js +0 -50
- package/template/server/scripts/wait-for-db.js +0 -60
- package/template/server/src/hooks/request-timing.hook.ts +0 -26
- package/template/server/src/libs/auth/authenticate.middleware.ts +0 -22
- package/template/server/src/libs/auth/rbac.middleware.test.ts +0 -134
- package/template/server/src/libs/auth/rbac.middleware.ts +0 -147
- package/template/server/src/libs/db.ts +0 -76
- package/template/server/src/libs/error-handler.ts +0 -89
- package/template/server/src/libs/queue.ts +0 -79
- package/template/server/src/modules/admin/admin.controller.ts +0 -122
- package/template/server/src/modules/admin/admin.routes.ts +0 -62
- package/template/server/src/modules/admin/admin.schemas.ts +0 -35
- package/template/server/src/modules/admin/admin.service.ts +0 -167
- package/template/server/src/modules/auth/auth.integration.test.ts +0 -150
- package/template/server/src/modules/auth/auth.service.test.ts +0 -119
- package/template/server/src/modules/auth/auth.types.ts +0 -97
- package/template/server/src/modules/resources/resources.controller.ts +0 -218
- package/template/server/src/modules/resources/resources.repo.ts +0 -253
- package/template/server/src/modules/resources/resources.routes.ts +0 -116
- package/template/server/src/modules/resources/resources.schemas.ts +0 -146
- package/template/server/src/modules/resources/resources.service.ts +0 -218
- package/template/server/src/modules/resources/resources.types.ts +0 -73
- package/template/server/src/plugins/rate-limit.plugin.ts +0 -21
- package/template/server/src/plugins/security.plugin.ts +0 -21
- package/template/server/src/routes/health.routes.ts +0 -31
- package/template/server/src/types/fastify.d.ts +0 -36
- package/template/server/src/utils/errors.ts +0 -108
- package/template/server/src/utils/pagination.ts +0 -120
- package/template/server/src/utils/response.ts +0 -110
- package/template/server/src/workers/file.worker.ts +0 -106
- package/template/server/tsconfig.build.json +0 -30
- package/template/server/tsconfig.test.json +0 -22
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Handling Utilities
|
|
3
|
-
*
|
|
4
|
-
* All errors thrown in the application MUST extend AppError.
|
|
5
|
-
* This ensures consistent error responses across the API.
|
|
6
|
-
*
|
|
7
|
-
* @see /mnt/project/06-response-handling.md
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Base error class for all application errors
|
|
12
|
-
*
|
|
13
|
-
* @property {number} statusCode - HTTP status code
|
|
14
|
-
* @property {string} code - Machine-readable error code
|
|
15
|
-
* @property {string} message - Human-readable error message
|
|
16
|
-
*/
|
|
17
|
-
export class AppError extends Error {
|
|
18
|
-
public readonly statusCode: number;
|
|
19
|
-
public readonly code: string;
|
|
20
|
-
public readonly isOperational: boolean;
|
|
21
|
-
|
|
22
|
-
constructor(message: string, statusCode: number, code: string) {
|
|
23
|
-
super(message);
|
|
24
|
-
|
|
25
|
-
this.statusCode = statusCode;
|
|
26
|
-
this.code = code;
|
|
27
|
-
this.isOperational = true;
|
|
28
|
-
|
|
29
|
-
// Maintains proper stack trace for where error was thrown (V8 only)
|
|
30
|
-
Error.captureStackTrace(this, this.constructor);
|
|
31
|
-
|
|
32
|
-
// Set the prototype explicitly for instanceof checks
|
|
33
|
-
Object.setPrototypeOf(this, AppError.prototype);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 400 Bad Request
|
|
39
|
-
* Use when client sends invalid data or malformed requests
|
|
40
|
-
*/
|
|
41
|
-
export class BadRequestError extends AppError {
|
|
42
|
-
constructor(message = 'Bad request') {
|
|
43
|
-
super(message, 400, 'BAD_REQUEST');
|
|
44
|
-
Object.setPrototypeOf(this, BadRequestError.prototype);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 401 Unauthorized
|
|
50
|
-
* Use when authentication is required but missing or invalid
|
|
51
|
-
*/
|
|
52
|
-
export class UnauthorizedError extends AppError {
|
|
53
|
-
constructor(message = 'Unauthorized') {
|
|
54
|
-
super(message, 401, 'UNAUTHORIZED');
|
|
55
|
-
Object.setPrototypeOf(this, UnauthorizedError.prototype);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 403 Forbidden
|
|
61
|
-
* Use when user is authenticated but lacks permission
|
|
62
|
-
*/
|
|
63
|
-
export class ForbiddenError extends AppError {
|
|
64
|
-
constructor(message = 'Forbidden') {
|
|
65
|
-
super(message, 403, 'FORBIDDEN');
|
|
66
|
-
Object.setPrototypeOf(this, ForbiddenError.prototype);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* 404 Not Found
|
|
72
|
-
* Use when requested resource does not exist
|
|
73
|
-
*/
|
|
74
|
-
export class NotFoundError extends AppError {
|
|
75
|
-
constructor(message = 'Resource not found') {
|
|
76
|
-
super(message, 404, 'NOT_FOUND');
|
|
77
|
-
Object.setPrototypeOf(this, NotFoundError.prototype);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 409 Conflict
|
|
83
|
-
* Use when request conflicts with current state (e.g., duplicate email)
|
|
84
|
-
*/
|
|
85
|
-
export class ConflictError extends AppError {
|
|
86
|
-
constructor(message = 'Conflict') {
|
|
87
|
-
super(message, 409, 'CONFLICT');
|
|
88
|
-
Object.setPrototypeOf(this, ConflictError.prototype);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 500 Internal Server Error
|
|
94
|
-
* Use for unexpected server errors
|
|
95
|
-
*/
|
|
96
|
-
export class InternalError extends AppError {
|
|
97
|
-
constructor(message = 'Internal server error') {
|
|
98
|
-
super(message, 500, 'INTERNAL_ERROR');
|
|
99
|
-
Object.setPrototypeOf(this, InternalError.prototype);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Type guard to check if error is an AppError
|
|
105
|
-
*/
|
|
106
|
-
export function isAppError(error: unknown): error is AppError {
|
|
107
|
-
return error instanceof AppError;
|
|
108
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pagination Utilities
|
|
3
|
-
*
|
|
4
|
-
* Unified pagination response format for all paginated API endpoints.
|
|
5
|
-
* This ensures consistent pagination structure across the entire API.
|
|
6
|
-
*
|
|
7
|
-
* @see /mnt/project/04-pagination.md
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Pagination metadata structure
|
|
12
|
-
*
|
|
13
|
-
* MANDATORY format - DO NOT modify
|
|
14
|
-
*/
|
|
15
|
-
export interface PaginationMeta {
|
|
16
|
-
page: number;
|
|
17
|
-
limit: number;
|
|
18
|
-
totalItems: number;
|
|
19
|
-
totalPages: number;
|
|
20
|
-
hasNextPage: boolean;
|
|
21
|
-
hasPreviousPage: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Paginated response structure
|
|
26
|
-
*
|
|
27
|
-
* MANDATORY format - DO NOT modify
|
|
28
|
-
*/
|
|
29
|
-
export interface PaginatedResponse<T = any> {
|
|
30
|
-
success: true;
|
|
31
|
-
message: string;
|
|
32
|
-
data: {
|
|
33
|
-
items: T[];
|
|
34
|
-
pagination: PaginationMeta;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Creates a standardized paginated response
|
|
40
|
-
*
|
|
41
|
-
* @param message - Human-readable success message
|
|
42
|
-
* @param items - Array of items for current page
|
|
43
|
-
* @param page - Current page number (1-indexed)
|
|
44
|
-
* @param limit - Items per page
|
|
45
|
-
* @param totalItems - Total count of items across all pages
|
|
46
|
-
* @returns Standardized paginated response object
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* // In controller
|
|
50
|
-
* const { items, totalItems } = await resourceService.getResources(filters, page, limit);
|
|
51
|
-
* return reply.send(
|
|
52
|
-
* paginatedResponse('Resources retrieved successfully', items, page, limit, totalItems)
|
|
53
|
-
* );
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* // Response format
|
|
57
|
-
* {
|
|
58
|
-
* "success": true,
|
|
59
|
-
* "message": "Resources retrieved successfully",
|
|
60
|
-
* "data": {
|
|
61
|
-
* "items": [...],
|
|
62
|
-
* "pagination": {
|
|
63
|
-
* "page": 2,
|
|
64
|
-
* "limit": 10,
|
|
65
|
-
* "totalItems": 237,
|
|
66
|
-
* "totalPages": 24,
|
|
67
|
-
* "hasNextPage": true,
|
|
68
|
-
* "hasPreviousPage": true
|
|
69
|
-
* }
|
|
70
|
-
* }
|
|
71
|
-
* }
|
|
72
|
-
*/
|
|
73
|
-
export function paginatedResponse<T = any>(
|
|
74
|
-
message: string,
|
|
75
|
-
items: T[],
|
|
76
|
-
page: number,
|
|
77
|
-
limit: number,
|
|
78
|
-
totalItems: number
|
|
79
|
-
): PaginatedResponse<T> {
|
|
80
|
-
// Calculate total pages (always round up)
|
|
81
|
-
const totalPages = Math.ceil(totalItems / limit);
|
|
82
|
-
|
|
83
|
-
// Calculate navigation flags
|
|
84
|
-
const hasNextPage = page < totalPages;
|
|
85
|
-
const hasPreviousPage = page > 1;
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
success: true,
|
|
89
|
-
message,
|
|
90
|
-
data: {
|
|
91
|
-
items,
|
|
92
|
-
pagination: {
|
|
93
|
-
page,
|
|
94
|
-
limit,
|
|
95
|
-
totalItems,
|
|
96
|
-
totalPages,
|
|
97
|
-
hasNextPage,
|
|
98
|
-
hasPreviousPage,
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Calculates offset for database queries
|
|
106
|
-
*
|
|
107
|
-
* @param page - Current page number (1-indexed)
|
|
108
|
-
* @param limit - Items per page
|
|
109
|
-
* @returns Offset value for database skip/offset
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* const offset = calculateOffset(page, limit);
|
|
113
|
-
* const items = await prisma.resource.findMany({
|
|
114
|
-
* skip: offset,
|
|
115
|
-
* take: limit,
|
|
116
|
-
* });
|
|
117
|
-
*/
|
|
118
|
-
export function calculateOffset(page: number, limit: number): number {
|
|
119
|
-
return (page - 1) * limit;
|
|
120
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Response Utilities
|
|
3
|
-
*
|
|
4
|
-
* Unified success response format for all API endpoints.
|
|
5
|
-
* This ensures consistent response structure across the entire API.
|
|
6
|
-
*
|
|
7
|
-
* @see /mnt/project/06-response-handling.md
|
|
8
|
-
* @see /mnt/project/04-pagination.md
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Success response structure
|
|
13
|
-
*
|
|
14
|
-
* MANDATORY format - DO NOT modify
|
|
15
|
-
*/
|
|
16
|
-
export interface SuccessResponse<T = any> {
|
|
17
|
-
success: true;
|
|
18
|
-
message: string;
|
|
19
|
-
data: T;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Paginated response structure
|
|
24
|
-
*
|
|
25
|
-
* MANDATORY format - DO NOT modify
|
|
26
|
-
*/
|
|
27
|
-
export interface PaginatedResponse<T = any> {
|
|
28
|
-
success: true;
|
|
29
|
-
message: string;
|
|
30
|
-
data: {
|
|
31
|
-
items: T[];
|
|
32
|
-
pagination: {
|
|
33
|
-
page: number;
|
|
34
|
-
limit: number;
|
|
35
|
-
totalItems: number;
|
|
36
|
-
totalPages: number;
|
|
37
|
-
hasNextPage: boolean;
|
|
38
|
-
hasPreviousPage: boolean;
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Creates a standardized success response
|
|
45
|
-
*
|
|
46
|
-
* @param message - Human-readable success message
|
|
47
|
-
* @param data - Response payload (object, array, or null)
|
|
48
|
-
* @returns Standardized success response object
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* // Simple success
|
|
52
|
-
* return reply.send(successResponse('User created successfully', user));
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* // With null data
|
|
56
|
-
* return reply.send(successResponse('Deleted successfully', null));
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* // With array data
|
|
60
|
-
* return reply.send(successResponse('Users retrieved', users));
|
|
61
|
-
*/
|
|
62
|
-
export function successResponse<T = any>(
|
|
63
|
-
message: string,
|
|
64
|
-
data: T
|
|
65
|
-
): SuccessResponse<T> {
|
|
66
|
-
return {
|
|
67
|
-
success: true,
|
|
68
|
-
message,
|
|
69
|
-
data,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Creates a standardized paginated response
|
|
75
|
-
*
|
|
76
|
-
* @param message - Human-readable success message
|
|
77
|
-
* @param items - Array of items for current page
|
|
78
|
-
* @param page - Current page number (1-indexed)
|
|
79
|
-
* @param limit - Items per page
|
|
80
|
-
* @param totalItems - Total count of items across all pages
|
|
81
|
-
* @returns Standardized paginated response object
|
|
82
|
-
*
|
|
83
|
-
* @example
|
|
84
|
-
* return reply.send(paginatedResponse('Users retrieved', users, 1, 10, 237));
|
|
85
|
-
*/
|
|
86
|
-
export function paginatedResponse<T = any>(
|
|
87
|
-
message: string,
|
|
88
|
-
items: T[],
|
|
89
|
-
page: number,
|
|
90
|
-
limit: number,
|
|
91
|
-
totalItems: number
|
|
92
|
-
): PaginatedResponse<T> {
|
|
93
|
-
const totalPages = Math.ceil(totalItems / limit);
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
success: true,
|
|
97
|
-
message,
|
|
98
|
-
data: {
|
|
99
|
-
items,
|
|
100
|
-
pagination: {
|
|
101
|
-
page,
|
|
102
|
-
limit,
|
|
103
|
-
totalItems,
|
|
104
|
-
totalPages,
|
|
105
|
-
hasNextPage: page < totalPages,
|
|
106
|
-
hasPreviousPage: page > 1,
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File Processing Background Worker
|
|
3
|
-
*
|
|
4
|
-
* Process jobs from the 'files' queue.
|
|
5
|
-
* Reference implementation for background job processing.
|
|
6
|
-
*
|
|
7
|
-
* @see /mnt/project/10-background-jobs-v2.md
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Worker, Job } from 'bullmq';
|
|
11
|
-
import { redis } from '@/libs/redis';
|
|
12
|
-
import logger from '@/libs/logger';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Data structure for file processing jobs
|
|
17
|
-
*/
|
|
18
|
-
export interface FileJobData {
|
|
19
|
-
fileId: string;
|
|
20
|
-
path: string;
|
|
21
|
-
operation: 'thumbnail' | 'compress' | 'convert';
|
|
22
|
-
options?: Record<string, any>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Mock file processor
|
|
27
|
-
* In a real app, this would use sharp, ffmpeg, etc.
|
|
28
|
-
*/
|
|
29
|
-
async function processFile(data: FileJobData): Promise<void> {
|
|
30
|
-
const { fileId, operation } = data;
|
|
31
|
-
|
|
32
|
-
// Simulate processing time
|
|
33
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
34
|
-
|
|
35
|
-
logger.info({ fileId, operation }, 'File successfully processed');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* File Worker Implementation
|
|
40
|
-
*
|
|
41
|
-
* Processes files in the background with:
|
|
42
|
-
* - Rate limit of 100 jobs per minute
|
|
43
|
-
* - Concurrency of 5 jobs at a time
|
|
44
|
-
*/
|
|
45
|
-
export const fileWorker = new Worker<FileJobData>(
|
|
46
|
-
'files',
|
|
47
|
-
async (job: Job<FileJobData>) => {
|
|
48
|
-
const { fileId, operation } = job.data;
|
|
49
|
-
|
|
50
|
-
logger.info({ jobId: job.id, fileId, operation }, 'Processing file job');
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
await processFile(job.data);
|
|
54
|
-
return { success: true, processedAt: new Date().toISOString() };
|
|
55
|
-
} catch (error) {
|
|
56
|
-
logger.error(
|
|
57
|
-
{
|
|
58
|
-
jobId: job.id,
|
|
59
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
60
|
-
},
|
|
61
|
-
'Failed to process file'
|
|
62
|
-
);
|
|
63
|
-
throw error;
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
connection: redis as any,
|
|
68
|
-
concurrency: 5,
|
|
69
|
-
limiter: {
|
|
70
|
-
max: 100,
|
|
71
|
-
duration: 60000,
|
|
72
|
-
},
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Worker Event Listeners
|
|
78
|
-
*/
|
|
79
|
-
fileWorker.on('completed', (job) => {
|
|
80
|
-
logger.info({ jobId: job.id, queue: 'files' }, 'File job completed');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
fileWorker.on('failed', (job, error) => {
|
|
84
|
-
logger.error(
|
|
85
|
-
{
|
|
86
|
-
jobId: job?.id,
|
|
87
|
-
queue: 'files',
|
|
88
|
-
error: error.message,
|
|
89
|
-
},
|
|
90
|
-
'File job failed'
|
|
91
|
-
);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Graceful Shutdown
|
|
96
|
-
*/
|
|
97
|
-
const shutdownWorker = async (signal: string) => {
|
|
98
|
-
logger.info(`Received ${signal}, closing file worker...`);
|
|
99
|
-
await fileWorker.close();
|
|
100
|
-
process.exit(0);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
process.on('SIGTERM', () => shutdownWorker('SIGTERM'));
|
|
104
|
-
process.on('SIGINT', () => shutdownWorker('SIGINT'));
|
|
105
|
-
|
|
106
|
-
logger.info('File worker initialized and listening for jobs');
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ES2022",
|
|
5
|
-
"lib": ["ES2022"],
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"removeComments": true,
|
|
9
|
-
"strict": false,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"declaration": false,
|
|
15
|
-
"sourceMap": false,
|
|
16
|
-
"incremental": true,
|
|
17
|
-
"types": [],
|
|
18
|
-
"baseUrl": ".",
|
|
19
|
-
"paths": {
|
|
20
|
-
"@/*": ["src/*"],
|
|
21
|
-
"@/config/*": ["src/config/*"],
|
|
22
|
-
"@/libs/*": ["src/libs/*"],
|
|
23
|
-
"@/modules/*": ["src/modules/*"],
|
|
24
|
-
"@/utils/*": ["src/utils/*"],
|
|
25
|
-
"@/types/*": ["src/types/*"]
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"include": ["src/**/*.ts"],
|
|
29
|
-
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
|
30
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ES2022",
|
|
5
|
-
"lib": [
|
|
6
|
-
"ES2022"
|
|
7
|
-
],
|
|
8
|
-
"outDir": "./dist",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"moduleResolution": "bundler",
|
|
15
|
-
"noEmit": true
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"src/utils/errors.ts",
|
|
19
|
-
"src/utils/response.ts",
|
|
20
|
-
"src/utils/pagination.ts"
|
|
21
|
-
]
|
|
22
|
-
}
|