vyvoj-dash

Tasky

159 tasků

Kanban board se všemi tasky napříč projekty.

Priorita:
Run: n nový 1-5 přesun
Backlog
0
Prázdné
To Do
0
Prázdné
In Progress
0
Prázdné
Hotovo
159
Auth middleware

Nový src/middleware.ts s defineMiddleware — parse session cookie, lookup přes Session service, populate Astro.locals.user + locals.session. SessionExpired catchTag → silent Option.none (uživatel se chová jako anonymní). DbError i ConfigMissing v middleware se logují a fallthrough na null locals (nezhroutí stránku).

Střední
Oskar
Protected /account stránka

Nová stránka src/pages/account.astro — prerender=false, čte Astro.locals.user, redirect na /login pokud null. Per-page guard místo middleware-driven redirect (žádný hidden seznam protected rout).

Střední
Oskar
Sprint 001 audit

pnpm tsc --noEmit a pnpm astro check oba běží clean. Jeden typecheck error po prvním write (passwordHash je nullable v schema, login musí na null branch vrátit no_password) opraven přidáním passwordHash null guardu v login.ts před verify.

Střední
Oskar
Login endpoint

Nový endpoint src/pages/api/auth/login.ts — POST form/JSON, findByEmail → verify PBKDF2 → vytvoří session a vrátí cookie. UserNotFound i wrong_password se klientovi vrací jako jeden tag invalid_credentials, aby chyba neodhalila existenci účtu. Login schema (src/auth/schemas/login.ts) vyžaduje jen přítomnost hesla, ne min 8, kvůli legacy slabým heslům.

Střední
Oskar
Login form stránka

Nová stránka src/pages/login.astro mirroring signup form — prerender=false, error banner z URL query (invalid_credentials/validation/internal), link na signup. Czech labels.

Střední
Oskar
Logout endpoint

Nový endpoint src/pages/api/auth/logout.ts — idempotent (vždy 303 → /), revoke session když cookie existuje, clear-cookie header. Žádný 404 při chybějící cookie aby logout fungoval i po expiraci.

Střední
Oskar
Zapojení env vars do session cookie + dev/prod Secure flag

Cookie attributes (HttpOnly/Secure/SameSite) byly hardcoded a env vars (SESSION_COOKIE_NAME, SESSION_TTL_DAYS) viseli nezapojené. Vznikl nový auth/config.ts který přes Effect.gen čte env a vrátí CookieConfig (name, maxAge, secure z import.meta.env.PROD); pokud chybí cookie name, fail s ConfigMissing. Session cookie serialize/clear přijímá secure: boolean — dev běh bez HTTPS funguje.

Střední
Oskar
Typecheck a uzavření runu

Typecheck pnpm tsc --noEmit a pnpm astro check oba 0 errors / 0 warnings. Hlavní typing landmine: TS 5.9 Uint8Array default ArrayBufferLike nesedí na BufferSource — explicit cast.

Střední
Oskar
Propojení Password + User do runtime

Layer.mergeAll(Session+User+Password) přes DbLive. runAuthToResponse přidán optional onFailure handler — umožní per-endpoint content negotiation (form redirect vs JSON).

Střední
Oskar
Signup POST endpoint

POST /api/auth/signup — handluje JSON i form. Browser: cookie + 303 redirect na /account, error 303 na /signup?error=&email=. JSON klient: 201 nebo errored JSON.

Střední
Oskar
Signup form stránka

Pure Astro form bez Svelte/JS hydration. prerender=false (čte query). Error banner s czech texty mapuje tag z URL.

Střední
Oskar
Password service s PBKDF2 hash/verify

PBKDF2 přes WebCrypto SubtleCrypto — 600k iter SHA-256, 16B salt, format pbkdf2$<iter>$<salt-b64>$<hash-b64>. Constant-time compare ve verify, žádný WASM payload.

Střední
Oskar
Schema validace pro signup

Effect Schema validace pro signup body (email pattern, password 8-200, name optional). decodeUnknownEffect → ValidationError s message z SchemaError.

Střední
Oskar
User service s create/find

User service nad Db: create/findByEmail/findById. UNIQUE constraint violation detekuji přes substring v error.message a remapuji DbError → UserAlreadyExists (409 místo 500). Email lowercase normalize.

Střední
Oskar
Session service

Login flow potrebuje session management. Session service (zavislost na Db) expose create/findByCookie/revoke/revokeAllForUser. Session ID = 32B random bytes base64url, default TTL 30 dni, findByCookie kontroluje expiry + maze expired session + touchuje lastUsedAt. K tomu cookie helpers (serialize/clear/parse) pro Run 01-03.

Střední
Oskar
Astro runtime adapter pro Effect

Astro endpointy potrebovaly entrypoint do Effect. Runtime.ts ma module-level ManagedRuntime (cached per Worker isolate) co builds Layer z DbLive + SessionLive + provideD1(env.DB) z cloudflare:workers. Export runAuth() a runAuthToResponse() (druha mapuje AuthError tagy na 400/401/409/500 Response).

Střední
Oskar
Typy a smoke test

Astro middleware potrebuje typed locals. env.d.ts deklaruje App.Locals.user a App.Locals.session jako nullable. Smoke endpoint /api/smoke overuje runtime+D1 connect (vraci pocet useru), v dev serveru vratil {ok:true,users:0}, pred commitem smazan.

Střední
Oskar
Instalace Effect 4 beta + Drizzle a konfigurace wrangleru

Projekt nemel auth deps ani D1. Pridany effect@4.0.0-beta.67, drizzle-orm, drizzle-kit; vytvorena D1 databaze oskar-db s bindingem DB v wrangler.jsonc; pridany scripty db:generate, db:migrate:local/remote.

Střední
Oskar
Drizzle schema pro auth (users, sessions, oauth_accounts, password_resets)

Auth potreboval persistent storage. Drizzle schema definuje 4 tabulky (users, sessions, oauth_accounts s composite PK, password_resets) vcetne FK cascade a indexu. Tabulky pro Sprint 002 jsou pridane preventivne aby nebyla druha migrace. Migrace aplikovana lokalne.

Střední
Oskar
AuthError ADT

