No ads. No paywall.
No account.
That constraint wrote the architecture.
Tedzi is a free learning platform for children and adults — physics, chemistry, rhetoric, web security, speed reading, time management and more. It works on a phone with no signal, and it never asks who you are.
Those refusals are not marketing. Because there is no account, there is no server that holds anyone's progress, which means there is no personal data to protect and almost nothing to keep running. A free product survives on the operating cost you avoided at design time.
- Status
- Live
- Kind
- Free learning platform
- Courses
- 30+
- Stack
- Static PWA · service worker
- Accounts
- None
- Tracking
- None
- lint content tree failOver a thousand corruption markers across 68 files. Valid text, wrong characters, nothing crashed.
- revert 68 files→last good commit restoredRecovered from version control rather than repaired by hand.
- lint content tree passZero markers. The check is now part of the build and fails it.
- version app + shell cache coupledBoth bump together or returning visitors get a stale shell — a rule the build now enforces.
- course a JSON file→a live test dataAdding a subject means writing content, not shipping a code change.
Every one of these gates exists because something got through once. A content pipeline is only as good as the things it declines to publish.
Brief What the refusals buy § 01
Free products die of running costs, not of bad ideas.
The usual shape for a learning platform is an account, a server that stores progress, and analytics to justify both. Each of those is a recurring bill, a privacy obligation and a thing that can be down at seven in the morning when a child wants to practise.
So we removed them at the design stage rather than economising later. Progress, scores and resume state live in the browser. The application is static files and a service worker. What is left to operate is a web server holding documents — which is why the platform can stay free without anyone deciding, one hard quarter, that it needs to earn money.
The interesting engineering is therefore not in the app. It is in the pipeline that produces the courses.
Ledger What is built § 02
Decisions What we chose, and what it cost § 03
Three calls, all downstream of the same refusal.
No account, so the browser is the database.
Scores, history and the ability to resume a paused test all live in local storage. There is no sign-up, no password reset, no session, and no table anywhere containing a learner.
Cost: progress does not follow a person to a second device, and clearing site data clears it.
Bought: no personal data to protect, no login to maintain, and an operating cost close to zero.
A new course is data, not code.
The test engine reads one structured file per course. Adding a subject means writing questions and shipping a file — no branching, no release, no regression risk to the courses that already work.
This is what made an agent squad viable as a content team at all. They produce data against a schema; the engine stays untouched.
Cost: the schema has to be right early, because everything written against it inherits its mistakes.
Bought: content scales without engineering becoming the bottleneck.
Wrong answers come back until they are right.
A test is not finished when it ends; it is finished when every question has been answered correctly at least once. There is a timed mode, a score history, and a paused test can be resumed later.
All of that shipped in the first version rather than being retrofitted. Motivation mechanics added afterwards tend to sit on top of a design that did not expect them.
Cost: a more complicated first release than a plain quiz would have been.
Bought: a learning loop rather than a scoring screen.
Incidents What broke, and what it changed § 04
Both were pipeline failures, not application bugs.
Content integrity
Parallel writers corrupted the content tree.
Several agents wrote into the same course files at the same time. German umlauts came apart under the overlapping writes. Sixty-eight files were affected and over a thousand corruption markers accumulated before anyone looked, because nothing failed — the files were still valid, still parsed, still rendered. They were just wrong.
What we had assumed: that separate tickets meant separate files. It was true often enough to feel like a rule and never written down as one.
Fix → restore from version control, then make the corruption check a build gate that fails rather than warns. Content is a build artefact and deserves the same gates as code.
Cache coherence
Returning visitors saw yesterday's application.
A service worker makes the app work offline. It also means a returning visitor is served whatever was cached, and updating that cache correctly is a two-part operation: the application version and the cached shell have to move together. When they did not, people needed two reloads to see a change.
What we had assumed: that shipping new files is the same as delivering them. With an offline-first app it is not.
Fix → couple the two version markers so they can only move together, and reload automatically when a new worker takes control. One reload now does what two used to.
Transfer What this means where you are § 05
Content systems fail differently from software systems.
Treat content as a build artefact
Text does not throw exceptions. If a pipeline produces content, it needs gates that fail the build on corruption, because the alternative is discovering it from a reader.
Offline-first is a data-ownership decision
Putting state in the browser removes a server, a login, and a privacy obligation in one move. It costs cross-device continuity — often a fair trade, and always worth making deliberately.
Schema first, when non-engineers will fill it
The moment content is produced against a schema rather than through a codebase, the schema is your API. Mistakes in it propagate into everything written afterwards.