All projects
Fitness
Live in production

Proton Fitness Academy — Fitness Academy Website and Learning Platform

Proton Fitness Academy runs trainer-certification courses and training programs. We built protonfit.com and the platform behind it: course batches with sessions and attendance, student and trainer portals, certificates, Razorpay checkout and a home-page CMS.

Updated

For Proton Fitness AcademyMay 2025 – Jul 2026
  • Public website (protonfit.com)
  • Student portal (web)
  • Trainer portal (web)
  • Admin and superadmin console (web)
Proton Fitness home page on desktop

Overview

Overview

Proton Fitness Academy trains fitness professionals. Its personal-trainer, nutrition and advanced certification courses run for weeks or months as dated batches, and it also sells group training, one-to-one home training, single-day and multi-day workshops and self-paced online courses. CountryDevs built its website and the platform behind it from May 2025: a Next.js client and a Node.js, Express and MongoDB API. The site is live at protonfit.com.

The platform has four kinds of user. Visitors browse the catalogue and enrol, paying through Razorpay or through a payment an admin records by hand. Students get a portal with their enrolments, the next class, a calendar of every session they can subscribe to from their own calendar app, attendance for each batch, an online-course player that remembers where they stopped, their certificates and their notifications. Trainers see the programs assigned to them and a teaching calendar. Admins and the superadmin run the catalogue, batches, enrolments, payments, refunds, certificates, users, inquiries, the blog and the home page.

The sections below walk through each part as it works in the code: how a batch turns into a timetable, who may enrol and when, how attendance and certificates are recorded, how money moves, and what each portal shows. In June 2026 we also found the live site serving no page titles or link previews and retrofitted its SEO without rewriting its pages. A daily AI blog is built and tested on a local database and is not yet switched on at protonfit.com.

The story in three steps

From the problem to what runs today

  1. 01 · Where it started

    The challenge

    Proton sells two different things. Training programs (group classes, home training and workshops) are booked and attended. Academy courses run for months as dated batches, with a weekly timetable, a trainer, a capacity, attendance at every session and a certificate at the end. Students, trainers and admins each need their own view of the same schedule, and a trainer cannot be in two places at once.

    Read the full challengeShow less

    The academy also needed to be found and shared. When we audited the live site in June 2026, a link to protonfit.com shared on WhatsApp previewed with "protonfit.com" as both its title and its description, and the browser tab showed the framework's default icon. And the team wanted to change the home page's banners, copy and featured courses without asking a developer each time.

  2. 02 · What we built

    The solution

    In April 2026 we restructured the backend from four flat program types into two verticals, Academy and Training. An academy course holds batches; each batch has dates, days of the week and time slots, and the server generates every session from that pattern. Attendance is recorded per session, and schedule conflicts are checked per trainer.

    Read the full solutionShow less

    Prices and checks stay on the server. A Razorpay order is priced from the course record, never from the browser; the payment signature is checked with HMAC-SHA256; and capacity and the enrolment window are checked again before a registration is created. Certificates are created as pending at enrolment and issued by an admin with attendance and grade. The home page became a CMS over a fixed set of sections, so the academy edits content without breaking the layout. For SEO we made the root layout a server component and added metadata route by route.

  3. 03 · Where it stands

    The impact

    protonfit.com is live (checked 17 October 2026) with its training programs, academy course pages and their batches, a blog and a certificate verification page. Since the SEO retrofit in June 2026, public pages carry their own titles, descriptions and canonical URLs, link previews show a branded image, and the site serves robots.txt, a sitemap and Organization structured data with the academy's real contact details. The student, trainer and admin portals ship with the site.

    Read the full impactShow less

    The AI blog is the part still in progress. Its scheduler, planning wizard and cover-image pipeline are built and were verified against a local database, including a second run on the same day doing nothing. It goes live once a production AI API key and server fonts for the cover text are in place.

Chapter 1

Two businesses in one catalogue: academy courses and training programs

Proton sells two different things, and the data model keeps them apart on purpose.

Academy courses list in the superadmin console
Academy courses in the superadmin console: each course is a template with a default trainer, price, class size and the number of batches running from it.

The academy