Auth flow potreboval typove vsechny failure mody. AuthError ADT v errors.ts pres Data.TaggedError pokryva 9 tagu (UserAlreadyExists, UserNotFound, InvalidCredentials, SessionNotFound/Expired, DbError, ValidationError, ConfigMissing, TokenInvalid). Runtime adapter pres ne exhaustive switchuje na HTTP statusy.

Střední
Oskar
Db service nad D1

Effect services potrebovaly D1 abstrakci. Db service (Context.Service v Effect 4) drzi drizzle handle + raw D1Database a expose run(operation, fn) helper co maps Promise na Effect s DbError. D1Binding je separatni service co se providuje z env.DB v runtime adapteru.

Střední
Oskar
Nastavit BUILD_ACCESS_TOKEN secret

Nastavení zablokováno: CF API 10053 binding conflict (živý worker měl BUILD_ACCESS_TOKEN jako var). Fix: nejdřív deploy (odstraní var binding), pak wrangler secret put BUILD_ACCESS_TOKEN. Zdokumentováno v access-setup.md.

Střední
Privatní Git server
Dokumentace CI/CD secrets v access-setup.md

access-setup.md: přidána tabulka vars vs secrets (BUILD_ACCESS_CLIENT_ID public var, BUILD_ACCESS_TOKEN/CF_API_TOKEN/WEBHOOK_URL secrets), pořadí setup (deploy first → secret put), per-owner CF token flow přes dočasný AUTH_ADMIN_TOKEN.

Střední
Privatní Git server
BUILD_ACCESS_CLIENT_ID a WEBHOOK_URL do wrangler.jsonc

BUILD_ACCESS_CLIENT_ID (public client_id service tokenu) přidán do vars — hodnota je v kódu, není secret. WEBHOOK_URL přidán s default prázdný string. BUILD_ACCESS_TOKEN přesunut z vars do secrets-only (wrangler vars a secret nemůžou mít stejné jméno).

Střední
Privatní Git server
Nový notifyWebhook helper

Nový helper src/common/notifyWebhook.ts: POST JSON payload na URL, swallows all errors, canceluje response body (aby nezůstala otevřená CF Workers connection). Exportován z common/index.ts.

Střední
Privatní Git server
buildRunner volá webhook po každém buildu

buildRunner.ts po recordAndAck zkontroluje env.WEBHOOK_URL — pokud nastaven, zavolá notifyWebhook s payload { repoId, buildId, status, commitSha }. Empty string je falsy, takže nenastaven = skip.

Střední
Privatní Git server
cf-typegen + typecheck

cf-typegen přegeneroval worker-configuration.d.ts s novými vars (BUILD_ACCESS_CLIENT_ID, WEBHOOK_URL). BUILD_ACCESS_TOKEN přidán do env-augment.d.ts jako ambient type. Typecheck prošel čistě.

Střední
Privatní Git server
Oprava clone auth (CF-Access extraheaders)

Git clone v containeru posílal HTTP basic auth, ale git.vyvoj.dev je za CF Access (vyžaduje Client-Id + Client-Secret headers). Přepnuto na git -c http.extraheader syntax — oba headers předány jako env var přes setEnvVars.

Střední
Privatní Git server
Research CF R2 backup a replikační možnosti

R2 nemá nativní cross-account replikaci. Zdokumentovány tři varianty: rclone (cross-account), Scheduled Worker (same-account), Super Slurper (jednorázový export).

Střední
Privatní Git server
run-013-r2-backup.md a dokumentace backup strategie

run-013-r2-backup.done.md s design doporučením a poznámkou o bucket.list() paginaci (max 1000 objektů/call) přidáno do sprint dokumentace.

Střední
Privatní Git server
Sprint 005 adresář a dokumentace

Sprint 005 adresář chyběl — vytvořen, sprint.md a run-012 soubory zapsány ve stejném formátu jako Sprint 004.

Střední
Privatní Git server
Research Cloudflare Observability a Logpush

Workers Observability auto-zachycuje HTTP metadata (IP, Ray, path, status) — 7 dní retence. Pro delší retenci doporučen Logpush → R2, zdokumentováno v sprint.md.

Střední
Privatní Git server
Audit logging do git.ts

git.ts nemělo žádný logging. Přidány tři audit eventy (git:service-advertise, git:fetch-start, git:push-start/auth-failed) s owner/repoId/IP kontextem.

Střední
Privatní Git server
Logpush doporučení v sprint dokumentaci

Logpush doporučení přidáno do sprint.md s porovnáním variant (Workers Observability vs Logpush → R2 vs externí) a konkrétními wrangler příkazy.

Střední
Privatní Git server
i18n pro builds

BuildsCard potřeboval překlady pro 8 stavů buildu a 4 sloupce tabulky. Přidáno 18 klíčů admin.builds.* + help.step6_title do dict.cs.ts.

Střední
Privatní Git server
HelpPage sekce automatický deploy

Uživatel nevěděl, že server umí auto-deploy. Přidán Step 6 'Automatický deploy workerů' v /napoveda — vysvětluje detekci, frontu, kontejner a kde najít výsledek. e2e-notes.md dokumentuje postup pro manuální ověření.

Střední
Privatní Git server
Sprint audit a access-setup docs

Sprint 004 neměl zdokumentovanou CI/CD architekturu. Přidána sekce do access-setup.md (architektura push→deploy, potřebné secrets, diagnostika, limity). Sprint audit: 5/6 DoD splněno, E2E deferred.

Střední
Privatní Git server
Builds karta v admin UI

Admin UI nemělo viditelnost buildů. Přidán BuildsCard.tsx s tabulkou buildů, expandovatelným log tailem a status badges (zelená/červená). Data přicházejí ze server-side fetchnutého getBuildHistory() RPC v adminPage.ts.

Střední
Privatní Git server
redactSecrets helper a AVA test

Secrets v build logu by prosakly do DO storage. Přidán redactSecrets.ts s regex chainem (Bearer/JWT/hex/base64/KEY=) a truncateLog pro UTF-8 safe ořez. AVA test pokrývá 10 vzorů.

Střední
Privatní Git server
BuildRecord typ a RepoDO RPCs pro záznamy buildů

RepoDO neměl kde ukládat výsledky buildů. Přidán BuildRecord typ (stav, log tail, version_id) do repoState.ts a recordBuild/getBuildHistory RPC do repoDO.ts — ring buffer 50 záznamů per repo.

