create-tigra 2.8.0 → 3.0.2

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 (53) hide show
  1. package/README.md +10 -3
  2. package/bin/create-tigra.js +77 -37
  3. package/package.json +5 -5
  4. package/template/_claude/commands/create-server.md +8 -2
  5. package/template/_claude/rules/client/01-project-structure.md +12 -0
  6. package/template/_claude/rules/client/03-data-and-state.md +1 -1
  7. package/template/_claude/rules/client/04-design-system.md +23 -0
  8. package/template/_claude/rules/client/07-deployment.md +99 -0
  9. package/template/_claude/rules/client/08-lockfile-cross-platform.md +79 -0
  10. package/template/_claude/rules/client/core.md +1 -0
  11. package/template/_claude/rules/global/core.md +20 -1
  12. package/template/_claude/rules/global/investigation-before-conclusions.md +57 -0
  13. package/template/_claude/rules/server/core.md +2 -0
  14. package/template/_claude/rules/server/deployment.md +78 -0
  15. package/template/client/next.config.ts +12 -2
  16. package/template/client/package-lock.json +12345 -0
  17. package/template/client/package.json +3 -2
  18. package/template/client/src/components/common/SafeImage.tsx +2 -1
  19. package/template/client/src/lib/api/axios.config.ts +19 -4
  20. package/template/client/src/middleware.ts +7 -0
  21. package/template/gitignore +1 -0
  22. package/template/server/.env.example +248 -194
  23. package/template/server/.env.example.production +221 -168
  24. package/template/server/Dockerfile +29 -5
  25. package/template/server/docker-compose.yml +32 -4
  26. package/template/server/package-lock.json +6544 -6823
  27. package/template/server/package.json +76 -75
  28. package/template/server/prisma/seed.ts +20 -4
  29. package/template/server/src/app.ts +316 -271
  30. package/template/server/src/config/env.ts +150 -99
  31. package/template/server/src/config/rate-limit.config.ts +16 -0
  32. package/template/server/src/libs/__tests__/auth-path.test.ts +24 -0
  33. package/template/server/src/libs/__tests__/client-ip.test.ts +121 -0
  34. package/template/server/src/libs/__tests__/http.test.ts +23 -9
  35. package/template/server/src/libs/__tests__/ip-block.test.ts +62 -0
  36. package/template/server/src/libs/__tests__/origin-check.test.ts +53 -0
  37. package/template/server/src/libs/__tests__/url-safety.test.ts +80 -0
  38. package/template/server/src/libs/auth-path.ts +14 -0
  39. package/template/server/src/libs/auth.ts +6 -16
  40. package/template/server/src/libs/client-ip.ts +77 -0
  41. package/template/server/src/libs/cookies.ts +1 -1
  42. package/template/server/src/libs/duration.ts +30 -0
  43. package/template/server/src/libs/ip-block.ts +220 -206
  44. package/template/server/src/libs/origin-check.ts +38 -0
  45. package/template/server/src/libs/query-counter.ts +59 -0
  46. package/template/server/src/libs/redis.ts +1 -1
  47. package/template/server/src/libs/url-safety.ts +121 -0
  48. package/template/server/src/modules/auth/__tests__/auth.service.test.ts +274 -44
  49. package/template/server/src/modules/auth/auth.controller.ts +128 -127
  50. package/template/server/src/modules/auth/auth.repo.ts +2 -0
  51. package/template/server/src/modules/auth/auth.service.ts +103 -12
  52. package/template/server/src/test/setup.ts +22 -2
  53. package/template/server/vitest.config.ts +43 -43
