@appinit/cli 1.2.0 → 1.3.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 (225) hide show
  1. package/LICENSE +57 -22
  2. package/README.md +27 -95
  3. package/dist/index.d.ts +371 -2
  4. package/dist/index.js +3794 -95
  5. package/dist/templates/backend-express/.appinit-generate/project/.appinit/project.json +6 -0
  6. package/dist/templates/backend-express/.appinit-generate/project/.appinit/template.json +6 -0
  7. package/dist/templates/backend-express/.appinit-generate/project/.env.example +4 -0
  8. package/dist/templates/backend-express/.appinit-generate/project/.husky/pre-commit +1 -0
  9. package/dist/templates/backend-express/.appinit-generate/project/.prettierignore +3 -0
  10. package/dist/templates/backend-express/.appinit-generate/project/.prettierrc +28 -0
  11. package/dist/templates/backend-express/.appinit-generate/project/.vscode/settings.json +6 -0
  12. package/dist/templates/backend-express/.appinit-generate/project/Dockerfile +14 -0
  13. package/dist/templates/backend-express/.appinit-generate/project/README.md +26 -0
  14. package/dist/templates/backend-express/.appinit-generate/project/eslint.config.js +76 -0
  15. package/dist/templates/backend-express/.appinit-generate/project/nodemon.json +8 -0
  16. package/dist/templates/backend-express/.appinit-generate/project/package.json +69 -0
  17. package/dist/templates/backend-express/.appinit-generate/project/src/__tests__/health.test.ts +19 -0
  18. package/dist/templates/backend-express/.appinit-generate/project/src/__tests__/validation.test.ts +36 -0
  19. package/dist/templates/backend-express/.appinit-generate/project/src/app.ts +72 -0
  20. package/dist/templates/backend-express/.appinit-generate/project/src/config/defaults.ts +5 -0
  21. package/dist/templates/backend-express/.appinit-generate/project/src/config/dev.ts +3 -0
  22. package/dist/templates/backend-express/.appinit-generate/project/src/config/env.ts +62 -0
  23. package/dist/templates/backend-express/.appinit-generate/project/src/config/prod.ts +3 -0
  24. package/dist/templates/backend-express/.appinit-generate/project/src/config/test.ts +3 -0
  25. package/dist/templates/backend-express/.appinit-generate/project/src/errors/app-error.ts +20 -0
  26. package/dist/templates/backend-express/.appinit-generate/project/src/errors/not-found.ts +16 -0
  27. package/dist/templates/backend-express/.appinit-generate/project/src/middleware/error-handler.ts +73 -0
  28. package/dist/templates/backend-express/.appinit-generate/project/src/middleware/http-logger.ts +5 -0
  29. package/dist/templates/backend-express/.appinit-generate/project/src/middleware/validate.ts +17 -0
  30. package/dist/templates/backend-express/.appinit-generate/project/src/routes/health.ts +13 -0
  31. package/dist/templates/backend-express/.appinit-generate/project/src/routes/users.ts +12 -0
  32. package/dist/templates/backend-express/.appinit-generate/project/src/schema/create-user.schema.ts +8 -0
  33. package/dist/templates/backend-express/.appinit-generate/project/src/server.ts +54 -0
  34. package/dist/templates/backend-express/.appinit-generate/project/src/utils/logger.ts +21 -0
  35. package/dist/templates/backend-express/.appinit-generate/project/tsconfig.json +30 -0
  36. package/dist/templates/backend-express/.appinit-generate/project/vitest.config.ts +15 -0
  37. package/dist/templates/backend-express/.appinit-preview/project/.appinit/project.json +6 -0
  38. package/dist/templates/backend-express/.appinit-preview/project/.appinit/template.json +6 -0
  39. package/dist/templates/backend-express/.appinit-preview/project/.env.example +4 -0
  40. package/dist/templates/backend-express/.appinit-preview/project/.husky/pre-commit +1 -0
  41. package/dist/templates/backend-express/.appinit-preview/project/.prettierignore +3 -0
  42. package/dist/templates/backend-express/.appinit-preview/project/.prettierrc +28 -0
  43. package/dist/templates/backend-express/.appinit-preview/project/.vscode/settings.json +6 -0
  44. package/dist/templates/backend-express/.appinit-preview/project/Dockerfile +14 -0
  45. package/dist/templates/backend-express/.appinit-preview/project/README.md +26 -0
  46. package/dist/templates/backend-express/.appinit-preview/project/eslint.config.js +76 -0
  47. package/dist/templates/backend-express/.appinit-preview/project/nodemon.json +8 -0
  48. package/dist/templates/backend-express/.appinit-preview/project/package.json +69 -0
  49. package/dist/templates/backend-express/.appinit-preview/project/src/__tests__/health.test.ts +19 -0
  50. package/dist/templates/backend-express/.appinit-preview/project/src/__tests__/validation.test.ts +36 -0
  51. package/dist/templates/backend-express/.appinit-preview/project/src/app.ts +72 -0
  52. package/dist/templates/backend-express/.appinit-preview/project/src/config/defaults.ts +5 -0
  53. package/dist/templates/backend-express/.appinit-preview/project/src/config/dev.ts +3 -0
  54. package/dist/templates/backend-express/.appinit-preview/project/src/config/env.ts +62 -0
  55. package/dist/templates/backend-express/.appinit-preview/project/src/config/prod.ts +3 -0
  56. package/dist/templates/backend-express/.appinit-preview/project/src/config/test.ts +3 -0
  57. package/dist/templates/backend-express/.appinit-preview/project/src/errors/app-error.ts +20 -0
  58. package/dist/templates/backend-express/.appinit-preview/project/src/errors/not-found.ts +16 -0
  59. package/dist/templates/backend-express/.appinit-preview/project/src/middleware/error-handler.ts +73 -0
  60. package/dist/templates/backend-express/.appinit-preview/project/src/middleware/http-logger.ts +5 -0
  61. package/dist/templates/backend-express/.appinit-preview/project/src/middleware/validate.ts +17 -0
  62. package/dist/templates/backend-express/.appinit-preview/project/src/routes/health.ts +13 -0
  63. package/dist/templates/backend-express/.appinit-preview/project/src/routes/users.ts +12 -0
  64. package/dist/templates/backend-express/.appinit-preview/project/src/schema/create-user.schema.ts +8 -0
  65. package/dist/templates/backend-express/.appinit-preview/project/src/server.ts +54 -0
  66. package/dist/templates/backend-express/.appinit-preview/project/src/utils/logger.ts +21 -0
  67. package/dist/templates/backend-express/.appinit-preview/project/tsconfig.json +30 -0
  68. package/dist/templates/backend-express/.appinit-preview/project/vitest.config.ts +15 -0
  69. package/dist/templates/backend-express/README.md +107 -0
  70. package/dist/templates/backend-express/appinit.template.json +25 -0
  71. package/dist/templates/backend-express/docs/README.md +11 -0
  72. package/dist/templates/backend-express/package.json +5 -0
  73. package/dist/templates/backend-express/template/.env.example +4 -0
  74. package/dist/templates/backend-express/template/.husky/pre-commit +1 -0
  75. package/dist/templates/backend-express/template/.prettierignore +3 -0
  76. package/dist/templates/backend-express/template/.prettierrc +28 -0
  77. package/dist/templates/backend-express/template/.vscode/settings.json +6 -0
  78. package/dist/templates/backend-express/template/Dockerfile +14 -0
  79. package/dist/templates/backend-express/template/README.md__tmpl +26 -0
  80. package/dist/templates/backend-express/template/eslint.config.js +76 -0
  81. package/dist/templates/backend-express/template/nodemon.json +8 -0
  82. package/dist/templates/backend-express/template/package.json__tmpl +69 -0
  83. package/dist/templates/backend-express/template/src/__tests__/health.test.ts +19 -0
  84. package/dist/templates/backend-express/template/src/__tests__/validation.test.ts +36 -0
  85. package/dist/templates/backend-express/template/src/app.ts +72 -0
  86. package/dist/templates/backend-express/template/src/config/defaults.ts +5 -0
  87. package/dist/templates/backend-express/template/src/config/dev.ts +3 -0
  88. package/dist/templates/backend-express/template/src/config/env.ts +62 -0
  89. package/dist/templates/backend-express/template/src/config/prod.ts +3 -0
  90. package/dist/templates/backend-express/template/src/config/test.ts +3 -0
  91. package/dist/templates/backend-express/template/src/errors/app-error.ts +20 -0
  92. package/dist/templates/backend-express/template/src/errors/not-found.ts +16 -0
  93. package/dist/templates/backend-express/template/src/middleware/error-handler.ts +73 -0
  94. package/dist/templates/backend-express/template/src/middleware/http-logger.ts +5 -0
  95. package/dist/templates/backend-express/template/src/middleware/validate.ts +17 -0
  96. package/dist/templates/backend-express/template/src/routes/health.ts +13 -0
  97. package/dist/templates/backend-express/template/src/routes/users.ts +12 -0
  98. package/dist/templates/backend-express/template/src/schema/create-user.schema.ts +8 -0
  99. package/dist/templates/backend-express/template/src/server.ts +54 -0
  100. package/dist/templates/backend-express/template/src/utils/logger.ts +21 -0
  101. package/dist/templates/backend-express/template/tsconfig.json +30 -0
  102. package/dist/templates/backend-express/template/vitest.config.ts +15 -0
  103. package/dist/templates/backend-express/template.config.ts +36 -0
  104. package/dist/templates/backend-express/variables/defaults.json +7 -0
  105. package/dist/templates/backend-express/variables/defaults.ts +4 -0
  106. package/dist/templates/backend-express/variables/schema.json +22 -0
  107. package/dist/templates/backend-express/variables/schema.ts +11 -0
  108. package/dist/templates/backend-express/variables/transform.ts +6 -0
  109. package/dist/templates/backend-fastify/.appinit-generate/project/.appinit/project.json +6 -0
  110. package/dist/templates/backend-fastify/.appinit-generate/project/.appinit/template.json +6 -0
  111. package/dist/templates/backend-fastify/.appinit-generate/project/README.md +26 -0
  112. package/dist/templates/backend-fastify/.appinit-generate/project/nodemon.json +8 -0
  113. package/dist/templates/backend-fastify/.appinit-generate/project/package-lock.json +3245 -0
  114. package/dist/templates/backend-fastify/.appinit-generate/project/package.json +24 -0
  115. package/dist/templates/backend-fastify/.appinit-generate/project/src/app.ts +13 -0
  116. package/dist/templates/backend-fastify/.appinit-generate/project/src/server.ts +15 -0
  117. package/dist/templates/backend-fastify/.appinit-generate/project/tsconfig.json +30 -0
  118. package/dist/templates/backend-fastify/README.md +27 -0
  119. package/dist/templates/backend-fastify/appinit.template.json +25 -0
  120. package/dist/templates/backend-fastify/docs/README.md +12 -0
  121. package/dist/templates/backend-fastify/package.json +5 -0
  122. package/dist/templates/backend-fastify/template/README.md__tmpl +26 -0
  123. package/dist/templates/backend-fastify/template/nodemon.json +8 -0
  124. package/dist/templates/backend-fastify/template/package.json__tmpl +24 -0
  125. package/dist/templates/backend-fastify/template/src/app.ts +13 -0
  126. package/dist/templates/backend-fastify/template/src/server.ts +15 -0
  127. package/dist/templates/backend-fastify/template/tsconfig.json +30 -0
  128. package/dist/templates/backend-fastify/template.config.ts +32 -0
  129. package/dist/templates/backend-fastify/variables/defaults.json +4 -0
  130. package/dist/templates/backend-fastify/variables/defaults.ts +3 -0
  131. package/dist/templates/backend-fastify/variables/schema.json +7 -0
  132. package/dist/templates/backend-fastify/variables/schema.ts +1 -0
  133. package/dist/templates/backend-fastify/variables/transform.ts +3 -0
  134. package/dist/templates/frontend-nextjs/.appinit-generate/project/.appinit/project.json +6 -0
  135. package/dist/templates/frontend-nextjs/.appinit-generate/project/.appinit/template.json +6 -0
  136. package/dist/templates/frontend-nextjs/.appinit-generate/project/README.md +33 -0
  137. package/dist/templates/frontend-nextjs/.appinit-generate/project/app/favicon.ico +0 -0
  138. package/dist/templates/frontend-nextjs/.appinit-generate/project/app/globals.css +42 -0
  139. package/dist/templates/frontend-nextjs/.appinit-generate/project/app/layout.tsx +33 -0
  140. package/dist/templates/frontend-nextjs/.appinit-generate/project/app/page.module.css +141 -0
  141. package/dist/templates/frontend-nextjs/.appinit-generate/project/app/page.tsx +67 -0
  142. package/dist/templates/frontend-nextjs/.appinit-generate/project/next-env.d.ts +6 -0
  143. package/dist/templates/frontend-nextjs/.appinit-generate/project/next.config.ts +8 -0
  144. package/dist/templates/frontend-nextjs/.appinit-generate/project/package.json +25 -0
  145. package/dist/templates/frontend-nextjs/.appinit-generate/project/public/file.svg +1 -0
  146. package/dist/templates/frontend-nextjs/.appinit-generate/project/public/globe.svg +1 -0
  147. package/dist/templates/frontend-nextjs/.appinit-generate/project/public/next.svg +1 -0
  148. package/dist/templates/frontend-nextjs/.appinit-generate/project/public/vercel.svg +1 -0
  149. package/dist/templates/frontend-nextjs/.appinit-generate/project/public/window.svg +1 -0
  150. package/dist/templates/frontend-nextjs/.appinit-generate/project/tsconfig.json +34 -0
  151. package/dist/templates/frontend-nextjs/.appinit-preview/project/.appinit/project.json +6 -0
  152. package/dist/templates/frontend-nextjs/.appinit-preview/project/.appinit/template.json +6 -0
  153. package/dist/templates/frontend-nextjs/.appinit-preview/project/README.md +33 -0
  154. package/dist/templates/frontend-nextjs/.appinit-preview/project/app/favicon.ico +0 -0
  155. package/dist/templates/frontend-nextjs/.appinit-preview/project/app/globals.css +42 -0
  156. package/dist/templates/frontend-nextjs/.appinit-preview/project/app/layout.tsx +33 -0
  157. package/dist/templates/frontend-nextjs/.appinit-preview/project/app/page.module.css +141 -0
  158. package/dist/templates/frontend-nextjs/.appinit-preview/project/app/page.tsx +67 -0
  159. package/dist/templates/frontend-nextjs/.appinit-preview/project/next-env.d.ts +6 -0
  160. package/dist/templates/frontend-nextjs/.appinit-preview/project/next.config.ts +8 -0
  161. package/dist/templates/frontend-nextjs/.appinit-preview/project/package.json +25 -0
  162. package/dist/templates/frontend-nextjs/.appinit-preview/project/public/file.svg +1 -0
  163. package/dist/templates/frontend-nextjs/.appinit-preview/project/public/globe.svg +1 -0
  164. package/dist/templates/frontend-nextjs/.appinit-preview/project/public/next.svg +1 -0
  165. package/dist/templates/frontend-nextjs/.appinit-preview/project/public/vercel.svg +1 -0
  166. package/dist/templates/frontend-nextjs/.appinit-preview/project/public/window.svg +1 -0
  167. package/dist/templates/frontend-nextjs/.appinit-preview/project/tsconfig.json +34 -0
  168. package/dist/templates/frontend-nextjs/README.md +27 -0
  169. package/dist/templates/frontend-nextjs/appinit.template.json +25 -0
  170. package/dist/templates/frontend-nextjs/docs/README.md +12 -0
  171. package/dist/templates/frontend-nextjs/package.json +5 -0
  172. package/dist/templates/frontend-nextjs/template/README.md__tmpl +33 -0
  173. package/dist/templates/frontend-nextjs/template/app/favicon.ico +0 -0
  174. package/dist/templates/frontend-nextjs/template/app/globals.css +42 -0
  175. package/dist/templates/frontend-nextjs/template/app/layout.tsx +33 -0
  176. package/dist/templates/frontend-nextjs/template/app/page.module.css +141 -0
  177. package/dist/templates/frontend-nextjs/template/app/page.tsx +67 -0
  178. package/dist/templates/frontend-nextjs/template/next-env.d.ts +6 -0
  179. package/dist/templates/frontend-nextjs/template/next.config.ts +8 -0
  180. package/dist/templates/frontend-nextjs/template/package.json__tmpl +25 -0
  181. package/dist/templates/frontend-nextjs/template/public/file.svg +1 -0
  182. package/dist/templates/frontend-nextjs/template/public/globe.svg +1 -0
  183. package/dist/templates/frontend-nextjs/template/public/next.svg +1 -0
  184. package/dist/templates/frontend-nextjs/template/public/vercel.svg +1 -0
  185. package/dist/templates/frontend-nextjs/template/public/window.svg +1 -0
  186. package/dist/templates/frontend-nextjs/template/tsconfig.json +34 -0
  187. package/dist/templates/frontend-nextjs/template.config.ts +28 -0
  188. package/dist/templates/frontend-nextjs/variables/defaults.json +6 -0
  189. package/dist/templates/frontend-nextjs/variables/defaults.ts +4 -0
  190. package/dist/templates/frontend-nextjs/variables/schema.json +22 -0
  191. package/dist/templates/frontend-nextjs/variables/schema.ts +7 -0
  192. package/dist/templates/frontend-nextjs/variables/transform.ts +3 -0
  193. package/dist/templates/frontend-react/.appinit-generate/project/.appinit/project.json +6 -0
  194. package/dist/templates/frontend-react/.appinit-generate/project/.appinit/template.json +6 -0
  195. package/dist/templates/frontend-react/appinit.template.json +26 -0
  196. package/dist/templates/frontend-react/template.config.ts +14 -18
  197. package/dist/templates/frontend-react/template.meta.json +10 -0
  198. package/dist/templates/frontend-react/variables/defaults.json +6 -0
  199. package/dist/templates/frontend-react/variables/schema.json +15 -0
  200. package/dist/templates/frontend-vue/README.md +27 -0
  201. package/dist/templates/frontend-vue/appinit.template.json +25 -0
  202. package/dist/templates/frontend-vue/docs/README.md +12 -0
  203. package/dist/templates/frontend-vue/package.json +5 -0
  204. package/dist/templates/frontend-vue/template/README.md__tmpl +31 -0
  205. package/dist/templates/frontend-vue/template/index.html +13 -0
  206. package/dist/templates/frontend-vue/template/package.json__tmpl +25 -0
  207. package/dist/templates/frontend-vue/template/public/vite.svg +1 -0
  208. package/dist/templates/frontend-vue/template/src/App.vue +30 -0
  209. package/dist/templates/frontend-vue/template/src/assets/vue.svg +1 -0
  210. package/dist/templates/frontend-vue/template/src/components/HelloWorld.vue +42 -0
  211. package/dist/templates/frontend-vue/template/src/main.ts +6 -0
  212. package/dist/templates/frontend-vue/template/src/style.css +79 -0
  213. package/dist/templates/frontend-vue/template/tsconfig.app.json +16 -0
  214. package/dist/templates/frontend-vue/template/tsconfig.json +7 -0
  215. package/dist/templates/frontend-vue/template/tsconfig.node.json +26 -0
  216. package/dist/templates/frontend-vue/template/vite.config.ts +7 -0
  217. package/dist/templates/frontend-vue/template.config.ts +32 -0
  218. package/dist/templates/frontend-vue/variables/defaults.json +6 -0
  219. package/dist/templates/frontend-vue/variables/defaults.ts +3 -0
  220. package/dist/templates/frontend-vue/variables/schema.json +22 -0
  221. package/dist/templates/frontend-vue/variables/schema.ts +1 -0
  222. package/dist/templates/frontend-vue/variables/transform.ts +3 -0
  223. package/package.json +41 -51
  224. package/bin/appinit.js +0 -15
  225. /package/dist/templates/frontend-react/template/{.env__tmpl → .env.example__tmpl} +0 -0
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "project",
3
+ "createdAt": "2025-12-18T14:18:56.212Z",
4
+ "cliVersion": "unknown",
5
+ "ats": "1.0"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "backend.backend-express.basic",
3
+ "version": "1.0.0",
4
+ "source": "builtin",
5
+ "installedAt": "2025-12-18T14:18:56.214Z"
6
+ }
@@ -0,0 +1,4 @@
1
+ NODE_ENV=development
2
+ PORT=3001
3
+ LOG_LEVEL=debug
4
+ CORS_ORIGIN=*
@@ -0,0 +1,3 @@
1
+ # Ignore artifacts:
2
+ build
3
+ coverage
@@ -0,0 +1,28 @@
1
+ {
2
+ "arrowParens": "always",
3
+ "bracketSameLine": false,
4
+ "objectWrap": "preserve",
5
+ "bracketSpacing": true,
6
+ "semi": true,
7
+ "experimentalOperatorPosition": "end",
8
+ "experimentalTernaries": false,
9
+ "singleQuote": false,
10
+ "jsxSingleQuote": false,
11
+ "quoteProps": "as-needed",
12
+ "trailingComma": "all",
13
+ "singleAttributePerLine": false,
14
+ "htmlWhitespaceSensitivity": "css",
15
+ "vueIndentScriptAndStyle": false,
16
+ "proseWrap": "preserve",
17
+ "endOfLine": "lf",
18
+ "insertPragma": false,
19
+ "printWidth": 80,
20
+ "requirePragma": false,
21
+ "tabWidth": 2,
22
+ "useTabs": false,
23
+ "embeddedLanguageFormatting": "auto",
24
+ "importOrder": ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
25
+ "importOrderSeparation": true,
26
+ "importOrderSortSpecifiers": true,
27
+ "plugins": ["@trivago/prettier-plugin-sort-imports"]
28
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
4
+ "eslint.format.enable": false,
5
+ "prettier.requireConfig": true
6
+ }
@@ -0,0 +1,14 @@
1
+ FROM node:20-alpine AS builder
2
+ WORKDIR /app
3
+ COPY package*.json ./
4
+ RUN npm ci
5
+ COPY . .
6
+ RUN npm run build
7
+
8
+ FROM node:20-alpine
9
+ WORKDIR /app
10
+ ENV NODE_ENV=production
11
+ COPY --from=builder /app/dist ./dist
12
+ COPY --from=builder /app/node_modules ./node_modules
13
+ EXPOSE 3001
14
+ CMD ["node", "dist/server.js"]
@@ -0,0 +1,26 @@
1
+ # ⚛️ backend-express
2
+
3
+ This project was generated using **AppInit 1.0**.
4
+
5
+ ## 🚀 Quick Start
6
+
7
+ ```bash
8
+ pnpm install
9
+ pnpm dev
10
+ ```
11
+
12
+ ## 🛠️ Stack Configuration
13
+
14
+ - **Framework**: React 18+ (Vite)
15
+ - **Engine Used**:
16
+ - **Generated At**:
17
+
18
+ ## 📂 Project Structure
19
+
20
+ - `src/`: Your React components and logic.
21
+ - `public/`: Static assets (images, icons).
22
+ - `tailwind.config.js`: Styling configuration.
23
+
24
+ ---
25
+
26
+ _Built with speed using the AppInit Scaffolding Engine._
@@ -0,0 +1,76 @@
1
+ import js from "@eslint/js";
2
+ import tsPlugin from "@typescript-eslint/eslint-plugin";
3
+ import tsParser from "@typescript-eslint/parser";
4
+ import prettier from "eslint-config-prettier";
5
+
6
+ export default [
7
+ // ─────────────────────────────────────────────
8
+ // Global ignores (ESLint v9 way)
9
+ // ─────────────────────────────────────────────
10
+ {
11
+ ignores: ["dist/**", "node_modules/**", "coverage/**"],
12
+ },
13
+
14
+ // ─────────────────────────────────────────────
15
+ // Base JS rules
16
+ // ─────────────────────────────────────────────
17
+ js.configs.recommended,
18
+
19
+ // ─────────────────────────────────────────────
20
+ // TypeScript (Node backend)
21
+ // ─────────────────────────────────────────────
22
+ {
23
+ files: ["src/**/*.ts"],
24
+ languageOptions: {
25
+ parser: tsParser,
26
+ parserOptions: {
27
+ project: "./tsconfig.json",
28
+ sourceType: "module",
29
+ },
30
+ globals: {
31
+ process: "readonly",
32
+ console: "readonly",
33
+ setTimeout: "readonly",
34
+ clearTimeout: "readonly",
35
+ },
36
+ },
37
+ plugins: {
38
+ "@typescript-eslint": tsPlugin,
39
+ },
40
+ rules: {
41
+ /* Disable base JS rules */
42
+ "no-undef": "off",
43
+ "no-unused-vars": "off",
44
+
45
+ /* TypeScript correctness */
46
+ "@typescript-eslint/no-unused-vars": [
47
+ "warn",
48
+ { argsIgnorePattern: "^_" },
49
+ ],
50
+ "@typescript-eslint/no-floating-promises": "error",
51
+ "@typescript-eslint/no-misused-promises": "error",
52
+
53
+ /* Production discipline */
54
+ "no-console": "error",
55
+ "no-debugger": "error",
56
+
57
+ /* Reality */
58
+ "@typescript-eslint/no-explicit-any": "off",
59
+ },
60
+ },
61
+
62
+ // ─────────────────────────────────────────────
63
+ // Allow console ONLY in env bootstrap
64
+ // ─────────────────────────────────────────────
65
+ {
66
+ files: ["src/config/env.ts"],
67
+ rules: {
68
+ "no-console": "off",
69
+ },
70
+ },
71
+
72
+ // ─────────────────────────────────────────────
73
+ // Disable formatting rules (Prettier owns formatting)
74
+ // ─────────────────────────────────────────────
75
+ prettier,
76
+ ];
@@ -0,0 +1,8 @@
1
+ {
2
+ "watch": ["src"],
3
+ "ext": "ts",
4
+ "ignore": ["dist", "node_modules"],
5
+ "exec": "tsx src/server.ts",
6
+ "signal": "SIGTERM",
7
+ "delay": "100"
8
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "my-express-app",
3
+ "description": "%%description | default:'Backend API built with AppInit'%%",
4
+ "author": "",
5
+ "license": "",
6
+ "version": "0.0.0",
7
+ "private": true,
8
+ "type": "module",
9
+ "scripts": {
10
+ "dev": "nodemon",
11
+ "clean": "rimraf dist",
12
+ "build": "npm run clean && tsc",
13
+ "start": "node dist/server.js",
14
+ "format": "prettier --write .",
15
+ "format:check": "prettier --check .",
16
+ "typecheck": "tsc --noEmit",
17
+ "lint": "eslint .",
18
+ "lint:fix": "eslint . --fix",
19
+ "test": "vitest",
20
+ "test:run": "vitest run",
21
+ "test:watch": "vitest watch",
22
+ "test:coverage": "vitest run --coverage",
23
+ "prepare": "husky"
24
+ },
25
+ "lint-staged": {
26
+ "**/*": "prettier --write --ignore-unknown"
27
+ },
28
+ "main": "index.js",
29
+ "keywords": [],
30
+ "dependencies": {
31
+ "compression": "^1.8.1",
32
+ "cors": "^2.8.5",
33
+ "dotenv": "^17.2.3",
34
+ "express": "^5.2.1",
35
+ "helmet": "^8.1.0",
36
+ "http-errors": "^2.0.1",
37
+ "pino": "^10.1.0",
38
+ "pino-http": "^11.0.0",
39
+ "uuid": "^13.0.0",
40
+ "zod": "^4.2.1"
41
+ },
42
+ "devDependencies": {
43
+ "@trivago/prettier-plugin-sort-imports": "^6.0.0",
44
+ "@types/compression": "^1.8.1",
45
+ "@types/cors": "^2.8.19",
46
+ "@types/express": "^5.0.6",
47
+ "@types/morgan": "^1.9.10",
48
+ "@types/node": "^25.0.2",
49
+ "@types/supertest": "^6.0.3",
50
+ "@typescript-eslint/eslint-plugin": "^8.50.0",
51
+ "@typescript-eslint/parser": "^8.50.0",
52
+ "eslint": "^9.39.2",
53
+ "eslint-config-prettier": "^10.1.8",
54
+ "husky": "^9.1.7",
55
+ "lint-staged": "^16.2.7",
56
+ "morgan": "^1.10.1",
57
+ "nodemon": "^3.1.11",
58
+ "pino-pretty": "^13.1.3",
59
+ "prettier": "3.7.4",
60
+ "rimraf": "^6.1.2",
61
+ "supertest": "^7.1.4",
62
+ "tsx": "^4.21.0",
63
+ "typescript": "^5.9.3",
64
+ "vitest": "^4.0.16"
65
+ },
66
+ "engines": {
67
+ "node": ">=18"
68
+ }
69
+ }
@@ -0,0 +1,19 @@
1
+ import request from "supertest";
2
+
3
+ import { app } from "../app.js";
4
+
5
+ describe("Health endpoints", () => {
6
+ it("GET /health should return ok", async () => {
7
+ const res = await request(app).get("/api/health");
8
+
9
+ expect(res.status).toBe(200);
10
+ expect(res.body).toEqual({ status: "ok" });
11
+ });
12
+
13
+ it("GET /ready should return ready", async () => {
14
+ const res = await request(app).get("/api/health/ready");
15
+
16
+ expect(res.status).toBe(200);
17
+ expect(res.body).toEqual({ ready: true });
18
+ });
19
+ });
@@ -0,0 +1,36 @@
1
+ import request from "supertest";
2
+
3
+ import { app } from "../app.js";
4
+
5
+ describe("Zod validation errors", () => {
6
+ it("returns 400 with field errors", async () => {
7
+ const res = await request(app)
8
+ .post("/api/users")
9
+ .send({ email: "invalid", password: "123" });
10
+
11
+ expect(res.status).toBe(400);
12
+ expect(res.body).toEqual({
13
+ error: {
14
+ code: "VALIDATION_ERROR",
15
+ message: "Invalid request",
16
+ fields: {
17
+ "body.email": ["Invalid email address"],
18
+ "body.password": [
19
+ "Too small: expected string to have >=8 characters",
20
+ ],
21
+ },
22
+ },
23
+ });
24
+ });
25
+
26
+ it("returns 201 with register", async () => {
27
+ const res = await request(app)
28
+ .post("/api/users")
29
+ .send({ email: "abc@gmail.com", password: "12345678" });
30
+
31
+ expect(res.status).toBe(201);
32
+ expect(res.body).toEqual({
33
+ ok: true,
34
+ });
35
+ });
36
+ });
@@ -0,0 +1,72 @@
1
+ import compression from "compression";
2
+ import cors from "cors";
3
+ import express, { Express } from "express";
4
+ import type { Request, Response } from "express";
5
+ import helmet from "helmet";
6
+ import morgan from "morgan";
7
+ import path from "path";
8
+ import { fileURLToPath } from "url";
9
+
10
+ import { env } from "./config/env";
11
+ import { notFoundHandler } from "./errors/not-found";
12
+ import { errorHandler } from "./middleware/error-handler";
13
+ import { httpLogger } from "./middleware/http-logger";
14
+ import { healthRouter } from "./routes/health";
15
+ import { userRouter } from "./routes/users";
16
+
17
+ // Define __dirname for ESM
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
+
21
+ const app: Express = express();
22
+
23
+ /**
24
+ * 1. SECURITY MIDDLEWARE
25
+ */
26
+ app.use(helmet());
27
+ app.use(cors({ origin: env.corsOrigin }));
28
+
29
+ /**
30
+ * 2. PERFORMANCE MIDDLEWARE
31
+ */
32
+ app.use(compression());
33
+
34
+ /**
35
+ * 3. REQUEST PARSING
36
+ */
37
+ app.use(express.json({ limit: "10kb" }));
38
+ app.use(express.urlencoded({ extended: true, limit: "10kb" }));
39
+
40
+ /**
41
+ * 4. LOGGING & STATIC FILES
42
+ */
43
+ app.use(httpLogger);
44
+ if (process.env.NODE_ENV !== "production") {
45
+ app.use(morgan("dev"));
46
+ } else {
47
+ app.use(morgan("combined"));
48
+ }
49
+
50
+ // Fixed static path for ESM
51
+ app.use(express.static(path.join(__dirname, "../public")));
52
+
53
+ /**
54
+ * 5. SETTINGS
55
+ */
56
+ app.disable("x-powered-by");
57
+
58
+ // route
59
+ app.get("/", (_req: Request, res: Response) => {
60
+ res.status(200).json({
61
+ version: "1.0.0",
62
+ });
63
+ });
64
+
65
+ app.use("/api/health", healthRouter);
66
+ app.use("/api/users", userRouter);
67
+ /* 404 */
68
+ app.use(notFoundHandler);
69
+
70
+ /* error handler (LAST) */
71
+ app.use(errorHandler);
72
+ export { app };
@@ -0,0 +1,5 @@
1
+ export const defaults = {
2
+ port: 3001,
3
+ logLevel: "info" as const,
4
+ corsOrigin: "*",
5
+ };
@@ -0,0 +1,3 @@
1
+ export const developmentConfig = {
2
+ logLevel: "debug" as const,
3
+ };
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+
3
+ import { defaults } from "./defaults";
4
+ import { developmentConfig } from "./dev";
5
+ import { productionConfig } from "./prod";
6
+ import { testConfig } from "./test";
7
+
8
+ /**
9
+ * Load dotenv ONLY outside production
10
+ */
11
+ if (process.env.NODE_ENV !== "production") {
12
+ await import("dotenv/config");
13
+ }
14
+
15
+ /**
16
+ * Raw env schema (what the platform provides)
17
+ */
18
+ const rawEnvSchema = z.object({
19
+ NODE_ENV: z
20
+ .enum(["development", "test", "production"])
21
+ .default("development"),
22
+ PORT: z.coerce.number().int().positive().optional(),
23
+ LOG_LEVEL: z
24
+ .enum(["fatal", "error", "warn", "info", "debug", "trace"])
25
+ .optional(),
26
+ CORS_ORIGIN: z.string().optional(),
27
+ });
28
+
29
+ /**
30
+ * Validate process.env
31
+ */
32
+ const parsed = rawEnvSchema.safeParse(process.env);
33
+
34
+ if (!parsed.success) {
35
+ console.error("❌ Invalid environment variables");
36
+ console.error(parsed.error.format());
37
+ process.exit(1);
38
+ }
39
+
40
+ const nodeEnv = parsed.data.NODE_ENV;
41
+
42
+ /**
43
+ * Select environment config
44
+ */
45
+ const envConfigMap = {
46
+ development: developmentConfig,
47
+ test: testConfig,
48
+ production: productionConfig,
49
+ } as const;
50
+
51
+ const envOverrides = envConfigMap[nodeEnv];
52
+
53
+ /**
54
+ * Final resolved config (single export)
55
+ */
56
+ export const env = {
57
+ nodeEnv,
58
+
59
+ port: parsed.data.PORT ?? defaults.port,
60
+ logLevel: parsed.data.LOG_LEVEL ?? envOverrides.logLevel ?? defaults.logLevel,
61
+ corsOrigin: parsed.data.CORS_ORIGIN ?? defaults.corsOrigin,
62
+ } as const;
@@ -0,0 +1,3 @@
1
+ export const productionConfig = {
2
+ logLevel: "info" as const,
3
+ };
@@ -0,0 +1,3 @@
1
+ export const testConfig = {
2
+ logLevel: "silent" as const,
3
+ };
@@ -0,0 +1,20 @@
1
+ export class AppError extends Error {
2
+ public readonly statusCode: number;
3
+ public readonly code: string;
4
+ public readonly isOperational: boolean;
5
+
6
+ constructor(
7
+ message: string,
8
+ options: {
9
+ statusCode?: number;
10
+ code?: string;
11
+ isOperational?: boolean;
12
+ } = {},
13
+ ) {
14
+ super(message);
15
+
16
+ this.statusCode = options.statusCode ?? 500;
17
+ this.code = options.code ?? "INTERNAL_SERVER_ERROR";
18
+ this.isOperational = options.isOperational ?? true;
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+
3
+ import { AppError } from "../errors/app-error.js";
4
+
5
+ export function notFoundHandler(
6
+ _req: Request,
7
+ _res: Response,
8
+ next: NextFunction,
9
+ ) {
10
+ next(
11
+ new AppError("Route not found", {
12
+ statusCode: 404,
13
+ code: "NOT_FOUND",
14
+ }),
15
+ );
16
+ }
@@ -0,0 +1,73 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ import { ZodError } from "zod";
3
+
4
+ import { env } from "../config/env.js";
5
+ import { AppError } from "../errors/app-error.js";
6
+ import { logger } from "../utils/logger.js";
7
+
8
+ export function errorHandler(
9
+ err: unknown,
10
+ _req: Request,
11
+ res: Response,
12
+ _next: NextFunction,
13
+ ) {
14
+ /**
15
+ * Zod validation errors (400)
16
+ */
17
+ if (err instanceof ZodError) {
18
+ const fieldErrors: Record<string, string[]> = {};
19
+
20
+ for (const issue of err.issues) {
21
+ const field = issue.path.join(".") || "root";
22
+ fieldErrors[field] ??= [];
23
+ fieldErrors[field].push(issue.message);
24
+ }
25
+
26
+ logger.warn({ fieldErrors }, "Request validation failed");
27
+
28
+ return res.status(400).json({
29
+ error: {
30
+ code: "VALIDATION_ERROR",
31
+ message: "Invalid request",
32
+ fields: fieldErrors,
33
+ },
34
+ });
35
+ }
36
+ // Normalize error
37
+ const error =
38
+ err instanceof AppError
39
+ ? err
40
+ : new AppError("Internal server error", {
41
+ statusCode: 500,
42
+ code: "INTERNAL_SERVER_ERROR",
43
+ isOperational: false,
44
+ });
45
+
46
+ // Log full error (always)
47
+ logger.error(
48
+ {
49
+ err,
50
+ statusCode: error.statusCode,
51
+ code: error.code,
52
+ },
53
+ "Unhandled application error",
54
+ );
55
+
56
+ // Response (safe for clients)
57
+ const response: Record<string, unknown> = {
58
+ error: {
59
+ code: error.code,
60
+ message: error.message,
61
+ },
62
+ };
63
+
64
+ // Dev-only details
65
+ if (env.nodeEnv !== "production") {
66
+ response.error = {
67
+ ...(response.error ?? {}),
68
+ details: err instanceof Error ? err.stack : err,
69
+ };
70
+ }
71
+
72
+ res.status(error.statusCode).json(response);
73
+ }
@@ -0,0 +1,5 @@
1
+ import pinoHttp from "pino-http";
2
+
3
+ import { logger } from "../utils/logger.js";
4
+
5
+ export const httpLogger = pinoHttp({ logger });
@@ -0,0 +1,17 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ import type { ZodSchema } from "zod";
3
+
4
+ export const validate =
5
+ <T>(schema: ZodSchema<T>) =>
6
+ (req: Request, _res: Response, next: NextFunction) => {
7
+ try {
8
+ schema.parse({
9
+ body: req.body,
10
+ query: req.query,
11
+ params: req.params,
12
+ });
13
+ next();
14
+ } catch (err) {
15
+ next(err);
16
+ }
17
+ };
@@ -0,0 +1,13 @@
1
+ import { Router } from "express";
2
+
3
+ export const router = Router();
4
+
5
+ router.get("/", (_req, res) => {
6
+ res.status(200).json({ status: "ok" });
7
+ });
8
+
9
+ router.get("/ready", (_req, res) => {
10
+ res.status(200).json({ ready: true });
11
+ });
12
+
13
+ export { router as healthRouter };
@@ -0,0 +1,12 @@
1
+ import { Router } from "express";
2
+
3
+ import { validate } from "../middleware/validate";
4
+ import { createUserSchema } from "../schema/create-user.schema";
5
+
6
+ const router = Router();
7
+
8
+ router.post("/", validate(createUserSchema), (_req, res) => {
9
+ res.status(201).json({ ok: true });
10
+ });
11
+
12
+ export { router as userRouter };
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+
3
+ export const createUserSchema = z.object({
4
+ body: z.object({
5
+ email: z.email(),
6
+ password: z.string().min(8),
7
+ }),
8
+ });