Skip to main content

Database Schema Documentation

Complete database structure for the NS Internship Portal.

Entity Relationship Diagram

Database Overview

Database: PostgreSQL hosted on Supabase with Row Level Security (RLS) enabled Total Tables: 26+ core tables + extensions

Note: supabase/schema.sql is the initial baseline schema. All subsequent migrations extend it. This documentation reflects the fully migrated state.

Core Tables

1. users

Purpose: User accounts (students, admins, reviewers, project admins, super admins)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, DEFAULT uuid_generate_v4()Unique user identifier
nameVARCHAR(255)NOT NULLFull name
emailVARCHAR(255)UNIQUE, NOT NULLEmail address (login)
passwordVARCHAR(255)NOT NULLbcrypt hash (10 rounds)
roleVARCHAR(20)DEFAULT 'student'User role
phoneVARCHAR(50)NULLPhone number
collegeVARCHAR(255)NULLCollege/University name
avatar_urlTEXTNULLCloudinary avatar URL
degreeVARCHAR(255)NULLAcademic degree
branchVARCHAR(255)NULLAcademic branch/specialization
year_of_studyINTEGERNULLCurrent year of study
graduation_yearINTEGERNULLExpected graduation year
birthdayDATENULLDate of birth
genderVARCHAR(20)NULLGender
cityVARCHAR(100)NULLCity
stateVARCHAR(100)NULLState
countryVARCHAR(100)NULLCountry
linkedin_urlTEXTNULLLinkedIn profile URL
github_urlTEXTNULLGitHub profile URL
reset_password_tokenVARCHAR(255)NULLPassword reset token
reset_password_expiryTIMESTAMPNULLToken expiry
last_loginTIMESTAMPNULLLast login timestamp
created_atTIMESTAMPDEFAULT NOW()Account creation
updated_atTIMESTAMPDEFAULT NOW()Last update

Indexes:

  • idx_users_email ON (email)
  • idx_users_role ON (role)

Roles: student, admin, project_admin, reviewer, super_admin

Profile completeness: Weighted score from 12 fields. Score ≥ 80 unlocks profile badge.

2. domains

Purpose: Internship domains/courses (Web Dev, Python, ML, etc.)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique domain identifier
nameVARCHAR(255)UNIQUE, NOT NULLDomain name
slugVARCHAR(255)UNIQUE, NOT NULLURL slug
descriptionTEXTNOT NULLDomain description
iconVARCHAR(255)NULLIcon URL
pricing_one_monthINTEGERDEFAULT 4001-month pricing (₹)
pricing_two_monthsINTEGERDEFAULT 7002-month pricing (₹)
pricing_three_monthsINTEGERDEFAULT 10003-month pricing (₹)
problem_statementsJSONBDEFAULT '[]'Problem statements per duration
is_activeBOOLEANDEFAULT trueDomain visibility
deleted_atTIMESTAMPNULLSoft delete timestamp
created_atTIMESTAMPDEFAULT NOW()Creation timestamp
updated_atTIMESTAMPDEFAULT NOW()Last update

3. enrollments

Purpose: Student enrollments in domains

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique enrollment ID
student_idUUIDREFERENCES users(id)Student reference
domain_idUUIDREFERENCES domains(id)Domain reference
durationINTEGERCHECK IN (1, 2, 3)Duration in months
amountINTEGERNOT NULLFinal amount paid (₹)
payment_idVARCHAR(255)NULLRazorpay payment ID
order_idVARCHAR(255)NULLRazorpay order ID
payment_statusVARCHAR(20)DEFAULT 'pending'Payment status
statusVARCHAR(20)DEFAULT 'active'Enrollment status
submission_emailVARCHAR(255)NULLFinal project email
submission_dateTIMESTAMPNULLFinal submission date
admin_notesTEXTNULLAdmin review notes
certificate_idVARCHAR(255)NULLCertificate ID if issued
start_dateTIMESTAMPNOT NULLEnrollment start
end_dateTIMESTAMPNOT NULLEnrollment end

Status values: pending, active, submitted, completed, cancelled