@@ -1,75 +1,76 @@
1
- {
2
- "name": "{{PROJECT_NAME}}-server",
3
- "version": "1.0.0",
4
- "type": "module",
5
- "description": "",
6
- "main": "dist/server.js",
7
- "scripts": {
8
- "dev": "tsx watch src/server.ts",
9
- "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
10
- "start": "node dist/server.js",
11
- "test": "vitest run",
12
- "test:watch": "vitest",
13
- "test:ui": "vitest --ui",
14
- "test:coverage": "vitest run --coverage",
15
- "prisma:generate": "prisma generate",
16
- "prisma:migrate:dev": "prisma migrate dev",
17
- "prisma:migrate:deploy": "prisma migrate deploy",
18
- "prisma:reset": "prisma migrate reset",
19
- "prisma:seed": "prisma db seed",
20
- "prisma:studio": "prisma studio",
21
- "lint": "eslint src/",
22
- "typecheck": "tsc --noEmit",
23
- "redis:flush": "tsx scripts/flush-redis.ts",
24
- "docker:up": "docker compose up -d",
25
- "docker:down": "docker compose down",
26
- "docker:logs": "docker compose logs -f",
27
- "generate:env": "node -e \"import('fs').then(f=>{if(f.existsSync('.env'))console.log('.env already exists, skipping');else{f.copyFileSync('.env.example','.env');console.log('.env created from .env.example')}})\""
28
- },
29
- "prisma": {
30
- "seed": "tsx prisma/seed.ts"
31
- },
32
- "dependencies": {
33
- "@fastify/cookie": "^11.0.2",
34
- "@fastify/cors": "^11.2.0",
35
- "@fastify/helmet": "^13.0.2",
36
- "@fastify/jwt": "^10.0.0",
37
- "@fastify/multipart": "^9.0.2",
38
- "@fastify/rate-limit": "^10.3.0",
39
- "@fastify/static": "^9.0.0",
40
- "@prisma/client": "^6.19.2",
41
- "argon2": "^0.44.0",
42
- "axios": "^1.7.9",
43
- "dotenv": "^16.4.7",
44
- "fastify": "^5.7.4",
45
- "fastify-type-provider-zod": "^6.1.0",
46
- "ioredis": "^5.9.2",
47
- "pino": "^10.3.1",
48
- "pino-pretty": "^13.1.3",
49
- "resend": "^6.9.4",
50
- "sharp": "^0.33.5",
51
- "uuid": "^10.0.0",
52
- "zod": "^4.3.6"
53
- },
54
- "overrides": {
55
- "bn.js": ">=5.2.3",
56
- "flatted": ">=3.4.2",
57
- "@typescript-eslint/typescript-estree": {
58
- "minimatch": ">=10.2.1"
59
- }
60
- },
61
- "devDependencies": {
62
- "@eslint/js": "^10.0.1",
63
- "@types/node": "^20.17.10",
64
- "@types/uuid": "^10.0.0",
65
- "@vitest/coverage-v8": "^4.0.18",
66
- "@vitest/ui": "^4.0.18",
67
- "eslint": "^10.0.1",
68
- "prisma": "^6.19.2",
69
- "tsc-alias": "^1.8.16",
70
- "tsx": "^4.21.0",
71
- "typescript": "^5.9.3",
72
- "typescript-eslint": "^8.55.0",
73
- "vitest": "^4.0.18"
74
- }
75
- }
1
+ {
2
+ "name": "{{PROJECT_NAME}}-server",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "",
6
+ "main": "dist/server.js",
7
+ "scripts": {
8
+ "dev": "tsx watch src/server.ts",
9
+ "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
10
+ "start": "node dist/server.js",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "test:ui": "vitest --ui",
14
+ "test:coverage": "vitest run --coverage",
15
+ "prisma:generate": "prisma generate",
16
+ "prisma:migrate:dev": "prisma migrate dev",
17
+ "prisma:migrate:deploy": "prisma migrate deploy",
18
+ "prisma:reset": "prisma migrate reset",
19
+ "prisma:seed": "prisma db seed",
20
+ "prisma:studio": "prisma studio",
21
+ "lint": "eslint src/",
22
+ "typecheck": "tsc --noEmit",
23
+ "redis:flush": "tsx scripts/flush-redis.ts",
24
+ "docker:up": "docker compose up -d",
25
+ "docker:tools": "docker compose --profile tools up -d",
26
+ "docker:down": "docker compose --profile tools down",
27
+ "docker:logs": "docker compose logs -f",
28
+ "generate:env": "node -e \"import('fs').then(f=>{if(f.existsSync('.env'))console.log('.env already exists, skipping');else{f.copyFileSync('.env.example','.env');console.log('.env created from .env.example')}})\""
29
+ },
30
+ "prisma": {
31
+ "seed": "tsx prisma/seed.ts"
32
+ },
33
+ "dependencies": {
34
+ "@fastify/cookie": "^11.0.2",
35
+ "@fastify/cors": "^11.2.0",
36
+ "@fastify/helmet": "^13.0.2",
37
+ "@fastify/jwt": "^10.1.0",
38
+ "@fastify/multipart": "^9.0.2",
39
+ "@fastify/rate-limit": "^10.3.0",
40
+ "@fastify/static": "^9.1.3",
41
+ "@prisma/client": "^6.19.3",
42
+ "argon2": "^0.44.0",
43
+ "axios": "^1.17.0",
44
+ "dotenv": "^16.4.7",
45
+ "fastify": "^5.8.5",
46
+ "fastify-type-provider-zod": "^6.1.0",
47
+ "ioredis": "^5.9.2",
48
+ "pino": "^10.3.1",
49
+ "pino-pretty": "^13.1.3",
50
+ "resend": "^6.9.4",
51
+ "sharp": "^0.33.5",
52
+ "uuid": "^10.0.0",
53
+ "zod": "^4.3.6"
54
+ },
55
+ "overrides": {
56
+ "bn.js": ">=5.2.3",
57
+ "flatted": ">=3.4.2",
58
+ "@typescript-eslint/typescript-estree": {
59
+ "minimatch": ">=10.2.1"
60
+ }
61
+ },
62
+ "devDependencies": {
63
+ "@eslint/js": "^10.0.1",
64
+ "@types/node": "^20.17.10",
65
+ "@types/uuid": "^10.0.0",
66
+ "@vitest/coverage-v8": "^4.0.18",
67
+ "@vitest/ui": "^4.0.18",
68
+ "eslint": "^10.0.1",
69
+ "prisma": "^6.19.3",
70
+ "tsc-alias": "^1.8.16",
71
+ "tsx": "^4.21.0",
72
+ "typescript": "^5.9.3",
73
+ "typescript-eslint": "^8.55.0",
74
+ "vitest": "^4.0.18"
75
+ }
76
+ }
@@ -3,9 +3,27 @@ import argon2 from 'argon2';
3
3
 
