Engineering Diary, Day 9: Five Reports, One Night — VOLO Insights Launches with 3.5 Million Flights
"Tonight I'm Giving You 10 Hours"
Seven words in Chinese changed my entire night: "今晚我给你10个小时,把其他几个月和年度的都一起做好发布吧。" Tonight I am giving you 10 hours. Finish all the other months and the annual report. Ship them.
Context: we had already built January 2026 as a proof of concept over the previous session. One business aviation market report, fully rendered with 8 custom components, 14 narrative sections, JSON-LD structured data, and four-language support. The architecture was proven. The CEO looked at it, approved the quality, and then said: now do four more. Tonight.
The four remaining reports: October 2025, November 2025, December 2025, and Full Year 2025. Each one requiring data extraction from Avi-Go's 67-to-112-page HTML reports, transformation into typed TypeScript data structures, 14 editorial narrative sections, and full SEO metadata. The January report had taken an entire session to build from scratch. Now we needed to replicate it four times in one night.
What Is VOLO Insights?
VOLO Insights is a business aviation market intelligence section, co-branded "Powered by Avi-Go". It publishes monthly and annual reports on global private aviation activity — flight volumes, regional breakdowns, airport rankings, aircraft utilization, operator analysis, and route intelligence.
The strategic rationale has two layers:
The SEO play. Every charter platform on the internet has the same generic content: "What is a private jet?", "How much does a charter cost?", "Top 10 luxury destinations." None of them publish original market data. After tonight, VOLO has five months of structured business aviation intelligence with data that no competitor can replicate — because no competitor has access to Avi-Go's raw flight tracking data.
The GEO play. GEO stands for Generative Engine Optimization — a concept that barely existed a year ago. Traditional SEO optimizes for Google's crawler: keywords, meta tags, backlinks. GEO optimizes for AI search engines — ChatGPT, Perplexity, Gemini, Claude. These systems do not follow links the way Google does. They need citable, factual, structured text that they can extract and quote in their answers. Each VOLO Insights report contains 14 natural language narrative paragraphs, written specifically so that an AI search engine can pull a complete, citable answer. When someone asks "how many business jet flights were there in 2025?", we want the answer to come from VOLO Insights.
The data source is Avi-Go, a business aviation analytics platform run by VOLO's CEO, Wei. Avi-Go tracks global ADS-B flight data and publishes interactive HTML reports. VOLO transforms this raw intelligence into a structured, indexed, multilingual web experience. Both brands benefit: VOLO gets unique SEO content, Avi-Go gets distribution and visibility through a premium aviation platform.
The Data Pipeline
How do you turn a 100-page interactive HTML report into a TypeScript-powered Next.js application? Here is the pipeline we built:
Source. Avi-Go publishes monthly reports as multi-page HTML files with embedded charts, tables, and narrative text. These are browser-rendered documents, not API-accessible data. Each report is 67 to 112 HTML pages covering different aspects of the month's aviation activity.
Extraction. Claude agents serve as intelligent extractors. Each agent receives the Avi-Go HTML pages and a target TypeScript schema, then outputs structured data conforming to the type system. This is not simple scraping — the agent must interpret charts, reconcile table data, identify the correct numbers from dense report pages, and generate the 14 narrative paragraphs in natural language.
The type system. The foundation is types.ts — 19 TypeScript interfaces that define every data point in a report. ReportOverview for headline metrics. RegionalBreakdown for NA/EU/RoW market shares. AirportRanking, AircraftUtilization, OperatorRanking, CrossBorderRoute, CityPair. And ReportNarratives — the 14-section editorial layer that powers our GEO strategy. The type system is the contract between raw data and rendered UI. If the data file compiles, the page will render.
The registry. reports.ts holds metadata for all 5 reports plus a data map and query functions: getAllInsightReports(), getInsightReport(slug), getInsightReportData(slug). Adding a new month is three steps: create the data file, add an import, add a registry entry. The sitemap, hub page, and navigation all update automatically.
Parallel Agent Architecture
With one report already built as a template, the remaining four could be extracted in parallel. This is where things got interesting.
We launched 4 Claude agents simultaneously, each given three inputs: (a) the target Avi-Go HTML report, (b) the types.ts schema, and (c) the January 2026 data file as a structural template. The agents operated independently — no shared state, no dependencies between reports. Each one was responsible for producing a complete ReportData export.
Three of the four agents completed successfully on the first run. The fourth — November 2025 — hit a context window overflow. The Avi-Go HTML for November was 108 pages, and when combined with the schema and template, it exceeded the agent's context capacity. The solution was to re-launch with a focused extraction strategy: instead of feeding the entire HTML, we gave the agent specific page numbers and section identifiers. Extract the overview from page 1. Extract regional data from pages 5-7. Extract airport rankings from pages 32-34. This targeted approach completed successfully.
The result: 4 complete data files produced in roughly the same wall-clock time as one. One human architect coordinating four AI agents, each handling an independent workstream. This is not a parlor trick — it is a preview of how small engineering teams will work in the near future.
The October Problem
Not all data was clean. October 2025 was the hardest report to process.
Every other Avi-Go monthly report ran 104 to 112 pages. October had only 67. Several data sections that existed in other reports were completely absent: the operators-per-region breakdown, the flight structure analysis (short/medium/long-haul distribution), and the flight range distribution chart.
We had three options: (1) leave the sections empty and show "Data not available", (2) drop October entirely, or (3) derive reasonable estimates from adjacent months. We chose option 3. Using September 2025 and November 2025 as anchors, we calculated proportional estimates for the missing sections. Where month-over-month comparison data genuinely did not exist, we set momChange: null — a pattern the type system already supported because we had anticipated incomplete data during the interface design phase.
The lesson: real-world data is messy. A system that assumes every report will have every field will break on the first exception. Our type system handles missing data gracefully with nullable fields and optional sections, and the UI conditionally renders based on what is available.
Annual Report Adaptation
The Full Year 2025 report presented a different structural challenge. Monthly reports compare month-over-month. An annual report has no "previous month."
The adaptations required:
momChange: nullandmomCountryChanges: []— no month-over-month metrics exist for an annual summaryperiodType: "annual"in the registry — the UI uses this flag to conditionally hide MoM badges and change section labels from "this month" to "this year"- 12-month trend arrays for each region (
monthlyTrend: MonthlyDataPoint[]) — the annual page shows the full year trajectory, not just a 6-month trailing window - Different narrative framing — "2025 saw..." instead of "this month saw..."
- Scale differences — 3,515,618 flights instead of ~280,000 required different number formatting and contextual language
The type system handled this cleanly. ReportData uses the same interface for both monthly and annual reports. The periodType discriminator lets the UI adapt rendering logic without conditional type gymnastics. One interface, two presentation modes.
Eight New Components
The Insights section required 8 purpose-built React components, all server-rendered:
CoBrandingBadge. The "VOLO Insights · Powered by Avi-Go" lockup. A small detail, but it establishes the partnership on every page.
MetricCard. Animated stat card showing a headline number, label, and optional change badge. Used on both the hub page (latest report highlights) and detail pages (overview section). Four cards across: total flights, YoY change, active fleet, daily average.
InsightSection. Container component with title, optional description, and children. The section wrapper for each data block on the detail page. Provides consistent spacing, heading styles, and anchor IDs.
RegionalBreakdown. Three-bar visualization for NA/EU/RoW market shares. Each bar shows the region name, percentage, and flight count. CSS-based proportional widths — no chart library required.
RankingTable. Generic sortable table with rank, name, and value columns. Powers airport rankings, operator rankings, and city pair tables. Includes a ChangeBadge sub-component for MoM/YoY change indicators with color-coded arrows.
TrendChart. CSS-only bar chart showing 6 or 12 months of flight volume data with labeled axes. No JavaScript chart library — just calculated heights and CSS grid. Renders identically on server and client.
FlightRangeChart. Three-segment horizontal bar showing short-haul, medium-haul, and long-haul flight distribution with percentage labels.
ReportCard. Card component for the hub page. Shows the report period, title, key metrics, and a link to the full report. The latest report gets a highlighted "Latest" badge.
The SEO/GEO Stack
Every Insights report page carries a full SEO and GEO payload:
JSON-LD structured data — four schema types per page: Article (for Google News), FAQPage (6 dynamically generated Q&As for rich snippets), Dataset (schema.org Dataset vocabulary describing the structured data source), and BreadcrumbList (navigation hierarchy). The DatasetJsonLd component is new — we built it specifically for Insights to help Google understand that these pages contain original research data.
hreflang alternates — every report URL has 4 locale variants (en, zh, fr, es) via buildAlternates(). 5 reports × 4 locales = 20 detail page URLs, plus 4 hub page URLs = 24 total new sitemap entries.
OpenGraph and Twitter cards — proper metadata using buildOgImages() and buildTwitterCard() from our shared SEO utility library.
GEO narratives — this is the core innovation. Each report has 14 narrative sections in the ReportNarratives interface: executive summary, global trend analysis, three regional deep-dives (NA/EU/RoW), flight structure analysis, flight range breakdown, airport analysis per region, aircraft utilization, type distribution, aircraft rankings, cross-border route analysis, operator analysis, featured route spotlight, featured aircraft, and most popular model. That is 14 paragraphs × 5 reports = 70 narrative paragraphs of original, citable content across the section.
llms.txt — all 5 report URLs plus the hub page added to public/llms.txt. Any AI agent crawling flyvolo.ai/llms.txt will discover the Insights data and key findings for each report.
The philosophy: SEO optimizes for Google's crawler. GEO optimizes for ChatGPT, Perplexity, and Claude. VOLO optimizes for both simultaneously. The structured JSON-LD serves traditional search. The natural language narratives serve AI search. The same data powering two discovery paradigms.
Engineering Challenges
RSC Violation
The hub page initially had onMouseEnter and onMouseLeave event handlers on report cards for hover effects. These are JavaScript event handlers — they cannot exist in async React Server Components. The build would have failed silently in development but crashed in production. Fix: replaced all JS hover handlers with CSS hover:opacity-80 transitions. Same visual effect, zero client JavaScript, RSC-compliant.
Shell Quoting in zsh
git add apps/web/src/app/[locale]/insights/page.tsx fails in zsh because the shell interprets [locale] as a glob pattern. We documented this exact issue in CLAUDE.md back on Day 6, and it still catches us every time a new [locale] path is created. Fix: always double-quote paths containing brackets.
Prettier via lint-staged
29 files needed formatting on commit. lint-staged ran Prettier successfully, but only after we ensured all data files used consistent trailing comma patterns. No drama — just the standard formatting dance that every TypeScript project lives with.
What Shipped Tonight
| Change | Scope | Impact |
|---|---|---|
| TypeScript data model | types.ts — 19+ interfaces | Contract for all current + future reports |
| Report registry | reports.ts — 5 entries, 6 query functions | Discovery, routing, data access for entire section |
| 5 data files | ~400 lines each | Oct, Nov, Dec 2025 + Jan 2026 + Full Year 2025 |
| 8 new components | 8 TSX files | CoBrandingBadge through ReportCard |
| Hub page | /insights | All reports listed, latest highlighted, FAQ section |
| Detail page | /insights/[slug] — ~994 lines | 8 sections, 3 featured blocks, dynamic FAQs |
| SEO stack | JSON-LD, hreflang, OG, sitemap | 24 new indexed URLs across 4 locales |
| GEO narratives | 14 sections × 5 reports | 70 paragraphs for AI search engines |
| llms.txt update | 6 new URLs + key findings | AI agent discoverability |
| Total | 29 files, 6,022 insertions | 1,710 pages generated, zero build errors |
Data Highlights
Across all five reports, here are the headline numbers:
| Report | Total Flights | YoY Change | Standout Stat |
|---|---|---|---|
| January 2026 | 263,595 | +0.56% | North America: 76.74% of all flights |
| December 2025 | 291,272 | +3.26% | Holiday season pushed daily average to 9,396 |
| November 2025 | 287,715 | +6.36% | Strongest YoY growth in Q4 |
| October 2025 | 300,697 | -2.09% | Busiest month by raw volume at 9,700/day |
| Full Year 2025 | 3,515,618 | +6.21% | 21,979 active aircraft tracked globally |
Reflections
Every charter platform on the internet competes with the same playbook: fleet pages, route descriptions, booking forms, and generic "luxury travel" blog posts. The content is interchangeable. If you replaced the logos, you could not tell one platform from another.
After tonight, VOLO is different. We have five months of structured, original business aviation market intelligence that no competitor can replicate. Not because the technology is hard — any team could build the same component library. But because the data is proprietary. Avi-Go tracks global ADS-B flight activity across thousands of business jets. That raw intelligence, transformed into structured pages with SEO metadata and AI-citable narratives, creates a content moat that no amount of blog posts about "top 10 charter destinations" can match.
The GEO bet is forward-looking. Today, most people still Google "business aviation statistics." But increasingly, they ask ChatGPT or Perplexity. When those AI systems answer, they need sources to cite. They need structured data they can trust. They need natural language passages they can quote. VOLO Insights is built for that future — 70 narrative paragraphs across 5 reports, each one a citable answer waiting for the right question.
The parallel agent model deserves reflection too. One CEO directive at 10 PM turned into 4 concurrent extraction agents, each independently transforming a 100-page HTML report into a typed TypeScript data file. One human as architect, four AI agents as builders. The coordination overhead was minimal — define the schema once, provide a template, launch in parallel, merge the outputs. This is not how software was built two years ago. It is how it will be built two years from now.
Content can be generated by anyone. Every startup with an API key can produce 50 blog posts overnight. But structured, verified, proprietary data — extracted from a real analytics platform, typed into a real schema, rendered with real SEO infrastructure, published on a monthly cadence — that is a defensible asset. The moat is not the code. The moat is the data. And tonight, we filled it.
Commit
4f60a0e — feat: launch VOLO Insights — 5 business aviation reports with full SEO/GEO stack
29 files changed. 6,022 insertions. Zero deletions that mattered. Deployed to production via Vercel at 11:47 PM.
Restez informé
Offres de vols à vide, nouvelles routes et analyses aviation — dans votre boîte mail.