Van idee naar SaaS: een abonnemententracker voor ZZP'ers
OpenAI kondigde deze week aan dat ChatGPT direct toegang krijgt tot bankrekeningen om abonnementen en uitgaven bij te houden. Interessant nieuws, maar het geeft ook een mooi maker-signaal: er is duidelijk vraag naar inzicht in terugkerende kosten. En jij hoeft niet te wachten op OpenAI om iets nuttigs te bouwen.
Vandaag bouwen we een eigen, lichte versie: een abonnemententracker voor ZZP'ers. Geen bankrekening-koppeling (laten we realistisch zijn voor een MVP), maar wel een tool waar freelancers handmatig hun software-abonnementen bijhouden, maandelijkse totaalkosten zien, en een waarschuwing krijgen als een betaling eraan komt.
Dit is een ideale eerste SaaS: het probleem is universeel, de scope is overzichtelijk, en je kunt het uitbreiden naar een betaald product.
Het probleem en de doelgroep
Doelgroep: ZZP'ers en kleine ondernemers die tien tot twintig SaaS-tools gebruiken (Notion, Figma, Mailchimp, Slack, Adobe, noem maar op) en geen idee hebben wat ze maandelijks kwijt zijn.
Het echte pijnpunt: Eind van het kwartaal, je stuurt je boekhouding door, en dan schrik je: Figma is naar 60 euro per maand gegaan, Adobe staat op jaarlijks maar je weet niet wanneer het verlengt. Spreadsheets zijn te veel werk, een echte boekhouding-app is overdreven.
De oplossing: Een simpele webapp met:
- Lijst van abonnementen met naam, bedrag, frequentie (maandelijks/jaarlijks), en vervaldatum
- Maandelijks en jaarlijks totaaloverzicht
- Notificatie (of visuele markering) als een abonnement binnen 14 dagen verlengt
- Categorieën (marketing, design, productiviteit, etc.)
De bouw in 7 stappen met Claude Code
Stap 1: Zet de basis neer
Open Claude Code in een nieuwe map en begin met de projectstructuur. Gebruik deze prompt:
Maak een Next.js 14 app met App Router en Tailwind CSS voor een abonnemententracker voor ZZP'ers. De app heet "SubCheck". Initialiseer het project met
npx create-next-app@latest subcheck --typescript --tailwind --app. Daarna wil ik een Supabase-database koppelen voor de data. Maak alvast een README met wat de app doet.
Na het initialiseren:
Installeer de Supabase client:
npm install @supabase/supabase-js. Maak eenlib/supabase.tsbestand aan met de client-setup. Gebruik placeholders voor de SUPABASE_URL en SUPABASE_ANON_KEY die ik later via.env.localinvul.
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
Stap 2: Maak de database in Supabase
Ga naar supabase.com, maak een nieuw project aan, en gebruik dan deze prompt in Claude Code:
Genereer de SQL voor een Supabase-tabel genaamd
subscriptionsmet de volgende velden:
- id (uuid, primary key, auto-generated)
- user_id (text, voor later als we auth toevoegen)
- name (text, naam van het abonnement)
- amount (numeric, bedrag in euro's)
- frequency (text: 'monthly' of 'yearly')
- category (text: marketing, design, productiviteit, communicatie, overig)
- next_billing_date (date)
- notes (text, optioneel)
- created_at (timestamp, default now())
Geef ook de SQL voor Row Level Security uitgeschakeld zodat ik snel kan testen zonder auth.
Kopieer de gegenereerde SQL en voer het uit in de Supabase SQL editor.
Stap 3: Bouw het formulier om abonnementen toe te voegen
Maak een React component
components/AddSubscriptionForm.tsxmet een formulier om een nieuw abonnement toe te voegen. Velden: naam (text input), bedrag (number input met euro-teken), frequentie (select: maandelijks/jaarlijks), categorie (select met de vijf opties), volgende betaaldatum (date picker), notities (textarea, optioneel).Bij submit sla je het op in de Supabase
subscriptionstabel. Gebruik de supabase client uitlib/supabase.ts. Na succesvol opslaan leeg je het formulier en roep je eenonSuccesscallback aan. Styling met Tailwind, clean en modern.
Stap 4: Bouw het dashboard met overzicht
Dit is het hart van de app. Gebruik deze prompt:
Maak een
app/page.tsxdie als dashboard fungeert. Het haalt alle abonnementen op uit Supabase en toont:
Drie summary-kaarten bovenaan:
- Maandelijkse kosten (som van alle maandelijkse abonnementen + jaarlijkse gedeeld door 12, afgerond op 2 decimalen)
- Jaarlijkse kosten (totaal)
- Aantal actieve abonnementen
Een tabel met alle abonnementen gesorteerd op volgende betaaldatum. Kolommen: naam, categorie, bedrag, frequentie, volgende betaling.
Abonnementen die binnen 14 dagen verlopen krijgen een oranje badge "Verloopt binnenkort". Abonnementen die al verlopen zijn (datum in verleden) krijgen een rode badge.
Gebruik Tailwind voor styling. Voeg een knop toe om het AddSubscriptionForm te openen als een modal.
Stap 5: Voeg verwijderen en bewerken toe
Voeg aan elke rij in de abonnementenlijst twee knoppen toe: een potlood-icoon om te bewerken en een prullenbak-icoon om te verwijderen. Bij verwijderen toon je een bevestigingsmelding ("Weet je het zeker?"). Bij bewerken open je het AddSubscriptionForm in een modal, maar dan pre-gevuld met de bestaande data. Zorg dat de Supabase update-call (
update().eq('id', id)) correct werkt.
Stap 6: Categoriefilter en maandoverzicht
Voeg een filterbalk toe boven de abonnementenlijst waarmee je kunt filteren op categorie. Voeg daarnaast een tweede tab of sectie toe die een maandoverzicht toont: voor elke maand van het huidige jaar een kolom met de abonnementen die die maand verlopen of verlengen, inclusief het totaalbedrag per maand. Dit helpt ZZP'ers om cashflow te plannen.
Stap 7: Exporteer naar CSV
Voeg een "Exporteer naar CSV" knop toe die alle abonnementen downloadt als een CSV-bestand. De kolommen zijn: naam, categorie, bedrag, frequentie, volgende betaaldatum, jaarlijkse kosten (bedrag x 12 als maandelijks, anders bedrag). Dit is handig voor de boekhouder.
// Voorbeeld van de CSV-export logica die Claude Code genereert:
const exportToCSV = (subscriptions: Subscription[]) => {
const headers = ['Naam', 'Categorie', 'Bedrag', 'Frequentie', 'Volgende betaling', 'Jaarlijkse kosten']
const rows = subscriptions.map(s => [
s.name,
s.category,
s.amount,
s.frequency === 'monthly' ? 'Maandelijks' : 'Jaarlijks',
s.next_billing_date,
s.frequency === 'monthly' ? (s.amount * 12).toFixed(2) : s.amount
])
const csv = [headers, ...rows].map(r => r.join(',')).join('\n')
const blob = new Blob([csv], { type: 'text/csv' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'abonnementen.csv'
a.click()
}
Wat te checken na afloop
Voordat je dit deelt met de eerste testgebruiker, loop je deze lijst af:
- Kan ik een abonnement toevoegen en ziet het er correct uit in de tabel?
- Kloppen de maandelijkse en jaarlijkse totalen? (Test met een maandelijks abonnement van 10 euro en een jaarlijks van 120 euro - beide moeten 10 euro per maand tonen)
- Krijgt een abonnement dat morgen verloopt de oranje badge?
- Werkt de CSV-export en opent het bestand correct in Excel?
- Filtert de categorie-filter correct?
Als alles aangevinkt is, deploy je naar Vercel met:
npx vercel --prod
Vergeet niet je Supabase environment variables in te stellen in het Vercel dashboard onder Settings > Environment Variables.
Wat zou je daarna nog willen toevoegen?
Dit MVP is al bruikbaar, maar hier zijn de logische volgende stappen:
- Authenticatie via Supabase Auth, zodat meerdere gebruikers elk hun eigen abonnementen beheren
- Email notificaties via Resend of SendGrid: stuur een week voor verlenging een reminder
- Stripe-integratie voor een betaald abonnement op SubCheck zelf (meta, maar logisch)
- Automatische import van PDF's of bankafschriften via een AI-koppeling om abonnementen te herkennen
- Teamfunctie voor kleine bureaus die gezamenlijk tools beheren
De stap van gratis naar betaald is klein: voeg Stripe Checkout toe voor 5 euro per maand en je hebt je eerste SaaS-inkomsten.
Bij Eighty leer ik je Claude Code in het Nederlands gebruiken, van installatie tot een werkend SaaS-product. Wekelijks een nieuwe module, persoonlijke begeleiding.
