Emad Ashraf

Ask Zico: Production Architecture And Request Flow

Written byEmad Ashraf4 min read

Ask Zico is the Arabic-first, source-grounded assistant I integrated into Madraset El Shamamsa. I shipped it in July 2026.

This page is the system map: what runs where, what each component owns, and how one user request moves through production. The rest of the series examines each boundary in depth.

Try Ask Zico

System architecture

flowchart LR
    subgraph browser["Untrusted browser"]
        visitor["Website visitor"] --> ui["Ask Zico UI"]
    end

    subgraph site["Madraset El Shamamsa server"]
        ui -->|"untrusted browser request"| proxy["Authenticated PHP intermediary"]
    end

    subgraph runtime["Cloudflare runtime"]
        proxy --> worker["Assistant Worker"]
        worker -->|"embed normalized query"| ai["Workers AI"]
        ai -->|"query embedding"| worker
        worker -->|"query with embedding"| vector["Vectorize"]
        vector -->|"candidate IDs"| worker
        worker --> kv["KV"]
        worker --> d1["D1"]
    end

    subgraph providers["Answer providers"]
        worker --> gemini["Gemini model ladder"]
        gemini -->|"answer or provider failure"| worker
        worker -->|"qualifying fallback only"| openrouter["OpenRouter fallback"]
        openrouter -->|"answer or failure"| worker
    end

    subgraph evidence["Offline evidence preparation"]
        sources["Public site content"] --> ingest["Deploy-time ingestion"]
        ingest --> vector
        ingest --> kv
    end

    subgraph operations["Protected operations"]
        d1 --> admin["Observability dashboard"]
    end

Component responsibilities

ElementWhat it does
Website visitorAsks a question, follows citation links, and can rate the response.
Ask Zico UIAn untrusted browser client that collects Arabic input, displays answer or fallback states, renders trusted citation objects, and sends feedback. The interaction states are detailed in the UX article.
PHP intermediaryValidates and bounds browser-controlled fields, derives privacy-preserving quota identifiers from server-visible context, handles Turnstile when required, authenticates to the Worker, and keeps Worker credentials out of the browser.
Assistant WorkerOwns caller authorization, request budgets, Arabic normalization, domain routing, retrieval, provider quota reservation, answer generation, citation-ID validation, fallback behavior, feedback, and bounded operational events. The major boundary choices are covered in the alternatives article.
Workers AIGenerates the normalized query embedding used for semantic retrieval.
VectorizeReturns semantic candidates whose vector IDs are application-owned chunk_id values. Retrieval details live in the retrieval article.
KVStores lean lexical and metadata shards plus the original readable chunk records hydrated by chunk_id.
D1Atomically reserves quota windows and stores feedback, query events, provider attempts, fallback reasons, and CPU timings. See observability.
Gemini model ladderProvides the primary grounded-answer path, selecting configured direct Gemini capacity without changing the evidence contract. See economics.
OpenRouter fallbackRuns only after direct-provider capacity is exhausted or a provider-layer failure occurs. It does not retry unsupported answers. The distinction is explained in the grounding article.
Public site contentSupplies the public articles, lessons, rites, Bible material, and other supported libraries that may become answer evidence.
Deploy-time ingestionExtracts, normalizes, chunks, identifies, and prepares public content for KV and Vectorize. See the ingestion article.
Observability dashboardExposes protected aggregate operational views; it is not a public browser API.

Request lifecycle

flowchart TD
    user["User"] --> ui["Untrusted browser UI"]
    ui -->|"message and page context"| php["Authenticated PHP intermediary"]
    php -->|"sanitized request and privacy-preserving quota ID"| worker["Assistant Worker"]
    worker --> requestBudget{"Authorized and request budget available?"}
    requestBudget -->|"denied or unavailable"| accessExit["Safe denial or unavailable response"]
    requestBudget -->|"yes"| route["Normalize and route"]
    route --> embed["Workers AI: embed query"]
    embed -->|"embedding"| vector["Worker queries Vectorize"]
    route --> lexical["Read KV lexical/domain shards"]
    vector -->|"candidate IDs"| select["Fuse, rank, and hydrate from KV"]
    lexical -->|"lexical candidates"| select
    embed -->|"failure"| infraFallback["Retrieval infrastructure fallback"]
    vector -->|"failure"| infraFallback
    lexical -->|"failure"| infraFallback
    select -->|"hydration or ID invariant failure"| infraFallback
    select --> evidence{"Enough evidence?"}
    evidence -->|"no"| searchFallback["Search fallback"]
    evidence -->|"yes"| geminiQuota["D1: reserve Gemini model capacity"]
    geminiQuota -->|"capacity reserved"| gemini["Call Gemini"]
    geminiQuota -->|"no direct-provider capacity"| fallbackDecision["Worker selects OpenRouter route"]
    geminiQuota -->|"denied or storage failure"| sourceFallback["Source fallback"]
    gemini -->|"provider failure"| fallbackDecision
    gemini -->|"structured output"| validate["Validate schema and allowed citation IDs"]
    fallbackDecision --> openRouterQuota["D1: reserve OpenRouter capacity"]
    openRouterQuota -->|"denied, unavailable, or storage failure"| sourceFallback
    openRouterQuota -->|"capacity reserved"| openrouter["Call OpenRouter"]
    openrouter -->|"failure"| sourceFallback
    openrouter -->|"structured output"| validate
    validate -->|"invalid, unsupported, or foreign ID"| safeFallback["Source or search fallback"]
    validate -->|"accepted"| answer["Answer with trusted citations"]
    accessExit --> event["Attempt bounded D1 event recording"]
    infraFallback --> event
    searchFallback --> event
    sourceFallback --> event
    safeFallback --> event
    answer --> event
    event -->|"recorded or write failed"| response["Return selected response through PHP"]
    response --> ui
    ui -.->|"optional feedback and message ID"| feedbackPhp["PHP intermediary"]
    feedbackPhp --> feedbackHandler["Worker feedback handler"]
    feedbackHandler --> feedbackD1["D1: store message-linked feedback"]

The architecture treats the browser as untrusted, keeps PHP as the authenticated server intermediary, and leaves the Worker as the single owner of retrieval, grounding, quotas, provider routing, and failure behavior. Answer, denial, and fallback paths attempt bounded D1 event recording, but a telemetry write failure does not prevent the selected response from returning.