4. milestones

Purpose: Weekly/major milestones per enrollment (sequential tracking)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique milestone ID
enrollment_idUUIDREFERENCES enrollments(id)Enrollment reference
weekINTEGERNOT NULLWeek number (1-12)
titleVARCHAR(255)NOT NULLMilestone title
descriptionTEXTNULLMilestone description
typeVARCHAR(20)CHECK IN ('weekly', 'major')Milestone type
statusVARCHAR(20)DEFAULT 'pending'Milestone status
submission_notesTEXTNULLStudent submission notes
submission_dateTIMESTAMPNULLSubmission timestamp
review_notesTEXTNULLAdmin review feedback
reviewed_byUUIDREFERENCES users(id)Reviewer user ID
reviewed_atTIMESTAMPNULLReview timestamp
deadlineTIMESTAMPNULLMilestone deadline
order_indexINTEGERDEFAULT 0Display order

Status values: pending, submitted, reviewed, rejected Sequential logic: Only reviewed (approved) unlocks the next milestone.

5. certificates

Purpose: Completion certificates and offer letters

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique certificate ID
certificate_idVARCHAR(255)UNIQUE, NOT NULLPublic ID (CERT-YY-XXXXXX)
student_idUUIDREFERENCES users(id)Student reference
enrollment_idUUIDREFERENCES enrollments(id)Enrollment reference
domain_idUUIDREFERENCES domains(id)Domain reference
student_nameVARCHAR(255)NOT NULLStudent name (snapshot)
domain_nameVARCHAR(255)NOT NULLDomain name (snapshot)
durationINTEGERNOT NULLDuration in months
project_titleVARCHAR(500)NOT NULLFinal project title
issue_dateTIMESTAMPDEFAULT NOW()Certificate issue date
expiry_atTIMESTAMPNULLExpiry date
is_revokedBOOLEANDEFAULT falseRevocation status
revoke_reasonTEXTNULLRevocation reason
pdf_urlTEXTNULLPDF URL (Cloudinary)

Certificate ID format: CERT-YY-XXXXXX (e.g., CERT-26-P9L2M4)

6. invoices

Purpose: Payment invoices with GST breakdown

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique invoice ID
invoice_numberVARCHAR(50)UNIQUE, NOT NULLInvoice number (INV-YYYY-NNNN)
enrollment_idUUIDREFERENCES enrollments(id)Enrollment reference
student_idUUIDREFERENCES users(id)Student reference
student_nameVARCHAR(255)NOT NULLStudent name (snapshot)
student_emailVARCHAR(255)NOT NULLStudent email (snapshot)
domain_nameVARCHAR(255)NOT NULLDomain name (snapshot)
durationINTEGERNOT NULLDuration in months
base_amountINTEGERNOT NULLAmount before GST (₹)
cgstINTEGERNOT NULLCGST 9% (₹)
sgstINTEGERNOT NULLSGST 9% (₹)
total_amountINTEGERNOT NULLTotal with GST (₹)
payment_idVARCHAR(255)NULLRazorpay payment ID
payment_statusVARCHAR(20)DEFAULT 'pending'Payment status
invoice_dateTIMESTAMPDEFAULT NOW()Invoice generation date

Invoice number format: INV-YYYY-NNNN (e.g., INV-2026-0001) GST calculation: CGST 9% + SGST 9% = 18% total (configurable via GST_RATE env)

7. coupons

Purpose: Discount coupons (percentage or flat)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique coupon ID
codeVARCHAR(50)UNIQUE, NOT NULLCoupon code
discount_typeVARCHAR(20)CHECK IN ('percentage', 'flat')Discount type
discount_valueINTEGERNOT NULLDiscount value
max_usesINTEGERNULLMax total uses
used_countINTEGERDEFAULT 0Current usage count
valid_fromTIMESTAMPNULLValidity start
valid_untilTIMESTAMPNULLValidity end
min_amountINTEGERNULLMinimum order amount
domain_idUUIDREFERENCES domains(id)Domain-specific
is_activeBOOLEANDEFAULT trueCoupon active status

