specgate/docs v0.20.0

The generated project#

forja builds a project from recipes. Each recipe writes one concern: the API, the web app, the database, auth, an extra. The configuration decides which recipes run, and in which order. This page goes through them one by one. Run forja init <name> --yes --dry-run with your flags to see the exact tree.

Node recipes#

They run in this order: base, shared, core-hexagonal, db-postgres-docker or db-none, web, mobile, auth-sessions or auth-none, mailer-console, design-tailwind, e2e-web, extras-lint, ci, specgate. Each one runs only when the configuration asks for it.

RecipeRuns whenWrites
basealwaysroot package.json (npm workspaces apps/*, packages/*; test and typecheck across them), tsconfig.base.json, .gitignore, .editorconfig, README.md, docs/architecture.md, forja.config.json
sharedalwayspackages/shared: API types and zod validation shared by web and mobile
core-hexagonalalwayspackages/core: domain, auth use cases, ports, in-memory adapters, bcrypt, clock, logger, container.ts, env.ts; unit tests with unit
db-postgres-dockerdb: postgres-dockerdocker-compose.yml (PostgreSQL 16), drizzle.config.ts, the Drizzle schema and repositories, db:push and db:studio scripts, DATABASE_URL
db-nonedb: nonenothing: the in-memory repositories are enough
webweb in platformsapps/web: Next.js App Router, layout, home page; root dev and build scripts
mobilemobile in platformsapps/mobile: Expo Router, app.config.ts, Babel and Metro config; root mobile script; EXPO_PUBLIC_API_URL
auth-sessionsauth: sessionsweb: login, register, forgot and reset password pages, Server Actions, proxy.ts, a dashboard; with mobile, the /api/auth/* route handlers and the mobile screens; integration tests with integration; SESSION_TTL_DAYS
auth-noneauth: nonenothing
mailer-consoleauth is not noneConsoleMailer and InMemoryMailer in packages/core
design-tailwinddesign: tailwinddesign tokens in packages/shared/src/design; Tailwind 4 on the web; NativeWind with Tailwind 3 on mobile
e2e-webe2e-web in testsPlaywright in apps/web; see End-to-end tests
extras-lintlint in extraseslint.config.mjs, .prettierrc.json, a lint script
cici in extras.github/workflows/ci.yml
specgatespecgate in extrasdocs/brief.md, docs/specgate.md, the Specgate dependency and scripts; see forja and Specgate

The environment variables the recipes declare are collected in one root .env.example, grouped by recipe: APP_URL, DATABASE_URL, SESSION_TTL_DAYS and EXPO_PUBLIC_API_URL, depending on the choices.

The Node tree#

text
apps/
  web/            Next.js 16 (built with --webpack), proxy.ts, (auth) and (app) route groups
  mobile/         Expo SDK 57, Expo Router, (auth) and (app) screens, lib/auth.tsx, lib/api.ts
packages/
  core/
    src/domain/          entities/User, value-objects/Email and Password, events, services, shared/Result
    src/application/     auth/: Register, Login, CreateSession, ValidateSession, Logout,
                         RequestPasswordReset, ResetPassword
    src/ports/           IUserRepository, ISessionRepository, IPasswordResetTokenRepository,
                         IPasswordHasher, IMailer, IClock, ILogger
    src/infrastructure/  clock/, config/ (container.ts, env.ts), database/, logging/, mail/, security/
    tests/unit/, tests/integration/
  shared/
    src/api/, src/validation/, src/design/

Java recipes#

They run in this order: base, api-spring or api-quarkus, compose, keycloak, then with a web app shared, web-java, design-tailwind and e2e-web, and last the extras in the order you listed them: extras-lint (with a web app only), ci, docker-java, specgate.

RecipeRuns whenWrites
basealwaysroot package.json with dev:api, test:api and, with web, dev:web, test:web; README.md, docs/architecture.md, .gitignore, forja.config.json
api-spring / api-quarkusthe backendapps/api: Maven Wrapper, pom.xml, the shared and tasks modules, tests; the PostgreSQL or in-memory adapter; the OAuth2 or no-auth security; ArchitectureTest with archunit
composedb: postgres-docker or auth: oauth2docker-compose.yml with PostgreSQL 17 and/or Keycloak 26.8
keycloakauth: oauth2infra/keycloak/<name>-realm.json
sharedweb in platformspackages/shared: the API's types for the web app
web-javaweb in platformsapps/web: Next.js 16, the tasks pages, a server-only API client; with OAuth2, Auth.js and its route; .env.example and a ready .env.local
design-tailwindweb and design: tailwindTailwind 4 and design tokens
e2e-webweb and e2e-web in testsPlaywright in apps/web
extras-lintweb and lint in extrasESLint and Prettier for the TypeScript side
cici in extras.github/workflows/ci.yml with an api job (./mvnw -B verify) and a web job
docker-javadocker in extrasapps/api/Dockerfile and .dockerignore; with web, apps/web/Dockerfile
specgatespecgate in extrasas on Node

Java backends shows the Java tree and how to run it.

Versions#

The versions forja pins, as written in the recipes and templates:

PieceVersion
Next.js^16.4.0
React (Node path: root, web and mobile)19.2.3, the version Expo SDK 57 pins
React (Java web app)^19.3.0
Expo SDK~57.0.28, with React Native 0.86.3 and Reanimated 4.5.1
TypeScript (Node path)~6.0.3
TypeScript (Java web app)^5.9.3
zod / vitest^4.6.7 / ^5.0.4
Drizzle ORM / drizzle-kit / postgres.js^0.45.4 / ^0.31.11 / ^3.4.9
Tailwind (web) / NativeWind with Tailwind (mobile)^4.3.3 / ^4.2.7 with ^3.4.17
ESLint / Prettier^10.12.0 / ^3.6.2
Auth.js (next-auth)5.0.0-beta.32
Playwright~1.63.0
Spring Boot / springdoc4.1.1 / 3.1.1
Quarkus3.40.1
ArchUnit1.5.1
Java21
PostgreSQL image16-alpine (Node), 17-alpine (Java)
Keycloak image26.8
Specgate^0.19.1

How it is written#

Recipes write to an in-memory file system. When all of them have run, forja formats the TypeScript, JavaScript, JSON, CSS and Markdown files with Prettier, and only then writes to disk. A failure part way through leaves nothing behind, and --dry-run prints that same in-memory tree.

Contributing explains how a recipe is written.