Tutorial 06 — Final Tutorial

The Three-Worker Pattern

How real PrivateAI apps stay organized as they grow — one site, one AI brain, one memory, working together.

Time: 30–40 minutes Cost: Free Level: Beginner–Intermediate

Why Split Into Three Workers?

The single-file chat app from Tutorial 4 works great — right up until your app needs to remember a conversation between visits, let people upload images, or generate a structured summary on demand. At that point, one giant file holding the page, the AI logic, and the storage logic all at once starts getting hard to follow and hard to fix.

The fix isn’t more complexity — it’s splitting one Worker into three, each with a single job. This is the exact pattern behind PrivateAI Tutoring and every journal-style app in this series.

1. Main Site Worker

Serves the page people actually see and use. Holds the HTML, CSS, and front-end JavaScript — the same pattern from Tutorial 4.

2. Chat Worker

Holds the system prompt and talks to the AI model. Receives a message, returns a reply. Nothing else.

3. Storage Worker

Saves and recalls data — conversation history, uploaded images, anything that needs to persist between visits.

💡 Notice each Worker has one job. When something breaks, you immediately know where to look — if replies are wrong, check the Chat Worker; if history isn’t saving, check the Storage Worker. That focus is the entire benefit of splitting things up.


How They Talk to Each Other

This is simpler than it sounds — it’s the exact same fetch() call from Tutorial 4, just pointed at a different Worker’s URL instead of your own /chat route:

const response = await fetch("https://my-chat-worker.yoursubdomain.workers.dev", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ message: userMessage, history: previousMessages })
});
const data = await response.json();

Your Main Site Worker calls this from inside its own /chat handler, then passes the reply straight back to the visitor’s browser. The visitor never knows there are three separate Workers involved — it all feels like one app.


Remembering Conversations With KV

Workers KV is a simple key-value storage system — think of it as labeled folders where you can save a piece of text and retrieve it later by name. It’s how the Storage Worker remembers a conversation between visits.

1Add a KV binding

In your Storage Worker’s Bindings tab, add a KV Namespace binding. Create a new namespace if you don’t have one, and name the variable something like JOURNAL_KV.

// Save data
await env.JOURNAL_KV.put("session:abc123", JSON.stringify(messages));

// Retrieve it later
const saved = await env.JOURNAL_KV.get("session:abc123");
const messages = saved ? JSON.parse(saved) : [];

That’s the entire mechanism — put to save, get to retrieve. The tricky part is the key, the label you use to find the data again — which is where sessions come in.


Sessions — Recognizing a Returning Visitor

A Worker has no idea who’s visiting — every request looks like a stranger unless you give each visitor a unique ID and ask their browser to remember it. The standard trick: generate a random ID the first time someone visits, and save it in the browser’s localStorage so it’s still there next time.

function getOrCreateSessionId() {
  let id = localStorage.getItem("my_session_id");
  if (!id) {
    id = "s_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
    localStorage.setItem("my_session_id", id);
  }
  return id;
}

This session ID becomes the KV key. The same visitor, on the same device, always gets the same ID back — so env.JOURNAL_KV.get("session:" + sessionId) always finds their own conversation, and no one else’s.

⚠️ localStorage is tied to one browser on one device. The same visitor on their phone and their laptop will get two different session IDs, and two separate conversations. That’s fine for a journal or practice tool, but worth knowing if you ever wonder why "my history disappeared" on a different device.


When to Use This Pattern

A simple rule of thumb: stay with the single-file Worker from Tutorial 4 until you specifically need one of these things — remembering a conversation between visits, storing uploaded files, or generating an on-demand summary of a whole session. The moment you need persistent memory, split into the three-Worker pattern. Until then, the simpler single file is genuinely the better choice — don’t add architecture you don’t need yet.


What You Learned

You’ve Gone From Zero to a Real, Installable AI App

Six tutorials ago you didn’t have a domain. Now you understand Cloudflare Workers, AI integration, chat app architecture, PWAs, and the Google Play Store. Keep building — and keep your own work private along the way.

Open Your Private Dev Journal →