@trinacria/cli 0.1.1-alpha.1

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.

Potentially problematic release.


This version of @trinacria/cli might be problematic. Click here for more details.

Files changed (129) hide show
  1. package/README.md +109 -0
  2. package/README.npm.md +109 -0
  3. package/dist/cli.d.ts +19 -0
  4. package/dist/cli.js +88 -0
  5. package/dist/commands/build.d.ts +2 -0
  6. package/dist/commands/build.js +102 -0
  7. package/dist/commands/dev.d.ts +28 -0
  8. package/dist/commands/dev.js +186 -0
  9. package/dist/commands/new.d.ts +41 -0
  10. package/dist/commands/new.js +280 -0
  11. package/dist/commands/start.d.ts +13 -0
  12. package/dist/commands/start.js +110 -0
  13. package/dist/config/config.contract.d.ts +9 -0
  14. package/dist/config/config.contract.js +2 -0
  15. package/dist/config/default-config.d.ts +2 -0
  16. package/dist/config/default-config.js +11 -0
  17. package/dist/config/load-config.d.ts +2 -0
  18. package/dist/config/load-config.js +113 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +5 -0
  21. package/dist/templates/api-events-rabbitmq/.env.example +23 -0
  22. package/dist/templates/api-events-rabbitmq/Dockerfile +18 -0
  23. package/dist/templates/api-events-rabbitmq/README.md +97 -0
  24. package/dist/templates/api-events-rabbitmq/docker-compose.yml +30 -0
  25. package/dist/templates/api-events-rabbitmq/package.json +21 -0
  26. package/dist/templates/api-events-rabbitmq/src/global/config.service.ts +95 -0
  27. package/dist/templates/api-events-rabbitmq/src/global/controllers/swagger/docs.html +28 -0
  28. package/dist/templates/api-events-rabbitmq/src/global/controllers/swagger/swagger-docs.controller.ts +79 -0
  29. package/dist/templates/api-events-rabbitmq/src/global/rabbitmq.service.ts +86 -0
  30. package/dist/templates/api-events-rabbitmq/src/global/register-global-controllers.ts +20 -0
  31. package/dist/templates/api-events-rabbitmq/src/main.ts +89 -0
  32. package/dist/templates/api-events-rabbitmq/src/modules/events/dto/event.dto.ts +24 -0
  33. package/dist/templates/api-events-rabbitmq/src/modules/events/dto/index.ts +2 -0
  34. package/dist/templates/api-events-rabbitmq/src/modules/events/dto/publish-event.dto.ts +12 -0
  35. package/dist/templates/api-events-rabbitmq/src/modules/events/events.controller.ts +76 -0
  36. package/dist/templates/api-events-rabbitmq/src/modules/events/events.module.ts +27 -0
  37. package/dist/templates/api-events-rabbitmq/src/modules/events/events.provider.ts +28 -0
  38. package/dist/templates/api-events-rabbitmq/src/modules/events/events.service.ts +19 -0
  39. package/dist/templates/api-events-rabbitmq/src/modules/events/events.store.ts +42 -0
  40. package/dist/templates/api-events-rabbitmq/src/modules/events/events.tokens.ts +11 -0
  41. package/dist/templates/api-events-rabbitmq/trinacria.config.mjs +12 -0
  42. package/dist/templates/api-events-rabbitmq/tsconfig.json +14 -0
  43. package/dist/templates/api-events-redis/.env.example +18 -0
  44. package/dist/templates/api-events-redis/Dockerfile +18 -0
  45. package/dist/templates/api-events-redis/README.md +97 -0
  46. package/dist/templates/api-events-redis/docker-compose.yml +33 -0
  47. package/dist/templates/api-events-redis/package.json +18 -0
  48. package/dist/templates/api-events-redis/src/global/config.service.ts +93 -0
  49. package/dist/templates/api-events-redis/src/global/controllers/swagger/docs.html +28 -0
  50. package/dist/templates/api-events-redis/src/global/controllers/swagger/swagger-docs.controller.ts +79 -0
  51. package/dist/templates/api-events-redis/src/global/redis.service.ts +50 -0
  52. package/dist/templates/api-events-redis/src/global/register-global-controllers.ts +20 -0
  53. package/dist/templates/api-events-redis/src/main.ts +88 -0
  54. package/dist/templates/api-events-redis/src/modules/events/dto/event.dto.ts +24 -0
  55. package/dist/templates/api-events-redis/src/modules/events/dto/index.ts +2 -0
  56. package/dist/templates/api-events-redis/src/modules/events/dto/publish-event.dto.ts +12 -0
  57. package/dist/templates/api-events-redis/src/modules/events/events.controller.ts +76 -0
  58. package/dist/templates/api-events-redis/src/modules/events/events.module.ts +27 -0
  59. package/dist/templates/api-events-redis/src/modules/events/events.provider.ts +28 -0
  60. package/dist/templates/api-events-redis/src/modules/events/events.service.ts +19 -0
  61. package/dist/templates/api-events-redis/src/modules/events/events.store.ts +42 -0
  62. package/dist/templates/api-events-redis/src/modules/events/events.tokens.ts +11 -0
  63. package/dist/templates/api-events-redis/trinacria.config.mjs +12 -0
  64. package/dist/templates/api-events-redis/tsconfig.json +14 -0
  65. package/dist/templates/api-mongoose-mongodb/.env.example +17 -0
  66. package/dist/templates/api-mongoose-mongodb/Dockerfile +18 -0
  67. package/dist/templates/api-mongoose-mongodb/README.md +98 -0
  68. package/dist/templates/api-mongoose-mongodb/docker-compose.yml +34 -0
  69. package/dist/templates/api-mongoose-mongodb/package.json +17 -0
  70. package/dist/templates/api-mongoose-mongodb/src/global/config.service.ts +92 -0
  71. package/dist/templates/api-mongoose-mongodb/src/global/controllers/swagger/docs.html +28 -0
  72. package/dist/templates/api-mongoose-mongodb/src/global/controllers/swagger/swagger-docs.controller.ts +79 -0
  73. package/dist/templates/api-mongoose-mongodb/src/global/mongoose-schema.provider.ts +18 -0
  74. package/dist/templates/api-mongoose-mongodb/src/global/mongoose.service.ts +36 -0
  75. package/dist/templates/api-mongoose-mongodb/src/global/register-global-controllers.ts +20 -0
  76. package/dist/templates/api-mongoose-mongodb/src/main.ts +70 -0
  77. package/dist/templates/api-mongoose-mongodb/src/modules/users/dto/create-user.dto.ts +14 -0
  78. package/dist/templates/api-mongoose-mongodb/src/modules/users/dto/index.ts +2 -0
  79. package/dist/templates/api-mongoose-mongodb/src/modules/users/dto/public-user.dto.ts +22 -0
  80. package/dist/templates/api-mongoose-mongodb/src/modules/users/users.controller.ts +89 -0
  81. package/dist/templates/api-mongoose-mongodb/src/modules/users/users.module.ts +17 -0
  82. package/dist/templates/api-mongoose-mongodb/src/modules/users/users.schema.ts +35 -0
  83. package/dist/templates/api-mongoose-mongodb/src/modules/users/users.service.ts +35 -0
  84. package/dist/templates/api-mongoose-mongodb/src/modules/users/users.tokens.ts +9 -0
  85. package/dist/templates/api-mongoose-mongodb/trinacria.config.mjs +12 -0
  86. package/dist/templates/api-mongoose-mongodb/tsconfig.json +14 -0
  87. package/dist/templates/api-prisma-postgresql/.env.example +19 -0
  88. package/dist/templates/api-prisma-postgresql/Dockerfile +24 -0
  89. package/dist/templates/api-prisma-postgresql/README.md +107 -0
  90. package/dist/templates/api-prisma-postgresql/docker-compose.yml +38 -0
  91. package/dist/templates/api-prisma-postgresql/package.json +26 -0
  92. package/dist/templates/api-prisma-postgresql/prisma/schema.prisma +15 -0
  93. package/dist/templates/api-prisma-postgresql/prisma.config.ts +9 -0
  94. package/dist/templates/api-prisma-postgresql/src/global/config.service.ts +92 -0
  95. package/dist/templates/api-prisma-postgresql/src/global/controllers/swagger/docs.html +28 -0
  96. package/dist/templates/api-prisma-postgresql/src/global/controllers/swagger/swagger-docs.controller.ts +79 -0
  97. package/dist/templates/api-prisma-postgresql/src/global/prisma.service.ts +20 -0
  98. package/dist/templates/api-prisma-postgresql/src/global/register-global-controllers.ts +20 -0
  99. package/dist/templates/api-prisma-postgresql/src/main.ts +70 -0
  100. package/dist/templates/api-prisma-postgresql/src/modules/users/dto/create-user.dto.ts +14 -0
  101. package/dist/templates/api-prisma-postgresql/src/modules/users/dto/index.ts +2 -0
  102. package/dist/templates/api-prisma-postgresql/src/modules/users/dto/public-user.dto.ts +22 -0
  103. package/dist/templates/api-prisma-postgresql/src/modules/users/users.controller.ts +89 -0
  104. package/dist/templates/api-prisma-postgresql/src/modules/users/users.module.ts +15 -0
  105. package/dist/templates/api-prisma-postgresql/src/modules/users/users.service.ts +36 -0
  106. package/dist/templates/api-prisma-postgresql/src/modules/users/users.tokens.ts +7 -0
  107. package/dist/templates/api-prisma-postgresql/trinacria.config.mjs +12 -0
  108. package/dist/templates/api-prisma-postgresql/tsconfig.json +14 -0
  109. package/dist/templates/app-starter/.env.example +1 -0
  110. package/dist/templates/app-starter/Dockerfile +13 -0
  111. package/dist/templates/app-starter/README.md +32 -0
  112. package/dist/templates/app-starter/docker-compose.yml +8 -0
  113. package/dist/templates/app-starter/package.json +14 -0
  114. package/dist/templates/app-starter/src/main.ts +14 -0
  115. package/dist/templates/app-starter/trinacria.config.mjs +12 -0
  116. package/dist/templates/app-starter/tsconfig.json +14 -0
  117. package/dist/templates/cron-example/.env.example +11 -0
  118. package/dist/templates/cron-example/Dockerfile +13 -0
  119. package/dist/templates/cron-example/README.md +68 -0
  120. package/dist/templates/cron-example/docker-compose.yml +11 -0
  121. package/dist/templates/cron-example/package.json +15 -0
  122. package/dist/templates/cron-example/src/config.service.ts +46 -0
  123. package/dist/templates/cron-example/src/main.ts +41 -0
  124. package/dist/templates/cron-example/src/modules/cron/cron.module.ts +15 -0
  125. package/dist/templates/cron-example/src/modules/cron/cron.tokens.ts +6 -0
  126. package/dist/templates/cron-example/src/modules/cron/example-cron-jobs.provider.ts +48 -0
  127. package/dist/templates/cron-example/trinacria.config.mjs +12 -0
  128. package/dist/templates/cron-example/tsconfig.json +14 -0
  129. package/package.json +32 -0