An academy course is a template, not a class. It holds the title, the topics covered, the banner, a default trainer, a default price, a default class size, a default weekly pattern and the number of grace days after the start. What students actually join is a batch of that course: "Weekend Batch — September", "Starting Batch", "Next Batch". Each batch copies the course defaults when it is created and can override any of them, so one course can run a weekend batch and a weekday batch with different trainers and timings side by side. The superadmin console lists every course with its trainer, default size and the number of batches running from it.

Online courses

Online courses are self-paced. Each is a list of sections, each section a list of lessons with a video and a duration, and the course works out its own lesson count and total running time from that structure. There is no batch and no schedule: a student buys it and works through it at their own pace.

Training programs

Training is three program types, each with its own listing, detail page and admin screen:

  • Workshops are single-day or multi-day events with a date, a location and a trainer.
  • Group training runs in a delivery mode (online, offline or hybrid) with a range of group sizes. Its price is a set of tiers by group size: the public page shows, for example, a per-person price for a group of four, six or eight, and the listing shows the "from" price.
  • Home training is one-to-one, again online, offline or hybrid, with its own trainer and duration.

Why the split matters

In April 2026 we restructured the backend from four flat program types into these two verticals. Everything that is genuinely different — dated batches, generated sessions, attendance, grace windows — lives only on the academy side, so the training programs stay simple. Everything that is genuinely shared — enrolment, payment, certificates, notifications, the student's schedule — works across all of them through one courseType and courseId pair on every registration, payment and certificate. A student's "My courses" page can then split one list into academy, online and workshops without three separate data paths behind it.

Group training programs in the superadmin console
Group training programs with their delivery mode (online, offline or hybrid) and the group size each one runs at.

Chapter 2

How a batch becomes a timetable

An academy batch is described once, as a pattern, and the server turns that pattern into every individual class.

Create batch form with dates, days, time slots and capacity
Creating a batch: dates, the day the enrolment window opens, the days of the week, one time for all days or a time per day, class size and the grace days after the start.

The pattern

Creating a batch asks for a start date and an end date, the date its enrolment opens, the days of the week it meets, and the time. The time can be one slot for every selected day ("Saturday and Sunday, 09:00 to 12:00") or a different slot per day ("Tuesday evening, Saturday morning"). The form also takes the class size, the location and the number of grace days.

From pattern to sessions

On save, the server expands the pattern into concrete sessions. It walks every date from the start to the end, keeps the dates that fall on a selected weekday, attaches that day's time slot, and inserts one numbered session per class: session 1, session 2 and so on, each with its date, start and end time, an empty attendance list and the status "scheduled". The batch records how many sessions it generated. A weekend batch from mid-September to mid-December comes out at 25 sessions without anyone typing a date.

The same pattern also becomes a calendar entry for the batch with its weekly slots and its trainer. That entry is what conflict checks and schedules read.

Enrolment windows and grace days

Each batch has an opening date for enrolment and a closing date the server derives on every save: the start date plus the grace days. A student can still join a batch in its first week if the academy allows seven grace days, and not after that. The batch moves through draft, enrolling, upcoming, ongoing, completed or cancelled, and only published, active batches inside their window appear as bookable on the public course page.

Changing a batch

Editing the schedule fields of a batch updates its calendar entry, regenerates its sessions and sends every actively enrolled student a "Batch Updated" notification, so nobody turns up to a class that moved. Changing only the trainer updates the calendar's trainer without touching the sessions. A batch with active enrolments cannot be deleted: the server refuses until those students have been dealt with, and deleting an empty batch removes its calendar entry and sessions with it.

Checking for clashes

Before a batch is saved, the console can ask the server whether its weekly slots overlap another batch's calendar on the same day. The answer names the day, the clashing times and the other course, so the academy sees "Saturday 09:00–12:00 clashes with Proton Nutrition Course" rather than a generic error. Workshops, group training and home training run the same kind of check against the trainer's existing schedule when they are created or edited, because a trainer cannot be in two studios at once.

Trainer's programs grid with a workshop, a group-training batch and two academy batches
A trainer sees every program assigned to them — workshops, group training and academy batches — with status, dates and a link into attendance.

Chapter 3

Who may enrol, and when

Every enrolment, whether it comes from a student's checkout or from an admin entering it by hand, passes through one eligibility check on the server. The browser is never trusted to decide.

My courses page listing the demo student's academy batch enrolments
Everything a student is enrolled in, split into academy batches, online courses and workshops.

