CODAC Berlin · Full-Stack Web Development
That phrase is carved into the translator plaque: it is why a WordPress template defeated me in 2019. In 2022 I went after the missing knowledge properly — a coding bootcamp in Berlin — and these fifteen repositories are the surviving school notebooks. None of them was ever a website with an address; they lived on localhost and in private repos, and this wing is the first time any of them has been seen in public.
They are amateur, naive, sometimes childish attempts to build something, and they are shown exactly as they stopped: placeholder text shipped, buttons that do nothing, sections that render a single word. Fourteen of the cards below are walkable — captured as frozen pages, every asset local, nothing live; between them they open sixteen faces, since the sprint-widgets card alone holds three. The rest are catalogue cards. Every card opens its plaque — click one. Where a card quotes something in monospace, it is quoted verbatim.

The earliest folder: sprint exercises and my two first React apps.
The earliest surviving folder — and by now mostly a frame of empty hooks: the restaurant site, both first React apps and three sprint widgets that once lived only in this card hang in frames of their own across the hall. What remains uniquely here: Sprint-1's exercise pile ("Answers to The Exercises 19-28, if any :)"), a shopping list, a file honestly named deneme.html — Turkish for "trial" — and the folder's name itself, CA-Projects-, trailing hyphen shipped.
Nav links labelled "sdf" and "asdf" — placeholder text I never came back for.
Every block on this page is a hand-written React component.
My first React app, preserved mid-lesson. A NavBar whose five links read sdf, asdf, sdf; a Contact view that renders the words "Contact information"; a Footer that says "copyright @atakee" on green. None of it is a page in the old sense — every block is a component, written by hand, mounted one under the other so each had somewhere to stand.
<div className="App">
<Contacts />
<h1 className='tomato'>Hey, Ercan is learning React! :)))</h1>
<h2 className='blue'>this should appear blue</h2>
<h3 className='blue' style={{color: "yellowgreen" }}>inline style</h3>
<h4 className='blue' style={myStyle}>style object</h4>
<MyComponent />
</div>
One heading per styling technique — that was the entire lesson. In the stylesheet, the class named tomato is, of course, red. And the walkable page next door is exactly what this JSX became.
import React from 'react'
function NavBar() {
return (
<div style={{color: "purple", fontWeight:"bold"}}>NavBar
<ul style={{display: "flex", flexDirection: "row", justifyContent: "space-evenly", backgroundColor:"lightblue"}}>
<li>sdf</li>
<li>sdf</li>
<li>asdf</li>
<li>sdf</li>
<li>asdf</li>
</ul>
</div>
)
}
export default NavBar
The list of names in MyComponent is a constant called elephants. Two of the elephants are Monique.
The search box searches — into the console, and no further.
My second React app fetched twenty Rick and Morty characters from the public API every time it started. The museum could not freeze a network, so it stocked a pantry instead: sixty characters fetched once, on capture day, and stored inside the page. Each visit the exhibit serves a different twenty. Nothing is requested; the pantry never empties.
const filterCharacters = ()=> {
const filteredCharacters = characters.filter((character)=> {
return character.name.toUpperCase().includes(inputValue.toUpperCase())})
console.log('filteredCharacters :>> ', filteredCharacters);
}
filterCharacters();
// if (filteredCharacters.length != 0) {
// characters = filteredCharacters;
// }
Typing in the search box computed the filtered list, logged it to the console — and stopped. The two lines that would have put it on screen sit commented out, directly underneath. They have been a few keystrokes from working since January 2023. In the frozen face even the console is silent, so the search now does exactly what it always appeared to do: nothing.
Every log label in the source ends in :>> — "filteredCharacters :>>" was the only place the search results ever appeared.
A restaurant whose header admits it: Yet Another Company Website.
The first thing I built at the bootcamp: a restaurant site that never got a name — the header says "Yet Another Company Website", the browser tab still says "Project Kick-Off". Lorem ipsum stands in for every paragraph the restaurant never wrote. But the reservation form works: book a table and the confirmation page reads your booking back to you — the wing's only working two-page flow, alive since November 2022.
let params = (new URL(document.location)).searchParams;
console.log("🚀 ~ params:", params);
let email = params.get("email");
console.log("🚀 ~ email:", email);
const emailPlace = document.querySelector(".email")
emailPlace.innerHTML = email
let fname = params.get("fname");
console.log("🚀 ~ fname:", fname);
const fnamePlace = document.querySelector(".fname")
fnamePlace.innerHTML = fname
Every log in that file launches a little rocket — the 🚀 ~ prefix a VS Code extension stamped on the era. The museum kept the rockets and defused one booby trap: the original pasted your booking into the page as live HTML; the exhibit pastes it as text. Everything else is untouched.
The form's checkbox arrives pre-ticked: "I do NOT want any special treatment."
Chuck Norris wisdom, a fisheries browser, Turkish news — one sprint, three doors.
Sprint exercises: each of these was an afternoon, a fetch call, and a div to put the result in. The museum gives them three small doors. Behind the first, Chuck Norris dispenses wisdom from a pantry of jokes stocked on capture day — a different one each visit. Behind the second, a browser of NOAA fish species whose photos sank with the government image server that hosted them — names, biology and habitat swim on. One fish stands open — its Show button is the only one of the 116 that still works. Behind the third, the day NewsAPI had no headlines left for Turkey — an empty front page, kept honestly.