@@ -0,0 +1,36 @@
1
+ import mongoose, { type Connection } from "mongoose";
2
+ import { createToken } from "@trinacria/core";
3
+ import type { ConfigService } from "./config.service";
4
+
5
+ export const MONGOOSE_SERVICE =
6
+ createToken<MongooseService>("MONGOOSE_SERVICE");
7
+
8
+ export class MongooseService {
9
+ private connection?: Connection;
10
+
11
+ constructor(private readonly config: ConfigService) {}
12
+
13
+ async onInit(): Promise<void> {
14
+ if (this.connection?.readyState === 1) {
15
+ return;
16
+ }
17
+
18
+ await mongoose.connect(this.config.get("DATABASE_URL"));
19
+ this.connection = mongoose.connection;
20
+ }
21
+
22
+ getConnection(): Connection {
23
+ if (!this.connection || this.connection.readyState !== 1) {
24
+ throw new Error("Mongoose connection is not ready");
25
+ }
26
+
27
+ return this.connection;
28
+ }
29
+
30
+ async onDestroy(): Promise<void> {
31
+ if (this.connection) {
32
+ await mongoose.disconnect();
33
+ this.connection = undefined;
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,20 @@
1
+ import { TrinacriaApp } from "@trinacria/core";
2
+ import { httpProvider } from "@trinacria/http";
3
+ import { ConfigService, CONFIG_SERVICE } from "./config.service";
4
+ import {
5
+ SWAGGER_DOCS_CONTROLLER,
6
+ SwaggerDocsController,
7
+ } from "./controllers/swagger/swagger-docs.controller";
8
+
9
+ export function registerGlobalControllers(
10
+ app: TrinacriaApp,
11
+ config: ConfigService,
12
+ ): void {
13
+ if (config.get("OPENAPI_ENABLED")) {
14
+ app.registerGlobalProvider(
15
+ httpProvider(SWAGGER_DOCS_CONTROLLER, SwaggerDocsController, [
16
+ CONFIG_SERVICE,
17
+ ]),
18
+ );
19
+ }
20
+ }
@@ -0,0 +1,70 @@
1
+ import { TrinacriaApp, classProvider, valueProvider } from "@trinacria/core";
2
+ import {
3
+ cors,
4
+ createHttpPlugin,
5
+ createSecurityHeadersBuilder,
6
+ rateLimit,
7
+ requestId,
8
+ requestLogger,
9
+ requestTimeout,
10
+ } from "@trinacria/http";
11
+ import { CONFIG_SERVICE, ConfigService } from "./global/config.service";
12
+ import { MONGOOSE_SERVICE, MongooseService } from "./global/mongoose.service";
13
+ import { registerGlobalControllers } from "./global/register-global-controllers";
14
+ import { UsersModule } from "./modules/users/users.module";
15
+
16
+ async function bootstrap() {
17
+ const app = new TrinacriaApp();
18
+ const configService = new ConfigService();
19
+ const config = configService.getAll();
20
+ const isProduction = config.ENV === "production";
21
+ const corsOrigins = config.CORS_ALLOWED_ORIGINS;
22
+ const securityHeadersMiddleware = createSecurityHeadersBuilder()
23
+ .preset(config.ENV)
24
+ .trustProxy(false)
25
+ .build();
26
+
27
+ app.registerGlobalProvider(valueProvider(CONFIG_SERVICE, configService));
28
+ app.registerGlobalProvider(
29
+ classProvider(MONGOOSE_SERVICE, MongooseService, [CONFIG_SERVICE]),
30
+ );
31
+ registerGlobalControllers(app, configService);
32
+
33
+ app.use(
34
+ createHttpPlugin({
35
+ host: config.HOST,
36
+ port: config.PORT,
37
+ middlewares: [
38
+ requestId(),
39
+ requestLogger({ includeUserAgent: !isProduction }),
40
+ cors({
41
+ origin: corsOrigins.length > 0 ? corsOrigins : "*",
42
+ credentials: true,
43
+ methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"],
44
+ }),
45
+ rateLimit({
46
+ windowMs: 60_000,
47
+ max: isProduction ? 240 : 2_000,
48
+ trustProxy: false,
49
+ }),
50
+ requestTimeout({ timeoutMs: 15_000 }),
51
+ securityHeadersMiddleware,
52
+ ],
53
+ openApi: config.OPENAPI_ENABLED
54
+ ? {
55
+ enabled: true,
56
+ title: "API Mongoose MongoDB Example",
57
+ version: "1.0.0",
58
+ }
59
+ : undefined,
60
+ }),
61
+ );
62
+
63
+ await app.registerModule(UsersModule);
64
+ await app.start();
65
+ }
66
+
67
+ bootstrap().catch((error) => {
68
+ console.error(error);
69
+ process.exit(1);
70
+ });
@@ -0,0 +1,14 @@
1
+ import { s } from "@trinacria/schema";
2
+
3
+ export interface CreateUserDto {
4
+ name: string;
5
+ email: string;
6
+ }
7
+
8
+ export const CreateUserDtoSchema = s.objectOf<CreateUserDto>()(
9
+ {
10
+ name: s.string({ trim: true, minLength: 1 }),
11
+ email: s.string({ trim: true, toLowerCase: true, email: true }),
12
+ },
13
+ { strict: true },
14
+ );
@@ -0,0 +1,2 @@
1
+ export * from "./create-user.dto";
2
+ export * from "./public-user.dto";
@@ -0,0 +1,22 @@
1
+ import { s } from "@trinacria/schema";
2
+
3
+ export interface PublicUserDto {
4
+ id: string;
5
+ name: string;
6
+ email: string;
7
+ createdAt: Date;
8
+ updatedAt: Date;
9
+ }
10
+
11
+ export const PublicUserDtoSchema = s.objectOf<PublicUserDto>()(
12
+ {
13
+ id: s.string({ trim: true, minLength: 1 }),
14
+ name: s.string({ trim: true, minLength: 1 }),
15
+ email: s.string({ trim: true, toLowerCase: true, email: true }),
16
+ createdAt: s.date(),
17
+ updatedAt: s.date(),
18
+ },
19
+ { strict: true },
20
+ );
21
+
22
+ export const PublicUserListDtoSchema = s.array(PublicUserDtoSchema);
@@ -0,0 +1,89 @@
1
+ import {
2
+ ConflictException,
3
+ HttpController,
4
+ HttpContext,
5
+ response,
6
+ } from "@trinacria/http";
7
+ import { UsersService } from "./users.service";
8
+ import {
9
+ CreateUserDtoSchema,
10
+ PublicUserDtoSchema,
11
+ PublicUserListDtoSchema,
12
+ } from "./dto";
13
+
14
+ export class UsersController extends HttpController {
15
+ constructor(private readonly users: UsersService) {
16
+ super();
17
+ }
18
+
19
+ routes() {
20
+ return this.router()
21
+ .get("/health", () => ({ status: "ok" }), {
22
+ docs: {
23
+ tags: ["Health"],
24
+ summary: "Health check",
25
+ },
26
+ })
27
+ .get("/users", this.listUsers, {
28
+ docs: {
29
+ tags: ["Users"],
30
+ summary: "List users",
31
+ responses: {
32
+ 200: {
33
+ description: "Users list",
34
+ schema: PublicUserListDtoSchema.toOpenApi(),
35
+ },
36
+ },
37
+ },
38
+ })
39
+ .post("/users", this.createUser, {
40
+ docs: {
41
+ tags: ["Users"],
42
+ summary: "Create user",
43
+ requestBody: {
44
+ required: true,
45
+ schema: CreateUserDtoSchema.toOpenApi(),
46
+ },
47
+ responses: {
48
+ 201: {
49
+ description: "Created user",
50
+ schema: PublicUserDtoSchema.toOpenApi(),
51
+ },
52
+ 409: {
53
+ description: "Email already exists",
54
+ },
55
+ },
56
+ },
57
+ })
58
+ .build();
59
+ }
60
+
61
+ async listUsers() {
62
+ return this.users.list();
63
+ }
64
+
65
+ async createUser(ctx: HttpContext) {
66
+ const payload = CreateUserDtoSchema.parse(ctx.body);
67
+
68
+ try {
69
+ const created = await this.users.create(payload);
70
+ return response(created, {
71
+ status: 201,
72
+ headers: {
73
+ location: `/users/${created.id}`,
74
+ },
75
+ });
76
+ } catch (error) {
77
+ if (
78
+ error &&
79
+ typeof error === "object" &&
80
+ "code" in error &&
81
+ error.code === 11000
82
+ ) {
83
+ throw new ConflictException("Email already exists");
84
+ }
85
+
86
+ throw error;
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,17 @@
1
+ import { classProvider, defineModule } from "@trinacria/core";
2
+ import { httpProvider } from "@trinacria/http";
3
+ import { createMongooseSchemaProvider } from "../../global/mongoose-schema.provider";
4
+ import { USERS_CONTROLLER, USERS_SERVICE, USER_SCHEMA } from "./users.tokens";
5
+ import { UsersController } from "./users.controller";
6
+ import { userSchema } from "./users.schema";
7
+ import { UsersService } from "./users.service";
8
+
9
+ export const UsersModule = defineModule({
10
+ name: "UsersModule",
11
+ providers: [
12
+ createMongooseSchemaProvider(USER_SCHEMA, "User", userSchema),
13
+ classProvider(USERS_SERVICE, UsersService, [USER_SCHEMA]),
14
+ httpProvider(USERS_CONTROLLER, UsersController, [USERS_SERVICE]),
15
+ ],
16
+ exports: [USERS_SERVICE, USERS_CONTROLLER],
17
+ });
@@ -0,0 +1,35 @@
1
+ import { type HydratedDocument, type Model, Schema } from "mongoose";
2
+
3
+ export interface UserEntity {
4
+ name: string;
5
+ email: string;
6
+ createdAt: Date;
7
+ updatedAt: Date;
8
+ }
9
+
10
+ export type UserDocument = HydratedDocument<UserEntity>;
11
+ export type UserSchemaModel = Model<UserEntity>;
12
+
13
+ const userSchema = new Schema<UserEntity>(
14
+ {
15
+ name: {
16
+ type: String,
17
+ required: true,
18
+ trim: true,
19
+ },
20
+ email: {
21
+ type: String,
22
+ required: true,
23
+ unique: true,
24
+ lowercase: true,
25
+ trim: true,
26
+ },
27
+ },
28
+ {
29
+ timestamps: true,
30
+ versionKey: false,
31
+ },
32
+ );
33
+
34
+ userSchema.index({ email: 1 }, { unique: true });
35
+ export { userSchema };
@@ -0,0 +1,35 @@
1
+ import type { CreateUserDto, PublicUserDto } from "./dto";
2
+ import type { UserDocument, UserSchemaModel } from "./users.schema";
3
+
4
+ export class UsersService {
5
+ constructor(private readonly userSchema: UserSchemaModel) {}
6
+
7
+ async list(): Promise<PublicUserDto[]> {
8
+ const users: UserDocument[] = await this.userSchema
9
+ .find({}, undefined, { sort: { createdAt: -1 } })
10
+ .exec();
11
+
12
+ return users.map((user: UserDocument) => ({
13
+ id: String(user._id),
14
+ name: user.name,
15
+ email: user.email,
16
+ createdAt: user.createdAt,
17
+ updatedAt: user.updatedAt,
18
+ }));
19
+ }
20
+
21
+ async create(input: CreateUserDto): Promise<PublicUserDto> {
22
+ const created = await this.userSchema.create({
23
+ name: input.name,
24
+ email: input.email.toLowerCase(),
25
+ });
26
+
27
+ return {
28
+ id: String(created._id),
29
+ name: created.name,
30
+ email: created.email,
31
+ createdAt: created.createdAt,
32
+ updatedAt: created.updatedAt,
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,9 @@
1
+ import { createToken } from "@trinacria/core";
2
+ import type { UserSchemaModel } from "./users.schema";
3
+ import { UsersController } from "./users.controller";
4
+ import { UsersService } from "./users.service";
5
+
6
+ export const USER_SCHEMA = createToken<UserSchemaModel>("USER_SCHEMA");
7
+ export const USERS_SERVICE = createToken<UsersService>("USERS_SERVICE");
8
+ export const USERS_CONTROLLER =
9
+ createToken<UsersController>("USERS_CONTROLLER");
@@ -0,0 +1,12 @@
1
+ /** @type {import('@trinacria/cli').TrinacriaConfig} */
2
+
3
+ const config = {
4
+ entry: "src/main.ts",
5
+ outDir: "dist",
6
+ watchDir: "src",
7
+ env: "development",
8
+ crashLoopWindowMs: 15_000,
9
+ maxConsecutiveCrashRestarts: 3,
10
+ };
11
+
12
+ export default config;
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "types": ["node"],
4
+ "target": "ES2022",
5
+ "module": "CommonJS",
6
+ "strict": true,
7
+ "declaration": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "rootDir": "src",
11
+ "outDir": "dist"
12
+ },
13
+ "include": ["src"]
14
+ }
@@ -0,0 +1,19 @@
1
+ # ------------------------------------------------------------
2
+ # Local app runtime (used by `npm run dev -w api-prisma-postgresql`)
3
+ # ------------------------------------------------------------
4
+ ENV=development
5
+ HOST=127.0.0.1
6
+ PORT=4001
7
+ OPENAPI_ENABLED=true
8
+ CORS_ALLOWED_ORIGINS=
9
+ DATABASE_URL="postgresql://postgres:postgres@localhost:5432/trinacria_example?schema=public"
10
+
11
+ # ------------------------------------------------------------
12
+ # Docker runtime (used by `docker compose ... --env-file .../.env`)
13
+ # ------------------------------------------------------------
14
+ DOCKER_POSTGRES_DB=trinacria_example
15
+ DOCKER_POSTGRES_USER=postgres
16
+ DOCKER_POSTGRES_PASSWORD=postgres
17
+ DOCKER_POSTGRES_PORT=5432
18
+ DOCKER_API_PORT=4001
19
+ DOCKER_DATABASE_URL="postgresql://postgres:postgres@postgres:5432/trinacria_example?schema=public"
@@ -0,0 +1,24 @@
1
+ FROM node:24-bookworm-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update -y && apt-get install -y --no-install-recommends openssl \
6
+ && rm -rf /var/lib/apt/lists/*
7
+
8
+ ENV DATABASE_URL=postgresql://postgres:postgres@localhost:5432/trinacria_example?schema=public
9
+
10
+ COPY package.json package-lock.json tsconfig.base.json ./
11
+ COPY packages ./packages
12
+ COPY apps/api-prisma-postgresql ./apps/api-prisma-postgresql
13
+
14
+ RUN npm ci
15
+ RUN npm run build:packages
16
+ RUN npm run prisma:generate -w api-prisma-postgresql
17
+ RUN npm run build -w api-prisma-postgresql
18
+
19
+ ENV HOST=0.0.0.0
20
+ ENV PORT=4001
21
+
22
+ EXPOSE 4001
23
+
24
+ CMD ["sh", "-c", "npm run prisma:push -w api-prisma-postgresql && npm run start -w api-prisma-postgresql"]
@@ -0,0 +1,107 @@
1
+ # API Example: Prisma + PostgreSQL
2
+
3
+ A minimal API-only example using Trinacria, Prisma, and PostgreSQL.
4
+
5
+ ## Scope
6
+
7
+ This app is intentionally a base template:
8
+
9
+ - no authentication (no JWT/session/password flow)
10
+ - no authorization roles/policies
11
+ - no background jobs
12
+
13
+ Use this as a starting point for integration examples.
14
+
15
+ ## Endpoints
16
+
17
+ - `GET /health`
18
+ - `GET /users`
19
+ - `POST /users`
20
+ - `GET /openapi.json`
21
+ - `GET /docs` (Swagger UI)
22
+
23
+ ## Built-in middleware enabled
24
+
25
+ - `requestId`
26
+ - `requestLogger`
27
+ - `cors`
28
+ - `rateLimit`
29
+ - `requestTimeout`
30
+ - `securityHeaders`
31
+
32
+ ## First steps (local)
33
+
34
+ 1. Install dependencies from the monorepo root:
35
+
36
+ ```bash
37
+ npm install
38
+ ```
39
+
40
+ 2. Copy the environment file:
41
+
42
+ ```bash
43
+ cp apps/api-prisma-postgresql/.env.example apps/api-prisma-postgresql/.env.development
44
+ ```
45
+
46
+ 3. Make sure PostgreSQL is running locally and matches `DATABASE_URL`.
47
+
48
+ 4. Push schema and generate Prisma client:
49
+
50
+ ```bash
51
+ npm run prisma:push -w api-prisma-postgresql
52
+ npm run prisma:generate -w api-prisma-postgresql
53
+ ```
54
+
55
+ 5. Start the API:
56
+
57
+ ```bash
58
+ npm run dev -w api-prisma-postgresql
59
+ ```
60
+
61
+ 6. Verify the app is running:
62
+
63
+ ```bash
64
+ curl http://127.0.0.1:4001/health
65
+ ```
66
+
67
+ ## Create your first user
68
+
69
+ ```bash
70
+ curl -X POST http://127.0.0.1:4001/users \
71
+ -H 'content-type: application/json' \
72
+ -d '{"name":"Mario Rossi","email":"mario@example.com"}'
73
+ ```
74
+
75
+ Then list users:
76
+
77
+ ```bash
78
+ curl http://127.0.0.1:4001/users
79
+ ```
80
+
81
+ ## Docker quick start
82
+
83
+ 1. Create the Docker env file from the same template:
84
+
85
+ ```bash
86
+ cp apps/api-prisma-postgresql/.env.example apps/api-prisma-postgresql/.env
87
+ ```
88
+
89
+ 2. Edit the Docker section in `apps/api-prisma-postgresql/.env` if you want custom credentials/ports.
90
+
91
+ 3. Start PostgreSQL + API using that `.env` file:
92
+
93
+ ```bash
94
+ docker compose \
95
+ --env-file apps/api-prisma-postgresql/.env \
96
+ -f apps/api-prisma-postgresql/docker-compose.yml \
97
+ up --build
98
+ ```
99
+
100
+ The API will be available at `http://127.0.0.1:${DOCKER_API_PORT}` (default `4001`).
101
+
102
+ Compose services:
103
+
104
+ - `postgres`: PostgreSQL 16
105
+ - `api`: this Trinacria API (built from this monorepo)
106
+
107
+ The container startup command automatically runs `prisma db push` before starting the API.
@@ -0,0 +1,38 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:16-alpine
4
+ environment:
5
+ POSTGRES_DB: ${DOCKER_POSTGRES_DB}
6
+ POSTGRES_USER: ${DOCKER_POSTGRES_USER}
7
+ POSTGRES_PASSWORD: ${DOCKER_POSTGRES_PASSWORD}
8
+ ports:
9
+ - "${DOCKER_POSTGRES_PORT}:5432"
10
+ volumes:
11
+ - trinacria_api_pg_data:/var/lib/postgresql/data
12
+ healthcheck:
13
+ test:
14
+ [
15
+ "CMD-SHELL",
16
+ "pg_isready -U ${DOCKER_POSTGRES_USER} -d ${DOCKER_POSTGRES_DB}",
17
+ ]
18
+ interval: 5s
19
+ timeout: 5s
20
+ retries: 20
21
+
22
+ api:
23
+ build:
24
+ context: ../..
25
+ dockerfile: apps/api-prisma-postgresql/Dockerfile
26
+ environment:
27
+ ENV: development
28
+ HOST: 0.0.0.0
29
+ PORT: 4001
30
+ DATABASE_URL: ${DOCKER_DATABASE_URL}
31
+ ports:
32
+ - "${DOCKER_API_PORT}:4001"
33
+ depends_on:
34
+ postgres:
35
+ condition: service_healthy
36
+
37
+ volumes:
38
+ trinacria_api_pg_data:
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "api-prisma-postgresql",
3
+ "private": true,
4
+ "type": "commonjs",
5
+ "scripts": {
6
+ "start": "node ../../packages/cli/dist/index.js start",
7
+ "build": "node ../../packages/cli/dist/index.js build",
8
+ "dev": "node ../../packages/cli/dist/index.js dev",
9
+ "prisma:generate": "prisma generate --schema prisma/schema.prisma",
10
+ "prisma:migrate:dev": "prisma migrate dev --schema prisma/schema.prisma",
11
+ "prisma:push": "prisma db push --schema prisma/schema.prisma",
12
+ "prisma:studio": "prisma studio --schema prisma/schema.prisma"
13
+ },
14
+ "dependencies": {
15
+ "@prisma/adapter-pg": "^7.4.1",
16
+ "@prisma/client": "^7.4.1",
17
+ "@trinacria/cli": "*",
18
+ "@trinacria/core": "*",
19
+ "@trinacria/http": "*",
20
+ "@trinacria/schema": "*",
21
+ "pg": "^8.16.3"
22
+ },
23
+ "devDependencies": {
24
+ "prisma": "^7.4.1"
25
+ }
26
+ }
@@ -0,0 +1,15 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "postgresql"
7
+ }
8
+
9
+ model User {
10
+ id String @id @default(cuid())
11
+ name String
12
+ email String @unique
13
+ createdAt DateTime @default(now())
14
+ updatedAt DateTime @updatedAt
15
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "prisma/config";
2
+ import "dotenv/config";
3
+
4
+ export default defineConfig({
5
+ schema: "prisma/schema.prisma",
6
+ datasource: {
7
+ url: process.env.DATABASE_URL,
8
+ },
9
+ });