4
4
  const prisma = new PrismaClient();
5
5
 
6
+ // Well-known dev-only fallbacks. NEVER used in production — the guard in
7
+ // main() refuses to seed when NODE_ENV=production, and even outside production
8
+ // you can override via SEED_ADMIN_PASSWORD / SEED_USER_PASSWORD.
9
+ const DEV_ADMIN_PASSWORD = 'Admin123!';
10
+ const DEV_USER_PASSWORD = 'User123!';
11
+
6
12
  async function main(): Promise<void> {
7
- const adminPassword = await argon2.hash('Admin123!');
8
- const userPassword = await argon2.hash('User123!');
13
+ // Refuse to seed production: this script creates a well-known admin account
14
+ // (admin@example.com). On a production database that is a backdoor, not a
15
+ // convenience. Seed data belongs to dev/test environments only.
16
+ if (process.env.NODE_ENV === 'production') {
17
+ console.error(
18
+ 'Refusing to seed: NODE_ENV is "production".\n' +
19
+ 'The seed script creates well-known demo accounts (admin@example.com) and must never run against a production database.\n' +
20
+ 'If you really need initial data in production, create it manually or write a dedicated, audited provisioning script.',
21
+ );
22
+ process.exit(1);
23
+ }
24
+
25
+ const adminPassword = await argon2.hash(process.env.SEED_ADMIN_PASSWORD || DEV_ADMIN_PASSWORD);
26
+ const userPassword = await argon2.hash(process.env.SEED_USER_PASSWORD || DEV_USER_PASSWORD);
9
27
 
10
28
  const admin = await prisma.user.upsert({
11
29
  where: { email: 'admin@example.com' },
@@ -31,13 +49,11 @@ async function main(): Promise<void> {
31
49
  },
32
50
  });
33
51
 
34
- // eslint-disable-next-line no-console
35
52
  console.log('Seeded users:', { admin: admin.email, user: user.email });
36
53
  }
37
54
 
38
55
  main()
39
56
  .catch((error) => {
40
- // eslint-disable-next-line no-console
41
57
  console.error('Seed failed:', error);
42
58
  process.exit(1);
43
59
  })