A dynamic multi-tenant SvelteKit application that supports unlimited brands/tenants through configuration. This codebase demonstrates a scalable architecture for building SaaS applications with tenant-specific branding, features, and configurations.
- LupinLearn: An AI-powered educational platform for creating lessons, quizzes, and personalized learning experiences
- BSOS (Be Smart On Social): An AI browser extension for social media content generation
The architecture is extensible - you can add new tenants without modifying the core codebase.
- Framework: SvelteKit with Svelte 5
- Styling: Tailwind CSS 4 + DaisyUI 5
- Database: MySQL with Prisma ORM
- Authentication: Better Auth
- AI Services: OpenAI and Anthropic APIs
- Payment: Stripe integration + Lemon Squeezy support
- i18n: Paraglide for internationalization
- Testing: Vitest (unit) + Playwright (integration)
- Build Tools: Vite
Before you begin, ensure you have the following installed:
- Node.js (v18 or higher)
- npm (v9 or higher)
- MySQL (v8.0 or higher)
- Git
git clone <Insert your repository URL here>
cd soloaiversionnpm installCreate a MySQL database for your application:
CREATE DATABASE your_app_name;Copy the example environment file and configure it for your tenant:
# For LupinLearn development
cp .env.example .env.lupinlearn.development
# For BSOS development
cp .env.example .env.bsos.development
# Or create your own tenant
cp .env.example .env.yourtenant.developmentEdit your .env.[tenant].development file and fill in all required values:
- Database credentials (MySQL host, user, password, database name)
- API keys (OpenAI, Anthropic, Stripe, etc.)
- OAuth credentials (Google, Microsoft, Apple)
- Better Auth secrets (generate with:
openssl rand -base64 32)
See .env.example for a complete list of required environment variables.
npx prisma generateSince this is a fresh setup, create your first migration:
npx prisma migrate dev --name initThis will create the database schema from prisma/schema.prisma.
Choose the tenant you want to develop:
# LupinLearn development
npm run dev:lupin
# BSOS development
npm run dev:bsosThe application will be available at http://localhost:5173
├── src/
│ ├── routes/ # SvelteKit routes
│ │ ├── (marketing)/ # Public marketing pages
│ │ ├── app/ # Authenticated app pages
│ │ ├── auth/ # Authentication flows
│ │ └── api/ # API endpoints
│ ├── lib/
│ │ ├── components/ # Shared components
│ │ ├── services/ # Business logic and external integrations
│ │ ├── tenant/ # Multi-tenant configuration
│ │ │ ├── configs/ # Tenant-specific configs
│ │ │ └── registry.ts # Tenant registry
│ │ ├── tenants/ # Tenant-specific components
│ │ └── paraglide/ # Generated i18n files (auto-generated)
│ ├── extension/ # Browser extension code
│ └── chatbot/ # Embeddable chatbot widget
├── prisma/
│ └── schema.prisma # Database schema
├── .env.example # Environment variables template
└── package.json # Dependencies and scripts
The application uses a tenant registry system that automatically discovers and loads tenant configurations:
- Tenant Configs: Each tenant has a configuration file in
src/lib/tenant/configs/ - Environment Files: Each tenant has dedicated environment files (
.env.[tenant-id].development,.env.[tenant-id].production) - Dynamic Loading: The tenant is determined at build time via the
APPenvironment variable - Component Overrides: Tenants can provide custom components in
src/lib/tenants/[tenant-id]/
- Create a tenant config file:
src/lib/tenant/configs/yourtenant.ts
import type { TenantConfig } from '../types';
export const config: TenantConfig = {
id: 'yourtenant',
name: 'yourtenant',
displayName: 'Your Tenant Name',
domain: '<Insert your production domain here>',
contactEmail: '<Insert your contact email here>',
// ... more configuration
};-
Create environment files:
.env.yourtenant.development.env.yourtenant.production
-
Add npm scripts to
package.json:
{
"scripts": {
"dev:yourtenant": "APP=yourtenant npm run dev",
"build:yourtenant": "APP=yourtenant npm run build"
}
}- (Optional) Add custom components:
src/lib/tenants/yourtenant/
Use the tenant store to conditionally render features:
<script>
import { tenant } from '$lib/tenant/store';
</script>
{#if tenant.isTenant('lupinlearn')}
<LupinLearnFeature />
{/if}
{#if tenant.hasFeature('chatbot')}
<ChatbotWidget />
{/if}# Run all tests
npm test
# Unit tests only
npm run test:unit
# Integration tests only
npm run test:integration# Type checking
npm run check
# Linting
npm run lint
# Formatting
npm run format# Build LupinLearn
npm run build:lupin
# Build BSOS
npm run build:bsos
# Build browser extension
npm run build:extension:dev # Development
npm run build:extension:prod # Production
# Build chatbot widget
npm run build:chatbot# Open Prisma Studio (database GUI)
npx prisma studio
# Create a new migration
npx prisma migrate dev --name your_migration_name
# Reset database (WARNING: deletes all data)
npx prisma migrate reset# Generate Paraglide translations
npm run translate-paraglide
# Generate Handsontable translations
npm run translate-handsontableThis project uses Svelte 5 with the new Runes API. Key patterns:
<script>
// Props
let { propName } = $props();
// State
let count = $state(0);
// Derived values
let doubled = $derived(count * 2);
// Effects
$effect(() => {
console.log('Count changed:', count);
});
</script>Avoid legacy Svelte 4 syntax ($:, export let, etc.)
Before deploying, ensure all environment variables are properly configured in your production environment files (.env.[tenant].production).
The repository includes GitHub Actions workflows for automated deployment:
.github/workflows/deploy-lupinlearn.yml.github/workflows/deploy-bsos.yml
Important: Customize the deployment steps in these workflows for your specific server environment.
- Build the project:
npm run build:[tenant-name]-
The built files will be in the
build/directory -
Deploy to your hosting provider (Vercel, Netlify, self-hosted Node.js server, etc.)
- Never commit
.envfiles - they contain sensitive credentials - Use environment variables for all API keys and secrets
- Rotate secrets regularly for production environments
- Enable CORS protection in production
- Keep dependencies updated to patch security vulnerabilities
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
For questions or issues:
- Open an issue on GitHub
- Check the documentation in
CLAUDE.md - Review the
.github/design-guidelines.mdfor design standards
Built with:
Note: This is a template project. Replace all placeholder values (marked with <Insert your ...>) with your actual configuration before deploying to production.