@ftisindia/create-app
v2.0.0
Published
One-command scaffolder for the Phase 1 NestJS foundation starter.
Readme
@ftisindia/create-app
A create-next-app-style scaffolder that generates a production-ready NestJS
modular-monolith starter — with authentication, organisations, memberships,
invitations, per-organisation RBAC, request context, audit logs, typed settings, Swagger
docs, health checks, definition-driven dynamic forms and reports, a client-SDK
generator, and a guided one-command local setup.
The CLI command is ftis-nest.
Quick start
npx @ftisindia/create-app@latest my-appOr install once and use the short command anywhere:
npm i -g @ftisindia/create-app
ftis-nest my-appThen bootstrap and run the generated app:
cd my-app
npm run setup:local # creates DBs, runs migrations, seeds demo data, prints login
npm run start:devOpen:
- Swagger API docs — http://localhost:3000/docs
- Health check — http://localhost:3000/health
Usage
ftis-nest <project-name|.> [options]
npx @ftisindia/create-app <project-name|.> [options]<project-name> is the folder to create. Use . to scaffold into the current directory
(it must be empty).
Options
| Option | Description |
|--------|-------------|
| --no-install | Copy files only; skip npm install and prisma generate |
| --no-git | Skip git init / add / initial commit |
| --pm <name> | Package manager to use: npm, pnpm, or yarn |
| --api-keys | Enable API-key support: writes API_KEYS_ENABLED=true into .env and .env.example. No secret is generated and no platform administrator is granted; organisation owners still opt in. See the generated docs/API_KEYS.md. |
| --help | Show help |
The initial commit is created with git commit --no-verify, so it is a byte-exact snapshot of
the template. The generated app installs husky + lint-staged during npm install, and running
that hook over ~350 freshly generated files would only reformat and slow down a commit nobody
authored; hooks apply from your first own commit.
Prerequisites
- Node.js 22+
- PostgreSQL running locally, or a reachable
DATABASE_URL
What you get
The generated app is a modular monolith with these modules ready to use:
- Auth — email/password + Google OAuth handoff, JWT access/refresh, logout
- Organisations / Memberships / Invitations — multi-tenant org model with roles and invites
- Access Control (RBAC) — per-organisation roles and permissions (CASL) with a permission registry
- Audit — org-scoped audit logs
- Settings — typed per-organisation settings
- Forms (
@ftisindia/form-builder) — a definition-driven dynamic form engine: versioned JSON definitions, validated transactional submissions, file uploads, public forms, and a reliable outbox for emails and webhooks. Most new forms need zero backend code - Reports (
@ftisindia/report-builder) — a definition-driven report engine: declared, versioned views over registered data sources with typed filters, keyset pagination, saved views, tags, drift-safe bulk row actions, and CSV/XLSX exports. Unindexed shapes fail at publish with the exact migration SQL to fix them - Health — database connectivity check
- Sample — a reference module to copy when adding your own
Plus global request validation, a consistent error envelope, Swagger at /docs,
request-context scoping, Prisma with migrations and seed scripts, a gen:module
generator, and ftis-sdk wiring that generates a typed Dart/Flutter or Angular client
from the generated app's own OpenAPI contract.
The FTIS plug-and-play modules (mailer, realtime, push, messaging, notifications — an internal catalog, not shipped in this package) require an app scaffolded by create-app ≥ 2.0.0: push, messaging and notifications append to its API-key host points, and every module is verified against that scaffold.
Common scripts in the generated app
npm run setup:local # one-command local bootstrap (non-destructive)
npm run start:dev # watch mode
npm run build # production build
npm test # unit tests
npm run test:e2e # end-to-end tests
npm run gen:module -- <name> # scaffold a new module (AppModule + registry wired)
npm run gen:form -- <key> # scaffold a form definition + its lint spec
npm run forms:push -- --file <file> --org <org> --user <email> --publish # load a form definition
npm run reports:push -- --file <file> --org <org> --user <email> --publish # load a report definition
npm run sdk:generate # typed Dart SDK (sdk:generate:angular for the web SDK)Windows PowerShell: the npm bundled with Node 20 and Node 22.13 (npm 10.8.x–10.9.2, also 11.0–11.4) drops the
--, so the push/docs flags never reach the script. Usenpm.cmd run … -- …,npx ts-node scripts/push-form.ts …, cmd.exe / Git Bash, or npm ≥ 10.9.3 / ≥ 11.5.0. The generated app'sdocs/FORMS.mdhas the details.
See the generated app's own README.md and docs/ for full guidance, including how to
add a module and the architecture rules.
License
Released under the PolyForm Noncommercial License 1.0.0 — free for any noncommercial
use. Commercial use requires a separate commercial license from
ftisindia.com. See the bundled LICENSE file.
Generating a module with gen:module
Every project this CLI generates ships a gen:module script. In any generated project,
run it to scaffold a new feature module that already follows the project's auth, RBAC,
request-context, and audit conventions.
npm run gen:module -- billingNote the
--before the name — it tells npm to pass the argument through to the generator. Names are normalized automatically, sobilling,Billing,"invoice items", andinvoiceItemsall resolve to the same module.
What it generates
For a name like billing, you get:
src/modules/billing/billing.module.ts— the NestJS module (wires controller + service)src/modules/billing/dto/billing-echo.dto.ts— a sample DTO (class-validator + Swagger)src/modules/billing/application/services/billing.service.ts— a service withgetStatus()andecho()that use Prisma, request context, and write an audit-log rowsrc/modules/billing/presentation/billing.controller.ts— an org-scoped controller guarded byJwtAuthGuard,OrgScopeGuard, andPermissionGuard, exposing:GET /organisations/:orgId/billing/status— requiresbilling.readPOST /organisations/:orgId/billing/echo— requiresbilling.update
test/billing.spec.ts— a starter unit test
It also wires the module in automatically by appending to:
src/modules/access-control/types/permission-key.ts— addsbilling.readandbilling.updatesrc/modules/access-control/types/route-permission-registry.ts— adds the two route entries (startup and tests fail if a guarded route is missing here)test/route-registry.validator.spec.ts— addsBillingControllerto the spec's hard-codedcontrollersarray (without this,npm testreports registry drift)src/app.module.ts— registersBillingModulein the@Moduleimports array
The generated module also imports AuthModule, mirroring sample.module.ts. If an
append anchor cannot be found (say, a hand-reshaped app.module.ts), the generator
prints a MANUAL STEP REQUIRED line naming the exact edit instead of failing.
The generator never overwrites existing files — it stops if any target already exists.
One step to finish
Re-seed permissions so the new keys exist in the database and can be granted to roles:
npm run prisma:seedThen assign billing.read / billing.update to the appropriate role(s).
Start the app and the new guarded endpoints are live (visible in Swagger at /docs).
When not to use it
- You need a non-org-scoped or public route. The output is hard-wired to
/organisations/:orgId/<name>with the org guards. Build global/unauthenticated endpoints by hand instead. - You're extending an existing module. It scaffolds a brand-new module and refuses to overwrite — add files to the existing module manually.
- Your feature doesn't map to simple read/update permissions. It generates exactly
<name>.readand<name>.update; for richer permission sets, edit the generatedpermission-key.tsand registry entries afterward. - You want a different shape than the
status+echoreference endpoints. Treat the output as a starting point, or copysrc/modules/sample(seedocs/SAMPLE_MODULE.md) for a fuller reference.
