OpenWealthLab OPENWEALTHLAB
SupportCoffee

2026-04-23

Build Log 001: Zero-Budget Stack – Architekturentscheidungen eines Hobby-Projekts Build Log 001: Zero-Budget Stack – Architecture Decisions for a Hobby Project

Das Problem mit Hobby-Projekten: Sie sterben an zu viel Ambition

Kurze Realitätscheck-Ansage: Das hier ist ein Hobby-Projekt.
Kein Startup. Kein Pitch-Deck. Kein „wir skalieren das auf 100k DAU“.

Das Ding entsteht zwischen:

  • zwei Kindern
  • einem Vollzeitjob
  • und dem Versuch, halbwegs regelmäßig ins Gym zu gehen

Heißt: Wenn ich es mir unnötig schwer mache, stirbt das Projekt. Punkt.

Deshalb Regel #1:
Kein Geld verbrennen, bevor irgendjemand überhaupt interessiert ist.

Klingt obvious. Ist es nicht.

Ich kenne das Spiel (auch aus eigener Erfahrung):
Man startet direkt mit AWS, Kubernetes, fancy Architektur – zahlt 40 € im Monat für Infrastruktur, die drei Requests am Tag sieht – und nach zwei Monaten ist die Motivation weg und das Abo gekündigt.

Dead on arrival.

Hier sind die Constraints, die ich mir selbst auferlegt habe:

  • Domain: < 10 €/Jahr
  • Hosting: kostenlos
  • Backend/API: kostenlos
  • Datenbank: kostenlos
  • Kosten bei Null-Traffic: 0 €

Domain: Namecheap, ~8 €, fertig, weiter geht’s

openwealthlab.com über Namecheap.
Unter 10 € im Jahr. Keine Spielchen, keine versteckten Gebühren.

Cloudflare DNS davor – kostenlos, schnell, funktioniert.
Mehr Gedanken habe ich da nicht reingesteckt. Muss auch nicht.


Frontend: Astro + Cloudflare Pages

Astro ist für genau so ein Projekt gemacht:
Static first, kein Framework-Zwang, aber React wenn man es braucht.

Die Inhalte?
Markdown im Repo. Fertig.

  • Build Logs
  • Dividend Logs
  • Experiments
  • Monthly Reports

Alles versioniert, alles portable, kein Vendor-Lock-in.

Deployment: Cloudflare Pages

  • kostenlos
  • globales CDN
  • direkt aus GitHub

Und ganz ehrlich: Für dieses Projekt gibt es keinen Grund, hier Geld auszugeben.


Backend: Cloudflare Pages Functions

Viele unterschätzen das:
Cloudflare Pages kann nicht nur statisch.

Pages Functions = Serverless direkt neben deinem Frontend.

  • eine Datei = eine API-Route
  • kein Express
  • kein Setup
  • kein Overhead

Das ist genau die Art von Infrastruktur, die ein Hobby-Projekt am Leben hält.

Free Tier: 100k Requests/Tag.
Ich werde sehr lange brauchen, um da hinzukommen.


Die nerdige Ecke: JWT-Signing ohne npm (weil… warum nicht)

Jetzt der Teil, der eigentlich unnötig kompliziert ist – und genau deshalb Spaß gemacht hat.

Problem:

  • API muss mit Google Cloud (Firestore) sprechen
  • Standardlösung: Firebase Admin SDK
  • Realität: mehrere MB groß und für klassische Server gedacht

Passt nicht zu V8-Isolates.

Also: selber bauen.

Mit der Web Crypto API:

