Indian market pricing — all costs in ₹ (INR)
Prices use ₹1 = USD $0.012 (approx ₹84/USD). USD-billed services (Vercel, Supabase, OpenAI) are converted at this rate. Indian GST of 18% applies on most foreign digital services billed to an Indian entity — factor this into your quotes to the business owner. All "free tier" services are genuinely free with no INR charge.
Exchange rate used
₹1 = $0.012 | $1 = ₹84
GST on foreign services
+18% on USD-billed items
Payment method note
International card needed for USD services
Domain Registration — Indian Options
meadowlarkmusic.com — BigRock₹849–999/yr
meadowlarkmusic.com — Hostinger India₹699–849/yr
meadowlarkmusic.com — GoDaddy India₹849/yr (renewal ₹1,499)
meadowlarkmusic.com — Namecheap~₹1,050/yr (USD billing)
Renewal tipGoDaddy cheap first yr, renews costly
meadowlarkmusic.in — BigRock₹599–699/yr
meadowlarkmusic.in — Hostinger₹499–599/yr
meadowlarkmusic.co.in₹399–499/yr
Cloudflare DNS (after buying)Free — point NS records
SSL (Cloudflare or Vercel)Free
Recommended: Buy from Hostinger India or BigRock, then use Cloudflare for free DNS
Buy the domain at Hostinger India (cheapest, INR payment, UPI accepted). Change nameservers to Cloudflare after purchase. Cloudflare gives you free CDN, DDoS protection, and SSL — BigRock/Hostinger DNS has none of that. This two-step gives you the best of both: low INR price + Cloudflare protection.
Hosting & Backend Infrastructure
Hobby tier (launch phase)₹0/mo
Pro tier — $20/mo~₹1,680/mo + 18% GST = ₹1,982/mo
Bandwidth — Hobby100 GB/mo free
Custom domainFree on both tiers
Billed inUSD — needs international card
Free tier — everything you need to launch₹0/mo
Free: DB storage500 MB
Free: Auth MAUs50,000 users
Pro tier — $25/mo~₹2,100/mo + 18% GST = ₹2,478/mo
Billed inUSD — needs international card
DNS + CDN + SSL + DDoS₹0/mo — genuinely free
Basic rate limiting₹0/mo
Pro tier (rarely needed)~₹1,680/mo + GST
India edge nodes includedMumbai, Chennai, Delhi — free
KVM 1 VPS (1 vCPU, 4 GB RAM)₹279/mo (promo) → ₹699/mo
LocationMumbai available
PaymentUPI / Debit card / Net banking
Trade-offYou manage server — more work
VerdictUse Vercel free tier instead
Payment Gateway Comparison (India)
Account setupFree (KYC required)
UPI transactions0% (up to ₹1 lakh/mo) then 1.8%
Debit / Credit card2% + GST
Net banking1.5% + ₹9 + GST
Subscriptions (recurring)Built-in — no extra fee
SettlementT+2 days to bank account
Example: ₹999 course feeYou receive ~₹979 (UPI)
Account setupFree (KYC required)
UPI transactions0.25%
Debit / Credit card1.75% + GST
Net banking1.5% + GST
SubscriptionsSupported
VerdictSlightly cheaper than Razorpay for cards
Account setupFree
All cards + UPI + Wallets2% + GST (flat)
SubscriptionsSupported
VerdictSimpler pricing, slightly higher rate
Account setupFree (complex KYC)
Domestic cards (India)3% + ₹2 per txn
UPI supportNot supported natively
INR settlementLimited — currency conversion fees apply
VerdictOnly if you have global customers
Third-Party Services (INR Converted)
GPT-4o-mini — recommended$0.15/1M tokens (≈₹13/1M)
100 users × 10 msgs/day~₹170–420/mo
500 active users~₹840–2,100/mo
Without rate limiting (!)Can reach ₹42,000+/mo instantly
+18% GST on USD billFactor into budget
Paid viaInternational credit card only
Resend free tier3,000 emails/mo — ₹0
Resend Pro — $20/mo~₹1,680/mo + GST = ₹1,982/mo
Brevo (Indian-friendly)300 emails/day free — ₹0
Brevo Starter₹1,265/mo (INR billing available)
RecommendationResend free tier for now
YouTube unlisted embeds₹0 — strongly recommended
Vimeo Basic₹0 (5 GB/wk upload limit)
Vimeo Starter — $9/mo~₹756/mo + GST = ₹892/mo
Supabase Storage for videoAVOID — ₹7.5/GB bandwidth
VerdictYouTube unlisted saves ₹10,000s/mo
Sentry (error monitoring) free₹0 — 5,000 errors/mo
Upstash Redis (rate limiting)₹0 — 10,000 reqs/day free
Vercel Analytics (on Pro)Included in Pro plan
Google Analytics 4₹0 — Indian users familiar
One-Time Setup Costs
Domain registration — .com (Hostinger India)₹699–849 (Year 1)
Domain renewal — .com (Year 2 onwards)₹849–999/yr
Domain — .in option (cheaper)₹499–599/yr all years
Razorpay KYC / account setupFree — needs GST + PAN + bank account
International card (for Vercel/Supabase USD billing)₹0 — use existing or apply for one
Cursor AI coding tool (optional)~₹1,680/mo (USD billing)
Design assets — Google Fonts already used₹0
Monthly Cost Summary — Indian Market (₹)
Phase 0–1 — Building, zero users
Domain amortised (~₹70/mo). Vercel, Supabase, Cloudflare all free. No users = no OpenAI cost.
~₹70/mo
Phase 2–3 — 100–500 active users
Still on all free tiers. OpenAI ~₹400–800/mo with rate limiting. Domain ~₹70/mo.
~₹500–900/mo
Phase 4 — 1,000–5,000 active users
Vercel Pro ₹1,982 + Supabase Pro ₹2,478 + OpenAI ₹1,680 + domain ₹70. All incl. GST.
~₹6,200/mo
At 50,000 users — mature product
Supabase Team $599 (~₹59,000) OR self-host on DigitalOcean Mumbai + Vercel Pro + OpenAI + Sentry.
~₹15,000–20,000/mo
Revenue vs Cost Reality Check
Scenario: 200 students × ₹499/mo subscription₹99,800/mo revenue
Infra cost at this stage~₹900/mo
Razorpay fee (2% avg)~₹2,000/mo
Total operating cost~₹2,900/mo (2.9% of revenue)
Net margin (infra only)~₹96,900/mo
Scenario: 1,000 students × ₹799/mo₹7,99,000/mo revenue
Infra cost at this stage~₹6,200/mo
Razorpay fee (2% avg)~₹15,980/mo
Total operating cost~₹22,180/mo (2.8% of revenue)
Net margin (infra only)~₹7,76,820/mo
The India-specific lean strategy
1. Buy domain from Hostinger India — UPI payment accepted, no international card needed for the domain. 2. Use YouTube unlisted embeds for all videos — this alone saves ₹10,000–50,000/mo in bandwidth vs self-hosting. 3. Use Razorpay (not Stripe) — lower fees, UPI support, INR settlement in T+2. 4. Use GPT-4o-mini and cap messages at 10/user/day. 5. Stay on Supabase free tier until you hit 500 paying users — the ₹2,478/mo Pro upgrade is worth it only at real revenue. 6. Use Brevo instead of Resend if you want INR billing and avoid international card dependency.
GST compliance note for the business owner
Foreign digital services (Vercel, Supabase, OpenAI) attract 18% GST under the OIDAR (Online Information and Database Access or Retrieval) rules. If the business is GST-registered, this is claimable as input tax credit. If not registered yet, factor 18% on top of USD costs in your pitch. For a bootstrapped start, Razorpay and Hostinger India are fully INR-billed and GST-compliant without any foreign currency headache.
Overview: GitHub Repo → Custom Domain on Vercel
Your code stays on GitHub. Vercel connects to your GitHub repo and deploys automatically on every push. You buy a domain separately and point it at Vercel. This is the standard setup for Next.js apps.
Step-by-Step: Domain Purchase
Choose and buy your domain
Go to Cloudflare Registrar (registrar.cloudflare.com) — at-cost pricing, no markup. Namecheap is a solid alternative. Search for "meadowlarkmusic.com" or "meadowlarkmusicacademy.com". A .com domain is ~$10/year. If .com is taken, consider .academy (more expensive ~$25/yr), .music, or just go with .in for ₹600–900/year.
# Recommended: Cloudflare Registrar
https://registrar.cloudflare.com
# Alternative: Namecheap
https://namecheap.com
# Best .com alternatives
meadowlarkmusic.com / meadowlarkmusicacademy.in / meadowlark.music
Point DNS to Vercel
In your domain registrar's DNS settings, add these records. If using Cloudflare as registrar AND DNS proxy, set "Proxy status" to DNS only (grey cloud) for the A/CNAME records pointing to Vercel — Vercel handles its own SSL.
# Add these DNS records at your registrar:
Type: A
Name: @ (root domain)
Value: 76.76.21.21 (Vercel's IP)
TTL: Auto
Type: CNAME
Name: www
Value: cname.vercel-dns.com
TTL: Auto
Connect GitHub repo to Vercel
Go to vercel.com → New Project → Import Git Repository → Select your Meadowlark Music Academy repo. Vercel auto-detects Next.js. Set your environment variables (NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, OPENAI_API_KEY) in Vercel's dashboard under Settings → Environment Variables.
# Environment variables to set in Vercel dashboard:
NEXT_PUBLIC_SUPABASE_URL = https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY = eyJ...
OPENAI_API_KEY = sk-... # NOT prefixed with NEXT_PUBLIC_
# NEVER put service role key in NEXT_PUBLIC_ variables
Add custom domain in Vercel
In Vercel project → Settings → Domains → Add "meadowlarkmusic.com" and "www.meadowlarkmusic.com". Vercel will verify the DNS records and provision an SSL certificate automatically within a few minutes.
Update Supabase allowed URLs
In Supabase dashboard → Authentication → URL Configuration → Add your production URL (https://meadowlarkmusic.com) to Site URL and Redirect URLs. Otherwise auth redirects will fail in production.
# Supabase Auth → URL Configuration:
Site URL: https://meadowlarkmusic.com
Additional Redirect URLs:
https://meadowlarkmusic.com/auth/callback
https://www.meadowlarkmusic.com/auth/callback
http://localhost:3000/auth/callback # keep for dev
Set up auto-deploy from GitHub
Vercel auto-deploys on every push to main branch. Pushes to feature branches create preview URLs (https://meadowlark-xxx.vercel.app) — great for testing before merging. No additional config needed.
# Workflow after setup:
git push origin main
# → Vercel builds and deploys automatically
# → Production: https://meadowlarkmusic.com
# → Preview: https://meadowlark-abc123.vercel.app
Do not skip: Add Supabase domain allowlist
After setting up your domain, go to Supabase → Authentication → URL Configuration and add your production domain. Without this, email confirmation links and OAuth redirects will fail — users won't be able to verify their email or log in via OAuth.
UI upgrade philosophy for Meadowlark Music Academy
A music academy should feel premium, artistic, and trustworthy. The current site is functional but looks like a default Next.js template. The upgrades below are ordered by impact — do the high-impact ones first.
High Impact — Do These First
1. Typography — choose a distinctive font pair
The current site uses system fonts. A music academy needs character. Use a serif display font for headings and a clean sans for body. This single change transforms the feel of the site.
Current (generic)
font-family: system-ui
All headings: font-weight: 700
No personality or brand identity
Recommended
Headings: Playfair Display or Cormorant Garamond (elegant, musical)
Body: DM Sans or Plus Jakarta Sans
Code/labels: DM Mono
2. Color system — define brand tokens in tailwind.config.ts
Replace ad-hoc color usage with a proper design system. Define 3 brand colors + semantic tokens. Every component reads from these variables — changing the brand color takes one edit, not a search-and-replace across 30 files.
// tailwind.config.ts
const config = {
theme: {
extend: {
colors: {
brand: {
primary: '#1a1035', // deep navy — trust, prestige
accent: '#e8901a', // warm gold — music, creativity
surface: '#f8f6f2', // warm off-white — not cold
},
},
},
},
};
3. Loading states — skeleton loaders everywhere
Currently all dashboard pages show nothing while loading — this feels broken. Add skeleton loaders that match the shape of the content being loaded. Tailwind's animate-pulse makes this easy.
Current
Blank screen → sudden content
No indication anything is loading
Feels broken to users
Fixed
Shimmer skeleton matching content shape → real content fades in
Add loading.tsx files in app directory
4. Dashboard layout — sidebar navigation
A music academy dashboard needs a persistent sidebar with navigation. The current full-page layout wastes space and makes navigation slow. A sidebar with instrument icons, course shortcuts, and user info is standard for SaaS dashboards.
Current
Top navbar only
No dashboard-specific nav
Poor content hierarchy
Recommended
Fixed left sidebar (240px) + main content area
Mobile: collapsible drawer sidebar
Breadcrumbs in header
Medium Impact
5. Course cards — premium music-academy aesthetic
Course cards should show the instrument image, teacher name, level badge, price, and an enrollment CTA. Think Masterclass or Coursera, but with a warm brand feel. Use next/image for all images with proper aspect ratios.
6. Landing page hero — animated, compelling CTA
The current hero is static text. Add a subtle background animation (audio waveform, floating music notes using CSS), a strong headline, a clear CTA ("Start your free trial"), and social proof (student count, rating). Framer Motion is already installed — use it.
7. Mobile navigation — hamburger menu
The current navbar may overflow on mobile. Add a proper mobile menu with smooth open/close animation. Test on real phone at 375px width. Touch targets must be at least 44×44px (Apple HIG requirement).
8. Empty states — designed, not blank
When a student has no courses yet, show an illustrated empty state: a music-themed illustration + encouraging text + CTA to browse courses. Every list view needs an empty state. Never show a blank white rectangle.
Design References (for inspiration)
Study these sites for UI patterns
• masterclass.com — course card design, premium feel, dark hero
• tonehall.com — music-specific SaaS, see their dashboard patterns
• coursera.org — enrollment flow, progress tracking UI
• linear.app — sidebar navigation, loading states, empty states
• stripe.com/docs — clean typography system with good hierarchy
These are real attacks on your current codebase
All five attacks below work right now on the current code. They are documented here so you know exactly what to fix. After Phase 0 and Phase 1 are complete, re-test each one — they should all fail.
Attack 01 — Currently works
Admin bypass with known email
- Open your site and go to /login
- Enter email:
[email protected] with any password (or blank)
- Click login — no Supabase call is made
- You are instantly redirected to /dashboard/admin with full access
- Also works with: [email protected] and [email protected]
FIX: Delete lines 27–34 in src/app/login/page.tsx. Replace with: const { error } = await supabase.auth.signInWithPassword({ email, password })
Attack 02 — Currently works
Direct URL access to admin dashboard
- Open a browser in incognito (no session)
- Navigate directly to https://yoursite.com/dashboard/admin
- The admin dashboard page renders with no auth check
- Currently shows mock data — once real data is connected, exposes everything
FIX: Add server-side auth guard. In page.tsx: const { data: { user } } = await supabase.auth.getUser(); if (!user) redirect('/login');
Attack 03 — Depends on RLS status (VERIFY NOW)
Dump entire database via browser console
- Sign up with a free account on your site
- Open browser DevTools → Console
- Run: const { data } = await supabase.from('users').select('*')
- If RLS is off on ANY table → all rows are returned to any authenticated user
- Can also try: supabase.from('subscriptions').select('*') to get all payment records
FIX: In Supabase SQL editor: ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; — run for every table. Then add per-table policies.
Attack 04 — Currently works
Burn all OpenAI credits via unauthenticated API loop
- Open browser DevTools → Network tab — find a chat request to /api/chat
- No authentication header is required by the route
- Run in Console: for(let i=0;i<100;i++) fetch('/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({messages:[{role:'user',content:'x'.repeat(5000)}]})})
- 100 requests × 5,000 tokens = 500,000 tokens = ~$75 in minutes at GPT-4o pricing
FIX: Add auth check at top of route.ts + per-user daily limit via Upstash Redis (free tier). 5 lines of code prevents hundreds of dollars in abuse.
Attack 05 — If roles are added without server enforcement
Privilege escalation via client-side profile update
- Sign up normally as a student
- In browser console: await supabase.from('profiles').update({role:'admin'}).eq('id', 'your-user-id')
- If no UPDATE RLS policy exists → you are now admin
- Refresh — admin dashboard is now accessible
FIX: RLS UPDATE policy: CREATE POLICY "only_admins_change_roles" ON profiles FOR UPDATE USING (auth.uid() = id) WITH CHECK (role = OLD.role OR (SELECT role FROM profiles WHERE id = auth.uid()) = 'admin');
How to perform the next audit without exposing API keys
The audit that produced this report required reading .env.local directly. The steps below describe how to run future audits safely — without ever passing real credentials to any AI tool.
Method 1 — Sanitize before sharing (Recommended)
1
Create a sanitized copy of your .env.local
Before sharing code with any AI tool or collaborator, replace all secret values with placeholder strings. Keep the variable names — the auditor needs to know which keys exist, just not their values.
# .env.local.safe — share this instead of .env.local
NEXT_PUBLIC_SUPABASE_URL=https://<YOUR_PROJECT_REF>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<REDACTED_ANON_KEY>
OPENAI_API_KEY=<REDACTED_OPENAI_KEY>
SUPABASE_SERVICE_ROLE_KEY=<REDACTED_SERVICE_ROLE_KEY>
2
Use git-secrets or secretlint in CI to block accidental commits
Install git-secrets as a pre-commit hook. It scans every commit for patterns that look like API keys (sk-, eyJ, etc.) and blocks the commit if found. This prevents the leak at the source.
# Install git-secrets (macOS/Linux)
brew install git-secrets
cd your-project
git secrets --install
git secrets --register-aws # adds AWS patterns
# Add OpenAI/Supabase patterns:
git secrets --add 'sk-[a-zA-Z0-9]{48}'
git secrets --add 'eyJ[a-zA-Z0-9_-]{50,}'
# Now: git commit will fail if secrets detected
3
Use GitHub Secret Scanning (free on public & private repos)
GitHub automatically scans for known API key patterns and alerts you if one is committed. Go to GitHub repo → Settings → Security → Secret scanning → Enable. Works for OpenAI, Supabase, Stripe, AWS, and 200+ other providers.
Method 2 — Scope the audit (Share only what's needed)
4
For architecture/code audits — exclude env files entirely
Most audit tasks (reviewing auth logic, RLS policies, component structure) don't require real credentials. When providing code to an AI tool, explicitly skip env files and note what variables exist by name only.
# When providing codebase for audit, exclude secrets:
find src -name "*.ts" -o -name "*.tsx" | \
xargs tar czf audit-package.tar.gz
# Include: package.json, tsconfig.json, next.config.ts
# Exclude: .env*, .env.local, any file with "secret" in name
5
For RLS/security audits — use a staging project
Create a separate Supabase project for staging with test data only. Run security tests against the staging project. The staging anon key can be shared safely — it only accesses fake data. Production keys never leave your environment.
# Supabase CLI: create a local dev stack
npx supabase init
npx supabase start # runs local Supabase on Docker
# Local URL: http://localhost:54321
# Local anon key printed in terminal — safe to share
# All data is local — no production exposure
Method 3 — Automated security scanning (run regularly)
6
Set up Snyk or npm audit for dependency vulnerabilities
These tools run without needing your secrets. They scan your package.json and source files for known vulnerabilities. Free for open-source and small teams.
# Built-in npm audit (free, no account needed):
npm audit
npm audit fix # auto-fixes non-breaking issues
# Snyk (free tier, deeper analysis):
npm install -g snyk
snyk auth # opens browser for GitHub OAuth
snyk test # scans dependencies
snyk code test # scans source code
7
Add GitHub Actions CI security scan on every PR
This runs on GitHub's servers — your local secrets are never involved. It catches vulnerabilities before code reaches production.
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm audit --audit-level=high
- uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
8
For the next AI-assisted audit — use this prompt template
Copy-paste this prompt structure. It gets equivalent audit depth without requiring credential access.
# Safe audit prompt template:
"I am sharing my Next.js + Supabase codebase for a security audit.
NOTE: All .env files are excluded. Credentials are not present.
The following env variables EXIST but are not shared:
- NEXT_PUBLIC_SUPABASE_URL (public, safe to know)
- NEXT_PUBLIC_SUPABASE_ANON_KEY (public, safe to know)
- OPENAI_API_KEY (server-only, not in NEXT_PUBLIC_)
Please audit the following for:
1. Auth logic and session handling in src/lib/supabase/
2. Any hardcoded credentials or dev bypasses
3. API route security (src/app/api/)
4. RLS policy recommendations based on the schema
5. RBAC enforcement in middleware and page guards
[paste source files here]"
Key rule going forward
Never share a real .env.local with any AI tool, collaborator, or audit service. If you must show env variable names, redact all values. Rotate keys immediately if exposure occurs. Use the Supabase CLI local development stack for any hands-on security testing — it creates a complete Supabase environment on your local machine with no production exposure.