create-pnpm-custom-app 1.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.
Files changed (77) hide show
  1. package/README.md +217 -0
  2. package/bin/cli.js +185 -0
  3. package/package.json +39 -0
  4. package/templates/.github/copilot-instructions.md +184 -0
  5. package/templates/.nvmrc +1 -0
  6. package/templates/.vscode/settings.json +51 -0
  7. package/templates/CONTRIBUTING.md +184 -0
  8. package/templates/LICENSE +21 -0
  9. package/templates/README.md +324 -0
  10. package/templates/apps/api/.env.example +36 -0
  11. package/templates/apps/api/.prettierrc.json +7 -0
  12. package/templates/apps/api/eslint.config.js +17 -0
  13. package/templates/apps/api/gitignore +45 -0
  14. package/templates/apps/api/jest.config.ts +22 -0
  15. package/templates/apps/api/package.json +49 -0
  16. package/templates/apps/api/src/app.ts +121 -0
  17. package/templates/apps/api/src/config/config.ts +38 -0
  18. package/templates/apps/api/src/config/logger.ts +57 -0
  19. package/templates/apps/api/src/db/mongo.ts +30 -0
  20. package/templates/apps/api/src/index.ts +40 -0
  21. package/templates/apps/api/src/middlewares/middleware.ts +75 -0
  22. package/templates/apps/api/src/models/example.model.ts +89 -0
  23. package/templates/apps/api/src/routes/routes.ts +54 -0
  24. package/templates/apps/api/src/schemas/swagger.schema.ts +58 -0
  25. package/templates/apps/api/src/services/example.service.ts +63 -0
  26. package/templates/apps/api/src/tests/health.test.ts +90 -0
  27. package/templates/apps/api/src/tests/helpers/test-helpers.ts +40 -0
  28. package/templates/apps/api/src/tests/mocks/mocks.ts +29 -0
  29. package/templates/apps/api/src/tests/setup.ts +11 -0
  30. package/templates/apps/api/src/types/fastify.d.ts +44 -0
  31. package/templates/apps/api/tsconfig.json +24 -0
  32. package/templates/apps/web/.env.example +25 -0
  33. package/templates/apps/web/.prettierignore +7 -0
  34. package/templates/apps/web/.prettierrc +9 -0
  35. package/templates/apps/web/app/ICONS.md +42 -0
  36. package/templates/apps/web/app/[locale]/(routes)/layout.tsx +13 -0
  37. package/templates/apps/web/app/[locale]/(routes)/page.tsx +49 -0
  38. package/templates/apps/web/app/[locale]/[...not-found]/page.tsx +8 -0
  39. package/templates/apps/web/app/[locale]/layout.tsx +35 -0
  40. package/templates/apps/web/app/[locale]/not-found.tsx +12 -0
  41. package/templates/apps/web/app/components/layout/Footer.component.tsx +30 -0
  42. package/templates/apps/web/app/components/layout/Nav.component.tsx +34 -0
  43. package/templates/apps/web/app/components/ui/README.md +39 -0
  44. package/templates/apps/web/app/components/ui/atoms/README.md +55 -0
  45. package/templates/apps/web/app/components/ui/molecules/README.md +51 -0
  46. package/templates/apps/web/app/globals.css +104 -0
  47. package/templates/apps/web/app/icon.svg +5 -0
  48. package/templates/apps/web/app/layout.tsx +37 -0
  49. package/templates/apps/web/app/manifest.json +22 -0
  50. package/templates/apps/web/app/providers.tsx +25 -0
  51. package/templates/apps/web/app/robots.ts +12 -0
  52. package/templates/apps/web/app/sitemap.ts +18 -0
  53. package/templates/apps/web/eslint.config.mjs +16 -0
  54. package/templates/apps/web/gitignore +56 -0
  55. package/templates/apps/web/hooks/README.md +25 -0
  56. package/templates/apps/web/i18n/config.ts +9 -0
  57. package/templates/apps/web/i18n/request.ts +15 -0
  58. package/templates/apps/web/interfaces/README.md +5 -0
  59. package/templates/apps/web/lib/README.md +45 -0
  60. package/templates/apps/web/lib/utils.ts +18 -0
  61. package/templates/apps/web/messages/en.json +34 -0
  62. package/templates/apps/web/messages/es.json +34 -0
  63. package/templates/apps/web/next.config.ts +50 -0
  64. package/templates/apps/web/package.json +34 -0
  65. package/templates/apps/web/postcss.config.mjs +7 -0
  66. package/templates/apps/web/proxy.ts +17 -0
  67. package/templates/apps/web/public/README.md +7 -0
  68. package/templates/apps/web/tsconfig.json +27 -0
  69. package/templates/apps/web/types/README.md +3 -0
  70. package/templates/docs/README.md +13 -0
  71. package/templates/gitignore-root +51 -0
  72. package/templates/package.json +30 -0
  73. package/templates/packages/shared/eslint.config.js +26 -0
  74. package/templates/packages/shared/package.json +22 -0
  75. package/templates/packages/shared/src/index.ts +39 -0
  76. package/templates/packages/shared/tsconfig.json +19 -0
  77. package/templates/pnpm-workspace.yaml +3 -0
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@{{PROJECT_NAME}}/api",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "tsx watch src/index.ts",
8
+ "build": "tsc",
9
+ "start": "node dist/index.js",
10
+ "test": "NODE_ENV=test node --experimental-vm-modules node_modules/jest/bin/jest.js",
11
+ "test:watch": "NODE_ENV=test node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
12
+ "test:coverage": "NODE_ENV=test node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
13
+ "lint": "eslint src --ext .ts"
14
+ },
15
+ "dependencies": {
16
+ "@fastify/cors": "^10.0.1",
17
+ "@fastify/jwt": "^9.0.1",
18
+ "@fastify/multipart": "^9.0.1",
19
+ "@fastify/rate-limit": "^10.1.1",
20
+ "@fastify/swagger": "^9.3.0",
21
+ "@fastify/swagger-ui": "^5.0.1",
22
+ "@{{PROJECT_NAME}}/shared": "workspace:*",
23
+ "bcrypt": "^5.1.1",
24
+ "dotenv": "^16.4.7",
25
+ "fastify": "^5.2.0",
26
+ "mongoose": "^8.9.3",
27
+ "pino": "^9.5.0",
28
+ "pino-pretty": "^13.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@eslint/js": "^9.18.0",
32
+ "@jest/globals": "^29.7.0",
33
+ "@types/bcrypt": "^5.0.2",
34
+ "@types/jest": "^29.5.14",
35
+ "@types/node": "^22.10.5",
36
+ "@types/supertest": "^6.0.2",
37
+ "eslint": "^9.18.0",
38
+ "jest": "^29.7.0",
39
+ "supertest": "^7.0.0",
40
+ "ts-jest": "^29.2.5",
41
+ "ts-node": "^10.9.2",
42
+ "tsx": "^4.19.2",
43
+ "typescript": "^5.7.3",
44
+ "typescript-eslint": "^8.21.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=20.0.0"
48
+ }
49
+ }
@@ -0,0 +1,121 @@
1
+ import Fastify, { FastifyInstance } from 'fastify';
2
+ import cors from '@fastify/cors';
3
+ import jwt from '@fastify/jwt';
4
+ import rateLimit from '@fastify/rate-limit';
5
+ import multipart from '@fastify/multipart';
6
+ import swagger from '@fastify/swagger';
7
+ import swaggerUi from '@fastify/swagger-ui';
8
+ import routes from './routes/routes.js';
9
+ import config from './config/config.js';
10
+ import { getLoggerConfig } from './config/logger.js';
11
+
12
+ /**
13
+ * Registers CORS middleware
14
+ */
15
+ function registerCors(app: FastifyInstance) {
16
+ app.register(cors, {
17
+ origin: config.corsOrigin,
18
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
19
+ allowedHeaders: ['Content-Type', 'Authorization'],
20
+ credentials: true,
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Registers JWT authentication plugin
26
+ */
27
+ function registerJWT(app: FastifyInstance) {
28
+ if (!config.jwtSecret) {
29
+ throw new Error(
30
+ 'JWT_SECRET is not defined. Please copy apps/api/.env.example to apps/api/.env and set JWT_SECRET'
31
+ );
32
+ }
33
+
34
+ app.register(jwt, {
35
+ secret: config.jwtSecret,
36
+ sign: {
37
+ expiresIn: '24h',
38
+ },
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Registers rate limiting plugin
44
+ */
45
+ function registerRateLimit(app: FastifyInstance) {
46
+ if (config.env === 'test') {
47
+ return;
48
+ }
49
+
50
+ app.register(rateLimit, {
51
+ global: false,
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Registers Swagger documentation
57
+ */
58
+ async function registerSwagger(app: FastifyInstance) {
59
+ await app.register(swagger, {
60
+ openapi: {
61
+ openapi: '3.0.0',
62
+ info: {
63
+ title: '{{PROJECT_NAME}} API',
64
+ description: 'API documentation for {{PROJECT_NAME}}',
65
+ version: '1.0.0',
66
+ },
67
+ servers: [
68
+ {
69
+ url: `http://localhost:${config.port}`,
70
+ description: 'Development server',
71
+ },
72
+ ],
73
+ tags: [
74
+ { name: 'Health', description: 'Health check endpoints' },
75
+ ],
76
+ },
77
+ });
78
+
79
+ await app.register(swaggerUi, {
80
+ routePrefix: '/docs',
81
+ uiConfig: {
82
+ docExpansion: 'list',
83
+ deepLinking: true,
84
+ },
85
+ staticCSP: true,
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Registers file upload support
91
+ */
92
+ function registerMultipart(app: FastifyInstance) {
93
+ app.register(multipart, {
94
+ limits: {
95
+ fileSize: 10 * 1024 * 1024, // 10MB
96
+ },
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Builds and configures the Fastify application
102
+ *
103
+ * @returns Configured Fastify instance
104
+ */
105
+ export async function buildApp(): Promise<FastifyInstance> {
106
+ const app = Fastify({
107
+ logger: getLoggerConfig(),
108
+ });
109
+
110
+ // Register plugins
111
+ registerCors(app);
112
+ registerJWT(app);
113
+ registerRateLimit(app);
114
+ registerMultipart(app);
115
+ await registerSwagger(app);
116
+
117
+ // Register routes
118
+ await app.register(routes);
119
+
120
+ return app;
121
+ }
@@ -0,0 +1,38 @@
1
+ import dotenv from 'dotenv';
2
+
3
+ dotenv.config();
4
+
5
+ interface Config {
6
+ env: string;
7
+ port: number;
8
+ mongoUri: string;
9
+ corsOrigin: string;
10
+ bcryptRounds: number;
11
+ jwtSecret?: string;
12
+ }
13
+
14
+ const env = process.env.NODE_ENV ?? 'development';
15
+
16
+ /**
17
+ * Application configuration loaded from environment variables
18
+ *
19
+ * @remarks
20
+ * Required environment variables:
21
+ * - MONGODB_URI: MongoDB connection string
22
+ * - JWT_SECRET: Secret for JWT token signing
23
+ *
24
+ * Optional environment variables:
25
+ * - PORT: Server port (default: 3002)
26
+ * - CORS_ORIGIN: Allowed CORS origin (default: *)
27
+ * - BCRYPT_ROUNDS: Bcrypt hashing rounds (default: 10, 4 in test)
28
+ */
29
+ const config: Config = {
30
+ env,
31
+ port: Number(process.env.PORT) || 3002,
32
+ mongoUri: process.env.MONGODB_URI || '',
33
+ corsOrigin: process.env.CORS_ORIGIN || '*',
34
+ bcryptRounds: Number(process.env.BCRYPT_ROUNDS || (env === 'test' ? 4 : 10)),
35
+ jwtSecret: process.env.JWT_SECRET,
36
+ };
37
+
38
+ export default config;
@@ -0,0 +1,57 @@
1
+ import config from './config.js';
2
+ import pino from 'pino';
3
+
4
+ /**
5
+ * Returns logger configuration based on environment
6
+ *
7
+ * @returns Logger config or false to disable logging in test
8
+ *
9
+ * @remarks
10
+ * - Test/E2E: Logging disabled
11
+ * - Production: Structured JSON logs at 'info' level
12
+ * - Development: Pretty-printed colored logs at 'debug' level
13
+ */
14
+ export function getLoggerConfig(): false | object {
15
+ if (config.env === 'test' || process.env.E2E_MODE === 'true') {
16
+ return false;
17
+ }
18
+
19
+ if (config.env === 'production') {
20
+ return {
21
+ level: 'info',
22
+ serializers: {
23
+ req: (req: { method: string; url: string }) => ({
24
+ method: req.method,
25
+ url: req.url,
26
+ }),
27
+ res: (res: { statusCode: number }) => ({
28
+ statusCode: res.statusCode,
29
+ }),
30
+ },
31
+ };
32
+ }
33
+
34
+ return {
35
+ level: 'debug',
36
+ transport: {
37
+ target: 'pino-pretty',
38
+ options: {
39
+ colorize: true,
40
+ translateTime: 'HH:MM:ss',
41
+ ignore: 'pid,hostname,reqId',
42
+ },
43
+ },
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Application-wide logger instance using Pino
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * logger.info({ userId: '123' }, 'User logged in');
53
+ * logger.error({ error }, 'Failed to process request');
54
+ * logger.debug({ data }, 'Processing data');
55
+ * ```
56
+ */
57
+ export const logger = pino(getLoggerConfig() || { level: 'silent' });
@@ -0,0 +1,30 @@
1
+ import mongoose from 'mongoose';
2
+
3
+ /**
4
+ * Establishes connection to MongoDB
5
+ *
6
+ * @param uri - MongoDB connection URI
7
+ * @returns Mongoose connection object
8
+ * @throws Error if connection fails
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * await connectMongo('mongodb://localhost:27017/mydb');
13
+ * ```
14
+ */
15
+ export async function connectMongo(uri: string) {
16
+ mongoose.set('strictQuery', true);
17
+ await mongoose.connect(uri);
18
+ return mongoose.connection;
19
+ }
20
+
21
+ /**
22
+ * Disconnects from MongoDB
23
+ *
24
+ * @remarks
25
+ * Call this when shutting down the application or when database
26
+ * connection is no longer needed.
27
+ */
28
+ export async function disconnectMongo() {
29
+ await mongoose.disconnect();
30
+ }
@@ -0,0 +1,40 @@
1
+ import { buildApp } from './app.js';
2
+ import { connectMongo } from './db/mongo.js';
3
+ import config from './config/config.js';
4
+
5
+ /**
6
+ * Starts the API server
7
+ *
8
+ * - Connects to MongoDB
9
+ * - Starts the Fastify server on configured port
10
+ * - Logs server URL when ready
11
+ */
12
+ async function start() {
13
+ const app = await buildApp();
14
+
15
+ try {
16
+ if (!config.mongoUri) {
17
+ app.log.error(
18
+ 'MONGODB_URI is not defined. Please copy apps/api/.env.example to apps/api/.env and set MONGODB_URI'
19
+ );
20
+ process.exit(1);
21
+ }
22
+
23
+ await connectMongo(config.mongoUri);
24
+ app.log.info('MongoDB connected successfully');
25
+
26
+ await app.listen({ port: config.port, host: '0.0.0.0' });
27
+ app.log.info(`🚀 API server listening on http://localhost:${config.port}`);
28
+ app.log.info(`📚 API documentation available at http://localhost:${config.port}/docs`);
29
+ } catch (error) {
30
+ app.log.error(error);
31
+ process.exit(1);
32
+ }
33
+ }
34
+
35
+ // Only start server if not in test environment
36
+ if (config.env !== 'test') {
37
+ start();
38
+ }
39
+
40
+ export { buildApp };
@@ -0,0 +1,75 @@
1
+ import { FastifyRequest, FastifyReply } from 'fastify';
2
+
3
+ /**
4
+ * Example Middleware
5
+ *
6
+ * Middlewares (preHandlers in Fastify) run before route handlers.
7
+ * They can modify requests, perform authentication, logging, etc.
8
+ *
9
+ * @remarks
10
+ * Common middleware uses:
11
+ * - Authentication/Authorization
12
+ * - Request validation
13
+ * - Logging
14
+ * - Rate limiting
15
+ * - Request transformation
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Authentication Middleware
20
+ * export async function authenticate(
21
+ * request: FastifyRequest,
22
+ * reply: FastifyReply
23
+ * ) {
24
+ * try {
25
+ * await request.jwtVerify();
26
+ * } catch (err) {
27
+ * reply.status(401).send({ error: 'Unauthorized' });
28
+ * }
29
+ * }
30
+ *
31
+ * // Admin Check Middleware
32
+ * export async function requireAdmin(
33
+ * request: FastifyRequest,
34
+ * reply: FastifyReply
35
+ * ) {
36
+ * if (request.user?.role !== 'admin') {
37
+ * reply.status(403).send({ error: 'Forbidden: Admin access required' });
38
+ * }
39
+ * }
40
+ * ```
41
+ *
42
+ * Usage in routes:
43
+ * ```typescript
44
+ * app.get('/admin/users', {
45
+ * preHandler: [authenticate, requireAdmin],
46
+ * handler: async (request, reply) => {
47
+ * // Only authenticated admins reach here
48
+ * },
49
+ * });
50
+ * ```
51
+ *
52
+ * Or register globally:
53
+ * ```typescript
54
+ * app.addHook('preHandler', authenticate);
55
+ * ```
56
+ */
57
+
58
+ export async function exampleMiddleware(
59
+ request: FastifyRequest,
60
+ _reply: FastifyReply
61
+ ) {
62
+ // Example: Log all requests
63
+ request.log.info(`${request.method} ${request.url}`);
64
+ }
65
+
66
+ export async function authenticate(
67
+ request: FastifyRequest,
68
+ reply: FastifyReply
69
+ ) {
70
+ try {
71
+ await request.jwtVerify();
72
+ } catch {
73
+ reply.status(401).send({ error: 'Unauthorized' });
74
+ }
75
+ }
@@ -0,0 +1,89 @@
1
+ import mongoose, { Schema, Document } from 'mongoose';
2
+
3
+ /**
4
+ * Example Mongoose Model
5
+ *
6
+ * Models define the structure of documents in MongoDB collections.
7
+ * They provide an interface for database operations.
8
+ *
9
+ * @remarks
10
+ * Model best practices:
11
+ * - Define TypeScript interfaces for type safety
12
+ * - Use Mongoose Schema for MongoDB structure
13
+ * - Add indexes for frequently queried fields
14
+ * - Include timestamps for audit trail
15
+ * - Add schema validation
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // User Model Example
20
+ * import mongoose, { Schema, Document } from 'mongoose';
21
+ *
22
+ * export interface IUser extends Document {
23
+ * email: string;
24
+ * password: string;
25
+ * name: string;
26
+ * role: 'user' | 'admin';
27
+ * createdAt: Date;
28
+ * updatedAt: Date;
29
+ * }
30
+ *
31
+ * const UserSchema = new Schema<IUser>(
32
+ * {
33
+ * email: {
34
+ * type: String,
35
+ * required: true,
36
+ * unique: true,
37
+ * lowercase: true,
38
+ * trim: true,
39
+ * },
40
+ * password: {
41
+ * type: String,
42
+ * required: true,
43
+ * },
44
+ * name: {
45
+ * type: String,
46
+ * required: true,
47
+ * trim: true,
48
+ * },
49
+ * role: {
50
+ * type: String,
51
+ * enum: ['user', 'admin'],
52
+ * default: 'user',
53
+ * },
54
+ * },
55
+ * {
56
+ * timestamps: true, // Adds createdAt and updatedAt
57
+ * }
58
+ * );
59
+ *
60
+ * // Add indexes
61
+ * UserSchema.index({ email: 1 });
62
+ *
63
+ * export const User = mongoose.model<IUser>('User', UserSchema);
64
+ * ```
65
+ */
66
+
67
+ export interface IExample extends Document {
68
+ name: string;
69
+ description?: string;
70
+ createdAt: Date;
71
+ updatedAt: Date;
72
+ }
73
+
74
+ const ExampleSchema = new Schema<IExample>(
75
+ {
76
+ name: {
77
+ type: String,
78
+ required: true,
79
+ },
80
+ description: {
81
+ type: String,
82
+ },
83
+ },
84
+ {
85
+ timestamps: true,
86
+ }
87
+ );
88
+
89
+ export const Example = mongoose.model<IExample>('Example', ExampleSchema);
@@ -0,0 +1,54 @@
1
+ import { FastifyInstance } from 'fastify';
2
+
3
+ /**
4
+ * Registers all API routes
5
+ *
6
+ * @param app - Fastify instance
7
+ *
8
+ * @remarks
9
+ * This function registers all route modules.
10
+ * Add your route registrations here as you create new endpoints.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // Register a new route module
15
+ * await app.register(userRoutes, { prefix: '/users' });
16
+ * ```
17
+ */
18
+ export default async function routes(app: FastifyInstance) {
19
+ // Health check endpoint
20
+ app.get('/health', {
21
+ schema: {
22
+ tags: ['Health'],
23
+ description: 'Health check endpoint',
24
+ response: {
25
+ 200: {
26
+ description: 'Server is healthy',
27
+ type: 'object',
28
+ properties: {
29
+ status: { type: 'string' },
30
+ timestamp: { type: 'string' },
31
+ },
32
+ },
33
+ },
34
+ },
35
+ handler: async () => {
36
+ return {
37
+ status: 'ok',
38
+ timestamp: new Date().toISOString(),
39
+ };
40
+ },
41
+ });
42
+
43
+ // Example protected route (uncomment when you have auth middleware)
44
+ // app.get('/protected', {
45
+ // preHandler: [app.authenticate], // JWT verification middleware
46
+ // handler: async (request) => {
47
+ // return { message: 'You are authenticated!', user: request.user };
48
+ // },
49
+ // });
50
+
51
+ // Register your route modules here:
52
+ // await app.register(authRoutes, { prefix: '/auth' });
53
+ // await app.register(userRoutes, { prefix: '/users' });
54
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Swagger Schema Definitions
3
+ *
4
+ * This file contains reusable schema definitions for Swagger/OpenAPI documentation.
5
+ *
6
+ * @remarks
7
+ * - Define request/response schemas here
8
+ * - Use these schemas in your route definitions
9
+ * - Keep schemas organized by feature/entity
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * export const UserSchema = {
14
+ * type: 'object',
15
+ * properties: {
16
+ * id: { type: 'string' },
17
+ * email: { type: 'string' },
18
+ * name: { type: 'string' },
19
+ * },
20
+ * required: ['id', 'email', 'name'],
21
+ * };
22
+ *
23
+ * export const CreateUserSchema = {
24
+ * type: 'object',
25
+ * properties: {
26
+ * email: { type: 'string' },
27
+ * password: { type: 'string' },
28
+ * name: { type: 'string' },
29
+ * },
30
+ * required: ['email', 'password', 'name'],
31
+ * };
32
+ * ```
33
+ *
34
+ * Usage in routes:
35
+ * ```typescript
36
+ * app.post('/users', {
37
+ * schema: {
38
+ * body: CreateUserSchema,
39
+ * response: {
40
+ * 201: UserSchema,
41
+ * },
42
+ * },
43
+ * handler: async (request, reply) => {
44
+ * // ...
45
+ * },
46
+ * });
47
+ * ```
48
+ */
49
+
50
+ export const HealthCheckSchema = {
51
+ type: 'object',
52
+ properties: {
53
+ status: { type: 'string' },
54
+ timestamp: { type: 'string' },
55
+ },
56
+ };
57
+
58
+ // Add your schemas here
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Example Service
3
+ *
4
+ * Services contain business logic and interact with models/database.
5
+ * They are called by route handlers and keep routes thin.
6
+ *
7
+ * @remarks
8
+ * Service responsibilities:
9
+ * - Business logic implementation
10
+ * - Data validation
11
+ * - Database operations via models
12
+ * - Error handling
13
+ * - Data transformation
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // User Service Example
18
+ * import bcrypt from 'bcrypt';
19
+ * import { User } from '../models/user.model.js';
20
+ *
21
+ * export class UserService {
22
+ * async createUser(email: string, password: string, name: string) {
23
+ * const hashedPassword = await bcrypt.hash(password, 10);
24
+ * const user = await User.create({
25
+ * email,
26
+ * password: hashedPassword,
27
+ * name,
28
+ * });
29
+ * return user;
30
+ * }
31
+ *
32
+ * async findUserByEmail(email: string) {
33
+ * return User.findOne({ email });
34
+ * }
35
+ *
36
+ * async findUserById(id: string) {
37
+ * return User.findById(id);
38
+ * }
39
+ * }
40
+ *
41
+ * export const userService = new UserService();
42
+ * ```
43
+ *
44
+ * Usage in routes:
45
+ * ```typescript
46
+ * import { userService } from '../services/user.service.js';
47
+ *
48
+ * app.post('/users', async (request, reply) => {
49
+ * const { email, password, name } = request.body;
50
+ * const user = await userService.createUser(email, password, name);
51
+ * reply.status(201).send(user);
52
+ * });
53
+ * ```
54
+ */
55
+
56
+ export class ExampleService {
57
+ async doSomething() {
58
+ // Your business logic here
59
+ return { message: 'Example service method' };
60
+ }
61
+ }
62
+
63
+ export const exampleService = new ExampleService();