The checks for an academy batch

For a batch the server checks, in order:

  1. The student is not already enrolled in it (a pending or active registration blocks a second one).
  2. The batch is published and active.
  3. Enrolment has opened, and has not closed: the closing date is the start date plus the grace days.
  4. The batch has room. The count is taken from the registrations themselves, active and completed, at the moment of the check, and compared with the batch's class size.

Each failure returns a reason a person can act on: "Enrollment opens on Sat Sep 12", "Enrollment is closed — grace period ended", "Batch is full".

The checks for other programs

Workshops, group training, home training and online courses are checked for being published and active, and for capacity where a program sets one, counted from pending and active registrations.

One gate, two doors

A registration is created in one of two ways, and both go through the same check:

  • Checkout. After a Razorpay payment is verified, the server runs the eligibility check again before creating the registration, because capacity or the enrolment window can change between the moment an order is created and the moment it is paid.
  • Manual enrolment. An admin enrolling a student who paid at the front desk goes through the same gates as the student would. There is no back door that skips the class size.

What happens on enrolment

A successful registration records the program, the payment and an attendance pattern ("single-event" for a workshop, "multi-session" for everything else). For an online course it also creates the student's progress record. For workshops, group training, home training and academy batches it creates a pending certificate straight away, so the certificate exists from day one and only needs issuing at the end. The student gets an "Enrollment Confirmed" notification, and the admins are told when a payment arrives.

Manual enrolment form in the superadmin console
Manual enrolment for students who paid outside the site: pick the student, the program type and the program, then record the amount and a payment note.

Chapter 4

Attendance at every session

For a course that runs for months, a certificate means little without attendance behind it, so attendance is recorded per session rather than per batch.

Attendance table for a demo academy batch with present and absent marks
Per-batch attendance: sessions held, present and absent counts, attendance percentage and a session-by-session record.

How a session is marked

Each generated session holds a list of attendance records: the student, present or absent, who marked it and when, and an optional note. Marking a student who already has a record updates it instead of adding a second one, so correcting a mistake does not double-count. Attendance can be marked one student at a time or for the whole class in one request, and the server ignores any value other than present or absent.

The first time anyone is marked for a session, the session's status changes from "scheduled" to held. A session can also be cancelled with a reason by an admin, and cancelled sessions are left out of the student's counts.

What the student sees

The student's attendance page for a batch lists every session with its date, time and their own status: present, absent, or not yet marked. Above the list it shows four numbers: total sessions, present, absent and an attendance percentage. The percentage is worked out only from sessions that have actually been marked, so a student is not shown as failing attendance because a trainer has not filled in last Saturday yet; future sessions and cancelled ones do not count against them either.

Who the pages are for

The session and attendance pages are built for the batch's assigned trainer and for admins. A trainer's access is checked against the batch itself: being a trainer is not enough, they must be assigned to that batch. Admins can see every batch.

Attendance on the certificate

When a certificate is issued at the end of a batch, the admin can record the attendance percentage, the sessions attended out of the total, a score and a grade on it. Those numbers are stored on the certificate itself, so the record says not only that the trainer passed but how much of the course they attended.

Academy course detail page on desktop
An academy course page: trainer, format, certificate and price, the course overview and its scheduled batches with dates, days and enrolment state.

Chapter 5

Paying: Razorpay checkout and payments recorded by hand

Proton takes money in two ways, and both end in the same payment record with its own invoice number.

Certificate management table filtered to issued demo certificates
Certificates are created as pending on enrolment and issued by an admin with attendance and grade; each carries a verifiable number, with bulk and manual issue.

Checkout through Razorpay

When a student enrols online, the server creates a Razorpay order. The amount comes from the program record on the server, never from the browser: the batch or course price, or for group training the price of its first tier. The payment record is created at this point as pending, with the order ID and an invoice number.

When Razorpay returns, the server checks the payment signature with HMAC-SHA256 against the order and payment IDs. A bad signature marks the payment failed and stops there. A good one marks it paid with the time, then runs the eligibility check again before creating the registration. If the class filled up in the meantime, the student is told the payment was captured and enrolment blocked, and the record is left for an admin to refund.

Payments recorded by hand

