Ž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
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
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.
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
Frontend Framework → Astro SSG
Astro v SSG režimu s Vue komponentami hydratovanými jen tam, kde je třeba.
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
Event Sourcing → Marten na PostgreSQL
Framework Marten na PostgreSQL místo vlastní implementace na MongoDB.
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
Auth → Supabase Auth
Vestavěná autentizace Supabase místo vlastního řešení nebo externího poskytovatele.
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
Organizace kódu → Vertical Slices
Kód organizovaný podle funkcionality, ne podle technické vrstvy.
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í.
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í
Plán vývoje
6 verzí od statické stránky po pokročilé backendové funkce. Každá verze přidá vrstvu složitosti.
Jednoduchý web
~7 hodin · 27. 3. 2026
Jednoduchý web s doménou, hostingem a deployment pipeline.
Co se udělalo
-
Nastavení domény, DNS a hostingu na Cloudflare Pages -
Návrh stránek v Google Stitch, stavba s Astro + Tailwind
-
Deploy pipeline přes GitHub Actions
-
Světlý a tmavý režim s detekcí systémových preferencí
-
Přepínač jazyků (angličtina / čeština) s per-page překlady
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
-
Supabase projekt a Google OAuth setup -
Oracle Cloud VM, PostgreSQL, Caddy reverse proxy -
ASP.NET Core Web API s vertical slices a Marten event sourcingem
-
Supabase Auth s email/heslo + Google OAuth, propojení účtů a nahrávání avataru
-
Formulář nabídek s nahráváním souborů, uživatelský dashboard a admin pohled
-
Docker setup, CI/CD pipeline na Oracle Cloud s blue/green deploymentem
-
Integrační testy (Testcontainers) a E2E testy (Playwright)
-
SEO: sitemap, robots.txt, llms.txt, stylovaná 404 stránka
-
Optimalizace CI/CD pipeline -
Vylepšení run konfigurací pro DevX -
Několikrát restrukturalizace kódu -
Cloudflare Turnstile CAPTCHA na formuláři pracovních nabídek
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.
Ú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.
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.
Pay to Win (Stripe)
Monetizace podání pracovních nabídek přes Stripe s odstupňovanými cenami.
| Úroveň | Cena | Garance |
|---|---|---|
| Zdarma | $0 | Odpověď do 7 dnů |
| Premium | $5 | Odpověď do 24 hodin |
| Pohovor (30 min) | $25 | Hovor do 7 dnů |
| Pohovor (1 hodina) | $50 | Hovor do 7 dnů |
Poučení z projektu
Názory utvořené po stavbě a nasazení s těmito technologiemi.
Použití Supabase
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
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
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