create-carlonicora-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 (149) hide show
  1. package/LICENSE +675 -0
  2. package/README.md +104 -0
  3. package/bin/cli.js +3 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +92 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/git.d.ts +7 -0
  9. package/dist/git.d.ts.map +1 -0
  10. package/dist/git.js +80 -0
  11. package/dist/git.js.map +1 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +5 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/prompts.d.ts +5 -0
  17. package/dist/prompts.d.ts.map +1 -0
  18. package/dist/prompts.js +30 -0
  19. package/dist/prompts.js.map +1 -0
  20. package/dist/replacer.d.ts +9 -0
  21. package/dist/replacer.d.ts.map +1 -0
  22. package/dist/replacer.js +11 -0
  23. package/dist/replacer.js.map +1 -0
  24. package/dist/scaffold.d.ts +3 -0
  25. package/dist/scaffold.d.ts.map +1 -0
  26. package/dist/scaffold.js +79 -0
  27. package/dist/scaffold.js.map +1 -0
  28. package/dist/types/index.d.ts +16 -0
  29. package/dist/types/index.d.ts.map +1 -0
  30. package/dist/types/index.js +2 -0
  31. package/dist/types/index.js.map +1 -0
  32. package/dist/utils/files.d.ts +6 -0
  33. package/dist/utils/files.d.ts.map +1 -0
  34. package/dist/utils/files.js +103 -0
  35. package/dist/utils/files.js.map +1 -0
  36. package/dist/utils/logger.d.ts +12 -0
  37. package/dist/utils/logger.d.ts.map +1 -0
  38. package/dist/utils/logger.js +35 -0
  39. package/dist/utils/logger.js.map +1 -0
  40. package/dist/utils/validation.d.ts +6 -0
  41. package/dist/utils/validation.d.ts.map +1 -0
  42. package/dist/utils/validation.js +63 -0
  43. package/dist/utils/validation.js.map +1 -0
  44. package/package.json +52 -0
  45. package/template/.env.example +159 -0
  46. package/template/.github/workflows/check-library-updates.yml +71 -0
  47. package/template/.github/workflows/dev.yml +63 -0
  48. package/template/.github/workflows/pull-request.yml +55 -0
  49. package/template/.gitmodules +6 -0
  50. package/template/.husky/pre-commit +1 -0
  51. package/template/.husky/pre-push +1 -0
  52. package/template/.prettierignore +1 -0
  53. package/template/.prettierrc +13 -0
  54. package/template/.releaserc +134 -0
  55. package/template/.vscode/settings.json +16 -0
  56. package/template/CHANGELOG.md +0 -0
  57. package/template/CLAUDE.md +34 -0
  58. package/template/DOCKER.md +1591 -0
  59. package/template/Dockerfile +228 -0
  60. package/template/README.md +1 -0
  61. package/template/apps/api/.prettierrc +12 -0
  62. package/template/apps/api/eslint.config.mjs +54 -0
  63. package/template/apps/api/jest.config.js +29 -0
  64. package/template/apps/api/nest-cli.json +15 -0
  65. package/template/apps/api/package.json +155 -0
  66. package/template/apps/api/src/config/config.ts +17 -0
  67. package/template/apps/api/src/config/enums/job.name.ts +6 -0
  68. package/template/apps/api/src/config/enums/queue.id.ts +3 -0
  69. package/template/apps/api/src/config/interfaces/config.interface.ts +3 -0
  70. package/template/apps/api/src/features/features.modules.ts +6 -0
  71. package/template/apps/api/src/i18n/en/notifications.json +3 -0
  72. package/template/apps/api/src/main.ts +23 -0
  73. package/template/apps/api/src/neo4j.migrations/20250901_001.ts +33 -0
  74. package/template/apps/api/src/neo4j.migrations/20250901_002.ts +90 -0
  75. package/template/apps/api/src/neo4j.migrations/20250901_003.ts +57 -0
  76. package/template/apps/api/src/neo4j.migrations/20250901_004.ts +32 -0
  77. package/template/apps/api/src/neo4j.migrations/queries/migration.queries.ts +49 -0
  78. package/template/apps/api/src/types/langchain.d.ts +56 -0
  79. package/template/apps/api/tsconfig.build.json +4 -0
  80. package/template/apps/api/tsconfig.json +38 -0
  81. package/template/apps/web/.swcrc +26 -0
  82. package/template/apps/web/components.json +21 -0
  83. package/template/apps/web/eslint.config.mjs +33 -0
  84. package/template/apps/web/global.d.ts +7 -0
  85. package/template/apps/web/messages/en.json +249 -0
  86. package/template/apps/web/next.config.js +50 -0
  87. package/template/apps/web/package.json +146 -0
  88. package/template/apps/web/playwright.config.ts +86 -0
  89. package/template/apps/web/postcss.config.mjs +5 -0
  90. package/template/apps/web/public/sw.js +32 -0
  91. package/template/apps/web/src/app/[locale]/(admin)/administration/companies/[id]/page.tsx +46 -0
  92. package/template/apps/web/src/app/[locale]/(admin)/administration/companies/page.tsx +23 -0
  93. package/template/apps/web/src/app/[locale]/(admin)/layout.tsx +49 -0
  94. package/template/apps/web/src/app/[locale]/(auth)/activation/[code]/page.tsx +13 -0
  95. package/template/apps/web/src/app/[locale]/(auth)/auth/page.tsx +11 -0
  96. package/template/apps/web/src/app/[locale]/(auth)/invitation/[code]/page.tsx +7 -0
  97. package/template/apps/web/src/app/[locale]/(auth)/layout.tsx +9 -0
  98. package/template/apps/web/src/app/[locale]/(auth)/login/page.tsx +6 -0
  99. package/template/apps/web/src/app/[locale]/(auth)/logout/page.tsx +5 -0
  100. package/template/apps/web/src/app/[locale]/(auth)/register/page.tsx +6 -0
  101. package/template/apps/web/src/app/[locale]/(auth)/reset/[code]/page.tsx +7 -0
  102. package/template/apps/web/src/app/[locale]/(main)/(foundations)/notifications/page.tsx +9 -0
  103. package/template/apps/web/src/app/[locale]/(main)/(foundations)/roles/[id]/page.tsx +23 -0
  104. package/template/apps/web/src/app/[locale]/(main)/(foundations)/roles/page.tsx +12 -0
  105. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/error.tsx +14 -0
  106. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/loading.tsx +21 -0
  107. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/page.tsx +46 -0
  108. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/page.tsx +17 -0
  109. package/template/apps/web/src/app/[locale]/(main)/error.tsx +62 -0
  110. package/template/apps/web/src/app/[locale]/(main)/layout.tsx +40 -0
  111. package/template/apps/web/src/app/[locale]/(main)/page.tsx +41 -0
  112. package/template/apps/web/src/app/[locale]/layout.tsx +54 -0
  113. package/template/apps/web/src/app/globals.css +256 -0
  114. package/template/apps/web/src/config/BootstrapProvider.tsx +13 -0
  115. package/template/apps/web/src/config/Bootstrapper.ts +77 -0
  116. package/template/apps/web/src/config/env.ts +51 -0
  117. package/template/apps/web/src/config/middleware-env.ts +14 -0
  118. package/template/apps/web/src/enums/feature.ids.ts +3 -0
  119. package/template/apps/web/src/features/common/components/containers/IndexContainer.tsx +11 -0
  120. package/template/apps/web/src/features/common/components/details/LayoutDetails.tsx +33 -0
  121. package/template/apps/web/src/features/common/components/navigations/CommonSidebar.tsx +233 -0
  122. package/template/apps/web/src/features/common/components/navigations/CreationDropDown.tsx +117 -0
  123. package/template/apps/web/src/features/common/components/navigations/UserSidebarFooter.tsx +115 -0
  124. package/template/apps/web/src/features/common/components/navigations/VersionDisplay.tsx +18 -0
  125. package/template/apps/web/src/features/common/contexts/ErrorContext.tsx +62 -0
  126. package/template/apps/web/src/i18n/request.ts +13 -0
  127. package/template/apps/web/src/i18n/routing.ts +9 -0
  128. package/template/apps/web/src/i18n/useDateFnsLocale.ts +15 -0
  129. package/template/apps/web/src/proxy.ts +107 -0
  130. package/template/apps/web/src/server-actions/auth-cookies.ts +134 -0
  131. package/template/apps/web/src/types/modules.d.ts +10 -0
  132. package/template/apps/web/src/utils/metadata.ts +50 -0
  133. package/template/apps/web/src/utils/revalidation.ts +7 -0
  134. package/template/apps/web/tsconfig.json +51 -0
  135. package/template/docker-compose.yml +211 -0
  136. package/template/package.json +72 -0
  137. package/template/packages/nestjs-neo4jsonapi/.gitkeep +0 -0
  138. package/template/packages/nextjs-jsonapi/.gitkeep +0 -0
  139. package/template/packages/shared/package.json +23 -0
  140. package/template/packages/shared/src/const/roles.id.ts +5 -0
  141. package/template/packages/shared/src/const/system.roles.id.ts +4 -0
  142. package/template/packages/shared/src/index.ts +1 -0
  143. package/template/packages/shared/tsconfig.json +10 -0
  144. package/template/packages/shared/tsup.config.ts +16 -0
  145. package/template/pnpm-workspace.yaml +3 -0
  146. package/template/tsconfig.base.json +62 -0
  147. package/template/tsconfig.json +12 -0
  148. package/template/turbo.json +88 -0
  149. package/template/versions.production.json +4 -0
