create-projx 1.0.0 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-projx",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Scaffold production-grade projects. Pick your stack (FastAPI, Fastify, React, Flutter), get a fully wired template with auth, database, CI/CD, and E2E tests.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,6 +13,8 @@
13
13
  "scripts": {
14
14
  "build": "tsup src/index.ts --format esm --target node18 --clean",
15
15
  "dev": "tsup src/index.ts --format esm --target node18 --watch",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
16
18
  "prepublishOnly": "npm run build"
17
19
  },
18
20
  "keywords": [
@@ -26,6 +28,15 @@
26
28
  "fullstack",
27
29
  "create"
28
30
  ],
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/ukanhaupa/projx.git",
34
+ "directory": "cli"
35
+ },
36
+ "homepage": "https://github.com/ukanhaupa/projx#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/ukanhaupa/projx/issues"
39
+ },
29
40
  "license": "MIT",
30
41
  "engines": {
31
42
  "node": ">=18"
@@ -39,6 +50,7 @@
39
50
  "eslint": "^10.2.0",
40
51
  "tsup": "^8",
41
52
  "typescript": "^5",
42
- "typescript-eslint": "^8.58.0"
53
+ "typescript-eslint": "^8.58.0",
54
+ "vitest": "^4.1.2"
43
55
  }
44
56
  }