Some students pay at the academy, by bank transfer or by UPI. The manual enrolment screen lets an admin pick the student, the program type and the program, and record the amount and a payment note ("UPI ref ABC123"). The server creates a payment with the method "manual" and a fresh invoice number, then the registration, through the same eligibility checks as checkout.

Invoices and refunds

Every payment gets an invoice number in the form INV-2026-000021, numbered within the year. The payments screen lists them all with the student, the program type, the amount, the status (pending, paid, failed or refunded), the method (Razorpay or manual) and the date, with filters for each.

A refund can only be made on a paid payment and never for more than was paid. For a Razorpay payment the server asks Razorpay to refund that payment and stores the refund ID; for a manual one it records the refund. Either way the payment keeps the amount, the reason and who processed it. Students can also request a refund on a registration, which lands with the admins rather than moving money on its own.

Batches table for a demo personal-trainer course
Each academy course runs as dated batches with a weekly schedule, trainer, price, capacity and status, plus links to sessions and trainer assignment.

Chapter 6

Certificates, from enrolment to a public check

Proton's certificates are what students are really paying for, so they are designed to be issued deliberately, with the evidence on them.

Certificate verification page with a certificate-number search field
Anyone can check a Proton certificate by its number on the public verification page.

Pending from day one

When a student enrols in a workshop, group training, home training or an academy batch, a certificate is created immediately with the status pending: the student's name and email, the program and a "Certificate of Completion" title. Online courses do not get one, because they have no trainer sign-off. Creating the pending certificate is best-effort: if it fails for any reason, the enrolment still goes through.

Numbered by year and program type

Each certificate gets a number like PROTON-2026-GRP-000001: the academy's prefix, the year, a code for the program type (workshop, group training, home training and so on) and a running number within that year and type. The number is the one thing a student needs to share.

Issued by an admin, with the evidence

At the end of the program an admin issues the pending certificate. Issuing makes it active, stamps the issue date and who issued it, and can record the trainer who signs it with their designation and the achievement: attendance percentage, sessions attended out of the total, score and grade. It also stores a signature built from the certificate number, the student, the program and the issue date, a hash of the certificate's details for tamper checks, and a verification link for its QR code. A certificate that is already active cannot be issued twice, and a revoked one cannot be re-issued.

The certificate screen lists every certificate with its number, recipient, program, type, status and dates, with filters for active, pending, expired and revoked, and actions to issue one at a time or in bulk.

A public verification page

protonfit.com has a public certificate verification page where anyone can enter a certificate number. The lookup behind it needs no login and is designed to answer with the certificate's details or a status: not found, expired (past its expiry date) or revoked.

Revoked when it must be

An admin can revoke a certificate with a reason. The record keeps who revoked it and when, the status changes to revoked, and the student is notified that their certificate for that program has been revoked. The console can also list certificates that are about to expire within a chosen number of days.

Student dashboard for a demo student with today's class and two academy enrolments
A student's home: active enrolments, upcoming sessions, today's academy class with time and studio, and enrolled academy courses.

Chapter 7

The student portal

A student logs in to one place that knows everything they have bought.

Subscribe-to-calendar dialog with a personal feed link
A student's personal calendar feed: paste the link into Google Calendar, Apple Calendar or Outlook, and every class across all enrolments stays in sync.

The dashboard

The dashboard greets the student by name, tells them when their next session is, and shows four numbers: active enrolments, online courses in progress, upcoming sessions and certificates earned. Below that are their current enrolments as cards with the trainer and start date, shortcuts to the schedule, certificates and catalogue, and links back into the academy courses, workshops, training programs and the blog.

My courses

"My courses" splits every enrolment by how it is delivered: academy, online and workshops. Each academy card shows the next class, the weekly schedule, the location and the trainer, with a link to the attendance page for that batch.

One schedule, and their own calendar

"My schedule" shows every class, workshop and live session across all enrolments in one calendar, with month, week and agenda views and a colour per program type. Two ways get it out of the website:

  • Add one class. Any single event can be downloaded as an .ics file and dropped into a calendar.
  • Subscribe to everything. "Subscribe to calendar" gives the student a personal feed link. Pasted into Google Calendar, Apple Calendar or Outlook, it keeps every class in sync: when a batch moves, their own calendar moves with it.

