@skyf0xx/hedgehog-core-full-stack-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 (137) hide show
  1. package/CLAUDE.core.md +147 -0
  2. package/LICENSE +21 -0
  3. package/README.md +41 -0
  4. package/agents/backend-eng.md +189 -0
  5. package/agents/front-end-eng.md +176 -0
  6. package/agents/ux-planner.md +174 -0
  7. package/hedgehog-core.yaml +20 -0
  8. package/package.json +41 -0
  9. package/skills/hedgehog-bootstrap/SKILL.md +324 -0
  10. package/skills/hedgehog-bootstrap-full-stack-app-core/SKILL.md +411 -0
  11. package/skills/hedgehog-loop/SKILL.md +643 -0
  12. package/skills/link-workspace-packages/SKILL.md +41 -0
  13. package/skills/nx-generate/SKILL.md +165 -0
  14. package/skills/nx-run-tasks/SKILL.md +52 -0
  15. package/skills/nx-workspace/SKILL.md +261 -0
  16. package/skills/nx-workspace/references/AFFECTED.md +27 -0
  17. package/vendor-skills/GSAP/ATTRIBUTION.md +30 -0
  18. package/vendor-skills/GSAP/LICENSE +21 -0
  19. package/vendor-skills/GSAP/gsap-core/SKILL.md +254 -0
  20. package/vendor-skills/GSAP/gsap-frameworks/SKILL.md +266 -0
  21. package/vendor-skills/GSAP/gsap-performance/SKILL.md +79 -0
  22. package/vendor-skills/GSAP/gsap-plugins/SKILL.md +433 -0
  23. package/vendor-skills/GSAP/gsap-react/SKILL.md +136 -0
  24. package/vendor-skills/GSAP/gsap-scrolltrigger/SKILL.md +296 -0
  25. package/vendor-skills/GSAP/gsap-timeline/SKILL.md +107 -0
  26. package/vendor-skills/GSAP/gsap-utils/SKILL.md +284 -0
  27. package/vendor-skills/GSAP/llms.txt +39 -0
  28. package/workspace/.env.example +5 -0
  29. package/workspace/.github/workflows/phase-gate.yml +17 -0
  30. package/workspace/.prettierignore +5 -0
  31. package/workspace/.prettierrc +3 -0
  32. package/workspace/.vscode/extensions.json +3 -0
  33. package/workspace/apps/api/eslint.config.mjs +3 -0
  34. package/workspace/apps/api/package.json +117 -0
  35. package/workspace/apps/api/src/app/app.module.spec.ts +15 -0
  36. package/workspace/apps/api/src/app/app.module.ts +15 -0
  37. package/workspace/apps/api/src/app/feature-modules.ts +8 -0
  38. package/workspace/apps/api/src/app/health.controller.ts +9 -0
  39. package/workspace/apps/api/src/assets/.gitkeep +0 -0
  40. package/workspace/apps/api/src/main.ts +32 -0
  41. package/workspace/apps/api/tsconfig.app.json +22 -0
  42. package/workspace/apps/api/tsconfig.json +13 -0
  43. package/workspace/apps/api/tsconfig.spec.json +36 -0
  44. package/workspace/apps/api/vitest.config.mts +18 -0
  45. package/workspace/apps/api/webpack.config.cjs +25 -0
  46. package/workspace/apps/api-e2e/eslint.config.mjs +3 -0
  47. package/workspace/apps/api-e2e/package.json +28 -0
  48. package/workspace/apps/api-e2e/src/api/api.spec.ts +11 -0
  49. package/workspace/apps/api-e2e/src/support/global-setup.ts +17 -0
  50. package/workspace/apps/api-e2e/src/support/test-setup.ts +6 -0
  51. package/workspace/apps/api-e2e/tsconfig.json +10 -0
  52. package/workspace/apps/api-e2e/tsconfig.spec.json +28 -0
  53. package/workspace/apps/api-e2e/vitest.config.mts +20 -0
  54. package/workspace/apps/web/.env.example +12 -0
  55. package/workspace/apps/web/.prettierrc.js +10 -0
  56. package/workspace/apps/web/.swcrc +30 -0
  57. package/workspace/apps/web/components.json +21 -0
  58. package/workspace/apps/web/eslint.config.mjs +12 -0
  59. package/workspace/apps/web/index.d.ts +7 -0
  60. package/workspace/apps/web/next-env.d.ts +7 -0
  61. package/workspace/apps/web/next.config.js +9 -0
  62. package/workspace/apps/web/package.json +38 -0
  63. package/workspace/apps/web/postcss.config.mjs +7 -0
  64. package/workspace/apps/web/public/.gitkeep +0 -0
  65. package/workspace/apps/web/public/favicon.ico +0 -0
  66. package/workspace/apps/web/src/app/global.css +83 -0
  67. package/workspace/apps/web/src/app/layout.tsx +34 -0
  68. package/workspace/apps/web/src/app/module-routes.ts +13 -0
  69. package/workspace/apps/web/src/app/page.tsx +34 -0
  70. package/workspace/apps/web/src/app/providers.tsx +12 -0
  71. package/workspace/apps/web/src/components/theme-toggle.spec.tsx +20 -0
  72. package/workspace/apps/web/src/components/theme-toggle.tsx +32 -0
  73. package/workspace/apps/web/src/components/ui/button.tsx +60 -0
  74. package/workspace/apps/web/src/lib/utils.ts +6 -0
  75. package/workspace/apps/web/src/test-setup.ts +1 -0
  76. package/workspace/apps/web/tsconfig.json +62 -0
  77. package/workspace/apps/web/tsconfig.spec.json +37 -0
  78. package/workspace/apps/web/vitest.config.mts +27 -0
  79. package/workspace/apps/web-e2e/eslint.config.mjs +12 -0
  80. package/workspace/apps/web-e2e/package.json +10 -0
  81. package/workspace/apps/web-e2e/playwright.config.mts +75 -0
  82. package/workspace/apps/web-e2e/src/example.spec.ts +7 -0
  83. package/workspace/apps/web-e2e/tsconfig.json +26 -0
  84. package/workspace/commitlint.config.cjs +3 -0
  85. package/workspace/core.yaml +68 -0
  86. package/workspace/docker-compose.yml +14 -0
  87. package/workspace/eslint.config.mjs +15 -0
  88. package/workspace/gitignore.template +24 -0
  89. package/workspace/lefthook.yml +52 -0
  90. package/workspace/nx.json +90 -0
  91. package/workspace/package.json +99 -0
  92. package/workspace/packages/config/eslint-base.js +205 -0
  93. package/workspace/packages/config/package.json +28 -0
  94. package/workspace/packages/config/prettier.js +13 -0
  95. package/workspace/packages/config/src/env.schema.spec.ts +38 -0
  96. package/workspace/packages/config/src/env.schema.ts +18 -0
  97. package/workspace/packages/config/src/index.ts +1 -0
  98. package/workspace/packages/config/tsconfig.json +13 -0
  99. package/workspace/packages/config/tsconfig.lib.json +27 -0
  100. package/workspace/packages/config/tsconfig.spec.json +34 -0
  101. package/workspace/packages/config/vitest.config.mts +18 -0
  102. package/workspace/packages/db/package.json +27 -0
  103. package/workspace/packages/db/src/index.ts +2 -0
  104. package/workspace/packages/db/src/lib/db.spec.ts +48 -0
  105. package/workspace/packages/db/src/lib/db.ts +54 -0
  106. package/workspace/packages/db/src/schema/index.ts +4 -0
  107. package/workspace/packages/db/tsconfig.json +13 -0
  108. package/workspace/packages/db/tsconfig.lib.json +27 -0
  109. package/workspace/packages/db/tsconfig.spec.json +34 -0
  110. package/workspace/packages/db/vitest.config.mts +18 -0
  111. package/workspace/pnpm-lock.yaml +23719 -0
  112. package/workspace/pnpm-workspace.yaml +7 -0
  113. package/workspace/tools/generate-feature-modules.cjs +104 -0
  114. package/workspace/tools/generate-module-routes.cjs +89 -0
  115. package/workspace/tools/generators/contract/generator.ts +336 -0
  116. package/workspace/tools/generators/contract/schema.json +24 -0
  117. package/workspace/tools/generators/controller/generator.ts +390 -0
  118. package/workspace/tools/generators/controller/schema.json +24 -0
  119. package/workspace/tools/generators/fields.ts +160 -0
  120. package/workspace/tools/generators/generators.json +42 -0
  121. package/workspace/tools/generators/hook/generator.ts +291 -0
  122. package/workspace/tools/generators/hook/schema.json +19 -0
  123. package/workspace/tools/generators/lib-shell.ts +124 -0
  124. package/workspace/tools/generators/naming.ts +84 -0
  125. package/workspace/tools/generators/package.json +6 -0
  126. package/workspace/tools/generators/repository/generator.ts +298 -0
  127. package/workspace/tools/generators/repository/schema.json +15 -0
  128. package/workspace/tools/generators/schema/generator.ts +169 -0
  129. package/workspace/tools/generators/schema/schema.json +20 -0
  130. package/workspace/tools/generators/screen/generator.ts +218 -0
  131. package/workspace/tools/generators/screen/schema.json +15 -0
  132. package/workspace/tools/generators/service/generator.ts +270 -0
  133. package/workspace/tools/generators/service/schema.json +19 -0
  134. package/workspace/tools/phase-gate.cjs +77 -0
  135. package/workspace/tsconfig.base.json +21 -0
  136. package/workspace/tsconfig.json +25 -0
  137. package/workspace/vitest.workspace.ts +4 -0