Střední
Privatní Git server
Build runner consumer — skutečná implementace

handleBuildMessage byl no-op (log + ack). Nahrazen skutečným buildRunner.ts: getSandbox → setEnvVars → git clone přes credential helper → checkout → npm ci → build → wrangler deploy → recordBuild do DO. destroy() vždy v finally.

Střední
Privatní Git server
Vitest worker test pro build pipeline

Build runner potřeboval worker-context test bez module-level mockování. Řešení: sandboxFactory parametr s default getSandbox, testy injektují mock. Pokrývá happy path (success + version_id parsing) + clone fail + deploy fail.

Střední
Privatní Git server
Produkční Dockerfile

Dockerfile byl jen v docs/sprints/004-ci-cd/Dockerfile.spike (proof-of-concept), produkce ho neměla. Promotnul jsem ho do rootu jako Dockerfile, wrangler pinnutý na 4.37.1 (= devDep verze v package.json) aby kontejner a dev tooling mluvily stejným CLI. Base image cloudflare/sandbox:0.7.0 + git + ca-certificates + smoke check.

Střední
Privatní Git server
AUTH_DO cfTokens schema + RPC + admin endpoint

AUTH_DO neměl kde držet CF API tokeny per owner — build runner potřebuje předat reálný token wrangler deploy v containeru. Přidal jsem typed key cfTokens do AuthStateSchema + RPC getCfToken/setCfToken (plaintext, nehashujem — token jde do CLI, ne pro verifikaci). HTTP endpoint POST /auth/api/cf-token v auth.ts (Bearer admin gate, ne admin.ts — ten má per-owner Basic auth = nesprávný gate pro system secret). UI pro ownery je až Sprint 005.

Střední
Privatní Git server
Wrangler bindings pro Sandbox container

Wrangler.jsonc neměl Sandbox container ani DO binding — runtime tedy neuměl spustit sandbox.exec(). Přidal jsem containers[] (lite, max_instances 1 per architecture §2 R3 serial build), Sandbox DO binding, migrations v3 new_sqlite_classes [Sandbox] (Sandbox SDK vyžaduje SQLite-backed DOs). BUILD_ACCESS_TOKEN secret zůstává mimo JSON — manuálně přes wrangler secret put.

Střední
Privatní Git server
Sandbox SDK install + re-export

Sandbox SDK nebyl v projektu — bez něj nešlo importovat Sandbox class ani postavit container binding. Nainstaloval jsem @cloudflare/sandbox@0.7.0 (verze sladěná se Sandbox Docker image) a re-exportuju Sandbox class z src/index.ts; Workers runtime ji potřebuje vidět na worker entry, jinak DO binding nezaregistruje.

Střední
Privatní Git server
Vitest worker test pro enqueue logiku

Producer logika potřebovala test coverage před plug-in build runneru v Run 010. Vitest worker test seedne pack-first repo s definovanou root tree a verifikuje 3 scénáře: worker repo enqueue / no-config skip / re-push HEAD-unchanged. Vše pass.

Střední
Privatní Git server
Korekce architecture.md (AUTH_DO storage shape)

Run zadání předpokládalo že AUTH_DO je Drizzle SQLite, ve skutečnosti je to typed KV storage (asTypedStorage). Architecture.md D4 + D5 + Decision summary opraveny, cf_api_token storage přesunut do Run 010 kde ho build-runner skutečně konzumuje. Také D5 implementace upravena z DO RPC na Worker-side helper, aby se neporušilo single-hop boundary.

Střední
Privatní Git server
RepoDO markBuildHead RPC

Bez transakčního trackingu by enqueue na feature-branch push nebo re-push téhož commitu vždy zařadil duplicitní build job. Přidán RPC markBuildHead na RepoDO + lastBuildHead key ve schema, single-threaded DO storage dělá read-then-write transakci natural — žádný blockConcurrencyWhile potřeba.

Střední
Privatní Git server
Worker-side detekce wrangler config

Detekce musela běžet Worker-side (ne v DO), jinak by Worker → DO → R2 porušila single-hop pravidlo z AGENTS.md. Nová detectWorkerProject v src/maintenance/buildDetect.ts čte HEAD commit a root tree přes existing readCommit/readTree, vrací tagged result (shouldBuild + configType jsonc/toml).

Střední
Privatní Git server
Build queue producer a wire-up

Producer-side build pipeline chyběla celá: nový buildEnqueue.ts s 3-step guard chain (HEAD → markBuildHead → detect → BUILD_QUEUE.send), dispatcher rozšířen v queue.ts o build kind, wire-up v routes/git.ts po addRepoToOwner s vlastním try/catch, BUILD_QUEUE binding v wrangler.jsonc.

Střední
Privatní Git server
Testy pro nové edge cases

Nový test v package.spec ověřuje že non-JSON upstream odpověď produkuje 502 s error.contains('malformed').

Střední
/home/github/Repoflare
Ošetření chyby JSON.parse v metadata fallbacku

Pokud npmjs.org vrátí 200 ale non-JSON tělo (HTML chybová stránka při výpadku), worker padal na náhodné 500. Teď try/catch okolo JSON.parse vrací strukturované 502 Bad Gateway.

Střední
/home/github/Repoflare
Ošetření chyb při zápisu tarballu do R2 cache

Zápis tarballu do R2 cache (ctx.waitUntil) mohl selhat tiše s unhandled rejection. Přidán .catch s logováním package+key, klient dostane stream bez ohledu na cache.

Střední
/home/github/Repoflare
Logika mazání starých fallback tarballů z R2

Fallback tarbally se v R2 hromadily bez TTL — pro popular balíčky to mohlo růst do GB ročně. Daily scheduled volá funkci, která projde R2 list s customMetadata, filtruje source=fallback + uploaded > 90 dní a batch maže.

Střední
/home/github/Repoflare
Cron trigger v Wrangler config

wrangler.jsonc triggers.crons '0 3 * * *' — denně ve 3:00 UTC. Cron registrace ověřena přes CF API workers/scripts/.../schedules.

Střední
/home/github/Repoflare
Test scheduled handleru

Vitest 3 testy: recent fallback survive, own packages never deleted, no side effects. Backdate uploaded netestováno (R2 binding read-only), jen invariants pro in-TTL chování.