8. announcement_reads

Purpose: Track which users have read which announcements

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique read ID
announcement_idUUIDREFERENCES announcements(id)Announcement reference
user_idUUIDREFERENCES users(id)User reference
read_atTIMESTAMPDEFAULT NOW()Read timestamp

Constraint: UNIQUE (announcement_id, user_id)

9. jobs

Purpose: Job listings cache (SerpAPI + RSS feeds)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique job ID
titleTEXTNOT NULLJob title
companyTEXTNOT NULLCompany name
locationTEXTNULLJob location
descriptionTEXTNULLJob description
apply_linkTEXTNOT NULLApplication URL
sourceTEXTNOT NULLSource (serpapi, rss_remotive, etc.)
tagsTEXT[]NULLTags (frontend, backend, etc.)
posted_atTIMESTAMPNULLOriginal posting date
fetched_atTIMESTAMPDEFAULT NOW()When fetched into cache

Tags: frontend, backend, data, design, marketing, mobile, devops, java, fullstack

10. saved_jobs

Purpose: User-saved job listings

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique save ID
user_idUUIDREFERENCES users(id)User reference
job_idUUIDREFERENCES jobs(id)Job reference
saved_atTIMESTAMPDEFAULT NOW()Save timestamp

Constraint: UNIQUE (user_id, job_id)

11. refresh_tokens

Purpose: JWT refresh token storage (rotation-based)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique token ID
user_idUUIDREFERENCES users(id)User reference
token_hashTEXTUNIQUE, NOT NULLSHA-256 hash of raw token
expires_atTIMESTAMPNOT NULLToken expiry (30 days)
created_atTIMESTAMPDEFAULT NOW()Token creation
revoked_atTIMESTAMPNULLRevocation timestamp

12. email_logs

Purpose: Email send tracking

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique log ID
recipientTEXTNOT NULLRecipient email
subjectTEXTNOT NULLEmail subject
typeTEXTNOT NULLTemplate type
statusTEXTDEFAULT 'sent'Send status
error_messageTEXTNULLError details if failed
sent_atTIMESTAMPDEFAULT NOW()Send timestamp

13. admin_activity_logs

Purpose: Audit trail for admin actions

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique log ID
admin_idUUIDREFERENCES users(id)Admin user reference
action_typeVARCHAR(50)NOT NULLAction type (28 types)
entity_typeVARCHAR(50)NOT NULLEntity type (10 types)
entity_idUUIDNULLEntity ID if applicable
metadataJSONBNULLAdditional action data
ip_addressVARCHAR(50)NULLRequest IP
user_agentTEXTNULLRequest user agent
created_atTIMESTAMPDEFAULT NOW()Action timestamp

Action types (28): create_domain, edit_domain, delete_domain, approve_enrollment, etc. Entity types (10): domain, enrollment, certificate, coupon, announcement, etc.

14. permissions

Purpose: Granular permission definitions (28 total)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique permission ID
nameVARCHAR(100)UNIQUE, NOT NULLPermission name
descriptionTEXTNULLPermission description
categoryVARCHAR(50)NULLPermission category

15. role_permissions

Purpose: Map permissions to roles

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique mapping ID
roleVARCHAR(20)NOT NULLRole name
permission_idUUIDREFERENCES permissions(id)Permission reference

16. user_permissions

Purpose: User-specific permission overrides

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique override ID
user_idUUIDREFERENCES users(id)User reference
permission_idUUIDREFERENCES permissions(id)Permission reference
grantedBOOLEANDEFAULT trueGrant or revoke

17. analytics_events

Purpose: User behavior event tracking

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique event ID
event_typeTEXTNOT NULLEvent type
user_idUUIDREFERENCES users(id) NULLUser reference
session_idTEXTNULLAnonymous session identifier
metadataJSONBDEFAULT ''Event-specific context data
created_atTIMESTAMPTZDEFAULT NOW()Event timestamp

18. leads

