A modern Next.js application with database, testing, and AI-powered tools built-in.
✨ Next.js 16 - Latest React framework with App Router 🗄️ Database Ready - Drizzle ORM + SQLite/Turso with migrations 🧪 Testing Suite - Vitest (unit) + Playwright (E2E) + b-test (database testing) 🤖 AI Integration - Vercel AI SDK with OpenAI support ⚡ Bun - Fast package manager and runtime 📝 TypeScript - Full type safety 🎨 Tailwind CSS - Utility-first styling
- Next.js 16.0.0 - React framework with App Router
- React 19.2.0 - Latest React with concurrent features
- TypeScript 5 - Type-safe development
- Tailwind CSS 4 - Utility-first CSS framework
- Bun - Fast JavaScript runtime and package manager
- Drizzle ORM 0.44.7 - Type-safe SQL ORM
- LibSQL/SQLite - Embedded database for development/testing
- Turso - Serverless database for production (optional)
- Vitest 4 - Fast unit testing framework
- Playwright 1.56 - End-to-end browser testing
- b-test - Custom database testing library (PreDB/PostDB)
- Tester - AI-powered browser testing utilities
- Vercel AI SDK 5.0 - AI integration toolkit
- OpenAI SDK - GPT models for AI features
- glob 11.0 - File pattern matching
- Bun v1.0.0 or higher
- Node.js 18+ (for Next.js compatibility)
# Clone the repository
git clone https://github.com/yourusername/opg.git
cd opg
# Install dependencies
bun install
# Set up environment variables
cp .env.example .env
# Initialize the database
bun run db:generate # Generate migrations
bun run db:push # Apply schema to development DB
# (Optional) Seed with sample data
bun run db:seed# Start development server
bun run devOpen http://localhost:3000 to view the application.
# Create production build
bun run build
# Start production server
bun run startThis project uses a Rails-style migration system:
- Single
db/migrations/folder for all environments - Migrations run against dev, test, and production databases
- Tests use in-memory SQLite (
:memory:) for speed and isolation
| Environment | Database | Location |
|---|---|---|
| Development | SQLite | file:./db/databases/development.db |
| Test | In-Memory SQLite | :memory: (fresh for each test run) |
| Production | Turso | libsql://your-database.turso.io |
# Schema Management
bun run db:push # Push schema changes (development only)
bun run db:generate # Generate migration files
bun run db:migrate # Apply migrations to database
# Database Tools
bun run db:studio # Open Drizzle Studio (visual editor)
bun run db:seed # Populate with seed data
bun run db:clean # Clear all data from database
bun run db:reset # Clean + push schema (fresh start)# 1. Update schema in db/schema.ts
# 2. Generate migration
bun run db:generate
# 3. Review generated SQL in db/migrations/
cat db/migrations/0001_*.sql
# 4. Apply to development database
bun run db:push
# 5. Tests automatically use in-memory DB with migrations
bun run testbun run test # Run all unit testsFeatures:
- In-memory SQLite for isolated database tests
- Automatic schema migration before tests
- Database cleanup between tests
- Sequential test execution with
singleFork: true
bun run spec # Run Playwright testsFeatures:
- Browser automation (Chromium, Firefox, WebKit)
- Auto-starts Next.js dev server
- Visual testing capabilities
- Screenshot/video recording on failure
The b-test library provides utilities for deterministic database testing:
import { db } from '@/db';
import { user } from '@/db/schema';
import { predb, postdb } from '@/lib/b-test';
test('user creation', async () => {
// Setup: Define initial database state
await predb(db, {
users: []
});
// Action: Your code that modifies the database
await db.insert(user).values({
name: 'Alice',
email: 'alice@example.com'
});
// Assert: Verify final database state
await postdb(db, {
users: [
{ name: 'Alice', email: 'alice@example.com' }
]
});
});See lib/b-test/README.md for full documentation.
.
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout
│ └── page.tsx # Homepage
├── db/
│ ├── databases/ # SQLite files (gitignored)
│ ├── migrations/ # Migration SQL files
│ │ └── meta/ # Migration metadata
│ ├── scripts/ # Database utilities
│ │ ├── clean.ts # Clear database
│ │ ├── seed.ts # Seed data
│ │ └── squash.ts # Migration squashing
│ ├── schema.ts # Database schema
│ └── index.ts # Database client
├── lib/
│ └── b-test/ # Database testing library
│ ├── predb.ts # Setup database state
│ ├── postdb.ts # Assert database state
│ ├── tester.ts # AI-powered browser testing
│ └── tests/ # b-test test suite
├── tests/
│ ├── example.spec.ts # Playwright tests
│ ├── example.test.ts # Vitest tests
│ └── db-memory.test.ts # Database integration tests
├── public/ # Static assets
├── drizzle.config.ts # Drizzle ORM configuration
├── vitest.config.ts # Vitest configuration
├── vitest.setup.ts # Test setup & DB migration
└── playwright.config.ts # Playwright configuration
Create a .env file in the root directory:
# Development Database
DATABASE_URL_DEVELOPMENT="file:./db/databases/development.db"
# Test Database (in-memory for speed)
DATABASE_URL_TEST=":memory:"
# Production Database (Turso - optional)
# DATABASE_URL_PRODUCTION="libsql://your-database.turso.io"
# TURSO_AUTH_TOKEN="your-auth-token"
# OpenAI API (for AI features)
# OPENAI_API_KEY="sk-..."bun run dev- Start development server (http://localhost:3000)bun run build- Create production buildbun run start- Start production serverbun run lint- Run ESLint
bun run db:push- Push schema to database (dev only)bun run db:studio- Open Drizzle Studiobun run db:generate- Generate migrationsbun run db:migrate- Run migrationsbun run db:seed- Seed databasebun run db:clean- Clear databasebun run db:reset- Reset database (clean + push)
bun run test- Run unit tests (Vitest)bun run spec- Run E2E tests (Playwright)
-
Always generate migrations for schema changes:
bun run db:generate
-
Review generated SQL before applying:
cat db/migrations/XXXX_migration_name.sql
-
Test migrations work correctly:
bun run test -
Commit migrations to version control
- Use PreDB to set up initial state
- Run your database operations
- Use PostDB to verify final state
- Tests automatically use fresh in-memory database
The test environment uses SQLite's :memory: mode for optimal performance:
- Fast: Database runs entirely in RAM
- Isolated: Each test run gets a fresh database
- Automatic: Migrations apply automatically via
vitest.setup.ts - Clean: Database resets between tests via
beforeEachhook
This project uses Bun exclusively:
- ✅
bun.lock- Committed to git - ❌
package-lock.json- Gitignored (npm) - ❌
yarn.lock- Gitignored (yarn) - ❌
pnpm-lock.yaml- Gitignored (pnpm)
Always use bun add/remove for dependencies.
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateText({
model: openai('gpt-4o'),
prompt: 'Explain quantum computing in simple terms',
});
console.log(result.text);Add your OpenAI API key to .env:
OPENAI_API_KEY="sk-..."The AI SDK automatically reads from OPENAI_API_KEY.