An enhanced open-source starter kit based on Midday with modern database architecture.
Original Website Β·
Issues Β·
What's included Β·
Prerequisites Β·
Getting Started Β·
Architecture Β·
Features
This is an enhanced version of the V1 boilerplate with significant improvements including database decoupling from Supabase, Neon PostgreSQL integration, advanced seeder system, multi-tenancy support, and modern development practices.
- Decoupled from Supabase: Database operations now use Neon PostgreSQL with Drizzle ORM
- Supabase Auth Only: Supabase is now used exclusively for authentication
- Type-safe Database: Full TypeScript support with Drizzle ORM
- Migration System: Robust migration management with Drizzle Kit
- tRPC as BFF: Type-safe API layer implemented as Backend for Frontend within the app
- End-to-end Type Safety: Shared types between client and server
- Integrated Authentication: Seamless auth integration with Supabase
- Optimized for Frontend: API designed specifically for frontend needs
- Laravel-inspired Seeders: Powerful seeder system with faker.js integration
- Batch Operations: Efficient data insertion with transaction support
- Realistic Data: Generate realistic fake data with consistent seeds
- Force Mode: Override protection with
--forceflag
- Organizations Module: Complete multi-tenancy system
- Team Management: Role-based access control (owner, admin, member)
- Invite System: Secure email-based invitation system
- Permission System: Granular permissions per organization
- Bun Package Manager: Faster package management and scripts
- Enhanced Scripts: Automated setup and provisioning
- Better Error Handling: Comprehensive error tracking and logging
- Type Safety: End-to-end TypeScript support
- Cloudflare R2: S3-compatible object storage
- Image Transformations: Real-time image processing with Sharp
- Presigned URLs: Secure upload/download URLs
- File Validation: Type and size validation
- React Components: Ready-to-use upload components
Next.js - Framework
Turborepo - Build system
Biome - Linter, formatter
TailwindCSS - Styling
Shadcn - UI components
TypeScript - Type safety
Neon PostgreSQL - Primary Database
Drizzle ORM - Type-safe ORM
Supabase - Authentication Only
Upstash - Cache and rate limiting
React Email - Email templates
Resend - Email delivery
i18n - Internationalization
Sentry - Error handling/monitoring
Dub - Sharable links
Trigger.dev - Background jobs
OpenPanel - Analytics
Polar - Billing (coming soon)
react-safe-action - Validated Server Actions
nuqs - Type-safe search params state manager
next-themes - Theme manager
tRPC - Type-safe BFF API
Cloudflare R2 - Object Storage
Sharp - Image Processing
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Supabase β β Neon β β Drizzle ORM β
β (Auth Only) β β PostgreSQL β β (Type-safe) β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β β β
β β β
βββββββββββββββββββββββββΌββββββββββββββββββββββββ
β
βββββββββββββββββββ
β Application β
β (Next.js) β
β + tRPC BFF β
βββββββββββββββββββ
.
βββ apps # App workspace
β βββ api # Supabase (Auth, Storage, Edge Functions)
β βββ app # Main application (with tRPC BFF)
β βββ web # Marketing site
β βββ email # Email templates
βββ packages # Shared packages
β βββ analytics # OpenPanel analytics
β βββ database # π Neon + Drizzle ORM
β β βββ src/
β β β βββ schema/ # Database schemas
β β β βββ queries/ # Database queries
β β β βββ mutations/ # Database mutations
β β β βββ seeders/ # π Seeder system
β β β βββ adapters/ # Database adapters
β β βββ migrations/ # Drizzle migrations
β βββ email # React email library
β βββ jobs # Trigger.dev background jobs
β βββ kv # Upstash rate-limited storage
β βββ logger # Logger library
β βββ supabase # Supabase (Auth only)
β βββ storage # π Cloudflare R2 storage
β β βββ src/
β β β βββ client.ts # Client-side storage
β β β βββ server.ts # Server-side R2 storage
β β β βββ components/ # React upload components
β β β βββ utils.ts # Storage utilities
β β βββ types.ts # Storage types
β βββ ui # Shared UI components
βββ scripts # π Setup and automation scripts
β βββ setup-neon.js # Neon database setup
β βββ setup-env.js # Environment setup
β βββ setup-storage.js # Storage setup
β βββ supabase-*.sh # Supabase management
βββ tooling # Shared configurations
βββ docs/ # π Documentation
- Neon PostgreSQL: Serverless PostgreSQL with automatic scaling
- Drizzle ORM: Type-safe database operations
- Migration Management: Version-controlled schema changes
- Seeder System: Laravel-inspired data seeding with faker.js
- Transaction Support: ACID-compliant operations
- Performance Optimization: Indexed queries and batch operations
- Organizations: Complete multi-tenant architecture
- Team Management: Role-based access control
- Invite System: Email-based invitations with tokens
- Permission System: Granular permissions per organization
- Isolation: Data isolation between tenants
- Supabase Auth: OAuth providers (Google, Discord, GitHub)
- Email/Password: Traditional email and password authentication
- Magic Link: Passwordless authentication via email links
- Password Reset: Secure password recovery system
- Session Management: Secure session handling
- Role-based Access: Integration with organization roles
- Email Verification: Secure email verification flow
- Type Safety: End-to-end TypeScript support
- tRPC BFF: Type-safe API layer implemented as Backend for Frontend
- Hot Reload: Fast development experience
- Error Tracking: Comprehensive error monitoring
- Performance Monitoring: Real-time performance insights
- Cloudflare R2: S3-compatible object storage
- Image Transformations: Real-time image processing with Sharp
- Presigned URLs: Secure upload/download URLs
- File Validation: Type and size validation
- React Components: Ready-to-use upload components
- Batch Operations: Multiple file uploads
- Progress Tracking: Real-time upload progress
- Bun - Package manager and runtime
- Docker - For local development
- Neon Account - PostgreSQL database
- Supabase Account - Authentication
- Upstash Account - Redis cache
- Resend Account - Email delivery
- Trigger.dev Account - Background jobs
- Sentry Account - Error tracking
- OpenPanel Account - Analytics
- Cloudflare Account - R2 Object Storage
git clone <your-repo-url>
cd v1-neonbun install# Copy environment files
cp apps/app/env.local.example apps/app/.env.local
cp apps/api/.env.example apps/api/.env
# Setup complete environment
bun run setup:env:complete# Setup Neon database (automated)
bun run setup:neon
# Or manually setup database
bun run db:setup# Setup Cloudflare R2 storage
bun run setup:storage# Start all services
bun dev
# Or start specific services
bun dev:app # Main application
bun dev:web # Marketing site
bun dev:api # API services
bun dev:email # Email templates# Generate migration
bun run db:generate
# Run migrations
bun run db:migrate
# Push schema changes
bun run db:push
# Open Drizzle Studio
bun run db:studio
# Setup database (migrate + seed)
bun run db:setup
# Reset database
bun run db:reset# Run all seeders
bun run seed:run
# Run specific seeders
bun run seed:run users,posts
# List available seeders
bun run seed:list
# Force run (overwrite existing data)
bun run seed:run --force
# Show help
bun run seed:help- database: Runs all seeders in correct order
- users: Creates sample users with realistic data
- posts: Creates sample posts distributed among users
- organizations: Creates sample organizations with members
- example-advanced: Demonstrates advanced faker features
The tRPC API is implemented as a Backend for Frontend (BFF) pattern within the main application:
- Type-safe API: End-to-end TypeScript support between client and server
- Integrated Authentication: Seamless auth integration with Supabase
- Optimized for Frontend: API designed specifically for frontend needs
- Automatic Caching: React Query integration for optimal performance
- Error Handling: Comprehensive error handling with type safety
auth.signUp- Email/password registrationauth.signIn- Email/password loginauth.signOut- User logoutauth.resetPassword- Password reset requestauth.updatePassword- Password update after resetauth.sendMagicLink- Passwordless authenticationauth.sendOtp- Send OTP codeauth.verifyOtp- Verify OTP codeauth.updateProfile- Update user profileauth.changePassword- Change user passwordauth.deleteAccount- Delete user accountauth.getCurrentUser- Get current user dataauth.isAuthenticated- Check authentication status
import { useSignIn, useSignUp, useSendMagicLink } from '@/lib/trpc';
function AuthExample() {
const signIn = useSignIn();
const signUp = useSignUp();
const sendMagicLink = useSendMagicLink();
const handleSignIn = async (email: string, password: string) => {
try {
await signIn.mutateAsync({ email, password });
// Redirect to dashboard
} catch (error) {
console.error('Sign in failed:', error);
}
};
const handleSignUp = async (email: string, password: string, fullName: string) => {
try {
await signUp.mutateAsync({ email, password, fullName });
// Show email confirmation message
} catch (error) {
console.error('Sign up failed:', error);
}
};
const handleMagicLink = async (email: string) => {
try {
await sendMagicLink.mutateAsync({ email });
// Show magic link sent message
} catch (error) {
console.error('Magic link failed:', error);
}
};
}import { usePosts, useCreatePost } from '@/lib/trpc';
function PostsPage() {
const { data: posts, isLoading } = usePosts({
search: 'react',
page: 1,
limit: 10
});
const createPost = useCreatePost();
const handleCreate = async (data) => {
try {
await createPost.mutateAsync(data);
} catch (error) {
if (error.data?.code === 'UNAUTHORIZED') {
console.log('User needs to login');
}
}
};
return (
<div>
{posts?.data.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}apps/app/src/lib/trpc/
βββ client.ts # tRPC client configuration
βββ provider.tsx # React Query provider
βββ hooks.ts # Custom hooks for API calls
βββ types.ts # Shared types
βββ context.ts # Server context (auth, etc.)
βββ server.ts # Server exports (routers)
βββ routers/
βββ posts.ts # Posts API routes
βββ organizations.ts # Organizations API routes
The Storage system provides comprehensive file management with Cloudflare R2:
- Direct Upload: Upload files directly to Cloudflare R2
- Image Transformations: Real-time image processing with Sharp
- Presigned URLs: Secure upload/download URLs
- File Validation: Type and size validation
- React Components: Ready-to-use upload components
- Batch Operations: Multiple file uploads
- Progress Tracking: Real-time upload progress
import { FileUpload } from '@v1/storage/components';
import { createClientStorage } from '@v1/storage/client';
function UploadComponent() {
const clientStorage = createClientStorage({
uploadUrl: '/api/upload',
maxFileSize: 10 * 1024 * 1024, // 10MB
allowedTypes: ['image/*', 'application/pdf']
});
const handleUpload = async (file: File) => {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
return response.json();
};
return (
<FileUpload
onUpload={handleUpload}
accept="image/*"
maxSize={5 * 1024 * 1024} // 5MB
multiple={true}
onUploadComplete={(result) => {
console.log('Upload completed:', result);
}}
/>
);
}import { createR2Storage } from '@v1/storage/server';
const storage = createR2Storage({
accountId: process.env.R2_ACCOUNT_ID!,
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
bucketName: process.env.R2_BUCKET_NAME!,
});
// Upload file
const result = await storage.upload('uploads/image.jpg', fileBuffer, {
contentType: 'image/jpeg',
public: true,
metadata: { userId: '123' }
});
// Generate presigned URL
const presignedUrl = await storage.getPresignedUploadUrl('uploads/file.pdf', {
expiresIn: 3600,
contentType: 'application/pdf'
});The Organizations module provides complete multi-tenancy support:
- Organization Management: CRUD operations for organizations
- Team Management: Add/remove members with roles
- Invite System: Email-based invitations with secure tokens
- Permission System: Role-based access control
- Multi-tenancy: Data isolation between organizations
import { useOrganizations, useCreateOrganization } from '@/lib/trpc';
function OrganizationsPage() {
const { data: organizations } = useOrganizations();
const createOrg = useCreateOrganization();
const handleCreate = async (data) => {
await createOrg.mutateAsync(data);
};
return (
<div>
{organizations?.data.map(org => (
<div key={org.id}>{org.name}</div>
))}
</div>
);
}bun run setup:env # Setup environment variables
bun run setup:env:complete # Complete environment setup
bun run setup:neon # Setup Neon database
bun run setup:webhook # Setup webhooks
bun run setup:storage # Setup Cloudflare R2 storagebun run db:migrate # Run migrations
bun run db:generate # Generate migration
bun run db:push # Push schema changes
bun run db:studio # Open Drizzle Studio
bun run db:setup # Setup database
bun run db:reset # Reset databasebun run seed:run # Run all seeders
bun run seed:list # List seeders
bun run seed:help # Show helpbun run supabase:local # Start local Supabase
bun run supabase:remote # Connect to remote Supabase
bun run supabase:status # Check Supabase statusRequired environment variables for deployment:
# Database
DATABASE_URL=your_neon_database_url
USE_DRIZZLE=true
# Supabase (Auth only)
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
# Email
RESEND_API_KEY=your_resend_api_key
# Redis
UPSTASH_REDIS_REST_URL=your_upstash_url
UPSTASH_REDIS_REST_TOKEN=your_upstash_token
# Analytics
OPENPANEL_SECRET_KEY=your_openpanel_key
NEXT_PUBLIC_OPENPANEL_CLIENT_ID=your_openpanel_client_id
# Error Tracking
SENTRY_AUTH_TOKEN=your_sentry_auth_token
NEXT_PUBLIC_SENTRY_DSN=your_sentry_dsn
SENTRY_ORG=your_sentry_org
SENTRY_PROJECT=your_sentry_project
# Background Jobs
TRIGGER_API_KEY=your_trigger_api_key
TRIGGER_API_URL=https://api.trigger.dev
# Cloudflare R2 Storage
R2_ACCOUNT_ID=your_r2_account_id
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
R2_BUCKET_NAME=your_r2_bucket_name
R2_REGION=auto
R2_ENDPOINT=https://your_account_id.r2.cloudflarestorage.com
## π Documentation
- [Database Seeding](./docs/database-seeding.md)
- [Discord OAuth Setup](./docs/discord-oauth-setup.md)
- [Supabase Environment Setup](./docs/supabase-environment-setup.md)
- [Webhook Setup](./docs/webhook-setup.md)
- [Storage System](./packages/storage/README.md)
## π€ Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request
## π License
This project is licensed under the MIT License - see the [LICENSE](LICENSE.md) file for details.
## π Acknowledgments
- Based on [Midday](https://midday.ai) and the original [V1](https://v1.run) boilerplate
- Enhanced with modern database architecture and development practices
- Built with the latest technologies and best practices
## π Notification System
The application includes a comprehensive notification system with the following features:
### Notification Features
- **Real-time Notifications**: Dropdown in navbar with unread count badge
- **Multiple Types**: Info, success, warning, error, invite, mention
- **Rich Content**: Support for organization and post references
- **Status Management**: Mark as read/unread, archive/unarchive
- **Detailed View**: Modal with full notification details
- **Bulk Actions**: Mark all as read functionality
- **Filtering**: View all, unread, or archived notifications
### Notification Components
```tsx
import { NotificationDropdown, NotificationItem, NotificationDetailModal } from '@/components/notifications';
// Dropdown in navbar
<NotificationDropdown />
// Individual notification item
<NotificationItem notification={notification} onMarkAsRead={handleMarkAsRead} />
// Detail modal
<NotificationDetailModal notification={notification} isOpen={isOpen} onClose={onClose} />// Get notifications with filters
const { data } = useNotifications({ limit: 20, includeRead: false });
// Get unread count
const { data } = useUnreadNotificationsCount();
// Mark as read/unread
const markAsRead = useMarkNotificationAsRead();
const markAsUnread = useMarkNotificationAsUnread();
// Archive/unarchive
const archive = useArchiveNotification();
const unarchive = useUnarchiveNotification();
// Delete notification
const deleteNotification = useDeleteNotification();/notifications- Full notifications management page- Navbar dropdown - Quick access to recent notifications
notifications (
id: uuid PRIMARY KEY,
userId: uuid REFERENCES users(id),
title: text NOT NULL,
message: text NOT NULL,
type: text NOT NULL,
isRead: boolean DEFAULT false,
isArchived: boolean DEFAULT false,
organizationId: uuid REFERENCES organizations(id),
postId: uuid REFERENCES posts(id),
metadata: jsonb,
createdAt: timestamp DEFAULT now(),
updatedAt: timestamp DEFAULT now(),
readAt: timestamp
)The application includes a comprehensive profile management system with the following features:
- Profile Information: Edit name, bio, website, location, avatar URL
- Security Settings: Change password with current password verification
- Account Management: Delete account with confirmation dialog
- User Overview: Display account statistics and metadata
import { ProfileForm, ChangePasswordForm, DeleteAccountForm } from '@/components/profile';
// Profile editing form
<ProfileForm />
// Password change form with validation
<ChangePasswordForm />
// Account deletion with confirmation dialog
<DeleteAccountForm />- Account Overview: User info, email verification status, member since date
- Profile Tab: Edit personal information and preferences
- Security Tab: Change password with current password verification
- Danger Zone: Delete account with confirmation and warnings
- Quick Actions: Links to dashboard, organizations, and posts
/profile- Main profile management page/dashboard- Dashboard with profile link
// Update profile information
const { mutate: updateProfile } = useUpdateProfile();
// Change password
const { mutate: changePassword } = useChangePassword();
// Delete account
const { mutate: deleteAccount } = useDeleteAccount();- Database Decoupling: Separated database from Supabase, now using Neon PostgreSQL
- Type-safe ORM: Replaced Supabase database with Drizzle ORM
- tRPC BFF: Type-safe API layer implemented as Backend for Frontend within the app
- Advanced Seeder System: Laravel-inspired seeding with faker.js
- Multi-tenancy: Complete organizations module with team management
- Storage System: Cloudflare R2 integration with image transformations
- Notification System: Comprehensive notification system with real-time updates
- Enhanced Scripts: Automated setup and provisioning scripts
- Better DX: Improved development experience with Bun and modern tooling
- Comprehensive Documentation: Detailed docs for all features
- Performance: Optimized database queries and batch operations
- Type Safety: End-to-end TypeScript support with tRPC BFF
- Scalability: Serverless database with automatic scaling
- Security: Enhanced authentication and permission systems
- Storage: S3-compatible object storage with image processing
- Notifications: Real-time notification system with rich content support
- API Design: BFF pattern for optimized frontend-backend communication
- Maintainability: Better code organization and separation of concerns
This enhanced version maintains all the benefits of the original V1 while adding modern database architecture, type-safe BFF API, multi-tenancy support, comprehensive storage system, and improved development experience! π