Purpose: Chatbot lead capture

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique lead ID
nameTEXTNOT NULLLead's full name
domainTEXTNOT NULLInternship domain of interest
durationTEXTNOT NULLDesired internship duration
phoneTEXTNOT NULL10-digit phone number
sourceTEXTDEFAULT 'chatbot'Lead source
statusTEXTDEFAULT 'new'Lead status
created_atTIMESTAMPTZDEFAULT NOW()Lead capture timestamp

19. newsletter_subscribers

Purpose: Email newsletter subscribers

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique subscriber ID
emailTEXTNOT NULL, UNIQUESubscriber email
created_atTIMESTAMPTZDEFAULT now()Subscription timestamp

20. email_queue

Purpose: Queued email delivery with retry and open tracking

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique queue entry ID
recipientTEXTNOT NULLRecipient email address
subjectTEXTNOT NULLEmail subject
htmlTEXTNOT NULLEmail HTML body
template_typeTEXTNOT NULLTemplate type
statusTEXTDEFAULT 'pending'Queue status
attemptsINTEGERDEFAULT 0Send attempt count
max_attemptsINTEGERDEFAULT 3Max retry attempts
scheduled_forTIMESTAMPDEFAULT NOW()Earliest send time
sent_atTIMESTAMPNULLActual send timestamp
error_messageTEXTNULLLast error if failed
opened_atTIMESTAMPNULLFirst open timestamp
open_countINTEGERDEFAULT 0Total open events
metadataJSONBNULLAdditional context data

21. certificate_templates

Purpose: Customizable certificate templates

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique template ID
template_typeVARCHAR(50)UNIQUE, CHECK IN (offer_letter, completion)Template type
contentJSONBNOT NULLTemplate content config
is_activeBOOLEANDEFAULT trueTemplate active status

22. site_settings

Purpose: Global site configuration

ColumnTypeConstraintsDescription
keyVARCHAR(100)PRIMARY KEYSetting key
valueTEXTNOT NULLSetting value

Common keys: siteName, siteEmail, sitePhone, siteAddress, maintenanceMode, maxEnrollmentsPerStudent

23. internship_resources

Purpose: Learning resources (videos, PDFs, links) per domain per week

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique resource ID
domain_idUUIDREFERENCES domains(id)Domain reference
titleVARCHAR(255)NOT NULLResource title
descriptionTEXTNULLResource description
typeVARCHAR(20)CHECK IN (video, document, link)Resource type
resource_urlTEXTNOT NULLURL (Cloudinary or external)
weekINTEGERNOT NULLWeek number (1-20)
order_indexINTEGERDEFAULT 0Display order within week
is_activeBOOLEANDEFAULT trueResource visibility

Resource types: video, document, link

Additional Tables

certificate_verifications

Purpose: Track public certificate verification attempts

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique verification ID
certificate_idVARCHAR(255)NOT NULLCertificate ID verified
verified_atTIMESTAMPDEFAULT NOW()Verification timestamp
ip_addressVARCHAR(50)NULLVerifier IP

domain_analytics

Purpose: Domain-specific analytics cache

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique analytics ID
domain_idUUIDREFERENCES domains(id)Domain reference
total_enrollmentsINTEGERDEFAULT 0Total enrollments
active_enrollmentsINTEGERDEFAULT 0Active enrollments
completedINTEGERDEFAULT 0Completed enrollments
revenueINTEGERDEFAULT 0Total revenue (₹)

search_queries

Purpose: Job search autocomplete suggestions

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique query ID
queryTEXTUNIQUE, NOT NULLSearch query text
countINTEGERDEFAULT 1Usage count
updated_atTIMESTAMPDEFAULT NOW()Last used

rate_limit_requests

Purpose: Rate limiting (Supabase-backed, survives restarts)

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEYUnique request ID
identifierTEXTNOT NULLIP or user ID
endpointTEXTNOT NULLAPI endpoint
countINTEGERDEFAULT 1Request count
window_startTIMESTAMPDEFAULT NOW()Rate limit window start

Relationships Summary

