create-projx 0.1.1 → 1.0.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/README.md +144 -0
- package/dist/index.js +6 -12
- package/package.json +1 -1
- package/src/templates/README.md.ejs +15 -5
- package/src/templates/setup.sh.ejs +1 -1
- package/src/templates/Makefile.ejs +0 -286
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Projx
|
|
2
|
+
|
|
3
|
+
Production-grade project scaffolder. Pick your stack, get a fully wired project with auth, database, CI/CD, and E2E tests — ready to deploy.
|
|
4
|
+
|
|
5
|
+
## The Problem
|
|
6
|
+
|
|
7
|
+
Starting a new project means days of boilerplate: setting up auth, database migrations, CI/CD pipelines, Docker configs, linting, pre-commit hooks, test infrastructure. Every team does this from scratch, every time.
|
|
8
|
+
|
|
9
|
+
## The Solution
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx create-projx my-app
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Pick the components you need. Get a production-ready project in seconds.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Interactive — pick your stack
|
|
21
|
+
npx create-projx my-app
|
|
22
|
+
|
|
23
|
+
# Non-interactive — specify components
|
|
24
|
+
npx create-projx my-app --components fastify,frontend,e2e
|
|
25
|
+
|
|
26
|
+
# Accept defaults (Fastify + Frontend + E2E)
|
|
27
|
+
npx create-projx my-app -y
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Components
|
|
31
|
+
|
|
32
|
+
| Component | Stack | What You Get |
|
|
33
|
+
| --------- | ----- | ------------ |
|
|
34
|
+
| `fastapi` | Python, SQLAlchemy, Alembic | Auto-entity CRUD, JWT auth, migrations, OpenAPI docs |
|
|
35
|
+
| `fastify` | Node.js, Prisma, TypeBox | Auto-entity CRUD, JWT auth, typed schemas, OpenAPI docs |
|
|
36
|
+
| `frontend` | React 19, TypeScript, Vite | Auto-entity UI from metadata, design tokens, light/dark mode |
|
|
37
|
+
| `mobile` | Flutter, Riverpod, GoRouter | Auto-entity screens, offline-first with Isar, biometric auth |
|
|
38
|
+
| `e2e` | Playwright | Page object model, auth fixtures, accessibility scans |
|
|
39
|
+
| `infra` | Terraform, AWS | EKS, RDS, VPC, ALB, CodePipeline, multi-environment |
|
|
40
|
+
|
|
41
|
+
All optional. Pick any combination.
|
|
42
|
+
|
|
43
|
+
## Commands
|
|
44
|
+
|
|
45
|
+
### Create a Project
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx create-projx my-app
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Interactive prompt lets you pick components. Or specify them directly:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx create-projx my-app --components fastapi,fastify,frontend,mobile,e2e,infra
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Add Components Later
|
|
58
|
+
|
|
59
|
+
Already have a project? Add more components anytime:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd my-app
|
|
63
|
+
npx create-projx add frontend mobile
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This copies the new component directories, regenerates shared files (docker-compose, CI, pre-commit hooks) to include them, and installs dependencies.
|
|
67
|
+
|
|
68
|
+
### Update Scaffolding
|
|
69
|
+
|
|
70
|
+
When we improve templates, update your project's scaffolding without touching your code:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd my-app
|
|
74
|
+
npx create-projx@latest update
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This updates template files (base models, middleware, configs, Dockerfiles, CI) tracked in `.projx` manifest. Files you created (new entities, pages, features) are never touched.
|
|
78
|
+
|
|
79
|
+
## Options
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
npx create-projx <name> [options]
|
|
83
|
+
npx create-projx add <components...>
|
|
84
|
+
npx create-projx update
|
|
85
|
+
|
|
86
|
+
--components <list> Comma-separated: fastapi,fastify,frontend,mobile,e2e,infra
|
|
87
|
+
--no-git Skip git init
|
|
88
|
+
--no-install Skip dependency installation
|
|
89
|
+
-y, --yes Accept defaults (fastify + frontend + e2e)
|
|
90
|
+
-h, --help Show help
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## What a Scaffolded Project Looks Like
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
my-app/
|
|
97
|
+
├── fastapi/ # Auto-entity CRUD backend
|
|
98
|
+
├── frontend/ # Auto-entity UI from /_meta
|
|
99
|
+
├── e2e/ # Playwright E2E tests
|
|
100
|
+
├── docker-compose.yml # Production (backend + frontend + SSL)
|
|
101
|
+
├── docker-compose.dev.yml # Development (PostgreSQL + hot reload)
|
|
102
|
+
├── .github/workflows/ # CI per component
|
|
103
|
+
├── .githooks/pre-commit # Format + lint on commit
|
|
104
|
+
├── setup.sh # Install all deps
|
|
105
|
+
└── .projx # Manifest (tracks template files for updates)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Only the components you selected appear. Shared files (docker-compose, CI, hooks) are generated to match your selection.
|
|
109
|
+
|
|
110
|
+
## Auto-Entity Pattern
|
|
111
|
+
|
|
112
|
+
The core idea: define a data model, get everything else for free.
|
|
113
|
+
|
|
114
|
+
**Backend** — Drop a model file. The registry auto-discovers it and generates CRUD routes, schemas, pagination, filtering, sorting, search, FK expansion, and OpenAPI docs.
|
|
115
|
+
|
|
116
|
+
**Frontend** — Fetches metadata from `GET /api/v1/_meta`, renders table + form UI automatically. Customize with overrides.
|
|
117
|
+
|
|
118
|
+
**Mobile** — Same metadata endpoint, generates list/detail/form screens. Offline-first with local DB and sync queue.
|
|
119
|
+
|
|
120
|
+
## What's Included
|
|
121
|
+
|
|
122
|
+
- JWT auth with Keycloak (pluggable providers)
|
|
123
|
+
- Docker Compose for dev and prod
|
|
124
|
+
- GitHub Actions CI per component
|
|
125
|
+
- Pre-commit hooks (format + lint + typecheck)
|
|
126
|
+
- Secret detection in pre-commit
|
|
127
|
+
- 80% test coverage enforced
|
|
128
|
+
- Auto-entity discovery across all stacks
|
|
129
|
+
|
|
130
|
+
## Development
|
|
131
|
+
|
|
132
|
+
Contributing to Projx itself:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
git clone https://github.com/ukanhaupa/projx.git
|
|
136
|
+
cd projx
|
|
137
|
+
./setup.sh
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The CLI lives in `cli/`. Templates are the root-level component directories (`fastapi/`, `frontend/`, etc.).
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -271,9 +271,6 @@ async function generateDockerCompose(vars) {
|
|
|
271
271
|
async function generateDockerComposeDev(vars) {
|
|
272
272
|
return renderShared("docker-compose.dev.yml.ejs", vars);
|
|
273
273
|
}
|
|
274
|
-
async function generateMakefile(vars) {
|
|
275
|
-
return renderShared("Makefile.ejs", vars);
|
|
276
|
-
}
|
|
277
274
|
async function generatePreCommit(vars) {
|
|
278
275
|
return renderShared("pre-commit.ejs", vars);
|
|
279
276
|
}
|
|
@@ -328,9 +325,6 @@ async function doScaffold(opts, dest, repoDir, name, nameSnake, vars) {
|
|
|
328
325
|
await writeFile2(join3(dest, "docker-compose.dev.yml"), dcDev);
|
|
329
326
|
manifest.push("docker-compose.dev.yml");
|
|
330
327
|
}
|
|
331
|
-
const makefile = await generateMakefile(vars);
|
|
332
|
-
await writeFile2(join3(dest, "Makefile"), makefile);
|
|
333
|
-
manifest.push("Makefile");
|
|
334
328
|
const readme = await generateReadme(vars);
|
|
335
329
|
await writeFile2(join3(dest, "README.md"), readme);
|
|
336
330
|
manifest.push("README.md");
|
|
@@ -383,7 +377,7 @@ async function doScaffold(opts, dest, repoDir, name, nameSnake, vars) {
|
|
|
383
377
|
p2.outro(`Done! Next steps:
|
|
384
378
|
|
|
385
379
|
cd ${name}
|
|
386
|
-
|
|
380
|
+
./setup.sh`);
|
|
387
381
|
}
|
|
388
382
|
async function substituteNames(dest, components, name, nameSnake) {
|
|
389
383
|
if (components.includes("fastapi")) {
|
|
@@ -594,15 +588,16 @@ async function update(cwd, localRepo) {
|
|
|
594
588
|
} finally {
|
|
595
589
|
await cleanupRepo(repoDir, isLocal);
|
|
596
590
|
}
|
|
597
|
-
execSync2(
|
|
591
|
+
execSync2("git add -A", { cwd, stdio: "pipe" });
|
|
592
|
+
execSync2(`git commit -m "projx update to v${pkg.version}"`, { cwd, stdio: "pipe" });
|
|
598
593
|
p3.outro(
|
|
599
|
-
`
|
|
594
|
+
`Updated on branch: ${branchName}
|
|
600
595
|
|
|
601
596
|
Review changes:
|
|
602
597
|
git diff ${originalBranch}...${branchName}
|
|
603
598
|
|
|
604
|
-
|
|
605
|
-
git merge ${branchName}`
|
|
599
|
+
Switch back and merge:
|
|
600
|
+
git checkout ${originalBranch} && git merge ${branchName}`
|
|
606
601
|
);
|
|
607
602
|
} else {
|
|
608
603
|
const dlSpinner = p3.spinner();
|
|
@@ -785,7 +780,6 @@ async function doAdd(cwd, config, toAdd, repoDir, skipInstall) {
|
|
|
785
780
|
await generateDockerComposeDev(vars)
|
|
786
781
|
);
|
|
787
782
|
}
|
|
788
|
-
await writeFile4(join5(cwd, "Makefile"), await generateMakefile(vars));
|
|
789
783
|
await writeFile4(join5(cwd, "README.md"), await generateReadme(vars));
|
|
790
784
|
await mkdir4(join5(cwd, ".githooks"), { recursive: true });
|
|
791
785
|
await writeFile4(join5(cwd, ".githooks/pre-commit"), await generatePreCommit(vars));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-projx",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
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": {
|
|
@@ -30,8 +30,8 @@ Scaffolded with [Projx](https://github.com/ukanhaupa/projx).
|
|
|
30
30
|
## Getting Started
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
|
@@ -73,10 +73,20 @@ cd mobile && cp .env.example .env && flutter pub get && flutter run
|
|
|
73
73
|
## Testing
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
<% if (components.includes('fastapi')) { %>
|
|
77
|
+
cd fastapi && uv run pytest
|
|
78
|
+
<% } %>
|
|
79
|
+
<% if (components.includes('fastify')) { %>
|
|
80
|
+
cd fastify && pnpm test
|
|
81
|
+
<% } %>
|
|
82
|
+
<% if (components.includes('frontend')) { %>
|
|
83
|
+
cd frontend && npx vitest run
|
|
84
|
+
<% } %>
|
|
85
|
+
<% if (components.includes('mobile')) { %>
|
|
86
|
+
cd mobile && flutter test
|
|
87
|
+
<% } %>
|
|
78
88
|
<% if (components.includes('e2e')) { %>
|
|
79
|
-
|
|
89
|
+
cd e2e && npx playwright test
|
|
80
90
|
<% } %>
|
|
81
91
|
```
|
|
82
92
|
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
.PHONY: setup install format lint fix check typecheck test test-coverage test-e2e \
|
|
2
|
-
migrate migrate-down seed run run-dev stop logs clean
|
|
3
|
-
|
|
4
|
-
# ─── Setup ───────────────────────────────────────────────────────────
|
|
5
|
-
|
|
6
|
-
setup:
|
|
7
|
-
git config core.hooksPath .githooks
|
|
8
|
-
@echo "Git hooks configured."
|
|
9
|
-
$(MAKE) install
|
|
10
|
-
|
|
11
|
-
install:
|
|
12
|
-
<% if (components.includes('fastapi')) { %>
|
|
13
|
-
cd fastapi && uv sync --all-extras
|
|
14
|
-
<% } %>
|
|
15
|
-
<% if (components.includes('fastify')) { %>
|
|
16
|
-
cd fastify && pnpm install --frozen-lockfile
|
|
17
|
-
<% } %>
|
|
18
|
-
<% if (components.includes('frontend')) { %>
|
|
19
|
-
cd frontend && npm ci
|
|
20
|
-
<% } %>
|
|
21
|
-
<% if (components.includes('e2e')) { %>
|
|
22
|
-
cd e2e && npm ci
|
|
23
|
-
<% } %>
|
|
24
|
-
<% if (components.includes('mobile')) { %>
|
|
25
|
-
cd mobile && flutter pub get 2>/dev/null || echo "Flutter SDK not installed — skipping mobile"
|
|
26
|
-
<% } %>
|
|
27
|
-
@echo "All dependencies installed."
|
|
28
|
-
|
|
29
|
-
# ─── Format ──────────────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
format:
|
|
32
|
-
<% if (components.includes('fastapi')) { %>
|
|
33
|
-
cd fastapi && uv run ruff format src tests
|
|
34
|
-
<% } %>
|
|
35
|
-
<% if (components.includes('fastify')) { %>
|
|
36
|
-
cd fastify && npx prettier --write --ignore-unknown .
|
|
37
|
-
<% } %>
|
|
38
|
-
<% if (components.includes('frontend')) { %>
|
|
39
|
-
cd frontend && npx prettier --write --ignore-unknown .
|
|
40
|
-
<% } %>
|
|
41
|
-
<% if (components.includes('e2e')) { %>
|
|
42
|
-
cd e2e && npx prettier --write --ignore-unknown .
|
|
43
|
-
<% } %>
|
|
44
|
-
<% if (components.includes('mobile')) { %>
|
|
45
|
-
cd mobile && dart format . 2>/dev/null || true
|
|
46
|
-
<% } %>
|
|
47
|
-
<% if (components.includes('infra')) { %>
|
|
48
|
-
cd infra/stack && terraform fmt -recursive 2>/dev/null || true
|
|
49
|
-
<% } %>
|
|
50
|
-
|
|
51
|
-
# ─── Lint ────────────────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
lint:
|
|
54
|
-
<% if (components.includes('fastapi')) { %>
|
|
55
|
-
cd fastapi && uv run ruff check src tests
|
|
56
|
-
<% } %>
|
|
57
|
-
<% if (components.includes('fastify')) { %>
|
|
58
|
-
cd fastify && npx eslint 'src/**/*.ts' 'tests/**/*.ts'
|
|
59
|
-
<% } %>
|
|
60
|
-
<% if (components.includes('frontend')) { %>
|
|
61
|
-
cd frontend && npx eslint 'src/**/*.{ts,tsx}'
|
|
62
|
-
<% } %>
|
|
63
|
-
<% if (components.includes('e2e')) { %>
|
|
64
|
-
cd e2e && npx eslint '**/*.ts'
|
|
65
|
-
<% } %>
|
|
66
|
-
<% if (components.includes('mobile')) { %>
|
|
67
|
-
cd mobile && dart analyze --fatal-infos 2>/dev/null || true
|
|
68
|
-
<% } %>
|
|
69
|
-
<% if (components.includes('infra')) { %>
|
|
70
|
-
cd infra/stack && terraform validate 2>/dev/null || true
|
|
71
|
-
<% } %>
|
|
72
|
-
|
|
73
|
-
# ─── Fix (format + lint with auto-fix) ──────────────────────────────
|
|
74
|
-
|
|
75
|
-
fix:
|
|
76
|
-
<% if (components.includes('fastapi')) { %>
|
|
77
|
-
cd fastapi && uv run ruff format src tests && uv run ruff check --fix src tests
|
|
78
|
-
<% } %>
|
|
79
|
-
<% if (components.includes('fastify')) { %>
|
|
80
|
-
cd fastify && npx prettier --write --ignore-unknown . && npx eslint --fix 'src/**/*.ts' 'tests/**/*.ts'
|
|
81
|
-
<% } %>
|
|
82
|
-
<% if (components.includes('frontend')) { %>
|
|
83
|
-
cd frontend && npx prettier --write --ignore-unknown . && npx eslint --fix 'src/**/*.{ts,tsx}'
|
|
84
|
-
<% } %>
|
|
85
|
-
<% if (components.includes('e2e')) { %>
|
|
86
|
-
cd e2e && npx prettier --write --ignore-unknown . && npx eslint --fix '**/*.ts'
|
|
87
|
-
<% } %>
|
|
88
|
-
<% if (components.includes('mobile')) { %>
|
|
89
|
-
cd mobile && dart format . 2>/dev/null && dart analyze --fatal-infos 2>/dev/null || true
|
|
90
|
-
<% } %>
|
|
91
|
-
<% if (components.includes('infra')) { %>
|
|
92
|
-
cd infra/stack && terraform fmt -recursive 2>/dev/null || true
|
|
93
|
-
<% } %>
|
|
94
|
-
|
|
95
|
-
# ─── Type Check ──────────────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
typecheck:
|
|
98
|
-
<% if (components.includes('fastify')) { %>
|
|
99
|
-
cd fastify && npx tsc --noEmit
|
|
100
|
-
<% } %>
|
|
101
|
-
<% if (components.includes('frontend')) { %>
|
|
102
|
-
cd frontend && npx tsc --noEmit
|
|
103
|
-
<% } %>
|
|
104
|
-
<% if (components.includes('e2e')) { %>
|
|
105
|
-
cd e2e && npx tsc --noEmit
|
|
106
|
-
<% } %>
|
|
107
|
-
|
|
108
|
-
# ─── Check (CI-equivalent) ──────────────────────────────────────────
|
|
109
|
-
|
|
110
|
-
check:
|
|
111
|
-
<% if (components.includes('fastapi')) { %>
|
|
112
|
-
cd fastapi && uv run ruff format --check src tests && uv run ruff check src tests
|
|
113
|
-
<% } %>
|
|
114
|
-
<% if (components.includes('fastify')) { %>
|
|
115
|
-
cd fastify && npx prettier --check . && npx eslint . && npx tsc --noEmit
|
|
116
|
-
<% } %>
|
|
117
|
-
<% if (components.includes('frontend')) { %>
|
|
118
|
-
cd frontend && npx prettier --check . && npx eslint 'src/**/*.{ts,tsx}' && npx tsc --noEmit
|
|
119
|
-
<% } %>
|
|
120
|
-
<% if (components.includes('e2e')) { %>
|
|
121
|
-
cd e2e && npx prettier --check . && npx eslint '**/*.ts' && npx tsc --noEmit
|
|
122
|
-
<% } %>
|
|
123
|
-
<% if (components.includes('mobile')) { %>
|
|
124
|
-
cd mobile && dart format --set-exit-if-changed . 2>/dev/null && dart analyze --fatal-infos 2>/dev/null || true
|
|
125
|
-
<% } %>
|
|
126
|
-
<% if (components.includes('infra')) { %>
|
|
127
|
-
cd infra/stack && terraform fmt -check -recursive 2>/dev/null && terraform validate 2>/dev/null || true
|
|
128
|
-
<% } %>
|
|
129
|
-
|
|
130
|
-
# ─── Test ────────────────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
test:
|
|
133
|
-
<% if (components.includes('fastapi')) { %>
|
|
134
|
-
cd fastapi && uv run pytest --tb=short -q
|
|
135
|
-
<% } %>
|
|
136
|
-
<% if (components.includes('fastify')) { %>
|
|
137
|
-
cd fastify && pnpm test
|
|
138
|
-
<% } %>
|
|
139
|
-
<% if (components.includes('frontend')) { %>
|
|
140
|
-
cd frontend && npx vitest run
|
|
141
|
-
<% } %>
|
|
142
|
-
<% if (components.includes('mobile')) { %>
|
|
143
|
-
cd mobile && flutter test 2>/dev/null || true
|
|
144
|
-
<% } %>
|
|
145
|
-
|
|
146
|
-
test-coverage:
|
|
147
|
-
<% if (components.includes('fastapi')) { %>
|
|
148
|
-
cd fastapi && uv run pytest --cov=src --cov-report=term-missing --cov-fail-under=80
|
|
149
|
-
<% } %>
|
|
150
|
-
<% if (components.includes('fastify')) { %>
|
|
151
|
-
cd fastify && pnpm test -- --coverage
|
|
152
|
-
<% } %>
|
|
153
|
-
<% if (components.includes('frontend')) { %>
|
|
154
|
-
cd frontend && npx vitest run --coverage
|
|
155
|
-
<% } %>
|
|
156
|
-
<% if (components.includes('mobile')) { %>
|
|
157
|
-
cd mobile && flutter test --coverage 2>/dev/null || true
|
|
158
|
-
<% } %>
|
|
159
|
-
<% if (components.includes('e2e')) { %>
|
|
160
|
-
|
|
161
|
-
test-e2e:
|
|
162
|
-
cd e2e && npx playwright test
|
|
163
|
-
<% } %>
|
|
164
|
-
<% if (components.includes('mobile')) { %>
|
|
165
|
-
|
|
166
|
-
test-e2e-mobile:
|
|
167
|
-
cd mobile && flutter test integration_test/
|
|
168
|
-
|
|
169
|
-
mobile-build-apk:
|
|
170
|
-
cd mobile && flutter build apk --release
|
|
171
|
-
|
|
172
|
-
mobile-build-ios:
|
|
173
|
-
cd mobile && flutter build ios --release --no-codesign
|
|
174
|
-
|
|
175
|
-
mobile-codegen:
|
|
176
|
-
cd mobile && dart run build_runner build --delete-conflicting-outputs
|
|
177
|
-
<% } %>
|
|
178
|
-
<% if (components.includes('fastapi')) { %>
|
|
179
|
-
|
|
180
|
-
# ─── Database ────────────────────────────────────────────────────────
|
|
181
|
-
|
|
182
|
-
migrate:
|
|
183
|
-
cd fastapi && uv run migrate.py
|
|
184
|
-
<% if (components.includes('fastify')) { %>
|
|
185
|
-
cd fastify && pnpm prisma:migrate:dev
|
|
186
|
-
<% } %>
|
|
187
|
-
|
|
188
|
-
migrate-deploy:
|
|
189
|
-
cd fastapi && uv run migrate.py
|
|
190
|
-
<% if (components.includes('fastify')) { %>
|
|
191
|
-
cd fastify && pnpm prisma:migrate:deploy
|
|
192
|
-
<% } %>
|
|
193
|
-
|
|
194
|
-
migrate-down:
|
|
195
|
-
cd fastapi && uv run migrate.py --downgrade -1
|
|
196
|
-
|
|
197
|
-
seed:
|
|
198
|
-
cd fastapi && uv run seed.py
|
|
199
|
-
<% } %>
|
|
200
|
-
<% if (components.includes('fastify') && !components.includes('fastapi')) { %>
|
|
201
|
-
|
|
202
|
-
migrate:
|
|
203
|
-
cd fastify && pnpm prisma:migrate:dev
|
|
204
|
-
|
|
205
|
-
migrate-deploy:
|
|
206
|
-
cd fastify && pnpm prisma:migrate:deploy
|
|
207
|
-
<% } %>
|
|
208
|
-
|
|
209
|
-
# ─── Run (local) ─────────────────────────────────────────────────────
|
|
210
|
-
|
|
211
|
-
run-local:
|
|
212
|
-
<% if (components.includes('fastapi')) { %>
|
|
213
|
-
cd fastapi && uv run main.py &
|
|
214
|
-
<% } %>
|
|
215
|
-
<% if (components.includes('fastify')) { %>
|
|
216
|
-
cd fastify && pnpm dev &
|
|
217
|
-
<% } %>
|
|
218
|
-
<% if (components.includes('frontend')) { %>
|
|
219
|
-
cd frontend && npm run dev &
|
|
220
|
-
<% } %>
|
|
221
|
-
@echo "All services starting. Run 'make stop-local' to stop."
|
|
222
|
-
@wait
|
|
223
|
-
|
|
224
|
-
stop-local:
|
|
225
|
-
@kill $$(lsof -ti:7860,3000,5173 2>/dev/null) 2>/dev/null || true
|
|
226
|
-
@echo "All local services stopped."
|
|
227
|
-
<% if (components.includes('fastapi')) { %>
|
|
228
|
-
|
|
229
|
-
run-fastapi:
|
|
230
|
-
cd fastapi && uv run main.py
|
|
231
|
-
<% } %>
|
|
232
|
-
<% if (components.includes('fastify')) { %>
|
|
233
|
-
|
|
234
|
-
run-fastify:
|
|
235
|
-
cd fastify && pnpm dev
|
|
236
|
-
<% } %>
|
|
237
|
-
<% if (components.includes('frontend')) { %>
|
|
238
|
-
|
|
239
|
-
run-frontend:
|
|
240
|
-
cd frontend && npm run dev
|
|
241
|
-
<% } %>
|
|
242
|
-
<% if (components.includes('mobile')) { %>
|
|
243
|
-
|
|
244
|
-
run-mobile:
|
|
245
|
-
cd mobile && flutter run
|
|
246
|
-
<% } %>
|
|
247
|
-
|
|
248
|
-
# ─── Run (Docker Compose) ───────────────────────────────────────────
|
|
249
|
-
|
|
250
|
-
run:
|
|
251
|
-
docker compose up -d --build
|
|
252
|
-
|
|
253
|
-
run-dev:
|
|
254
|
-
docker compose -f docker-compose.dev.yml up -d --build
|
|
255
|
-
|
|
256
|
-
stop:
|
|
257
|
-
docker compose down
|
|
258
|
-
docker compose -f docker-compose.dev.yml down 2>/dev/null || true
|
|
259
|
-
|
|
260
|
-
logs:
|
|
261
|
-
docker compose logs -f
|
|
262
|
-
<% if (components.includes('fastapi')) { %>
|
|
263
|
-
|
|
264
|
-
entity:
|
|
265
|
-
@test -n "$(name)" || (echo "Usage: make entity name=my_entity" && exit 1)
|
|
266
|
-
cd fastapi && uv run scaffold.py $(name)
|
|
267
|
-
|
|
268
|
-
entity-custom:
|
|
269
|
-
@test -n "$(name)" || (echo "Usage: make entity-custom name=my_entity" && exit 1)
|
|
270
|
-
cd fastapi && uv run scaffold.py $(name) --controller
|
|
271
|
-
<% } %>
|
|
272
|
-
|
|
273
|
-
# ─── Clean ───────────────────────────────────────────────────────────
|
|
274
|
-
|
|
275
|
-
clean:
|
|
276
|
-
docker compose down -v
|
|
277
|
-
docker compose -f docker-compose.dev.yml down -v 2>/dev/null || true
|
|
278
|
-
<% if (components.includes('fastapi')) { %>
|
|
279
|
-
cd fastapi && rm -rf .pytest_cache __pycache__ .coverage htmlcov
|
|
280
|
-
<% } %>
|
|
281
|
-
<% if (components.includes('fastify')) { %>
|
|
282
|
-
cd fastify && rm -rf dist coverage node_modules/.cache
|
|
283
|
-
<% } %>
|
|
284
|
-
<% if (components.includes('frontend')) { %>
|
|
285
|
-
cd frontend && rm -rf dist coverage node_modules/.cache playwright-report test-results
|
|
286
|
-
<% } %>
|