create-nexst-monorepo 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/dist/index.js +1727 -0
- package/package.json +37 -0
- package/template/.agents/plugins/marketplace.json +21 -0
- package/template/.claude/settings.json +6 -0
- package/template/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/template/.claude/skills/frontend-design/SKILL.md +154 -0
- package/template/.claude/skills/theme-factory/SKILL.md +95 -0
- package/template/.claude/skills/theme-factory/references/schema.md +104 -0
- package/template/.claude/skills/theme-factory/scripts/theme.mjs +261 -0
- package/template/.dockerignore +43 -0
- package/template/.editorconfig +10 -0
- package/template/.github/workflows/ci.yaml +289 -0
- package/template/.github/workflows/publish-app.yaml +66 -0
- package/template/.github/workflows/publish.yaml +148 -0
- package/template/.github/workflows/snyk.yaml +34 -0
- package/template/.vscode/settings.json +8 -0
- package/template/AGENTS.md +42 -0
- package/template/Dockerfile.base +9 -0
- package/template/README.md +54 -0
- package/template/_gitignore +10 -0
- package/template/apps/api/.env.example +32 -0
- package/template/apps/api/AGENTS.md +44 -0
- package/template/apps/api/Dockerfile +69 -0
- package/template/apps/api/_gitignore +8 -0
- package/template/apps/api/knip.config.ts +22 -0
- package/template/apps/api/kustomize/base/application.properties +16 -0
- package/template/apps/api/kustomize/base/deployment.yaml +94 -0
- package/template/apps/api/kustomize/base/kustomization.yaml +17 -0
- package/template/apps/api/kustomize/base/service.yaml +10 -0
- package/template/apps/api/kustomize/overlays/prod/kustomization.yaml +17 -0
- package/template/apps/api/kustomize/overlays/staging/application.properties +1 -0
- package/template/apps/api/kustomize/overlays/staging/kustomization.yaml +21 -0
- package/template/apps/api/kustomize/secret.keys +14 -0
- package/template/apps/api/oxfmt.config.ts +8 -0
- package/template/apps/api/oxlint.config.ts +107 -0
- package/template/apps/api/package.json +79 -0
- package/template/apps/api/prisma/migrations/20260927000000_init/migration.sql +113 -0
- package/template/apps/api/prisma/migrations/migration_lock.toml +3 -0
- package/template/apps/api/prisma/schema.prisma +113 -0
- package/template/apps/api/prisma.config.ts +7 -0
- package/template/apps/api/scripts/auth.cli.ts +19 -0
- package/template/apps/api/scripts/seal-secret.sh +171 -0
- package/template/apps/api/sonar-project.properties +9 -0
- package/template/apps/api/src/app-info/app-info.dto.ts +10 -0
- package/template/apps/api/src/app-info/app-info.module.ts +7 -0
- package/template/apps/api/src/app-info/app-info.resolver.spec.ts +14 -0
- package/template/apps/api/src/app-info/app-info.resolver.ts +21 -0
- package/template/apps/api/src/app.module.spec.ts +93 -0
- package/template/apps/api/src/app.module.ts +77 -0
- package/template/apps/api/src/auth/auth.guard.spec.ts +90 -0
- package/template/apps/api/src/auth/auth.guard.ts +97 -0
- package/template/apps/api/src/auth/auth.ts +129 -0
- package/template/apps/api/src/auth/decorator/allow-anonymous.decorator.ts +17 -0
- package/template/apps/api/src/auth/decorator/is-email-verified.decorator.spec.ts +41 -0
- package/template/apps/api/src/auth/decorator/is-email-verified.decorator.ts +20 -0
- package/template/apps/api/src/auth/decorator/roles.decorator.ts +27 -0
- package/template/apps/api/src/auth/testing/make-session.ts +31 -0
- package/template/apps/api/src/auth/types/auth.types.ts +27 -0
- package/template/apps/api/src/bootstrap/register-graphql-enums.ts +12 -0
- package/template/apps/api/src/bootstrap/security.ts +24 -0
- package/template/apps/api/src/bootstrap/swagger.ts +28 -0
- package/template/apps/api/src/config/app.config.spec.ts +22 -0
- package/template/apps/api/src/config/app.config.ts +122 -0
- package/template/apps/api/src/config/graphql-depth-limit.ts +103 -0
- package/template/apps/api/src/config/graphql.config.ts +77 -0
- package/template/apps/api/src/config/resources/app.yaml +29 -0
- package/template/apps/api/src/errors/app-parse-uuid.pipe.ts +27 -0
- package/template/apps/api/src/errors/app.exception.ts +47 -0
- package/template/apps/api/src/errors/error-code.enum.ts +54 -0
- package/template/apps/api/src/errors/http-status-fallback-code.util.ts +27 -0
- package/template/apps/api/src/errors/validation-exception.factory.ts +43 -0
- package/template/apps/api/src/health/health.controller.spec.ts +82 -0
- package/template/apps/api/src/health/health.controller.ts +57 -0
- package/template/apps/api/src/health/health.module.ts +12 -0
- package/template/apps/api/src/logging/context-logger.ts +18 -0
- package/template/apps/api/src/logging/logger.config.ts +23 -0
- package/template/apps/api/src/logging/logging.module.ts +22 -0
- package/template/apps/api/src/mail/mail.module.ts +12 -0
- package/template/apps/api/src/mail/mail.service.spec.ts +47 -0
- package/template/apps/api/src/mail/mail.service.ts +123 -0
- package/template/apps/api/src/main.ts +41 -0
- package/template/apps/api/src/prisma/prisma.module.ts +12 -0
- package/template/apps/api/src/prisma/prisma.service.spec.ts +136 -0
- package/template/apps/api/src/prisma/prisma.service.ts +138 -0
- package/template/apps/api/src/queue/dto/enqueue-example.input.ts +11 -0
- package/template/apps/api/src/queue/example-queue.resolver.ts +14 -0
- package/template/apps/api/src/queue/example-queue.service.spec.ts +21 -0
- package/template/apps/api/src/queue/example-queue.service.ts +32 -0
- package/template/apps/api/src/queue/queue.module.ts +27 -0
- package/template/apps/api/src/r2/r2.module.ts +12 -0
- package/template/apps/api/src/r2/r2.service.spec.ts +117 -0
- package/template/apps/api/src/r2/r2.service.ts +131 -0
- package/template/apps/api/src/user/dto/user.dto.ts +26 -0
- package/template/apps/api/src/user/user.module.ts +10 -0
- package/template/apps/api/src/user/user.resolver.spec.ts +18 -0
- package/template/apps/api/src/user/user.resolver.ts +24 -0
- package/template/apps/api/src/utils/catch-everything-exception.filter.spec.ts +292 -0
- package/template/apps/api/src/utils/catch-everything-exception.filter.ts +70 -0
- package/template/apps/api/src/utils/error-handler.util.spec.ts +20 -0
- package/template/apps/api/src/utils/error-handler.util.ts +12 -0
- package/template/apps/api/src/utils/escape-like-pattern.util.spec.ts +29 -0
- package/template/apps/api/src/utils/escape-like-pattern.util.ts +11 -0
- package/template/apps/api/src/utils/pagination.input.ts +20 -0
- package/template/apps/api/src/utils/prisma-exception.filter.spec.ts +186 -0
- package/template/apps/api/src/utils/prisma-exception.filter.ts +45 -0
- package/template/apps/api/src/utils/prisma-graphql-exception.filter.spec.ts +216 -0
- package/template/apps/api/src/utils/prisma-graphql-exception.filter.ts +43 -0
- package/template/apps/api/tests/app.e2e-spec.ts +35 -0
- package/template/apps/api/tests/auth.e2e-spec.ts +38 -0
- package/template/apps/api/tests/helpers/api.ts +27 -0
- package/template/apps/api/tsconfig.json +11 -0
- package/template/apps/api/vitest.config.e2e.ts +16 -0
- package/template/apps/api/vitest.config.ts +40 -0
- package/template/apps/web/.env.example +7 -0
- package/template/apps/web/.storybook/decorators.tsx +38 -0
- package/template/apps/web/.storybook/main.ts +17 -0
- package/template/apps/web/.storybook/preview.ts +38 -0
- package/template/apps/web/.storybook/vitest.setup.ts +5 -0
- package/template/apps/web/AGENTS.md +29 -0
- package/template/apps/web/Dockerfile +49 -0
- package/template/apps/web/_gitignore +16 -0
- package/template/apps/web/knip.config.ts +15 -0
- package/template/apps/web/kustomize/base/application.properties +5 -0
- package/template/apps/web/kustomize/base/deployment.yaml +60 -0
- package/template/apps/web/kustomize/base/kustomization.yaml +17 -0
- package/template/apps/web/kustomize/base/service.yaml +10 -0
- package/template/apps/web/kustomize/overlays/prod/kustomization.yaml +12 -0
- package/template/apps/web/kustomize/overlays/staging/application.properties +2 -0
- package/template/apps/web/kustomize/overlays/staging/kustomization.yaml +18 -0
- package/template/apps/web/messages/de.json +124 -0
- package/template/apps/web/messages/en.json +124 -0
- package/template/apps/web/next-env.d.ts +7 -0
- package/template/apps/web/next.config.ts +39 -0
- package/template/apps/web/oxfmt.config.ts +9 -0
- package/template/apps/web/oxlint.config.ts +36 -0
- package/template/apps/web/package.json +80 -0
- package/template/apps/web/playwright.config.ts +34 -0
- package/template/apps/web/postcss.config.mjs +7 -0
- package/template/apps/web/sonar-project.properties +9 -0
- package/template/apps/web/src/app/[locale]/(auth)/recovery/page.tsx +22 -0
- package/template/apps/web/src/app/[locale]/(auth)/reset-password/page.tsx +29 -0
- package/template/apps/web/src/app/[locale]/(auth)/sign-in/page.tsx +24 -0
- package/template/apps/web/src/app/[locale]/(auth)/sign-up/page.tsx +24 -0
- package/template/apps/web/src/app/[locale]/(auth)/verify/page.tsx +24 -0
- package/template/apps/web/src/app/[locale]/dashboard/page.tsx +34 -0
- package/template/apps/web/src/app/[locale]/layout.tsx +60 -0
- package/template/apps/web/src/app/[locale]/page.tsx +23 -0
- package/template/apps/web/src/app/api/health/route.ts +3 -0
- package/template/apps/web/src/app/global-error.tsx +19 -0
- package/template/apps/web/src/app/globals.css +98 -0
- package/template/apps/web/src/app/icon.svg +1 -0
- package/template/apps/web/src/app/robots.ts +15 -0
- package/template/apps/web/src/app/sitemap.ts +24 -0
- package/template/apps/web/src/components/alert/alert.stories.tsx +25 -0
- package/template/apps/web/src/components/alert/alert.tsx +50 -0
- package/template/apps/web/src/components/avatar/avatar.stories.tsx +116 -0
- package/template/apps/web/src/components/avatar/avatar.tsx +88 -0
- package/template/apps/web/src/components/button/button-variants.ts +28 -0
- package/template/apps/web/src/components/button/button.stories.tsx +33 -0
- package/template/apps/web/src/components/button/button.tsx +32 -0
- package/template/apps/web/src/components/checkbox/checkbox.stories.tsx +312 -0
- package/template/apps/web/src/components/checkbox/checkbox.tsx +38 -0
- package/template/apps/web/src/components/dialog/danger-panel.stories.tsx +41 -0
- package/template/apps/web/src/components/dialog/danger-panel.tsx +32 -0
- package/template/apps/web/src/components/dialog/dialog.stories.tsx +239 -0
- package/template/apps/web/src/components/dialog/dialog.tsx +136 -0
- package/template/apps/web/src/components/dialog-buttons.stories.tsx +55 -0
- package/template/apps/web/src/components/dialog-buttons.tsx +48 -0
- package/template/apps/web/src/components/drawer/drawer.stories.tsx +251 -0
- package/template/apps/web/src/components/drawer/drawer.tsx +120 -0
- package/template/apps/web/src/components/dropdown-menu/dropdown-menu.stories.tsx +329 -0
- package/template/apps/web/src/components/dropdown-menu/dropdown-menu.tsx +263 -0
- package/template/apps/web/src/components/empty-state.stories.tsx +49 -0
- package/template/apps/web/src/components/empty-state.tsx +33 -0
- package/template/apps/web/src/components/field-group.stories.tsx +47 -0
- package/template/apps/web/src/components/field-group.tsx +20 -0
- package/template/apps/web/src/components/field-label.stories.tsx +34 -0
- package/template/apps/web/src/components/field-label.tsx +28 -0
- package/template/apps/web/src/components/icons.tsx +25 -0
- package/template/apps/web/src/components/input/input-otp.stories.tsx +86 -0
- package/template/apps/web/src/components/input/input-otp.tsx +184 -0
- package/template/apps/web/src/components/input/input.stories.tsx +35 -0
- package/template/apps/web/src/components/input/input.tsx +180 -0
- package/template/apps/web/src/components/popover/popover.stories.tsx +479 -0
- package/template/apps/web/src/components/popover/popover.tsx +45 -0
- package/template/apps/web/src/components/responsive-dialog/responsive-dialog.stories.tsx +307 -0
- package/template/apps/web/src/components/responsive-dialog/responsive-dialog.tsx +96 -0
- package/template/apps/web/src/components/searchbar/searchbar.stories.tsx +59 -0
- package/template/apps/web/src/components/searchbar/searchbar.tsx +64 -0
- package/template/apps/web/src/components/select/select.stories.tsx +293 -0
- package/template/apps/web/src/components/select/select.tsx +445 -0
- package/template/apps/web/src/components/skeleton/skeleton.stories.tsx +76 -0
- package/template/apps/web/src/components/skeleton/skeleton.tsx +13 -0
- package/template/apps/web/src/components/spinner/spinner.tsx +18 -0
- package/template/apps/web/src/components/switch/switch.stories.tsx +71 -0
- package/template/apps/web/src/components/switch/switch.tsx +35 -0
- package/template/apps/web/src/components/tabs/tabs.stories.tsx +209 -0
- package/template/apps/web/src/components/tabs/tabs.tsx +69 -0
- package/template/apps/web/src/components/tabs/url-tabs.stories.tsx +68 -0
- package/template/apps/web/src/components/tabs/url-tabs.tsx +42 -0
- package/template/apps/web/src/components/textarea/textarea.stories.tsx +144 -0
- package/template/apps/web/src/components/textarea/textarea.tsx +115 -0
- package/template/apps/web/src/components/toast/toaster.tsx +38 -0
- package/template/apps/web/src/components/tooltip/tooltip.stories.tsx +237 -0
- package/template/apps/web/src/components/tooltip/tooltip.tsx +49 -0
- package/template/apps/web/src/config/csp.ts +59 -0
- package/template/apps/web/src/config/routes.ts +14 -0
- package/template/apps/web/src/config/site.ts +5 -0
- package/template/apps/web/src/env.ts +15 -0
- package/template/apps/web/src/features/auth/auth-card.tsx +20 -0
- package/template/apps/web/src/features/auth/auth-divider.tsx +14 -0
- package/template/apps/web/src/features/auth/google-auth-button.tsx +49 -0
- package/template/apps/web/src/features/auth/google-one-tap.tsx +23 -0
- package/template/apps/web/src/features/auth/lib/auth-error.test.ts +22 -0
- package/template/apps/web/src/features/auth/lib/auth-error.ts +16 -0
- package/template/apps/web/src/features/auth/lib/return-to.test.ts +41 -0
- package/template/apps/web/src/features/auth/lib/return-to.ts +19 -0
- package/template/apps/web/src/features/auth/lib/validator.test.ts +45 -0
- package/template/apps/web/src/features/auth/lib/validator.ts +49 -0
- package/template/apps/web/src/features/auth/passkey-settings.tsx +106 -0
- package/template/apps/web/src/features/auth/recovery-form.tsx +61 -0
- package/template/apps/web/src/features/auth/resend-verification-button.tsx +36 -0
- package/template/apps/web/src/features/auth/reset-password-form.tsx +62 -0
- package/template/apps/web/src/features/auth/sign-in-form.stories.tsx +22 -0
- package/template/apps/web/src/features/auth/sign-in-form.tsx +116 -0
- package/template/apps/web/src/features/auth/sign-out-button.tsx +26 -0
- package/template/apps/web/src/features/auth/sign-up-form.tsx +107 -0
- package/template/apps/web/src/features/shared/provider.tsx +16 -0
- package/template/apps/web/src/features/shared/site-header.tsx +48 -0
- package/template/apps/web/src/features/shared/theme-toggle.tsx +24 -0
- package/template/apps/web/src/i18n/navigation.ts +5 -0
- package/template/apps/web/src/i18n/request.ts +21 -0
- package/template/apps/web/src/i18n/routing.ts +6 -0
- package/template/apps/web/src/lib/auth-client.ts +19 -0
- package/template/apps/web/src/lib/auth-server.ts +46 -0
- package/template/apps/web/src/lib/auth.ts +8 -0
- package/template/apps/web/src/lib/codegen.ts +30 -0
- package/template/apps/web/src/lib/graphql-client.ts +29 -0
- package/template/apps/web/src/lib/graphql-server.ts +28 -0
- package/template/apps/web/src/lib/graphql-utils.test.ts +32 -0
- package/template/apps/web/src/lib/graphql-utils.ts +76 -0
- package/template/apps/web/src/lib/hooks/use-media-query.ts +21 -0
- package/template/apps/web/src/lib/metadata.ts +17 -0
- package/template/apps/web/src/lib/network-error.test.ts +30 -0
- package/template/apps/web/src/lib/network-error.ts +17 -0
- package/template/apps/web/src/lib/proxy-utils.ts +42 -0
- package/template/apps/web/src/lib/query-client.ts +29 -0
- package/template/apps/web/src/lib/utils.ts +5 -0
- package/template/apps/web/src/proxy.ts +57 -0
- package/template/apps/web/test-results/.last-run.json +4 -0
- package/template/apps/web/tests/auth.spec.ts +17 -0
- package/template/apps/web/tests/csp-theme-script.spec.ts +37 -0
- package/template/apps/web/tests/home.spec.ts +25 -0
- package/template/apps/web/tsconfig.build.json +4 -0
- package/template/apps/web/tsconfig.json +28 -0
- package/template/apps/web/vitest.config.ts +40 -0
- package/template/apps/web/vitest.shims.d.ts +1 -0
- package/template/apps/worker/.env.example +4 -0
- package/template/apps/worker/AGENTS.md +11 -0
- package/template/apps/worker/Dockerfile +35 -0
- package/template/apps/worker/knip.config.ts +3 -0
- package/template/apps/worker/kustomize/base/application.properties +4 -0
- package/template/apps/worker/kustomize/base/deployment.yaml +62 -0
- package/template/apps/worker/kustomize/base/kustomization.yaml +16 -0
- package/template/apps/worker/kustomize/overlays/prod/kustomization.yaml +12 -0
- package/template/apps/worker/kustomize/overlays/staging/application.properties +1 -0
- package/template/apps/worker/kustomize/overlays/staging/kustomization.yaml +18 -0
- package/template/apps/worker/oxfmt.config.ts +8 -0
- package/template/apps/worker/oxlint.config.ts +15 -0
- package/template/apps/worker/package.json +33 -0
- package/template/apps/worker/sonar-project.properties +8 -0
- package/template/apps/worker/src/env.ts +13 -0
- package/template/apps/worker/src/lib/graceful-shutdown.ts +27 -0
- package/template/apps/worker/src/lib/logger.ts +20 -0
- package/template/apps/worker/src/main.ts +17 -0
- package/template/apps/worker/src/processors/example-processor.ts +15 -0
- package/template/apps/worker/src/worker/redis.ts +19 -0
- package/template/apps/worker/src/worker/worker.ts +37 -0
- package/template/apps/worker/tests/example-processor.test.ts +13 -0
- package/template/apps/worker/tests/graceful-shutdown.test.ts +34 -0
- package/template/apps/worker/tsconfig.json +4 -0
- package/template/apps/worker/vitest.config.ts +13 -0
- package/template/bun.lock +3053 -0
- package/template/bunfig.toml +2 -0
- package/template/compose.yaml +53 -0
- package/template/docker-bake.hcl +86 -0
- package/template/package.json +47 -0
- package/template/packages/lint/knip.ts +40 -0
- package/template/packages/lint/oxfmt.ts +8 -0
- package/template/packages/lint/oxlint.ts +136 -0
- package/template/packages/lint/package.json +13 -0
- package/template/packages/queues/oxfmt.config.ts +8 -0
- package/template/packages/queues/oxlint.config.ts +7 -0
- package/template/packages/queues/package.json +15 -0
- package/template/packages/queues/src/example-job.ts +11 -0
- package/template/packages/queues/src/index.ts +3 -0
- package/template/packages/queues/src/queue-names.ts +2 -0
- package/template/packages/queues/src/redis-connection.ts +27 -0
- package/template/packages/queues/tsconfig.json +4 -0
- package/template/packages/tsconfig/base.json +23 -0
- package/template/packages/tsconfig/node.json +11 -0
- package/template/packages/tsconfig/package.json +4 -0
- package/template/turbo.json +50 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
name: Publish Images
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
concurrency:
|
|
8
|
+
group: publish-images-${{ github.ref }}
|
|
9
|
+
cancel-in-progress: false
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
packages: write
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
changes:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
outputs:
|
|
19
|
+
web: ${{ steps.filter.outputs.web }}
|
|
20
|
+
api: ${{ steps.filter.outputs.api }}
|
|
21
|
+
# @if worker
|
|
22
|
+
worker: ${{ steps.filter.outputs.worker }}
|
|
23
|
+
# @endif
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v6
|
|
26
|
+
- uses: dorny/paths-filter@v3
|
|
27
|
+
id: filter
|
|
28
|
+
with:
|
|
29
|
+
filters: |
|
|
30
|
+
shared: &shared
|
|
31
|
+
- 'package.json'
|
|
32
|
+
- 'bun.lock'
|
|
33
|
+
- 'bunfig.toml'
|
|
34
|
+
- 'turbo.json'
|
|
35
|
+
- '.dockerignore'
|
|
36
|
+
- 'Dockerfile.base'
|
|
37
|
+
- 'docker-bake.hcl'
|
|
38
|
+
- 'packages/**'
|
|
39
|
+
web:
|
|
40
|
+
- *shared
|
|
41
|
+
- 'apps/web/**'
|
|
42
|
+
- '!apps/web/kustomize/**'
|
|
43
|
+
api:
|
|
44
|
+
- *shared
|
|
45
|
+
- 'apps/api/**'
|
|
46
|
+
- '!apps/api/kustomize/**'
|
|
47
|
+
# @if worker
|
|
48
|
+
worker:
|
|
49
|
+
- *shared
|
|
50
|
+
- 'apps/worker/**'
|
|
51
|
+
- '!apps/worker/kustomize/**'
|
|
52
|
+
# @endif
|
|
53
|
+
|
|
54
|
+
web:
|
|
55
|
+
needs: changes
|
|
56
|
+
if: needs.changes.outputs.web == 'true'
|
|
57
|
+
uses: ./.github/workflows/publish-app.yaml
|
|
58
|
+
with:
|
|
59
|
+
app: web
|
|
60
|
+
secrets: inherit
|
|
61
|
+
|
|
62
|
+
api:
|
|
63
|
+
needs: changes
|
|
64
|
+
if: needs.changes.outputs.api == 'true'
|
|
65
|
+
uses: ./.github/workflows/publish-app.yaml
|
|
66
|
+
with:
|
|
67
|
+
app: api
|
|
68
|
+
secrets: inherit
|
|
69
|
+
|
|
70
|
+
api-migrate:
|
|
71
|
+
needs: changes
|
|
72
|
+
if: needs.changes.outputs.api == 'true'
|
|
73
|
+
uses: ./.github/workflows/publish-app.yaml
|
|
74
|
+
with:
|
|
75
|
+
app: api-migrate
|
|
76
|
+
secrets: inherit
|
|
77
|
+
# @if worker
|
|
78
|
+
|
|
79
|
+
worker:
|
|
80
|
+
needs: changes
|
|
81
|
+
if: needs.changes.outputs.worker == 'true'
|
|
82
|
+
uses: ./.github/workflows/publish-app.yaml
|
|
83
|
+
with:
|
|
84
|
+
app: worker
|
|
85
|
+
secrets: inherit
|
|
86
|
+
# @endif
|
|
87
|
+
|
|
88
|
+
# Pins the freshly pushed sha-* tags in the prod overlays so GitOps (Flux/Argo)
|
|
89
|
+
# rolls them out.
|
|
90
|
+
rewind:
|
|
91
|
+
if: >-
|
|
92
|
+
always() &&
|
|
93
|
+
needs.changes.result == 'success' &&
|
|
94
|
+
!contains(needs.*.result, 'failure') &&
|
|
95
|
+
!contains(needs.*.result, 'cancelled') &&
|
|
96
|
+
contains(needs.*.result, 'success')
|
|
97
|
+
# @if worker
|
|
98
|
+
needs: [changes, web, api, api-migrate, worker]
|
|
99
|
+
# @endif
|
|
100
|
+
# @if !worker
|
|
101
|
+
# needs: [changes, web, api, api-migrate]
|
|
102
|
+
# @endif
|
|
103
|
+
runs-on: ubuntu-latest
|
|
104
|
+
permissions:
|
|
105
|
+
contents: write
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/checkout@v6
|
|
108
|
+
with:
|
|
109
|
+
fetch-depth: 0
|
|
110
|
+
ref: main
|
|
111
|
+
|
|
112
|
+
- name: Set up Kustomize
|
|
113
|
+
working-directory: ${{ runner.temp }}
|
|
114
|
+
run: |
|
|
115
|
+
curl -sSfL https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash
|
|
116
|
+
sudo mv kustomize /usr/local/bin/
|
|
117
|
+
|
|
118
|
+
- name: Update image tags in prod overlays
|
|
119
|
+
env:
|
|
120
|
+
API_CHANGED: ${{ needs.changes.outputs.api }}
|
|
121
|
+
WEB_CHANGED: ${{ needs.changes.outputs.web }}
|
|
122
|
+
WORKER_CHANGED: ${{ needs.changes.outputs.worker }} # @if worker
|
|
123
|
+
run: |
|
|
124
|
+
TAG="sha-${GITHUB_SHA::7}"
|
|
125
|
+
REGISTRY="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}"
|
|
126
|
+
|
|
127
|
+
pin() { # <app dir> <image>
|
|
128
|
+
(cd "apps/$1/kustomize/overlays/prod" && kustomize edit set image "$2=$REGISTRY/$2:$TAG")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if [ "$WEB_CHANGED" = "true" ]; then pin web nexst-web; fi
|
|
132
|
+
if [ "$API_CHANGED" = "true" ]; then
|
|
133
|
+
pin api nexst-api
|
|
134
|
+
pin api nexst-api-migrate
|
|
135
|
+
fi
|
|
136
|
+
if [ "$WORKER_CHANGED" = "true" ]; then pin worker nexst-worker; fi # @if worker
|
|
137
|
+
|
|
138
|
+
- name: Commit and push
|
|
139
|
+
run: |
|
|
140
|
+
git config user.name "github-actions[bot]"
|
|
141
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
142
|
+
git add apps/*/kustomize/overlays/prod/kustomization.yaml
|
|
143
|
+
if git diff --cached --quiet; then
|
|
144
|
+
echo "No image tag changes to commit."
|
|
145
|
+
exit 0
|
|
146
|
+
fi
|
|
147
|
+
git commit -m "chore: rewind images to sha-${GITHUB_SHA::7} [skip ci]"
|
|
148
|
+
git push origin HEAD:main
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Snyk Scan
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 0 * * *'
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
security:
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
security-events: write
|
|
19
|
+
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
env:
|
|
22
|
+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v6
|
|
26
|
+
- uses: snyk/actions/setup@master
|
|
27
|
+
|
|
28
|
+
- name: Snyk Code test
|
|
29
|
+
run: snyk code test --sarif-file-output=snyk.sarif || true
|
|
30
|
+
|
|
31
|
+
- name: Upload result to GitHub Code Scanning
|
|
32
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
33
|
+
with:
|
|
34
|
+
sarif_file: snyk.sarif
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Nexst
|
|
2
|
+
|
|
3
|
+
Bun workspace: one `package.json`, one lockfile (`bun.lock`), one CI (root
|
|
4
|
+
`.github/workflows/`). `apps/*/AGENTS.md` add app-specific rules.
|
|
5
|
+
|
|
6
|
+
- **web** — Next.js 16, next-intl (en, de), Tailwind 4, React Query.
|
|
7
|
+
- **api** — NestJS 12 on Fastify (REST + GraphQL), Prisma 7 on Postgres.
|
|
8
|
+
<!-- @if worker -->
|
|
9
|
+
- **worker** — BullMQ worker for background jobs the API enqueues; shared queue
|
|
10
|
+
contracts in `packages/queues`.
|
|
11
|
+
<!-- @endif -->
|
|
12
|
+
- **packages/lint**, **packages/tsconfig** — shared oxlint/oxfmt/knip and TS configs.
|
|
13
|
+
|
|
14
|
+
## Local dev
|
|
15
|
+
|
|
16
|
+
`bun dev` starts the infra from `compose.yaml` and runs all apps in watch mode.
|
|
17
|
+
The backend apps have no build step; bun runs `src/*.ts` directly, also in production.
|
|
18
|
+
Secrets live in each app's `.env`/`.env.development` (see `.env.example`); bun loads
|
|
19
|
+
them itself. Run TypeScript with bun (`bun <file>`, `bunx --bun prisma`), not node.
|
|
20
|
+
|
|
21
|
+
## Docker
|
|
22
|
+
|
|
23
|
+
`docker buildx bake <api|api-migrate|web> --load` (arm64, needs `docker login dhi.io`).
|
|
24
|
+
Images are DHI bun Alpine and must stay small: pruned lockfile +
|
|
25
|
+
`--production --omit=peer`, prisma only in the `prisma` stage, system packages via
|
|
26
|
+
`apk add --root`. Kustomize manifests per app in `apps/*/kustomize`; the publish
|
|
27
|
+
workflow pins new `sha-*` tags into the prod overlays.
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
- Check the installed version (`package.json`, `bun.lock`) and use the docs for exactly
|
|
32
|
+
that version, not training knowledge.
|
|
33
|
+
- Superpowers skills (`.agents/plugins/marketplace.json`): `brainstorming` before
|
|
34
|
+
behavior-changing features, then `writing-plans`; `systematic-debugging` before bug
|
|
35
|
+
fixes; `test-driven-development` for app code; `requesting-code-review` for larger
|
|
36
|
+
changes; `verification-before-completion` before claiming done.
|
|
37
|
+
- After every TS/JS change, in the affected app: `bun run lint` (Oxlint, no ESLint),
|
|
38
|
+
`bun run lint:ts`, and the smallest relevant Vitest run (`bun run vitest run <path>`).
|
|
39
|
+
Visible web UI changes also need Playwright (`bun run test`) and browser verification;
|
|
40
|
+
api changes to external interfaces, DB or auth need the affected E2E tests.
|
|
41
|
+
- Touch `bun.lock` only with an intentional dependency change. Fix root causes; new
|
|
42
|
+
lint-disable comments need a narrow, documented reason.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
ARG BUN_VERSION
|
|
2
|
+
|
|
3
|
+
FROM dhi.io/bun:${BUN_VERSION}-alpine-dev
|
|
4
|
+
ENV PATH="/root/.bun/bin:${PATH}"
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
COPY package.json ./
|
|
7
|
+
RUN --mount=type=cache,id=bun-turbo-install,sharing=locked,target=/root/.bun/install/cache \
|
|
8
|
+
bun add -g turbo@$(bun -p 'require("./package.json").devDependencies.turbo')
|
|
9
|
+
COPY . .
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Nexst
|
|
2
|
+
|
|
3
|
+
Monorepo generated with `create-nexst-monorepo`:
|
|
4
|
+
|
|
5
|
+
- `apps/web` — Next.js frontend
|
|
6
|
+
- `apps/api` — NestJS backend (REST + GraphQL, Prisma)
|
|
7
|
+
- `apps/worker` — BullMQ worker <!-- @if worker -->
|
|
8
|
+
|
|
9
|
+
## Getting started
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
cp apps/api/.env.example apps/api/.env.development # fill in secrets
|
|
13
|
+
cp apps/web/.env.example apps/web/.env
|
|
14
|
+
<!-- @if worker -->
|
|
15
|
+
cp apps/worker/.env.example apps/worker/.env
|
|
16
|
+
<!-- @endif -->
|
|
17
|
+
bun install
|
|
18
|
+
(cd apps/api && bun run db:generate && bunx --bun prisma migrate deploy)
|
|
19
|
+
bun dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- Web: http://localhost:3000
|
|
23
|
+
- API: http://localhost:3001 (GraphiQL `/graphql`, Swagger `/api`, health `/health`)
|
|
24
|
+
<!-- @if auth -->
|
|
25
|
+
- Mail (MailHog): http://localhost:8025
|
|
26
|
+
|
|
27
|
+
Google sign-in (button + One Tap) stays hidden until it is configured: create an OAuth
|
|
28
|
+
client (type "Web application") in the Google Cloud console with the redirect URI
|
|
29
|
+
`http://localhost:3001/api/auth/callback/google` and the JavaScript origin
|
|
30
|
+
`http://localhost:3000`, then set `GOOGLE_CLIENT_ID`/`GOOGLE_CLIENT_SECRET` in
|
|
31
|
+
`apps/api/.env.development` and `NEXT_PUBLIC_GOOGLE_CLIENT_ID` in `apps/web/.env`.
|
|
32
|
+
<!-- @endif -->
|
|
33
|
+
|
|
34
|
+
## Scripts (root, via turbo)
|
|
35
|
+
|
|
36
|
+
| Script | What it does |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `bun dev` | Infra via docker compose + all apps in watch mode |
|
|
39
|
+
| `bun run lint` / `lint:fix` | Oxlint (type-aware) |
|
|
40
|
+
| `bun run fmt` / `fmt:check` | Oxfmt |
|
|
41
|
+
| `bun run lint:ts` | TypeScript (tsgo) |
|
|
42
|
+
| `bun run test:unit` | Vitest in every app |
|
|
43
|
+
| `bun run unused` | knip |
|
|
44
|
+
|
|
45
|
+
## Deployment
|
|
46
|
+
|
|
47
|
+
- Images: `docker buildx bake` (targets in `docker-bake.hcl`), pushed to ghcr.io by
|
|
48
|
+
`.github/workflows/publish.yaml`, which also pins the new tags in
|
|
49
|
+
`apps/*/kustomize/overlays/prod`.
|
|
50
|
+
- Secrets: `apps/api/scripts/seal-secret.sh` seals the keys listed in
|
|
51
|
+
`apps/api/kustomize/secret.keys` into a SealedSecret.
|
|
52
|
+
- CI secrets: `DHI_REGISTRY_USERNAME`/`DHI_REGISTRY_PASSWORD` (image builds),
|
|
53
|
+
optional `SONAR_TOKEN`/`SONAR_HOST_URL`, `SNYK_TOKEN`. Repository variables
|
|
54
|
+
`NEXT_PUBLIC_API_URL`/`NEXT_PUBLIC_HOST_URL` are baked into the web image.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Copy to .env.development (bun loads it automatically in dev) and fill in.
|
|
2
|
+
NODE_ENV=development
|
|
3
|
+
LOG_LEVEL=debug
|
|
4
|
+
PORT=3001
|
|
5
|
+
|
|
6
|
+
DATABASE_URL=postgresql://nexst_user:test-pw@localhost:5432/nexst_db?schema=nexst_user
|
|
7
|
+
# @if auth
|
|
8
|
+
|
|
9
|
+
# openssl rand -base64 32
|
|
10
|
+
BETTER_AUTH_SECRET=change-me-change-me-change-me-change-me
|
|
11
|
+
BETTER_AUTH_URL=http://localhost:3001
|
|
12
|
+
# Mail goes to MailHog (http://localhost:8025) outside production.
|
|
13
|
+
MAIL_SMTP_HOST=localhost
|
|
14
|
+
# RESEND_API_KEY=
|
|
15
|
+
# Google sign-in: OAuth client (Web application) from https://console.cloud.google.com/apis/credentials
|
|
16
|
+
# with redirect URI http://localhost:3001/api/auth/callback/google. Disabled while unset.
|
|
17
|
+
# GOOGLE_CLIENT_ID=
|
|
18
|
+
# GOOGLE_CLIENT_SECRET=
|
|
19
|
+
# @endif
|
|
20
|
+
# @if r2
|
|
21
|
+
|
|
22
|
+
R2_ACCESS_KEY_ID=
|
|
23
|
+
R2_SECRET_ACCESS_KEY=
|
|
24
|
+
R2_BUCKET=nexst
|
|
25
|
+
R2_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
|
|
26
|
+
# R2_PUBLIC_URL=https://cdn.example.com
|
|
27
|
+
# @endif
|
|
28
|
+
# @if worker
|
|
29
|
+
|
|
30
|
+
REDIS_HOST=localhost
|
|
31
|
+
REDIS_PORT=6379
|
|
32
|
+
# @endif
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# api (NestJS)
|
|
2
|
+
|
|
3
|
+
This project uses NestJS 12 with ESM (`"type": "module"` in `package.json`,
|
|
4
|
+
`module`/`moduleResolution: nodenext` in `tsconfig.json`) — not the CommonJS setup most
|
|
5
|
+
NestJS tutorials, examples, and training data assume. Import paths, dynamic `import()`
|
|
6
|
+
usage, decorator/metadata behavior, and module interop can differ under ESM. When in
|
|
7
|
+
doubt, read the official NestJS documentation for the installed version
|
|
8
|
+
(`@nestjs/core` in `package.json`) rather than relying on memory.
|
|
9
|
+
|
|
10
|
+
## Conventions
|
|
11
|
+
|
|
12
|
+
- Imports use the `#src/*` / `#tests/*` subpath aliases with a `.js` suffix.
|
|
13
|
+
- Prisma client always from `#src/generated/prisma/client.js` (`bun run db:generate`
|
|
14
|
+
after schema changes), never `@prisma/client`.
|
|
15
|
+
- Codes-only errors: throw `new AppException(ErrorCode.X, HttpStatus.Y, params?)`
|
|
16
|
+
(`src/errors/`), never a free-text `HttpException`. `bun run lint:error-codes` and
|
|
17
|
+
oxlint's `no-restricted-imports` enforce it; add new codes to `error-code.enum.ts`.
|
|
18
|
+
- Loggers: inject `ContextLogger`, not `nestjs-pino` directly.
|
|
19
|
+
- Config: static defaults in `src/config/resources/app.yaml`, secrets/env in
|
|
20
|
+
`src/config/app.config.ts` (zod-validated at startup).
|
|
21
|
+
- The global `ValidationPipe` runs with `whitelist: true`: every input field needs a
|
|
22
|
+
class-validator decorator (`@IsOptional()`/`@Allow()` for JSON fields) or it is
|
|
23
|
+
silently stripped.
|
|
24
|
+
- Auth (if present): every route needs a session unless marked `@AllowAnonymous()`;
|
|
25
|
+
`@IsEmailVerified()` and `@Roles(...)` are enforced by `src/auth/auth.guard.ts`.
|
|
26
|
+
|
|
27
|
+
## Local dev
|
|
28
|
+
|
|
29
|
+
- Schema changes: `bun run db:migrate` (creates a migration) or `bun run db:push`
|
|
30
|
+
against the local dev Postgres (`DATABASE_URL` from `.env.development`).
|
|
31
|
+
- Swagger UI at `/api`, GraphiQL at `/graphql` when `NODE_ENV=development`.
|
|
32
|
+
|
|
33
|
+
## Tests
|
|
34
|
+
|
|
35
|
+
- Unit: `bun run test:unit` (co-located `*.spec.ts`, no services needed).
|
|
36
|
+
- E2E: `bun run test:e2e` against a running API (`API_URL`, default
|
|
37
|
+
`http://localhost:3001`); start it with `NODE_ENV=test` so sign-up skips mail.
|
|
38
|
+
|
|
39
|
+
## Docker image testing
|
|
40
|
+
|
|
41
|
+
Separate path, not the regular dev loop. Build with `docker buildx bake api --load`
|
|
42
|
+
(`api-migrate` for the migrator), then run it against the local infra from `bun dev`
|
|
43
|
+
(env from `.env`, `DATABASE_URL` pointing at `host.docker.internal`) and check
|
|
44
|
+
`/health` plus the container logs.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
ARG BUN_VERSION
|
|
2
|
+
|
|
3
|
+
# ---------------------------------------------------
|
|
4
|
+
# Stage 1: Pruner
|
|
5
|
+
# ---------------------------------------------------
|
|
6
|
+
FROM toolchain AS pruner
|
|
7
|
+
RUN turbo prune @nexst/api --docker
|
|
8
|
+
|
|
9
|
+
# ---------------------------------------------------
|
|
10
|
+
# Stage 2: Deps
|
|
11
|
+
# ---------------------------------------------------
|
|
12
|
+
FROM dhi.io/bun:${BUN_VERSION}-alpine-dev AS deps
|
|
13
|
+
WORKDIR /app
|
|
14
|
+
COPY --from=pruner /app/out/json/ .
|
|
15
|
+
RUN --mount=type=cache,id=bun-install,sharing=locked,target=/root/.bun/install/cache \
|
|
16
|
+
bun install --frozen-lockfile --production --omit=peer
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------
|
|
19
|
+
# Stage 3: Prisma
|
|
20
|
+
# ---------------------------------------------------
|
|
21
|
+
FROM dhi.io/bun:${BUN_VERSION}-alpine-dev AS prisma
|
|
22
|
+
WORKDIR /app/apps/api
|
|
23
|
+
RUN --mount=type=bind,from=pruner,source=/app/out/json/bun.lock,target=/tmp/bun.lock \
|
|
24
|
+
--mount=type=cache,id=bun-install,sharing=locked,target=/root/.bun/install/cache \
|
|
25
|
+
bun add --omit=peer $(bun -p 'require("/tmp/bun.lock").packages.prisma[0]') && \
|
|
26
|
+
find node_modules -path '*@prisma/engines/schema-engine-*' -type f | grep -q .
|
|
27
|
+
COPY --from=pruner /app/out/full/apps/api/prisma ./prisma
|
|
28
|
+
COPY --from=pruner /app/out/full/apps/api/prisma.config.ts ./
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------
|
|
31
|
+
# Stage 4: Builder
|
|
32
|
+
# ---------------------------------------------------
|
|
33
|
+
FROM prisma AS builder
|
|
34
|
+
RUN --mount=type=bind,from=pruner,source=/app/out/json/bun.lock,target=/tmp/bun.lock \
|
|
35
|
+
--mount=type=cache,id=bun-install,sharing=locked,target=/root/.bun/install/cache \
|
|
36
|
+
bun add --omit=peer $(bun -p 'require("/tmp/bun.lock").packages["@prisma/client"][0]') && \
|
|
37
|
+
bunx --bun prisma generate
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------
|
|
40
|
+
# Stage 5: Migrator
|
|
41
|
+
# ---------------------------------------------------
|
|
42
|
+
FROM prisma AS migrator
|
|
43
|
+
ENV NODE_ENV=production
|
|
44
|
+
USER nonroot
|
|
45
|
+
CMD ["bunx", "--bun", "prisma", "migrate", "deploy"]
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------
|
|
48
|
+
# Stage 6: Runtime
|
|
49
|
+
# ---------------------------------------------------
|
|
50
|
+
FROM dhi.io/bun:${BUN_VERSION}-alpine AS runtime
|
|
51
|
+
WORKDIR /app
|
|
52
|
+
ENV NODE_ENV=production \
|
|
53
|
+
PRISMA_AUTO_MIGRATE=false
|
|
54
|
+
|
|
55
|
+
COPY --from=deps --chown=nonroot:nonroot /app/node_modules ./node_modules
|
|
56
|
+
COPY --from=deps --chown=nonroot:nonroot /app/apps/api/node_modules ./apps/api/node_modules
|
|
57
|
+
# @if worker
|
|
58
|
+
COPY --from=pruner --chown=nonroot:nonroot /app/out/full/packages/queues ./packages/queues
|
|
59
|
+
# @endif
|
|
60
|
+
COPY --from=pruner --chown=nonroot:nonroot /app/out/full/apps/api ./apps/api
|
|
61
|
+
COPY --from=builder --chown=nonroot:nonroot /app/apps/api/src/generated ./apps/api/src/generated
|
|
62
|
+
|
|
63
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=15s --retries=3 \
|
|
64
|
+
CMD ["bun", "-e", "require('http').get('http://localhost:3001/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) }).on('error', () => process.exit(1))"]
|
|
65
|
+
|
|
66
|
+
EXPOSE 3001
|
|
67
|
+
STOPSIGNAL SIGTERM
|
|
68
|
+
WORKDIR /app/apps/api
|
|
69
|
+
CMD ["bun", "src/main.ts"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createKnipConfig } from "@nexst/lint/knip";
|
|
2
|
+
import type { KnipConfig } from "knip";
|
|
3
|
+
|
|
4
|
+
const config: KnipConfig = createKnipConfig({
|
|
5
|
+
entry: [
|
|
6
|
+
"prisma/schema.prisma",
|
|
7
|
+
"src/main.ts",
|
|
8
|
+
"scripts/auth.cli.ts", // @if auth
|
|
9
|
+
// Template building blocks, kept until the first feature uses them.
|
|
10
|
+
"src/auth/decorator/roles.decorator.ts", // @if auth
|
|
11
|
+
"src/errors/app-parse-uuid.pipe.ts",
|
|
12
|
+
"src/utils/pagination.input.ts",
|
|
13
|
+
],
|
|
14
|
+
ignoreBinaries: [
|
|
15
|
+
"better-auth", // @if auth
|
|
16
|
+
],
|
|
17
|
+
ignoreDependencies: ["@prisma/client-runtime-utils", "@types/js-yaml"],
|
|
18
|
+
project: ["prisma/**/*.prisma"],
|
|
19
|
+
vitest: { config: ["vitest.config.ts", "vitest.config.e2e.ts"] },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export default config;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
NODE_ENV=production
|
|
2
|
+
LOG_LEVEL=info
|
|
3
|
+
PRISMA_AUTO_MIGRATE=false
|
|
4
|
+
# @if auth
|
|
5
|
+
BETTER_AUTH_URL=https://api.example.com
|
|
6
|
+
COOKIE_DOMAIN=.example.com
|
|
7
|
+
# GOOGLE_CLIENT_ID=<id>.apps.googleusercontent.com
|
|
8
|
+
# @endif
|
|
9
|
+
# @if worker
|
|
10
|
+
REDIS_HOST=redis-master
|
|
11
|
+
REDIS_PORT=6379
|
|
12
|
+
# @endif
|
|
13
|
+
# @if r2
|
|
14
|
+
R2_BUCKET=nexst
|
|
15
|
+
R2_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
|
|
16
|
+
# @endif
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
apiVersion: apps/v1
|
|
2
|
+
kind: Deployment
|
|
3
|
+
metadata:
|
|
4
|
+
name: nexst-api
|
|
5
|
+
spec:
|
|
6
|
+
replicas: 1
|
|
7
|
+
selector:
|
|
8
|
+
matchLabels:
|
|
9
|
+
app: nexst-api
|
|
10
|
+
template:
|
|
11
|
+
metadata:
|
|
12
|
+
labels:
|
|
13
|
+
app: nexst-api
|
|
14
|
+
spec:
|
|
15
|
+
securityContext:
|
|
16
|
+
runAsNonRoot: true
|
|
17
|
+
runAsUser: 10001
|
|
18
|
+
runAsGroup: 10001
|
|
19
|
+
fsGroup: 10001
|
|
20
|
+
seccompProfile:
|
|
21
|
+
type: RuntimeDefault
|
|
22
|
+
serviceAccountName: ghcr-puller
|
|
23
|
+
initContainers:
|
|
24
|
+
- name: db-migrate
|
|
25
|
+
image: nexst-api-migrate
|
|
26
|
+
imagePullPolicy: IfNotPresent
|
|
27
|
+
envFrom:
|
|
28
|
+
- configMapRef:
|
|
29
|
+
name: nexst-api-config
|
|
30
|
+
- secretRef:
|
|
31
|
+
name: nexst-api-secret
|
|
32
|
+
resources:
|
|
33
|
+
requests:
|
|
34
|
+
memory: 128Mi
|
|
35
|
+
cpu: 50m
|
|
36
|
+
limits:
|
|
37
|
+
memory: 256Mi
|
|
38
|
+
cpu: 200m
|
|
39
|
+
securityContext:
|
|
40
|
+
allowPrivilegeEscalation: false
|
|
41
|
+
runAsNonRoot: false
|
|
42
|
+
readOnlyRootFilesystem: false
|
|
43
|
+
capabilities:
|
|
44
|
+
drop: [ALL]
|
|
45
|
+
seccompProfile:
|
|
46
|
+
type: RuntimeDefault
|
|
47
|
+
containers:
|
|
48
|
+
- name: nexst-api
|
|
49
|
+
image: nexst-api
|
|
50
|
+
imagePullPolicy: IfNotPresent
|
|
51
|
+
ports:
|
|
52
|
+
- name: http
|
|
53
|
+
containerPort: 3001
|
|
54
|
+
protocol: TCP
|
|
55
|
+
securityContext:
|
|
56
|
+
allowPrivilegeEscalation: false
|
|
57
|
+
runAsNonRoot: true
|
|
58
|
+
runAsUser: 10001
|
|
59
|
+
runAsGroup: 10001
|
|
60
|
+
readOnlyRootFilesystem: true
|
|
61
|
+
capabilities:
|
|
62
|
+
drop: [ALL]
|
|
63
|
+
seccompProfile:
|
|
64
|
+
type: RuntimeDefault
|
|
65
|
+
envFrom:
|
|
66
|
+
- configMapRef:
|
|
67
|
+
name: nexst-api-config
|
|
68
|
+
- secretRef:
|
|
69
|
+
name: nexst-api-secret
|
|
70
|
+
volumeMounts:
|
|
71
|
+
- name: tmp
|
|
72
|
+
mountPath: /tmp
|
|
73
|
+
resources:
|
|
74
|
+
requests:
|
|
75
|
+
memory: 256Mi
|
|
76
|
+
cpu: 100m
|
|
77
|
+
limits:
|
|
78
|
+
memory: 512Mi
|
|
79
|
+
cpu: 500m
|
|
80
|
+
livenessProbe:
|
|
81
|
+
httpGet:
|
|
82
|
+
path: /health/live
|
|
83
|
+
port: http
|
|
84
|
+
initialDelaySeconds: 5
|
|
85
|
+
periodSeconds: 10
|
|
86
|
+
readinessProbe:
|
|
87
|
+
httpGet:
|
|
88
|
+
path: /health
|
|
89
|
+
port: http
|
|
90
|
+
initialDelaySeconds: 5
|
|
91
|
+
periodSeconds: 5
|
|
92
|
+
volumes:
|
|
93
|
+
- name: tmp
|
|
94
|
+
emptyDir: {}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
labels:
|
|
2
|
+
- pairs:
|
|
3
|
+
app.kubernetes.io/name: nexst-api
|
|
4
|
+
app.kubernetes.io/part-of: nexst
|
|
5
|
+
app.kubernetes.io/managed-by: kustomize
|
|
6
|
+
app.kubernetes.io/created-by: your-org
|
|
7
|
+
app.kubernetes.io/component: api
|
|
8
|
+
includeSelectors: true
|
|
9
|
+
|
|
10
|
+
resources:
|
|
11
|
+
- deployment.yaml
|
|
12
|
+
- service.yaml
|
|
13
|
+
|
|
14
|
+
configMapGenerator:
|
|
15
|
+
- name: nexst-api-config
|
|
16
|
+
envs:
|
|
17
|
+
- application.properties
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
2
|
+
kind: Kustomization
|
|
3
|
+
|
|
4
|
+
resources:
|
|
5
|
+
- ../../base
|
|
6
|
+
# Generate with scripts/seal-secret.sh, then uncomment.
|
|
7
|
+
# - sealedsecret.yaml
|
|
8
|
+
|
|
9
|
+
namespace: nexst
|
|
10
|
+
|
|
11
|
+
images:
|
|
12
|
+
- name: nexst-api
|
|
13
|
+
newName: ghcr.io/your-org/nexst-api
|
|
14
|
+
newTag: latest
|
|
15
|
+
- name: nexst-api-migrate
|
|
16
|
+
newName: ghcr.io/your-org/nexst-api-migrate
|
|
17
|
+
newTag: latest
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Staging overrides for base/application.properties.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
2
|
+
kind: Kustomization
|
|
3
|
+
|
|
4
|
+
resources:
|
|
5
|
+
- ../../base
|
|
6
|
+
|
|
7
|
+
namespace: nexst-staging
|
|
8
|
+
|
|
9
|
+
images:
|
|
10
|
+
- name: nexst-api
|
|
11
|
+
newName: ghcr.io/your-org/nexst-api
|
|
12
|
+
newTag: test
|
|
13
|
+
- name: nexst-api-migrate
|
|
14
|
+
newName: ghcr.io/your-org/nexst-api-migrate
|
|
15
|
+
newTag: test
|
|
16
|
+
|
|
17
|
+
configMapGenerator:
|
|
18
|
+
- name: nexst-api-config
|
|
19
|
+
behavior: merge
|
|
20
|
+
envs:
|
|
21
|
+
- application.properties
|