function createCard(wisdom) {
const cardContainer = document.getElementById("card-container");
cardContainer.innerHTML = "";
cardContainer.innerHTML = wisdom.value;
}
Empty the container, then fill it — belt and braces, in two consecutive lines. The pantry that serves the jokes now is curator code and uses textContent; Chuck's original createCard is retired to this plaque.
Two of the three titles promise dailiness — "Daily Wisdom by Chuck Norris", "Daily News From Turkey" — from pages that never saw a second day.
A MERN forum for the neighbourhood, eternally empty.
My first big thing: a MERN forum for the neighbourhood — Mahalle, Turkish for exactly that, punning on German meine Halle. Discussions, announcements, recommendations; register, log in, start a debate. The backend didn't come along to the museum, so the forum stands eternally empty: search box ready, nobody home. The landing page's sideways-rotated headings are an original bug, preserved.
Commit message: "Adding forum posts works! :) But there are a lot more to do! Go to work! :))"
Twenty-three lines of Node; the chat happened in a console window.
Twenty-three lines of Node that let you chat with GPT-3.5 in a console window. March 2023: everyone was building one of these. No browser was ever involved, so there is nothing to walk through — this card is the whole exhibit.
The commit message says it best: "the script file is working, one can have a chat in the console window."
A blog front page for ninjas that was never a blog.
A blog front page for ninjas — "Tips for Ninjas / For Ninjas" — that was never a blog. A Tailwind styling exercise with three fake posts whose images have nothing to do with their titles. The "Most Popular" section is an empty comment in the source; the "Load more" button loads nothing. Both preserved.
The entire git history: "Initial commit, but everything's done :))"
A server with no website. Press Play and 2023 answers.
My first GraphQL server — the typo in the name shipped, and stuck. Two Turkish-named users, three posts, four comments, all hardcoded; its only face was the query playground, and it is the whole exhibit: a server that never had a website.
The query waiting in the editor is my own, copied out of the notes file I kept while learning. To photograph an answer the museum had to start the server one more time, in 2026, and ask: press Play and what comes back is not computed here, but what it replied that day. The Schema tab opens the shape I had built: users with posts, posts with comments, everything pointing at everything else. Nothing here runs; three frozen pages simply link to each other, so the exhibit needs no JavaScript at all. One thing survived the freeze on its own: beside the address bar a small light still pulses, labelled "Polling Schema" — an animation that needs no script, keeping watch over a server that is no longer listening.
const comments = [
{ id: "1", text: "This is Ahmet's comment", post_id: "1", user_id: "2" },
{ id: "2", text: "Mehmet's comment", post_id: "1", user_id: "1" },
{ id: "3", text: "foo bar", post_id: "2", user_id: "2" },
{ id: "4", text: "foo bar baz", post_id: "3", user_id: "1" },
];
Beside the code I kept a second file, theirResponses.txt,
where I pasted the answers the server gave me. It has fallen out of
step: the saved replies are still in Turkish, from before I translated
my own test data into English. The notes are older than the code, and
neither was ever told about the other.
{
"id": "1",
"text": "Bu Ahmet'in yorumudur",
"post_id": "1",
"user": {
"id": "2",
"fullName": "Ahmet Günal"
},
"post": {
"id": "1",
"title": "Mehmet'in gönderisi"
}
},
The fake data gives up halfway through: the last comments are "foo bar" and "foo bar baz".
Caught mid-refactor and never run again.
A book-catalogue API, caught mid-refactor from require to
import and never run again. Three separate errors stand
between it and starting; behind them, every query resolver is commented
out anyway. No frontend was ever committed. Some exercises end
mid-sentence.
Last words: "Modified the app.js file with import statements instead of require.."
Six hooks pinned to one page; one of them still beats.
One page, six hooks, one component each — my React cheat sheet. It fetched ten fake users from a placeholder API and filtered for the one named Antonette, to prove useMemo worked. A commented-out map component records the ambition that got shelved: the users' coordinates are printed as raw numbers instead.
{/* <MapContainer style={{ height: "400px" }}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker
position={[
Number(user!.address.geo.lat),
Number(user!.address.geo.lng),
]}
>
<Popup>A pretty CSS3 popup.</Popup>
</Marker>
</MapContainer> */}
Freezing a page about hooks stops every hook on it. So the curator wrote a handful of lines, allowed to change only text the page had already written: the useEffect counter picks up where the capture left it and goes on ticking, once a second. The reducer still adds ten and takes five, the array still grows, and the context still changes its mind about whose name it holds — once, which is all it ever did. Nothing is rebuilt; the numbers are simply allowed to move again.
A comment in the custom hook: '"Payload" instead of "User[]" to make it genuinely generic :-]'
Woke to a blank screen; the museum lent it a dummy config.
A movie browser with watchlists and Firebase accounts. Without its keys it woke up to a blank white screen — the museum lent it a dummy config so it would open its eyes. The accounts were never real; nothing here can log in. In 2026 the museum went further and carried the movie hall door off its hinges: the grid behind the login now hangs here too, fed with real posters on capture day.

The footer credit is a ternary joke: @copyright ? @copyright : " " 😆
An admin dashboard for nothing; every stat reads 100.
An admin dashboard for nothing: hardcoded numbers, Game-of-Thrones users, a revenue chart for a business that doesn't exist. Every stat reads 100, up 20%. Total sales made today: $420. The front door is unmodified boilerplate, so the museum's door drops you at /home, where the sidebar logo reads atakeedmin.
The login page's title is literal keyboard mash — dsfgsdfgs — and one user lives in the country of "OrasiBurasi", Turkish for "somewhere or other".
The one exhibit that still functions — until you reload.
A one-page invoice logger in hand-compiled TypeScript — and the one exhibit in this wing that still functions: type an entry and it appends to the list, until you reload and it forgets everything. The background image died with the Discord link it was hotlinked from; its filename was the AI image prompt that generated it.
The entire git history is one commit: "Port changed".
Ein Kiez-Gesichterbuch; three doors painted on walls.
The second MaHalle: Ein Kiez-Gesichterbuch — a literal German "face-book", for the neighbourhood. Eighty commits over eight months, my longest project of the era. Login, register, profile and add-topic are fully dressed; Blog, Shop and Kalendar are doors painted on walls — each page renders exactly one word. Walk in and count them.
The footer component renders the word "Footer". On every page.

The navbar just says ATAKEE; the list page crashes on cue.
A CRUD exercise wearing my own name as its brand — the navbar just says ATAKEE. The list page crashes without its database, and would crash on any port but 3000 regardless: the tutorial's hardcoded URLs came along verbatim. The add-topic form renders beautifully, for topics that can never arrive.

Sole commit: "mostly completed".
The direct ancestor of ercan-atak.de, fed by its own CMS.
My first developer portfolio — the direct ancestor of the site at ercan-atak.de today. A hover-to-expand showcase of projects from this very wing ("Home~made Facebook for my Neighbours"), a blog fed by its original CMS, and About/Work sections that are honest empty placeholders. Contact details in the footer are redacted by the curator.
One project card uses the tag <h1p> — not a real HTML element; every browser politely rendered it anyway.
Adopt a broken image.
Dogs and classic films: my two favourite unrelated things, as one catalogue. The film posters still shine; the forty-nine shelter dogs lost their photos when the shelter's image server died — the museum keeps them broken, names and kennel numbers intact. Adopt a broken image.
The footer of every page says, in full: "Copyrighted".

A postscript from 2026: the Lehrjahre never really end.
Not a Lehrjahr — a postscript. An AI receptionist for a translation office, built years later with the knowledge this wing was for: voice calls, chat, a call log, text-to-speech. Photographed keyless, all four tabs politely reporting "Ready". The Lehrjahre never really end.
A code comment narrates its own bug fix in full sentences — the era of AI pair-programming had begun.
Each walkable face is the rendered page as a browser saw it on localhost
in 2026, frozen: scripts removed, every image and font stored locally,
outside links disabled with their originals kept in
data-original. Broken images are original breakage, not the
museum's. Where a face is marked pantry-fed, the museum stocked it at
capture time — data fetched once, stored in the page, served by a few
curator lines; the exhibit still makes no requests. Details in the restoration lab
and the repository's provenance notes.