create-projx 0.1.1
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 +1064 -0
- package/package.json +44 -0
- package/src/templates/Makefile.ejs +286 -0
- package/src/templates/README.md.ejs +87 -0
- package/src/templates/ci.yml.ejs +117 -0
- package/src/templates/docker-compose.dev.yml.ejs +168 -0
- package/src/templates/docker-compose.yml.ejs +146 -0
- package/src/templates/pre-commit.ejs +122 -0
- package/src/templates/setup.sh.ejs +37 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
services:
|
|
2
|
+
<% if (components.includes('fastapi')) { %>
|
|
3
|
+
migrate:
|
|
4
|
+
build: ./fastapi
|
|
5
|
+
command: ['uv', 'run', 'migrate.py']
|
|
6
|
+
env_file:
|
|
7
|
+
- ./fastapi/.env
|
|
8
|
+
deploy:
|
|
9
|
+
resources:
|
|
10
|
+
limits:
|
|
11
|
+
memory: 256M
|
|
12
|
+
cpus: '0.5'
|
|
13
|
+
networks:
|
|
14
|
+
- app-network
|
|
15
|
+
|
|
16
|
+
backend:
|
|
17
|
+
build: ./fastapi
|
|
18
|
+
expose:
|
|
19
|
+
- '7860'
|
|
20
|
+
env_file:
|
|
21
|
+
- ./fastapi/.env
|
|
22
|
+
restart: unless-stopped
|
|
23
|
+
depends_on:
|
|
24
|
+
migrate:
|
|
25
|
+
condition: service_completed_successfully
|
|
26
|
+
healthcheck:
|
|
27
|
+
test:
|
|
28
|
+
[
|
|
29
|
+
'CMD',
|
|
30
|
+
'python',
|
|
31
|
+
'-c',
|
|
32
|
+
"import urllib.request; urllib.request.urlopen('http://localhost:7860/api/health')",
|
|
33
|
+
]
|
|
34
|
+
interval: 30s
|
|
35
|
+
timeout: 10s
|
|
36
|
+
retries: 3
|
|
37
|
+
start_period: 15s
|
|
38
|
+
deploy:
|
|
39
|
+
resources:
|
|
40
|
+
limits:
|
|
41
|
+
memory: 512M
|
|
42
|
+
cpus: '1.0'
|
|
43
|
+
reservations:
|
|
44
|
+
memory: 256M
|
|
45
|
+
security_opt:
|
|
46
|
+
- no-new-privileges:true
|
|
47
|
+
read_only: true
|
|
48
|
+
tmpfs:
|
|
49
|
+
- /tmp
|
|
50
|
+
networks:
|
|
51
|
+
- app-network
|
|
52
|
+
<% } %>
|
|
53
|
+
<% if (components.includes('fastify')) { %>
|
|
54
|
+
backend-fastify:
|
|
55
|
+
build: ./fastify
|
|
56
|
+
expose:
|
|
57
|
+
- '3000'
|
|
58
|
+
env_file:
|
|
59
|
+
- ./fastify/.env
|
|
60
|
+
restart: unless-stopped
|
|
61
|
+
healthcheck:
|
|
62
|
+
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3000/api/health']
|
|
63
|
+
interval: 30s
|
|
64
|
+
timeout: 10s
|
|
65
|
+
retries: 3
|
|
66
|
+
start_period: 15s
|
|
67
|
+
deploy:
|
|
68
|
+
resources:
|
|
69
|
+
limits:
|
|
70
|
+
memory: 512M
|
|
71
|
+
cpus: '1.0'
|
|
72
|
+
security_opt:
|
|
73
|
+
- no-new-privileges:true
|
|
74
|
+
networks:
|
|
75
|
+
- app-network
|
|
76
|
+
<% } %>
|
|
77
|
+
<% if (components.includes('frontend')) { %>
|
|
78
|
+
frontend:
|
|
79
|
+
build:
|
|
80
|
+
context: ./frontend
|
|
81
|
+
args:
|
|
82
|
+
VITE_API_URL: ''
|
|
83
|
+
ports:
|
|
84
|
+
- '80:80'
|
|
85
|
+
- '443:443'
|
|
86
|
+
environment:
|
|
87
|
+
- DOMAIN=${DOMAIN:-localhost}
|
|
88
|
+
volumes:
|
|
89
|
+
- letsencrypt:/etc/letsencrypt
|
|
90
|
+
- certbot-www:/var/www/certbot
|
|
91
|
+
<% if (components.includes('fastapi')) { %>
|
|
92
|
+
depends_on:
|
|
93
|
+
backend:
|
|
94
|
+
condition: service_healthy
|
|
95
|
+
<% } %>
|
|
96
|
+
<% if (components.includes('fastify') && !components.includes('fastapi')) { %>
|
|
97
|
+
depends_on:
|
|
98
|
+
backend-fastify:
|
|
99
|
+
condition: service_healthy
|
|
100
|
+
<% } %>
|
|
101
|
+
restart: unless-stopped
|
|
102
|
+
healthcheck:
|
|
103
|
+
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:80/']
|
|
104
|
+
interval: 30s
|
|
105
|
+
timeout: 5s
|
|
106
|
+
retries: 3
|
|
107
|
+
start_period: 10s
|
|
108
|
+
deploy:
|
|
109
|
+
resources:
|
|
110
|
+
limits:
|
|
111
|
+
memory: 128M
|
|
112
|
+
cpus: '0.5'
|
|
113
|
+
security_opt:
|
|
114
|
+
- no-new-privileges:true
|
|
115
|
+
networks:
|
|
116
|
+
- app-network
|
|
117
|
+
|
|
118
|
+
certbot:
|
|
119
|
+
image: certbot/certbot:latest
|
|
120
|
+
volumes:
|
|
121
|
+
- letsencrypt:/etc/letsencrypt
|
|
122
|
+
- certbot-www:/var/www/certbot
|
|
123
|
+
entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew --quiet; sleep 12h & wait $${!}; done"
|
|
124
|
+
restart: unless-stopped
|
|
125
|
+
depends_on:
|
|
126
|
+
frontend:
|
|
127
|
+
condition: service_healthy
|
|
128
|
+
profiles:
|
|
129
|
+
- ssl
|
|
130
|
+
deploy:
|
|
131
|
+
resources:
|
|
132
|
+
limits:
|
|
133
|
+
memory: 64M
|
|
134
|
+
cpus: '0.25'
|
|
135
|
+
networks:
|
|
136
|
+
- app-network
|
|
137
|
+
<% } %>
|
|
138
|
+
<% if (components.includes('frontend')) { %>
|
|
139
|
+
volumes:
|
|
140
|
+
letsencrypt:
|
|
141
|
+
certbot-www:
|
|
142
|
+
<% } %>
|
|
143
|
+
|
|
144
|
+
networks:
|
|
145
|
+
app-network:
|
|
146
|
+
driver: bridge
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# ── Secret detection ──────────────────────────────────────────────
|
|
5
|
+
STAGED_DIFF="$(git diff --cached --diff-filter=ACMR)"
|
|
6
|
+
|
|
7
|
+
if echo "$STAGED_DIFF" | grep -qE '(AKIA|ASIA)[A-Z0-9]{16}'; then
|
|
8
|
+
echo "ERROR: Possible AWS access key detected in staged changes."
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
if echo "$STAGED_DIFF" | grep -qE '(password|secret|token)\s*[:=]\s*["\x27][^"'\'']{8,}' 2>/dev/null; then
|
|
13
|
+
REAL_SECRETS="$(echo "$STAGED_DIFF" | grep -E '(password|secret|token)\s*[:=]\s*["\x27][^"'\'']{8,}' | grep -vE '(test-secret|dev-secret|example|placeholder|your-|changeme|CHANGE_ME)' || true)"
|
|
14
|
+
if [ -n "$REAL_SECRETS" ]; then
|
|
15
|
+
echo "WARNING: Possible secret detected in staged changes:"
|
|
16
|
+
echo "$REAL_SECRETS" | head -5
|
|
17
|
+
echo "If intentional, commit with: git commit --no-verify"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
STAGED_ENV_FILES="$(git diff --cached --name-only --diff-filter=ACMR | grep -E '^(\.env$|.*\/\.env$|.*\.env\.(prod|staging|dev)$)' || true)"
|
|
23
|
+
if [ -n "$STAGED_ENV_FILES" ]; then
|
|
24
|
+
echo "ERROR: .env file(s) staged for commit:"
|
|
25
|
+
echo "$STAGED_ENV_FILES"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
|
|
30
|
+
<% if (components.includes('fastapi')) { %>
|
|
31
|
+
|
|
32
|
+
FASTAPI_PY=$(echo "$STAGED_FILES" | grep '^fastapi/.*\.py$' || true)
|
|
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
|
|
38
|
+
cd ..
|
|
39
|
+
echo "$FASTAPI_PY" | xargs git add
|
|
40
|
+
fi
|
|
41
|
+
<% } %>
|
|
42
|
+
<% if (components.includes('fastify')) { %>
|
|
43
|
+
|
|
44
|
+
FASTIFY_TS=$(echo "$STAGED_FILES" | grep '^fastify/.*\.ts$' || true)
|
|
45
|
+
FASTIFY_ALL=$(echo "$STAGED_FILES" | grep '^fastify/' || true)
|
|
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
|
|
50
|
+
if [ -n "$FASTIFY_TS" ]; then
|
|
51
|
+
echo "$FASTIFY_TS" | sed 's|^fastify/||' | xargs npx eslint --fix
|
|
52
|
+
npx tsc --noEmit
|
|
53
|
+
fi
|
|
54
|
+
cd ..
|
|
55
|
+
echo "$FASTIFY_ALL" | xargs git add
|
|
56
|
+
fi
|
|
57
|
+
<% } %>
|
|
58
|
+
<% if (components.includes('frontend')) { %>
|
|
59
|
+
|
|
60
|
+
FRONTEND_TS=$(echo "$STAGED_FILES" | grep '^frontend/.*\.tsx\?$' || true)
|
|
61
|
+
FRONTEND_ALL=$(echo "$STAGED_FILES" | grep '^frontend/' || true)
|
|
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
|
|
66
|
+
if [ -n "$FRONTEND_TS" ]; then
|
|
67
|
+
echo "$FRONTEND_TS" | sed 's|^frontend/||' | xargs npx eslint --fix
|
|
68
|
+
npx tsc --noEmit
|
|
69
|
+
fi
|
|
70
|
+
cd ..
|
|
71
|
+
echo "$FRONTEND_ALL" | xargs git add
|
|
72
|
+
fi
|
|
73
|
+
<% } %>
|
|
74
|
+
<% if (components.includes('e2e')) { %>
|
|
75
|
+
|
|
76
|
+
E2E_TS=$(echo "$STAGED_FILES" | grep '^e2e/.*\.ts$' || true)
|
|
77
|
+
E2E_ALL=$(echo "$STAGED_FILES" | grep '^e2e/' || true)
|
|
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
|
|
82
|
+
if [ -n "$E2E_TS" ]; then
|
|
83
|
+
echo "$E2E_TS" | sed 's|^e2e/||' | xargs npx eslint --fix
|
|
84
|
+
npx tsc --noEmit
|
|
85
|
+
fi
|
|
86
|
+
cd ..
|
|
87
|
+
echo "$E2E_ALL" | xargs git add
|
|
88
|
+
fi
|
|
89
|
+
<% } %>
|
|
90
|
+
<% if (components.includes('mobile')) { %>
|
|
91
|
+
|
|
92
|
+
MOBILE_DART=$(echo "$STAGED_FILES" | grep '^mobile/.*\.dart$' || true)
|
|
93
|
+
if [ -n "$MOBILE_DART" ]; then
|
|
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
|
|
98
|
+
if command -v flutter &> /dev/null; then
|
|
99
|
+
dart analyze --fatal-infos
|
|
100
|
+
fi
|
|
101
|
+
cd ..
|
|
102
|
+
echo "$MOBILE_DART" | xargs git add
|
|
103
|
+
else
|
|
104
|
+
echo "Skipping mobile lint (dart not installed)"
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
<% } %>
|
|
108
|
+
<% if (components.includes('infra')) { %>
|
|
109
|
+
|
|
110
|
+
INFRA_TF=$(echo "$STAGED_FILES" | grep '^infra/.*\.tf$' || true)
|
|
111
|
+
if [ -n "$INFRA_TF" ]; then
|
|
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
|
|
116
|
+
cd ../..
|
|
117
|
+
echo "$INFRA_TF" | xargs git add
|
|
118
|
+
else
|
|
119
|
+
echo "Skipping infra lint (terraform not installed)"
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
<% } %>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
git config core.hooksPath .githooks
|
|
5
|
+
echo "Git hooks configured."
|
|
6
|
+
<% if (components.includes('fastapi')) { %>
|
|
7
|
+
|
|
8
|
+
cd fastapi && uv sync --all-extras && cd ..
|
|
9
|
+
echo "FastAPI dependencies installed."
|
|
10
|
+
<% } %>
|
|
11
|
+
<% if (components.includes('fastify')) { %>
|
|
12
|
+
|
|
13
|
+
cd fastify && pnpm install --frozen-lockfile && cd ..
|
|
14
|
+
echo "Fastify dependencies installed."
|
|
15
|
+
<% } %>
|
|
16
|
+
<% if (components.includes('frontend')) { %>
|
|
17
|
+
|
|
18
|
+
cd frontend && npm ci && cd ..
|
|
19
|
+
echo "Frontend dependencies installed."
|
|
20
|
+
<% } %>
|
|
21
|
+
<% if (components.includes('e2e')) { %>
|
|
22
|
+
|
|
23
|
+
cd e2e && npm ci && cd ..
|
|
24
|
+
echo "E2E dependencies installed."
|
|
25
|
+
<% } %>
|
|
26
|
+
<% if (components.includes('mobile')) { %>
|
|
27
|
+
|
|
28
|
+
if command -v flutter &>/dev/null; then
|
|
29
|
+
cd mobile && flutter pub get && cd ..
|
|
30
|
+
echo "Flutter dependencies installed."
|
|
31
|
+
else
|
|
32
|
+
echo "Flutter SDK not installed — skipping mobile."
|
|
33
|
+
fi
|
|
34
|
+
<% } %>
|
|
35
|
+
|
|
36
|
+
echo ""
|
|
37
|
+
echo "Done. Run 'make run-dev' to start, or 'make help' for all commands."
|