@next-friday/create-app 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +94 -2
- package/dist/main.mjs +414 -0
- package/package.json +84 -3
- package/templates/base/.agents/hooks/agent-shell-gate.sh +355 -0
- package/templates/base/.agents/hooks/agent-suppression-gate.sh +45 -0
- package/templates/base/.agents/rules/automation-owned-checks.md +5 -0
- package/templates/base/.agents/rules/code-comments.md +3 -0
- package/templates/base/.agents/rules/current-state-authority.md +17 -0
- package/templates/base/.agents/rules/demand-driven-configuration.md +7 -0
- package/templates/base/.agents/rules/dependency-security.md +5 -0
- package/templates/base/.agents/rules/deterministic-testing.md +15 -0
- package/templates/base/.agents/rules/diagnostics-and-error-handling.md +7 -0
- package/templates/base/.agents/rules/git-workflow.md +10 -0
- package/templates/base/.agents/rules/no-suppression.md +7 -0
- package/templates/base/.agents/rules/script-driven-changes.md +7 -0
- package/templates/base/.agents/rules/single-author-style.md +7 -0
- package/templates/base/.claude/rules/agents-guide.md +1 -0
- package/templates/base/.claude/rules/automation-owned-checks.md +1 -0
- package/templates/base/.claude/rules/code-comments.md +1 -0
- package/templates/base/.claude/rules/current-state-authority.md +1 -0
- package/templates/base/.claude/rules/demand-driven-configuration.md +1 -0
- package/templates/base/.claude/rules/dependency-security.md +12 -0
- package/templates/base/.claude/rules/diagnostics-and-error-handling.md +1 -0
- package/templates/base/.claude/rules/git-workflow.md +1 -0
- package/templates/base/.claude/rules/no-suppression.md +1 -0
- package/templates/base/.claude/rules/script-driven-changes.md +1 -0
- package/templates/base/.claude/rules/single-author-style.md +1 -0
- package/templates/base/.claude/settings.json +61 -0
- package/templates/base/.commitlintrc.json +3 -0
- package/templates/base/.cursor/BUGBOT.md +17 -0
- package/templates/base/.cursor/hooks/agent-constitution-gate.sh +32 -0
- package/templates/base/.cursor/hooks.json +26 -0
- package/templates/base/.cursor/rules/automation-owned-checks.mdc +10 -0
- package/templates/base/.cursor/rules/code-comments.mdc +8 -0
- package/templates/base/.cursor/rules/current-state-authority.mdc +22 -0
- package/templates/base/.cursor/rules/demand-driven-configuration.mdc +12 -0
- package/templates/base/.cursor/rules/dependency-security.mdc +11 -0
- package/templates/base/.cursor/rules/diagnostics-and-error-handling.mdc +12 -0
- package/templates/base/.cursor/rules/git-workflow.mdc +15 -0
- package/templates/base/.cursor/rules/no-suppression.mdc +12 -0
- package/templates/base/.cursor/rules/script-driven-changes.mdc +12 -0
- package/templates/base/.cursor/rules/single-author-style.mdc +12 -0
- package/templates/base/.editorconfig +13 -0
- package/templates/base/.gitattributes +1 -0
- package/templates/base/.github/CODEOWNERS +2 -0
- package/templates/base/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/templates/base/.github/dependabot.yml +77 -0
- package/templates/base/.github/file-filters.yml +19 -0
- package/templates/base/.github/labeler.yml +25 -0
- package/templates/base/.github/requirements/diff-cover.txt +213 -0
- package/templates/base/.github/workflows/deploy.yml +124 -0
- package/templates/base/.github/workflows/osv-scanner.yml +34 -0
- package/templates/base/.github/workflows/pr-triage.yml +29 -0
- package/templates/base/.github/workflows/secret-scan.yml +50 -0
- package/templates/base/.github/workflows/validate-pr-title.yml +48 -0
- package/templates/base/.github/workflows/zizmor.yml +62 -0
- package/templates/base/.github/zizmor.yml +4 -0
- package/templates/base/.gitleaks.toml +14 -0
- package/templates/base/.husky/commit-msg +3 -0
- package/templates/base/.husky/pre-commit +17 -0
- package/templates/base/.husky/pre-merge-commit +7 -0
- package/templates/base/.husky/pre-push +15 -0
- package/templates/base/.nvmrc +1 -0
- package/templates/base/SECURITY.md +15 -0
- package/templates/base/knip.json +3 -0
- package/templates/base/pnpm-workspace.yaml +17 -0
- package/templates/base/railway.json +9 -0
- package/templates/base/scripts/check-agent-gates.ts +252 -0
- package/templates/base/scripts/sync-agent-rules.ts +121 -0
- package/templates/nestjs/.agents/rules/typescript-first.md +7 -0
- package/templates/nestjs/.agents/rules.json +41 -0
- package/templates/nestjs/.claude/rules/deterministic-testing.md +20 -0
- package/templates/nestjs/.claude/rules/typescript-first.md +13 -0
- package/templates/nestjs/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/nestjs/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/nestjs/.dependency-cruiser.json +28 -0
- package/templates/nestjs/.dockerignore +9 -0
- package/templates/nestjs/.env.example +1 -0
- package/templates/nestjs/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/nestjs/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/nestjs/.github/pull_request_template.md +25 -0
- package/templates/nestjs/.github/workflows/ci.yml +181 -0
- package/templates/nestjs/.github/workflows/sast.yml +45 -0
- package/templates/nestjs/.lintstagedrc.json +10 -0
- package/templates/nestjs/.prettierignore +2 -0
- package/templates/nestjs/.prettierrc.json +1 -0
- package/templates/nestjs/AGENTS.md +8 -0
- package/templates/nestjs/CONTRIBUTING.md +57 -0
- package/templates/nestjs/Dockerfile +27 -0
- package/templates/nestjs/README.md +78 -0
- package/templates/nestjs/_gitignore +47 -0
- package/templates/nestjs/eslint.config.ts +7 -0
- package/templates/nestjs/nest-cli.json +8 -0
- package/templates/nestjs/package.json +81 -0
- package/templates/nestjs/src/app.controller.test.ts +23 -0
- package/templates/nestjs/src/app.controller.ts +13 -0
- package/templates/nestjs/src/app.module.ts +12 -0
- package/templates/nestjs/src/app.service.ts +10 -0
- package/templates/nestjs/src/health/health.controller.test.ts +17 -0
- package/templates/nestjs/src/health/health.controller.ts +14 -0
- package/templates/nestjs/src/health/health.module.ts +10 -0
- package/templates/nestjs/src/main.ts +25 -0
- package/templates/nestjs/src/port.test.ts +29 -0
- package/templates/nestjs/src/port.ts +20 -0
- package/templates/nestjs/test/app.e2e.test.ts +40 -0
- package/templates/nestjs/tsconfig.build.json +9 -0
- package/templates/nestjs/tsconfig.json +20 -0
- package/templates/nestjs/vitest.config.ts +13 -0
- package/templates/nestjs/vitest.e2e.config.ts +8 -0
- package/templates/nextjs/.agents/rules/typescript-first.md +7 -0
- package/templates/nextjs/.agents/rules.json +41 -0
- package/templates/nextjs/.claude/rules/deterministic-testing.md +21 -0
- package/templates/nextjs/.claude/rules/typescript-first.md +15 -0
- package/templates/nextjs/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/nextjs/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/nextjs/.dependency-cruiser.json +34 -0
- package/templates/nextjs/.dockerignore +10 -0
- package/templates/nextjs/.env.example +1 -0
- package/templates/nextjs/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/nextjs/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/nextjs/.github/pull_request_template.md +25 -0
- package/templates/nextjs/.github/workflows/ci.yml +187 -0
- package/templates/nextjs/.github/workflows/sast.yml +46 -0
- package/templates/nextjs/.lintstagedrc.json +10 -0
- package/templates/nextjs/.prettierignore +2 -0
- package/templates/nextjs/AGENTS.md +18 -0
- package/templates/nextjs/CONTRIBUTING.md +57 -0
- package/templates/nextjs/Dockerfile +23 -0
- package/templates/nextjs/README.md +74 -0
- package/templates/nextjs/_gitignore +51 -0
- package/templates/nextjs/app/favicon.ico +0 -0
- package/templates/nextjs/app/globals.css +26 -0
- package/templates/nextjs/app/health/route.test.ts +20 -0
- package/templates/nextjs/app/health/route.ts +23 -0
- package/templates/nextjs/app/layout.tsx +29 -0
- package/templates/nextjs/app/page.test.ts +11 -0
- package/templates/nextjs/app/page.tsx +8 -0
- package/templates/nextjs/eslint.config.ts +32 -0
- package/templates/nextjs/knip.json +4 -0
- package/templates/nextjs/next.config.ts +35 -0
- package/templates/nextjs/package.json +78 -0
- package/templates/nextjs/playwright.config.ts +27 -0
- package/templates/nextjs/postcss.config.mjs +7 -0
- package/templates/nextjs/prettier.config.ts +11 -0
- package/templates/nextjs/test/home.e2e.test.ts +11 -0
- package/templates/nextjs/tsconfig.json +33 -0
- package/templates/nextjs/vitest.config.ts +12 -0
- package/templates/nodejs/.agents/rules/typescript-first.md +7 -0
- package/templates/nodejs/.agents/rules.json +41 -0
- package/templates/nodejs/.claude/rules/deterministic-testing.md +20 -0
- package/templates/nodejs/.claude/rules/typescript-first.md +13 -0
- package/templates/nodejs/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/nodejs/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/nodejs/.dependency-cruiser.json +28 -0
- package/templates/nodejs/.dockerignore +8 -0
- package/templates/nodejs/.env.example +1 -0
- package/templates/nodejs/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/nodejs/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/nodejs/.github/pull_request_template.md +25 -0
- package/templates/nodejs/.github/workflows/ci.yml +179 -0
- package/templates/nodejs/.github/workflows/sast.yml +45 -0
- package/templates/nodejs/.lintstagedrc.json +10 -0
- package/templates/nodejs/.prettierignore +2 -0
- package/templates/nodejs/.prettierrc.json +1 -0
- package/templates/nodejs/AGENTS.md +8 -0
- package/templates/nodejs/CONTRIBUTING.md +56 -0
- package/templates/nodejs/Dockerfile +27 -0
- package/templates/nodejs/README.md +74 -0
- package/templates/nodejs/_gitignore +47 -0
- package/templates/nodejs/eslint.config.ts +7 -0
- package/templates/nodejs/package.json +66 -0
- package/templates/nodejs/src/main.ts +22 -0
- package/templates/nodejs/src/port.test.ts +30 -0
- package/templates/nodejs/src/port.ts +20 -0
- package/templates/nodejs/src/server.test.ts +60 -0
- package/templates/nodejs/src/server.ts +37 -0
- package/templates/nodejs/tsconfig.build.json +9 -0
- package/templates/nodejs/tsconfig.json +19 -0
- package/templates/nodejs/vitest.config.ts +12 -0
- package/templates/payload/.agents/rules/typescript-first.md +7 -0
- package/templates/payload/.agents/rules.json +41 -0
- package/templates/payload/.claude/rules/deterministic-testing.md +21 -0
- package/templates/payload/.claude/rules/typescript-first.md +15 -0
- package/templates/payload/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/payload/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/payload/.dependency-cruiser.json +34 -0
- package/templates/payload/.dockerignore +9 -0
- package/templates/payload/.editorconfig-checker.json +3 -0
- package/templates/payload/.env.example +4 -0
- package/templates/payload/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/payload/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/payload/.github/pull_request_template.md +25 -0
- package/templates/payload/.github/workflows/ci.yml +204 -0
- package/templates/payload/.github/workflows/sast.yml +46 -0
- package/templates/payload/.lintstagedrc.json +10 -0
- package/templates/payload/.prettierignore +5 -0
- package/templates/payload/.prettierrc.json +1 -0
- package/templates/payload/AGENTS.md +19 -0
- package/templates/payload/CONTRIBUTING.md +58 -0
- package/templates/payload/Dockerfile +26 -0
- package/templates/payload/README.md +98 -0
- package/templates/payload/_gitignore +52 -0
- package/templates/payload/eslint.config.ts +35 -0
- package/templates/payload/next.config.ts +43 -0
- package/templates/payload/package.json +86 -0
- package/templates/payload/playwright.config.ts +27 -0
- package/templates/payload/src/app/(frontend)/layout.tsx +18 -0
- package/templates/payload/src/app/(frontend)/page.test.ts +14 -0
- package/templates/payload/src/app/(frontend)/page.tsx +14 -0
- package/templates/payload/src/app/(frontend)/styles.css +15 -0
- package/templates/payload/src/app/(payload)/admin/[[...segments]]/not-found.tsx +24 -0
- package/templates/payload/src/app/(payload)/admin/[[...segments]]/page.tsx +24 -0
- package/templates/payload/src/app/(payload)/admin/importMap.ts +6 -0
- package/templates/payload/src/app/(payload)/api/[...slug]/route.ts +19 -0
- package/templates/payload/src/app/(payload)/api/graphql/route.ts +8 -0
- package/templates/payload/src/app/(payload)/api/graphql-playground/route.ts +7 -0
- package/templates/payload/src/app/(payload)/custom.scss +0 -0
- package/templates/payload/src/app/(payload)/layout.tsx +31 -0
- package/templates/payload/src/app/health/route.test.ts +20 -0
- package/templates/payload/src/app/health/route.ts +23 -0
- package/templates/payload/src/collections/media.test.ts +27 -0
- package/templates/payload/src/collections/media.ts +18 -0
- package/templates/payload/src/collections/users.test.ts +10 -0
- package/templates/payload/src/collections/users.ts +10 -0
- package/templates/payload/src/environment.test.ts +32 -0
- package/templates/payload/src/environment.ts +14 -0
- package/templates/payload/src/migrations/20261030_005055_initial.json +969 -0
- package/templates/payload/src/migrations/20261030_005055_initial.ts +134 -0
- package/templates/payload/src/migrations/index.ts +9 -0
- package/templates/payload/src/payload-types.ts +339 -0
- package/templates/payload/src/payload.config.ts +47 -0
- package/templates/payload/test/home.e2e.test.ts +16 -0
- package/templates/payload/tsconfig.json +34 -0
- package/templates/payload/vitest.config.ts +19 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
name: Verify
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
|
|
6
|
+
push:
|
|
7
|
+
branches:
|
|
8
|
+
- main
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: "0 3 * * 1"
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
changes:
|
|
21
|
+
name: Detect Changes
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 5
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
pull-requests: read # Needed by paths-filter to inspect pull request changes.
|
|
27
|
+
outputs:
|
|
28
|
+
heavy: ${{ steps.filter.outputs.heavy }}
|
|
29
|
+
ci_policy: ${{ steps.filter.outputs.ci_policy }}
|
|
30
|
+
full_verification: ${{ steps.mode.outputs.full_verification }}
|
|
31
|
+
steps:
|
|
32
|
+
- name: Checkout repository
|
|
33
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
34
|
+
with:
|
|
35
|
+
persist-credentials: false
|
|
36
|
+
- name: Detect relevant changes
|
|
37
|
+
id: filter
|
|
38
|
+
if: github.event_name == 'pull_request'
|
|
39
|
+
uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
|
|
40
|
+
with:
|
|
41
|
+
predicate-quantifier: some-with-excludes
|
|
42
|
+
filters: .github/file-filters.yml
|
|
43
|
+
- name: Select verification mode
|
|
44
|
+
id: mode
|
|
45
|
+
shell: bash
|
|
46
|
+
env:
|
|
47
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
48
|
+
DRAFT: ${{ github.event.pull_request.draft }}
|
|
49
|
+
HEAVY: ${{ steps.filter.outputs.heavy }}
|
|
50
|
+
CI_POLICY: ${{ steps.filter.outputs.ci_policy }}
|
|
51
|
+
run: |
|
|
52
|
+
full_verification=false
|
|
53
|
+
if [[ "$EVENT_NAME" == "push" || ( "$EVENT_NAME" == "pull_request" && "$DRAFT" != "true" && ( "$HEAVY" == "true" || "$CI_POLICY" == "true" ) ) ]]; then
|
|
54
|
+
full_verification=true
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo "full_verification=$full_verification" >> "$GITHUB_OUTPUT"
|
|
58
|
+
|
|
59
|
+
checks:
|
|
60
|
+
name: Static Checks, Tests & Build
|
|
61
|
+
needs: changes
|
|
62
|
+
if: needs.changes.outputs.full_verification == 'true'
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
timeout-minutes: 20
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout repository
|
|
67
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
68
|
+
with:
|
|
69
|
+
fetch-depth: 0
|
|
70
|
+
persist-credentials: false
|
|
71
|
+
- name: Set up Node.js and pnpm
|
|
72
|
+
uses: pnpm/setup@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.0
|
|
73
|
+
with:
|
|
74
|
+
cache: true
|
|
75
|
+
require-lockfile: true
|
|
76
|
+
- name: Reject suppression directives
|
|
77
|
+
run: pnpm suppressions:check
|
|
78
|
+
- name: Check Cursor rules match .agents/rules
|
|
79
|
+
run: pnpm rules:check
|
|
80
|
+
- name: Check agent gates
|
|
81
|
+
run: pnpm gates:check
|
|
82
|
+
- name: Check lint
|
|
83
|
+
run: pnpm lint:check
|
|
84
|
+
- name: Check formatting
|
|
85
|
+
run: pnpm format:check
|
|
86
|
+
env:
|
|
87
|
+
GITHUB_TOKEN: ${{ github.token }} # editorconfig-checker downloads its binary from GitHub releases; the token avoids the anonymous rate limit.
|
|
88
|
+
- name: Check package.json ordering
|
|
89
|
+
run: pnpm sort-package-json:check
|
|
90
|
+
- name: Validate peer dependency contracts
|
|
91
|
+
run: pnpm peers:check
|
|
92
|
+
- name: Check types
|
|
93
|
+
run: pnpm typecheck
|
|
94
|
+
- name: Run Knip
|
|
95
|
+
run: pnpm knip
|
|
96
|
+
- name: Check dependency graph
|
|
97
|
+
run: pnpm depcruise
|
|
98
|
+
- name: Run tests with coverage
|
|
99
|
+
run: pnpm test:coverage
|
|
100
|
+
- name: Run end-to-end tests
|
|
101
|
+
run: pnpm test:e2e
|
|
102
|
+
- name: Build
|
|
103
|
+
run: pnpm build
|
|
104
|
+
- name: Check patch coverage
|
|
105
|
+
if: github.event_name == 'pull_request'
|
|
106
|
+
env:
|
|
107
|
+
BASE_REF: ${{ github.base_ref }}
|
|
108
|
+
run: |
|
|
109
|
+
python3 -m venv "$RUNNER_TEMP/diff-cover"
|
|
110
|
+
"$RUNNER_TEMP/diff-cover/bin/pip" install --quiet --require-hashes --only-binary=:all: -r .github/requirements/diff-cover.txt
|
|
111
|
+
"$RUNNER_TEMP/diff-cover/bin/diff-cover" coverage/cobertura-coverage.xml --compare-branch "origin/$BASE_REF" --fail-under 95
|
|
112
|
+
|
|
113
|
+
image:
|
|
114
|
+
name: Container Image
|
|
115
|
+
needs: changes
|
|
116
|
+
if: needs.changes.outputs.full_verification == 'true' || github.event_name == 'schedule'
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
timeout-minutes: 15
|
|
119
|
+
env:
|
|
120
|
+
HADOLINT_VERSION: 2.15.1
|
|
121
|
+
HADOLINT_SHA256: c7187db94eeeeca956519a6af171adc31453941a1e777961f6e680f697c8c507
|
|
122
|
+
TRIVY_VERSION: 0.76.1
|
|
123
|
+
TRIVY_SHA256: c7cbe3137fb8a48a17574bede3dd6beb16742d1e9772929940fc90082c39d9c0
|
|
124
|
+
steps:
|
|
125
|
+
- name: Checkout repository
|
|
126
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
127
|
+
with:
|
|
128
|
+
persist-credentials: false
|
|
129
|
+
- name: Lint Dockerfile
|
|
130
|
+
run: |
|
|
131
|
+
curl --silent --show-error --fail --location --output hadolint \
|
|
132
|
+
"https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-linux-x86_64"
|
|
133
|
+
echo "${HADOLINT_SHA256} hadolint" | sha256sum --check --strict
|
|
134
|
+
chmod +x hadolint
|
|
135
|
+
./hadolint Dockerfile
|
|
136
|
+
- name: Build image
|
|
137
|
+
run: docker build --tag app:ci .
|
|
138
|
+
- name: Smoke test image
|
|
139
|
+
id: smoke
|
|
140
|
+
run: |
|
|
141
|
+
docker run --detach --name app --env PORT=3000 --publish 3000:3000 app:ci
|
|
142
|
+
curl --silent --show-error --fail --retry 15 --retry-delay 1 --retry-all-errors --output /dev/null http://localhost:3000/health
|
|
143
|
+
- name: Show container logs
|
|
144
|
+
if: failure() && steps.smoke.outcome == 'failure'
|
|
145
|
+
run: docker logs app
|
|
146
|
+
- name: Scan image for vulnerabilities
|
|
147
|
+
run: |
|
|
148
|
+
archive="trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
|
|
149
|
+
curl --silent --show-error --fail --location --output "$archive" \
|
|
150
|
+
"https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/${archive}"
|
|
151
|
+
echo "${TRIVY_SHA256} ${archive}" | sha256sum --check --strict
|
|
152
|
+
tar --extract --gzip --file "$archive" trivy
|
|
153
|
+
./trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed --no-progress app:ci
|
|
154
|
+
|
|
155
|
+
deploy-dev:
|
|
156
|
+
name: Deploy to dev
|
|
157
|
+
needs:
|
|
158
|
+
- checks
|
|
159
|
+
- image
|
|
160
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && vars.DEPLOY_ENABLED == 'true'
|
|
161
|
+
permissions:
|
|
162
|
+
contents: read
|
|
163
|
+
actions: read # Needed by deploy.yml to find the CI run of the deployed commit.
|
|
164
|
+
uses: ./.github/workflows/deploy.yml
|
|
165
|
+
with:
|
|
166
|
+
environment: dev
|
|
167
|
+
commit_sha: ${{ github.sha }}
|
|
168
|
+
|
|
169
|
+
ci:
|
|
170
|
+
name: All Checks
|
|
171
|
+
if: always()
|
|
172
|
+
timeout-minutes: 5
|
|
173
|
+
needs:
|
|
174
|
+
- changes
|
|
175
|
+
- checks
|
|
176
|
+
- image
|
|
177
|
+
runs-on: ubuntu-latest
|
|
178
|
+
steps:
|
|
179
|
+
- name: Require all verification jobs
|
|
180
|
+
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
|
|
181
|
+
run: exit 1
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: SAST
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request: {}
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
paths-ignore:
|
|
9
|
+
- "**/*.md"
|
|
10
|
+
- ".agents/**"
|
|
11
|
+
- ".claude/**"
|
|
12
|
+
- ".cursor/**"
|
|
13
|
+
schedule:
|
|
14
|
+
- cron: "17 2 * * 1"
|
|
15
|
+
|
|
16
|
+
permissions: {}
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
semgrep:
|
|
24
|
+
name: Semgrep (OWASP)
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
timeout-minutes: 15
|
|
27
|
+
permissions:
|
|
28
|
+
contents: read
|
|
29
|
+
container:
|
|
30
|
+
image: semgrep/semgrep:1.179.0@sha256:93963d9295a366f59e4850127b1550400ee7b388f04fe144e4a1f6325d96e01b
|
|
31
|
+
steps:
|
|
32
|
+
- name: Checkout repository
|
|
33
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
34
|
+
with:
|
|
35
|
+
persist-credentials: false
|
|
36
|
+
- name: Scan source
|
|
37
|
+
run: >-
|
|
38
|
+
semgrep scan
|
|
39
|
+
--config p/owasp-top-ten
|
|
40
|
+
--config p/typescript
|
|
41
|
+
--config p/nodejsscan
|
|
42
|
+
--severity ERROR --severity WARNING
|
|
43
|
+
--error --metrics=off
|
|
44
|
+
--timeout 60 --timeout-threshold 0
|
|
45
|
+
.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"*.{ts,tsx,js,jsx,mjs,cjs}": [
|
|
3
|
+
"pnpm exec eslint --fix --cache --max-warnings=0 --no-warn-ignored --no-inline-config",
|
|
4
|
+
"prettier --write --cache"
|
|
5
|
+
],
|
|
6
|
+
"!(package).json": ["prettier --write --cache"],
|
|
7
|
+
"*.{md,yml,yaml}": ["prettier --write --cache"],
|
|
8
|
+
"package.json": ["sort-package-json", "prettier --write --cache"],
|
|
9
|
+
".husky/{commit-msg,pre-commit,pre-merge-commit,pre-push}": ["prettier --write --cache"]
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"@next-friday/prettier-config-friday"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Agent guide
|
|
2
|
+
|
|
3
|
+
NestJS service on pnpm. Source lives in `src/`, end-to-end tests in `test/`.
|
|
4
|
+
|
|
5
|
+
- Follow the rules in `.agents/rules/`; `.agents/rules.json` gives each rule's scope. Claude Code and Cursor load them automatically.
|
|
6
|
+
- Rule files, agent hooks, and agent settings are company policy: propose a change to the user, who edits them.
|
|
7
|
+
- Put unit tests next to the code as `*.test.ts`; put end-to-end tests in `test/` as `*.e2e.test.ts`.
|
|
8
|
+
- Read configuration from environment variables and fail when one is missing; document each variable in `.env.example`.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Use this guide to prepare changes to this repository.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Use the Node.js version declared by `.nvmrc` and `package.json#engines`.
|
|
8
|
+
- Change the Node.js version in `.nvmrc` and the `Dockerfile` together. Dependabot updates only the `Dockerfile`.
|
|
9
|
+
- Install pnpm once with `npm install --global pnpm`. It switches to the version declared by `package.json#packageManager` automatically.
|
|
10
|
+
- Use Claude Code v2.1.295 or later. It reads `AGENTS.md` directly and supports the `onFailure` field the agent hooks use.
|
|
11
|
+
- Install gitleaks 8.19 or later, which the `pre-commit` hook runs, and jq, which the agent hooks and the `pre-push` hook (`pnpm gates:check`) need: `brew install gitleaks jq` on macOS, or install them from each project's releases on Linux.
|
|
12
|
+
|
|
13
|
+
From the repository root:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install --global pnpm
|
|
17
|
+
pnpm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quality standards
|
|
21
|
+
|
|
22
|
+
- Fix lint, type, and test failures at their root cause.
|
|
23
|
+
- Put unit tests next to the code as `*.test.ts` and end-to-end tests in `test/` as `*.e2e.test.ts`.
|
|
24
|
+
- Treat `coverage/` as generated output.
|
|
25
|
+
- Do not commit `.env` files or credentials.
|
|
26
|
+
|
|
27
|
+
## Verification
|
|
28
|
+
|
|
29
|
+
Run the narrowest check that covers the change while you work. Git hooks run these checks:
|
|
30
|
+
|
|
31
|
+
| Hook | Checks |
|
|
32
|
+
| :----------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
+
| `pre-commit` | blocks commits on `main` except the first commit of a new repository, gitleaks on staged changes, `pnpm rules:check`, and lint-staged on staged files |
|
|
34
|
+
| `commit-msg` | commitlint |
|
|
35
|
+
| `pre-merge-commit` | blocks merge commits on `main` |
|
|
36
|
+
| `pre-push` | blocks pushes to `main` except the push that creates it, then `pnpm check`: the static checks and the unit tests related to your changes |
|
|
37
|
+
|
|
38
|
+
- **Scans:** CI also runs coverage, the build, the container image, and the secret, SAST, and OSV scans. Dependabot and OSV-Scanner report vulnerable dependencies.
|
|
39
|
+
- **End-to-end tests:** run `pnpm test:e2e` when you change endpoints. CI runs it on every pull request that is ready for review and changes code.
|
|
40
|
+
- **Coverage:** CI requires 95% line coverage on changed lines in `src/`, except `main.ts` and `*.module.ts`, which hold only wiring. Keep logic out of them, as `src/port.ts` does for `main.ts`. CI does not gate branch coverage, because NestJS decorators emit metadata branches that never run.
|
|
41
|
+
|
|
42
|
+
Run `pnpm verify` for repository changes.
|
|
43
|
+
|
|
44
|
+
Agent rules live in `.agents/rules/` with their scope in `.agents/rules.json`. After you change either, run `pnpm rules:sync` to regenerate `.claude/rules/` and `.cursor/rules/`.
|
|
45
|
+
|
|
46
|
+
## Pull requests
|
|
47
|
+
|
|
48
|
+
We use trunk-based development. `main` is the only long-lived branch, and every deploy promotes a commit from `main` (see the Deploy section in the README).
|
|
49
|
+
|
|
50
|
+
- Branch from `main` and merge back within a day or two. Do not create `develop` or release branches.
|
|
51
|
+
- Merge unfinished work behind a feature flag or keep it unreachable instead of holding a long-lived branch.
|
|
52
|
+
- Pull requests are squash-merged, so the pull request title becomes the commit on `main`.
|
|
53
|
+
- Write commit messages in the format that `@next-friday/commitlint-config-friday` defines. Pull request titles use `<type>(<scope>): <subject>`, which `.github/workflows/validate-pr-title.yml` checks.
|
|
54
|
+
- Keep each pull request focused on one cohesive change.
|
|
55
|
+
- Describe observable endpoint, request or response, or configuration effects.
|
|
56
|
+
- Report only checks that actually ran and include their results.
|
|
57
|
+
- Add or update tests only when they protect a distinct observable contract.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Runs on any OCI platform (Railway, Vercel Container Runtime, Fly.io, Cloud Run). The platform sets `PORT`.
|
|
2
|
+
FROM node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53 AS base
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
5
|
+
RUN npm install --global "pnpm@$(node --print 'require("./package.json").packageManager.split("+")[0].split("@")[1]')"
|
|
6
|
+
|
|
7
|
+
FROM base AS build
|
|
8
|
+
RUN pnpm install --frozen-lockfile --ignore-scripts
|
|
9
|
+
COPY nest-cli.json tsconfig.json tsconfig.build.json ./
|
|
10
|
+
COPY src ./src
|
|
11
|
+
RUN pnpm build
|
|
12
|
+
|
|
13
|
+
FROM base AS prod-deps
|
|
14
|
+
RUN pnpm install --frozen-lockfile --ignore-scripts --prod
|
|
15
|
+
|
|
16
|
+
FROM node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53
|
|
17
|
+
ENV NODE_ENV=production
|
|
18
|
+
WORKDIR /app
|
|
19
|
+
# Apply Alpine security fixes released after the base image, and drop npm, corepack, and yarn: the app never runs them, and their bundled dependencies carry their own CVEs.
|
|
20
|
+
RUN apk upgrade --no-cache \
|
|
21
|
+
&& rm -rf /usr/local/lib/node_modules /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack /usr/local/bin/yarn /usr/local/bin/yarnpkg /opt/yarn-*
|
|
22
|
+
COPY package.json ./
|
|
23
|
+
COPY --from=prod-deps /app/node_modules ./node_modules
|
|
24
|
+
COPY --from=build /app/dist ./dist
|
|
25
|
+
USER 1000
|
|
26
|
+
HEALTHCHECK --interval=30s --timeout=5s CMD ["node", "-e", "fetch('http://127.0.0.1:' + (process.env.PORT || 3000) + '/health').then(response => process.exit(response.ok ? 0 : 1), () => process.exit(1))"]
|
|
27
|
+
CMD ["node", "dist/main.js"]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# next-friday-template-nestjs
|
|
2
|
+
|
|
3
|
+
Next Friday starter for NestJS services.
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install --global pnpm
|
|
9
|
+
pnpm install
|
|
10
|
+
pnpm start:dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The server listens on the port set by `PORT` in `.env`, which the CLI created from `.env.example`.
|
|
14
|
+
|
|
15
|
+
## After creating a project from this template
|
|
16
|
+
|
|
17
|
+
1. Install gitleaks and jq (see [CONTRIBUTING.md](CONTRIBUTING.md)). Make the first commit on `main` and push it. The Git hooks allow only this first commit and push on `main`; work on branches after that.
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
git add --all
|
|
21
|
+
git commit -m "chore(repo): start from template"
|
|
22
|
+
git push --set-upstream origin main
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. Add your team as the owner of every file in `.github/CODEOWNERS`, and replace the owner placeholder in `.github/zizmor.yml`.
|
|
26
|
+
3. Replace the template's description and owner: `package.json#description`, `repository.url`, and `author`. Change `license` from `UNLICENSED` if the project is open source.
|
|
27
|
+
4. In the repository settings:
|
|
28
|
+
- **Actions → General → Workflow permissions:** select **Read repository contents and packages permissions**. Every workflow requests the extra permissions it needs.
|
|
29
|
+
- **Advanced Security:** enable private vulnerability reporting, Dependabot alerts, Dependabot security updates, secret scanning, and push protection. `SECURITY.md` sends reporters to private vulnerability reporting.
|
|
30
|
+
- **Cursor Bugbot:** enable the repository at [Bugbot](https://cursor.com/automations/from-cursor/bugbot). Bugbot reviews pull requests against the rules linked from `.cursor/BUGBOT.md`.
|
|
31
|
+
- **Rules → Rulesets:** protect `main` with squash merges only, a linear history, no force pushes or deletion, and the required checks `All Checks` and `Validate pull request title`. Rulesets in a private repository need GitHub Pro, Team, or Enterprise; on GitHub Free, make the repository public or upgrade.
|
|
32
|
+
- Create the `needs triage` label, which the issue forms apply: `gh label create "needs triage"`.
|
|
33
|
+
|
|
34
|
+
## Scripts
|
|
35
|
+
|
|
36
|
+
| Script | Purpose |
|
|
37
|
+
| :----------------- | :------------------------------------------------------------------------------ |
|
|
38
|
+
| `pnpm start` | Start once, without watch mode; loads `.env` when present |
|
|
39
|
+
| `pnpm start:dev` | Start in watch mode; loads `.env` when present |
|
|
40
|
+
| `pnpm start:debug` | Start in watch mode with the Node.js inspector; loads `.env` when present |
|
|
41
|
+
| `pnpm build` | Compile to `dist/` |
|
|
42
|
+
| `pnpm start:prod` | Run `dist/main.js`; the environment sets `PORT` |
|
|
43
|
+
| `pnpm test` | Run unit tests (`src/**/*.test.ts`) |
|
|
44
|
+
| `pnpm test:e2e` | Run end-to-end tests (`test/**/*.e2e.test.ts`) |
|
|
45
|
+
| `pnpm check` | Run the static checks and the unit tests for changed code (the `pre-push` hook) |
|
|
46
|
+
| `pnpm verify` | Run the static checks and all unit tests with coverage |
|
|
47
|
+
|
|
48
|
+
CI also runs the build, the end-to-end tests, the container image scan, and the security scans.
|
|
49
|
+
|
|
50
|
+
## Container
|
|
51
|
+
|
|
52
|
+
The `Dockerfile` builds a production image that runs as the `node` user. The platform must set `PORT`; Railway sets it automatically.
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
docker build -t app .
|
|
56
|
+
docker run --env PORT=3000 --publish 3000:3000 app
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
On Vercel, the zero-configuration NestJS preset takes precedence over the `Dockerfile`. Set the project framework to Container to use the image, and set `PORT` in the project settings.
|
|
60
|
+
|
|
61
|
+
## Deploy
|
|
62
|
+
|
|
63
|
+
`.github/workflows/deploy.yml` deploys the `Dockerfile` to Railway and promotes one commit through `dev`, `uat`, and `prod`. `railway.json` sets the Railway health check to `/health`. The workflow stays off until you configure it:
|
|
64
|
+
|
|
65
|
+
1. In Railway, create a project with one service for this repository and the environments `dev`, `uat`, and `prod`. The workflow passes these names to `railway up --environment`. Create one project token per environment under **Project Settings → Tokens**.
|
|
66
|
+
2. In GitHub, create the `dev`, `uat`, and `prod` environments under **Settings → Environments**, and add to each:
|
|
67
|
+
- the `RAILWAY_TOKEN` secret: that environment's project token;
|
|
68
|
+
- the `RAILWAY_SERVICE` variable: the service name;
|
|
69
|
+
- the `APP_URL` variable: the public `https://` URL.
|
|
70
|
+
|
|
71
|
+
Limit `prod` to the `main` branch and add required reviewers. Environment secrets and variables in a private repository need GitHub Pro, Team, or Enterprise; required reviewers in a private repository need GitHub Enterprise.
|
|
72
|
+
|
|
73
|
+
3. Set the repository variable `DEPLOY_ENABLED` to `true`. Each push to `main` that passes CI then deploys to `dev`.
|
|
74
|
+
4. Promote with **Actions → Deploy → Run workflow**, giving the environment and the full commit SHA. The workflow requires a successful CI run on `main` for that commit and a successful deployment to the previous environment, then waits for `/health`.
|
|
75
|
+
|
|
76
|
+
Remove the workflow, `railway.json`, and the `deploy-dev` job in `ci.yml` if the project deploys elsewhere.
|
|
77
|
+
|
|
78
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
node_modules
|
|
2
|
+
.pnpm-store
|
|
3
|
+
|
|
4
|
+
coverage
|
|
5
|
+
*.tsbuildinfo
|
|
6
|
+
|
|
7
|
+
.cache
|
|
8
|
+
|
|
9
|
+
*.pem
|
|
10
|
+
|
|
11
|
+
npm-debug.log*
|
|
12
|
+
pnpm-debug.log*
|
|
13
|
+
*.log
|
|
14
|
+
|
|
15
|
+
**/.env*
|
|
16
|
+
!.env.example
|
|
17
|
+
|
|
18
|
+
.eslintcache
|
|
19
|
+
|
|
20
|
+
.vscode/*
|
|
21
|
+
!.vscode/settings.json
|
|
22
|
+
!.vscode/extensions.json
|
|
23
|
+
/.idea
|
|
24
|
+
|
|
25
|
+
logs
|
|
26
|
+
.temp
|
|
27
|
+
.tmp
|
|
28
|
+
|
|
29
|
+
.DS_Store
|
|
30
|
+
.DS_Store?
|
|
31
|
+
._*
|
|
32
|
+
.Spotlight-V100
|
|
33
|
+
.Trashes
|
|
34
|
+
ehthumbs.db
|
|
35
|
+
Thumbs.db
|
|
36
|
+
**/.DS_Store
|
|
37
|
+
|
|
38
|
+
*.key
|
|
39
|
+
*.p12
|
|
40
|
+
*.pfx
|
|
41
|
+
id_rsa*
|
|
42
|
+
id_ed25519*
|
|
43
|
+
|
|
44
|
+
/.claude/settings.local.json
|
|
45
|
+
/.claude/worktrees/
|
|
46
|
+
|
|
47
|
+
/dist
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "next-friday-template-nestjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Next Friday NestJS template.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/next-friday/next-friday-template-nestjs.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "UNLICENSED",
|
|
11
|
+
"author": "Next Friday",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "nest build",
|
|
15
|
+
"check": "pnpm verify:static && pnpm test:changed",
|
|
16
|
+
"clean": "rm -rf dist coverage *.tsbuildinfo .eslintcache node_modules/.cache",
|
|
17
|
+
"depcruise": "depcruise --config .dependency-cruiser.json src test eslint.config.ts vitest.config.ts vitest.e2e.config.ts",
|
|
18
|
+
"format": "prettier --write --cache .",
|
|
19
|
+
"format:check": "prettier --check --cache . && editorconfig-checker",
|
|
20
|
+
"gates:check": "node scripts/check-agent-gates.ts",
|
|
21
|
+
"knip": "knip",
|
|
22
|
+
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
23
|
+
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
24
|
+
"peers:check": "pnpm peers check",
|
|
25
|
+
"prepare": "husky",
|
|
26
|
+
"rules:check": "node scripts/sync-agent-rules.ts --check",
|
|
27
|
+
"rules:sync": "node scripts/sync-agent-rules.ts",
|
|
28
|
+
"sort-package-json": "sort-package-json package.json",
|
|
29
|
+
"sort-package-json:check": "sort-package-json --check package.json",
|
|
30
|
+
"start": "node --env-file-if-exists=.env node_modules/@nestjs/cli/bin/nest.js start",
|
|
31
|
+
"start:debug": "node --env-file-if-exists=.env node_modules/@nestjs/cli/bin/nest.js start --debug --watch",
|
|
32
|
+
"start:dev": "node --env-file-if-exists=.env node_modules/@nestjs/cli/bin/nest.js start --watch",
|
|
33
|
+
"start:prod": "node dist/main",
|
|
34
|
+
"suppressions:check": "bash .agents/hooks/agent-suppression-gate.sh --repo",
|
|
35
|
+
"test": "vitest run --passWithNoTests",
|
|
36
|
+
"test:changed": "if git rev-parse --quiet --verify origin/main > /dev/null && git diff --quiet \"$(git merge-base origin/main HEAD)\" -- pnpm-lock.yaml pnpm-workspace.yaml \"*package.json\" \"*tsconfig.json\" .husky; then vitest run --changed origin/main --passWithNoTests; else vitest run --passWithNoTests; fi",
|
|
37
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
38
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
41
|
+
"verify": "pnpm verify:static && pnpm test:coverage",
|
|
42
|
+
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@nestjs/common": "12.3.2",
|
|
46
|
+
"@nestjs/core": "12.3.2",
|
|
47
|
+
"@nestjs/platform-express": "12.3.2",
|
|
48
|
+
"@nestjs/terminus": "12.1.0",
|
|
49
|
+
"reflect-metadata": "0.2.2",
|
|
50
|
+
"rxjs": "7.8.2"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@commitlint/cli": "21.2.4",
|
|
54
|
+
"@nestjs/cli": "12.0.11",
|
|
55
|
+
"@nestjs/schematics": "12.0.11",
|
|
56
|
+
"@nestjs/testing": "12.3.2",
|
|
57
|
+
"@next-friday/commitlint-config-friday": "4.0.0",
|
|
58
|
+
"@next-friday/eslint-config-friday": "5.0.0",
|
|
59
|
+
"@next-friday/prettier-config-friday": "4.0.0",
|
|
60
|
+
"@types/node": "24.19.2",
|
|
61
|
+
"@types/supertest": "7.2.1",
|
|
62
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
63
|
+
"dependency-cruiser": "18.7.0",
|
|
64
|
+
"editorconfig-checker": "7.0.0",
|
|
65
|
+
"eslint": "10.13.0",
|
|
66
|
+
"fast-check": "4.10.2",
|
|
67
|
+
"husky": "9.1.7",
|
|
68
|
+
"jiti": "2.7.0",
|
|
69
|
+
"knip": "6.43.0",
|
|
70
|
+
"lint-staged": "17.6.0",
|
|
71
|
+
"prettier": "3.9.10",
|
|
72
|
+
"sort-package-json": "4.1.0",
|
|
73
|
+
"supertest": "7.3.1",
|
|
74
|
+
"typescript": "6.0.3",
|
|
75
|
+
"vitest": "5.0.5"
|
|
76
|
+
},
|
|
77
|
+
"packageManager": "pnpm@12.6.0+sha512.3ef68f951cb111ac204b4a5a16f0b2ddf0da56a96e0413e81d855d9f0b55ef926714709028e1cd00c405c2c5fb7b9e8ec4dc46777c805d0373c2f2ff00fd20ec",
|
|
78
|
+
"engines": {
|
|
79
|
+
"node": ">=24.15.0 <25"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {Test, TestingModule} from "@nestjs/testing";
|
|
2
|
+
|
|
3
|
+
import {AppController} from "./app.controller.js";
|
|
4
|
+
import {AppService} from "./app.service.js";
|
|
5
|
+
|
|
6
|
+
describe("AppController", () => {
|
|
7
|
+
let appController: AppController;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
const app: TestingModule = await Test.createTestingModule({
|
|
11
|
+
controllers: [AppController],
|
|
12
|
+
providers: [AppService],
|
|
13
|
+
}).compile();
|
|
14
|
+
|
|
15
|
+
appController = app.get<AppController>(AppController);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("root", () => {
|
|
19
|
+
it('should return "Hello World!"', () => {
|
|
20
|
+
expect(appController.getHello()).toBe("Hello World!");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {Controller, Get} from "@nestjs/common";
|
|
2
|
+
|
|
3
|
+
import {AppService} from "./app.service.js";
|
|
4
|
+
|
|
5
|
+
@Controller()
|
|
6
|
+
export class AppController {
|
|
7
|
+
constructor(private readonly appService: AppService) {}
|
|
8
|
+
|
|
9
|
+
@Get()
|
|
10
|
+
getHello(): string {
|
|
11
|
+
return this.appService.getHello();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {Module} from "@nestjs/common";
|
|
2
|
+
|
|
3
|
+
import {AppController} from "./app.controller.js";
|
|
4
|
+
import {AppService} from "./app.service.js";
|
|
5
|
+
import {HealthModule} from "./health/health.module.js";
|
|
6
|
+
|
|
7
|
+
@Module({
|
|
8
|
+
imports: [HealthModule],
|
|
9
|
+
controllers: [AppController],
|
|
10
|
+
providers: [AppService],
|
|
11
|
+
})
|
|
12
|
+
export class AppModule {}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {TerminusModule} from "@nestjs/terminus";
|
|
2
|
+
import {Test} from "@nestjs/testing";
|
|
3
|
+
|
|
4
|
+
import {HealthController} from "./health.controller.js";
|
|
5
|
+
|
|
6
|
+
describe("HealthController", () => {
|
|
7
|
+
it("reports ok when every check passes", async () => {
|
|
8
|
+
const moduleReference = await Test.createTestingModule({
|
|
9
|
+
imports: [TerminusModule],
|
|
10
|
+
controllers: [HealthController],
|
|
11
|
+
}).compile();
|
|
12
|
+
|
|
13
|
+
await expect(moduleReference.get(HealthController).check()).resolves.toMatchObject({
|
|
14
|
+
status: "ok",
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {Controller, Get} from "@nestjs/common";
|
|
2
|
+
import {HealthCheck, HealthCheckService} from "@nestjs/terminus";
|
|
3
|
+
import type {HealthCheckResult} from "@nestjs/terminus";
|
|
4
|
+
|
|
5
|
+
@Controller("health")
|
|
6
|
+
export class HealthController {
|
|
7
|
+
constructor(private readonly health: HealthCheckService) {}
|
|
8
|
+
|
|
9
|
+
@Get()
|
|
10
|
+
@HealthCheck()
|
|
11
|
+
check(): Promise<HealthCheckResult> {
|
|
12
|
+
return this.health.check([]);
|
|
13
|
+
}
|
|
14
|
+
}
|