Střední
/home/github/Repoflare
Custom worker entry s scheduled handlerem

Astro 6 adapter generoval jen fetch handler, scheduled cron nešel jednoduše přidat. Vytvořen custom worker entry kombinující Astro handle (přes @astrojs/cloudflare/handler) a scheduled handler.

Střední
/home/github/Repoflare
Dockerfile prototype pro build container

Produkční build container chybí specifikaci. Vytvořen Dockerfile.spike extending cloudflare/sandbox:0.7.0 s git + wrangler@3 + smoke step; komentář o cílové image size ~600 MB jako vstup pro Run 010 produkční Dockerfile.

Střední
Privatní Git server
Standalone spike worker s POST /spike-build endpoint

Feasibility Sandbox SDK ve workeru nebyla nikdy ověřena. Vytvořen standalone worker v docs/sprints/004-ci-cd/spike/ (4 soubory, mimo hlavní package.json) s POST /spike-build endpointem volajícím sandbox.exec. Spuštění blokované absencí Dockeru v dev env — acceptance pro Run 010.

Střední
Privatní Git server
Sandbox SDK průzkum přes context7 docs

Sandbox SDK je v cloudflare:sandbox-sdk skillu i context7 docs. Tři queries (exec+filesystem, lifecycle, wrangler containers binding) → potvrzeno: sandbox.exec vrací {stdout,stderr,exitCode,success}, getSandbox podporuje sleepAfter/keepAlive, containers binding v wrangler.jsonc je zaužívaný shape.

Střední
Privatní Git server
Architecture dokument s 5 rozhodnutími

Bez explicitních rozhodnutí by Run 009-011 psaly hypotézy. Vytvořen kanonický doc s Mermaid push→deploy flow, pěti rozhodnutími (delivery, lifecycle, timeout, secrets, detekce), 9-řádkovou failure modes tabulkou a decision summary jako vstupem pro Run 009.

Střední
Privatní Git server
Test non-scoped balíčku přes plný proxy

Run 012 nepokrýval success path proxy stahování. Test ověří round-trip: metadata fetch z fallbacku má dist.tarball přepsaný na vlastní host, druhý request tarball stream vrátí mock body byte-by-byte.

Střední
/home/github/Repoflare
Test scoped balíčku přes plný proxy

Scoped balíčky byly bug-prone (regex transformace + scope strip). Test ověří úplný řetězec: URL-encoded /@types%2Fnode metadata → rewrite na double-scope, navazující tarball download projde 5-seg scoped route a strip-scope upstream fetch.

Střední
/home/github/Repoflare
Test cache hit při druhém stažení

Po prvním cache miss by druhý fetch měl jít z R2 bez upstream callu. Test pre-populuje BUCKET (eliminuje waitUntil timing flakiness) a ověří, že read s cache-hit metadatami vrátí body bez jakéhokoli mocku k upstream.

Střední
/home/github/Repoflare
Hono router pro fallback tarball

Service změnila kontrakt z R2ObjectBody na ReadableStream — router teď wrapuje do Response s Content-Type: application/gzip a předává c.executionCtx pro async cache write.

Střední
/home/github/Repoflare
Přepis URL tarballů v metadata fallbacku

Fallback metadata vracela URL na npmjs.org — v plném proxy režimu klient pak chodil mimo Repoflare. Teď JSON.parse + per-version dist.tarball rewrite na vlastní host; scoped balíčky se transformují na Repoflare double-scope formát, aby matchly existující 5-segment scoped route.

Střední
/home/github/Repoflare
Návod dual-mode (scope-first + full-proxy)

Návod byl psaný jen pro plný proxy režim, scope-first nebyl vysvětlen. Sekce 2 přepsána na scope-first jako doporučené, sekce 5 přejmenována na 'Plný proxy režim' pro lockdown setupy s anchor odkazem mezi nimi.

Střední
/home/github/Repoflare
Stream proxy a R2 cache pro tarbally

Tarbally veřejných balíčků se stahovaly přímo z npmjs.org → v lockdown sítích nešly a R2 cache se neplnila. Service teď na R2 miss fetchne upstream, tee() split stream do cache i klientovi, ctx.waitUntil schová R2 put na pozadí.

Střední
/home/github/Repoflare
Sjednocení textů u prázdných seznamů

Texty u prázdných seznamů byly nekonzistentní ('Žádné tokeny.' vs jiné varianty). Sjednoceno na vzor 'Zatím tu nejsou žádné X.' u tokenů i balíčků.

Střední
/home/github/Repoflare
Vlastní 404 stránka

Astro default 404 vrací plain text. Přidána vlastní stránka 404.astro s BaseLayout, headerem a CTA tlačítky na úvod a dashboard.

Střední
/home/github/Repoflare
Ošetření chyby kopírování do schránky

Při zamítnutí oprávnění na clipboard padalo unhandled promise. Tlačítka pro kopírování teď mají tristate (idle/copied/failed) s 2s flashí 'Kopírování selhalo'.

Střední
/home/github/Repoflare
Vylepšení chybové hlášky u vytváření tokenu

Chybová hláška u tokenu byla jen tichý červený text. Nyní má výraznější border, dismiss tlačítko a aria-describedby, takže screen reader chybu spojí s polem názvu.

Střední
/home/github/Repoflare
Přístupnost — focus, ARIA, ikony

Klávesnicová a screen-reader přístupnost. Šipky '←' v back-link odkazech obaleny aria-hidden, fokus-visible ring doplněn na plain <a> odkazy, search input dostal aria-label a počet je aria-live.

Střední
/home/github/Repoflare
Middleware: + /docs do allowlist

Middleware isAstro allowlist neměl /docs. Rozšířen o pathname === '/docs' — request projde Access verify a renderuje docs.astro.

Střední
/home/github/Repoflare
Stránka docs.astro s návodem

Návštěvníci neměli kde najít jak registry používat. Vytvořen src/pages/docs.astro: 6 sekcí v CS (vygenerovat token z dashboardu, nastavit .npmrc per-host i per-scope, publish, install s npm.org fallback, scoped balíčky, troubleshoot 401/403/409).

Střední
/home/github/Repoflare
Link na /docs z homepage

Homepage měla 3 tlačítka (Dashboard, API dokumentace, GitHub) — bez návodu. Přidán Návod button mezi Dashboard a API dokumentace, variant=outline (secondary CTA).

