Change Log

Date-stamped record of what changed, when it changed, and what was affected.

Update Rule

Every SEO, indexing, sitemap, configuration, or content change must include a new entry before merge/deploy using this format:date, summary, scope, status.

2026-08-01

deployed

Added 10 new PSIR/Essay blog posts (scheduled every other day, 31 Jul-18 Aug) with cover images and internal cross-links; extended the article renderer to support [text](url) inline links; added a scheduled GitHub Actions workflow to trigger a daily rebuild so cPanel's auto-deploy picks up each post on its scheduled date without manual redeploys.

Scope

  • src/data/blog-posts.ts
  • src/app/resources/[slug]/page.tsx
  • public/images/blog/*.webp
  • scripts/generate-blog-covers-batch4.mjs
  • .github/workflows/scheduled-deploy-trigger.yml

2026-08-01

deployed

Marked the three now-past PSIR masterclasses (12, 19, 26 July) as isDraft — they're no longer in generateStaticParams, so they're gone from the /masterclass listing, return a real 404 if visited directly, and no longer appear in the build-regenerated sitemap.xml. Kept their data in masterclasses.ts (just hidden) rather than deleting outright, in case the copy is needed again.

Scope

  • src/data/masterclasses.ts

2026-08-01

deployed

Added a fourth PSIR masterclass — 'How to Read Political Thinkers' — live 2 August 2026, 10:00 AM IST, as a new entry in schedules.json (psir-masterclass-4) and masterclasses.ts (slug psir-4), with its own hero copy, SEO metadata, 7 learn points, and FAQs. Registered on the masterclass listing and sitemap the same way as the existing PSIR series (psir, psir-2, psir-3).

Scope

  • src/data/schedules.json
  • src/data/masterclasses.ts
  • public/sitemap.xml

2026-07-29

deployed

Closed gaps in the 'all fields required, email always verified' policy across every lead form: Contact form's WhatsApp Phone and Subject, and the Enroll form's Preferred Mode and Message, were previously optional client-side — now required on all five forms (Newsletter, Contact, Enroll, Inquiry/PDF-download, Campaign Registration). Also added server-side enforcement in send-email.php (a per-form required-field map, checked right after OTP validation) since the client-side 'required' attribute alone could be bypassed by a direct API call — previously only the OTP token itself was enforced server-side. The required-field check runs before the single-use token is invalidated, so a rejected request (e.g. a field genuinely left blank) doesn't burn the user's OTP and force them to re-verify their email just to retry.

Scope

  • src/app/contact/ContactForm.tsx
  • src/app/enroll/EnrollForm.tsx
  • public/api/send-email.php

2026-07-24

deployed

Replaced the scattered lead sheets with a single 'Student Registrations' Google Sheet (one row per person, deduplicated by email/phone across course and masterclass registrations) via a new isolated Apps Script Web App — never touches the existing live leads script. Every course/masterclass registration (not newsletter or generic contact-form leads) now best-effort posts to this sheet from send-email.php, appending new interests and updating Last Activity on repeat registrations instead of creating duplicate rows.

Scope

  • public/api/config.php
  • public/api/send-email.php

2026-07-23

deployed

Replaced the psir-masterclass-3 (26 July) placeholder Zoom link with the real one — registrant confirmations and the 1-hour reminder were sending an unusable REPLACE-WITH-PSIR-3-ZOOM-LINK URL to anyone who registered before this fix.

Scope

  • src/data/schedules.json
  • public/schedules.json

2026-07-22

deployed

Course registrants (schedules.json kind === 'course') now get a distinct WATI WhatsApp confirmation (course_enrollment_confirmation: 'we've received your enrollment request, our team will contact you shortly') instead of the webinar_confirmation template's join-now link — they registered for a multi-week course, not a specific live session.

Scope

  • public/api/config.php
  • public/api/send-email.php

2026-07-21

deployed

Wired the Google Ads 'Submit lead form' conversion event (AW-17848425972/RZOECK_ij9QcEPS75b5C) into the /thank-you page, firing directly via gtag.js alongside the existing GA4 generate_lead event — each deduplicated independently per session so neither is skipped by the other.

Scope

  • src/lib/gtag.ts
  • src/components/seo/ThankYouConversion.tsx

2026-07-21

deployed

Added a standalone Google Ads gtag.js snippet (AW-17848425972) alongside the existing GTM container, for Google Ads conversion tracking that doesn't route through GTM.

Scope

  • src/lib/gtag.ts
  • src/components/seo/GoogleAdsTag.tsx
  • src/app/layout.tsx

2026-07-21

deployed

Wired Google conversion tracking through the existing GTM container (GTM-P995JGG8): added a dataLayer helper that fires GA4 generate_lead/sign_up events plus a generic conversion event on every verified form submission (registration, enrollment, contact, PDF download, newsletter) and on the /thank-you page, with session deduplication to avoid double-counting redirects.

Scope

  • src/lib/gtag.ts
  • src/components/seo/GoogleTagManager.tsx
  • src/components/seo/ThankYouConversion.tsx
  • src/app/layout.tsx
  • src/components/RegisterInterest.tsx
  • src/components/LeadCaptureModal.tsx
  • src/app/contact/ContactForm.tsx
  • src/app/enroll/EnrollForm.tsx
  • src/components/layout/Footer.tsx
  • src/app/thank-you/page.tsx

2026-07-18

deployed

Added 4 new PDF study materials (India's Gender Crisis, Rare Earth Metals & India's Defence Industry, Saudi Arabia and Iran conflict analysis, and India's Welfare Politics / freebies debate) to the study materials library.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/Gender Inequality.pdf
  • public/docs/study-materials/Rare Earth Weapon.pdf
  • public/docs/study-materials/saudi arabia and iran watermark.pdf
  • public/docs/study-materials/welfare politics watermark.pdf

2026-07-16

deployed

Fixed the real reason WhatsApp class reminders weren't delivering: WATI's sendTemplateMessage API requires each parameter's "name" to match the template's ORIGINAL named placeholder (name/class_name/time_info/link) rather than the compiled positional {{1}}-{{4}} the code was sending — the mismatch silently failed with a generic "check your template" error on every send, even though class_reminder_v2 was fully approved. Confirmed via direct API testing against the live account (isolated the bug from an initial red herring: the account is on a WATI trial, and a same-account UI broadcast send succeeded while the direct API failed, which first looked like a plan/API restriction but turned out to be this parameter-naming mismatch). Also added the missing WATI_API_ENDPOINT/WATI_API_TOKEN environment variables to the live Hostinger deployment (previously only present locally), so WhatsApp sends now actually run in production instead of silently no-op'ing. Verified with a real delivered WhatsApp message.

Scope

  • public/api/send-reminder.php

2026-07-15

deployed

Created the WATI WhatsApp templates for class reminders: submitted class_reminder (Utility category, 4 variables: name/class name/combined time+date sentence/Zoom link) — approved by WhatsApp's per-template rules only after two rejected attempts (too many variables for the message length; then a variable at the very end of the body). Also fixed send-reminder.php, which still called WatiHelper::sendTemplate() with the old 5-variable shape from before those constraints were discovered — never committed after the original template work. When the template was later deleted and needed recreating, WhatsApp blocks reusing a deleted template's exact name for a cooldown period, so it was recreated as class_reminder_v2 and WATI_REMINDER_TEMPLATE_NAME in config.php now points at that name. Also attempted an Authentication-category OTP template via the same API — WATI's API rejected every variation of the required OTP button with a generic, non-actionable error, so that one still needs to be created through the WATI dashboard directly (deferred by the account owner for now).

Scope

  • public/api/send-reminder.php
  • public/api/config.php

2026-07-15

in-progress

Added genuine two-factor phone verification: when a phone/WhatsApp number is given, a SEPARATE 6-digit code (independent from the email code) is now generated and sent via WhatsApp, and both codes must be entered correctly before a form submits — proving the visitor actually has access to both channels, not just whichever one they happened to check. Rewrote send-otp.php/verify-otp.php's session format (email_otp_hash + phone_otp_hash, independent attempt counters, 5 tries each) and added the second code field to all 4 forms that collect a phone number (registration, contact, enrollment, PDF download). Built fail-safe: phone verification only becomes required for a given attempt if the WhatsApp send actually succeeds — since WATI's templates aren't approved yet, every attempt right now correctly falls back to email-only, exactly like before, rather than locking visitors out. Verified the whole flow (missing code, wrong email code, wrong phone code, both correct) against the live backend with seeded test sessions. Once WATI's templates are approved, two-factor kicks in automatically with no further code changes.

Scope

  • public/api/send-otp.php
  • public/api/verify-otp.php
  • src/lib/otp.ts
  • src/components/RegisterInterest.tsx
  • src/app/contact/ContactForm.tsx
  • src/app/enroll/EnrollForm.tsx
  • src/components/LeadCaptureModal.tsx

2026-07-15

in-progress

Wired WhatsApp delivery (via WATI) alongside email for the OTP verification code and the 1-hour class reminder — the two notification types requested. Added a non-blocking WatiHelper (public/api/wati.php) that calls WATI's REST API; a WhatsApp send failure never affects the email flow it accompanies. Threaded the phone/WhatsApp number through every OTP call site that collects one (masterclass/course registration, contact form, enrollment, PDF-download lead capture — the newsletter footer form has no phone field and stays email-only) and through the Google Sheets reminder trigger (added a 'Phone' column lookup). NOT yet live: requires two things only the account owner can provide — (1) WATI_API_ENDPOINT/WATI_API_TOKEN from the WATI dashboard (Settings > API Docs), and (2) two new WhatsApp message templates (otp_verification, class_reminder) created in WATI and approved by Meta — the account currently has no usable templates. Until both exist, WhatsApp sends silently no-op and email is unaffected.

Scope

  • public/api/wati.php
  • public/api/config.php
  • public/api/send-otp.php
  • public/api/send-reminder.php
  • scripts/google-apps-script-reminder.js
  • src/lib/otp.ts
  • src/components/RegisterInterest.tsx
  • src/app/contact/ContactForm.tsx
  • src/app/enroll/EnrollForm.tsx
  • src/components/LeadCaptureModal.tsx

2026-07-11

deployed

Restored the early-bird countdown/deadline on the Essay Mentorship and PSIR 2027 landing pages (removed earlier today), but made it self-advancing instead of hand-maintained: added nextRollingDeadline() in src/lib/rollingDeadline.ts, which steps a deadline forward in fixed 7-day increments from a fixed anchor date, always landing on the next occurrence that hasn't passed yet relative to build time. Since this is a static export with no server, the deadline is computed once at each rebuild — so once the current early-bird window lapses, the very next deploy automatically shows a deadline exactly one week later, with no manual date edit required. This replaces the earlier bug where the deadline had been manually bumped once (a July 1st commit) but never followed up after it lapsed again, leaving the countdown reading 'Offer closed' next to a banner insisting the offer was still live. The essay page's cohort 'start date' is likewise derived as deadline + 1 day rather than hardcoded.

Scope

  • src/lib/rollingDeadline.ts
  • src/app/courses/essay/page.tsx
  • src/app/courses/psir-mains-2027/page.tsx

2026-07-11

deployed

Removed the expiring early-bird countdown/deadline mechanic from the Essay Mentorship and PSIR 2027 landing pages after finding both were showing self-contradicting, stale content live: the hero banner said 'Early-bird 15% off — ends 7 July 2026' while the countdown directly below it read 'Offer closed', and 'Starts 8 July 2026' had also already passed — the deadline had been manually bumped once before (a July 1st commit) but never followed up after it lapsed again. The pages' own JSON-LD schema (Offer.validThrough, CourseInstance.startDate) carried the same expired dates. This kind of stale, self-contradicting commercial page is a plausible contributor to /courses/essay/ sitting un-indexed in Google despite being fully crawlable (no robots/noindex/canonical issue found). Replaced with flat, evergreen pricing (no countdown, no compare-at price, no hardcoded dates) and 'rolling cohorts' language on both pages, so this can't silently go stale again — removes a recurring manual-maintenance trap rather than just re-extending the deadline.

Scope

  • src/app/courses/essay/page.tsx
  • src/app/courses/psir-mains-2027/page.tsx

2026-07-11

deployed

SEO indexability fix: blog links and future-post gating were only enforced client-side, so a non-JS crawler's first pass saw zero real links on /blog and every post page, and 16 future-dated posts were fully crawlable with complete article content despite not being publicly linked yet. Replaced ScheduledArticleGate/PublishedBlogGrid's mounted-state gating with a plain server-rendered BlogGrid component and a generateStaticParams() filter on /resources/[slug] that only builds pages for already-published posts — a scheduled post's page now simply doesn't exist until a rebuild happens on/after its date (real 404, not crawlable-but-hidden HTML). Also fixed 57 sitemap URLs missing their trailing slash (each was 301-redirecting before Google could reach the real page), added the 5 missing /masterclass/* pages to the sitemap, fixed per-post lastmod dates (previously frozen to one shared timestamp across every blog URL), de-duplicated the identical <title> shared by the 3 PSIR masterclass pages, removed /_next/ from robots.txt's disallow list (was blocking Googlebot from fetching JS chunks), and extended validate-sitemap.mjs to check masterclass URLs so a missing page like this can't ship silently again. Verified against a real production build (not just dev server) — confirmed future posts are genuinely absent from output, published posts unaffected.

Scope

  • src/app/resources/[slug]/page.tsx
  • src/components/blog/BlogGrid.tsx
  • src/app/blog/page.tsx
  • src/components/sections/BlogPreview.tsx
  • src/data/masterclasses.ts
  • public/robots.txt
  • public/sitemap.xml
  • scripts/generate-blog-sitemap.mjs
  • scripts/validate-sitemap.mjs

2026-07-11

deployed

Added 8 new SEO blog posts generated from source PDFs on rare earth elements/defence supply chains, Trump-tariff trade strategy, women's economic participation, and Saudi-Iran middle-power diplomacy, scheduled every other day from July 10-24, 2026. 4 of the source PDFs overlapped with existing published posts (Trump Tariffs/MSME, Saudi-Iran, Gender Crisis, China REE export controls) — each new post was deliberately angled to cover genuinely different ground (e.g. trade-bloc strategy response instead of tariff-impact, PSIR-theory application instead of a general current-affairs summary, economic-participation stats instead of the broad multi-dimensional gender picture) rather than duplicating the existing article. Generated 8 matching branded cover images via a new scripts/generate-blog-covers-batch3.mjs (two new shared motifs: globe for trade/IR, chip for the semiconductor-comparison post).

Scope

  • src/data/blog-posts.ts
  • src/lib/images.ts
  • scripts/generate-blog-covers-batch3.mjs
  • public/images/blog/
  • public/sitemap.xml

2026-07-10

deployed

Every verified form submission is now also added to the Resend audience / contact list, so the mailing list grows from every form fill — contact form, PDF-download lead capture, course/masterclass registration, enrollment, and the newsletter signup alike. Added ResendMailHelper::addContact() (and getAudienceId(), which auto-discovers the account's audience once and caches it in data/resend_audience.json, or honours an optional RESEND_AUDIENCE_ID override), called from send-email.php after OTP verification. Non-blocking: any contact-sync failure is logged and never affects lead capture. `unsubscribed` is deliberately omitted so re-submitting a form never re-subscribes someone who opted out.

Scope

  • public/api/resend.php
  • public/api/send-email.php

2026-07-10

deployed

Replaced the 26 July Ethics masterclass with a third PSIR Optional masterclass. Removed the Ethics masterclass entry/page and its ethics-masterclass schedule; added a new /masterclass/psir-3 page (psir-masterclass-3, 26 Jul, cloned from the existing PSIR masterclass) and wired getCourseSlug() so its registrations map to the new schedule key for reminders/confirmations. Added a 301 redirect from /masterclass/ethics to /masterclass/psir-3, and repointed a blog reference from the retired masterclass to the Ethics course. NOTE: the psir-masterclass-3 Zoom link in schedules.json is a placeholder and must be replaced before the session.

Scope

  • src/data/schedules.json
  • src/data/masterclasses.ts
  • public/api/resend.php
  • .htaccess
  • src/data/blog-posts.ts

2026-07-10

deployed

Published the Masterclass on Essay recording. Switched essay-masterclass in schedules.json to kind=recording with the YouTube link, so registrants now receive the recording link in their confirmation email (instead of a Zoom link) and the 1-hour reminder is disabled. Flipped the /masterclass/essay page from 'recording coming soon' to an on-demand recording (recordingUrl) with matching hero, badges, FAQ, and registration copy.

Scope

  • src/data/schedules.json
  • src/data/masterclasses.ts

2026-07-10

deployed

Added a hidden, password-gated internal ops page at /ops/email-automations.php that documents every automated email the site sends (OTP verification, admin lead alert, student welcome/seat confirmation, and the 1-hour class reminder), plus related non-email lead syncs. The page is server-side password protected (password held in PHP, never shipped to the browser; body renders only after login) and blocked from search indexing three ways: X-Robots-Tag header, <meta robots>, and a robots.txt Disallow on /ops/. The reminder section reads schedules.json live to show which classes currently have an active reminder.

Scope

  • public/ops/email-automations.php
  • public/robots.txt

2026-07-10

deployed

Explicitly excluded newsletter form submissions from the Privyr CRM forwarding in send-email.php. Newsletter subscribers are a mailing-list audience, not sales leads, so they are now skipped via a form-name guard regardless of any course context in the payload — hardening the previous implicit exclusion (which only relied on newsletter submissions never carrying a course/resource) against future regressions.

Scope

  • public/api/send-email.php

2026-07-09

deployed

Made email OTP verification actually mandatory for every lead form (Contact, PDF-download lead modal, course/masterclass registration, Enroll page, and newly the footer newsletter form) instead of a client-side-only UX step. verify-otp.php now mints a short-lived single-use token on success; send-email.php rejects any submission without a valid, matching, unexpired token. Also removed a debug log that was writing plaintext OTP codes to disk.

Scope

  • public/api/send-otp.php
  • public/api/verify-otp.php
  • public/api/send-email.php
  • src/lib/otp.ts
  • src/app/contact/ContactForm.tsx
  • src/app/enroll/EnrollForm.tsx
  • src/components/LeadCaptureModal.tsx
  • src/components/RegisterInterest.tsx
  • src/components/layout/Footer.tsx

2026-07-07

deployed

Backdated 10 of the scheduled posts (SEZ, RBI monetary policy, NIA Act, NHRC, NMC, Domestic Violence Act, Soil Health Card Scheme, classical languages/dance forms, India's states & UTs) from their original August slots to an alternating June 1-19 schedule instead, so all 10 are live immediately rather than still pending. No content changes — dates only.

Scope

  • src/data/blog-posts.ts

2026-07-07

deployed

Three blog fixes plus a new homepage section. (1) Fixed all 25 new posts double-rendering their FAQ section — each had FAQs both inline in `content` and in the structured `faqs` array; stripped the inline copy, keeping only the structured one (which also emits FAQPage schema). (2) Blog listing, homepage preview, and related-posts now sort strictly newest-first instead of by array-insertion order. (3) Discovered and fixed a real inefficiency introduced alongside the scheduling work: PublishedBlogGrid was receiving the *entire* BlogPost array as a prop (full article text and all) purely to render summary cards, bloating every page's hydration payload; added a BlogPostSummary type + toBlogPostSummary() so only the fields actually rendered cross the server/client boundary. (4) Added UpcomingSessionsCarousel — a horizontally-scrollable homepage section (directly below the hero) showing upcoming live masterclasses (via the existing upcomingMasterclasses() helper, gated the same way as blog scheduling — the visitor's own clock, not build time) and the newest study material.

Scope

  • src/data/blog-posts.ts
  • src/components/blog/PublishedBlogGrid.tsx
  • src/app/blog/page.tsx
  • src/components/sections/BlogPreview.tsx
  • src/app/resources/[slug]/page.tsx
  • src/components/sections/UpcomingSessionsCarousel.tsx
  • src/app/page.tsx

2026-07-07

deployed

Generated and wired branded cover images for all 25 new blog posts. The connected AI image-generation tool (Higgsfield) had a persistent parameter-validation bug, so instead extended the existing generate-blog-covers.mjs approach (SVG templates rendered to WebP via sharp) with a new scripts/generate-blog-covers-batch2.mjs — 12 reusable category-level motifs (PSIR, essay, ethics, strategy, documents, economy, security, culture, etc.) shared across topically related posts, matching the site's navy/coral brand palette exactly. Registered all 25 in src/lib/images.ts and wired the image field into each post.

Scope

  • scripts/generate-blog-covers-batch2.mjs
  • public/images/blog/
  • src/lib/images.ts
  • src/data/blog-posts.ts

2026-07-07

deployed

Put the 25 new blog posts on a real publish schedule: one every other day from 1 July through 18 August (today's slot is the Essay Pyramid Method post). Since this is a static export with no server, scheduling only works if visibility is checked with the *visitor's own clock*, not at build time — added an isPublished() helper plus two client components (PublishedBlogGrid for listings/related-posts, ScheduledArticleGate for the detail page) that do exactly that: the blog listing, homepage preview, and related-posts sections now only ever show already-published posts, and visiting a not-yet-published post's URL directly shows a 'coming soon' placeholder instead of its content — both update automatically as each date arrives, with zero redeploy needed. Also added scripts/generate-blog-sitemap.mjs (wired into `npm run build`) so sitemap.xml's blog-post entries regenerate from each post's scheduled date on every future build, and updated validate-sitemap.mjs to expect the same already-published subset — no more hand-editing sitemap.xml for this. Cover images for the 25 posts were not generated in this pass: the Higgsfield image-generation tool's `params` argument is failing MCP-side validation (every shape tried lands as a string, not an object) regardless of input — a tool bug, not a credits issue this time.

Scope

  • src/data/blog-posts.ts
  • src/components/blog/PublishedBlogGrid.tsx
  • src/components/blog/ScheduledArticleGate.tsx
  • src/app/blog/page.tsx
  • src/components/sections/BlogPreview.tsx
  • src/app/resources/[slug]/page.tsx
  • scripts/generate-blog-sitemap.mjs
  • scripts/validate-sitemap.mjs
  • package.json
  • public/sitemap.xml

2026-07-07

deployed

Published 25 new SEO blog posts from the Ubersuggest keyword content plan, covering the PSIR optional and Essay funnels (notes, PYQs, subject overview, essay-writing method, handwritten/model essay samples), an Ethics GS-IV case-study piece, a Mains-strategy companion post, a previous-year-papers hub, evergreen UPSC-basics explainers (full form, syllabus), and 13 GS-2/GS-3 topics the team had already flagged for tracking but never written (Fundamental Rights/Duties, Union Territories, SEZ, RBI monetary policy, NIA Act, NHRC, NMC, Domestic Violence Act, Soil Health Card Scheme, classical languages/dance forms, India's states & UTs). Every post follows the existing article format (intro keyword usage, H2 sections, one course-callout blockquote, FAQ section) and additionally populates the faqs field so FAQPage JSON-LD now fires — previously unused by any of the 13 pre-existing posts. Cover images were intentionally not generated for this batch (flagged separately, pending confirmation of AI image-credit budget) — posts render correctly without one.

Scope

  • src/data/blog-posts.ts
  • public/sitemap.xml

2026-07-05

deployed

Added 'The Pyramid of a Great UPSC Essay' PDF (the Roundtable IAS Essay Masterclass deck — an eight-level framework for writing a high-scoring UPSC Mains essay) to the study materials library.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/Pyramid_of_a_Great_UPSC_Essay.pdf

2026-07-05

deployed

Set the 'Masterclass on Essay' to a 'recording available soon' holding state now that its live session has ended. Added a reusable recordingComingSoon flag: when set, the detail page and listing card drop the date, countdown, and register button and show 'recording available soon' instead, and the detail page omits the Event/VideoObject schema. Switch the masterclass to recordingUrl once the recording is published.

Scope

  • src/data/masterclasses.ts
  • src/app/masterclass/[slug]/page.tsx
  • src/app/masterclass/MasterclassList.tsx
  • src/app/masterclass/page.tsx

2026-07-04

deployed

Automated the class reminder system end-to-end. Added src/data/schedules.json as the single source of truth for every class date, time, and Zoom/recording link (wired into masterclasses.ts and courses.ts), replacing the hardcoded CLASS_SCHEDULES array previously duplicated in public/api/config.php. A new build step (scripts/generate-schedules.mjs) publishes it as /schedules.json on every deploy. Google Sheets now stores a 'Course Slug' and 'Reminder Sent' column per lead (public/api/send-email.php forwards the resolved slug; scripts/google-apps-script-lead-capture.js persists it), and a new 15-minute Apps Script trigger (scripts/google-apps-script-reminder.js) reads /schedules.json, finds leads whose class starts within the hour, and calls a new on-demand endpoint (public/api/send-reminder.php) to send the reminder — replacing the old server cron job (public/api/cron.php, deleted).

Scope

  • src/data/schedules.json
  • src/data/masterclasses.ts
  • src/data/courses.ts
  • src/lib/types.ts
  • scripts/generate-schedules.mjs
  • public/api/config.php
  • public/api/send-email.php
  • public/api/send-reminder.php
  • scripts/google-apps-script-lead-capture.js
  • scripts/google-apps-script-reminder.js
  • package.json

2026-07-01

deployed

Converted 'Masterclass on Answer Writing' from a live session into an on-demand recording. Removed the date and countdown across its listing card and detail page (now shown as 'Recording · Watch anytime'), and switched its registration email to send the YouTube recording link instead of a Zoom joining link. Added a reusable recordingUrl field so any masterclass can be flagged as a recording: such pages emit VideoObject schema instead of a dated Event, and the 1-hour reminder email is disabled for them.

Scope

  • src/data/masterclasses.ts
  • src/app/masterclass/[slug]/page.tsx
  • src/app/masterclass/MasterclassList.tsx
  • src/app/masterclass/page.tsx
  • public/api/config.php
  • public/api/send-email.php

2026-06-27

deployed

Drafted all masterclasses except 'Masterclass on Answer Writing' (Ethics, PSIR, Essay) by adding an isDraft property in masterclasses data and updating routes to exclude draft sessions from the listing page (/masterclass) and un-publish their dedicated detail landing pages until needed again.

Scope

  • src/data/masterclasses.ts
  • src/app/masterclass/[slug]/page.tsx

2026-06-26

deployed

Added 4 new PDF study materials ('The Carbon Books Are Wrong', 'NFHS-6 Analysis', 'Green Colonialism or Sustainable Progress', and 'The Indian Monsoon') to the study materials library.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/THE CARBON BOOKS ARE WRONG, AND INDIAN FARMERS ARE PAYING THE PRICE (final pdf).pdf
  • public/docs/study-materials/NATIONAL FAMILY HEALTH SURVEY -6 (NFHS-6)final pdf.pdf
  • public/docs/study-materials/Green Colonialism or Sustainable Progress (final pdf).pdf
  • public/docs/study-materials/indian monsoon watermark final pdf.pdf

2026-06-26

deployed

Added 'The Delimitation Debate: Federalism, Representation & Constitutional Challenges' PDF study material to the study materials library.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/the delimitation watermark final pdf.pdf

2026-06-25

deployed

Added 'The Feminization of Climate Vulnerability' PDF study material to the study materials library.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/The_Feminization_of_Climate_Vulnerability_branded.pdf

2026-06-25

deployed

Added 'Energy Subsidies, Fiscal Stress and India's Development Challenge' PDF study material to the study materials library.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/Energy_Subsidies__Fiscal_Stress_and_India_s_Development_Challenge_branded.pdf

2026-06-24

deployed

Masterclass listing now shows all masterclasses, including past/completed sessions (e.g. Answer Writing), instead of only upcoming ones. Removed the client-side upcoming-only date filter from MasterclassList, relabelled the section from 'Upcoming Masterclasses' to 'Our Masterclasses', and re-published Ethics, PSIR, and Essay (removed their isDraft flags) so all four detail pages are live and every listing card links correctly. The isDraft mechanism is retained for future use.

Scope

  • src/app/masterclass/MasterclassList.tsx
  • src/app/masterclass/page.tsx
  • src/data/masterclasses.ts

2026-06-24

deployed

Added strict cache-bypass directives to .htaccess files to prevent Hostinger LiteSpeed server and browser from caching HTML pages, resolving the 'broken layout' deployment issue caused by stale HTML referencing missing hashed CSS/JS chunks. Added [E=Cache-Control:no-cache] for dynamic routes and standard no-store headers for HTML, while preserving immutable caching for static assets.

Scope

  • .htaccess
  • public/.htaccess

2026-06-23

deployed

Implemented a secure inline email OTP verification flow on lead capture forms (resource download modal, course registration popup, and program enrollment page). Swaps the email input inline to a 6-digit OTP code entry field on submit to prevent invalid entries while keeping other form fields visible. Includes inline resend controls, a 'Change email' option that preserves the typed email via React key reconciliation, and backend session validation APIs (send-otp.php, verify-otp-php) with rate limits and failure thresholds. Also created local OTP log files for testing and updated next.config.ts local dev rewrites.

Scope

  • src/app/enroll/EnrollForm.tsx
  • src/components/LeadCaptureModal.tsx
  • src/components/RegisterInterest.tsx
  • src/components/ui/FormInput.tsx
  • public/api/send-otp.php
  • public/api/verify-otp.php
  • public/api/templates/otp_verification.html
  • src/lib/otp.ts
  • next.config.ts
  • .gitignore

2026-06-23

deployed

Reduced the subject grid below the hero to the two visible courses. It previously showed seven subject tiles linking to now-hidden course pages (and its PSIR tile pointed at the hidden /courses/international-relations) — now it shows just PSIR 2027 and Essay Mentorship, with the PSIR tile repointed to /courses/psir-mains-2027 and the grid adapted for two cards. Also repointed the homepage intro paragraph's course links from the hidden GS Foundation / Answer Writing Program to PSIR 2027 / Essay Mentorship, so the homepage now links only to the two visible courses.

Scope

  • src/components/sections/SubjectCategories.tsx
  • src/app/page.tsx

2026-06-23

deployed

Added a 'Free Resources for Every Aspirant' section to the homepage so resources are easily reachable without opening the nav dropdown — a 6-card grid linking to Masterclasses, Notifications, Blog, Syllabus, Previous Year Papers, and Study Material, plus an 'Explore All Resources' button to /resources. Placed between the founder spotlight and events sections, reusing the existing resource-card style.

Scope

  • src/components/sections/ResourcesHighlight.tsx
  • src/app/page.tsx

2026-06-23

deployed

Fixed the broken logo on the live site. The Hostinger CDN was returning 502 Bad Gateway for the logo asset; the source was also heavily oversized (1600×626, 558 KB, displayed at ~48px tall). Resized it to 600×234 (76 KB) — which also changes its content hash, so the next deploy serves a fresh asset that bypasses the broken cached file. (apple-touch-icon.png is also 502 on the CDN; it's a fixed, unhashed path, so it needs a redeploy / CDN cache purge rather than a code change.)

Scope

  • public/logo.png

2026-06-23

deployed

Adapted the Courses mega-menu for the now-2-course offering: narrowed the panel and switched to a 2-column grid (from a full-width 4-column layout), and removed the 'View all courses' link in both the desktop mega-menu and the mobile Courses accordion.

Scope

  • src/components/layout/MegaMenu.tsx
  • src/components/layout/Navbar.tsx

2026-06-23

deployed

Social links: updated YouTube to youtube.com/@theroundtableias and Instagram to instagram.com/theroundtableias, removed the X (Twitter) and LinkedIn footer icons, kept Telegram, and updated the Organization schema sameAs to match. Courses: reduced the visible course offering to PSIR 2027 and Essay Mentorship only — added a VISIBLE_COURSE_SLUGS / visibleCourses helper and routed the mega-menu, mobile menu, homepage grid, /courses listing, enroll dropdown, and IAS-coaching featured section through it. The other course pages stay live at their URLs (and in the sitemap) but are unlinked from navigation and listings.

Scope

  • src/lib/constants.ts
  • src/components/layout/Footer.tsx
  • src/components/seo/StructuredData.tsx
  • src/data/courses.ts
  • src/components/sections/CoursesGrid.tsx
  • src/app/courses/page.tsx
  • src/app/enroll/page.tsx
  • src/app/ias-coaching-classes/page.tsx

2026-06-23

deployed

Made the blog/article system production-ready for SEO articles. Added an optional structured `faqs` field and an `authorCredential` to BlogPost; the article page now renders a styled FAQ section, emits FAQPage JSON-LD alongside the existing Article schema, and shows the author's one-line credential in the byline. Fully backward-compatible — existing posts render unchanged.

Scope

  • src/lib/types.ts
  • src/app/resources/[slug]/page.tsx

2026-06-23

deployed

SEO basics pass on the homepage and all course pages. Rewrote every <title> to under 60 characters with the page's main keyword and every meta description to 140–160 characters (homepage, the 3 dedicated course pages, and the 7 dynamic [slug] course pages — adding SEO meta for gs-foundation and interview-guidance). Confirmed exactly one H1 per page. Added Course JSON-LD to the dynamic course pages (the dedicated pages already had it) so all 10 course pages carry Course schema. Corrected the sitewide Organization (EducationalOrganization) sameAs to instagram.com/theroundtableias and youtube.com/@RoundtableIAS. Verified sitemap.xml is current (41 URLs) and robots.txt allows crawling. Metadata and schema only — no visual changes.

Scope

  • src/app/page.tsx
  • src/app/layout.tsx
  • src/app/courses/[slug]/page.tsx
  • src/app/courses/essay/page.tsx
  • src/app/courses/psir-mains-2027/page.tsx
  • src/app/courses/international-relations/page.tsx
  • src/components/seo/StructuredData.tsx

2026-06-23

deployed

Extended 'Rohan Dange Sir' site-wide — homepage, About, FAQ, Resources, the courses index, Roundtable Dialogue, enroll, the pedagogy/events/blog-preview sections, the organisation description (SITE.description), SEO keyword data, and in-article blog mentions. Deliberately kept the canonical 'Rohan Dange' in JSON-LD Person entities, blog author bylines, the SITE.founder field, image alt text, and the legal Terms page. Build, sitemap, and lead routing verified unaffected.

Scope

  • src/lib/constants.ts
  • src/app/page.tsx
  • src/app/about/page.tsx
  • src/data/faq.ts
  • src/data/blog-posts.ts
  • src/components/sections/PedagogyHighlight.tsx
  • src/components/sections/EventsCarousel.tsx
  • src/components/sections/BlogPreview.tsx
  • src/app/resources/page.tsx
  • src/app/courses/page.tsx
  • src/app/roundtable-dialogue/page.tsx
  • src/app/ias-coaching-classes/page.tsx
  • src/app/enroll/EnrollForm.tsx
  • src/app/blog/page.tsx
  • src/data/ias-coaching-seo-keywords.ts

2026-06-23

deployed

Across the course and masterclass landing pages (and the data and mentor block that feed them), refer to the founder as 'Rohan Dange Sir' in all visible and SEO copy — how aspirants search for and refer to him. Kept the canonical 'Rohan Dange' in JSON-LD Person entities and image alt text for correct knowledge-graph/entity matching. Lead routing verified unaffected.

Scope

  • src/data/masterclasses.ts
  • src/data/courses.ts
  • src/app/courses/essay/page.tsx
  • src/app/courses/psir-mains-2027/page.tsx
  • src/app/courses/international-relations/page.tsx
  • src/app/masterclass/[slug]/page.tsx
  • src/app/masterclass/page.tsx
  • src/components/sections/FounderSpotlight.tsx

2026-06-23

deployed

Replaced the Ethics, PSIR, and Essay masterclass cover images with hyper-realistic, on-brand photographs (a contemplative aspirant with the scales of justice for Ethics; a globe-and-world-map study desk for PSIR; a fountain pen on a writing desk for Essay). Optimised each to WebP — Ethics went from a 10 MB PNG to 102 KB — and pointed both the listing cards and the detail-page heroes at them.

Scope

  • src/data/masterclasses.ts
  • src/lib/images.ts
  • public/images/masterclass/ethics-masterclass.webp
  • public/images/masterclass/psir-masterclass.webp
  • public/images/masterclass/essay-masterclass.webp

2026-06-23

deployed

Added three masterclasses to the series from the June–July schedule — Ethics (GS-IV, 30 June), PSIR Optional (7 July), and Essay (8 July), all free and live at 10:00 AM IST. Each got its own landing page automatically via the data-driven /masterclass/[slug] template, with subject cover images on the listing cards. Wired the Resend email automation for them: added dedicated CLASS_SCHEDULES entries (welcome email on registration + reminder 1 hour before) and routed /masterclass/* registrations to those schedules in getCourseSlug, fixing a collision where Essay/PSIR masterclass leads would otherwise have matched the long-form course schedules. Zoom links are placeholders pending the real per-class links.

Scope

  • src/data/masterclasses.ts
  • public/api/config.php
  • public/api/resend.php

2026-06-23

deployed

Masterclass listing cards now lead with the masterclass's featured image (with the Free/price badge overlaid) instead of a plain date strip.

Scope

  • src/app/masterclass/MasterclassList.tsx
  • src/app/masterclass/page.tsx

2026-06-22

deployed

Turned masterclasses into a data-driven series. Added a listing page at /masterclass/ that always shows only upcoming sessions (filtered by the visitor's current time, so past ones drop off without a redeploy) plus a dynamic detail page at /masterclass/[slug] generated from src/data/masterclasses.ts — each masterclass now gets its own landing page (hero, live countdown, what-you'll-learn, mentor, FAQ, and a free register popup). Migrated the Answer Writing masterclass into the data and removed the hand-built static page. Linked Masterclasses in the Resources menu, footer, and resources hub, and added /masterclass to the sitemap.

Scope

  • src/data/masterclasses.ts
  • src/app/masterclass/page.tsx
  • src/app/masterclass/MasterclassList.tsx
  • src/app/masterclass/[slug]/page.tsx
  • src/lib/constants.ts
  • src/components/layout/Footer.tsx
  • src/app/resources/page.tsx
  • public/sitemap.xml

2026-06-22

deployed

Updated Google Apps Script to dynamically route campaign registration leads into distinct, sanitized course-specific tabs (e.g. Reg - psir-mains-2027, Reg - essay) instead of a single Campaign Registration sheet, keeping leads separated for each dedicated course page.

Scope

  • scripts/google-apps-script-lead-capture.js

2026-06-22

deployed

Built a webinar landing page at /masterclass/answer-writing/ for the free live 'Masterclass on Answer Writing' (UPSC Mains, 29 June 2026). Hero with a live countdown, 7 'what you'll learn' cards, mentor section, who-should-attend, FAQ, a free register-interest popup, and Event/FAQ JSON-LD. Not added to the sitemap (it's a paid-ads landing page).

Scope

  • src/app/masterclass/answer-writing/page.tsx

2026-06-22

deployed

Added pricing to the PSIR 2027 page: ₹21,999 with a 15% early-bird discount to ₹18,699 (all-inclusive, no taxes), an offer deadline of 30 June 2026, and a live countdown timer in the hero, offer strip, pricing card, and final CTA — mirroring the Essay page. Updated the fee FAQ and added Offer schema to the JSON-LD.

Scope

  • src/app/courses/psir-mains-2027/page.tsx

2026-06-22

deployed

Tablet navigation: show the full desktop nav and Courses/Resources mega-menus from the md breakpoint (768px) instead of lg (1024px), so tablets get the complete navigation and mega-menus rather than a phone-style hamburger. Verified the nav fits and the mega-menu renders at ~889px tablet width.

Scope

  • src/components/layout/Navbar.tsx

2026-06-21

deployed

Linked the two flagship campaign pages across navigation: added PSIR 2027 to the Courses mega-menu and mobile menu, relabelled Essay as 'Essay Mentorship', and added both to the footer Quick Links.

Scope

  • src/lib/constants.ts
  • src/components/layout/Footer.tsx

2026-06-21

deployed

Launched the PSIR 2027 campaign landing page at /courses/psir-mains-2027/ ('Ace PSIR, Ace Mains — Target 280') — India's first PSIR optional with think-tank certifications. Hero, insurance-policy framing, 12-feature grid, 5 certification tracks, Paper 1 & 2 structure, outcomes, FAQ, and an in-page register-interest popup. Generalised the popup into a reusable RegisterInterest component (now shared with the Essay page). Added the course to courses.ts, excluded it from the dynamic route, and added it to the sitemap.

Scope

  • src/app/courses/psir-mains-2027/page.tsx
  • src/components/RegisterInterest.tsx
  • src/data/courses.ts
  • src/app/courses/[slug]/page.tsx
  • public/sitemap.xml

2026-06-21

deployed

Added a live early-bird countdown timer (hero, offer strip, pricing card, final CTA) and an on-page popup registration form to the Essay Mentorship page so users can submit interest without leaving. All fields are mandatory; submissions post through the existing lead pipeline (with auto-reply intent) and redirect to a new /thank-you page.

Scope

  • src/app/courses/essay/page.tsx
  • src/app/courses/essay/EssayEnroll.tsx
  • src/components/CountdownTimer.tsx
  • src/app/thank-you/page.tsx

2026-06-21

deployed

Built a dedicated landing page at /courses/essay/ for the 'Target 140+: Essay Mentorship by Rohan Dange' programme — hero with early-bird offer, pricing (15% off until 30 June 2026, starts 7 July 2026), 13-feature grid, test-series highlight, outcomes, FAQ, and Course/Offer/FAQ JSON-LD schema. Excluded the essay slug from the dynamic course route to avoid a collision.

Scope

  • src/app/courses/essay/page.tsx
  • src/app/courses/[slug]/page.tsx
  • public/sitemap.xml

2026-06-21

deployed

Published four current-affairs blog posts with branded cover images and SEO keywords: UPSC Mains 2026 DAF guide, the 2026 Strait of Hormuz/Iran war and energy security, the India-EU FTA and India-UK CETA, and India's near-elimination of Left-Wing Extremism. Added the new routes to the sitemap.

Scope

  • src/data/blog-posts.ts
  • src/lib/images.ts
  • public/images/blog/upsc-daf-2026.webp
  • public/images/blog/iran-hormuz-2026.webp
  • public/images/blog/india-trade-deals-2026.webp
  • public/images/blog/lwe-naxalism-2026.webp
  • public/sitemap.xml

2026-06-16

deployed

Bypassed the lead capture download form for the UPSC CSE 2026 Preliminary Results PDF, allowing students to download it directly.

Scope

  • src/data/upsc-results.ts
  • src/app/notifications/page.tsx
  • src/components/sections/HeroSection.tsx
  • src/components/sections/ResultsAnnouncementBanner.tsx

2026-06-16

deployed

Rebuilt the PSIR optional coaching landing page at /courses/international-relations/ with SEO metadata, FAQ/Course schema, mentor section, and commercial landing-page structure.

Scope

  • src/app/courses/international-relations/page.tsx
  • src/data/courses.ts
  • public/sitemap.xml

2026-06-16

deployed

Rewrote UPSC Prelims Result 2026 blog using Vajiram-style SEO structure: overview, PDF download steps, roll-number check guide, post-result action plan, and 7 FAQs.

Scope

  • src/data/blog-posts.ts
  • src/app/resources/[slug]/page.tsx
  • src/lib/submitLead.ts
  • public/docs/upsc-results/CSE_2026_Preliminary_Results.pdf
  • public/images/blog/upsc-prelims-2026-result.webp
  • public/sitemap.xml

2026-05-27

deployed

Published the PSIR optional booklist blog post with SEO metadata, optimized hero image, and sitemap entry.

Scope

  • src/data/blog-posts.ts
  • public/images/blog/psir-booklist.webp
  • src/lib/images.ts
  • public/sitemap.xml

2026-06-16

deployed

Published UPSC CSE 2026 Preliminary Results on the notifications page and home page notification banner.

Scope

  • src/data/upsc-results.ts
  • public/docs/upsc-results/CSE_2026_Preliminary_Results.pdf
  • /notifications
  • /

2026-06-12

deployed

Added the 'Notes for PSIR Masterclass 102' PDF study material to the study materials list.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/PSIR Masterclass Class1 Branded.pdf

2026-06-09

deployed

Uploaded the PSIR Masterclass 101 Notes PDF study material and surfaced it on the study material page.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/PSIR Masterclass Concept Note Branded.pdf
  • public/docs/study-materials/PSIR Masterclass Class1 Branded.pdf

2026-06-08

deployed

Added the Roundtable IAS Essay Handbook PDF to the study materials page.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/Roundtable IAS Essay Handbook Final.pdf

2026-04-19

deployed

Replaced the Day 14 answer-writing PDF with a revised version (Day - 14 (2)) while keeping the same public link on the answer-writing programme page.

Scope

  • assets/documents/Day - 14 (2).pdf
  • public/docs/subject-categories/mains-answer-writing/Day - 14.pdf
  • /courses/answer-writing-program

2026-04-19

deployed

Added Day 14 (GS-III coral reefs) to the answer-writing programme resources and published the PDF in the mains-answer-writing documents folder.

Scope

  • src/data/courses.ts
  • public/docs/subject-categories/mains-answer-writing/Day - 14.pdf
  • assets/documents/Day - 14.pdf

2026-04-18

deployed

Added the UNESCO World Heritage Sites in India PDF to the public study-materials library and surfaced it on the study material page.

Scope

  • src/data/study-materials.ts
  • public/docs/study-materials/unesco-world-heritage-sites.pdf
  • assets/documents/UNESCO World Heritage Sites.pdf

2026-04-18

deployed

Published Day 13 of the answer-writing programme (GS-III agriculture and nitrogen pollution) and linked it on the answer-writing course resources list.

Scope

  • src/data/courses.ts
  • public/docs/subject-categories/mains-answer-writing/Day - 13.pdf

2026-04-17

deployed

Ashutosh Choudhary refined subject category naming in course resource metadata so programme labels read more clearly on the site.

Scope

  • src/data/courses.ts

2026-04-17

deployed

Ashutosh Choudhary added Day 12 mains answer-writing material (model PDF) and linked it from the answer-writing programme resources list.

Scope

  • /courses/answer-writing-program
  • public/docs/subject-categories/mains-answer-writing/Day - 12 (1).pdf
  • src/data/courses.ts

2026-04-15

deployed

Executed keyword-focused on-page SEO updates: added faculty guidance page, aligned course/home/mentorship content to target intents, expanded footer/navigation discoverability, and updated sitemap coverage.

Scope

  • src/app/faculty-guidance/page.tsx
  • src/app/courses/[slug]/page.tsx
  • src/app/ias-coaching-classes/page.tsx
  • src/app/page.tsx
  • src/components/layout/Footer.tsx
  • src/lib/constants.ts
  • public/sitemap.xml

2026-04-15

deployed

Submitted the production sitemap to Google Search Console for indexing.

Scope

  • https://theroundtableias.com/sitemap.xml

2026-04-15

deployed

Updated UI and content details: international relations course title, navbar visibility/readability, fixed-content offset, blog breadcrumb hierarchy, and footer email placeholder text.

Scope

  • src/app/courses/[slug]/page.tsx
  • src/components/layout/Navbar.tsx
  • src/app/layout.tsx
  • src/app/resources/[slug]/page.tsx
  • src/components/layout/Footer.tsx

2026-04-15

deployed

Fixed canonical indexing signals, replaced stale static sitemap with generated route-aware sitemap, aligned robots and schema domain, and added automated sitemap drift validation.

Scope

  • src/app/layout.tsx
  • src/app/sitemap.ts
  • public/robots.txt
  • scripts/validate-sitemap.mjs
  • package.json
  • src/app/**/page.tsx metadata

2026-04-15

deployed

Created a dedicated change log page and documented the mandatory date-based logging rule for all SEO/config/content updates.

Scope

  • /log
  • README.md
  • src/lib/constants.ts
  • src/app/resources/page.tsx