The feed link carries a random token tied to the student's account, and that token is the only key: calendar apps cannot log in, so the server looks the student up by the token and builds the calendar from their current enrolments. The link is offered as webcal:// so calendar apps treat it as a subscription rather than a one-off download, and the server accepts it with or without the .ics extension because some calendar apps insist on it. The dialog warns the student not to share it.

Profile and notifications

The profile keeps personal details, an emergency contact and the student's fitness goals, which trainers and support use to reach them. Email is read-only and the account type shows whether they sign in with a password. A bell in the header shows unread notifications — enrolment confirmations, batch changes, course completions — with "mark all read".

Month calendar with weekend academy classes for a demo student
Every class across all enrolments on one month/week/agenda calendar, with a subscribable calendar feed.

Chapter 8

Online courses and the course player

Self-paced courses need a different experience from a timetable: the student needs to know where they stopped and how far they have come.

Course player with a lesson video area and section list for a seeded online course
The online-course player: video lessons grouped into sections, completed-lesson ticks and overall progress through the course.

How a course is built

An online course is a list of sections, each a list of lessons with a video and a duration. The course works out its total lesson count and running time from that structure, which is what the public course page shows: "18 Lessons · 4h 49m". Admins manage these courses in their own list with lesson counts, enrolment and the assigned trainer.

A progress record per student

When a student buys an online course, the same payment step that creates the registration also creates a progress record for that student and that course. The registration points to it, so the portal can open the player straight onto it.

Marking lessons complete

As the student finishes a lesson, the player marks it complete with the section and lesson number and the time watched. The server ignores a lesson that is already complete, so replaying a video does not inflate progress. It then recalculates:

  • the percentage complete, from completed lessons over the total lessons in the course,
  • the last lesson, so the player reopens where the student stopped,
  • the status: once every lesson is complete the course is marked completed with the completion time.

Finishing a course

When progress reaches 100 percent, the student gets a "Congratulations! You completed …" notification with the course title. On the dashboard, "online courses in progress" counts the ones still under 100 percent.

Access stays with enrolment

The player only opens for a student with an active registration for that course. Anyone else sees "Not enrolled" with a link to the catalogue, so lessons are not reachable by sharing a URL.

Online courses list in the superadmin console
Self-paced online courses, listed with their lesson counts, enrolment and the trainer they are assigned to.

Chapter 9

The trainer portal

Trainers work across programs, so their portal is organised around what they teach and when, not around one course.

Home training programs in the superadmin console
Home training: one-to-one programs, delivered online, offline or both, each with its own trainer.

My programs

"My programs" lists everything the trainer is assigned to, across all five types, with a tab for each: online courses, workshops, home training, group training and academy courses. Each card shows its status and dates, and academy batches carry a link to manage attendance for that batch.

Assignments come from the console: admins assign a trainer to a specific workshop, program or batch, and a batch can also carry additional trainers beside the lead. That assignment is what decides whether a trainer may open a batch's session pages.

My teaching schedule

The teaching schedule is a month calendar of every class the trainer runs, coloured by type (workshop, home training, group training, live session), with a list view beside it. It is built from the same calendar entries the conflict checks use, so the calendar a trainer sees is the one that stops them being double-booked.

Profile

The trainer's profile holds their email, phone, bio, experience, certifications and specialties, which is the information students see about who is teaching them.

Why trainers do not see money

Trainer screens carry no revenue, payment or refund data. Trainers see their programs, their students and their schedule; everything to do with money and certificates stays with admins and the superadmin.

Workshops list in the superadmin console
Workshops are one-day or multi-day events with their own trainer, status and enrolment.

Chapter 10

The console: roles, users, enrolments and inquiries

Behind the portals is one console, shown in two versions: a full one for the superadmin and a narrower one for admins.

Home page content editor with the hero slider section open for editing
Every section of the public home page is edited in place — copy, images, slide order and featured courses — with character counters before saving.

Four roles, checked on the server

Every account is a student, a trainer, an admin or the superadmin. The role guards on the API load the user's record on each request and check its role there, rather than trusting what the browser says, and they answer 403 when the role is not allowed. Money-moving and site-wide actions sit behind the superadmin; day-to-day running sits with admins and the superadmin together.

Accounts and their lifecycle

