Skip to content

ukanhaupa/projx

Repository files navigation

Projx

npm version CI GitHub stars License: MIT

Go from blank folder to production-ready project in 30 seconds. Backend-only API, AI/ML app, mobile, full-stack, infra setup — pick what you need and get it wired with auth, database, Docker, CI/CD, hooks, and tests. All optional. All yours.

projx demo

npx create-projx my-app

No SDK lock-in. No runtime dependency on Projx. Just clean code in your repo that you own forever.


You've done this a hundred times

Every new project starts with the same week of plumbing:

  • Wire up auth (again).
  • Configure the database and migrations (again).
  • Write the Dockerfile and docker-compose.yml (again).
  • Set up CI, linting, formatting, pre-commit hooks (again).
  • Build the same login + CRUD scaffolding (again).
  • Realize at 11pm that something's broken and you don't remember why (again).

You ship features two weeks late because the first two weeks were boilerplate.

Or your AI does it badly

Ask an LLM to "scaffold a full-stack app" and you get 50 files of plausible-looking code that breaks on first run. Wrong import paths. Outdated package versions. Auth that doesn't actually authenticate. You end up debugging machine-generated boilerplate, which is worse than writing it yourself.

What if you just… didn't?

npx create-projx my-app       # interactive — pick exactly what you need
cd my-app
./scripts/setup.sh            # installs everything you picked

Pick any combination of components — they're all optional:

# AI/ML backend only
npx create-projx vision-api --components fastapi -y

# Node API + React frontend
npx create-projx saas --components fastify,frontend -y

# Minimal Express API + React frontend
npx create-projx api-app --components express,frontend -y

# Drizzle-backed Node API + React frontend
npx create-projx ledger --components express,frontend --orm drizzle -y

# Mobile app with backend
npx create-projx field-app --components fastapi,mobile -y

# Full-stack with infra and E2E
npx create-projx prod-app --components fastify,frontend,e2e,infra -y

# Just the infra
npx create-projx platform --components infra -y

30 seconds. No matter what you pick, you get auth, Docker, CI/CD, hooks, and tests wired up for it.

If this saves you even one hour, it's already paid for itself. (It's free.)

Why teams pick Projx and stay

  • It actually runs. Every template is tested in CI before release. No "looks right" surprises.
  • Tests ship with the code. gen entity writes integration tests alongside every model — 11 tests per entity, against a real database. You start green, not scrambling.
  • Auto-entity pattern. Define a data model, get CRUD routes, validation, OpenAPI docs, and a typed UI for free. Backend, frontend, and mobile all stay in sync.
  • Updates don't nuke your code. projx update does a 3-tier merge — your custom controllers, pages, and config survive template upgrades. No rewrites.
  • No lock-in. Projx generates files and walks away. Delete the .projx config and it's just a normal repo.
  • Adopt incrementally. Already have a project? projx init adds CI, hooks, and Docker without touching your code.
  • Pick your package manager. npm, pnpm, yarn, or bun. The choice propagates everywhere — scripts, Docker, CI, docs.
  • Pick your Node ORM. Prisma is the auto-CRUD default. Drizzle, Sequelize, and TypeORM ship as first-class addons with identical runtime surface (auto-routes, pagination, filtering, search, lifecycle hooks).
  • AI-agent friendly. Ships with SKILL.md so Claude, Cursor, and other agents call Projx instead of hand-writing broken scaffolds.

What you get

Component Stack What it gives you
fastapi Python, SQLAlchemy, Alembic Auto-entity CRUD, JWT auth, migrations, OpenAPI docs
fastify Node.js, Prisma / Drizzle / Sequelize / TypeORM, TypeBox Auto-entity CRUD, JWT auth, typed schemas, OpenAPI docs
express Express 5, TypeScript, Prisma / Drizzle / Sequelize / TypeORM Auto-entity CRUD, JWT auth, validation, security middleware, health checks
frontend React 19, TypeScript, Vite Auth, theming, design tokens, light/dark mode
mobile Flutter, Riverpod, GoRouter Auth, biometric, theming, GoRouter shell
e2e Playwright Page object model, auth fixtures, accessibility scans
infra Terraform, AWS EKS, RDS, VPC, ALB, CodePipeline, multi-environment

