A Turborepo monorepo with Elysia backend and Vite React frontend.
elysia-monorepo/
├── apps/
│ ├── backend/ # Elysia + Drizzle ORM backend
│ └── web/ # Vite + React frontend
├── packages/
│ └── typescript-config/ # Shared TypeScript configurations
├── turbo.json # Turborepo configuration
└── package.json # Root package.json
- Framework: Elysia.js
- Database: PostgreSQL with Drizzle ORM
- Auth: JWT authentication
- Validation: drizzle-typebox
- Linting: oxlint
- Runtime: Bun
- Framework: React 19
- Build Tool: Vite
- Language: TypeScript
- Port: 3000
- Bun >= 1.3.6
- PostgreSQL (for backend)
- Docker (optional, for containerized DB)
-
Install dependencies:
cd elysia-monorepo npm i -
Setup backend environment:
cd apps/backend cp .env.example .env # Edit .env with your database credentials
-
Start PostgreSQL (using Docker):
cd apps/backend docker-compose up -d -
Run migrations:
cd apps/backend bun run db:migrate
bun run devThis starts:
- Backend on
http://localhost:8000 - Frontend on
http://localhost:3000
Backend only:
turbo run dev --filter=@repo/backendFrontend only:
turbo run dev --filter=@repo/webbun run dev- Start all apps in development modebun run build- Build all appsbun run lint- Lint all appsbun run type-check- Type check all appsbun run clean- Clean all build artifacts
bun run dev- Start development serverbun run build- Build for productionbun run start- Start production serverbun run db:generate- Generate Drizzle migrationsbun run db:migrate- Run migrationsbun run db:studio- Open Drizzle Studiobun run lint- Lint with oxlint
bun run dev- Start Vite dev serverbun run build- Build for productionbun run preview- Preview production buildbun run lint- Lint with ESLintbun run type-check- TypeScript type checking
- Runtime: Bun
- Framework: Elysia.js
- Database: PostgreSQL
- ORM: Drizzle ORM
- Validation: drizzle-typebox
- Auth: @elysiajs/jwt
- API Docs: @elysiajs/openapi
- Linter: oxlint
- Framework: React 19
- Build: Vite 7
- Language: TypeScript 5
- Linter: oxlint
- Tool: Turborepo 2.7
- Package Manager: NPM(workspace - frontend) / BUN (backend)
- Parallel execution: Run tasks across packages simultaneously
- Smart caching: Cache build outputs and skip redundant work
- Task dependencies: Define relationships between tasks
- Filtering: Run commands for specific packages
DATABASE_URL=postgres://user:password@localhost:5432/dbname
JWT_SECRET=your-secret-key
JWT_EXPIRES_IN=7d
PORT=3000Backend API documentation is available at:
http://localhost:8000/openapi(openapi UI)
Generate migration:
cd apps/backend
bun run db:generateRun migrations:
cd apps/backend
bun run db:migrateOpen Drizzle Studio:
cd apps/backend
bun run db:studioThe backend includes semantic search capabilities using vector embeddings, allowing users to search tracks by meaning rather than exact keyword matches.
- PostgreSQL + pgvector: Vector storage and similarity search
- Hugging Face Transformers: Local embedding generation
- Model:
sentence-transformers/all-MiniLM-L6-v2(384 dimensions, ~22MB) - Index: HNSW (Hierarchical Navigable Small World) for fast approximate nearest neighbor search
- Track metadata (title, description, genre, artist) is combined and converted into a 384-dimensional vector embedding
- Search queries are similarly converted to embeddings
- PostgreSQL's pgvector extension performs cosine similarity search to find the most relevant tracks
- Hybrid search falls back to keyword matching when vector results are insufficient
-
Enable pgvector extension:
cd apps/backend bun run scripts/setup-pgvector.tsThis script checks for pgvector availability, enables the extension, and creates the necessary column and HNSW index.
-
Backfill embeddings for existing tracks:
cd apps/backend bun run scripts/backfill-embeddings.tsThis generates embeddings for all existing public tracks that don't have embeddings yet.
Search tracks:
GET /search/tracks?q=<query>&limit=20&threshold=0.3
| Parameter | Type | Default | Description |
|---|---|---|---|
q |
string | - | Search query (1-200 characters) |
limit |
integer | 20 | Max results (1-50) |
threshold |
number | 0.3 | Minimum similarity score (0-1) |
Response:
{
"data": [
{
"id": "track_id",
"title": "Track Title",
"description": "Track description",
"genre": "Electronic",
"mainArtist": "Artist Name",
"coverArtUrl": "https://...",
"playCount": 100,
"similarity": 0.85,
"user": { "id": "user_id", "username": "username" },
"likeCount": 10
}
]
}If using Docker, use the pgvector image:
docker run -d -e POSTGRES_PASSWORD=postgres -p 5432:5432 pgvector/pgvector:pg16Or update your docker-compose.yml to use pgvector/pgvector:pg16 instead of the standard PostgreSQL image.
# Build all apps
npm run build
# Start backend in production
cd apps/backend
npm run start
# Preview frontend build
cd apps/web
npm run preview# Backend
bun add <package> --filter=@repo/backend
# Frontend
npm add <package> --filter=@repo/webbun add <package> -DShared TypeScript configurations are in packages/typescript-config:
base.json- Base TypeScript configreact.json- React-specific confignode.json- Node.js/Bun-specific config
MIT