A modern GadgetBot rental service application (inspired by Ratchet & Clank) built with TanStack Start, Effect, Zitadel, and PostgreSQL.
- TanStack Start: Full-stack React framework with SSR/SSG
- TanStack Router: File-based routing
- TanStack Query: Server state management
- oRPC: Type-safe RPC framework with Effect Schema
- Effect: Runtime validation and functional programming
- PostgreSQL: Database with Drizzle ORM
- Better Auth + Zitadel: OAuth 2.0 authentication
- Tailwind CSS v4: Styling with Shadcn components
- Biome: Linting and formatting
Before running this application, ensure you have:
- Node.js 18+ installed
- Docker installed and running (for PostgreSQL and Zitadel)
- Git for version control
npm installCreate a .env file in the project root with the following variables:
# Database Configuration
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/gadgetbot
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
# Zitadel OAuth Configuration
ZITADEL_ISSUER_URL=http://localhost:8080
ZITADEL_CLIENT_ID=your-client-id-here@gadgetbot
# Note: ZITADEL_CLIENT_SECRET not needed when using PKCE
# Better Auth Configuration
BETTER_AUTH_SECRET=changeme-generate-a-random-32-character-secret
BETTER_AUTH_URL=http://localhost:3000
# Optional: Application Settings
VITE_APP_TITLE=GadgetBotGenerate a secure BETTER_AUTH_SECRET:
# Using OpenSSL
openssl rand -base64 32
# Or using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"Start the PostgreSQL container:
npm run docker:upRun migrations and seed data:
npm run db:migrate
npm run db:seedStart the Zitadel container:
npm run zitadel:upWait about 30 seconds for Zitadel to initialize, then configure OAuth:
- Open http://localhost:8080/ui/console
- Sign in with:
[email protected]/Admin123! - Create a new Web application with PKCE authentication
- Copy the Client ID and add it to your
.envfile
For detailed authentication setup instructions, see docs/AUTH_SETUP.md
npm run devThe application will be available at http://localhost:3000
# Start PostgreSQL
npm run docker:up
# Stop PostgreSQL
npm run docker:down
# View PostgreSQL logs
npm run docker:logs
# Generate migrations from schema changes
npm run db:generate
# Apply pending migrations
npm run db:migrate
# Open Drizzle Studio (visual DB manager)
npm run db:studio
# Seed database with sample data
npm run db:seed
# Reset database (drop, migrate, seed)
npm run db:reset# Start Zitadel container
npm run zitadel:up
# Stop Zitadel container
npm run zitadel:down
# View Zitadel logs
npm run zitadel:logs
# Reset Zitadel (fresh start with clean data)
npm run zitadel:resetTest domain operations directly from a Node REPL:
npm run replExample usage:
// Import domain
> const Products = await import('./src/domains/products.js')
// List all gadgetbots
> await Products.GadgetBot.findAll()
// Create a new gadgetbot
> await Products.GadgetBot.create({ name: "CleanBot 3000", type: "cleaning", status: "available" })# Lint code
npm run lint
# Format code
npm run format
# Run all Biome checks
npm run check# Run all tests
npm run test
# Test domain operations
npm run test:domain# Build for production
npm run build
# Clear build cache
npm run build:clear
# Preview production build
npm run servesrc/
├── domains/ # Domain layer (business logic)
│ └── products/ # Product domain (GadgetBot)
├── orpc/ # Type-safe RPC layer
│ └── router/ # API procedures
├── web/ # Web client
│ ├── routes/ # File-based routes
│ ├── components/ # React components
│ └── orpc/ # Web-specific oRPC client
├── db/ # Database layer
│ ├── schema/ # Drizzle table schemas
│ ├── services/ # Database operations
│ └── migrations/ # SQL migrations
├── auth/ # Authentication (Better Auth + Zitadel)
├── cli/ # CLI tools (REPL, scripts)
└── env.ts # Environment variables with validation
- Multi-Client Architecture: Domains are client-agnostic and can be used by web, CLI, and API clients
- Type-Safe APIs: oRPC provides end-to-end type safety from database to client
- Effect Schema: Runtime validation and functional error handling
- File-Based Routing: TanStack Router with automatic route generation
- Authentication: OAuth 2.0 with Zitadel and Better Auth
- Database Migrations: Ecto-like workflow with Drizzle Kit
- Interactive Development: REPL for testing domain operations
This project uses Tailwind CSS v4 with Shadcn components.
# Add a new Shadcn component
pnpx shadcn@latest add button
pnpx shadcn@latest add card
pnpx shadcn@latest add formFor detailed information, see:
- CLAUDE.md - Complete architecture and development guide
- docs/AUTH_SETUP.md - Authentication setup with Zitadel
- docs/AUTH_PATTERNS.md - Authentication development patterns
- IMPLEMENTATION_PLAN.md - Domain-driven design workflow
# Check if PostgreSQL is running
docker ps
# Restart database
npm run docker:down
npm run docker:up
npm run db:migrate# Reset Zitadel with fresh data
npm run zitadel:reset
# Wait 30 seconds for initialization
sleep 30
# Check logs
npm run zitadel:logs# Clear build cache
npm run build:clear
# Reinstall dependencies
rm -rf node_modules package-lock.json
npm installSee docs/AUTH_SETUP.md for detailed troubleshooting steps.