Přeskočit na obsah

Živě budovaná ukázka.

Tahle stránka je experiment, který se pořád vyvíjí. Slouží jako ukázka mých dovedností — každá iterace je zdokumentovaná, od prvních wireframů po pokročilé featury.

Rychlý přehled

Čas nasazení Sledovaný čas pouze pro prvotní nasazení. Výrazně více času bylo stráveno vylepšováním a iteracemi.
32 hodin
Viz roadmap pro rozpis.
Jednorázové náklady
3 €
Průběžné náklady
0 €/měsíc
Zdrojový kód
GitHub

Postaveno na

Frontend

  • Astro
  • Tailwind CSS
  • Supabase Auth
  • Cloudflare Pages

Backend

  • C# ASP.NET Core
  • PostgreSQL
  • Marten Event Sourcing

Infrastruktura

  • Oracle Cloud VPS
  • Supabase
  • GitHub Actions
    • Build + Test + Deploy
    • E2E testy (Playwright)

Cíle a požadavky

Osobní prezentace

Představit se potenciálním zaměstnavatelům a recruiterům.

Ukázka dovedností

Zdokumentovat proces stavby jako součást ukázky — architektura, rozhodnutí a pokrok.

Technologické hřiště

Experimentovat s novými technologiemi v reálném, nasazeném projektu.

  • Event sourcing
  • Cloudflare Pages zdarma
  • Ekosystém Supabase
  • Temporal

Nefunkční požadavky

Automatizace Minimální manuální režie. Infrastructure as code nebo GitHub Actions pro všechno.
Spolehlivost Web musí být spolehlivě dostupný.
Náklady Co nejlevněji — nejlépe zdarma. Backend hosting: Oracle Cloud Always Free (záloha: Hetzner VPS ~4 €/měsíc).

Přehled architektury

CLOUDFLARE DNS DNS / Doména Astro Statický web (CDN) ORACLE CLOUD VPS Caddy Reverzní proxy ASP.NET Core Backend API Blue/Green Temporal Úlohy na pozadí SUPABASE PostgreSQL Databáze Auth Autentizace (JWT) File Storage Avatary / Soubory CI / CD GitHub Actions Backend testy Frontend testy E2E testy BE deploy na VPS FE deploy na Cloudflare OBSERVABILITA Sentry PostHog NOTIFIKACE Slack Brevo Email (SMTP)

Architektonická rozhodnutí

Klíčová technická rozhodnutí zdokumentovaná jako Architecture Decision Records.

Backend Hosting → Oracle Cloud

Oracle Cloud Always Free ARM A1 instance, se zálohou na Hetzner VPS.

Context

Potřebujeme hosting, který podporuje dlouhodobě běžící procesy (ASP.NET Core + Temporal). Většina free tierů je serverless/scale-to-zero a při nečinnosti proces ukončí.

Decision

Začít s Oracle Cloud Always Free ARM A1 instancí (4 OCPU, 24 GB RAM, 200 GB úložiště). Pokud bude Oracle nespolehlivý, přejít na Hetzner VPS (~4 €/měsíc).

Why

  • Free tier se štědrými parametry (4 OCPU, 24 GB RAM, 200 GB úložiště)
  • Podporuje dlouhodobě běžící procesy a Docker
  • Upgrade na PAYG (stále zdarma) vypne recyklaci nečinných instancí

Known Risks

Risk Details Mitigation
Odmítnutí registrace Oracle odmítá mnoho registrací podle poptávky v regionu a platební metody Použít skutečnou kreditní kartu, odpovídající fakturační adresu, méně populární region
Kapacita ARM Populární regiony často nemají dostupnou A1 kapacitu Zvolit EU nebo méně populární region při registraci
Recyklace nečinných Instance s <20% CPU na P95 za 7 dní jsou zastaveny po 1 týdnu upozornění Reálné workloady zůstanou nad prahem; PAYG toto zcela vypne
Pozastavení účtu Vzácné hlášení o pozastavení účtů bez jasného důvodu Mít PAYG zapnutý; udržovat reálné využití

Setup Notes

  • Oracle Linux 8 aarch64 — Podman funguje rovnou po instalaci, optimalizovaný pro Oracle Cloud hardware
  • Nastavit velký boot volume (~150 GB) při vytvoření, aby se předešlo složitosti iSCSI block volume
  • Otevřít porty v OCI security list i v OS firewallu

