2022 – 2023

The Lehrjahre

CODAC Berlin · Full-Stack Web Development

Missing developer knowledge

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 catalogue

catalogue only

CA-Projects 2022 – 2023

my-first-react-app: 'Hey, Ercan is learning React!'

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.

walkable

my-first-react-app Jan 2023

Hey, Ercan is learning React! — the rendered page

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.

Specimen — App.js, the styling lesson
<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.

Specimen — NavBar.js, one whole component
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.

Enter the exhibit →

walkable · pantry-fed

rick-n-morty Jan 2023

Rick and Morty character grid with a search box

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.

Specimen — App.js, the broken search
   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.

Enter the exhibit →

walkable · still works

Yet Another Company Website Nov 2022

Dark restaurant home page, crescent moon icon, header 'Yet Another Company Website'

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.

Specimen — confirmation-page.js, the rockets
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."

Enter the exhibit →

walkable · three doors

The sprint widgets Dec 2022

Daily Wisdom by Chuck Norris, one joke in a card

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.

The fisheries browser, species cards
Specimen — ChuckNorris/main.js, createCard
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.

Daily Wisdom by Chuck Norris →

The fisheries browser →

Daily News From Turkey →

walkable

MaHalle v1 Feb – Aug 2023

MaHalle v1 forum home, Discussions tab

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! :))"

Enter the exhibit →

no face — it was a terminal

ChatGPT-Interface Mar 2023

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."

walkable

GoneWithTheTailwind Mar 2023

Ninja Blogger, a Tailwind blog front page

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 :))"

Enter the exhibit →

walkable · answered

GraphOL-server-example Mar 2023

GraphQL Playground answering a users query

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.

Specimen — src/data.ts, the whole cast
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.

Specimen — theirResponses.txt, an answer to a question no longer asked
{
  "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".

Enter the exhibit →

dead on arrival

GraphQL-Booklist Mar 2023

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.."

walkable · still ticking

React-Hooks-with-TypeScript Apr 2023

Hooks cheat sheet with fetched user cards

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.

Specimen — CustomHookComponent.tsx, the map that never opened
{/* <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 :-]'

Enter the exhibit →

walkable · revived · fed

movie-db Apr 2023

movie-db home

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 movie grid, fed: real posters on capture day

The footer credit is a ternary joke: @copyright ? @copyright : " " 😆

Enter the exhibit →

walkable

admin-dashboard May 2023

Admin dashboard with widgets and revenue chart

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".

Enter the exhibit →

walkable · still works

Finance_Logger May 2023

Finance Logger with one invoice entry

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".

Enter the exhibit →

walkable

MaHalle v2 Jul 2023 – Mar 2024

maHalle v2 login with torn-paper logo

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.

Enter the exhibit →

catalogue only

mongodb-crud Sep 2023

Next.js error overlay on the topics list

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.

The add-topic form under the ATAKEE navbar

Sole commit: "mostly completed".

walkable · fed by its own CMS

Developer-Portefeuille Oct 2023 – Feb 2024

The 2023 developer portfolio

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.

Enter the exhibit →

walkable

dogsNfilms Dec 2023

The films catalogue, posters intact

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".

Enter the exhibit →

epilogue · 2026

translation-office-ai-assistant 2026

AI receptionist, Live Call tab, status Ready

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.

How these were captured

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.

← Back to the museum