Skip to content
Public template

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

4 Commits

Folders and files

Repository files navigation

RaineStack

A modern, production-ready full-stack TypeScript monorepo starter built with Bun, Turborepo, Prisma, and React.

Bun TypeScript Prisma React


⚑️ Quick Start

# Install dependencies
bun install

# Start PostgreSQL (Docker)
bun run db:start
bun run db:dev

# Start all dev servers
bun run dev

Visit http://localhost:3024 to see your app!


πŸš€ What's Included

This starter provides a complete, opinionated stack with everything you need to build modern web applications:

Backend

  • ⚑️ Bun 1.3.9 β€” Fast runtime, package manager, and HTTP server
  • πŸ—„οΈ PostgreSQL 18.1 + Prisma 7.3 β€” Type-safe database with migrations
  • πŸ”Œ oRPC β€” Contract-first APIs with auto-generated OpenAPI spec
  • πŸ“ Audit Trail β€” Automatic change tracking with actor attribution
  • πŸ”” Real-time β€” LISTEN/NOTIFY for cross-instance awareness
  • ⏰ Scheduled Jobs β€” pg_cron for automatic cleanup

Frontend

  • βš›οΈ React 19.2 + Vite 7.3 β€” Modern UI with React Compiler
  • 🎨 shadcn/ui β€” 50+ beautiful, accessible components
  • 🎯 React Router 7 β€” Type-safe routing with loaders
  • πŸ“Š TanStack Query 5 β€” Powerful data fetching and caching
  • πŸ“– Fumadocs β€” Beautiful MDX documentation rendering
  • πŸŒ™ Dark Mode β€” Built-in theme system
  • πŸ“± Responsive β€” Mobile-first design

Developer Experience

  • πŸ“¦ Turborepo β€” Cached builds and parallel execution
  • πŸ”’ TypeScript 5.9.3 β€” Strict mode, full type safety
  • ✨ Biome β€” Fast formatting and linting
  • πŸ§ͺ Bun Test β€” Built-in test runner
  • πŸ”§ Path Aliases β€” Clean imports across packages

Authentication

  • πŸ” JWT Tokens β€” Access (15m) + refresh (30d) with rotation
  • πŸ“§ OTP β€” Email-based passwordless authentication
  • πŸ”‘ OIDC β€” Google and GitHub social login
  • πŸ”’ WebAuthn β€” Hardware-backed passkeys
  • πŸ‘€ Actor Tracking β€” Know who made every change

πŸ“ Project Structure

packages/
β”œβ”€β”€ tools/        # Shared utilities (tryCatch, Temporal, prototypes)
β”œβ”€β”€ tsconfig/     # Shared TypeScript configurations
β”œβ”€β”€ database/     # Prisma schema, migrations, audit infrastructure
β”œβ”€β”€ server/       # Bun HTTP server with oRPC API
β”œβ”€β”€ api/          # Type-safe API client for frontend
β”œβ”€β”€ ui/           # shadcn/ui component library
β”œβ”€β”€ web/          # Main application (micro-frontend)
└── docs/         # Documentation site (Fumadocs + MDX)
    └── public/
        └── content/  # MDX documentation files go here

πŸ”§ Available Commands

Development

bun run dev         # Start all packages in development mode
bun run build       # Build all packages for production
bun run typecheck   # Type-check all packages
bun run lint        # Lint all packages with Biome
bun run format      # Format all files with Biome

Database

bun run db:start    # Start PostgreSQL via Docker Compose
bun run db:dev      # Run migrations + apply triggers (development)
bun run db:deploy   # Run migrations + apply triggers (production)

πŸ—οΈ Tech Stack

Layer Technology
Runtime Bun 1.3.9
Monorepo Turborepo with Bun workspaces
Language TypeScript 5.9.3 (strict mode)
Backend Bun HTTP server, oRPC, Pino logging
Database PostgreSQL 18.1, Prisma 7.3 (@prisma/adapter-pg)
Frontend React 19.2, Vite 7.3, React Router 7, TanStack Query 5
UI shadcn/ui (base-vega), Tailwind CSS 4.1, Lucide icons
Auth JWT (jose), OTP, OIDC (Google/GitHub), WebAuthn passkeys
Linting Biome 2.3 (formatting + linting)
Validation Zod 4.1
Date/Time Temporal API via temporal-polyfill

🌟 Key Features

Type Safety Everywhere

// Define API once
export const getUser = authedProcedure
  .input(z.object({ id: z.string() }))
  .output(UserSchema)
  .handler(async ({ input, context }) => {
    return usersData.findById(context.db, input.id);
  });

// Use with full type safety
const user = await api.users.getUser({ id: '123' });
//    ^? User (fully typed!)

