Case study
LLM.Info: Directory, LMS, and Community for the world of AI
A production platform pairing a structured, searchable catalog of AI models, apps, and tools with a full learning-management system, an educator marketplace, and a moderated community, built end to end.
The problem
The AI tooling landscape moves faster than any single list can keep up with. People evaluating models and tools were stitching together scattered blog posts, changelogs, and social threads, with no authoritative, structured place to compare what exists.
But "another list" was never the goal. The harder, more useful problem is a place where people can compare AI tooling, learn how to use it, and discuss it, all over the same source of record: accurate, fast, searchable, and opinionated about what matters. That turned LLM.Info into a single platform spanning a directory, a learning-management system, an educator marketplace, and a moderated community.
The constant difficulty underneath all of it: keeping a fast-churning catalog and a stream of community contributions correct without hand-reviewing every row forever.
My role
I own LLM.Info end to end: product strategy, data modeling, architecture, implementation, moderation flow, payments, and production delivery. The most interesting decisions sit exactly where product judgment meets engineering: what to model as first-class entities, what to let search do, what to review, what to trust, and how the system should absorb change without losing accuracy.
Architecture
A clean two-runtime split: a Python API that owns all data and is the single writer, and a Next.js front end that renders and searches it. The front end never touches the database directly. It calls the API.
- FastAPI + SQLAlchemy 2.0 (async) owns every table; Alembic owns migrations.
- PostgreSQL holds the canonical graph, including a unified content spine where learning paths, courses, modules, and lessons live in one polymorphic table.
- Meilisearch powers typo-tolerant, faceted search across the catalog and content.
- Redis handles caching, rate limiting, and batched view counts.
- A third-party auth provider handles sealed sessions, with self-managed TOTP MFA layered on top.
- Stripe Connect runs the marketplace: course checkout, educator onboarding, and payouts.
- Celery + APScheduler run background work: moderation jobs, payout reconciliation, GDPR exports, view-count flushes, and scheduled syncs.
The single-writer rule is the load-bearing decision. Because the API is the only thing that writes, every invariant (moderation status, trust tier, rate limits, entitlements) lives in one place and can't be bypassed by the front end:
@router.get("/api/v1/models", response_model=list[ModelOut])
async def list_models(
session: AsyncSession = Depends(get_session),
q: str | None = None,
) -> list[ModelOut]:
# Meilisearch for free-text; Postgres for the canonical record.
if q:
return await search_models(q)
result = await session.execute(select(Model).order_by(Model.released_at.desc()))
return list(result.scalars())What it actually does
LLM.Info is four products sharing one spine:
- Directory. Models, apps, tools, and providers are modeled as first-class entities with canonical data, typo-tolerant Meilisearch discovery, and side-by-side comparison.
- Learning (LMS). A full learning system built on the unified content spine: paths, courses, modules, and lessons, with quizzes, progress tracking, and certifications. Educators run classrooms with rosters, assignments, and privacy-preserving student tokens.
- Marketplace. Paid courses run on Stripe Connect, with a 70/30 educator revenue split and a durable payout saga that survives retries and reconciliation.
- Community. Profiles, follows, ratings and reviews, 1:1 messaging, and notifications with email digests, plus a reputation layer of trust tiers, badges, achievements, and leaderboards.
Around all of it sits trust, safety, and compliance: moderation queues with an append-only audit log, content-safety checks (spam, PII, toxicity), a DMCA counter-notice flow, NCMEC/CSAM reporting, GDPR export and deletion, and six-language i18n including RTL.
Decisions that mattered
- Canonical data model: models, apps, tools, and providers are first-class entities.
- Unified content spine: one polymorphic table for paths, courses, modules, and lessons, with four orthogonal axes (content tier, access tier, pricing, and publisher) so a node's provenance, entitlement, monetization, and byline are independent and enforceable.
- Search-first experience: Meilisearch supports typo-tolerant discovery across a fast-moving catalog.
- Moderation and trust tiers: new contributors are reviewed, while proven contributors earn more direct publishing rights, so the system scales past manual review of every submission.
- Two-track authorization: an internal staff role hierarchy is kept orthogonal to the educator publishing flag, so each is granted and reasoned about independently.
Outcomes
- A structured AI platform that stays correct as the space churns: directory, learning, marketplace, and community over one canonical data layer.
- A moderation and trust model that scales contribution beyond hand-reviewing every row.
- A production architecture that separates the product experience from the source-of-truth data layer, with payments, auth, MFA, and compliance flows shipped.
- The exact stack proven here (Next.js 16 + FastAPI + Postgres + Redis + Meilisearch) is what yaj.net itself runs on. Product thinking and full-stack execution in the same person.