New accounts are activated through an emailed link, which can be re-sent, and passwords are reset through an emailed link too. The superadmin can ban an account with a reason; a banned user who tries to log in is told their account is banned and why, instead of seeing a generic error. User management filters by role, activation and ban status, and opens each student's enrolments.

Running the catalogue

Each program type has its own list with search, status and delivery-mode filters and pagination: academy courses and their batches, online courses, workshops, group training and home training, each with create, edit, publish and "assign trainer" actions. Group training has its pricing tiers by group size in the same form as its description, mode, status and trainer.

Manual enrolment

The manual enrolment screen covers students who paid outside the website: choose the student, the program type and the program, add the amount and a payment note, and confirm. A short "How it works" panel beside the form tells the admin what will happen: a manual payment record and the registration are created together.

Inquiries and settings

Messages from the contact form arrive as inquiries with the sender, subject and type. Each moves through pending, responded, on-going, completed or rejected, so the team can see what still needs a reply. Settings hold the academy's contact details (WhatsApp number and message, support email and phone), business details and social links, which the public site reads instead of hard-coding them.

Content without a developer

The blog has categories the academy manages itself (nutrition, wellness, career, training) and posts with status, author, featured flag and schedule. The home page is a CMS over a fixed set of eight sections — hero slider, academy highlights, about, academy courses, steps, why choose us, testimonials and featured blog — where the team edits the copy, images, lists and course picks inside each section while the order and layout stay fixed in code.

Create group training form with delivery mode and pricing tiers
The group-training form: a rich-text description, delivery mode, status, trainer and the pricing tiers by group size.

Chapter 11

Notifications that follow the work

The platform tells people about the things that change their plans, inside the portal they already use.

What triggers a notification

Notifications are written by the server at the moment something happens, not by a nightly job:

  • Enrolment confirmed when a registration is created, through checkout or by an admin.
  • Batch updated to every actively enrolled student when a batch's dates, days, times or details change.
  • Course completed when a student finishes the last lesson of an online course.
  • Certificate revoked to the student, with the program named.

Each one carries a type, a category (information, success, warning or error), a title, a message, an optional link and a reference to the record it is about, so the portal can take the reader straight to the batch or certificate concerned.

Sending to the right people

The service can notify one user, a list of users (every student in a batch), everyone with a role, or all admins at once. Sending to a batch's students is done after the change is saved and outside the request's success path: if a notification fails to write, the batch update itself still succeeds.

Reading them

A bell in the header of every portal shows the unread count. Opening it lists the latest notifications with their time; each can be marked read, deleted, or all marked read at once. The list is paginated and can be filtered to unread only, so a student who was away for a month is not handed a wall of old alerts.

Chapter 12

Why protonfit.com had no page titles, and a retrofit that left 22 pages alone

A WhatsApp message started it: a link to protonfit.com previewed as a bare card, with "protonfit.com" for both its title and its description.

Home training programs on protonfit.com
Home training on protonfit.com: one-to-one programs filtered by online, offline or hybrid delivery.

The cause

The site's root layout began with "use client". Next.js ignores metadata exported from a client component, so the whole site had been shipping with no <title>, no meta description and no Open Graph or Twitter tags. All 22 public page files were client components too, so none of them could export its own. There was no favicon beyond the framework's default, no app icons, no share image, no robots.txt and no sitemap.

The fix, without rewriting the pages

  • The root layout became a server component. The interactive shell (navbar, footer and login modal, chosen by path) moved unchanged into its own client component.
  • One file holds the site's SEO facts, and each static route got a small server layout with its own title, description and canonical URL. The page files themselves were not touched.
  • Blog, course, workshop, online-course and training detail pages build their metadata on the server from the public API.
  • A script renders the favicon, app icons and a 1200 × 630 share image from the logo with sharp, including a small ICO writer so it needs no extra dependency.
  • robots.txt keeps the student, trainer and admin areas out of search, a sitemap lists static and dynamic URLs, and Organization structured data describes the academy.

Facts before markup

The audit also found that the phone number and address in the footer looked like template values, and that contact details lived in three copies that disagreed. We did not put business structured data on top of that. The academy supplied its real details, and phone, email, address and social links now come from admin settings that feed the footer, the contact page and the structured data from one place.

The production build came out at 64 pages, and the live site now serves titles, previews, robots.txt and a sitemap.