Alternatives Considered

Hetzner VPS (~4 €/měsíc) — Spolehlivá záloha. Plná kontrola, předvídatelný. Přejdeme sem, pokud Oracle dělá problémy.
Azure App Service Free (F1) — 60 min CPU/den, žádný always-on — aplikace usíná při nečinnosti.
AWS Lambda / Google Cloud Run — Serverless — žádný trvalý background proces pro Temporal workery.
Render free tier — Vypíná se po 15 min nečinnosti. Background workery jsou jen placené.
Fly.io — Free tier se zhoršil; pravděpodobně to stojí pár dolarů.
Azure Container Apps — Free tier je štědrý, ale self-hosting Temporal by byl nepraktický.

Frontend Framework → Astro SSG

Astro v SSG režimu s Vue komponentami hydratovanými jen tam, kde je třeba.

Context

Potřebujeme frontend framework pro převážně statický web na Cloudflare Pages. Požadavky: Tailwind CSS, i18n (čeština/angličtina), progresivní interaktivita, minimum JS pro uživatele.

Decision

Astro ve statickém režimu (SSG). Interaktivní komponenty používají vanilla JS, s možností Vue islands pro složitější UI logiku. Žádné Cloudflare Workers — Pages servíruje čisté HTML/CSS/JS z CDN.

Why

  • Zdarma navždy — SSG na Cloudflare Pages nemá žádné náklady za request, na rozdíl od SSR s Workers, které se účtují za volání
  • Každá stránka je předgenerovaná a cachovaná na CDN edge nodech po celém světě — téměř okamžité načítání
  • Ve výchozím stavu posílá nula JS — jen interaktivní islands obsahují klientský kód
  • Vestavěný i18n routing a detekce locale
  • Cloudflare koupil Astro (leden 2026) — nejlepší integrace s Pages

Alternatives Considered

Vue/Nuxt (SSR) — Druhá nejlepší volba — hostováno ideálně jako Cloudflare Worker, případně jako Docker image na VPS. Ale SSG je jednodušší a zdarma, tak začínám s tím, dokud to stačí.
Vanilla ES6 moduly — Stále potřebuje Tailwind build krok. Museli bychom ručně stavět routing, i18n a komponentový systém.
React/Next.js — Posílá ~80-120 KB React runtime. JS-first přístup. Next.js je Vercel-aligned, ne Cloudflare.
SvelteKit — Dobrý framework, ale i18n stále není vestavěný. Více zaměřený na interaktivní aplikace.
Vercel hosting — SSR model spouští serverové funkce — fakticky druhý backend. Cíl je tenký statický klient s jedním ASP.NET Core backendem.

Event Sourcing → Marten na PostgreSQL

Framework Marten na PostgreSQL místo vlastní implementace na MongoDB.

Context

Event sourcing byl jasná volba — otázka byla, jestli ho stavět od nuly na MongoDB nebo použít zavedený framework. Tohle je první implementace event sourcingu, takže záleží na křivce učení a rychlosti.

Decision

Použít Marten na PostgreSQL — vyspělý .NET event sourcing framework běžící na stejné databázi, kterou už máme.

Why

  • Již zkušenosti s SQL, ale ne s MongoDB — rychlejší rozjezd
  • Žádná extra infrastruktura — využívá existující Supabase PostgreSQL, není potřeba provozovat MongoDB
  • Inline snapshot projekce udržují read modely bez extra kódu
  • Vyspělý framework s dobrou dokumentací — rychlejší na naučení než stavba od nuly
  • Chtěl jsem vyzkoušet ekosystém Supabase — to znamenalo PostgreSQL, a Marten do toho přirozeně zapadá

Alternatives Considered

Postavit sám na PostgreSQL — Jednodušší indexování a řízení souběžnosti než Marten. Ale vyžaduje ruční schema migrace při vývoji modelu — Marten ukládá eventy jako JSON a tomuto se vyhýbá.
Postavit sám na MongoDB — Globálně distribuovaná multi-master DB s free tierem na Azure Cosmos DB. Ale žádné zkušenosti s MongoDB transakcemi a řízením souběžnosti — příliš mnoho neznámých pro první implementaci event sourcingu.

Auth → Supabase Auth

Vestavěná autentizace Supabase místo vlastního řešení nebo externího poskytovatele.

