name: multi-institution-manager description: | Comprehensive guide for managing multi-institution architecture in JKKN websites. This skill should be used when:
- Adding a new institution to the platform
- Creating or syncing database migrations across institutions
- Setting up Supabase projects for new institutions
- Configuring Vercel deployments for institutions
- Managing environment variables and feature flags
- Troubleshooting multi-institution issues
- Understanding the Single Repository, Multiple Deployments (SRMD) architecture
- Applying database schema to new or existing institution Supabase projects
- Running local development server for a specific institution
Automatically triggers when user mentions: "add institution", "new institution", "sync migrations", "multi-tenant", "setup supabase project", "setup vercel", "institution deployment", "switch institution", "dev:main", "dev:dental", or asks about managing multiple JKKN websites.
Multi-Institution Manager
This skill provides comprehensive guidance for managing the JKKN multi-institution architecture where ONE codebase serves SIX institution websites through separate Supabase and Vercel deployments.
CRITICAL: Institution-Specific MCP Tools
Each Supabase project has its own dedicated MCP server. You MUST use the correct MCP tool prefix for the target institution:
| Institution | Supabase Project ID | MCP Tool Prefix |
|---|---|---|
| Main | pmqodbfhsejbvfbmsfeq |
mcp__Main_Supabase_Project__ |
| Dental College | wnmyvbnqldukeknnmnpl |
mcp__Dental_College_Supabase_Project__ |
| Pharmacy College | rwskookarbolpmtolqkd |
mcp__Pharmacy_College_Supabase_Project__ |
| Engineering College | kyvfkyjmdbtyimtedkie |
mcp__Engineering_College_Supabase_Project__ |
| Arts & Science | TBD | TBD |
| Nursing | TBD | TBD |
Available MCP Tools Per Institution
Each institution's MCP server provides these tools:
mcp__[Institution]_Supabase_Project__list_tables
mcp__[Institution]_Supabase_Project__execute_sql
mcp__[Institution]_Supabase_Project__apply_migration
mcp__[Institution]_Supabase_Project__list_migrations
mcp__[Institution]_Supabase_Project__generate_typescript_types
mcp__[Institution]_Supabase_Project__get_logs
mcp__[Institution]_Supabase_Project__get_advisors
mcp__[Institution]_Supabase_Project__get_project_url
mcp__[Institution]_Supabase_Project__get_publishable_keys
mcp__[Institution]_Supabase_Project__search_docs
Example: Applying Same Migration to Multiple Institutions
// Step 1: Apply to Main Supabase
mcp__Main_Supabase_Project__apply_migration({
name: "add_new_feature_table",
query: "CREATE TABLE ..."
})
// Step 2: Apply to Dental College Supabase
mcp__Dental_College_Supabase_Project__apply_migration({
name: "add_new_feature_table",
query: "CREATE TABLE ..." // Same SQL
})
// Step 3: Repeat for other institutions when their MCP servers are configured
CRITICAL: Database Documentation as Source of Truth
ALL database schema, functions, RLS policies, and triggers are documented in docs/database/.
Documentation Structure
docs/database/
├── main-supabase/ # Main Supabase project (pmqodbfhsejbvfbmsfeq)
│ ├── README.md # Documentation guide
│ ├── 01-functions.sql # All PostgreSQL functions (51+ functions)
│ ├── 02-rls-policies.sql # All RLS policies (126+ policies)
│ ├── 03-triggers.sql # All triggers
│ ├── 04-foreign-keys.sql # All foreign key relationships
│ └── 05-migrations/ # Migration history
├── dental-supabase/ # Dental College project
│ └── [same structure]
└── [other-institution]/ # Future institution projects
└── [same structure]
Mandatory Workflow: Document First, Execute Second
BEFORE executing ANY database migration, you MUST:
- Document the SQL code FIRST in
docs/database/main-supabase/ - Update the appropriate documentation file based on change type
- ONLY THEN execute the migration via MCP tools
- Sync to other institutions using their MCP tools
File Mapping: What Goes Where
| Change Type | Documentation File | Example |
|---|---|---|
| New function | 01-functions.sql |
is_super_admin(), get_dashboard_stats() |
| New RLS policy | 02-rls-policies.sql |
User roles SELECT policy |
| New trigger | 03-triggers.sql |
handle_new_user() trigger |
| New foreign key | 04-foreign-keys.sql |
user_roles.user_id → auth.users.id |
| New table | All files as needed | Create table + RLS + triggers |
Documentation Format
When adding SQL to documentation files, use this format:
-- ============================================
-- Function/Policy/Trigger Name
-- ============================================
-- Purpose: [Brief description]
-- Created: [Date]
-- Modified: [Date if updated]
-- Dependencies: [List any dependencies]
-- Used by: [List tables/functions that use this]
-- Security: [SECURITY DEFINER / INVOKER if applicable]
-- ============================================
[SQL CODE HERE]
-- End of [Name]
-- ============================================
Creating Complete Backend for New Institution
When setting up a new institution's Supabase project, follow this workflow to create the complete backend:
Step 1: Read Existing Documentation
// Read all SQL documentation files
Read({ file_path: "docs/database/main-supabase/01-functions.sql" })
Read({ file_path: "docs/database/main-supabase/02-rls-policies.sql" })
Read({ file_path: "docs/database/main-supabase/03-triggers.sql" })
Read({ file_path: "docs/database/main-supabase/04-foreign-keys.sql" })
Step 2: Apply Functions First
Functions must be created before RLS policies that reference them:
// Apply all functions from 01-functions.sql
mcp__[New_Institution]_Supabase_Project__apply_migration({
name: "001_create_functions",
query: "[SQL from 01-functions.sql]"
})
Step 3: Apply Table Schemas
Create all tables (get from existing migrations or documentation):
mcp__[New_Institution]_Supabase_Project__apply_migration({
name: "002_create_tables",
query: "[Table creation SQL]"
})
Step 4: Apply RLS Policies
mcp__[New_Institution]_Supabase_Project__apply_migration({
name: "003_create_rls_policies",
query: "[SQL from 02-rls-policies.sql]"
})
Step 5: Apply Triggers
mcp__[New_Institution]_Supabase_Project__apply_migration({
name: "004_create_triggers",
query: "[SQL from 03-triggers.sql]"
})
Step 6: Verify Schema
// List all tables to verify
mcp__[New_Institution]_Supabase_Project__list_tables()
// Check for security advisories
mcp__[New_Institution]_Supabase_Project__get_advisors({ type: "security" })
Key Functions Reference (from docs/database/main-supabase/01-functions.sql)
The following functions are critical for the permission system:
Core Permission Functions
| Function | Purpose |
|---|---|
is_super_admin(user_uuid) |
Check if user has super_admin role |
has_permission(user_uuid, permission) |
Check if user has specific permission |
has_any_role(user_uuid, role_names[]) |
Check if user has any of the specified roles |
get_user_roles(user_uuid) |
Get all roles assigned to a user |
get_role_permissions(role_id) |
Get all permissions for a role |
Dashboard & Analytics Functions
| Function | Purpose |
|---|---|
get_dashboard_stats() |
Get dashboard statistics |
get_user_activity_summary(user_uuid) |
Get user activity metrics |
Auth Functions
| Function | Purpose |
|---|---|
handle_new_user() |
Trigger function for new user creation |
is_email_approved(email) |
Check if email is in approved list |
Key RLS Policies Reference (from docs/database/main-supabase/02-rls-policies.sql)
Policy Patterns
Pattern 1: Public Read, Admin Write
-- Public can view
CREATE POLICY "Public can view published"
ON table_name FOR SELECT
USING (status = 'published');
-- Admins can manage
CREATE POLICY "Admins can manage"
ON table_name FOR ALL
TO authenticated
USING (is_super_admin(auth.uid()));
Pattern 2: Owner-Based Access
-- Users can manage their own
CREATE POLICY "Users can manage own"
ON table_name FOR ALL
TO authenticated
USING (created_by = auth.uid());
Pattern 3: Permission-Based Access
-- Users with specific permission
CREATE POLICY "Users with permission can manage"
ON table_name FOR ALL
TO authenticated
USING (has_permission(auth.uid(), 'module:resource:action'));
Local Development: Institution Switcher
Quick Start
# Start development with Main Institution
npm run dev:main
# Start development with Dental College
npm run dev:dental
# Switch without starting server
npm run switch main
npm run switch dental
How It Works
The scripts/switch-institution.ts script:
- Takes institution ID as argument
- Generates
.env.localwith correct Supabase credentials - Dev server uses the selected institution's database
Adding New Institution to Switcher
Edit scripts/switch-institution.ts:
const INSTITUTIONS: Record<string, InstitutionEnv> = {
main: { /* existing */ },
dental: { /* existing */ },
// Add new institution:
'arts-science': {
id: 'arts-science',
name: 'JKKN Arts & Science College',
supabaseUrl: 'https://xxx.supabase.co',
supabaseAnonKey: 'eyJ...',
siteUrl: 'http://localhost:3000',
features: 'blog,careers,page-builder,analytics',
},
};
Service Role Key Storage
For admin operations requiring service role key:
- Create
.env.[institution-id].servicekeyfile (gitignored) - Paste service role key (single line)
- Switcher will include it in
.env.local
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ ONE GitHub Repository │
│ (jkkn-institution-website) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Vercel: Main │ │ Vercel: Dental│ │ Vercel: Arts │
│ jkkn.ac.in │ │ dental.jkkn. │ │ arts.jkkn. │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Supabase Main │ │Supabase Dental│ │ Supabase Arts │
│ MCP: Main_... │ │ MCP: Dental...│ │ MCP: TBD │
└───────────────┘ └───────────────┘ └───────────────┘
Current Institutions
| ID | Name | Domain | Supabase Project | MCP Available |
|---|---|---|---|---|
main |
JKKN Institutions | jkkn.ac.in | pmqodbfhsejbvfbmsfeq | Yes |
dental |
JKKN Dental College | dental.jkkn.ac.in | wnmyvbnqldukeknnmnpl | Yes |
pharmacy |
JKKN Pharmacy | pharmacy.jkkn.ac.in | rwskookarbolpmtolqkd | Yes |
engineering |
JKKN Engineering | engg.jkkn.ac.in | kyvfkyjmdbtyimtedkie | Yes |
arts-science |
JKKN Arts & Science | arts.jkkn.ac.in | TBD | No |
nursing |
JKKN Nursing | nursing.jkkn.ac.in | TBD | No |
Adding a New Institution
Prerequisites Checklist
Before starting, ensure:
- Supabase account with organization access
- Vercel account with team access
- GitHub repository access
- Domain DNS access for custom domain
- Institution branding assets (logo, colors)
Step 1: Create Supabase Project
Navigate to Supabase Dashboard:
https://supabase.com/dashboard/projectsCreate New Project:
- Click "New Project"
- Select organization: JKKN
- Project name:
jkkn-[institution-id](e.g.,jkkn-dental) - Database password: Generate strong password (save securely)
- Region:
ap-south-1(Mumbai) orap-southeast-1(Singapore) - Pricing plan: Free tier initially
Wait for Project Setup:
- Takes 2-3 minutes for project to be ready
- Note the project reference ID (e.g.,
abcdefghijklmnop)
Get API Credentials:
- Go to Project Settings → API
- Copy:
Project URL,anon/public key,service_role key
Step 2: Configure MCP Server
Add the new institution's Supabase MCP server to Claude Code settings:
{
"mcpServers": {
"[Institution]_Supabase_Project": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-supabase", "--project-ref", "[project-ref]"]
}
}
}
Step 3: Apply Database Schema from Documentation
Read and apply from docs/database/main-supabase/:
// 1. Read the source of truth
Read({ file_path: "docs/database/main-supabase/01-functions.sql" })
Read({ file_path: "docs/database/main-supabase/02-rls-policies.sql" })
// 2. Apply functions first (required for RLS policies)
mcp__[New_Institution]_Supabase_Project__apply_migration({
name: "001_core_functions",
query: "[Functions SQL from documentation]"
})
// 3. Create tables from existing migrations
mcp__[New_Institution]_Supabase_Project__list_migrations() // Check what exists
// 4. Apply RLS policies
mcp__[New_Institution]_Supabase_Project__apply_migration({
name: "002_rls_policies",
query: "[RLS SQL from documentation]"
})
// 5. Verify
mcp__[New_Institution]_Supabase_Project__list_tables()
mcp__[New_Institution]_Supabase_Project__get_advisors({ type: "security" })
Step 4: Configure Supabase Project
Enable Auth Providers:
- Go to Authentication → Providers
- Enable Google OAuth
- Configure: Client ID, Client Secret
- Authorized redirect:
https://[domain]/auth/callback
Configure Auth Settings:
- Site URL:
https://[institution-domain] - Redirect URLs: Add callback URLs
- Site URL:
Set up Storage Buckets:
INSERT INTO storage.buckets (id, name, public) VALUES ('avatars', 'avatars', true), ('media', 'media', true), ('resumes', 'resumes', false);
Step 5: Create Vercel Project
Navigate to Vercel Dashboard:
https://vercel.com/dashboardImport Git Repository:
- Click "Add New..." → Project
- Select:
jkkn-institution-websiterepository - Framework: Next.js (auto-detected)
Configure Project:
- Project Name:
jkkn-[institution-id] - Root Directory:
./(default) - Build Command:
npm run build(default) - Install Command:
npm install(default)
- Project Name:
Add Environment Variables:
Required variables:
NEXT_PUBLIC_INSTITUTION_ID=[institution-id] NEXT_PUBLIC_INSTITUTION_NAME=[Full Institution Name] NEXT_PUBLIC_SITE_URL=https://[domain] NEXT_PUBLIC_SUPABASE_URL=https://[project-ref].supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=[anon-key] SUPABASE_SERVICE_ROLE_KEY=[service-role-key] NEXT_PUBLIC_FEATURES=blog,careers,page-builder,analyticsDeploy:
- Click "Deploy"
- Wait for build to complete
Step 6: Configure Custom Domain
In Vercel Project Settings → Domains:
- Add domain:
[institution].jkkn.ac.in
- Add domain:
Configure DNS:
- Add CNAME record:
[institution]→cname.vercel-dns.com - Or A record to Vercel IP if apex domain
- Add CNAME record:
Wait for SSL:
- Vercel auto-provisions SSL certificate
- Usually takes 5-10 minutes
Step 7: Update Local Development Switcher
Add to scripts/switch-institution.ts:
'[institution-id]': {
id: '[institution-id]',
name: '[Full Institution Name]',
supabaseUrl: 'https://[project-ref].supabase.co',
supabaseAnonKey: '[anon-key]',
siteUrl: 'http://localhost:3000',
features: '[feature-list]',
},
Step 8: Update Registry and Documentation
- Update
lib/config/multi-tenant.ts - Update CLAUDE.md institutions table
- Update this skill's institutions table
Database Migration Management
Syncing Changes Across Institutions
When making database changes:
- Document in
docs/database/main-supabase/first - Apply to Main Supabase via MCP:
mcp__Main_Supabase_Project__apply_migration({ name: "descriptive_name", query: "[SQL from documentation]" }) - Apply to Dental College:
mcp__Dental_College_Supabase_Project__apply_migration({ name: "descriptive_name", query: "[Same SQL]" }) - Repeat for other institutions with MCP servers
Migration Best Practices
- Always document SQL in
docs/database/first - Test on Main Supabase before other institutions
- Use idempotent SQL (IF NOT EXISTS, etc.)
- Include RLS policies for new tables
- Update TypeScript types after schema changes:
mcp__Main_Supabase_Project__generate_typescript_types()
Checking Applied Migrations
// Main Supabase
mcp__Main_Supabase_Project__list_migrations()
// Dental College
mcp__Dental_College_Supabase_Project__list_migrations()
Feature Flags
Available Features
| Feature | Description |
|---|---|
blog |
Blog system with posts, categories, tags |
careers |
Job listings and applications |
page-builder |
Visual page editor |
analytics |
Traffic and engagement analytics |
comments |
User comments on blog posts |
newsletter |
Email subscription system |
events |
Event management and calendar |
gallery |
Photo/video gallery |
testimonials |
Testimonial management |
admissions |
Admission portal |
faculty-directory |
Faculty profiles |
course-catalog |
Course listings |
research-publications |
Research paper management |
placements |
Placement statistics |
Configuring Features
Via Environment Variable:
NEXT_PUBLIC_FEATURES=blog,careers,page-builder,analytics
In Code:
import { hasFeature } from '@/lib/config/multi-tenant'
if (hasFeature('blog')) {
// Blog-specific code
}
In Components:
import { FeatureGate } from '@/lib/hooks/use-institution'
<FeatureGate feature="blog">
<BlogSection />
</FeatureGate>
Troubleshooting
Common Issues
1. Migration sync fails:
- Verify using correct MCP tool for target institution
- Check Supabase project is accessible
- Verify service role key has correct permissions
2. MCP tool not found:
- MCP server may not be configured for that institution
- Check Claude Code settings for MCP server configuration
3. Schema mismatch between institutions:
- Compare tables:
mcp__Main_Supabase_Project__list_tables()vsmcp__Dental_College_Supabase_Project__list_tables() - Apply missing migrations to sync
4. Wrong content showing in development:
- Verify which institution switcher was used (
npm run dev:mainvsnpm run dev:dental) - Check
.env.localhas correctNEXT_PUBLIC_INSTITUTION_ID - Restart dev server after switching
5. RLS policies blocking access:
- Check functions exist:
mcp__[Institution]__execute_sql({ query: "SELECT * FROM pg_proc WHERE proname = 'is_super_admin'" }) - Verify user has correct roles
- Check
mcp__[Institution]__get_logs({ service: "auth" })
Debug Commands
// Check Supabase connection
mcp__Main_Supabase_Project__get_project_url()
mcp__Dental_College_Supabase_Project__get_project_url()
// Check for security issues
mcp__Main_Supabase_Project__get_advisors({ type: "security" })
// Check tables exist
mcp__Main_Supabase_Project__list_tables()
// Check migrations applied
mcp__Main_Supabase_Project__list_migrations()
Key Files Reference
| File | Purpose |
|---|---|
lib/config/multi-tenant.ts |
Institution registry, feature flags |
lib/hooks/use-institution.ts |
React hooks for institution context |
scripts/switch-institution.ts |
Local dev institution switcher |
docs/database/main-supabase/*.sql |
Source of truth for database schema |
docs/MULTI-INSTITUTION-ARCHITECTURE.md |
Full architecture docs |
CLAUDE.md |
Project documentation with multi-institution section |
Quick Reference Commands
# Local Development
npm run dev:main # Start with Main Institution
npm run dev:dental # Start with Dental College
npm run switch main # Switch to Main (no server start)
npm run switch dental # Switch to Dental (no server start)
// MCP Tools - Main Supabase
mcp__Main_Supabase_Project__list_tables()
mcp__Main_Supabase_Project__apply_migration({ name: "...", query: "..." })
mcp__Main_Supabase_Project__execute_sql({ query: "..." })
// MCP Tools - Dental College Supabase
mcp__Dental_College_Supabase_Project__list_tables()
mcp__Dental_College_Supabase_Project__apply_migration({ name: "...", query: "..." })
mcp__Dental_College_Supabase_Project__execute_sql({ query: "..." })
Additional Resources
For detailed information, see:
docs/database/main-supabase/README.md- Database documentation guidereferences/environment-variables.md- Complete env var referencereferences/migration-guide.md- Detailed migration proceduresreferences/institution-checklist.md- Full setup checklist