Founders Fuel Academy

Platform Manual

Last updated: May 2026← Back to site

Platform Overview

Founders Fuel Academy is a self-hosted community + online course platform built specifically for Indian entrepreneurs. It combines a gated community feed, a full course curriculum, a members-only resource vault, live events, and a Razorpay-powered subscription system — all in a single Next.js 16 application with no separate backend.

Stack

Next.js 16, TypeScript, Tailwind CSS

Database

PostgreSQL via Prisma 5

Payments

Razorpay Subscriptions

Email

Resend (transactional + bulk)

Storage

Vercel Blob

Hosting

Vercel (Serverless + Edge)

Auth

NextAuth.js (Google OAuth + Email)

AI

Google Gemini API (newsletter)

Domain: https://foundersfuelacademy.com

Architecture

Routing Structure

app/

(auth)/ — login, signup (no header/nav layout)

(public)/ — landing, about, vision, subscribe, unsubscribe, manual

(platform)/ — all authenticated pages (PlatformLayout wraps these)

admin/ — admin-only dashboard & tools

classroom/ — course list + lesson player

community/ — social feed + post detail

resources/ — members-only vault

members/ — directory + profile pages

messages/ — DM inbox + thread

free/ — public-facing free resources

events/calendar/ — event calendar

api/ — all API routes (Next.js Route Handlers)