Střední
/home/github/Repoflare
CF Access app: + /docs destination

Access app chránila jen / a /dashboard*. /docs by bez Access destination obešel ochranu (Astro middleware sice gate-uje, ale CF Access by header neposlal). Přidán třetí destination 'npm.vyvoj.dev/docs' (exact match) do existing Access app via API.

Střední
/home/github/Repoflare
Middleware routing pro Astro root

Catch-all middleware z Run 002 delegoval všechny non-/dashboard requesty na Hono. Pro novou homepage / je potřeba povolit Astro render. Přidána explicit kontrola isAstroRoot — / projde na next() (Astro), zbytek non-/dashboard dál na Hono (NPM protokol).

Střední
/home/github/Repoflare
Homepage index.astro s landing copy

https://npm.vyvoj.dev/ vracelo Hono 404 — návštěvník netušil co je to za službu. Vytvořen src/pages/index.astro s minimal landing: heading, 2 odstavce popisu (D1+R2+CF Access+bearer tokeny, jak nastavit .npmrc), 3 Buttons (Otevřít dashboard primary, API dokumentace outline, GitHub ghost external s rel=noopener).

Střední
/home/github/Repoflare
Install shadcn Input/Select/Card/Alert

Run 003 nainstaloval jen Button. Run 005-007 napsaly komponenty s plain HTML inputy/selecty/error bloky — proti shadcn rule 'always use components'. Doinstalován Input, Select, Card, Alert (+ Separator transitively) přes shadcn CLI. Z select-content.svelte odstraněn defaultní shadow-md (skill no-shadow rule).

Střední
/home/github/Repoflare
CreateTokenForm refactor

CreateTokenForm měl plain input pro name, plain select pro scope, custom red text pro error, custom green border pro success token reveal — nekonzistentní s design systemem. Refactorováno: Input pro name, Select.Root/Trigger/Content/Item pro scope (s triggerLabel $derived), Alert variant=destructive pro error, Alert default pro success s code+copy uvnitř Description.

Střední
/home/github/Repoflare
PackageSearch refactor

PackageSearch měl plain <input type=search> s ručně napsanými border classes. Nahrazeno za <Input type=search class='max-w-md'> — méně klutterového kódu, konzistentní s ostatními formuláři.

Střední
/home/github/Repoflare
Tokens list delete button

Delete button v tokens listu byl plain <button> s ručně napsaným destructive border + hover bg. Nahrazeno za <Button variant=destructive size=sm>. Astro renderuje SSR-only (žádný client:* directive), zero JS shipped pro tento widget — submit je native form behavior.

Střední
/home/github/Repoflare
PackageSearch Svelte island

List balíčků se nedal prohledávat — při růstu počtu nepoužitelný. Vytvořen PackageSearch.svelte: Svelte 5 island s runes ($state pro query, $derived pro filtered list), case-insensitive substring match. Empty state rozlišuje 'no packages' vs 'no match for query'.

Střední
/home/github/Repoflare
InstallSnippet Svelte island

Detail page nezobrazila install command — user musel hádat package name pro npm install. Vytvořen InstallSnippet.svelte: code block s 'npm install <name>' + Copy button (navigator.clipboard) s 2s 'Zkopírováno' flash, stejný pattern jako CreateTokenForm.

Střední
/home/github/Repoflare
Index page refactor s islandem

Inline list rendering v index.astro znemožnoval interaktivní filter. Refactor: list přesunut do PackageSearch islandu (mount client:load, packages prop), SSR fetch zůstává v frontmatter. Index.astro je teď tenký shell.

Střední
/home/github/Repoflare
Detail page mount install snippet

Detail page chyběl install snippet. Mount InstallSnippet islandu mezi description a README sekci s pkg.name jako prop, client:load pro interaktivitu copy buttonu.

Střední
/home/github/Repoflare
Tokens list stránka

Pod /dashboard/tokens neexistovala žádná stránka. Vytvořen tokens/index.astro: SSR fetch tokenů, masked display (jen xxxx…yyyy, plaintext nikdy v listu), scope summary, formátované createdAt, delete form per řádek + mount Svelte create islandu nahoře.

Střední
/home/github/Repoflare
Svelte 5 island na create form

Form pro create token potřebuje JS pro one-shot reveal plaintext tokenu (no-JS fallback by chtěl session storage flash). CreateTokenForm.svelte: Svelte 5 island s runes ( pro inputs/loading/error/copied, pro canSubmit), fetch POST → success render token + Copy button (navigator.clipboard) s 2s flash 'Zkopírováno'.

Střední
/home/github/Repoflare
Helper listTokens + masking

Tokens stránky neměly query helper, pattern stejný jako u packages. Přidán listTokens v dashboard-queries (findMany ordered desc by createdAt) + samostatný mask-token util pro UI display ve formátu xxxx…yyyy bez plaintextu.

Střední
/home/github/Repoflare
Create token endpoint

Bez Astro endpointu by Svelte island neměl kam fetchnout. Hono /-/npm/v1/tokens potřebuje bearer token (assertTokenAccess) — CF Access user ho nemá. Vytvořen create.ts: POST endpoint pod /dashboard/tokens/create (uvnitř middleware gate), zod validace + delegace na tokenService.createToken, vrací 201 s plaintext tokenem.

Střední
/home/github/Repoflare
Delete token endpoint

