AFM Aero — Aviation Market Intelligence Platform
A B2B aviation platform — pilot training market intelligence, a supplier directory, ad placements, and corporate subscriptions billed through Stripe and PayPal — Next.js 15 frontend on a Strapi 5 headless CMS.
Overview
AFM Aero is a B2B SaaS for the aviation industry — a market intelligence portal for pilot training, a curated supplier directory, an industry-update feed, ad placement inventory, and tiered corporate subscriptions billed through both Stripe and PayPal. The product is split into a Next.js 15 / T3 frontend and a Strapi 5 headless backend on MySQL.
I owned the platform end-to-end: payment integrations (dual PSP), invoice generation, the Strapi data model spanning ~40 content APIs, marketing automation via Mailchimp, and the customer-facing onboarding + dashboard flows.
Architecture
┌──────────────────────────────────┐ ┌──────────────────────────────────┐
│ afm-nextjs (Frontend) │ │ Strapiback (Backend) │
│ Next.js 15 + React 19 + TS │ │ Strapi 5 on Koa │
│ Tailwind 4 · T3 env validation │◀──▶│ MySQL · Nodemailer · JWT │
│ PayPal + Stripe checkout │ │ Stripe · PayPal webhooks │
│ Mailchimp · reCAPTCHA · jsPDF │ │ bcryptjs · slugify │
└──────────────────────────────────┘ └──────────────────────────────────┘Frontend routes (afm-nextjs)
A real-world product surface, not a marketing brochure:
- Public —
about-us,contact-us,advertise-with-us,pilot-training-market-intelligence,terms-and-conditions-privacy-policy,guide-to-using-afm,topics-of-interest,[permalink](CMS-driven slugs). - Marketplace —
market-place,suppliers. - Subscriptions & checkout —
corporate-monthly,corporate-annually,subscriptions,payment. - Auth —
login,forgot-password,reset-password,onboarding. - Authenticated —
dashboard,dashboard-sim. - SEO / infra — dynamic
sitemap.ts,robots.ts,opengraph-image.png.
Strapi APIs (Strapiback)
The CMS exposes ~40 collection types covering the entire business:
| Domain | Collections |
|---|---|
| Identity & access | auth, subscribers-user, reset-password, reset-password-request, user-migration, user-keyword-list, organization-name, organization-type |
| Subscriptions & licensing | corporate-monthly, corporate-annually, corporate-monthly-checkout, corporate-annually-checkout, price-plan, master-license, complimentary-license, subscription-actions |
| Payments | stripe-checkout, paypal-webhook, custom-payment, payment, invoice |
| Marketplace | supplier-directory, supplier-directory-category, supplier-type, related-supplier-directory, market-place, market-place-category |
| Content & ads | industry-update, industry-updates-category, related-industry-updates, event, ads-display, tag, tags-new, category |
| Ops | bulk-delete, filter-options, form-submissions, country, region, test-link, testsub, owner-dashboard |
Highlights
Dual-PSP Checkout
The product accepts both PayPal (@paypal/react-paypal-js) and Stripe for corporate subscriptions. The frontend renders the user's preferred provider; the backend captures both flows in a unified payment / invoice model so reporting and license issuance don't care which rail the money came in on. PayPal IPN/webhooks land at /api/paypal-webhook and Stripe at /api/stripe-checkout.
License Issuance
Three license types — master, corporate (monthly / annually), and complimentary — are minted on payment success and tied to seats inside an organization-name. subscription-actions handles renewals, cancellations, and seat resizing without re-entering checkout.
PDF Invoicing
Invoices are generated client-side with jsPDF, signed against the server-issued invoice record, and downloadable from the dashboard. Keeping rendering on the client kept the Strapi pod stateless and avoided shipping a PDF runtime to the backend.
Marketing & Onboarding
Mailchimp Marketing API drives newsletter sign-ups and segmented industry-update digests. Onboarding captures topics-of-interest and organization metadata to seed personalized supplier and industry-update feeds. Public forms use Google reCAPTCHA v2 to keep the spam off contact and "advertise-with-us".
Content-Driven SEO
A [permalink] catch-all route resolves CMS-managed slugs against Strapi, so the editorial team can publish landing pages, partner microsites, and topic hubs without a frontend deploy. Sitemap and OG images are generated on demand via Next.js metadata routes.
Type-safe Env
The frontend uses @t3-oss/env-nextjs + Zod to validate every env var at build time — Stripe keys, PayPal client IDs, Mailchimp API keys, reCAPTCHA secrets — so a misconfigured deploy fails at the build step instead of leaking into runtime.
Tech Stack
| Layer | Choices |
|---|---|
| Frontend | Next.js 15 (App Router, Turbo dev), React 19, TypeScript 5, Tailwind 4, T3 + Zod env |
| Backend | Strapi 5 on Koa 3 / @koa/router, plugin-users-permissions, plugin-cloud, custom controllers/services per content type |
| Database | MySQL via mysql2, with seed scripts and dump-based migration |
@strapi/provider-email-nodemailer, Mailchimp Marketing API | |
| Payments | Stripe (server SDK) + PayPal (@paypal/react-paypal-js) with webhook handlers |
| Security | bcryptjs, JWT, Google reCAPTCHA, raw-body verification on webhooks |
| PDF / utility | jsPDF, country-codes-list, slugify, moment |
// more projects
Let's work together
Have a project in mind? Reach out and let's build something great.