Key Conventions

  • • All times stored in UTC, displayed in IST (Asia/Kolkata).
  • • Razorpay webhooks are the source of truth for subscription state.
  • Server components by default; "use client" only when state/effects needed.
  • • All API routes return { data, error } shape.
  • • Monetary amounts stored in paise (×100 for Razorpay).
  • getRazorpay() and getResend() are lazy factories — safe to import at build time.
  • • Middleware at middleware.ts gates /platform/* routes — checks session cookie.
  • • Gamification points are calculated on-write, not in batch.

Access Control Tiers

TierWhoAccess
PublicAnyoneLanding, about, vision, subscribe, login, signup
FreeSigned-in, no active subCommunity (read), free resources, preview lesson, leaderboard, members directory
PaidActive Razorpay subscriptionEverything in Free + full classroom, resource vault, DMs, events
Adminrole = "admin" in DBEverything + admin panel, member management, course editing, email tools

Authentication

Powered by NextAuth.js. Two providers are configured: Google OAuth and Credentials (email + bcrypt password).

Login Flow

  1. User visits /login and submits email/password or clicks Google.
  2. NextAuth issues a JWT session cookie (next-auth.session-token).
  3. JWT payload includes: id, email, role, name, image, gamificationLevel.
  4. Middleware at middleware.ts reads the cookie — unauthenticated requests redirect to /login.
  5. Admin role is checked server-side via session.user.role === "admin".

Session Helper

Use getSession() from lib/session.ts in server components (React-cached, avoids N+1 queries). Use auth() from lib/auth.ts directly in API routes.

Subscriptions & Payments

All payments are processed through Razorpay Subscriptions. The platform uses recurring plans (monthly/annual) and the webhook handler is the authoritative source for subscription state.

Checkout Flow

  1. POST /api/subscriptions/create — creates a Razorpay subscription, returns subscription_id.
  2. Front-end opens the Razorpay checkout modal with the subscription ID.
  3. On payment success, front-end calls POST /api/subscriptions/verify with signature.
  4. Razorpay fires webhook to POST /api/webhooks/razorpay — this creates/updates the Subscription record.
  5. Webhook also triggers welcome email, in-app notification, and gamification points.

Coupons

Coupons are managed at Admin → Coupons. Supported types: PERCENT and FLAT. Validate via POST /api/coupons/validate at checkout time. The coupon code is stored on the Subscription record for auditing.

Webhook Events Handled

  • subscription.activated — mark subscription active, send welcome email
  • subscription.charged — renewal confirmed
  • subscription.cancelled — mark cancelled
  • subscription.halted — mark expired, send reminder
  • payment.failed — log failure

Community

The community feed is the social hub. All signed-in users can read; only paid members can post.

Posts

  • Categories: General, Wins, Questions, Resources, Announcements, Events
  • Media: Images, videos, links supported. Uploaded via /api/posts/upload to Vercel Blob.
  • Pinning & hiding: Admin can pin important posts and hide inappropriate ones.
  • Polls: Posts can include a poll (stored as JSON in pollData).
  • Gamification: +5 pts on post creation; +2 pts per like received.

Comments & Likes

  • Threaded: Comments can have a parentCommentId for reply threads.
  • Likes: Works on both posts and comments. A user can only like once per item.
  • Gamification: +3 pts for creating a comment; +1 pt per like received on a comment.

Notifications on Activity

When someone comments on or likes your post, an in-app notification is created. Notification bell in the header shows unread count. Clicking marks them read. The unread-reply badge(orange “Tap to reply”) appears for notifications the user has seen but not yet acted on — tracked in localStorage under notif-actioned.

Classroom

Full LMS with 8 courses, 70+ lessons, module grouping, drip release, and progress tracking.

Content Hierarchy

Course → Module → Lesson

  • Course: Has a cover image, description, access level (free/paid), and sort order.
  • Module: Grouping of lessons within a course. Has a sort order.
  • Lesson: Video URL, Markdown content, action items (JSON array), completion tracking.

Access Gating

  • • Lessons with isFree = true are accessible to all signed-in users.
  • • The first lesson of the first published course is always free (preview).
  • • All other lessons require an active subscription — shown as UpgradeWall if not subscribed.
  • • Admin bypasses all gates.

Progress & View Tracking

  • Completion: Marked via POST /api/lessons/[id]/complete. Stored in UserLessonProgress. Awards +5 pts; +50 pts on full course completion.
  • View tracking: LessonViewTracker client component fires POST /api/track/lesson on mount. Inserts into lesson_views table (used in weekly report).
  • • Prev / Next lesson navigation is shown at the bottom of each lesson page.

Drip Content

If a course has isDrip = true, lessons are unlocked based on dripDayOffsetrelative to the member's subscription start date. This is enforced in the lesson page access check.

Resource Vault

A members-only file vault for PDFs, templates, videos, links, zip files — anything the admin uploads. Files are stored in Vercel Blob.

Adding Resources (Admin)

  • • Admin sees an “Add Resource” button on the Resources page (top-right).
  • • Supports single file, multiple files, external links, and video URLs.
  • Multi-file upload: Multiple files are grouped under a Folder Name. Each file is uploaded individually with ?skipNotify=true, then one summary notification email is sent via POST /api/resources/notify.
  • Single file: Requires Title, Category (folder), Type, and optional description. Sends individual email on upload.

Folder Accordion UI

Resources are grouped by their category field and displayed as collapsible folder cards (ResourceFolderView component). Each folder shows file count and total size. If only one folder exists, it auto-opens. Clicking a file fires a resource view event.

Member Notifications

  • Paid members: Get email with resource title/link to /resources.
  • Free users: Get a teaser email with a link to /subscribe and pricing CTA.

Free Resources (Public)

Separate from the vault — managed via Admin → Free Resources. These are links/resources visible to all signed-in users at /free. Stored in the FreeResource model.

View Tracking

Every resource click fires POST /api/track/resource. Inserts a row into resource_views table. Used in the weekly analytics report to show engagement trends.

Events & Calendar

Admin can schedule live events (calls, workshops, AMAs) visible on the platform calendar.

Creating & Editing Events

  • • Admin creates events via Admin → Events with: title, date/time (IST), duration, category, meeting link, recording URL.
  • • Event times are saved in UTC, always displayed in IST (Asia/Kolkata).
  • • A double-conversion bug was fixed: the form input is IST → converted once to UTC on save. Never double-convert.
  • Editing: Admin can edit all event fields inline via the event card.

Reminders

  • POST /api/events/[id]/remind sends email reminders to all paid members.
  • • Admin always receives a notification copy regardless of event type.

Direct Messaging

1-to-1 direct messaging between members. Available at /messages.

  • • Messages stored in DirectMessage table (senderId, receiverId, body, isRead).
  • • Inbox shows all conversations grouped by the other participant.
  • • Messages are marked read via POST /api/messages/read when the thread is opened.
  • • Unread DM count shown in the sidebar navigation badge.

Notifications

In-app notification bell in the platform header. Three visual states:

Unread

Orange background + orange dot. Cleared when bell is opened.

Read

Plain white — user has seen the notification.

Read, not replied

Orange “Tap to reply →” badge. Tracked in localStorage (notif-actioned). Disappears after clicking.

  • • Notification types: comment, reply, mention, like, new_post, direct_message, event_reminder, system
  • • Created via createNotification() in lib/notifications.ts.
  • • Web push (browser notifications) supported via PushSubscription model. Subscribe at POST /api/push/subscribe.
  • • Daily cron (/api/cron/notify-unread) emails users about unread notifications they missed.

Gamification

Points-based system with 10 levels, visible on the leaderboard and member profiles.

Points Table

ActionPoints
Post created+5
Like received on post+2
Like received on comment+1
Comment created+3
Lesson completed+5
Course completed+50
7-day login streak+10

Level Thresholds

L1

0 pts

L2

50 pts

L3

150 pts

L4

350 pts

L5

700 pts

L6

1200 pts

L7

2000 pts

L8

3500 pts

L9

5500 pts

L10

8000 pts

Analytics & Tracking

Weekly Report (Friday 9 AM IST)

Auto-generated email report sent every Friday at 9 AM IST via /api/cron/weekly-report. Can also be triggered manually from admin or via GET request with the cron bearer token.

Metrics tracked (this week vs last week):

New signups
New paid conversions
Community posts
Comments
Lessons completed
Lesson views
Resource opens
Cancellations/Churn
Total paid members
Total free users
Conversion rate
Active members this week

Alert thresholds:

  • • 🔴 Zero new signups
  • • 🔴 Signups dropped ≥ 25% week-over-week
  • • 🔴 No new paid conversions (when free users exist)
  • • 🔴 Paid conversions dropped ≥ 30%
  • • 🟡 Community engagement dropped ≥ 25%
  • • 🟡 Lesson completions dropped ≥ 25%
  • • 🔴 3+ subscriptions cancelled/expired

View Tracking Tables

Two raw SQL tables (not Prisma-migrated — created via GET /api/admin/run-migrations):

  • lesson_views (id, lesson_id, user_id, viewed_at) — logged every time a lesson page loads
  • resource_views (id, resource_id, user_id, viewed_at) — logged on resource click

Funnel Events

The UserEvent model tracks conversion funnel milestones:signup, subscribe_page_view, checkout_started, subscription_created. Visible in the Admin Analytics dashboard.

Email & Newsletter

All transactional and marketing emails are sent via Resend. The from address is configured via RESEND_FROM.

Email Types

EmailTrigger
Welcome emailSubscription activated webhook
Subscription reminder (7d, 1d, 0d)Daily cron /api/cron/subscription-reminders
Resource notification (paid)New resource uploaded
Resource teaser (free users)New resource uploaded
Event reminderAdmin clicks Remind on event
Weekly analytics reportFriday 9 AM IST cron
Free tier nurture sequenceMonday cron, 14d after signup
Conversion emailsDaily cron, targets free users
Unread notifications digestDaily 6:30 AM IST cron
Newsletter broadcastAdmin sends via Admin → Email
Bug report confirmationUser submits bug report

Admin Newsletter Tool

  • • Admin → Email tab: compose newsletter manually or with AI-powered composition (uses Gemini API).
  • • Draft workflow: write → preview → approve → send. Drafts stored in SystemSetting table.
  • • Broadcasts can be targeted to all members, paid only, or newsletter subscribers.
  • • Gmail integration available for OAuth-authenticated sending.

Subscriber Management

Newsletter subscribers (separate from members) are stored in EmailSubscriber. Managed at Admin → Subscribers with bulk import/export, UTM tracking, and unsubscribe handling.

Admin Panel

Accessible at /admin — only for users with role = "admin" in the database.

Dashboard

/admin

Overview: total members, revenue, recent activity

Analytics

/admin/analytics

Funnel metrics, signups, conversions, engagement trends

Members

/admin/members (+ /[userId])

List all users, edit roles, view subscription status

Courses

/admin/courses (+ /[courseId])

Create/edit courses, modules, lessons. Toggle published state.

Resources

/admin/resources

Manage paid vault resources. Edit titles, categories, delete.

Coupons

/admin/coupons

Create PERCENT or FLAT coupons with usage limits and expiry

Events

/admin/events

Create and edit live events with reminders

Subscribers

/admin/subscribers

Email subscriber list, bulk import CSV, send campaigns

Email / Newsletter

/admin/email

Compose newsletters, AI drafting, send broadcasts

Cron Jobs

Configured in vercel.json. All schedules are UTC. Protected by Authorization: Bearer CRON_SECRET.

JobSchedule (UTC)IST TimePurpose
/api/cron/subscription-reminders30 2 * * *8:00 AM dailySubscription expiry reminders + grace-period kicks
/api/cron/free-tier-nurture0 4 * * 19:30 AM MondayNurture emails to free users who haven't converted
/api/cron/newsletter30 3 * * *9:00 AM dailyScheduled newsletter digest sending
/api/cron/notify-unread30 6 * * *12:00 PM dailyEmail users about unread in-app notifications
/api/cron/conversion-emails30 1 * * *7:00 AM dailyConversion funnel emails to free users
/api/cron/weekly-report30 3 * * 59:00 AM FridayWeekly analytics report email to admin

API Reference

All routes are in app/api/. All POST/PATCH bodies are JSON unless noted.

Authentication

POST/api/auth/registerCreate new user account (email + password)public
GET/api/auth/check-emailCheck if an email is already registeredpublic
POST/api/auth/logoutDestroy session cookieuser
POST/api/auth/clearClear stale auth cookiespublic

Community

GET/api/postsList community posts (paginated, filterable by category)user
POST/api/postsCreate a new postpaid
PATCH/api/posts/[id]Edit post (author or admin)user
DELETE/api/posts/[id]Delete post (author or admin)user
POST/api/posts/uploadUpload media for a post → Vercel Blobpaid
POST/api/posts/[postId]/voteToggle like on a postuser
GET/api/posts/[postId]/votersList users who liked a postuser
GET/api/commentsList comments for a postuser
POST/api/commentsCreate a comment (or reply)paid
DELETE/api/comments/[id]Delete comment (author or admin)user
POST/api/likesToggle like on a commentuser

Resources

GET/api/resourcesList paid resources (grouped by category)paid
POST/api/resources/uploadUpload resource file or link to vault. ?skipNotify=true suppresses emailsadmin
POST/api/resources/notifySend batch notification after multi-file uploadadmin
POST/api/track/resourceRecord a resource view event (fire-and-forget)user
GET/api/admin/free-resourcesList free resourcesadmin
POST/api/admin/free-resourcesCreate free resourceadmin
DELETE/api/admin/free-resources/[id]Delete free resourceadmin

Classroom

GET/api/courses/progressGet completion % per course for current useruser
POST/api/track/lessonRecord a lesson view event (fire-and-forget)user
PATCH/api/admin/lessons/[lessonId]Update lesson title, video, content, action itemsadmin

Subscriptions & Payments

POST/api/subscriptions/createCreate Razorpay subscription. Returns subscription_id.user
POST/api/subscriptions/verifyVerify Razorpay payment signature after checkoutuser
POST/api/subscriptions/cancelCancel current subscriptionuser
POST/api/coupons/validateValidate coupon code. Returns discount amount.user
POST/api/webhooks/razorpayRazorpay webhook handler (HMAC-verified)public

Events

GET/api/events/upcomingGet next 5 upcoming eventsuser
GET/api/events/allGet all events for calendar viewuser
POST/api/eventsCreate eventadmin
PATCH/api/events/[id]Edit event fieldsadmin
DELETE/api/events/[id]Delete eventadmin
POST/api/events/[id]/remindSend reminder email to all paid membersadmin

Messages

GET/api/messagesGet DM thread between current user and ?userId=user
POST/api/messagesSend a direct messagepaid
POST/api/messages/readMark messages in thread as readuser

Admin Utilities

GET/api/admin/run-migrationsCreate resource_views + lesson_views tables (idempotent)admin
GET/api/admin/analyticsFull analytics dashboard dataadmin
GET/api/admin/membersList all users with subscription infoadmin
PATCH/api/admin/members/[userId]Update user role, subscription overrideadmin
GET/api/admin/subscribersList all email subscribersadmin
POST/api/admin/subscribers/importBulk CSV import of subscribersadmin
POST/api/admin/broadcastSend broadcast email to a segmentadmin
POST/api/admin/newsletter/draftSave/update newsletter draftadmin
POST/api/admin/newsletter/send-draftSend draft newsletter to all subscribersadmin
POST/api/admin/newsletter/ai-composeAI-generate newsletter (Gemini API)admin
GET/api/cron/weekly-reportTrigger weekly report manually. Bearer CRON_SECRET or admin session.admin
POST/api/admin/test-emailSend diagnostic test email to admin addressadmin
GET/api/heartbeatUpdate user's online/lastActive timestampuser

Environment Variables

Set in Vercel Dashboard → Project → Settings → Environment Variables. Never commit to git.

VariablePurposeRequired
DATABASE_URLPostgreSQL connection string (Prisma)required
NEXTAUTH_SECRETJWT signing secret (min 32 chars)required
NEXTAUTH_URLFull app URL (e.g. https://foundersfuelacademy.com)required
NEXT_PUBLIC_APP_URLPublic app URL (used in emails/links)required
GOOGLE_CLIENT_IDGoogle OAuth client IDrequired
GOOGLE_CLIENT_SECRETGoogle OAuth client secretrequired
RAZORPAY_KEY_IDRazorpay API key IDrequired
RAZORPAY_KEY_SECRETRazorpay API secretrequired
RAZORPAY_WEBHOOK_SECRETWebhook signature secretrequired
RAZORPAY_PLAN_IDDefault Razorpay subscription plan IDrequired
RESEND_API_KEYResend email API keyrequired
RESEND_FROMFrom address (e.g. team@foundersfuelacademy.com)required
ADMIN_EMAILAdmin email for reports/alertsrequired
BLOB_READ_WRITE_TOKENVercel Blob storage tokenrequired
CRON_SECRETBearer token to authenticate cron job callsrequired
GEMINI_API_KEYGoogle Gemini API key for AI newsletter compositionrequired
VAPID_PUBLIC_KEYWeb push VAPID public keyoptional
VAPID_PRIVATE_KEYWeb push VAPID private keyoptional
GMAIL_CLIENT_IDGmail OAuth client ID (newsletter sending)optional
GMAIL_CLIENT_SECRETGmail OAuth client secretoptional

Database Schema

Managed by Prisma 5. Source of truth: prisma/schema.prisma. Run npm run db:generate after schema changes, npm run db:migrate to apply.

Note: resource_views and lesson_views are created via raw SQL through/api/admin/run-migrations — not via Prisma migrations. Run this endpoint once after deploy to production.

User

Core user account + gamification + online status

Account

OAuth provider accounts (NextAuth)

Session

Active user sessions

Subscription

Razorpay subscription records

Coupon

Discount codes

Post

Community feed posts

Comment

Threaded post comments

Like

Post and comment likes

Course

Course metadata

Module

Course section grouping

Lesson

Individual lesson content

UserLessonProgress

Lesson completion tracking

Event

Scheduled live events

GamificationLog

Points audit trail

DirectMessage

1-to-1 messages

UserEvent

Analytics funnel events

FreeResource

Public free resources

PaidResource

Members vault resources

Notification

In-app notifications

PushSubscription

Browser push tokens

EmailSubscriber

Newsletter subscribers

SystemSetting

Key-value config store

ResourceView

Resource view tracking (raw SQL)

LessonView

Lesson view tracking (raw SQL)

Deployment

Deploying to Vercel

  1. Ensure all env vars are set in Vercel project settings.
  2. Run npm run build locally first to catch TypeScript errors.
  3. Deploy: vercel --prod
  4. After first deploy (or after adding new models): call GET /api/admin/run-migrations to create raw SQL tables.

Database Migrations

  • • Schema changes: edit prisma/schema.prisma, run npm run db:migrate (requires DATABASE_URL).
  • • View data: npm run db:studio — opens Prisma Studio GUI.
  • • Seed courses: npm run db:seed — loads 8 courses and 70+ lessons.

Post-Deploy Checklist

  • Verify Razorpay webhook URL is set to https://foundersfuelacademy.com/api/webhooks/razorpay
  • Run GET /api/admin/run-migrations to create lesson_views + resource_views tables
  • Send a test email via POST /api/admin/test-email
  • Confirm cron jobs are active in Vercel Dashboard → Settings → Cron Jobs
  • Check admin panel loads at /admin

Founders Fuel Academy Platform Manual · Updated May 2026 ·Admin Panel