Actor-Tracked Transactions

Every database mutation knows who made it:

await withActor(db, userId, async (tx) => {
  return tx.post.create({ data });
});
// Automatically logged in audit.change_log

Real-Time Database Subscriptions

import { listener } from '@rainestack/database';

listener.on('post', (event) => {
  console.log(`Post ${event.operation}:`, event.id);
  // Invalidate caches, broadcast to WebSocket clients, etc.
});

Beautiful UI Components

import { Button } from '@rainestack/ui/components/ui/button';
import { Card } from '@rainestack/ui/components/ui/card';
import { useTheme } from '@rainestack/ui/providers/theme';

<Button variant="default">Click me</Button>

Error Handling with tryCatch

import { tryCatch } from '@rainestack/tools/try-catch';

const { data, error } = await tryCatch(fetchUser(id));
if (error) return handleError(error);

console.log(data.name); // fully typed, no try/catch blocks

πŸ“ Environment Variables

Create a .env file in the root:

# Required
DATABASE_URL=postgresql://dev_user:dev_password@localhost:5432/dev_db
JWT_SECRET=your-super-secret-key-at-least-32-characters-long

# Optional - OIDC Providers
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

# Optional - WebAuthn
RP_ID=localhost
RP_NAME=RaineStack
RP_ORIGIN=http://localhost:3000

Generate a secure JWT_SECRET:

# Using openssl
openssl rand -base64 32

# Using Bun
bun -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

🎨 Customization

This is a starter template β€” make it your own:

1. Replace Example Models

The Post model is just a placeholder. Replace it with your domain models:

// packages/database/prisma/schema.prisma
model YourModel {
  id        String   @id @default(cuid())
  // Your fields here
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Then create a migration:

cd packages/database
bunx --bun prisma migrate dev --name add_your_model

2. Customize the UI Theme

Edit Tailwind CSS variables in packages/ui/src/styles/theme.css:

:root {
  --primary: 240 5.9% 10%;        /* Your brand color */
  --primary-foreground: 0 0% 98%;
  /* ... */
}

3. Add Your Domain Logic

  • Data Layer: packages/server/src/data/ β€” Database operations
  • Routes: packages/server/src/routes/ β€” API endpoints
  • Components: packages/web/src/components/ β€” UI components
  • Pages: packages/web/src/routes/ β€” Application pages

4. Configure Authentication

Choose which auth methods you need by setting environment variables. Remove unused providers from packages/server/src/routes/auth.ts.

5. Update Documentation

Replace the docs content in packages/docs/src/app.tsx with your own documentation.


🚒 Deployment

Build for Production

# Build all packages
bun run build

# Run migrations
bun run db:deploy

# Start server
cd packages/server
bun run dist/index.js

Set STATIC_DIR environment variable to the directory containing built frontend assets.


πŸ“– Documentation

When you run bun run dev, documentation is available at:

Adding Documentation Pages

Create MDX files in packages/docs/public/content/:

---
title: Your Page Title
description: Page description
---

# Your Page Title

Your content here with full MDX support!

For detailed project rules and architecture, see AGENTS.md.


πŸ› οΈ Key Conventions

Dependency Management

All dependencies MUST be in the catalog with exact versions:

// Root package.json
{
  "workspaces": {
    "catalog": {
      "some-package": "1.2.3"  // Exact version, no ^ or ~
    }
  }
}

// Package package.json
{
  "dependencies": {
    "some-package": "catalog:"
  }
}

Database Operations

Always use withActor() for mutations:

// βœ… Correct
await withActor(db, userId, async (tx) => {
  return tx.post.create({ data });
});

// ❌ Wrong
await db.post.create({ data });  // No audit trail!

UI Components

Always check @rainestack/ui before creating new components:

// βœ… Use existing components
import { Button } from '@rainestack/ui/components/ui/button';

// Import from subpaths for tree-shaking
import { Card } from '@rainestack/ui/components/ui/card';

Error Handling

Prefer tryCatch over try/catch:

// βœ… Type-safe error handling
const { data, error } = await tryCatch(operation());
if (error) return handleError(error);

// ❌ Traditional try/catch
try {
  const data = await operation();
} catch (error) {
  handleError(error);
}

πŸ“œ License

MIT License - see LICENSE for details.


πŸ™ Built With

  • Bun β€” Fast all-in-one JavaScript runtime
  • Turborepo β€” High-performance monorepo build system
  • Prisma β€” Next-generation ORM
  • oRPC β€” Contract-first RPC framework
  • shadcn/ui β€” Beautifully designed components
  • Temporal API Polyfill β€” Modern date/time

⭐️ Star this repo if you find it useful!

GitHub β€’ Issues β€’ Documentation

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages