ZapiszPrzepis: how I use AI on real projects

· 6 min read

An app built and shipped from scratch with AI — the 10xDevs 3.0 final project, passed first time with a Best Project distinction. What that process looks like.

An app built and shipped from scratch with AI — the 10xDevs 3.0 final project, passed first time with a Best Project distinction. What that process looks like.

AI has been part of my daily work for a long time — but saying so proves nothing, so here is a project instead. I built ZapiszPrzepis from scratch and shipped it to production: the app runs, the code is public, and as the final assignment of the 10xDevs 3.0 programme it passed first time and earned a Best Project distinction.

It is still a test version: a few people close to me use it day to day, and registration is not open.

This post is about what that process actually looks like — because the process is what I bring to client work, not just to my own side projects.

What the app does

Recipes circulate as posts, reels and videos. The reflex is to bookmark them or use the platform’s own “Save” button. The trouble is that all of those store a pointer, not the content.

After a few months a good share of saved links stop working. The author deletes a reel, a cooking group vanishes, a blog goes dark, a post flips to private. A saved collection quietly turns into a list of 404s — and you find out at the moment you actually want to use it.

ZapiszPrzepis works the other way round — archive-first. Every link becomes a permanent copy: title, ingredients, steps and image land in the user’s own database. The source URL is stored with them, so the original is one click away for as long as it lives. When it goes, you lose nothing but that button.

That copy is not a snapshot of the page. An OpenAI model writes the text — it keeps the ingredients and the steps, and strips the navigation, the ads and the long preamble you have to scroll past to reach the actual recipe. English sources get translated into Polish along the way.

I designed for a non-technical person — someone who does not type ingredients by hand, fill in forms, or manage folders and tags. That constraint turned out to be the most useful filter in the whole project: it immediately ruled out most of the “obvious” features.

How it works

The entire entry path is one gesture. The app registers as a Web Share Target, so it shows up on the system share sheet next to Messenger and WhatsApp. The user sends it a link and does nothing else.

ZapiszPrzepis home screen on a phone

Everything after that happens in the background:

What happens after a link is shared
  1. Step 1

    Source detection

    A blog post, a video and a social post are each handled differently.

  2. Step 2

    Content retrieval

    Via Firecrawl, or for Blogger-hosted blogs via their JSON feed — a deterministic result instead of guessing from scraped HTML.

  3. Step 3

    Extraction

    An OpenAI model (gpt-4o-mini) pulls out the title, ingredients, steps and category, translating English sources into Polish.

  4. Step 4

    Image archiving

    The picture is copied into our own storage so it cannot disappear with the source.

  5. Step 5

    Storage

    The finished recipe lands in the database with per-user isolation.

Extraction can take a dozen seconds and is occasionally flaky, so it does not run inside the request cycle. It emits an event to Inngest, which handles queueing and retries. The user gets an immediate response and the recipe appears shortly afterwards.

Web recipe search with voice input came later — archiving only solved half the problem. The other half is finding something you do not have yet.

The stack, and why

Layer Choice and reason
Framework
Next.js 15 (App Router) — Server Actions, so forms need no separate API
Database and auth
Supabase — Postgres with RLS plus passwordless magic-link login
Background jobs
Inngest — retries and queueing without running my own infrastructure
Extraction
Firecrawl + OpenAI (gpt-4o-mini) — fetch the content, then pull structure out of it
Hosting
Cloudflare Workers (OpenNext) — the rest of the project already lived there
Client layer
PWA + Web Share Target — the only way to get a genuine one-gesture entry point

One decision determined the rest: hosting on Cloudflare Workers means no Node.js APIs at runtime. Every integration had to work over plain fetch. That ruled out several libraries before I wrote a line of code — which was a gift, because discovering it mid-deployment would have cost one of the few days available.

I break down the choice between Next.js and lighter generators in my comparison of web application frameworks — here the need for dynamic server-side state settled it.

How I actually work with AI

This is the part that carries over to client projects one to one.

Project context as long-term memory

The repository carries a directory with the requirements, the roadmap, per-change plans and a register of lessons learned. This is not documentation written for humans after the fact — it is input for the model before every change.

The difference is tangible. A model without context produces code that looks reasonable but ignores a decision made three days earlier. A model with the requirements and the plan in hand proposes solutions consistent with what already exists — and flags it when you ask for something that contradicts an earlier call.

For a client that has a mundane consequence: those documents stay. You are not buying a black box, you are buying a project where it is visible what was decided and why.

A plan before code, every time

Every meaningful change starts with a document laying out phases, acceptance criteria and risks — not with an instruction to “add search”. Only an approved plan goes to implementation.

It sounds like bureaucracy. In practice it is what shortens the whole thing, because it removes the most expensive category of mistake: building something that works and solves the wrong problem. The July search feature is the clearest example — it had a week of budget and took three days, because the plan was finished before the first line.

Tests where the logic is sneaky

The project carries over 70 unit tests plus an end-to-end suite in Playwright. They are not spread evenly, and that is deliberate — they sit where silent mistakes are easiest: source-type detection, ingredient normalisation, judging whether fetched content is even a recipe, parsing video identifiers.

I cover how I wire AI into E2E tests in my guide to E2E testing with Playwright.

Review as a gate, not a formality

Code written with a model’s help is rarely wrong in obvious ways. It is wrong where something works but rests on a false assumption: a regular expression that looks watertight. A match that holds for today’s inputs. A privilege granted just in case.

Those are exactly the things that sail past the compiler and the test suite. So review is not the last item on a checklist here — it is where I spend a disproportionate amount of time, and the more code a model writes, the better that trade gets.

What your project gets out of it

Concretely, without the platitudes:

  • Requirements written down before the code. You know what is being built and how we will know it is finished.
  • A faster route to a working version. AI shortens the typing, which leaves more time for what actually decides the outcome.
  • Tests where things break quietly. Not for a pretty coverage number, but so a regression does not reach production.
  • The code and the docs are yours. Repository, decisions and change history — you can take them further, with me or without me.
  • One person accountable for the whole thing. From architecture through deployment to support after launch.

Summary

  • AI does not replace the thinking, it shortens the typing. The difference is made where we settle what is being built at all.
  • Project context in the repository is infrastructure, not documentation — and it stays with the client.
  • Review and tests matter more the more code a model writes, because mistakes shift from “does not compile” toward “works, but on a false assumption”.
  • Learn the platform’s constraints before the first line, not during deployment.

ZapiszPrzepis was built as part of 10xDevs 3.0, passed first time with a Best Project distinction — verify the certificate — and the code is public on GitHub.

Got a project that simply has to work?

I build websites and web applications from scratch — with a plan before the code, tests where the logic is sneaky, and a repository that stays yours. Tell me what you need and I will tell you whether and how it can be done.

Talk to me about your project See what I do

Frequently Asked Questions

— 01
Does using AI mean worse code?
It depends entirely on the process. A model with no context produces code that looks sensible and ignores earlier decisions. Given the requirements and a plan, it proposes solutions consistent with the rest of the system. That is why the plan comes before the code here, and every change goes through review.
— 02
Does AI make a project cheaper or faster?
Faster, sometimes — AI shortens the typing, not the thinking. The real saving does not come from generating code quickly. It comes from settling the requirements and the plan before implementation. The most expensive mistake is building something that works and solves the wrong problem.
— 03
Who is responsible for the quality of AI-assisted code?
I am. The model is a tool, like a framework or an editor — responsibility for what reaches production stays with me. In practice that means tests where silent mistakes are easy, and review as a gate rather than a formality.
— 04
Do I get the code and the documentation?
Yes. The repository, the requirements and the architectural decisions are yours. ZapiszPrzepis is public, so you can see exactly what a project of mine looks like inside — documentation, tests and change history included.
— 05
Can I sign up for ZapiszPrzepis?
Not yet. It is a test version used day to day by a few people close to me, and registration is not open. The code is public, so you can see how the app works inside — documentation and tests included.
— 06
How is archive-first different from bookmarking?
A bookmark saves a pointer — it works only while the source exists. Archive-first saves a copy of the content: title, ingredients, steps and image land in your own database. The original URL is stored with them, so you can still jump back to the source — and when that post disappears, the recipe stays.
Back to blog

Related posts

Read more