Binged: een complete webapp bouwen zonder fulltime developer te zijn
Binged: een complete webapp bouwen zonder fulltime developer te zijn
Ik ben geen fulltime developer. Ik heb een bedrijf, beleg, doe aan waterpolo en gebruik AI als gereedschap. Toch draait er op dit moment een webapp op mijn eigen VPS die versie 1.17.0 heeft, een PostgreSQL-database bijhoudt, series trackt per aflevering, films logt, co-watchers synchroniseert en gepersonaliseerde aanbevelingen geeft via de Claude API. Die webapp heet Binged, en ik bouwde hem samen met Claude Code.
Dit is het verhaal.
Waarom een eigen TV-tracker?
We zijn een gezin dat series kijkt. Vroeger gebruikten we Trakt.tv, maar dat klopte niet. Te veel functies die ik niet gebruik, te weinig die ik wel wil. Ik wilde weten welke afleveringen er al zijn uitgezonden — niet welke gepland zijn. Ik wilde co-watching bijhouden zonder handmatig dubbel aan te vinken. En ik wilde dat de app op mijn eigen server draaide.
Trakt.tv kon dat niet. Dus bouwde ik het zelf.
De stack
Binged draait op Next.js 14 met de App Router, TypeScript, Tailwind CSS en PostgreSQL via Prisma. Authenticatie via NextAuth 5 met Microsoft Entra ID — ik log in met mijn gewone Microsoft-account. De app is een PWA: installeerbaar op telefoon en desktop, met een offline-fallback en correcte safe-area afhandeling op iOS.
Externe data komt van TMDB voor metadata en TVmaze voor exacte uitzendtijden. Aanbevelingen via de Anthropic Claude API. De boel draait op mijn eigen Debian-server op Azure, Apache als reverse proxy, PM2 als process manager. GitHub Actions deployt bij elke push naar main.
De features die er echt toe doen
Aired-aware voortgang
Als een serie bezig is met een seizoen van 24 afleveringen maar er zijn er maar 12 uitgezonden, wil ik "12/12 gekeken" zien — niet "12/24". TMDB gooit namelijk alvast alle geplande afleveringen in de teller, waardoor een voortgangsbalk nooit 100% haalt. Binged trekt exacte uitzendtijden via TVmaze en past de noemer dynamisch aan. DST-bewust, per land.
Cross-seizoen backfill
Ben je bij seizoen 3 episode 5, maar vergeten seizoen 2 af te vinken? Binged vraagt of je alle eerdere afleveringen automatisch als gezien wil markeren. Over alle seizoenen. Één klik.
Co-watching
Mijn partner en ik kijken veel samen. Als zij een aflevering aanvinkt, synchroniseert dat naar mijn account. Begin je een serie samen via een uitnodiging, dan backfilt Binged de hele geschiedenis — ze hoeft niet handmatig bij te werken wat we al gezien hebben.
AI-aanbevelingen
Binged bouwt een smaakprofiel op uit je kijkgeschiedenis: genres, acteurs, decennia. Dat profiel gaat als prompt naar Claude, die aanbevelingen teruggeeft. Daarna worden die gevalideerd tegen TMDB voordat ze getoond worden. Claude verzint soms titels die niet bestaan — die validatiestap filtert ze eruit.
Er is ook een conversationele zoekbalk. Je typt "iets zoals Breaking Bad maar in Japan" en Claude verfijnt op basis van dat gesprek.
Hoe ik dit bouwde met Claude Code
Ik bouw in sessies. Een sessie begint met een concreet doel — "co-watching uitbreiden naar series, nu werkt het alleen voor films" — en eindigt met werkende code op productie. Soms een uur, soms een dag.
Elk feature begint als een PRD: een kort document met wat het moet doen, de edge cases, en hoe het in de bestaande architectuur past. Binged heeft er inmiddels zo'n tachtig. Gemaakt samen met Claude, gebruikt als specificatie tijdens de bouw, en later terug te lezen als je vergeten bent waarom iets zo werkt.
Claude Code schrijft het grootste deel van de code. Ik stuur bij, review, test handmatig en push. Na een paar maanden vibecoding is één ding duidelijk: de kwaliteit van de output hangt af van hoe precies je je intent beschrijft. "Voeg co-watching toe" werkt niet. "Maak het mogelijk dat twee gebruikers een serie linken, waarbij afleveringen die één van beiden markeert zichtbaar zijn voor de ander, met een uitnodigingsflow en de mogelijkheid om de koppeling te pauzeren" — dát werkt.
Het grootste risico is drift. Na twintig sessies vol nieuwe features begint een codebase zonder overzicht te worstelen. Ik houd dat bij met CLAUDE.md-bestanden per project: welke keuzes zijn gemaakt, waarom, wat Claude niet moet aanraken.
Wat ik leerde
De Claude API is goed in aanbevelingen genereren. Hij weet niet of een serie echt bestaat op TMDB. Die twee lagen scheiden — Claude genereert, TMDB valideert — is het verschil tussen een werkende feature en één die willekeurig kapot gaat.
Caching is architectuur, geen optimalisatie achteraf. TMDB-metadata zit in PostgreSQL met een TTL van zeven dagen, ververst via een cronjob. Die keuze vroeg in het project gemaakt. Als ik dat later had gedaan, had ik de helft van de codebase opnieuw moeten schrijven.
PRDs voelen als overhead. Ze zijn het niet. Claude kent je vorige sessies niet. Jij ook nauwelijks. Een document dat zegt "dit werkt zo en om deze reden" is het enige wat coherentie over tachtig sessies mogelijk maakt.
Self-hosting heeft consequenties. Deployen, migreren, logrotate instellen, cron-jobs bijhouden. Claude helpt daarmee, maar het kost tijd. Als je gewoon een app wil gebruiken: Trakt.tv. Als je wil begrijpen hoe een webapp werkt van database tot deploy: bouw het zelf.
Afsluiting
Binged is niet perfect. Er zijn bugs. Er zijn dingen die ik anders zou doen als ik opnieuw begon. Maar het draait, het wordt dagelijks gebruikt, en ik heb het gebouwd zonder fulltime developer te zijn.
Dat is vibecoding in de praktijk: niet code schrijven alsof je al tien jaar developer bent, maar met de juiste tools een idee omzetten in iets wat werkt.
Binged is live op binged.wallieweb.nl.