Plus, in every project: Docker Compose for dev + prod, GitHub Actions CI per component (path-filtered), pre-commit hooks, secret detection, VS Code settings, and 80% test coverage enforced.

All optional. Pick any combination.

Optional features

Components are the floor. Features are the opt-in modules that ride on top — same standard, same CI, same skip-list discipline. Today there's one, and it's the one everyone rewrites: auth.

# Fastify + Prisma (default ORM)
npx create-projx my-app --components fastify --auth fastify

# Express + Drizzle
npx create-projx my-app --components express --orm drizzle --auth express

# FastAPI + SQLAlchemy
npx create-projx my-app --components fastapi --auth fastapi

# Multiple backends, one flag — comma-separable targets
npx create-projx my-app --components fastify,express --auth fastify,express

What --auth ships

  • Email + password signup — first user auto-promoted to admin
  • Login with JWT access token and refresh-token rotation, with replay detection
  • Account lockout after 5 failed logins (15-minute cooldown)
  • MFA via TOTP authenticator app — enroll via otpauth URL (client renders the QR), verify on challenge
  • MFA recovery codes — generate, single-use consume, regenerate
  • MFA lockout on repeated bad codes with time-based unlock
  • Password reset via emailed single-use token (30-minute TTL)
  • Email verification with resend endpoint (24-hour TTL token)
  • Authenticated password change — revokes all other sessions
  • Active session listing
  • Current-user lookup via /me
  • Role-based permissions baked into the JWT payload
  • SMTP mailer for verification and reset emails — falls back to logging the link when SMTP is unset
  • Cron-driven cleanup of expired tokens (toggle via AUTH_BACKGROUND_JOBS)
  • Centralized error responses with request_id propagation