@@ -0,0 +1,107 @@
1
+ import { ENV } from "@/config/middleware-env";
2
+ import createMiddleware from "next-intl/middleware";
3
+ import { NextResponse, type NextRequest } from "next/server";
4
+ import { routing } from "./i18n/routing";
5
+
6
+ const intlMiddleware = createMiddleware(routing);
7
+
8
+ async function getNewToken(refreshToken: string): Promise<string | null> {
9
+ try {
10
+ const headers: HeadersInit = {};
11
+ const options: RequestInit = { method: "POST", headers: headers };
12
+ const uri = `${process.env.NEXT_PUBLIC_API_URL}auth/refreshtoken/${refreshToken}`;
13
+ const tokenRefreshResponse = await fetch(uri, options);
14
+
15
+ if (tokenRefreshResponse.ok) {
16
+ const data = await tokenRefreshResponse.json();
17
+ return data.data.attributes.token;
18
+ }
19
+
20
+ return null;
21
+ } catch (error) {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ function isTokenCloseToExpiry(token: string): boolean {
27
+ try {
28
+ const base64Url = token.split(".")[1];
29
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
30
+ const payload = JSON.parse(Buffer.from(base64, "base64").toString("utf8"));
31
+ const exp = payload.exp;
32
+ const currentTime = Math.floor(Date.now() / 1000);
33
+ return exp - currentTime < 300;
34
+ } catch (error) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ export default async function proxy(request: NextRequest) {
40
+ const { pathname, searchParams } = request.nextUrl;
41
+
42
+ if (pathname === "/githubconnects/callback") {
43
+ const code = searchParams.get("code");
44
+ const installation_id = searchParams.get("installation_id");
45
+ const setup_action = searchParams.get("setup_action");
46
+ const state = searchParams.get("state");
47
+
48
+ let path = null;
49
+ if (state && state.startsWith("{{name}}")) {
50
+ path = decodeURIComponent(state.substring(5));
51
+ }
52
+
53
+ const nextPublicAddress = ENV.APP_URL;
54
+ if (state && path && !nextPublicAddress.includes(path)) {
55
+ const redirectUrl = `${path}?code=${encodeURIComponent(code || "")}&installation_id=${encodeURIComponent(installation_id || "")}&setup_action=${encodeURIComponent(setup_action || "")}`;
56
+ return NextResponse.redirect(redirectUrl);
57
+ }
58
+ }
59
+
60
+ const normalizedPathname = pathname.replace(/^\/([a-z]{2})(?=\/)/, "");
61
+
62
+ const exemptPaths = ["/", "/activation", "/auth", "/invitation", "/login", "/logout", "/register", "/reset"];
63
+ const isExempt = exemptPaths.some((path) => normalizedPathname.startsWith(path));
64
+
65
+ const refreshToken = request.cookies.get("refreshToken")?.value;
66
+
67
+ if (!isExempt && !refreshToken) {
68
+ return NextResponse.redirect(new URL("/login", request.url));
69
+ }
70
+
71
+ const requestsSupport = normalizedPathname.startsWith("/support");
72
+ if (
73
+ (!process.env.NEXT_PUBLIC_PRIVATE_INSTALLATION ||
74
+ process.env.NEXT_PUBLIC_PRIVATE_INSTALLATION.toLowerCase() !== "true") &&
75
+ requestsSupport
76
+ ) {
77
+ return NextResponse.redirect(new URL("/", request.url));
78
+ }
79
+
80
+ const intlResponse = intlMiddleware(request);
81
+ const response = intlResponse instanceof NextResponse ? intlResponse : NextResponse.next();
82
+
83
+ const token = request.cookies.get("token")?.value;
84
+ if (refreshToken && (!token || isTokenCloseToExpiry(token))) {
85
+ const newToken = await getNewToken(refreshToken);
86
+ if (newToken) {
87
+ response.cookies.set("token", newToken, {
88
+ httpOnly: false,
89
+ path: "/",
90
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24),
91
+ });
92
+ response.cookies.set("reloadData", "true", {
93
+ httpOnly: false,
94
+ path: "/",
95
+ });
96
+ }
97
+ }
98
+
99
+ const fullUrl = request.url.replace(/^http:/, "https:");
100
+ response.headers.set("x-full-url", fullUrl);
101
+
102
+ return response;
103
+ }
104
+
105
+ export const config = {
106
+ matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)",
107
+ };
@@ -0,0 +1,134 @@
1
+ "use server";
2
+
3
+ import { cookies } from "next/headers";
4
+ import zlib from "zlib";
5
+
6
+ export async function updateToken(params: {
7
+ token?: string;
8
+ refreshToken?: string;
9
+ userId?: string;
10
+ companyId?: string;
11
+ licenseExpirationDate?: Date;
12
+ roles?: string[];
13
+ features?: string[];
14
+ modules?: {
15
+ id: string;
16
+ permissions: {
17
+ create: boolean | string;
18
+ read: boolean | string;
19
+ update: boolean | string;
20
+ delete: boolean | string;
21
+ };
22
+ }[];
23
+ }): Promise<void> {
24
+ const isProduction = process.env.NODE_ENV === "production";
25
+
26
+ if (params.token)
27
+ (await cookies()).set({
28
+ name: "token",
29
+ value: params.token,
30
+ httpOnly: false,
31
+ path: "/",
32
+ secure: isProduction,
33
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24),
34
+ });
35
+ if (params.refreshToken)
36
+ (await cookies()).set({
37
+ name: "refreshToken",
38
+ value: params.refreshToken,
39
+ httpOnly: true,
40
+ path: "/",
41
+ secure: isProduction,
42
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
43
+ });
44
+
45
+ if (params.userId)
46
+ (await cookies()).set({
47
+ name: "userId",
48
+ value: params.userId,
49
+ httpOnly: true,
50
+ path: "/",
51
+ secure: isProduction,
52
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
53
+ });
54
+
55
+ if (params.companyId)
56
+ (await cookies()).set({
57
+ name: "companyId",
58
+ value: params.companyId,
59
+ httpOnly: true,
60
+ path: "/",
61
+ secure: isProduction,
62
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
63
+ });
64
+
65
+ if (params.licenseExpirationDate)
66
+ (await cookies()).set({
67
+ name: "licenseExpirationDate",
68
+ value: params.licenseExpirationDate.toISOString(),
69
+ httpOnly: true,
70
+ path: "/",
71
+ secure: isProduction,
72
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
73
+ });
74
+
75
+ if (params.roles)
76
+ (await cookies()).set({
77
+ name: "roles",
78
+ value: JSON.stringify(params.roles),
79
+ httpOnly: true,
80
+ path: "/",
81
+ secure: isProduction,
82
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
83
+ });
84
+
85
+ if (params.features)
86
+ (await cookies()).set({
87
+ name: "features",
88
+ value: JSON.stringify(params.features),
89
+ httpOnly: true,
90
+ path: "/",
91
+ secure: isProduction,
92
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
93
+ });
94
+
95
+ if (params.modules) {
96
+ const compressedValue = zlib.gzipSync(JSON.stringify(params.modules)).toString("base64");
97
+
98
+ (await cookies()).set({
99
+ name: "modules",
100
+ value: JSON.stringify(compressedValue),
101
+ httpOnly: true,
102
+ path: "/",
103
+ secure: isProduction,
104
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
105
+ });
106
+ }
107
+ }
108
+
109
+ export async function removeToken(): Promise<void> {
110
+ (await cookies()).delete({
111
+ name: "token",
112
+ });
113
+ (await cookies()).delete({
114
+ name: "refreshToken",
115
+ });
116
+ (await cookies()).delete({
117
+ name: "userId",
118
+ });
119
+ (await cookies()).delete({
120
+ name: "companyId",
121
+ });
122
+ (await cookies()).delete({
123
+ name: "licenseExpirationDate",
124
+ });
125
+ (await cookies()).delete({
126
+ name: "roles",
127
+ });
128
+ (await cookies()).delete({
129
+ name: "features",
130
+ });
131
+ (await cookies()).delete({
132
+ name: "modules",
133
+ });
134
+ }
@@ -0,0 +1,10 @@
1
+ import type { AllModuleDefinitions } from "@/config/Bootstrapper";
2
+ import type { FoundationModuleDefinitions } from "@carlonicora/nextjs-jsonapi/core";
3
+
4
+ // Simply reference the type from Bootstrapper - NO MANUAL LIST NEEDED
5
+ // This augments AppModuleDefinitions with feature modules only
6
+ // (foundation types already defined in library's FoundationModuleDefinitions)
7
+ declare module "@carlonicora/nextjs-jsonapi/core" {
8
+ // Override the combined type to use our full definition
9
+ interface AppModuleDefinitions extends Omit<AllModuleDefinitions, keyof FoundationModuleDefinitions> {}
10
+ }
@@ -0,0 +1,50 @@
1
+ import { ENV } from "@/config/env";
2
+ import { Metadata } from "next";
3
+ import { getTranslations } from "next-intl/server";
4
+ import { headers } from "next/headers";
5
+
6
+ //https://nextjs.org/docs/app/api-reference/functions/generate-metadata
7
+
8
+ export async function generateSpecificMetadata(params: {
9
+ title?: string;
10
+ description?: string;
11
+ url?: string;
12
+ }): Promise<Metadata> {
13
+ const t = await getTranslations();
14
+
15
+ const url = (await headers()).get("x-full-url") ?? ENV.APP_URL ?? "{{name}}.com";
16
+
17
+ const title: string = params.title ? `${params.title} | ${t(`generic.title`)}` : t(`generic.title`);
18
+ const description = params.description ? params.description : t(`generic.description`);
19
+
20
+ const response: Metadata = {
21
+ title: title,
22
+ description: description,
23
+ keywords: [],
24
+ publisher: "Phlow",
25
+ openGraph: {
26
+ type: "website",
27
+ title: title,
28
+ description: description,
29
+ url: url,
30
+ siteName: "Phlow",
31
+ },
32
+ twitter: {
33
+ card: "summary_large_image",
34
+ title: title,
35
+ description: description,
36
+ },
37
+ metadataBase: new URL(ENV.APP_URL ?? "{{name}}.com"),
38
+ alternates: {
39
+ canonical: url,
40
+ languages: {
41
+ en: "/en",
42
+ it: "/it",
43
+ fr: "/fr",
44
+ fi: "/fi",
45
+ },
46
+ },
47
+ };
48
+
49
+ return response;
50
+ }
@@ -0,0 +1,7 @@
1
+ "use server";
2
+
3
+ import { revalidatePath } from "next/cache";
4
+
5
+ export async function revalidatePaths(path: string): Promise<void> {
6
+ revalidatePath(path, "page");
7
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "composite": true,
4
+ "compilerOptions": {
5
+ "baseUrl": ".",
6
+ "target": "esnext",
7
+ "lib": ["dom", "dom.iterable", "esnext"],
8
+ "allowJs": true,
9
+ "skipLibCheck": true,
10
+ "strict": false,
11
+ "strictNullChecks": false,
12
+ "noImplicitAny": false,
13
+ "strictBindCallApply": false,
14
+ "strictFunctionTypes": false,
15
+ "strictPropertyInitialization": false,
16
+ "noImplicitThis": false,
17
+ "alwaysStrict": false,
18
+ "forceConsistentCasingInFileNames": false,
19
+ "noEmit": true,
20
+ "noEmitOnError": false,
21
+ "esModuleInterop": true,
22
+ "module": "esnext",
23
+ "moduleResolution": "bundler",
24
+ "resolveJsonModule": true,
25
+ "isolatedModules": true,
26
+ "jsx": "preserve",
27
+ "incremental": true,
28
+ "noUnusedLocals": false,
29
+ "noUnusedParameters": false,
30
+ "noImplicitReturns": false,
31
+ "declaration": false,
32
+ "declarationMap": false,
33
+ "plugins": [
34
+ {
35
+ "name": "next"
36
+ }
37
+ ],
38
+ "paths": {
39
+ "@/*": ["./src/*"]
40
+ }
41
+ },
42
+ "include": [
43
+ "next-env.d.ts",
44
+ "**/*.ts",
45
+ "**/*.tsx",
46
+ "**/*.mdx",
47
+ "**/*.test.ts",
48
+ ".next/types/**/*.ts"
49
+ ],
50
+ "exclude": ["node_modules", "jest.setup.tsx"]
51
+ }
@@ -0,0 +1,211 @@
1
+ # =============================================================================
2
+ # ASSETTRACK MONOREPO - DOCKER COMPOSE CONFIGURATION
3
+ # =============================================================================
4
+ # This docker-compose.yml references environment variables from the root .env file
5
+ # It can also work with Coolify where variables are injected via Coolify's UI
6
+ #
7
+ # IMPORTANT: Infrastructure services (Neo4j, Redis, MinIO) are expected to run
8
+ # externally and are configured via the .env file connection strings.
9
+ #
10
+ # Usage:
11
+ # docker compose up # Start all three services (api, worker, web)
12
+ # docker compose up api # Start only API service
13
+ # docker compose up worker # Start only Worker service
14
+ # docker compose up web # Start only Web service
15
+ # docker compose up api worker # Start API and Worker services
16
+ # =============================================================================
17
+ x-api-worker-shared-env: &api_worker_shared_env
18
+ # Database - Use .env values (external services)
19
+ NEO4J_URI: ${NEO4J_URI}
20
+ NEO4J_USER: ${NEO4J_USER}
21
+ NEO4J_PASSWORD: ${NEO4J_PASSWORD}
22
+ NEO4J_DATABASE: ${NEO4J_DATABASE}
23
+
24
+ # Cache & Queue - Use .env values (external services)
25
+ REDIS_HOST: ${REDIS_HOST}
26
+ REDIS_PORT: ${REDIS_PORT}
27
+ REDIS_PASSWORD: ${REDIS_PASSWORD}
28
+ REDIS_USERNAME: ${REDIS_USERNAME}
29
+ REDIS_QUEUE: ${REDIS_QUEUE}
30
+
31
+ # Authentication
32
+ JWT_SECRET: ${JWT_SECRET}
33
+ JWT_EXPIRES_IN: ${JWT_EXPIRES_IN}
34
+
35
+ # Web Push - VAPID
36
+ VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY}
37
+ VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY}
38
+ VAPID_EMAIL: ${VAPID_EMAIL}
39
+
40
+ # Email Configuration
41
+ EMAIL_PROVIDER: ${EMAIL_PROVIDER}
42
+ EMAIL_API_KEY: ${EMAIL_API_KEY}
43
+ EMAIL_FROM: ${EMAIL_FROM}
44
+ EMAIL_HOST: ${EMAIL_HOST}
45
+ EMAIL_PORT: ${EMAIL_PORT}
46
+ EMAIL_SECURE: ${EMAIL_SECURE}
47
+ EMAIL_USERNAME: ${EMAIL_USERNAME}
48
+ EMAIL_PASSWORD: ${EMAIL_PASSWORD}
49
+
50
+ # Logging - Loki
51
+ LOKI_ENABLED: ${LOKI_ENABLED}
52
+ LOKI_HOST: ${LOKI_HOST}
53
+ LOKI_USERNAME: ${LOKI_USERNAME}
54
+ LOKI_PASSWORD: ${LOKI_PASSWORD}
55
+ LOKI_APP_LABEL: ${LOKI_APP_LABEL}
56
+
57
+ # Tracing - Tempo
58
+ TEMPO_ENABLED: ${TEMPO_ENABLED}
59
+ TEMPO_ENDPOINT: ${TEMPO_ENDPOINT}
60
+ TEMPO_SERVICE_NAME: ${TEMPO_SERVICE_NAME}
61
+ TEMPO_SERVICE_VERSION: ${TEMPO_SERVICE_VERSION}
62
+
63
+ # Object Storage - S3/MinIO - Use .env values (external services)
64
+ S3_TYPE: ${S3_TYPE}
65
+ S3_ENDPOINT: ${S3_ENDPOINT}
66
+ S3_BUCKET: ${S3_BUCKET}
67
+ S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
68
+ S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
69
+ S3_REGION: ${S3_REGION}
70
+
71
+ # ai
72
+ AI_PROVIDER: ${AI_PROVIDER}
73
+ AI_API_KEY: ${AI_API_KEY}
74
+ AI_MODEL: ${AI_MODEL}
75
+ AI_URL: ${AI_URL}
76
+ AI_REGION: ${AI_REGION}
77
+ AI_SECRET: ${AI_SECRET}
78
+ AI_INSTANCE: ${AI_INSTANCE}
79
+ AI_API_VERSION: ${AI_API_VERSION}
80
+ AI_INPUT_COST_PER_1M_TOKENS: ${AI_INPUT_COST_PER_1M_TOKENS}
81
+ AI_OUTPUT_COST_PER_1M_TOKENS: ${AI_OUTPUT_COST_PER_1M_TOKENS}
82
+
83
+ #transcriber
84
+ TRANSCRIBER_PROVIDER: ${TRANSCRIBER_PROVIDER}
85
+ TRANSCRIBER_API_KEY: ${TRANSCRIBER_API_KEY}
86
+ TRANSCRIBER_MODEL: ${TRANSCRIBER_MODEL}
87
+ TRANSCRIBER_URL: ${TRANSCRIBER_URL}
88
+ TRANSCRIBER_API_VERSION: ${TRANSCRIBER_API_VERSION}
89
+
90
+ # embedder
91
+ EMBEDDER_PROVIDER: ${EMBEDDER_PROVIDER}
92
+ EMBEDDER_API_KEY: ${EMBEDDER_API_KEY}
93
+ EMBEDDER_MODEL: ${EMBEDDER_MODEL}
94
+ EMBEDDER_INSTANCE: ${EMBEDDER_INSTANCE}
95
+ EMBEDDER_API_VERSION: ${EMBEDDER_API_VERSION}
96
+ EMBEDDER_DIMENSIONS: ${EMBEDDER_DIMENSIONS}
97
+
98
+ # =============================================================================
99
+
100
+ services:
101
+ # ---------------------------------------------------------------------------
102
+ # API Server (NestJS Backend)
103
+ # ---------------------------------------------------------------------------
104
+ api:
105
+ build:
106
+ context: .
107
+ dockerfile: Dockerfile
108
+ target: api-production
109
+ args:
110
+ - API_PORT=${API_PORT:-3400}
111
+ ports:
112
+ - "${API_PORT:-3400}:${API_PORT:-3400}"
113
+ environment:
114
+ <<: *api_worker_shared_env
115
+ # Build & Application Mode
116
+ PORT: ${API_PORT:-3400}
117
+ API_URL: ${API_URL}
118
+ API_PORT: ${API_PORT:-3400}
119
+ NODE_OPTIONS: ${API_NODE_OPTIONS:-"--max-old-space-size=6144"}
120
+
121
+ # Cache Configuration
122
+ CACHE_ENABLED: ${CACHE_ENABLED}
123
+ CACHE_DEFAULT_TTL: ${CACHE_DEFAULT_TTL}
124
+ CACHE_SKIP_PATTERNS: ${CACHE_SKIP_PATTERNS}
125
+
126
+ # Rate Limiting
127
+ RATE_LIMIT_ENABLED: ${RATE_LIMIT_ENABLED}
128
+ RATE_LIMIT_TTL: ${RATE_LIMIT_TTL}
129
+ RATE_LIMIT_REQUESTS: ${RATE_LIMIT_REQUESTS}
130
+ IP_RATE_LIMIT_REQUESTS: ${IP_RATE_LIMIT_REQUESTS}
131
+
132
+ # CORS Configuration
133
+ CORS_ORIGINS: ${CORS_ORIGINS}
134
+ CORS_ORIGIN_PATTERNS: ${CORS_ORIGIN_PATTERNS}
135
+ CORS_CREDENTIALS: ${CORS_CREDENTIALS}
136
+ CORS_METHODS: ${CORS_METHODS}
137
+ CORS_ALLOWED_HEADERS: ${CORS_ALLOWED_HEADERS}
138
+ CORS_MAX_AGE: ${CORS_MAX_AGE}
139
+ CORS_PREFLIGHT_CONTINUE: ${CORS_PREFLIGHT_CONTINUE}
140
+ CORS_OPTIONS_SUCCESS_STATUS: ${CORS_OPTIONS_SUCCESS_STATUS}
141
+ CORS_LOG_VIOLATIONS: ${CORS_LOG_VIOLATIONS}
142
+ healthcheck:
143
+ test: ["CMD", "node", "-e", "require('http').get({host:'localhost',port:process.env.API_PORT||3400,path:'/version'},(r)=>process.exit(r.statusCode>=200&&r.statusCode<500?0:1))"]
144
+ interval: 10s
145
+ timeout: 5s
146
+ retries: 3
147
+ start_period: 40s
148
+
149
+ # ---------------------------------------------------------------------------
150
+ # Worker (Background Job Processing)
151
+ # ---------------------------------------------------------------------------
152
+ worker:
153
+ build:
154
+ context: .
155
+ dockerfile: Dockerfile
156
+ target: api-production
157
+ environment:
158
+ <<: *api_worker_shared_env
159
+ NODE_OPTIONS: ${WORKER_NODE_OPTIONS:-"--max-old-space-size=6144"}
160
+ healthcheck:
161
+ test: ["CMD", "pgrep", "-f", "node.*dist/main.*worker"]
162
+ interval: 10s
163
+ timeout: 5s
164
+ retries: 3
165
+ start_period: 30s
166
+ command:
167
+ - node
168
+ - dist/main
169
+ - --mode=worker
170
+
171
+ # ---------------------------------------------------------------------------
172
+ # Web Application (Next.js Frontend)
173
+ # ---------------------------------------------------------------------------
174
+ web:
175
+ build:
176
+ context: .
177
+ dockerfile: Dockerfile
178
+ target: web-production
179
+ args:
180
+ - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
181
+ - NEXT_PUBLIC_ADDRESS=${NEXT_PUBLIC_ADDRESS}
182
+ - NEXT_PUBLIC_VAPID_PUBLIC_KEY=${NEXT_PUBLIC_VAPID_PUBLIC_KEY}
183
+ - NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=${NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}
184
+ - PORT=${PORT:-3401}
185
+ ports:
186
+ - "${PORT:-3401}:${PORT:-3401}"
187
+ environment:
188
+ # Build & Application Configuration
189
+ - PORT=${PORT:-3401}
190
+ - APP_URL=${APP_URL}
191
+ - NODE_OPTIONS=${WEB_NODE_OPTIONS:-"--max-old-space-size=4096"}
192
+
193
+ # API Connection
194
+ - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
195
+ - NEXT_PUBLIC_ADDRESS=${NEXT_PUBLIC_ADDRESS}
196
+ - API_INTERNAL_URL=${API_INTERNAL_URL:-http://api:3400/}
197
+
198
+ # Web Push - VAPID
199
+ - NEXT_PUBLIC_VAPID_PUBLIC_KEY=${NEXT_PUBLIC_VAPID_PUBLIC_KEY}
200
+
201
+ # Image Sources
202
+ - IMAGE_SOURCES=${IMAGE_SOURCES}
203
+
204
+ # Google Maps API Key
205
+ - NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=${NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}
206
+ healthcheck:
207
+ test: ["CMD", "node", "-e", "require('http').get({host:'localhost',port:process.env.PORT||3401,path:'/'},(r)=>process.exit(r.statusCode>=200&&r.statusCode<500?0:1))"]
208
+ interval: 10s
209
+ timeout: 5s
210
+ retries: 3
211
+ start_period: 40s
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Role Playing Game platform powered by AI",
6
+ "engines": {
7
+ "node": ">=22.0.0",
8
+ "pnpm": ">=10.0.0"
9
+ },
10
+ "packageManager": "pnpm@10.25.0",
11
+ "scripts": {
12
+ "dev": "turbo run dev dev:worker",
13
+ "dev:api": "turbo run dev --filter={{name}}-api",
14
+ "dev:web": "turbo run dev --filter={{name}}-web",
15
+ "dev:worker": "turbo run start:worker:dev --filter={{name}}-api",
16
+ "build": "turbo run build",
17
+ "build:api": "turbo run build --filter={{name}}-api",
18
+ "build:web": "turbo run build --filter={{name}}-web",
19
+ "start": "turbo run start",
20
+ "start:prod": "turbo run start:prod",
21
+ "test": "turbo run test",
22
+ "test:watch": "turbo run test:watch",
23
+ "test:e2e": "turbo run test:e2e",
24
+ "test:cov": "turbo run test:cov",
25
+ "lint": "turbo run lint",
26
+ "format": "turbo run format",
27
+ "clean": "turbo run clean && rm -rf node_modules .turbo",
28
+ "clean:all": "pnpm clean && pnpm -r exec rm -rf node_modules dist .next .turbo",
29
+ "structure": "bash scripts/import-structure.sh",
30
+ "prepare": "husky",
31
+ "preinstall": "npx only-allow pnpm",
32
+ "neo4jsonapi-migrate": "node ./packages/nestjs-neo4jsonapi/dist/tools/migrate-entity/index.js"
33
+ },
34
+ "dependencies": {
35
+ "dotenv-cli": "^11.0.0",
36
+ "zod": "^4.1.13"
37
+ },
38
+ "devDependencies": {
39
+ "@eslint/eslintrc": "^3.3.3",
40
+ "@semantic-release/changelog": "^6.0.3",
41
+ "@semantic-release/commit-analyzer": "^13.0.1",
42
+ "@semantic-release/git": "^10.0.1",
43
+ "@semantic-release/npm": "^13.1.2",
44
+ "@semantic-release/release-notes-generator": "^14.1.0",
45
+ "@types/node": "^25.0.1",
46
+ "@typescript-eslint/eslint-plugin": "^8.49.0",
47
+ "@typescript-eslint/parser": "^8.49.0",
48
+ "conventional-changelog-conventionalcommits": "^9.1.0",
49
+ "eslint": "^9.39.1",
50
+ "eslint-config-prettier": "^10.1.8",
51
+ "eslint-plugin-prettier": "^5.5.4",
52
+ "husky": "^9.1.7",
53
+ "prettier": "^3.7.4",
54
+ "semantic-release": "^25.0.2",
55
+ "ts-node": "^10.9.2",
56
+ "turbo": "^2.6.3",
57
+ "typescript": "^5.9.3"
58
+ },
59
+ "workspaces": [
60
+ "api",
61
+ "web",
62
+ "packages/*"
63
+ ],
64
+ "pnpm": {
65
+ "overrides": {
66
+ "yjs": "^13.6.27",
67
+ "validator": ">=13.15.20",
68
+ "@types/react": "19.2.7",
69
+ "@types/react-dom": "19.2.3"
70
+ }
71
+ }
72
+ }
File without changes
File without changes
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@{{name}}/shared",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsup --watch",
18
+ "clean": "rm -rf dist"
19
+ },
20
+ "devDependencies": {
21
+ "tsup": "^8.5.0"
22
+ }
23
+ }
@@ -0,0 +1,5 @@
1
+ import { SystemRoles } from "./system.roles.id";
2
+
3
+ export const RoleId = {
4
+ ...SystemRoles,
5
+ } as const;
@@ -0,0 +1,4 @@
1
+ export const SystemRoles = {
2
+ Administrator: "53394cb8-1e87-11ef-8b48-bed54b8f8aba",
3
+ CompanyAdministrator: "2e1eee00-6cba-4506-9059-ccd24e4ea5b0",
4
+ } as const;
@@ -0,0 +1 @@
1
+ export { RoleId } from "./const/roles.id";