Simon-Pierre Boucher
All apps & projects
Web Platform
Python + TypeScript

Forma·Ka

Every training program in Québec. One place.

Forma·Ka, live at www.forma-ka.com, aggregates 4,900+ programs from 18 Québec institutions into one searchable, always-current catalog. Part of the KA family of Québec aggregators.

4,900+

Aggregated programs

18

Institutions with active connectors

130+

Free programs

3

Fetch backends per connector

6 h

Default sync interval

~1,760

Programs from the largest source (ULaval Distance)

Overview

Forma·Ka is an independent aggregator of training programs across Québec — online courses, university and college courses, seminars, workshops, certifications, and bootcamps. Finding training normally means opening dozens of websites, from universities and CEGEPs to training firms and event organizers, each with its own navigation and format. Forma·Ka flips the problem: every program appears in a single interface with its full standardized details — description, learning objectives, course outline, prerequisites, duration, credits, delivery mode, offered dates — and a direct link to the original page.

A dedicated connector per institution visits each site and normalizes every program into a single Formation schema. Since training sites don't offer webhooks, Forma·Ka reproduces the equivalent with periodic sync plus content hashing: additions, updates, and removals are detected automatically, and a program that disappears from its source site disappears from Forma·Ka after a two-sync grace period. Connectors choose among three fetch backends — direct requests for server-rendered sites, Scrapfly for anti-bot bypass with JavaScript rendering, and Firecrawl as a JS-rendering fallback — chained automatically, with detail pages cached on a weekly key.

The backend is Python 3.14 with FastAPI serving a filterable API (type, category, mode, city, language, level, free, price, source, full-text search) plus facets, stats, and sync endpoints over SQLite with hash-and-diff upserts. The frontend is a React 18 + Vite TypeScript app in an editorial-sharp design — Space Grotesk type, offset shadows, amber accent, live ticker, mobile bottom sheet — installable as a PWA. A PM2-supervised watcher runs the sync loop every six hours by default; the app runs on MacLustr cluster node M3U96a, exposed via ngrok at www.forma-ka.com.

Key Features

18 Québec institutions, one catalog

From Université Laval, TÉLUQ, McGill, HEC, and UQAM to Technologia, AFI, Cégep à distance, and Le Wagon — one dedicated connector per site feeds a single unified catalog covering all of Québec.

Webhook-equivalent change detection

Periodic sync plus content hashing detects additions, updates, and removals automatically; programs gone from the source site are retired after a two-sync grace period.

Details-first standardized schema

Every program is normalized into one Formation schema: description, objectives, course outline, prerequisites, target audience, duration, credits/CEUs, sessions, delivery mode — with price optional by design.

Three chained fetch backends

Connectors go from direct requests to Scrapfly (anti-bot bypass, JS rendering, Canadian geolocation) to Firecrawl via an automatic fetch_html() fallback, with detail pages cached on a weekly key.

Faceted search API

GET /api/formations filters by type, category, mode, city, language, level, source, free, and price, with full-text search, sorting, facets, stats, and a background sync trigger.

Installable mobile PWA

An editorial-sharp React 18 frontend — Space Grotesk, offset shadows, amber accent, live ticker, mobile bottom sheet, 12-per-page pagination — installable as a PWA.

How It Works

  1. Per-institution connectors

    One auto-discovered Python module per source implements fetch() against server-rendered HTML, internal JSON APIs (Shopify, WordPress REST, Gatsby, Destiny One), or schema.org JSON-LD.

  2. Chained fetch backends

    fetch_html() falls back automatically from direct requests to Scrapfly (anti-bot, render_js, Canadian geolocation) to Firecrawl, and detail pages are cached in the database on a weekly key.

  3. Normalization into one schema

    Every scraped program becomes a standardized Formation record — type, category, mode, description, objectives, outline, prerequisites, duration, credits/CEUs, sessions, and optional price.

  4. Diff engine over SQLite

    Content-hash upserts classify each record as new, changed, or gone (with a two-sync grace period) and detect connector drift; a PM2 watcher re-syncs every 6 hours by default.

  5. FastAPI serving the React PWA

    The API exposes filterable formations, facets, sources, stats, and a sync trigger; the React 18 + Vite frontend consumes it, all exposed publicly through ngrok on node M3U96a.

Tech Stack

Backend

Python 3.14
FastAPI
SQLite (hash + diff engine)
PM2 watcher

Frontend & Scraping

React 18 + Vite (TypeScript)
Installable PWA
Scrapfly
Firecrawl

Deployment

MacLustr node M3U96a
ngrok tunnel
www.forma-ka.com

Highlights

  • Aggregates 4,900+ training programs from 18 Québec institutions, including 130+ free programs.
  • One dedicated connector per institution normalizes every program into a single standardized Formation schema.
  • Content hashing plus periodic sync reproduces webhooks: additions, updates, and removals are detected automatically.
  • Three chained fetch backends — direct requests, Scrapfly, and Firecrawl — handle everything from static HTML to anti-bot JavaScript sites.
  • Adding a new source takes one auto-discovered Python class and one entry in data/sources.json.
  • Runs on MacLustr cluster node M3U96a with a PM2 sync watcher, exposed via ngrok at www.forma-ka.com.

Explore Forma·Ka

Every training program in Québec, one place — the full source is on GitHub.