users (1) ──< (N) enrollments
users (1) ──< (N) certificates
users (1) ──< (N) refresh_tokens
users (1) ──< (N) admin_activity_logs
users (1) ──< (N) saved_jobs
users (1) ──< (N) announcement_reads
users (1) ──< (N) coupon_usage
users (1) ──< (N) user_permissions
users (1) ──< (N) analytics_events

domains (1) ──< (N) enrollments
domains (1) ──< (N) certificates
domains (1) ──< (N) internship_resources
domains (1) ──< (N) domain_analytics

enrollments (1) ──< (N) milestones
enrollments (1) ──< (1) certificates
enrollments (1) ──< (1) invoices

Indexes Summary

Performance indexes (15+ total):

  • Composite: idx_enrollments_student_status, idx_enrollments_domain_student
  • Single: idx_enrollments_payment_status, idx_enrollments_created_at
  • Milestones: idx_milestones_enrollment_id, idx_milestones_status
  • Activity logs: idx_admin_activity_logs_created_at, idx_admin_activity_logs_admin_id
  • Announcements: idx_announcements_created_at, idx_announcements_status
  • Refresh tokens: idx_refresh_tokens_user_id, idx_refresh_tokens_token_hash
  • Email logs: idx_email_logs_sent_at, idx_email_logs_type

Constraints Summary

CHECK constraints:

  • users.role IN (student, admin, project_admin, reviewer, super_admin)
  • enrollments.duration IN (1, 2, 3)
  • enrollments.status IN (pending, active, submitted, completed, cancelled)
  • milestones.type IN (weekly, major)
  • milestones.status IN (pending, submitted, reviewed, rejected)
  • announcements.type IN (info, warning, success, error)

UNIQUE constraints:

  • users.email, domains.name, domains.slug
  • certificates.certificate_id, invoices.invoice_number
  • coupons.code, refresh_tokens.token_hash
  • (coupon_id, user_id) in coupon_usage

Triggers

Auto-update updated_at on:

  • users, domains, enrollments, certificates, invoices, coupons, announcements, internship_resources
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';

Row Level Security (RLS)

RLS enabled on all core tables. Policies allow all operations through service role key.

Custom policies can be added for:

  • Students can only view their own enrollments/certificates
  • Admins can view all data
  • Public can verify certificates

Migration Order

Run migrations in this order:

  1. schema.sql — Core tables
  2. schema_extensions.sql — Milestones, permissions, coupons, invoices, announcements
  3. create_admin_activity_logs.sql — Activity logging
  4. rate_limit_and_soft_delete.sql — Rate limiting + soft delete
  5. create_invoices_table.sql — Invoice table
  6. alter_invoices_table.sql — Invoice enhancements
  7. internship_resources.sql — Learning resources
  8. 20240320_jobs_cache.sql — Job portal tables
  9. add_cancelled_enrollment_status.sql — Add cancelled status
  10. add_rejected_milestone_status.sql — Add rejected status
  11. create_refresh_tokens.sql — JWT refresh tokens
  12. create_email_logs.sql — Email tracking
  13. extend_announcements.sql — Enhanced announcements
  14. optimize_milestone_queries.sql — Milestone query optimization
  15. create_email_queue.sql — Email queue system
  16. certificate_templates.sql — Certificate templates table

Data Types

  • UUID: All primary keys use UUID v4 (gen_random_uuid())
  • TIMESTAMP: All timestamps use TIMESTAMPTZ (timezone-aware)
  • JSONB: Used for flexible data (problem_statements, delivery_channels, metadata)
  • TEXT[]: Array type for job tags
  • VARCHAR: Fixed-length strings with explicit limits
  • INTEGER: Numeric values (amounts in ₹, counts)
  • BOOLEAN: True/false flags

Backup & Maintenance

Recommended:

  • Daily automated backups (Supabase provides this)
  • Weekly manual exports for critical tables
  • Monitor table sizes and index usage
  • Vacuum and analyze periodically
  • Archive old email_logs (>90 days)
  • Purge expired refresh_tokens (>30 days past expiry)
  • Clean up old jobs cache (>14 days)
  • Archive sent/failed email_queue entries (>30 days)