@@ -0,0 +1,62 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "preserve",
5
+ "noEmit": true,
6
+ "emitDeclarationOnly": false,
7
+ "esModuleInterop": true,
8
+ "module": "esnext",
9
+ "moduleResolution": "bundler",
10
+ "resolveJsonModule": true,
11
+ "lib": ["dom", "dom.iterable", "esnext"],
12
+ "allowJs": true,
13
+ "allowSyntheticDefaultImports": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ },
24
+ "outDir": "dist",
25
+ "rootDir": "src",
26
+ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo"
27
+ },
28
+ "include": [
29
+ "src/**/*.ts",
30
+ "src/**/*.tsx",
31
+ "src/**/*.js",
32
+ "src/**/*.jsx",
33
+ "../../apps/web/.next/types/**/*.ts",
34
+ "../../dist/apps/web/.next/types/**/*.ts",
35
+ "index.d.ts",
36
+ "next-env.d.ts"
37
+ ],
38
+ "exclude": [
39
+ "out-tsc",
40
+ "dist",
41
+ "node_modules",
42
+ "jest.config.ts",
43
+ "jest.config.cts",
44
+ "src/test-setup.ts",
45
+ "src/**/*.spec.ts",
46
+ "src/**/*.test.ts",
47
+ "src/**/*.spec.tsx",
48
+ "src/**/*.test.tsx",
49
+ ".next",
50
+ "eslint.config.js",
51
+ "eslint.config.cjs",
52
+ "eslint.config.mjs"
53
+ ],
54
+ "references": [
55
+ {
56
+ "path": "../../packages/config"
57
+ },
58
+ {
59
+ "path": "./tsconfig.spec.json"
60
+ }
61
+ ]
62
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./out-tsc/vitest",
5
+ "jsx": "preserve",
6
+ "types": [
7
+ "vitest/globals",
8
+ "vitest/importMeta",
9
+ "vite/client",
10
+ "node",
11
+ "vitest",
12
+ "@testing-library/jest-dom"
13
+ ],
14
+ "forceConsistentCasingInFileNames": true
15
+ },
16
+ "include": [
17
+ "vite.config.ts",
18
+ "vite.config.mts",
19
+ "vitest.config.ts",
20
+ "vitest.config.mts",
21
+ "src/test-setup.ts",
22
+ "src/**/*.test.ts",
23
+ "src/**/*.spec.ts",
24
+ "src/**/*.test.tsx",
25
+ "src/**/*.spec.tsx",
26
+ "src/**/*.test.js",
27
+ "src/**/*.spec.js",
28
+ "src/**/*.test.jsx",
29
+ "src/**/*.spec.jsx",
30
+ "src/**/*.d.ts"
31
+ ],
32
+ "references": [
33
+ {
34
+ "path": "../../packages/config"
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,27 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import react from '@vitejs/plugin-react';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ export default defineConfig(() => ({
6
+ root: __dirname,
7
+ cacheDir: '../../node_modules/.vite/apps/web',
8
+ plugins: [react()],
9
+ resolve: {
10
+ alias: {
11
+ '@': fileURLToPath(new URL('./src', import.meta.url)),
12
+ },
13
+ },
14
+ test: {
15
+ name: 'web',
16
+ watch: false,
17
+ globals: true,
18
+ environment: 'jsdom',
19
+ setupFiles: ['./src/test-setup.ts'],
20
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
21
+ reporters: ['default'],
22
+ coverage: {
23
+ reportsDirectory: './test-output/vitest/coverage',
24
+ provider: 'v8' as const,
25
+ },
26
+ },
27
+ }));
@@ -0,0 +1,12 @@
1
+ import playwright from 'eslint-plugin-playwright';
2
+ import baseConfig from '../../eslint.config.mjs';
3
+
4
+ export default [
5
+ playwright.configs['flat/recommended'],
6
+ ...baseConfig,
7
+ {
8
+ files: ['**/*.ts', '**/*.js'],
9
+ // Override or add rules here
10
+ rules: {},
11
+ },
12
+ ];
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "web-e2e",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "nx": {
6
+ "implicitDependencies": [
7
+ "web"
8
+ ]
9
+ }
10
+ }
@@ -0,0 +1,75 @@
1
+ import { defineConfig, devices } from '@playwright/test';
2
+ import { nxE2EPreset } from '@nx/playwright/preset';
3
+ import { workspaceRoot } from '@nx/devkit';
4
+
5
+ // For CI, you may want to set BASE_URL to the deployed application.
6
+ const baseURL = process.env['BASE_URL'] || 'http://localhost:3000';
7
+
8
+ /**
9
+ * Read environment variables from file.
10
+ * https://github.com/motdotla/dotenv
11
+ */
12
+ // import 'dotenv/config';
13
+
14
+ /**
15
+ * See https://playwright.dev/docs/test-configuration.
16
+ *
17
+ * Generated as a .mts file so Node forces ESM regardless of workspace
18
+ * `type`. Playwright routes `.mts` through its ESM loader (dynamic import,
19
+ * bypassing the pirates CJS-compile path), and Nx's native TS strip loads
20
+ * `.mts` directly. Playwright's configLoader auto-discovers
21
+ * `playwright.config.mts` via its extension list
22
+ * (.ts/.js/.mts/.mjs/.cts/.cjs).
23
+ */
24
+ export default defineConfig({
25
+ ...nxE2EPreset(import.meta.dirname, { testDir: './src' }),
26
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
27
+ use: {
28
+ baseURL,
29
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30
+ trace: 'on-first-retry',
31
+ },
32
+ /* Run your local dev server before starting the tests */
33
+ webServer: {
34
+ command: 'pnpm exec nx run web:dev',
35
+ url: 'http://localhost:3000',
36
+ reuseExistingServer: true,
37
+ cwd: workspaceRoot,
38
+ },
39
+ projects: [
40
+ {
41
+ name: 'chromium',
42
+ use: { ...devices['Desktop Chrome'] },
43
+ },
44
+
45
+ {
46
+ name: 'firefox',
47
+ use: { ...devices['Desktop Firefox'] },
48
+ },
49
+
50
+ {
51
+ name: 'webkit',
52
+ use: { ...devices['Desktop Safari'] },
53
+ },
54
+
55
+ // Uncomment for mobile browsers support
56
+ /* {
57
+ name: 'Mobile Chrome',
58
+ use: { ...devices['Pixel 5'] },
59
+ },
60
+ {
61
+ name: 'Mobile Safari',
62
+ use: { ...devices['iPhone 12'] },
63
+ }, */
64
+
65
+ // Uncomment for branded browsers
66
+ /* {
67
+ name: 'Microsoft Edge',
68
+ use: { ...devices['Desktop Edge'], channel: 'msedge' },
69
+ },
70
+ {
71
+ name: 'Google Chrome',
72
+ use: { ...devices['Desktop Chrome'], channel: 'chrome' },
73
+ } */
74
+ ],
75
+ });
@@ -0,0 +1,7 @@
1
+ import { test, expect } from '@playwright/test';
2
+
3
+ test('renders the base page', async ({ page }) => {
4
+ await page.goto('/');
5
+
6
+ await expect(page.locator('h1')).toContainText('Hedgehog');
7
+ });
@@ -0,0 +1,26 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "allowJs": true,
5
+ "outDir": "out-tsc/playwright",
6
+ "sourceMap": false,
7
+ "types": ["node"]
8
+ },
9
+ "include": [
10
+ "**/*.ts",
11
+ "**/*.js",
12
+ "playwright.config.mts",
13
+ "src/**/*.spec.ts",
14
+ "src/**/*.spec.js",
15
+ "src/**/*.test.ts",
16
+ "src/**/*.test.js",
17
+ "src/**/*.d.ts"
18
+ ],
19
+ "exclude": [
20
+ "out-tsc",
21
+ "test-output",
22
+ "eslint.config.js",
23
+ "eslint.config.mjs",
24
+ "eslint.config.cjs"
25
+ ]
26
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ extends: ['@commitlint/config-conventional'],
3
+ };
@@ -0,0 +1,68 @@
1
+ # Shipped core definition for full-stack-app. Layer order, scope, and
2
+ # verify commands are the same shape this package's skills/hedgehog-loop
3
+ # Domain Module step tables describe in prose — this file is their data form.
4
+ # {module} is filled in by the compiler with the domain module name a
5
+ # task is generated for.
6
+ #
7
+ # Every per-module layer's scope carries {module} — module-disjoint by
8
+ # construction, so two modules' tasks never touch the same file
9
+ # (src/db/core.mjs's validateCore enforces this: a module-axis core
10
+ # rejects any non-exclusive layer whose scope omits {module}). schema and
11
+ # hook run Vitest anchored to their own module's directory (`nx test db
12
+ # -- src/schema/{module}/`), a distinct Nx target from typecheck under
13
+ # this workspace's target inference (nx.json), so the command's real
14
+ # radius is exactly its scope — no wider declaration to make. Cross-module
15
+ # type/integration breakage isn't caught at the task that caused it; join
16
+ # is exclusive: true and scoped to everything, running full typecheck and
17
+ # every test once after every module's layers land, in exchange for those
18
+ # layers running in parallel.
19
+ id: full-stack-app
20
+ layers:
21
+ - id: schema
22
+ scope: ["packages/db/src/schema/{module}/**", "packages/db/src/schema/index.ts"]
23
+ verify: "pnpm nx test db -- src/schema/{module}/"
24
+ commit: "feat({module}): schema"
25
+ - id: contract
26
+ depends_on: schema
27
+ scope: ["packages/contracts/src/{module}/**"]
28
+ verify: "pnpm nx test contracts -- src/{module}/"
29
+ commit: "feat({module}): contract"
30
+ - id: repository
31
+ depends_on: contract
32
+ scope: ["libs/{module}/repository/**"]
33
+ verify: "pnpm nx test {module}-repository"
34
+ commit: "feat({module}): repository"
35
+ - id: service
36
+ depends_on: repository
37
+ scope: ["libs/{module}/service/**"]
38
+ verify: "pnpm nx test {module}-service"
39
+ commit: "feat({module}): service"
40
+ - id: controller
41
+ depends_on: service
42
+ scope: ["apps/api/src/app/{module}/**"]
43
+ verify: "pnpm nx test api -- src/app/{module}/"
44
+ commit: "feat({module}): api"
45
+ - id: hook
46
+ depends_on: controller
47
+ scope: ["packages/hooks/src/{module}/**"]
48
+ verify: "pnpm nx test hooks -- src/{module}/"
49
+ commit: "feat({module}): hooks"
50
+ # Web only, because apps/mobile only exists when the Mobile add-on is
51
+ # on. A layer scoped to a project that was never scaffolded fails its
52
+ # own verify on every module, so the Mobile clause is added by
53
+ # hedgehog-bootstrap's Expo step — which is also what creates the Nx
54
+ # project the extra verify target needs — rather than shipped here and
55
+ # broken by default.
56
+ - id: screen
57
+ depends_on: hook
58
+ scope: ["apps/web/src/app/{module}/**"]
59
+ verify: "pnpm nx test web -- src/app/{module}/"
60
+ commit: "feat({module}): screen-web"
61
+ # Workspace-wide by design: the only gate that can see cross-module
62
+ # breakage, since every layer above is parallel and module-scoped.
63
+ - id: join
64
+ depends_on: screen
65
+ scope: ["**"]
66
+ verify: "pnpm nx run-many -t typecheck && pnpm nx run-many -t test"
67
+ exclusive: true
68
+ commit: "chore({module}): join"
@@ -0,0 +1,14 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:16-alpine
4
+ environment:
5
+ POSTGRES_USER: postgres
6
+ POSTGRES_PASSWORD: postgres
7
+ POSTGRES_DB: app
8
+ ports:
9
+ - '5432:5432'
10
+ volumes:
11
+ - postgres-data:/var/lib/postgresql/data
12
+
13
+ volumes:
14
+ postgres-data:
@@ -0,0 +1,15 @@
1
+ import baseConfig from './packages/config/eslint-base.js';
2
+
3
+ /**
4
+ * Root flat ESLint config. Extends the locked shared base from
5
+ * `packages/config/eslint-base.js` (module boundaries, TypeScript/JS
6
+ * rules). Every app/lib in the workspace resolves through this file —
7
+ * don't add per-project overrides here; fix the base config at its
8
+ * source instead.
9
+ */
10
+ export default [
11
+ ...baseConfig,
12
+ {
13
+ ignores: ['**/vitest.config.*.timestamp*', '**/test-output'],
14
+ },
15
+ ];
@@ -0,0 +1,24 @@
1
+ node_modules
2
+ dist
3
+ tmp
4
+ out-tsc
5
+ .env
6
+ .env.local
7
+ *.log
8
+ .DS_Store
9
+ .hedgehog/graph-server.json
10
+ .hedgehog/hedgehog.db
11
+ .hedgehog/hedgehog.db-*
12
+ .hedgehog/commit.lock
13
+
14
+ .nx/cache
15
+ .nx/workspace-data
16
+ .nx/polygraph
17
+ .claude/worktrees
18
+ .claude/settings.local.json
19
+ vitest.config.*.timestamp*
20
+
21
+ # Next.js
22
+ .next
23
+ out
24
+ test-output
@@ -0,0 +1,52 @@
1
+ # The commit gate. Two things in here are load-bearing and read like
2
+ # noise if you don't know what they're for — don't "clean them up".
3
+ #
4
+ # `assert_lefthook_installed: true` is what makes the gate fail CLOSED.
5
+ # It is consumed by `lefthook install`, which bakes a refusing branch
6
+ # into the generated .git/hooks/* scripts. Without it, a repo whose
7
+ # node_modules has been cleared — a workspace clean, a fresh clone
8
+ # before install, a core switch — prints "Can't find lefthook in PATH"
9
+ # and exits 0, so the commit lands with no typecheck, no lint and no
10
+ # test while .git/hooks and this file both still look like a gate.
11
+ # There is nothing in the output that distinguishes "passed the gate"
12
+ # from "there was no gate". With it, the hook refuses the commit and
13
+ # names the escape hatch (`git commit --no-verify`, or `LEFTHOOK=0`).
14
+ # Restore enforcement with `pnpm install` — lefthook's own postinstall
15
+ # re-runs `lefthook install -f` — or with `pnpm dlx lefthook install`
16
+ # on its own. `hedgehog status` reports whether the gate is live.
17
+ #
18
+ # Because the assertion is written into the hook at install time, this
19
+ # flag only protects hooks generated after it was set. `pnpm install`
20
+ # regenerates them, so any project that has installed once since is
21
+ # covered.
22
+ #
23
+ # The `git rev-parse --verify --quiet HEAD` guard on each command is
24
+ # there because `--base=HEAD` cannot resolve in a repo with no commits:
25
+ # on the very first commit of a fresh install every command dies with
26
+ # "fatal: ambiguous argument 'HEAD': unknown revision", the commit is
27
+ # rejected, and `git commit --no-verify` becomes the only way through —
28
+ # which is exactly the habit this gate exists to prevent. The fallback
29
+ # is `run-many`, not a skip: with no history there is no diff to narrow
30
+ # by, every project is new, and running the whole workspace is both the
31
+ # honest answer and the strongest one. Silencing the gate on the one
32
+ # commit that introduces the entire codebase would be the worst
33
+ # possible place to do it.
34
+ assert_lefthook_installed: true
35
+
36
+ pre-commit:
37
+ parallel: true
38
+ commands:
39
+ typecheck:
40
+ glob: '*.{ts,tsx}'
41
+ run: if git rev-parse --verify --quiet HEAD >/dev/null 2>&1; then npx nx affected -t typecheck --base=HEAD; else npx nx run-many -t typecheck; fi
42
+ lint:
43
+ glob: '*.{ts,tsx}'
44
+ run: if git rev-parse --verify --quiet HEAD >/dev/null 2>&1; then npx nx affected -t lint --base=HEAD; else npx nx run-many -t lint; fi
45
+ test:
46
+ glob: '*.{ts,tsx}'
47
+ run: if git rev-parse --verify --quiet HEAD >/dev/null 2>&1; then npx nx affected -t test --base=HEAD; else npx nx run-many -t test; fi
48
+
49
+ commit-msg:
50
+ commands:
51
+ commitlint:
52
+ run: npx commitlint --edit {1}
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "./node_modules/nx/schemas/nx-schema.json",
3
+ "targetDefaults": {
4
+ "build": {
5
+ "cache": true,
6
+ "dependsOn": ["generate-module-routes"]
7
+ },
8
+ "dev": {
9
+ "dependsOn": ["generate-module-routes"]
10
+ },
11
+ "test": {
12
+ "cache": true,
13
+ "dependsOn": ["^build", "generate-feature-modules", "generate-module-routes"]
14
+ },
15
+ "typecheck": {
16
+ "dependsOn": ["generate-feature-modules", "generate-module-routes"]
17
+ },
18
+ "lint": {
19
+ "cache": true
20
+ }
21
+ },
22
+ "defaultBase": "master",
23
+ "plugins": [
24
+ {
25
+ "plugin": "@nx/js/typescript",
26
+ "options": {
27
+ "typecheck": {
28
+ "targetName": "typecheck"
29
+ },
30
+ "build": {
31
+ "targetName": "build",
32
+ "configName": "tsconfig.lib.json",
33
+ "buildDepsName": "build-deps",
34
+ "watchDepsName": "watch-deps"
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "plugin": "@nx/vitest",
40
+ "options": {
41
+ "testTargetName": "test",
42
+ "ciTargetName": "test-ci",
43
+ "testMode": "watch"
44
+ },
45
+ "exclude": ["apps/api-e2e/**"]
46
+ },
47
+ {
48
+ "plugin": "@nx/eslint/plugin",
49
+ "options": {
50
+ "targetName": "lint"
51
+ }
52
+ },
53
+ {
54
+ "plugin": "@nx/webpack/plugin",
55
+ "options": {
56
+ "buildTargetName": "build",
57
+ "serveTargetName": "serve",
58
+ "previewTargetName": "preview",
59
+ "buildDepsTargetName": "build-deps",
60
+ "watchDepsTargetName": "watch-deps",
61
+ "serveStaticTargetName": "serve-static"
62
+ }
63
+ },
64
+ {
65
+ "plugin": "@nx/next/plugin",
66
+ "options": {
67
+ "startTargetName": "start",
68
+ "buildTargetName": "build",
69
+ "devTargetName": "dev",
70
+ "serveStaticTargetName": "serve-static",
71
+ "buildDepsTargetName": "build-deps",
72
+ "watchDepsTargetName": "watch-deps"
73
+ }
74
+ },
75
+ {
76
+ "plugin": "@nx/playwright/plugin",
77
+ "options": {
78
+ "targetName": "e2e"
79
+ }
80
+ }
81
+ ],
82
+ "generators": {
83
+ "@nx/next": {
84
+ "application": {
85
+ "style": "css",
86
+ "linter": "eslint"
87
+ }
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "app",
3
+ "private": true,
4
+ "type": "module",
5
+ "packageManager": "pnpm@9.0.0",
6
+ "scripts": {
7
+ "dev": "docker compose up -d && nx run-many --target=serve,dev --projects=api,web --parallel"
8
+ },
9
+ "devDependencies": {
10
+ "@commitlint/cli": "^21.2.1",
11
+ "@commitlint/config-conventional": "^21.2.0",
12
+ "@eslint/js": "^10.0.1",
13
+ "@nestjs/schematics": "^11.0.0",
14
+ "@nestjs/testing": "^11.0.0",
15
+ "@next/eslint-plugin-next": "^16.1.6",
16
+ "@nx/devkit": "23.1.0",
17
+ "@nx/eslint": "^23.1.0",
18
+ "@nx/eslint-plugin": "^23.1.0",
19
+ "@nx/js": "^23.1.0",
20
+ "@nx/nest": "23.1.0",
21
+ "@nx/next": "23.1.0",
22
+ "@nx/node": "23.1.0",
23
+ "@nx/playwright": "23.1.0",
24
+ "@nx/vitest": "23.1.0",
25
+ "@nx/web": "23.1.0",
26
+ "@nx/webpack": "23.1.0",
27
+ "@playwright/test": "^1.37.0",
28
+ "@swc-node/register": "~1.11.1",
29
+ "@swc/cli": "~0.8.1",
30
+ "@swc/core": "~1.15.5",
31
+ "@swc/helpers": "~0.5.18",
32
+ "@testing-library/jest-dom": "^7.0.1",
33
+ "@testing-library/react": "^16.3.2",
34
+ "@testing-library/user-event": "^14.6.4",
35
+ "@types/node": "^22.0.0",
36
+ "@types/pg": "^8.20.0",
37
+ "@types/react": "^19.0.0",
38
+ "@types/react-dom": "^19.0.0",
39
+ "@typescript-eslint/eslint-plugin": "^8.65.0",
40
+ "@typescript-eslint/parser": "^8.65.0",
41
+ "@vitejs/plugin-react": "^6.0.5",
42
+ "@vitest/coverage-v8": "~4.1.0",
43
+ "drizzle-kit": "^0.31.10",
44
+ "drizzle-zod": "^0.8.3",
45
+ "eslint": "^10.7.0",
46
+ "eslint-config-next": "^16.1.6",
47
+ "eslint-plugin-import": "2.31.0",
48
+ "eslint-plugin-jsx-a11y": "6.10.1",
49
+ "eslint-plugin-playwright": "^1.6.2",
50
+ "eslint-plugin-react": "^7.35.0",
51
+ "eslint-plugin-react-hooks": "5.0.0",
52
+ "jsdom": "^30.0.1",
53
+ "lefthook": "^2.1.10",
54
+ "nx": "23.1.0",
55
+ "prettier": "~3.6.2",
56
+ "tslib": "^2.3.0",
57
+ "typescript": "~6.0.3",
58
+ "typescript-eslint": "^8.65.0",
59
+ "vite": "^8.0.0",
60
+ "vitest": "~4.1.0",
61
+ "webpack": "^5.101.3",
62
+ "webpack-cli": "^7.0.0",
63
+ "webpack-dev-server": "^5.2.1"
64
+ },
65
+ "dependencies": {
66
+ "@nestjs/common": "^11.0.0",
67
+ "@nestjs/core": "^11.0.0",
68
+ "@nestjs/platform-express": "^11.0.0",
69
+ "axios": "^1.18.0",
70
+ "drizzle-orm": "^0.45.2",
71
+ "nestjs-pino": "^4.6.1",
72
+ "next": "~16.3.0",
73
+ "pg": "^8.22.0",
74
+ "pino-http": "^11.0.0",
75
+ "react": "^19.0.0",
76
+ "react-dom": "^19.0.0",
77
+ "reflect-metadata": "^0.2.0",
78
+ "rxjs": "^7.8.0",
79
+ "zod": "^4.4.3"
80
+ },
81
+ "pnpm": {
82
+ "onlyBuiltDependencies": [
83
+ "lefthook"
84
+ ],
85
+ "overrides": {
86
+ "esbuild": "0.25.12",
87
+ "axios": "^1.18.0",
88
+ "brace-expansion@1": "^1.1.18",
89
+ "brace-expansion@2": "^2.1.4",
90
+ "brace-expansion@5": "^5.0.9",
91
+ "fast-uri": "^3.1.5",
92
+ "js-yaml@3": "^3.15.1",
93
+ "js-yaml@4": "^4.3.1",
94
+ "nanoid": "^3.3.17",
95
+ "sharp": "^0.35.0",
96
+ "uuid@8": "^11.1.1"
97
+ }
98
+ }
99
+ }