Form delete potřeboval endpoint pod /dashboard/* (NE /api/*) jinak middleware skipne a Hono catch-all vrátí 404. Vytvořen [token]/delete.ts: POST handler, deleteToken + 303 redirect zpět na list. CF Access JWT funguje jako de facto CSRF token (cross-origin requesty bez něj dostanou 403).

Střední
/home/github/Repoflare
Detail stránka balíčku s README

Detail page chyběl celý. Vytvořen [...name].astro (rest param kvůli scoped balíčkům @scope/pkg), fetch package + latest release, render README přes renderMarkdown. 404 pokud balíček neexistuje, fallback hláška pokud manifest nemá readme field.

Střední
/home/github/Repoflare
Auth gate util require-user

Dev escape hatch v middleware nechá Astro.locals.user = null bez Access headeru. Bez gate by neautorizovaný request prošel na dashboard. Přidán shared util require-user, který vrací Response 403 nebo AccessUser — explicit return je idiomatic v Astro page frontmatter (oproti throw).

Střední
/home/github/Repoflare
Drizzle query helpers pro dashboard

Dashboard stránky neměly query helpery, raw SQL na page by zaplevelilo frontmatter. Přidán dashboard-queries.ts: listPackages (findMany ordered desc) + getPackageWithLatestRelease (2 queries — package, pak release dle distTags.latest). Relational with-filter nešel kvůli závislosti na parent column.

Střední
/home/github/Repoflare
Markdown rendering bez raw HTML

marked v18 neescapuje raw HTML ani nesanitizuje URL schémata — README publisher může injectnout <script> nebo [link](javascript:...). Přidán render-markdown.ts: Marked instance s renderer.html escape + allowlist URL schemes (http/https/mailto/relative) v link/image renderer.

Střední
/home/github/Repoflare
Index stránka s listem balíčků

Pod /dashboard byl prázdný placeholder z Run 003. Index page nyní SSR fetchuje balíčky přes listPackages, zobrazí name + latest version + cs-CZ formátované updated_at, link na detail. Empty state pro 0 balíčků.

Střední
/home/github/Repoflare
Astro middleware ochrana /dashboard/*

Astro middleware měl jen Hono delegaci a /dashboard/* puštěné dál veřejně. Přidána větev: pro /dashboard* ověří Access JWT, jinak delegate na Hono beze změny. NPM protokol nezměněn.

Střední
/home/github/Repoflare
JWT verify pomocí jose a Access JWKS

JWT verify extracted do samostatného lib/access-jwt.ts. Module-level JWKS singleton (createRemoteJWKSet) sdílený přes requesty, jwtVerify s issuer + audience, payload.email uložen do Astro.locals.user.

Střední
/home/github/Repoflare
Env vars TEAM_DOMAIN a POLICY_AUD

TEAM_DOMAIN a POLICY_AUD přidány do vars v wrangler.jsonc s empty defaults — produkce doplní podle access-setup.md. Wrangler types regenerated, env.* je type-safe.

Střední
/home/github/Repoflare
Typování App.Locals.user

App.Locals neměl typ pro přihlášeného uživatele. Nový src/env.d.ts augmentuje App.Locals o user: AccessUser | null, takže pages pod /dashboard/* můžou číst locals.user.email type-safe.

Střední
/home/github/Repoflare
Návod na setup CF Access

Žádný návod, jak Access nakonfigurovat. Nový docs/access-setup.md popisuje Self-Hosted Application + Policy + zkopírování AUD tagu, dev escape hatch a troubleshooting.

Střední
/home/github/Repoflare
shadcn-svelte init s tokens

shadcn-svelte CLI v1.2.7 vyžaduje interaktivní preset selection, neslo skriptovat. Manuálně vytvořeny components.json + src/lib/utils.ts s cn helperem + src/styles/global.css s neutral oklch tokens. Outcome ekvivalentní.

Střední
/home/github/Repoflare
BaseLayout a refactor dashboard pages

Dashboard byl bare HTML bez stylingu. Vytvořen src/layouts/BaseLayout.astro (slot + global.css import + viewport meta), dashboard/index.astro ho používá s Tailwind container utilities.

Střední
/home/github/Repoflare
Button island na hello-world stránce

Plán chtěl ověřit Svelte hydration na CF Workers. pnpm dlx shadcn-svelte add button vygeneroval Button komponentu, dashboard ji ukazuje 2× — client:load (Svelte island, hydratovaný) a outline (SSR-only). Bonus: check-types přepnut z tsc na astro check kvůli Svelte type re-exports.

Střední
/home/github/Repoflare
Astro Svelte + Tailwind v configu

astro.config.mjs měl jen adapter, web UI nemělo žádný styling. Přidán svelte() integration + @tailwindcss/vite plugin + $lib alias přes vite.resolve. Tailwind classes a Svelte 5 hydration teď fungují v .astro souborech.

Střední
/home/github/Repoflare
Catch-all endpoint pro npm protokol

Původně catch-all endpoint v src/pages/[...npm].ts vyhodil 404 pro /_ui/, protože Astro routing prioritizuje endpoint nad page. Přepsáno na src/middleware.ts který volá next() pro /dashboard/* a app.fetch() pro vše ostatní — žádný preempt.

Střední
/home/github/Repoflare
Přepnutí Worker entry na Astro

wrangler.jsonc: main na @astrojs/cloudflare/entrypoints/server (Astro 6 v13 unified entry), přidán account_id, custom_domain route na npm.vyvoj.dev, kv/r2/d1 bindings s reálnými ID. Worker name přejmenován na npm-vyvoj-dev.

Střední
/home/github/Repoflare
Oprava package.json a vitest configu

vitest.config.ts měl stale wrangler.toml path a src/index.ts main z Run 001. Fix na wrangler.jsonc + nový hono-app.ts main. package.json: dev na astro dev, check-types doplněn o astro sync (Locals types). Bonus: turbo/biome/knip/sherif odstraněny.

Střední
/home/github/Repoflare
Smoke test buildu a integration testů

Lokální astro build + vitest run prošly (55/55). Wrangler deploy --dry-run čistý. Po deploy do produkce smoke test přes curl: /dashboard/ → Astro hello-world 200, /_/docs → Scalar 200, /<package> → npm proxy 200, /-/npm/v1/tokens admin auth 200.

Střední
/home/github/Repoflare
Přesun Hono entry do lib

Hono app byl přímo v src/index.ts a sloužil jako Worker entry. Přesun do src/lib/hono-app.ts s dual exportem (named app + default app) — named pro Astro middleware delegaci, default kvůli vitest pool worker main.

Střední
/home/github/Repoflare
Přejmenování apps/api na apps/worker

git mv apps/api → apps/worker, package name @npflared/api → @npflared/worker. biome.json path update. Workspace glob apps/* nepotřeboval změnu.

Střední
/home/github/Repoflare
Převod wrangler.toml na wrangler.jsonc

wrangler.toml → wrangler.jsonc se referencí, observability:enabled, compatibility_date 2026-05-10. Bindings (D1, R2, vars) zachovány s původními placeholder hodnotami.

Střední
/home/github/Repoflare
Instalace Astro 6 + Cloudflare adapteru

pnpm add astro 6.3, @astrojs/cloudflare 13.5, @astrojs/svelte 8.1, svelte 5.55, jose 6.2, marked 18.0. Wrangler bumped 4.58 → 4.90 protože adapter peer dep požaduje ^4.83.

Střední
/home/github/Repoflare
Astro config + minimální stránka

astro.config.mjs minimální (jen adapter cloudflare()), svelte() zatím vypnutá komentem - aktivuje Run 003. Hello-world stránka pod /_ui/ namespace aby budoucí catch-all na rootu nekolidovala s npm protokolem.

Střední
/home/github/Repoflare
Ověření že astro build projde

pnpm astro build prošel s 0 errors. Build vyprodukoval dist/client + dist/server (Astro 6 nová struktura, ne stará dist/_worker.js). Acceptance kritérium runu splněno.

Střední
/home/github/Repoflare
Našeptávač v hero search baru

Hero search bar v patičce ukazoval mock 10 fake položek. Teď se po 250ms debounce zeptá API a klik na výsledek vede přímo na detail spotu. Generation-token guard zahodí pomalý response, kdyby user mezitím doťukal další písmeno.

Střední
Hammocknook CF
Vyhledávání na /mapa

Vyhledávací input nahoře na /mapa byl decorative — neposílal nic. Obalený do <form action=/mapa>, Enter teď refreshuje stránku s ?q=… a backend filtruje. Stávající filtry (amenities, terrain, rating) přežijí přes hidden inputy.

Střední
Hammocknook CF
Hledání spotů přes API ?q=...

Backend listSpots neuměl text search — UI parametr ?q=... se ignoroval. Teď filtruje přes LIKE na názvu, regionu a popisu. SQLite default ASCII case-insensitive, diakritika přesný match (pro v1 dataset stovek spotů OK).

Střední
Hammocknook CF
Záložka Oblíbené v účtu funguje

Záložka Oblíbené v profilu místo placeholderu načítá první stránku skutečně uložených spotů (přes /api/favorites) a zobrazí je stejnými kartami. Prázdný stav má vlastní hlášku a tlačítko na mapu.

Střední
Hammocknook CF
Počítadlo oblíbených v profilu

Číslo u záložky Oblíbené bylo hardcoded 0. /api/users/me/stats teď vrací reálný počet z DB a profil ho zobrazí v záložce.

Střední
Hammocknook CF
Smoke test produkce

Smoke test produkce zbývá ručně po deploy: kliknout ♡ na kartě, ověřit že se ve /ucet objeví, refresh drží stav, druhý klik odebere.

Střední
Hammocknook CF
Tlačítko ♡ Uložit s instant odezvou

♡ tlačítko na kartě a detailu spotu chybělo — bylo jen statický placeholder. Přidaný islet s animací prázdné→plné srdce, který reaguje hned (optimistic), a v případě chyby se vrátí do původního stavu. Pro nepřihlášené přesměruje na /sign-in.

Střední
Hammocknook CF
♡ button na kartách + detailu spotu

Karty spotů (homepage Top spoty + /ucet) i stránka detailu teď mají funkční ♡. Backend vrací stav přes ?include=isFavorited, takže po refreshi srdce drží uloženou hodnotu.

Střední
Hammocknook CF
Tabulka oblíbených spotů v databázi

Vytvořena migration 0007 + Drizzle schema pro user_favorite tabulku — relation many-to-many (user, spot) s unique(userId, spotId), cascade delete + 2 indexy pro listFavorites a include batch lookup. Před prvním deployem fronend musí proběhnout 'wrangler d1 migrations apply hammocknook-prod --remote'.

Střední
Hammocknook CF
Datové modely pro oblíbené (Effect Schema)

Přidán Effect Schema FavoriteResponse (id, userId, spotId, createdAt) v libs/api-models/src/favorite.ts + isFavorited optional Boolean field na SpotResponse. Reuse SpotListResponse pro GET /api/favorites — žádný extra DTO.

Střední
Hammocknook CF
API rozhraní pro oblíbené (3 endpointy)

FavoritesApi HttpApiGroup s 3 endpointy v libs/api-models/src/api/favorites.ts: POST/DELETE /api/spots/:spotId/favorite + GET /api/favorites (auth, vrací plný SpotListResponse). Wired do HammocknookApi.

Střední
Hammocknook CF
Implementace handlerů pro oblíbené

Handlery v api/src/api-groups/favorites.ts: idempotent POST přes onConflictDoNothing+SELECT fallback, idempotent DELETE bez existence check, listFavorites s INNER JOIN spot + cursor pagination + privacy filter (ADMIN vidí vše, jinak isPrivate=false OR createdBy=me).

Střední
Hammocknook CF
Příznak ?include=isFavorited v list + detail spotu

?include=isFavorited query flag: listSpots batch lookup přes inArray() na page IDs (1 query pro celou stránku), getSpot single SELECT row check. Pro neauth user se flag tiše ignoruje, isFavorited se neobjeví v response.

Střední
Hammocknook CF
Wire HttpApiGroups do http-app + drop Hono mounty
Střední
Hammocknook CF
Smoke + typecheck
Střední
Hammocknook CF
Migrace recenzí na Effect HTTP API
Střední
Hammocknook CF
Migrace endpointu uživatelských statistik na Effect HTTP API
Střední
Hammocknook CF
Migrace administrátorských akcí na Effect HTTP API
Střední
Hammocknook CF
Wire HttpApiGroups do http-app + drop Hono mounty
Střední
Hammocknook CF
Smoke + typecheck
Střední
Hammocknook CF
Migrace Spot endpointů na Effect HTTP API
Střední
Hammocknook CF
Migrace Photo endpointů na Effect HTTP API
Střední
Hammocknook CF
Migrace Vote endpointu na Effect HTTP API
Střední
Hammocknook CF
Backend stats endpoint

Profil potřeboval real čísla místo hardcodovaných. Přibyl GET /api/users/me/stats — vrací počet spotů, recenzí, hlasů a datum registrace. 4 paralelní COUNT queries přes Effect.all, jeden D1 roundtrip.

Střední
Hammocknook CF
Mount + OpenAPI metadata

Endpoint potřeboval session ověření a živou dokumentaci. Mount pod /api/users/* za sessionMiddleware, schema UserStatsResponse v api-models a OpenAPI 3.1 metadata pro Scalar UI.

Střední
Hammocknook CF
Profil stránka real counters

Profil ukazoval jen 'X sdíleno' a hardcoded '14 lesů'. Header teď má 3 živá počítadla (sdíleno · recenzí · hlasů) + sekce 'S Hammocknookem od {měsíc rok}' z reálného joinedAt.

Střední
Hammocknook CF
Tabs Oblíbené/Moje spoty

Taby na profilu byly statické. Teď fungují přes ?tab= URL parametr — 'Moje spoty' default ukazuje cards, 'Oblíbené' prázdný state (přijde Sprint 012). 'Výlety'/'Nastavení' zůstávají vizuálně disabled.

Střední
Hammocknook CF
Auth endpointy v dokumentaci

Doposud chybělo 9 auth endpointů v dokumentaci. Doplněn celý better-auth-parity router (sign-up/sign-in email i sociální, OAuth callback, refresh, sign-out, forget+reset password, verify-email). Body shapes jako generic object placeholder s odkazem na better-auth, protože ne Effect Schema.

Střední
Hammocknook CF
Votes endpoint v dokumentaci

Hlasování (upvote/downvote) bylo neviditelné v Scalar UI. Přidán PUT endpoint s VoteInput/VoteResponse schemas — body popsán jako idempotent toggle (1 upvote, -1 downvote, 0 remove) a response counters jako celkový stav po batch update.

Střední
Hammocknook CF
Admin endpointy v dokumentaci

Admin endpointy (role flip + anonymizace) chyběly. Doplněny s tagy ['Admin'], security pro session cookie a description vysvětlující last-admin guard (403 při pokusu sundat posledního ADMINa, 409 při pokusu ho anonymizovat).

Střední
Hammocknook CF
Memo OpenAPI dokumentu pro výkon

Build celého OpenAPI dokumentu (Effect Schema → JSON Schema walk + ref rewrite) běžel při každém GET /openapi.json — zbytečný CPU cost. Přidán module-level cachedDocument; první request build-uje, další serve cached. Cold-start race je idempotent, takže safe.

Střední
Hammocknook CF
Smoke test a uzavření sprintu

Curl /openapi.json: 200 application/json, 31KB validní OpenAPI 3.1, 18 paths / 24 operations / 13 schemas. Sprint 016 hotovo, sprint.md status změněn na 'hotovo (čeká audit)'.

Střední
Hammocknook CF
Vyčištění OpenAPI Number shape přes Schema.annotations

JSON Schema výstup byl ošklivý — Schema.Number povoluje NaN/Infinity přes string encoding (anyOf branche). Swap na Schema.Finite (dedikované schema, ne jen check) tyhle větve odstraní → lat/lng/rating mají v Scalar UI čisté {type:'number'}.

Střední
Hammocknook CF
OpenAPI metadata pro zbývající Spots endpointy

Spots měly hand-tagged jen GET list (R059 PoC). Doplněno POST /api/spots, GET /api/spots/{id}, PATCH /api/spots/{id}, DELETE /api/spots/{id} — security pro auth-protected, response refs na Spot.* schemas, error responses 400/401/403/404 dokumentovány.

Střední
Hammocknook CF
OpenAPI metadata pro Photos endpointy

Tři Photos endpointy chyběly v dokumentaci — POST link userFile ke spotu, GET list (s visitorOnly filtrem co odděluje hero galerii od galerie návštěvníků), DELETE unlink (multi-owner check: file owner / spot owner / ADMIN). Photo.* schemas přidány do components.

Střední
Hammocknook CF
OpenAPI metadata pro Reviews endpointy

Čtyři Reviews endpointy doplněny: POST + GET pod /api/spots/{spotId}/reviews, PATCH + DELETE top-level /api/reviews/{reviewId}. Doc původně zmiňoval že ADMIN nesmí PATCH cizí recenze — code skutečně dovoluje, opraveno v review fází. Review.* schemas v components.

Střední
Hammocknook CF
Smoke OpenAPI spec + automatické checky

Curl /openapi.json vrátil 200 application/json (23KB validní OpenAPI 3.1, 6 paths / 12 operations / 11 named schemas). SpotResponse.lat má teď shape {type:'number'} bez anyOf NaN/Infinity větví. Typecheck/oxlint čistý, 35/35 vitest pass.

Střední
Hammocknook CF
Hand-tagged metadata pro endpoint seznamu spotů

Endpoint pro list spotů (12 query params, response refs na SpotListResponse) je první a vzor pro R060/R061. Tagy, summary, parameters jsou ručně — Effect Schema neumí URL routing, takže path/query metadata se píší per-route.

Střední
Hammocknook CF
Mount Scalar UI a OpenAPI JSON endpointu

Routes /docs (Scalar UI) a /openapi.json (runtime spec) namountovány v app.ts mimo blok session middleware — jsou public, žádný auth pro doc browsing. Pozice mimo chained routes const je záměr (nepatří do Hono RPC AppType, web wrapper je nepotřebuje).

Střední
Hammocknook CF
Manual smoke /docs UI

curl /openapi.json vrátil 200 application/json (16KB validní OpenAPI 3.1: openapi/info/servers/components/paths). curl /docs vrátil 200 text/html (Scalar HTML shell). Typecheck/oxlint čistý, 35/35 vitest pass.

Střední
Hammocknook CF
Cleanup mrtvých OpenAPI zbytků a instalace Scalar

Kořenový openapi.json byl mrtvý NestJS dump z dob před přepisem na Hono. generate-openapi script ukazoval na neexistující soubor a táhl s sebou jiti devDep. Vše smazáno (api + root), místo file dumpu nasazujeme runtime endpoint. @scalar/hono-api-reference instalován jako základ pro UI.

Střední
Hammocknook CF
OpenAPI document builder s validací Effect Schema converter

Effect Schema (single source of truth pro DTO) se převádí na OpenAPI components přes builtin converter. Vlastní openapi.ts builder volá Schema.toJsonSchemaDocument na pojmenované schemas a toMultiDocumentOpenApi3_1 přepíše refy do OpenAPI tvaru. Bez ručního duplikování shape v Zod nebo jiném schema lib.

Střední
Hammocknook CF
Zrušeno
0
Prázdné
Vráceno
0
Prázdné