@@ -30,15 +30,15 @@ Scaffolded with [Projx](https://github.com/ukanhaupa/projx).
30
30
  ## Getting Started
31
31
 
32
32
  ```bash
33
- make setup # Install all dependencies
34
- make run-dev # Start with Docker (dev mode)
33
+ ./setup.sh # Install all dependencies
34
+ docker compose -f docker-compose.dev.yml up # Start with Docker (dev mode)
35
35
  ```
36
36
  <% if (components.includes('fastapi')) { %>
37
37
 
38
38
  ### FastAPI
39
39
 
40
40
  ```bash
41
- cd fastapi && cp .env.example .env && uv sync && uv run main.py
41
+ cd <%= paths.fastapi %> && cp .env.example .env && uv sync && uv run main.py
42
42
  ```
43
43
 
44
44
  API docs at `http://localhost:7860/docs`.
@@ -48,7 +48,7 @@ API docs at `http://localhost:7860/docs`.
48
48
  ### Fastify
49
49
 
50
50
  ```bash
51
- cd fastify && cp .env.example .env && pnpm install && npx prisma migrate dev && pnpm dev
51
+ cd <%= paths.fastify %> && cp .env.example .env && pnpm install && npx prisma migrate dev && pnpm dev
52
52
  ```
53
53
 
54
54
  API docs at `http://localhost:3000/docs`.
@@ -58,7 +58,7 @@ API docs at `http://localhost:3000/docs`.
58
58
  ### Frontend
59
59
 
60
60
  ```bash
61
- cd frontend && cp .env.example .env && npm install && npm run dev
61
+ cd <%= paths.frontend %> && cp .env.example .env && npm install && npm run dev
62
62
  ```
63
63
  <% } %>
64
64
  <% if (components.includes('mobile')) { %>
@@ -66,17 +66,27 @@ cd frontend && cp .env.example .env && npm install && npm run dev
66
66
  ### Mobile
67
67
 
68
68
  ```bash
69
- cd mobile && cp .env.example .env && flutter pub get && flutter run
69
+ cd <%= paths.mobile %> && cp .env.example .env && flutter pub get && flutter run
70
70
  ```
71
71
  <% } %>
72
72
 
73
73
  ## Testing
74
74
 
75
75
  ```bash
76
- make test # Run all tests
77
- make test-coverage # Run with coverage
76
+ <% if (components.includes('fastapi')) { %>
77
+ cd <%= paths.fastapi %> && uv run pytest
78
+ <% } %>
79
+ <% if (components.includes('fastify')) { %>
80
+ cd <%= paths.fastify %> && pnpm test
81
+ <% } %>
82
+ <% if (components.includes('frontend')) { %>
83
+ cd <%= paths.frontend %> && npx vitest run
84
+ <% } %>
85
+ <% if (components.includes('mobile')) { %>
86
+ cd <%= paths.mobile %> && flutter test
87
+ <% } %>
78
88
  <% if (components.includes('e2e')) { %>
79
- make test-e2e # Playwright E2E tests
89
+ cd <%= paths.e2e %> && npx playwright test
80
90
  <% } %>
81
91
  ```
82
92
 
@@ -85,3 +95,7 @@ make test-e2e # Playwright E2E tests
85
95
  ```bash
86
96
  npx create-projx@latest update
87
97
  ```
98
+
99
+ ---
100
+
101
+ Scaffolded with [create-projx](https://github.com/ukanhaupa/projx)
@@ -13,7 +13,7 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  defaults:
15
15
  run:
16
- working-directory: fastapi
16
+ working-directory: <%= paths.fastapi %>
17
17
  steps:
18
18
  - uses: actions/checkout@v5
19
19
  - uses: astral-sh/setup-uv@v4
@@ -27,7 +27,7 @@ jobs:
27
27
  runs-on: ubuntu-latest
28
28
  defaults:
29
29
  run:
30
- working-directory: fastify
30
+ working-directory: <%= paths.fastify %>
31
31
  steps:
32
32
  - uses: actions/checkout@v5
33
33
  - uses: pnpm/action-setup@v4
@@ -37,7 +37,7 @@ jobs:
37
37
  with:
38
38
  node-version: 20
39
39
  cache: pnpm
40
- cache-dependency-path: fastify/pnpm-lock.yaml
40
+ cache-dependency-path: <%= paths.fastify %>/pnpm-lock.yaml
41
41
  - run: pnpm install --frozen-lockfile
42
42
  - run: npx prisma generate
43
43
  - run: npx prettier --check .
@@ -50,14 +50,14 @@ jobs:
50
50
  runs-on: ubuntu-latest
51
51
  defaults:
52
52
  run:
53
- working-directory: frontend
53
+ working-directory: <%= paths.frontend %>
54
54
  steps:
55
55
  - uses: actions/checkout@v5
56
56
  - uses: actions/setup-node@v5
57
57
  with:
58
58
  node-version: 22
59
59
  cache: npm
60
- cache-dependency-path: frontend/package-lock.json
60
+ cache-dependency-path: <%= paths.frontend %>/package-lock.json
61
61
  - run: npm ci
62
62
  - run: npx prettier --check .
63
63
  - run: npx eslint 'src/**/*.{ts,tsx}'
@@ -69,7 +69,7 @@ jobs:
69
69
  runs-on: ubuntu-latest
70
70
  defaults:
71
71
  run:
72
- working-directory: mobile
72
+ working-directory: <%= paths.mobile %>
73
73
  steps:
74
74
  - uses: actions/checkout@v5
75
75
  - uses: subosito/flutter-action@v2
@@ -86,14 +86,14 @@ jobs:
86
86
  runs-on: ubuntu-latest
87
87
  defaults:
88
88
  run:
89
- working-directory: e2e
89
+ working-directory: <%= paths.e2e %>
90
90
  steps:
91
91
  - uses: actions/checkout@v5
92
92
  - uses: actions/setup-node@v5
93
93
  with:
94
94
  node-version: 22
95
95
  cache: npm
96
- cache-dependency-path: e2e/package-lock.json
96
+ cache-dependency-path: <%= paths.e2e %>/package-lock.json
97
97
  - run: npm ci
98
98
  - run: npx prettier --check .
99
99
  - run: npx eslint '**/*.ts'
@@ -105,7 +105,7 @@ jobs:
105
105
  runs-on: ubuntu-latest
106
106
  defaults:
107
107
  run:
108
- working-directory: infra/stack
108
+ working-directory: <%= paths.infra %>/stack
109
109
  steps:
110
110
  - uses: actions/checkout@v5
111
111
  - uses: hashicorp/setup-terraform@v3
@@ -25,7 +25,7 @@ services:
25
25
  <% } %>
26
26
  <% if (components.includes('fastapi')) { %>
27
27
  migrate:
28
- build: ./fastapi
28
+ build: ./<%= paths.fastapi %>
29
29
  command: ['uv', 'run', 'migrate.py']
30
30
  environment:
31
31
  - SQLALCHEMY_DATABASE_URI=postgresql+asyncpg://dev:dev@db:5432/app
@@ -41,7 +41,7 @@ services:
41
41
  - app-network
42
42
 
43
43
  backend:
44
- build: ./fastapi
44
+ build: ./<%= paths.fastapi %>
45
45
  command:
46
46
  [
47
47
  'uv', 'run', 'uvicorn', 'src.app:app',
@@ -57,9 +57,9 @@ services:
57
57
  - JWT_SECRET=dev-secret-that-is-at-least-32-bytes-long
58
58
  - JWT_ALGORITHMS=HS256
59
59
  volumes:
60
- - ./fastapi/src:/app/src
61
- - ./fastapi/alembic.ini:/app/alembic.ini
62
- - ./fastapi/migrate.py:/app/migrate.py
60
+ - ./<%= paths.fastapi %>/src:/app/src
61
+ - ./<%= paths.fastapi %>/alembic.ini:/app/alembic.ini
62
+ - ./<%= paths.fastapi %>/migrate.py:/app/migrate.py
63
63
  depends_on:
64
64
  migrate:
65
65
  condition: service_completed_successfully
@@ -84,7 +84,7 @@ services:
84
84
  <% } %>
85
85
  <% if (components.includes('fastify')) { %>
86
86
  backend-fastify:
87
- build: ./fastify
87
+ build: ./<%= paths.fastify %>
88
88
  command: ['pnpm', 'dev']
89
89
  ports:
90
90
  - '3000:3000'
@@ -94,7 +94,7 @@ services:
94
94
  - JWT_PROVIDER=shared_secret
95
95
  - JWT_SECRET=dev-secret-that-is-at-least-32-bytes-long
96
96
  volumes:
97
- - ./fastify/src:/app/src
97
+ - ./<%= paths.fastify %>/src:/app/src
98
98
  depends_on:
99
99
  db:
100
100
  condition: service_healthy
@@ -128,7 +128,7 @@ services:
128
128
  - VITE_API_URL=http://localhost:3000
129
129
  <% } %>
130
130
  volumes:
131
- - ./frontend:/app
131
+ - ./<%= paths.frontend %>:/app
132
132
  - frontend_node_modules:/app/node_modules
133
133
  <% if (components.includes('fastapi')) { %>
134
134
  depends_on:
@@ -1,10 +1,10 @@
1
1
  services:
2
2
  <% if (components.includes('fastapi')) { %>
3
3
  migrate:
4
- build: ./fastapi
4
+ build: ./<%= paths.fastapi %>
5
5
  command: ['uv', 'run', 'migrate.py']
6
6
  env_file:
7
- - ./fastapi/.env
7
+ - ./<%= paths.fastapi %>/.env
8
8
  deploy:
9
9
  resources:
10
10
  limits:
@@ -14,11 +14,11 @@ services:
14
14
  - app-network
15
15
 
16
16
  backend:
17
- build: ./fastapi
17
+ build: ./<%= paths.fastapi %>
18
18
  expose:
19
19
  - '7860'
20
20
  env_file:
21
- - ./fastapi/.env
21
+ - ./<%= paths.fastapi %>/.env
22
22
  restart: unless-stopped
23
23
  depends_on:
24
24
  migrate:
@@ -52,11 +52,11 @@ services:
52
52
  <% } %>
53
53
  <% if (components.includes('fastify')) { %>
54
54
  backend-fastify:
55
- build: ./fastify
55
+ build: ./<%= paths.fastify %>
56
56
  expose:
57
57
  - '3000'
58
58
  env_file:
59
- - ./fastify/.env
59
+ - ./<%= paths.fastify %>/.env
60
60
  restart: unless-stopped
61
61
  healthcheck:
62
62
  test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3000/api/health']
@@ -77,7 +77,7 @@ services:
77
77
  <% if (components.includes('frontend')) { %>
78
78
  frontend:
79
79
  build:
80
- context: ./frontend
80
+ context: ./<%= paths.frontend %>
81
81
  args:
82
82
  VITE_API_URL: ''
83
83
  ports:
@@ -29,26 +29,26 @@ fi
29
29
  STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
30
30
  <% if (components.includes('fastapi')) { %>
31
31
 
32
- FASTAPI_PY=$(echo "$STAGED_FILES" | grep '^fastapi/.*\.py$' || true)
32
+ FASTAPI_PY=$(echo "$STAGED_FILES" | grep '^<%= paths.fastapi %>/.*\.py$' || true)
33
33
  if [ -n "$FASTAPI_PY" ]; then
34
- echo "Formatting & linting fastapi..."
35
- cd fastapi
36
- echo "$FASTAPI_PY" | sed 's|^fastapi/||' | xargs uv run ruff format
37
- echo "$FASTAPI_PY" | sed 's|^fastapi/||' | xargs uv run ruff check --fix
34
+ echo "Formatting & linting <%= paths.fastapi %>..."
35
+ cd <%= paths.fastapi %>
36
+ echo "$FASTAPI_PY" | sed 's|^<%= paths.fastapi %>/||' | xargs uv run ruff format
37
+ echo "$FASTAPI_PY" | sed 's|^<%= paths.fastapi %>/||' | xargs uv run ruff check --fix
38
38
  cd ..
39
39
  echo "$FASTAPI_PY" | xargs git add
40
40
  fi
41
41
  <% } %>
42
42
  <% if (components.includes('fastify')) { %>
43
43
 
44
- FASTIFY_TS=$(echo "$STAGED_FILES" | grep '^fastify/.*\.ts$' || true)
45
- FASTIFY_ALL=$(echo "$STAGED_FILES" | grep '^fastify/' || true)
44
+ FASTIFY_TS=$(echo "$STAGED_FILES" | grep '^<%= paths.fastify %>/.*\.ts$' || true)
45
+ FASTIFY_ALL=$(echo "$STAGED_FILES" | grep '^<%= paths.fastify %>/' || true)
46
46
  if [ -n "$FASTIFY_ALL" ]; then
47
- echo "Formatting fastify..."
48
- cd fastify
49
- echo "$FASTIFY_ALL" | sed 's|^fastify/||' | xargs npx prettier --write --ignore-unknown
47
+ echo "Formatting <%= paths.fastify %>..."
48
+ cd <%= paths.fastify %>
49
+ echo "$FASTIFY_ALL" | sed 's|^<%= paths.fastify %>/||' | xargs npx prettier --write --ignore-unknown
50
50
  if [ -n "$FASTIFY_TS" ]; then
51
- echo "$FASTIFY_TS" | sed 's|^fastify/||' | xargs npx eslint --fix
51
+ echo "$FASTIFY_TS" | sed 's|^<%= paths.fastify %>/||' | xargs npx eslint --fix
52
52
  npx tsc --noEmit
53
53
  fi
54
54
  cd ..
@@ -57,14 +57,14 @@ fi
57
57
  <% } %>
58
58
  <% if (components.includes('frontend')) { %>
59
59
 
60
- FRONTEND_TS=$(echo "$STAGED_FILES" | grep '^frontend/.*\.tsx\?$' || true)
61
- FRONTEND_ALL=$(echo "$STAGED_FILES" | grep '^frontend/' || true)
60
+ FRONTEND_TS=$(echo "$STAGED_FILES" | grep '^<%= paths.frontend %>/.*\.tsx\?$' || true)
61
+ FRONTEND_ALL=$(echo "$STAGED_FILES" | grep '^<%= paths.frontend %>/' || true)
62
62
  if [ -n "$FRONTEND_ALL" ]; then
63
- echo "Formatting frontend..."
64
- cd frontend
65
- echo "$FRONTEND_ALL" | sed 's|^frontend/||' | xargs npx prettier --write --ignore-unknown
63
+ echo "Formatting <%= paths.frontend %>..."
64
+ cd <%= paths.frontend %>
65
+ echo "$FRONTEND_ALL" | sed 's|^<%= paths.frontend %>/||' | xargs npx prettier --write --ignore-unknown
66
66
  if [ -n "$FRONTEND_TS" ]; then
67
- echo "$FRONTEND_TS" | sed 's|^frontend/||' | xargs npx eslint --fix
67
+ echo "$FRONTEND_TS" | sed 's|^<%= paths.frontend %>/||' | xargs npx eslint --fix
68
68
  npx tsc --noEmit
69
69
  fi
70
70
  cd ..
@@ -73,14 +73,14 @@ fi
73
73
  <% } %>
74
74
  <% if (components.includes('e2e')) { %>
75
75
 
76
- E2E_TS=$(echo "$STAGED_FILES" | grep '^e2e/.*\.ts$' || true)
77
- E2E_ALL=$(echo "$STAGED_FILES" | grep '^e2e/' || true)
76
+ E2E_TS=$(echo "$STAGED_FILES" | grep '^<%= paths.e2e %>/.*\.ts$' || true)
77
+ E2E_ALL=$(echo "$STAGED_FILES" | grep '^<%= paths.e2e %>/' || true)
78
78
  if [ -n "$E2E_ALL" ]; then
79
- echo "Formatting e2e..."
80
- cd e2e
81
- echo "$E2E_ALL" | sed 's|^e2e/||' | xargs npx prettier --write --ignore-unknown
79
+ echo "Formatting <%= paths.e2e %>..."
80
+ cd <%= paths.e2e %>
81
+ echo "$E2E_ALL" | sed 's|^<%= paths.e2e %>/||' | xargs npx prettier --write --ignore-unknown
82
82
  if [ -n "$E2E_TS" ]; then
83
- echo "$E2E_TS" | sed 's|^e2e/||' | xargs npx eslint --fix
83
+ echo "$E2E_TS" | sed 's|^<%= paths.e2e %>/||' | xargs npx eslint --fix
84
84
  npx tsc --noEmit
85
85
  fi
86
86
  cd ..
@@ -89,12 +89,12 @@ fi
89
89
  <% } %>
90
90
  <% if (components.includes('mobile')) { %>
91
91
 
92
- MOBILE_DART=$(echo "$STAGED_FILES" | grep '^mobile/.*\.dart$' || true)
92
+ MOBILE_DART=$(echo "$STAGED_FILES" | grep '^<%= paths.mobile %>/.*\.dart$' || true)
93
93
  if [ -n "$MOBILE_DART" ]; then
94
94
  if command -v dart &> /dev/null; then
95
- echo "Formatting mobile..."
96
- cd mobile
97
- echo "$MOBILE_DART" | sed 's|^mobile/||' | xargs dart format
95
+ echo "Formatting <%= paths.mobile %>..."
96
+ cd <%= paths.mobile %>
97
+ echo "$MOBILE_DART" | sed 's|^<%= paths.mobile %>/||' | xargs dart format
98
98
  if command -v flutter &> /dev/null; then
99
99
  dart analyze --fatal-infos
100
100
  fi
@@ -107,12 +107,12 @@ fi
107
107
  <% } %>
108
108
  <% if (components.includes('infra')) { %>
109
109
 
110
- INFRA_TF=$(echo "$STAGED_FILES" | grep '^infra/.*\.tf$' || true)
110
+ INFRA_TF=$(echo "$STAGED_FILES" | grep '^<%= paths.infra %>/.*\.tf$' || true)
111
111
  if [ -n "$INFRA_TF" ]; then
112
112
  if command -v terraform &> /dev/null; then
113
- echo "Formatting infra..."
114
- cd infra/stack
115
- echo "$INFRA_TF" | sed 's|^infra/stack/||' | xargs terraform fmt
113
+ echo "Formatting <%= paths.infra %>..."
114
+ cd <%= paths.infra %>/stack
115
+ echo "$INFRA_TF" | sed 's|^<%= paths.infra %>/stack/||' | xargs terraform fmt
116
116
  cd ../..
117
117
  echo "$INFRA_TF" | xargs git add
118
118
  else
@@ -5,28 +5,28 @@ git config core.hooksPath .githooks
5
5
  echo "Git hooks configured."
6
6
  <% if (components.includes('fastapi')) { %>
7
7
 
8
- cd fastapi && uv sync --all-extras && cd ..
8
+ cd <%= paths.fastapi %> && uv sync --all-extras && cd ..
9
9
  echo "FastAPI dependencies installed."
10
10
  <% } %>
11
11
  <% if (components.includes('fastify')) { %>
12
12
 
13
- cd fastify && pnpm install --frozen-lockfile && cd ..
13
+ cd <%= paths.fastify %> && pnpm install --frozen-lockfile && cd ..
14
14
  echo "Fastify dependencies installed."
15
15
  <% } %>
16
16
  <% if (components.includes('frontend')) { %>
17
17
 
18
- cd frontend && npm ci && cd ..
18
+ cd <%= paths.frontend %> && npm ci && cd ..
19
19
  echo "Frontend dependencies installed."
20
20
  <% } %>
21
21
  <% if (components.includes('e2e')) { %>
22
22
 
23
- cd e2e && npm ci && cd ..
23
+ cd <%= paths.e2e %> && npm ci && cd ..
24
24
  echo "E2E dependencies installed."
25
25
  <% } %>
26
26
  <% if (components.includes('mobile')) { %>
27
27
 
28
28
  if command -v flutter &>/dev/null; then
29
- cd mobile && flutter pub get && cd ..
29
+ cd <%= paths.mobile %> && flutter pub get && cd ..
30
30
  echo "Flutter dependencies installed."
31
31
  else
32
32
  echo "Flutter SDK not installed — skipping mobile."
@@ -34,4 +34,4 @@ fi
34
34
  <% } %>
35
35
 
36
36
  echo ""
37
- echo "Done. Run 'make run-dev' to start, or 'make help' for all commands."
37
+ echo "Done. Run 'docker compose -f docker-compose.dev.yml up' to start."