Sixteen endpoints across signup, login, MFA challenge/enroll/disable, recovery-code regen, refresh, logout, change-password, sessions, forgot/reset password, verify/resend email, me. Same surface on every backend — mounted at /auth/* on fastify and express, /api/v1/auth/* on fastapi.

Backend × ORM compatibility

Backend Prisma Drizzle Sequelize TypeORM SQLAlchemy
fastify yes yes yes yes
express yes yes yes yes
fastapi yes

Nine combinations, one external contract. ORM-specific bits live under features/auth/ (per-stack, per-ORM subdirectories); the shared surface per stack lives under each stack's common/ subdirectory. Env vars the feature reads: JWT_SECRET, FRONTEND_URL, AUTH_BACKGROUND_JOBS (all backends); JWT_ALGORITHMS, MFA_ISSUER, AUTH_CLEANUP_INTERVAL_SECONDS (fastapi).

Full feature-template spec — manifests, patches, anchors, idempotency — in docs/feature-templates.md.

Built for humans and AI agents

Projx is a shared operating system for teams that ship with both:

  • Developers get a readable layout, stable conventions, and safe updates.
  • AI agents get a deterministic CLI to call instead of guessing folder structures.
  • Teams get consistency across repos, less drift, and fewer surprise refactors.

If you're an AI agent reading this, see SKILL.md for trigger conditions, decision rules, and the canonical invocation.

Quick Start

# Interactive — pick your stack
npx create-projx my-app

# Non-interactive — specify components
npx create-projx my-app --components fastify,frontend,e2e

# Use Drizzle for Node backends instead of Prisma
npx create-projx my-app --components express,frontend --orm drizzle

# Accept defaults (Fastify + Frontend + E2E)
npx create-projx my-app -y

Package Manager Support

Projx supports npm, pnpm, yarn, and bun. During create, you're prompted to pick one. The choice is stored in .projx and used everywhere — scripts/setup.sh, Docker, CI, pre-commit hooks, and README.

{ "packageManager": "pnpm" }

For init, the package manager is auto-detected from lockfiles (pnpm-lock.yaml → pnpm, yarn.lock → yarn, bun.lockb → bun). Falls back to a prompt if no lockfile is found.

Commands

Create a Project

npx create-projx my-app

Interactive prompt lets you pick components. Or specify them directly:

npx create-projx my-app --components fastapi,fastify,frontend,mobile,e2e,infra

Adopt an Existing Project

Already have a project? Initialize projx to get the scaffolding (CI, hooks, docker-compose) without overwriting your code:

cd my-existing-app
npx create-projx init

Auto-detects components by scanning for fastapi in pyproject.toml, react/fastify in package.json, flutter in pubspec.yaml, and .tf files. Confirms each mapping, creates a projx/baseline branch with the template, and merges it — preserving all your existing code while establishing the ancestry link that makes future updates work.

Add Components Later

cd my-app
npx create-projx add frontend mobile

Copies the new component directories, regenerates shared files (docker-compose, CI, pre-commit hooks) to include them, and installs dependencies.

Multiple instances of the same type

Need a second backend service alongside an existing one (e.g. an SMTP listener next to your CRUD API)? Use --name <dir>:

npx create-projx add fastify --name email-ingestor

Creates email-ingestor/ with the fastify scaffold and a .projx-component marker. Each instance gets its own job in .github/workflows/ci.yml, its own section in .githooks/pre-commit, and its own install step in scripts/setup.sh. update keeps every instance refreshed on every run.

Update Scaffolding

When templates improve, update your project:

cd my-app
npx create-projx@latest update

Updates use a 3-tier merge strategy:

  1. Git merge — if the template merges cleanly with your code, it's auto-committed. Done.
  2. 3-way merge — if git merge fails, each file is merged individually using git merge-file. Your additions (extra deps, env vars, custom config) are preserved alongside template updates. Clean merges are auto-staged; only true conflicts need review.
  3. Direct copy — if no merge baseline exists, template files are written directly. You pick which changes to keep via an interactive prompt, and discarded files are automatically added to your skip list.

Your custom files (controllers, pages, middleware) are never deleted. Files you created that don't exist in the template are always preserved.

Skip Files

Common user-owned files are default-skipped automatically — template updates won't touch them:

Scope Default skips
Root (.projx) docker-compose.yml, README.md, .githooks/pre-commit, .github/workflows/ci.yml, scripts/setup.sh, scripts/setup-docker.sh, scripts/setup-ssl.sh
fastapi pyproject.toml
fastify / frontend / e2e package.json
mobile pubspec.yaml

Defaults are applied once on first update and saved to the skip array. To skip additional files, add them to skip in .projx (root-level) or .projx-component (per-component):

// .projx — root skip
{
  "version": "x.y.z",
  "skip": ["docker-compose.yml", "README.md", "my-custom-config.yml"]
}
// fastapi/.projx-component — component skip
{
  "component": "fastapi",
  "origin": "init",
  "skip": ["pyproject.toml", "src/custom_middleware.py"]
}

To opt back in to updates for a skipped file, use npx create-projx unpin <file>.

Options

npx create-projx <name> [options]
npx create-projx init
npx create-projx add <components...>
npx create-projx add <type> --name <dir>
npx create-projx update
npx create-projx diff
npx create-projx pin <patterns...>
npx create-projx unpin <patterns...>
npx create-projx pin --list
npx create-projx doctor [--fix]
npx create-projx gen entity <name> [--ai | --backend]

--components <list>    Comma-separated: fastapi,fastify,express,frontend,mobile,e2e,infra
--name <dir>           Custom directory for `add <type>` (multi-instance)
--ai                   Target fastapi (AI/ML) for gen entity
--backend              Target fastify (API backend) for gen entity
--no-git               Skip git init
--no-install           Skip dependency installation
-y, --yes              Accept defaults (fastify + frontend + e2e)
-h, --help             Show help

Preview Changes

See what update would change before applying:

cd my-app
npx create-projx diff

Shows file-by-file analysis: clean updates, files needing merge, user-only changes, and skipped files.

Pin / Unpin Files

Skip files from future template updates without editing JSON:

npx create-projx pin backend/pyproject.toml      # skip this file
npx create-projx pin "backend/src/**"             # skip with glob
npx create-projx unpin backend/pyproject.toml     # allow updates again
npx create-projx pin --list                       # show all pinned files

Files inside a component directory are added to that component's .projx-component skip list. Root-level files are added to .projx skip.

Health Check

Diagnose issues with your projx setup:

npx create-projx doctor         # check everything
npx create-projx doctor --fix   # auto-fix what's possible

Checks: config validity, component markers, baseline ref, stale worktrees, skip pattern coverage.

Generate Entities

Scaffold a new entity in your primary backend + typed models for frontend/mobile:

npx create-projx gen entity invoice                                          # interactive
npx create-projx gen entity invoice --fields "name:string,amount:number"     # non-interactive
npx create-projx gen entity embedding --ai --fields "name:string,vector:json"  # target AI backend
npx create-projx gen entity invite --fields "email:string,code:string:unique:generated"  # server-fills `code`

Field modifiers (Fastify/Express only, after the type): unique adds a Prisma @unique constraint; generated (alias: server, server-generated) marks the field as server-populated — it's omitted from the create-schema and a beforeCreate hook stub is emitted that fills it before persist (override the body of generateXxx() with your slug/code/UUID logic). Use both together for server-issued unique identifiers (invite codes, slugs, short URLs).

When both fastapi and fastify exist, the entity generates in the primary backend only (not both). First run prompts you to choose and saves to .projx:

{ "primaryBackend": "fastify" }

Override with --ai (fastapi) or --backend (fastify).

Component Generated
Primary backend (fastapi) src/entities/<name>/_model.py + tests/test_<name>_entity.py — model + 11 CRUD/auth tests
Primary backend (fastify) src/modules/<name>/schemas.ts + index.ts + Prisma model + tests/modules/<name>.test.ts
frontend src/types/<name>.ts — TypeScript interface + Create/Update variants

Tests included: every gen entity writes a working integration test file alongside the model — 11 tests for FastAPI (extending BaseEntityApiTest), 11 tests for Fastify (via describeCrudEntity). Both run against a real database (Postgres). New entities ship green from day one — no scrambling to bolt on tests at go-live.

No migrations — run alembic revision --autogenerate or prisma migrate dev (via your package manager) when ready.

ORM choice (Node backends)

Pick an ORM at create-time with --orm <provider>. Default: prisma. Supported: prisma, drizzle, sequelize, typeorm.

ORM Schema home gen entity produces Sync schema to DB
prisma prisma/schema.prisma Prisma model + Fastify/Express module (schemas.ts, index.ts) + integration test prisma migrate dev
drizzle src/db/schema.ts Typed pgTable + Fastify/Express router wired via _base/ + CRUD test drizzle-kit push --force
sequelize src/models/<name>.ts Sequelize Model class + aggregator entry + Fastify/Express router + CRUD test pnpm db:sync (uses sequelize.sync)
typeorm src/entities/<name>.ts Decorated @Entity class + aggregator entry + Fastify/Express router + CRUD test pnpm db:sync (uses dataSource.synchronize)

All four ORMs scaffold equivalent runtime behavior: _base/auto-routes.ts wires POST/GET/PATCH/DELETE/bulk routes with pagination, equality filters, ILIKE search, and the lifecycle hook contract (beforeCreate, afterCreate, beforeUpdate, afterUpdate, beforeDelete).

ORM-specific scaffolding lives in cli/src/addons/orms/ — each ORM is a self-contained folder with a manifest.json (deps, file removals, scripts), shared/ files, per-framework overlays, and gen-entity/ templates. Adding a new ORM means adding a new folder there; no CLI core changes.

Rename Component Directories

Rename fastapi/ to backend/? Just rename the folder — the .projx-component marker file moves with it. The update command auto-discovers where each component lives by scanning for these markers. No config changes needed.

backend/.projx-component  →  { "components": ["fastapi"] }
web/.projx-component      →  { "components": ["frontend"] }

CI, scripts/setup.sh, pre-commit hooks, and docker-compose are all regenerated with your custom directory names.

What a Scaffolded Project Looks Like

my-app/
├── fastapi/                # Auto-entity CRUD backend
│   └── .projx-component    # Identifies this as the fastapi component
├── frontend/               # React + Vite shell
│   └── .projx-component
├── e2e/                    # Playwright E2E tests
│   └── .projx-component
├── docker-compose.yml      # Production (backend + frontend + SSL)
├── .github/workflows/      # CI per component (runs only on changes)
├── .githooks/pre-commit    # Format + lint on commit
├── .vscode/                # Editor settings + recommended extensions
├── scripts/                # setup.sh, setup-docker.sh, setup-ssl.sh
└── .projx                  # Components list + version

Only the components you selected appear. Shared files (docker-compose, CI, hooks) are generated to match your selection.

Auto-Entity Pattern

The core idea: define a data model, get everything else for free.

Backend — Drop a model file. The registry auto-discovers it and generates CRUD routes, schemas, pagination, filtering, sorting, search, FK expansion, and OpenAPI docs.

Field privacy — Sensitive columns (password_hash, secret, api_key, mfa_secret, etc.) are automatically stripped from API responses via a built-in baseline. Add project-specific hidden fields per entity (__hidden_fields__ in FastAPI, hiddenFields in Fastify). Mark entire entities as __private__ / private: true to hide them from the API entirely — no routes registered.

Frontend — Ships a React shell with auth, theming, and design tokens. Build your own pages using the generated types from gen entity.

Mobile — Ships a Flutter shell with auth, biometric, and GoRouter scaffolding. Build screens using the generated Dart models from gen entity.

Encrypted Service Config

Both backends ship with a service_configs table for storing third-party credentials (SMTP, OAuth, S3, etc.) encrypted at rest with AES-256-GCM. The purpose column is a free-form string — pick whatever taxonomy fits your project.

// Fastify
import { setServiceConfig, getServiceConfig } from "./lib/service-config.js";
await setServiceConfig(prisma, "smtp", { host, port, user, password });
const cfg = await getServiceConfig<{ host: string }>(prisma, "smtp");
# FastAPI
from src.entities.service_config._repository import ServiceConfigRepository
repo = ServiceConfigRepository(session)
await repo.set_config('smtp', {'host': ..., 'port': 587})
cfg = await repo.get_config('smtp')

Encryption key resolves from CRED_ENCRYPTION_KEY (32-byte base64). If absent, derived from JWT_SECRET for development. Set an explicit key in production. Reads are cached in-memory for 10 minutes; invalidate(purpose) clears.

Rate Limiting

The Fastify backend ships with @fastify/rate-limit registered globally. Defaults: 200 requests per minute per user (or per IP for unauthenticated requests). Tune via RATE_LIMIT_MAX and RATE_LIMIT_WINDOW in .env.

Override per route for sensitive endpoints:

fastify.post(
  "/auth/resend-verification",
  {
    config: {
      rateLimit: {
        max: 5,
        timeWindow: "1 hour",
        keyGenerator: (req) => (req.body?.email ?? req.ip).toLowerCase(),
      },
    },
  },
  handler,
);

For the FastAPI service, edge rate limits are enforced by the frontend nginx (auth_limit and api_limit zones in frontend/nginx.conf) — no application-level limiter is wired by default since the service is internal.

Development

Contributing to Projx itself:

git clone https://github.com/ukanhaupa/projx.git
cd projx
./scripts/setup.sh

The CLI lives in cli/. Templates are the root-level component directories (fastapi/, frontend/, etc.).

cd cli
pnpm test       # run tests
pnpm build      # build CLI

Try it now

You're still reading. Stop reading. Run this:

npx create-projx my-app

Pick whatever you need from the menu — backend-only, AI app, mobile, full-stack, just infra. 30 seconds. Free. No signup. If you don't like it, rm -rf my-app and we never speak of this again.


Badge

Add this to your project's README:

[![Built with Projx](https://img.shields.io/badge/Built%20with-Projx-blue)](https://github.com/ukanhaupa/projx)

License

MIT

About

Projx — A CLI tool for scaffolding production-grade projects. Pick your stack (FastAPI, Fastify, React, Flutter), get a fully wired template with auth, database, CI/CD, and E2E tests. Update anytime when templates improve.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors