Project / Nov 2024 - Present

Aglaea

TypeScriptSvelteKitElysiaGoPostgreSQLKafkaQdrantCloudflare Workers

Aglaea is the umbrella project for the Cobblemon community system I have been building: the Aglaea web app at cobblemonwiki.com, the Herta data API, and the Cyrene RAG/indexing service. The system supports a production community with 500+ concurrent users, with engineering work centered on keeping content, search, media, and game data moving while people are using it.

Aglaea frontend

The frontend is a SvelteKit app for community content and game-data browsing. It handles rich pages, species and article surfaces, searchable data views, and the authoring paths around them. I used Cloudflare-facing deployment pieces for the web layer and built an upload path to R2 with JWT checks and file validation so media can be accepted at the edge without routing everything through one application server.

Herta API

Herta owns the structured game data. The newer backend is a Bun/Elysia service backed by PostgreSQL and Drizzle, with modules for Pokemon, moves, abilities, items, types, images, and spawn data. The API keeps exact filters and lookups in the relational layer where they belong, uses Redis-style response caching for common reads, and has integration tests around the domain modules instead of treating the API as a loose collection of routes.

Cyrene RAG service

Cyrene is the Go service that connects domain events to retrieval. It consumes Kafka events, turns updated records into embedding text, upserts or deletes Qdrant vectors, and exposes tools for both structured search and semantic lookup. That split lets Aglaea answer plain data questions through Herta while reserving vector search for queries that need context rather than a single exact row.

Engineering notes

  • Used an outbox-to-Kafka path so content and embedding invalidation can move through the system without coupling the web request to every downstream update.
  • Kept structured search and RAG search separate. Herta handles exact filters; Cyrene handles retrieved context.
  • Used background worker patterns such as FOR UPDATE SKIP LOCKED where polling needed to be safe under concurrency.
  • Treated uploads, indexing, and content edits as separate failure domains so one slow path would not make the whole community site feel stuck.
Back To Projects