Koinder Practitioner Track 18+ ← My Learning About the track Clubhouse

Capstone: Ship Something a Stranger Can Use

Build and deploy a working AI service that exercises all four fields at once — then break it on purpose, because the failure path is what gets you hired.

Module 12 · Practitioner Track · 18+

What you are building, and why this one

By the end of this build you will have a working AI service, deployed at a public URL, that a stranger can use without you present. That artifact is your portfolio. Not a certificate — the URL.

It is deliberately one project rather than four, because one system exercises all four fields at once:

Cloudit is deployed, it has an endpoint, it holds state, it handles load and failure
AIit calls a language model and shapes its behaviour
Machine learningit classifies and routes before it spends money on the model
Roboticsit is a sense–think–act loop; swap the input for a sensor and the output for a motor and nothing else changes

That last row is the point. People treat robotics as a separate world because it has hardware. It is the same loop with a different input and a different output.

Why this stack — and why not AWS

You will build on PHP on shared cPanel hosting, with Supabase for data. Some people will tell you that is not a real engineer's stack. Consider what actually matters:

It costs a few thousand naira a month, not a credit card you cannot afford when the free tier ends.

It is deployed today, not after two weeks of configuration.

🎯

The six patterns are identical on every stack. An interviewer asking how you made a webhook safe to retry does not care whether it ran on Lambda or on cPanel.

Learn the patterns where it is cheap. Move them to bigger infrastructure when someone else is paying for it — which is a two-day job once the patterns are in your hands, not a two-month one.

The architecture — and which pattern each piece is

Read this before writing a line. Every box below exists because of a pattern from the previous lesson.

1. ReceiveHTTP endpoint takes a question [Pattern 1 · take in]
2. CheckHave we answered this exact question before? Return the cached answer [Pattern 2 · slow clock]
3. ClassifyCheap local classifier: is this even in scope? Reject junk before paying for a model call [Pattern 2]
4. ThinkCall the language model with a shaped system prompt [Pattern 1 · decide]
5. GuardLow confidence or model down? Fall back, do not invent [Pattern 6]
6. Respond & logReturn the answer, record what happened [Pattern 1 · act, Pattern 6 · loudly]
7. ImproveThumbs up/down feeds an eval set you review weekly [Pattern 3 · correction]

Step 3 is the one that separates you from most people building on top of AI models. Almost everybody sends every request straight to the model and is surprised by the bill. A classifier that costs nothing, filtering before a call that costs money, is a real engineering decision — and it is the sort of thing you say in an interview.

Build it — step by step

Do not paste all of this at once. Build one step, run it, break it deliberately, then move on. Code you have watched fail is code you understand.

Step 1 — the endpoint Pattern 1

<?php
// ask.php — the loop: take in, decide, act
header('Content-Type: application/json');

$input = json_decode(file_get_contents('php://input'), true);
$question = trim($input['question'] ?? '');

if ($question === '') {
    http_response_code(400);
    echo json_encode(['ok' => false, 'error' => 'Ask me something.']);
    exit;
}

// everything else goes here
echo json_encode(['ok' => true, 'answer' => 'not built yet']);

Break it on purpose: send an empty body. Send malformed JSON. Send a 50,000-character question. Whatever it does badly now is what it will do in production.

Step 2 — cache before you spend Pattern 2

$key = 'ans:' . hash('sha256', mb_strtolower($question));
$cached = cacheGet($key);          // your Supabase read
if ($cached) {
    echo json_encode(['ok' => true, 'answer' => $cached, 'cached' => true]);
    exit;                          // no model call, no money spent
}

Measure it: time the same question twice. Write down both numbers. That difference is the Two Clocks pattern in milliseconds, and it is a sentence in your interview.

Step 3 — classify before you call Pattern 2 + ML

// A cheap local classifier. No model call, no cost.
// Later you replace these keywords with a trained classifier —
// the SHAPE of the code does not change, only what decides.
function inScope($q) {
    $topics = ['loop','cloud','robot','model','deploy','api','data','train'];
    $q = mb_strtolower($q);
    foreach ($topics as $t) if (strpos($q, $t) !== false) return true;
    return false;
}

if (!inScope($question)) {
    echo json_encode(['ok' => true, 'answer' => 'I only answer questions about building systems.']);
    exit;
}

