- Add comprehensive project overview and core philosophy - Document file structure reference for the codebase - Create key files reference table for task-specific guidance - Include multi-tenant guidelines and site resolution flow
9.0 KiB
The Collective Hub — Copilot Instructions
Project Overview
The Collective Hub is a reusable SvelteKit website template system for launching branded landing pages for online theater hosts, watch-party communities, and Discord communities. One codebase → multiple deployed sites → one shared database + CDN.
Core philosophy: One codebase, multiple sites, no data leaks, maintainable by one person.
File Structure Reference
.github/
instructions/ ← Development guidelines for The Collective Hub
multi-tenant-architecture.instructions.md
database-schema.instructions.md
auth-and-roles.instructions.md
deployment-guide.instructions.md
admin-panel.instructions.md
cdn-and-assets.instructions.md
public-site-theming.instructions.md
api-route-patterns.instructions.md
testing-multi-tenant.instructions.md
bits-ui.instructions.md
components.instructions.md
icons.instructions.md
server-ts.instructions.md
svelte-ts.instructions.md
svelte5.instructions.md
tailwindcss.instructions.md
testing.instructions.md
prompts/ ← Scaffolding templates for routes, components, API, DB
new-route.prompt.md
generate-component-test.prompt.md
generate-api-endpoint.prompt.md
generate-admin-page.prompt.md
generate-db-migration.prompt.md
generate-svelte-component.prompt.md
generate-seed-data.prompt.md
test-coverage.prompt.md
workflows/ ← CI/CD and release automation
docs/ ← Architecture, database, roadmap, environment docs
src/ ← SvelteKit application
Key Files to Read When Working on Specific Tasks
| When working on... | Read this first |
|---|---|
| Understanding site resolution, data scoping, deployment model | multi-tenant-architecture.instructions.md |
| Database queries, schema changes, migrations | database-schema.instructions.md |
| Authentication, Discord OAuth, role-based access | auth-and-roles.instructions.md |
| Deploying a new site, Docker, Coolify setup | deployment-guide.instructions.md |
| Admin panel pages, auth guards, form actions | admin-panel.instructions.md |
| CDN storage, image upload, asset management | cdn-and-assets.instructions.md |
| Public landing page, theming, CSS custom properties | public-site-theming.instructions.md |
| API route conventions, validation, site scoping | api-route-patterns.instructions.md |
| Writing tests with multi-tenant mocking patterns | testing-multi-tenant.instructions.md |
| SvelteKit server-side code, Drizzle queries, form actions | server-ts.instructions.md |
| Svelte 5 runes, snippets, component patterns | svelte5.instructions.md |
| Tailwind CSS v4 styling | tailwindcss.instructions.md |
| Vitest + Playwright testing patterns | testing.instructions.md |
Multi-Tenant Guidelines
Site Resolution Flow
Request → hooks.server.ts (reads SITE_SLUG) → site-resolver.ts (queries DB by slug)
→ locals.site / locals.siteSettings → app renders with site context
Data Scoping Rule
Every table that owns site data must have a siteId column. Every query must filter by it.
// ✅ Always filter by siteId
const items = await db
.select()
.from(events)
.where(and(eq(events.siteId, locals.site.id), eq(events.isPublished, true)));
CDN Key Rule
Store CDN keys (paths) in the database, never full URLs.
// Database stores: "sites/bad-movies-theater/logo.webp"
// Use cdnUrl() to get the full URL:
const url = cdnUrl(settings.branding.logoCdnKey);
Auth Flow
OWNER_DISCORD_ID— bootstraps the site owner on first loginSUPER_ADMIN_DISCORD_IDS— comma-separated, grants cross-site access- Roles:
owner>admin>editor
Tech Stack Instructions
The web application is a SvelteKit project with TypeScript, PostgreSQL, Drizzle ORM, Better Auth, Tailwind CSS v4, Vitest, and Playwright. When generating or modifying code, read the relevant instruction file for detailed conventions.
| File | Purpose |
|---|---|
multi-tenant-architecture.instructions.md |
Site resolution, data scoping, deployment model, env vars |
database-schema.instructions.md |
All tables, relationships, indexes, migration strategy |
auth-and-roles.instructions.md |
Better Auth, Discord OAuth, role system, super admin |
deployment-guide.instructions.md |
Coolify multi-deploy, Docker, migration runner, env setup |
admin-panel.instructions.md |
Admin layout, auth guards, form patterns, admin pages |
cdn-and-assets.instructions.md |
CDN helpers, image upload, webp conversion, URL construction |
public-site-theming.instructions.md |
SSR-only landing page, CSS custom properties, theme presets |
api-route-patterns.instructions.md |
API route conventions, asset upload, event CRUD, validation |
testing-multi-tenant.instructions.md |
Multi-tenant test patterns, mocking site context, auth testing |
bits-ui.instructions.md |
Bits UI headless component patterns |
components.instructions.md |
Svelte 5 component architecture |
icons.instructions.md |
Lucide icon usage guidelines |
server-ts.instructions.md |
SvelteKit server-side TypeScript patterns |
svelte-ts.instructions.md |
Svelte 5 .svelte.ts reactive module patterns |
svelte5.instructions.md |
Svelte 5 runes, snippets, migrations |
tailwindcss.instructions.md |
Tailwind CSS v4 configuration |
testing.instructions.md |
Vitest + Playwright base testing patterns |
Hard Rules
-
Always filter by
siteId. Every Drizzle query on site-owned data must include asiteIdfilter. Missing this is the most common multi-tenant bug and causes data leaks between sites. -
Store CDN keys, not full URLs. Database fields store paths like
sites/{slug}/logo.webp. ThecdnUrl()helper constructs full URLs usingCDN_BASE_URL. Never store a full URL in the database. -
One deployment runs migrations. Only the deployment with
RUN_MIGRATIONS=trueruns database migrations. Deploy this one first when schema changes are included in a release. -
No site-specific conditional logic. Never write
if (site.slug === 'some-site'). All per-site differences come from database settings. If a site genuinely needs a unique feature, build it as a configurable option for all sites. -
Never commit
.envfiles. Environment variables are configured per-deployment in Coolify. The.envfile is in.gitignoreand must never be committed. -
Use
$libaliases, not relative paths. Always import from$lib/server/db,$lib/components/, etc. Never use relative imports like../../lib/server/db. -
Co-locate tests. Test files go next to the source they test. Server tests use
.test.ts, browser component tests use.svelte.test.ts. -
No
svelte-ignoresuppression comments. All accessibility and type issues must be fixed properly. Never hide a warning behind a suppression comment. -
Prefer additive migrations. In production, add new columns and tables. Avoid destructive operations (ALTER DROP, RENAME). JSON settings columns reduce migration frequency.
-
Respect the phase roadmap. Phase 1 must be fully working (public site + admin login + settings save) before Phase 2. A working simple site is more valuable than a half-built complex one.