Skip to content

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

effect-stack

An opinionated full-stack TypeScript template built with Effect, React Router Framework, TanStack Query, Drizzle ORM, PostgreSQL, and Better Auth.

Tech stack

  • Effect v4 — backend effects, services, failures, schemas, and structured concurrency
  • React Router 8 Framework Mode + Vite — server rendering, loaders, hydration, and server routes
  • Orval + TanStack Query — an OpenAPI-generated browser and SSR query client
  • shadcn/ui + Tailwind CSS — accessible UI components without application-specific handwritten CSS
  • React 19 — hydrated user interface
  • Drizzle ORM + PostgreSQL — typed persistence
  • Better Auth — same-origin cookie sessions
  • Docker Compose — application services, PostgreSQL, Redis, and S3-compatible storage

Project structure

effect-stack/
├── apps/
│   ├── backend/                 # Effect API, handlers, auth, and database
│   └── frontend/
│       ├── src/routes/          # React Router route modules and API proxy
│       ├── src/components/ui/   # shadcn/ui components generated by its CLI
│       ├── src/generated/       # Orval models and TanStack Query hooks
│       ├── src/components/      # Application UI
│       └── src/lib/             # Auth, localization, fetch, and query runtime
├── packages/api/                # Shared HttpApi contract and OpenAPI document
├── Dockerfile.backend
├── Dockerfile.frontend          # Node.js React Router SSR image
└── compose.production.yaml

Requirements

  • Node.js 24
  • Yarn 4 through Corepack
  • Docker Engine or Docker Desktop
  • Task for the documented workspace commands

Local development

Install dependencies:

corepack enable
yarn install

Start PostgreSQL, Redis, and RustFS, migrate the database, then run the backend and React Router development servers:

task dev

Open http://localhost:5173. The React Router server uses http://localhost:30000 as BACKEND_URL by default. Override it when the backend is elsewhere:

BACKEND_URL=http://localhost:30000 task frontend:dev

Browser authentication and API requests stay on /api. The React Router server proxies that path to BACKEND_URL, so session cookies remain same-origin. Initial todo data is fetched during SSR and dehydrated into the TanStack Query cache; later queries and mutations use the same generated client in the browser.

Useful infrastructure commands:

task infra:config
task dev:status
task dev:logs -- postgres
task dev:stop       # stop containers and preserve volumes
task dev:destroy    # delete development containers and data

API client generation

@effect-stack/api is the source of truth for endpoint paths, schemas, failures, and middleware. It exports openApiDocument from the same Api value implemented by the backend.

Generate the frontend client after changing an API contract:

task frontend:generate

The command writes a temporary OpenAPI JSON document, then Orval regenerates apps/frontend/src/generated/. The generated query functions are used by both React Router loaders and hydrated React components. Do not edit generated files by hand.

The running backend also serves /api/openapi.json and Scalar API documentation at /api/docs.

Frontend conventions

  • Declare routes in apps/frontend/src/routes.ts and implement them under src/routes/.
  • Use Orval-generated TanStack Query hooks and query options; the frontend does not use Effect Atom.
  • Add shadcn/ui components with yarn dlx shadcn@latest add <component> from apps/frontend/.
  • Use shadcn components and Tailwind utilities for layout and presentation. src/app.css is the CLI-generated theme layer; do not add handwritten component CSS.
  • Keep every user-visible string in src/lib/localization.ts. English and Simplified Chinese resources are checked by TypeScript.
  • Keep BACKEND_URL server-only. Browser code must call same-origin /api.

Verification

task typecheck          # type-check every workspace
task test               # API contract and frontend behavior tests
task lint               # lint backend and frontend
task build              # build backend and frontend SSR bundles
task infra:config       # render and validate Compose configuration

The frontend build regenerates its OpenAPI client before compiling, which catches drift between the shared contract and generated code.

Production with Docker Compose

Copy the production example and replace every placeholder:

cp .env.production.example .env.production
docker compose --env-file .env.production -f compose.yaml -f compose.production.yaml config

BETTER_AUTH_URL and BETTER_AUTH_TRUSTED_ORIGINS should both use the public frontend origin, such as https://example.com.

Start dependencies, initialize storage, migrate, and launch the applications:

docker compose --env-file .env.production -f compose.yaml -f compose.production.yaml up -d --wait postgres redis rustfs
docker compose --env-file .env.production -f compose.yaml -f compose.production.yaml run --rm rustfs-setup
docker compose --env-file .env.production -f compose.yaml -f compose.production.yaml run --rm --build migrate
docker compose --env-file .env.production -f compose.yaml -f compose.production.yaml up -d --build --wait backend frontend

The frontend container runs the React Router Node server on port 3000. It performs SSR and forwards /api to the backend through the private Compose network.

Build images directly:

docker build -f Dockerfile.frontend -t effect-stack/frontend .
docker build -f Dockerfile.backend -t effect-stack/backend .
docker build -f Dockerfile.backend --target migrate -t effect-stack/migrate .

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages