Back to Case Study

CraftQL

Navigating Edge Constraints & AI Cost Control

Architecture & Strategy
Creator
Doyin OlarewajuCreator

Project Technologies

Frontend Next.js (React)
Languages TypeScript
Transport & API Route Handlers (Edge)
AI / ML Base Gemini 2.5 Flash Lite
Infrastructure & Tooling
Cloudflare WorkersCloudflare D1PrismaSafe-MDXPostHog

Feature Overview

CraftQL is a gamified generative AI learning platform. To achieve sub-second latency globally, the entire architecture was pushed to the Cloudflare Edge. This decision, while eliminating cold starts, introduced strict constraints regarding code evaluation, database ACID compliance, and state management. This deep dive explores how those constraints were navigated to build a secure, interactive, and cost-controlled AI platform.

Evading the eval() Constraint with Safe-MDX

CraftQL relies heavily on MDX to embed interactive React components (BlankFillingQuiz, PromptQuiz) directly within the lesson content. Typically, MDX libraries like next-mdx-remote or mdx-bundler rely on new Function() or eval() to execute the compiled components at runtime.

Cloudflare Workers actively strip eval() capabilities for security reasons. Relying on standard MDX libraries results in hard crashes at the edge.

To circumvent this, CraftQL parses markdown using Safe-MDX, a library specifically built to render MDX securely without dynamic function evaluation, allowing rich, interactive content to be served directly from Cloudflare Nodes.

MDX Rendering Flow

Pseudo-Transactions & Concurrency in D1

Managing a virtual wallet system requires strict transactional integrity to prevent double-spending or race conditions when users rapidly fire off AI prompts. Cloudflare D1 is a serverless SQLite database. While fast, it does not support true interactive ACID transactions. Prisma's $transaction block on D1 merely batches statements sequentially—it does not provide row-level locking.

// Executing a batched D1 operation safely
const [updatedWallet] = await db.$transaction([
  db.user_wallet.update({
    where: {
      id: wallet.id,
      // Critical: Optimistic Lock
      balance: { gte: requiredCoins }, 
    },
    data: {
      balance: { decrement: requiredCoins },
    },
  }),
  db.transaction.create({ ... })
]);

By adding balance: { gte: requiredCoins } directly into the where clause, the database strictly enforces that the mutation fails if a concurrent request drains the balance before the batch executes.

Edge AI Strategy

Stateless AI Context Management

LLMs are inherently stateless. Managing chat history for the Generative AI playground required choosing between storing conversational vectors in a costly memory store or managing state purely on the client.

To minimize database reads at the edge and keep backend execution times strictly under Cloudflare Worker limits, the backend acts purely as a stateless evaluator.

  • 1Client-Side State: The Next.js client maintains the entire conversation array.
  • 2Pre-flight Token Count: Before calling the LLM, the edge function calculates exact cost using model.countTokens() to verify wallet balance.
  • 3Execution: The payload is formatted for Gemini via startChat() and executed statelessly, eliminating latency spikes.
AI Context Management Flow

Relational Edge Content

While many Next.js setups rely on static MDX files bundled at build time, CraftQL requires dynamic progression gating and user-specific state tracking.

  • Dynamic Gating: The API actively constructs the course tree on the fly, calculating real-time user progress via optimized aggregates in D1.
  • Content Delivery: MDX content is fetched as a raw string from the database and passed to the Safe-MDX client parser, acting as a headless CMS at the edge.

Edge Observability

Gaining visibility into edge deployments can be notoriously difficult. To track user journeys and capture silent fail states in the token conversion engine, PostHog was integrated pervasively.

  • Journey Tracking: Every critical user action, from lesson completion to specific interactive quiz submissions, fires telemetry events to PostHog.
  • Identity Binding: A custom Auth Context ensures the Firebase User ID is bound to the PostHog session. This links edge API failures directly to the frontend user journey.

Learnings & Takeaways

  • 1 Edge computing is not a silver bullet: Moving to Cloudflare Workers requires deeply understanding the underlying V8 isolate constraints (no eval, strict execution limits).
  • 2 Database constraints breed resilient patterns: The lack of interactive transactions in D1 forced the adoption of Optimistic Concurrency Control, which scales better horizontally than traditional row-locking.
  • 3 Stateless over Stateful: Pushing conversational state entirely to the client reduced backend complexity massively, at the minor trade-off of slightly higher network payload sizes per request.
  • 4 Micro-transactions at scale: Building a custom virtual currency engine provided granular cost tracking, ensuring API limits are never unexpectedly exceeded.

References

  • #

    Safe-MDX

    Bypassing Cloudflare Worker `eval()` limitations for interactive content parsing.

  • #

    Cloudflare D1 & Prisma

    Optimizing batched limits and concurrency without interactive transactions via Optimistic Concurrency Control.

  • #

    Google Generative AI

    Node SDK integration for Edge-based inference and token cost calculation.