Context

Aplikace musí fungovat jako OAuth provider — uživatelé se budou autentizovat přes OAuth při připojení přes MCP. Také potřebuje standardní email/heslo přihlášení.

Decision

Použít Supabase Auth — je součástí ekosystému Supabase, který už používáme pro databázi, podporuje OAuth ihned po instalaci a běží lokálně v Dockeru pro vývoj.

Why

  • Již používáme Supabase pro databázi — auth je součástí, žádná extra služba
  • Podporuje fungování jako OAuth provider — potřebné pro MCP, kde se uživatelé autentizují vůči aplikaci přes OAuth
  • Běží lokálně v Dockeru — kompletní auth flow funguje offline bez externích závislostí

Alternatives Considered

Vlastní implementace auth — Plná kontrola, ale stavba OAuth flow, správy tokenů a zabezpečení od nuly je složitá a náchylná k chybám.
WorkOS / Clerk / Auth0 — Vyspělí poskytovatelé auth, ale přidávají další externí závislost a náklady. Některé neběží lokálně. Supabase auth je už součástí — není důvod přidávat další službu.

Organizace kódu → Vertical Slices

Kód organizovaný podle funkcionality, ne podle technické vrstvy.

Context

Potřebujeme strategii organizace backend kódu, která drží související kód pohromadě a zabraňuje problému "změna jedné featury, úprava pěti vrstev".

Decision

Kód je organizovaný podle featury (např. Features/JobOffers/) místo podle technické vrstvy. Každá feature složka obsahuje svůj controller, eventy, DTO a handlery.

Why

  • Přidání nové featury = přidání nové složky se všemi soubory, žádné změny sdílených vrstev
  • Každá featura je samostatná — snadno pochopitelná, reviewovatelná a testovatelná izolovaně
  • Předchází typickému problému vrstvené architektury, kde jedna změna zasáhne Controllers/, Services/, Models/, DTOs/ atd.

Testovací strategie

Mockovat co nejméně. Reálná databáze všude, full-stack E2E s fungující autentizací.

Context

Potřebujeme testovací přístup, který poskytuje vysokou jistotu s minimem mockování a pokrývá celý stack od API endpointů po databázi.

Decision

Tři vrstvy testování, všechny běží paralelně v CI/CD. Každá blokuje deployment při selhání.

Why

  • Backend integrační testy (hlavní zaměření): xUnit + Testcontainers — reálný PostgreSQL, celé API přes WebApplicationFactory. Mockovat co nejméně (auth je mockovaný, externí služby jako Slack/email budou mockované), ale databáze je reálná, takže většinu funkcionality lze snadno ověřit
  • Backend unit testy: pro doménovou logiku a čisté funkce, kde by integrační testy byly zbytečně složité
  • Frontend page testy: Playwright — builduje statický web, ověřuje renderování, navigaci, i18n a dark mode
  • E2E testy: Playwright proti celé běžící aplikaci — fungující auth, fungující DB, vše reálné. Pouze externí systémy jako Slack a email nelze ověřit
  • CI/CD: Všechny tři testovací sady běží paralelně, všechny blokují deployment při selhání
Časová osa

Plán vývoje

6 verzí od statické stránky po pokročilé backendové funkce. Každá verze přidá vrstvu složitosti.

Version 1

Jednoduchý web

~7 hodin · 27. 3. 2026

Jednoduchý web s doménou, hostingem a deployment pipeline.

Co se udělalo
  • Pavel Nastavení domény, DNS a hostingu na Cloudflare Pages
  • Claude Návrh stránek v Google Stitch, stavba s Astro + Tailwind
  • Claude Deploy pipeline přes GitHub Actions
  • Claude Světlý a tmavý režim s detekcí systémových preferencí
  • Claude Přepínač jazyků (angličtina / čeština) s per-page překlady
Version 2

Backend Included

~25 hodin · 28. 3. – 1. 4. 2026

Příště bych to zvládl za ~10 hodin.

Sledovaný čas pokrývá pouze základní implementaci. Vylepšování a iterace zaberou výrazně víc.

ASP.NET Core backend se Supabase Auth a Marten event sourcingem. Slouží ke správě pracovních nabídek — uživatelé mohou podávat a sledovat nabídky, admini je přezkoumávat a měnit stavy.