Group training program detail with pricing tiers on protonfit.com
A group-training program on protonfit.com with per-person pricing tiers by group size and its prerequisites.

Chapter 13

A daily AI blog that publishes once, even in cluster mode

Proton's API runs in Node cluster mode: a master process and a worker for every CPU core. A scheduled job placed naively would run in each of them and publish the same post several times a day. The academy asked for a blog that writes and publishes itself once a day.

Auto-blog automation wizard, step one, with date range and category options
The AI auto-blog wizard's first step sets the publishing window, frequency and categories for a content calendar the scheduler publishes from. (Opened only; nothing generated.)

Two guards, not one

The scheduler starts only in the cluster's master process. That holds for one server but not for two, so each day's run must also win an atomic MongoDB update: set lastRunOn to today's UTC date only where it is not already today. Whichever process gets there first publishes; every other process finds nothing to update and stops. The day's posting hour is picked at random within Indian daytime, and that choice is claimed the same atomic way, so every process agrees on it.

Plan first, then publish

A three-step wizard in the admin console plans the content:

  1. Pick categories, or have the AI suggest new ones.
  2. Review a dated schedule of titles, and regenerate, reorder or move any of them.
  3. Generate drafts in the background, each with a cover: a Lorem Picsum photo with the title and category drawn over it using sharp, stored in S3.

An hourly tick publishes the draft dated for today. A second hourly job writes drafts for any topic still waiting, for example after the admin closed the wizard early. Each topic is claimed atomically, from scheduled to generating, so the catch-up job and a wizard run never write the same post twice. In testing, one of six drafts stayed unwritten because a backend restart had interrupted it; the catch-up job generated it without anyone pressing a button.

Where it stands

On a local database a tick published a post with its cover in S3, and a second tick on the same day did nothing. The feature is not deployed yet: it needs a production AI API key and fonts on the server for the cover text.

Blog posts list with categories, status and schedule
Blog posts with categories, author, status and the column that shows whether a post was scheduled by the automation.

By the numbers

  • 22Public page files that were client components when the site was found serving no titles
  • 64Pages in the production build after the SEO retrofit
  • 8Home-page sections the academy edits from its CMS
Features

What we built into Proton Fitness Academy

Training programs

Group training, home training and workshops each have a public listing and detail page, a schedule and their own enrolment.

Academy courses in dated batches

A course runs as batches with dates, days, time slots, a trainer, a price and a capacity. The server generates the sessions from that pattern, and each batch shows as upcoming, enrolling or ongoing.

Attendance per session

Attendance is recorded for every session. A student sees sessions held, present and absent counts and an attendance percentage for each batch.

Student portal

Today's classes with time and studio, all enrolments, an online-course player with lesson progress, and one calendar of every session that can be subscribed to as a calendar feed.

Trainer portal

Trainers see every workshop, training program and academy batch assigned to them, and a teaching calendar colour-coded by program type.

Certificates

Enrolment creates a pending certificate; an admin issues it with attendance and grade, one at a time or in bulk. Each gets a number such as PROTON-2026-GRP-000001 and a SHA-256 signature and can be revoked, and the site has a public verification page.

Razorpay checkout and manual payments

Orders are priced on the server and payment signatures checked with HMAC-SHA256. Admins can also record a manual payment and process refunds from the console, and every payment gets an invoice number.

Home-page CMS

Eight fixed home-page sections, from the hero slider (one to eight slides) to the featured blog, are edited in place with character limits, while the layout stays fixed.

SEO and link previews

Per-page titles and descriptions, server-built metadata for blog and course pages, icons and a share image generated from the logo, plus robots.txt, a sitemap and structured data.

Daily AI blog (built, not yet live)

A three-step wizard plans categories, a dated title schedule and cover images; an AI model drafts the posts, and a scheduler publishes one each day.

Online courses with progress

Sections and lessons with video, a progress record per student, completion percentage, resume where you stopped and a completion notification.

Personal calendar feed

Every student gets a private subscription link that keeps all their classes in Google Calendar, Apple Calendar or Outlook, plus a single-class .ics download.

Refunds and invoices

Every payment gets a yearly invoice number; refunds are limited to paid payments and the amount paid, and go back through Razorpay where the payment came from.

Notifications

Enrolment confirmations, batch changes, course completions and certificate revocations, with unread counts and mark-all-read.