Notice what you just did. You made an engineering decision about cost, not just a feature. When you later swap those keywords for a trained model, steps 1, 2, 4, 5 and 6 do not change at all. That is Pattern 4 — you hid the method behind a promise called inScope().

Step 4 — the model call Pattern 1 · decide

$ch = curl_init('https://api.anthropic.com/v1/messages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_TIMEOUT        => 20,          // ALWAYS set this
    CURLOPT_HTTPHEADER     => [
        'x-api-key: ' . kodiConfig('ANTHROPIC_API_KEY'),   // never in JS
        'anthropic-version: 2023-06-01',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'model'      => 'claude-haiku-4-5-20251001',
        'max_tokens' => 400,
        'system'     => 'You explain system-building to a 16-year-old in plain words. '
                      . 'If you are not sure, say so. Never invent an API that does not exist.',
        'messages'   => [['role' => 'user', 'content' => $question]],
    ]),
]);
$raw  = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

Two things most people get wrong here. No timeout means one slow call holds a connection open until your whole site stops answering. And the key belongs on the server — the moment it is in JavaScript, it is public and someone else is spending your money.

Step 5 — the guard Pattern 6

if ($code !== 200 || !$raw) {
    logEvent('model_failed', ['code' => $code]);      // LOUDLY
    echo json_encode([                                 // SOFTLY
        'ok'     => true,
        'answer' => 'I cannot reach my brain right now. Try again shortly.',
        'degraded' => true,
    ]);
    exit;
}

Test this properly: put a wrong API key in on purpose and call your endpoint. A user must see a calm sentence. You must see a log line. If you see a stack trace on screen, you have failed both halves.

This step is the single most valuable thing in the whole build. Nearly every portfolio project you will compete against has no step 5 at all.

Step 6 — respond and record Patterns 1 + 6

cacheSet($key, $answer);
logEvent('answered', [
    'q_hash'  => substr($key, 4, 12),
    'ms'      => $elapsedMs,
    'cached'  => false,
]);
echo json_encode(['ok' => true, 'answer' => $answer]);

Log the hash, not the question. You do not need people's raw text sitting in a table, and choosing not to collect it is a decision you should be able to defend out loud.

Step 7 — the correction loop Pattern 3

// /api/feedback.php  — thumbs up or down against the question hash
// Once a week, read every thumbs-down. Those are your eval set.
// Adjust the system prompt. Re-run them. Did the bad ones improve?
// Did any GOOD ones get worse?  <-- that second question is the job.

This is gradient descent done by hand: measure the error, make a small correction, measure again. Same pattern as PID, same pattern as training. You are the optimiser.

Ship it — the part people skip

1

Deploy to a real domain. A localhost screenshot is worth nothing to an employer.

2

Put a rate limit on it before you announce it. One person with a script can spend your whole balance overnight.

3

Give ten strangers the link and watch what they type. They will break it in ways you never imagined, which is exactly why you need them.

4

Write a README with an architecture diagram and one paragraph per pattern explaining why each piece exists.

5

Record a 2-minute screen video: here is the happy path, here is what happens when I break the model call. That video gets you interviews.

Say this in an interview, word for word:
"I put a cheap classifier in front of the model call, so junk requests never cost anything. When the model is unreachable the user gets a calm message and I get a log line. Repeated questions are served from cache — same question twice went from 1.8 seconds to 40 milliseconds."

That is three of the six patterns, spoken in fifteen seconds, with a number in it. Most candidates with a degree cannot do that.

Then make it physical — the robotics bridge

When your service works, change two things and nothing else:

IN

Instead of a typed question, a sensor reading arriving from an ESP32 over wifi.

OUT

Instead of returning text, return a command that turns a motor.

Steps 2, 5, 6 and 7 do not change at all. You still cache, still guard, still log, still correct.

You have not learned a new field. You have swapped the two ends of a loop you already own — and that realisation, honestly earned, is worth more than any certificate on the wall.

🤖

One question before we start

The Practitioner track is built for adults. It assumes you are ready to deploy real systems that real strangers will use, and to be answerable for what they do.

We ask because in Nigeria you become an adult at 18, and this track is a paid commitment. Nothing here is stored for anyone under that age.