Co se udělalo
  • Pavel Supabase projekt a Google OAuth setup
  • Pavel Oracle Cloud VM, PostgreSQL, Caddy reverse proxy
  • Claude ASP.NET Core Web API s vertical slices a Marten event sourcingem
  • Claude Supabase Auth s email/heslo + Google OAuth, propojení účtů a nahrávání avataru
  • Claude Formulář nabídek s nahráváním souborů, uživatelský dashboard a admin pohled
  • Claude Docker setup, CI/CD pipeline na Oracle Cloud s blue/green deploymentem
  • Claude Integrační testy (Testcontainers) a E2E testy (Playwright)
  • Claude SEO: sitemap, robots.txt, llms.txt, stylovaná 404 stránka
  • Pavel Optimalizace CI/CD pipeline
  • Pavel Vylepšení run konfigurací pro DevX
  • Pavel Několikrát restrukturalizace kódu
  • Claude Cloudflare Turnstile CAPTCHA na formuláři pracovních nabídek
Version 3

Emaily, Slack a observabilita

Emailová potvrzení a Slack notifikace při podání pracovních nabídek a změnách stavu. Kompletní observability stack: Sentry pro chyby, traces a logy, PostHog pro produktovou analytiku.

Version 4

Úlohy na pozadí

Přesun emailů a notifikací do zpracování na pozadí. Self-hosted Temporal na backend VPS s retry sémantikou. Záloha: Azure Queue Storage.

Version 5

MCP Server

Zpřístupnění správy pracovních nabídek přes Model Context Protocol server. Uživatelé mohou podávat, sledovat a spravovat své nabídky přes jakéhokoliv MCP-kompatibilního klienta.

Version 6

Pay to Win (Stripe)

Monetizace podání pracovních nabídek přes Stripe s odstupňovanými cenami.

Úroveň Cena Garance
Zdarma$0Odpověď do 7 dnů
Premium$5Odpověď do 24 hodin
Pohovor (30 min)$25Hovor do 7 dnů
Pohovor (1 hodina)$50Hovor do 7 dnů

Poučení z projektu

Názory utvořené po stavbě a nasazení s těmito technologiemi.

Použití Supabase

Verdict

Asi bych to udělal znovu pro jednoduchost nastavení u osobních projektů. Ne u komerčních projektů se skutečným rozpočtem.

Observations

  • PostgreSQL zdarma je super a samo o sobě stojí za to
  • Auth má některé hrubé hrany — např. problémy s email providerem ( viz diskuze )
  • File storage je levný všude — S3 nebo Azure Blobs jsou stejně levné a věřil bych jim víc než Supabase Storage
  • Použití Supabase zpomaluje dev CLI oproti prostému PostgreSQL Docker image
  • Není žádný skutečný tlak používat přibalený file storage a auth — ale připadáte si hloupě, když to nepoužijete, když už to tam je

Použití Event Sourcingu / Marten

Verdict

Příště bych asi napsal něco vlastního místo použití Martenu tak jak je.

Observations

  • Nepsal bych 100% čistý event sourcing — místo toho by každý update také uložil záznam o změně obsahující předchozí hodnoty
  • Ukládání předchozích hodnot jde proti filozofii ES, ale umožňuje stránkování záznamů historie — což je praktičtější
  • Pro projekce bych použil standardní SQL úložiště místo JSONu — to také umožňuje jemnější řízení souběžnosti. Marten nabízí jen dva extrémy: připojit vše bez kontrol, nebo spadnout pokud se cokoliv změnilo. Žádná střední cesta
  • Eventy by se ukládaly ve stejné transakci do jiné tabulky, pak přesouvaly do levnějšího úložiště (např. Azure Table Storage) přes outbox pattern, až by velikost SQL začala vadit

Astro SSG

Verdict

Příště bych asi zvolil SSR framework.

Observations

  • Už teď byly místa, kde by pomohl router — např. sdílený header, footer a auth status napříč stránkami
  • SSG je jednodušší pro nastavení deploye, ale v reálných podmínkách prostě zaplatíte za infrastrukturu a neřešíte to

Sledujte, jak to roste.

Toto je veřejný technický deník. Sledujte repozitář a podívejte se na commity, ze kterých vznikla tato stránka.

Zobrazit zdrojový kód

Přihlásit se

Nemáte účet?

nebo