const key = await crypto.subtle.importKey(
  "pkcs8",
  pemToArrayBuffer(sa.private_key),
  { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
  false,
  ["sign"]
);
const signature = await crypto.subtle.sign(
  "RSASSA-PKCS1-v1_5",
  key,
  textEncode(signingInput)
);

Ergebnis:

  • ~250 Zeilen Code
  • 0 Dependencies
  • kompletter OAuth2 JWT Flow
  • inkl. Token-Caching

Ist das nötig? Nein.
War es eine gute Entscheidung? Wahrscheinlich auch nein.
Macht es Spaß und passt zur Idee? Absolut.


Datenbank: Firestore (weil ich eh schon da bin)

Die Daten (Dividenden) liegen in Firestore.

Free Tier:

  • 1 GiB Storage
  • 50k Reads/Tag
  • 20k Writes/Tag

Für mein Setup: komplett überdimensioniert.

Warum Firestore? Ganz einfach: Ich arbeite täglich mit GCP.

  • BigQuery
  • Cloud Jobs
  • Infrastruktur

Account existiert, Credentials liegen rum, ich weiß wie es funktioniert.

Vendor-Bias? Ja.
Aber pragmatisch > ideologisch.


Der Dividenden-Report: Alles kommt zusammen

Hier passiert der eigentliche Use Case:

Trade Republic

openwealthlab-pipeline

Firestore

/api/dividends

Frontend

Pipeline:

  • Broker-Export rein
  • Daten anreichern (ISIN, Ticker, Steuern)
  • in Firestore schreiben

API:

  • GET /api/dividends?week=2026-W17
  • liefert Woche + Vergleichswerte + Deltas

Frontend:

  • Tabelle
  • Pie Chart
  • Bar Chart
  • zweisprachig

Und das Wichtigste:
Das sind echte Daten aus meinem echten Depot.

Kein Demo-Kram. Kein Fake.


Was noch kommt

Aktuell ist das alles Version 0.x.

Nächste Schritte:

  • Portfolio Logs (echte Transaktionen)
  • Performance Tracking
  • Tools, die ich selbst vermisse

Und ja – irgendwann vielleicht eine richtige App.

Alles öffentlich. Alles nachvollziehbar.
Weil „build in public“ kein Buzzword ist, sondern der einzige Weg, sowas langfristig durchzuziehen.

Code: openwealthlab-pipeline

The problem with hobby projects: they need to be allowed to exist

Fair warning before we drown in tech: this is a hobby project. Not one that’s raising Series A next month. Not one that needs to serve 100k DAU. It’s built by one person, in spare time, between two kids, a full-time job, and the occasional gym visit.

The first design principle was therefore non-negotiable: it must not burn money before anyone cares about it.

Sounds obvious. It’s not. The temptation to start with AWS, Kubernetes, and a managed Postgres instance is real — especially when you build scalable cloud infrastructure professionally. But I’ve seen this pattern too many times: you pay €40/month for a server that handles three requests a day, you lose motivation, and you cancel. Done it myself.

Here’s the constraint list I built against:

  • Domain: one-time, under €10/year
  • Hosting: free
  • Backend/API: free (free tier)
  • Database: free (free tier)
  • Running costs at zero traffic: €0

Domain: Namecheap, ~€8, done

openwealthlab.com via Namecheap. Under €10/year. No renegotiation, no hidden renewal fees, no drama. Cloudflare DNS in front — also free — for fast propagation and a few nice extras.


Frontend: Astro + Cloudflare Pages

The site runs on Astro. Static site generator, code-first, no JavaScript framework required by default, but React components where it makes sense. The blog system uses Astro Content Collections — all articles (Build Logs, Dividend Logs, Experiments, Monthly Reports) are plain Markdown files in the repo. Versioned, portable, no vendor lock-in.

Deployed on Cloudflare Pages: free, global CDN, build runs directly from the GitHub repo. What Vercel can do, Cloudflare can too — and the free tier is generous enough that no invoice is coming anytime soon.


Backend: Cloudflare Pages Functions

The thing many people don’t immediately think of: Cloudflare Pages has Pages Functions — serverless functions that run right alongside the static build. One function = one file in functions/api/. Routing is handled by Cloudflare automatically. No Express, no deployment overhead.

The free tier allows 100,000 requests/day. At current traffic levels, that covers what feels like forever.

The technically interesting corner: JWT signing without npm

Here’s the part that surprised me while building. Cloudflare Workers/Pages Functions run in a V8 isolate — no Node.js, no classic require(). You could bundle npm packages, but that adds complexity and size.

The API needs to authenticate against Google Cloud (Firestore). The standard approach would be the Firebase Admin SDK. Problem: it weighs several megabytes and is built for server environments, not V8 isolates.

The solution: Web Crypto API, natively available in every modern browser (and in Cloudflare Workers). The function signs the JWT itself — using crypto.subtle.sign() — without a single external dependency.

const key = await crypto.subtle.importKey(
  "pkcs8",
  pemToArrayBuffer(sa.private_key),
  { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
  false,
  ["sign"]
);
const signature = await crypto.subtle.sign(
  "RSASSA-PKCS1-v1_5",
  key,
  textEncode(signingInput)
);

The result: a ~250-line file, zero npm dependencies, implementing a complete OAuth2 JWT flow against Google Cloud. Including token caching so a new token isn’t fetched on every request.

Maybe overengineered for a hobby project. Maybe exactly right. Honest either way.


Database: Firestore (GCP free tier)

The data — specifically: dividend payments — lives in Firestore, Google’s document-oriented database. The free tier includes:

  • 1 GiB storage
  • 50,000 reads / day
  • 20,000 writes / day
  • 20,000 deletes / day

For the current data volume (a few hundred dividend entries), this is generously oversized. Even as the project grows, the estimate is: under €1/month, probably much less.

The choice fell on Firestore over SQL for pragmatic reasons: I’ve worked with Google Cloud professionally for years. BigQuery, Cloud Jobs, GCP infrastructure — that’s my day job. The account was there. The credentials were already set up. Vendor bias? Yes. Works anyway.


The dividend report: an end-to-end example

Everything described above converges in the weekly dividend report. Here’s the full data flow:

Trade Republic (brokerage)

openwealthlab-pipeline (Python, local / Cloud Job)

Firestore (collection: dividends)

/api/dividends (Cloudflare Pages Function)

DividendWeeklyReport (React component in browser)

What the pipeline does: Raw dividend data is extracted from the broker export, enriched (ISIN lookup, ticker normalization, tax calculation) and written as documents to Firestore. The pipeline is open source — it lives as openwealthlab-pipeline on GitHub under the MIT license.

What the API does: GET /api/dividends?week=2026-W17 returns dividends for the requested week — plus comparison data for the previous week and the same calendar week last year, including calculated deltas. Everything in one response so the frontend doesn’t need to make multiple requests.

What the frontend does: The React component renders the data as a table, pie chart (by stock), and bar chart (weekly comparison). Bilingual — DE/EN via localStorage. Live data, no rebuild required.

Every dividend report that appears on this site is a real event from my real portfolio. No demo dataset, no fabricated content.


What’s next

This is version 0.x of everything. Planned are more services following the same pattern: portfolio logs with real transaction data, performance tracking, and eventually the first step toward an app with features that other portfolio trackers are missing.

All of it public, traceable, and — where it makes sense — open source. Because “build in public” isn’t a marketing claim. It’s how this works.

The code for the dividend service: openwealthlab-pipeline

Comments