Real screens · 29

What Proton Fitness Academy looks like

On desktop 13

Project details
Tech stack
Next.jsReactRedux ToolkitTiptapRechartsNode.jsExpressMongoDBRazorpayAWS S3sharpnode-cronAI text-generation API
Timeline & team
May 2025 – Jul 2026
FAQ

Questions about this project

How does Proton run a months-long course as dated batches?

Each academy course has batches with start and end dates, days of the week, time slots, a trainer, a price and a capacity. The server generates every session from that pattern, attendance is recorded per session, and students see sessions held, present, absent and their attendance percentage.

How does Proton's AI blog avoid posting twice when the server runs in cluster mode?

The scheduler starts only in the cluster's master process, and each day's run must also win an atomic MongoDB update on the date of the last run, so only one process can publish per UTC day. The blog is built and tested on a local database and is not yet switched on at protonfit.com.

Why did protonfit.com show no title or description in WhatsApp link previews?

The root layout was a client component, and Next.js ignores metadata exported from client components, so the site served no title, description or Open Graph tags. We made the layout a server component, moved the interactive shell into its own client component and added per-page metadata, icons, a sitemap and robots.txt.

How are Proton certificates numbered and issued?

Enrolling in a workshop, training program or academy batch creates a pending certificate. An admin issues it with attendance and grade, and it carries a number in the form PROTON-2026-GRP-000001 and a SHA-256 signature; it can be revoked later.

How does Proton stop a batch from taking more students than it can teach?

Every enrolment, online or entered by an admin, runs one server-side check that counts the batch's active and completed registrations at that moment and compares them with its class size. Checkout runs it again after the payment is verified, because the batch can fill up while a student is paying.

What does a Proton certificate record besides the student's name?

When an admin issues it, a certificate can carry the attendance percentage, the sessions attended out of the total, a score, a grade and the trainer who signs it with their designation. Its number shows the year and the program type, and the record keeps who issued it and when.

How does a Proton student keep every class in their own calendar app?

The schedule page gives each student a private subscription link. Added to Google Calendar, Apple Calendar or Outlook, it lists every class across their enrolments and updates when a batch changes. Single classes can also be downloaded as an .ics file.

More work

Other things we shipped

All projects
Storafleet fleet overview with storage totals, trend line, transfers list and per-provider footprint barsFeatured
Saasfor Storafleet

Storafleet — Multi-Cloud Storage Control Plane

Storafleet is CountryDevs' own SaaS control plane for object storage. Teams connect buckets they already own on 50+ providers, including AWS S3, Cloudflare R2, Backblaze B2, Wasabi and MinIO, then browse, migrate, search, secure and cost-check them from one console.

Next.js 15ReactRedux ToolkitNode.js+11
50+Storage providers in the connection roster
Case study
Pakka Logistics home page hero on desktopFeatured
Mobile Appfor Pakka Logistics

Pakka Logistics — On-Demand Goods Delivery Platform

Pakka Logistics is an on-demand goods delivery platform for India. We built all of it: Android apps for customers and drivers, a business portal, an operations console and the website. The web platform is live and both Android apps are on Google Play; the two iPhone apps are in App Store review.

React NativeTypeScriptRedux ToolkitNode.js+12
96.3%API routes exercised by a probe before launch (260 of 270)
Case study
Superadmin stories grid with photo storiesFeatured
Mobile Appfor Slic Solutions Private Limited

LetSlic — Social Media App with Group Chat, Stories and Premium

LetSlic, listed on Google Play as Slic, is a social app for photo posts, 24-hour stories and real-time chat with group moderation. We built it for Slic Solutions Private Limited: the React Native app, two Node.js APIs, the superadmin console and the website, plus Premium and ads.

React NativeTypeScriptReduxNode.js+13
About 25Days of build work, across a project that ran Jun 2025 – Jul 2026 at the client's pace
Case study
Got a project?

Let's build the
next one together

Tell us what you're trying to ship and which project here is closest to it. We'll reply with the questions that shape the plan, then start with a two-week Discovery Sprint, so you see the screens and the plan before any code is written.

Not ready for a full build? Start with a Discovery Sprint, or get a code audit of an app someone else built. See how a project runs with us.

More on what we build from Bangalore for Indian businesses: App Development Company in Bangalore.