TODO
Otevřené úkoly napříč projektem. Seřazeno podle priority. (revize 2026-07-20 — kompletní revize: hotové věci přesunuté do archivu na konci souboru, otevřené přeorganizované nahoru podle toho, co dává smysl dělat teď.)
Teď — dává smysl udělat
Zálohy
- Legacy MySQL mimo VPS (2026-07-21) — denní
mysqldump→ gzip → age → bezplatný Google Drive přes rclone, retence 90 dní, systemd timer. Ověřen úplný restore do čistého MySQL 5.7 (46 tabulek, 254 highlines). Runbook vbackups.md. - Druhá kopie privátního age recovery klíče (2026-07-21) — uložená v rootu backup Google Drivu, mimo
slack-cz-backups. - Nová aplikace — později doplnit PostgreSQL +
public/uploads; teď není kritické.
Intro
Stránka /intro hotová (app_intro + seed citáty), ale zatím nelinkovaná z nav.
- Rozhodnout, jak a kde Intro ukázat uživatelům (homepage onboarding? první návštěva? odkaz v menu?).
Cutover: slack.cz → nový VPS (launch blockery)
Detailně v deploy.md. Appka běží na beta.slack.cz, tohle je poslední balík
před ostrou doménou.
-
MAILER_DSNpřes externí SMTP relay (Brevo / Mailgun / Postmark) — Hetzner blokuje port 25 outbound. Dokud nejede, fallback:bin/console app:user:reset-password <email>. Odblokuje i admin/autor notifikace u verifikací (viz níž). - Fotky na betu —
public/uploads/line/*jsou mimo git i mimopg_dump.make syncBetaFromLocalveze jen DB → po lokálním importu ještěmake syncBetaPhotos(rsync masterů), jinakline_photořádky ukazují na neexistující soubory. - DNS swap — A pro
slack.czz legacy IP na178.105.81.158+ AAAA (gray cloud, DNS-only). -
slack.cz+www.slack.czblok vinfra/Caddyfile— zatím proxyuje legacy aplikaci na127.0.0.1:8090; při cutoveru se přepne na Symfony webroot/PHP-FPM. - Po DNS swapu přepsat
DEFAULT_URIv/var/www/slack-cz/.env.localzhttps://beta.slack.cznahttps://slack.cz+ reload PHP-FPM. - Zkontrolovat
LineController::PRODUCTION_URL(https://www.slack.cz) — používá ji/data-reportpro proklik na legacy detail; upravit, pokud se prod host změní. - Nastavit reálné
YOUTUBE_API_KEYv.env.localna serveru pro slackTV feed. - Po prvním deployi s galerií zkontrolovat
line_photo.widthna serveru (SELECT count(*) FROM line_photo WHERE width IS NULL). Kdyby zůstaly NULL, spustitbin/console app:photo:backfill-dimensions; bez toho/galeriekreslí fallback poměr 4:3. - (volitelné)
unattended-upgradesna auto-security patches. - (volitelné) Hetzner snapshot schedule pro disaster recovery.
Mapa
- „Přidat lajnu" CTA klikem na mapu — z
/mapaklik na prázdné místo předvyplní Bod 1 (teď jen v hlavičce + ručně nastavené GPS). - Vlastní ikony per typ (Highline / Midline / Longline / Waterline — různé barvy).
UX — co nejjednodušší pro lajnery
Cíl (sezení 2026-06-12): ať je appka pro lajnery co nejjednodušší na používání.
- Smooth highline edit flow — projít celý edit flow, minimum kroků, žádné tření.
- Smooth zadávání přechodu — stejný princip: co nejmíň klikání, rychlé zapsání zážitku.
Highline edit / verification — follow-upy
Trust model + proposal queue v docs/line-edits.md.
- Bulk verify — admin UI s checkboxy nad seznamem unverified lajn (teď to musí klikat 1×1).
- Notifikace adminovi mailem při
PENDINGproposalu — závisí naMAILER_DSNvýš. - Notifikace autorovi proposalu o schválení/zamítnutí.
- „Soft-delete" lajny (
deleted_atflag) místo hard delete — kdyby admin chtěl revertovat omylem smazanou lajnu.
Wiki
- Doplnit chybějící obrázky — úvodní Google Docs seed přenesl jen 8 z ~N obrázků. Editovat
wiki/NN-skupina/NN-slug.md, přidat![][imageN]ref-defs. (LOW, kosmetika)
Obsah ze starého slack.cz
Vyžaduje ruční sběr materiálu, ne jen dev práci.
- Archiv článků — nasosat texty/články z původního slack.cz, udělat z nich archiv v nové appce.
- slackTV — content z old slack.cz — nasát videa/odkazy do slackTV.
- Nové fotky — z původního slack.cz máme hodně low-quality fotek. Hlavní výzva pro Intro stránku.
Údržba / drobnosti
- Rozšířit smoke testy o DB-backed routy (
/,/mapa,/denik/{id}, …) — vyžaduje test DB se schématem. - Rozšířit smoke testy o
/registracea další form-rendering routy; registrace už má samostatné testy validace a availability endpointu, chybí ale plný render/submit smoke test. - Default Symfony
hello_controller.jsvassets/controllers/smazat až bude místo něj něco užitečného. - Restrikce
YOUTUBE_API_KEYv Google Cloud Console (HTTP referrers + jen YouTube Data API v3) — teď bez restrikce. (nízká) - Po nasazení produkce rotovat
YOUTUBE_API_KEY. (nízká)
Backlog / odloženo (neřešit teď)
- Time-travel („Přehrát historii") — doladit do „super feature" — user ho chce zachovat a vylepšit, ne smazat. Toggle je zakomentovaný v
map.html.twig(atop: 44pxoffset v_map.scss) od 2026-07-05; mobilní redesign ovládání, na který se čekalo, mezitím proběhl (map-panel taby, 2026-07-07/08), takže je to odemčené — jen teď nemá prioritu. - Profil: avatar / bio / odkazy (IG, web) — UI editor pro vlastní profil + sloupce v entitě, případně backfill z legacy.
- Non-highline fotky (FotoLIVE) — legacy tabulka
fotolivejsou fotky nepatřící ke konkrétní lajně. Rozhodnout, jestli pro ně udělat zvlášť kategorii / galerii. - ⏸ webbing themes picker — odloženo na neurčito (2026-07-01).
slackTV — follow-upy
- Cold-cache
/tvdělá ~19 sekvenčních HTTP volání — při expiracitv.sections(6 h) první návštěvník čeká ~5–10 s. Paralelizovat (concurrent HttpClient) nebo nahřívat cache cronem. (MED) - Hashtag slider „view on YouTube" míří na
/hashtag/{tag}místo na search — dead-end (~10 videí místo tisíců). Fix = jeden řádek:url: 'https://www.youtube.com/results?search_query=' . rawurlencode($tag). (LOW, hotový recept) - Hashtag taby bez klávesové navigace (arrow keys / roving
tabindex). (LOW, a11y) - Přidat další search query / kanál — TTL 6h má quota rezervu ~25×. Až bude YT kanál CAS, přidat jeho channel ID do
feed.youtube.channels. - Promyslet FB Page CAS jako další zdroj (jiný fetcher; Meta API).
-
highline_media— externí odkazy (foto/video/článek na youtube / rajce / lezec), ne lokální fotky → potřebuje vlastní entitu + UI sekci na detailu. Deferred, vizmigration.md§ Mimo scope. - Galerie: fotky z přechodů / hero momenty — netřeba akce teď; až budou user uploady s reálnými EXIF daty, kronika se zpřesní sama (legacy fotky mají datum = 1. napnutí lajny).
Offline PWA — highline mapa v terénu (PLÁN)
Stav: návrh k doladění. Sepsáno session 2026-06-02. Záměr: highliner v horách bez signálu si appku nainstaluje jako PWA a má offline celou ČR (podkladová mapa + body highlinů + popupy + časová osa). Nic se zatím nestaví — nejdřív dorozhodnout otevřené body níž.
Rozhodnutí, která už padla
- Zůstává Leaflet, nemění se za MapLibre. Použít
protomaps-leaflet(renderuje vektorové PMTiles přímo v Leafletu, canvas). Vymění se jen podkladová vrstva —L.tileLayer(OSM)→ vektor nad pmtiles. Všechny 4 mapové controllery (map,line_detail_map,user_denik_map,line_form_map) i veškerý marker/popup/timeline kód zůstávají beze změny. - Instalace PWA = souhlas se stažením celé ČR. Po instalaci se automaticky na pozadí stáhne
cz.pmtiles. Install je vědomý úkon → bereme ho jako „chci to celé offline". - Vlastní hostovaný pmtiles, ne OSM tile server (OSM policy zakazuje hromadný předstah; navíc chceme nezávislost na cizím zdroji).
Architektura (4 etapy, ~2,5 dne, největší riziko etapa 3)
Etapa 1 — PWA základ (~půlden)
symfonycasts/pwa-bundle(integruje AssetMapper). Manifest + service worker.- Precache: app shell, Leaflet/protomaps-leaflet assety, marker ikony.
- JSON endpointy (
app_line_map_data/_feed/_timeline) → runtime cache stale-while-revalidate. - Výsledek: appka instalovatelná, body + popupy + časová osa offline. Podklad zatím chybí.
Etapa 2 — vektorový podklad ČR (~půlden)
- CZ extract z
protomaps.com/downloads(bbox ~12.0,48.5,18.9,51.1) →public/maps/cz.pmtiles. - V
map_controller.jsvyměnit OSM tileLayer zaprotomaps-leafletvrstvu (flavor sladit s light theme + magenta). - Online jede přes HTTP range requesty z vlastního souboru.
Etapa 3 — auto-offline po instalaci (~1 den, tady je vlastní inženýrská práce)
- Detekce instalace:
appinstalled(Chromium/Android) + standalone-detekce při startu (display-mode: standalone) pro iOS, kdeappinstalled/beforeinstallpromptneexistují. - Po instalaci stáhnout
cz.pmtiles→ OPFS (Origin Private File System, iOS 16.4+ OK), progress bar. - Custom pmtiles source čte rozsahy z OPFS přes
File.slice()→ range requesty lokálně. - Resume při přerušení (foreground download); fallback na online range requests dokud není staženo.
Etapa 4 — prod parity (~půlden)
- Caddy: servírovat
.pmtilessRange+ MIMEapplication/octet-stream(infra/Caddyfile+make deployCaddy). .pmtilesmimo git (desítky MB) → stáhnout/vygenerovat při deployi. Updatedeploy.md,deploy.sh, paměť.
Odhad velikosti (ballpark, změřit po reálném extractu)
- maxzoom 14 ≈ ~80–150 MB — dobrý lokální detail (vidíš ke skalám)
- maxzoom 13 ≈ ~40–60 MB — terénní kontext, hrubší zoom
OTEVŘENÉ ROZHODOVACÍ BODY (k doptání)
- Styl podkladu / vrstevnice.
protomaps-leafletbasemap je „city" styl bez vrstevnic / hillshade / terénu — pro highliny v horách možná chceme topo. Tohle je největší otevřená otázka. - maxzoom — z13 (lehčí) vs z14 (detailnější).
- Co všechno je offline. Jen
/mapa, nebo i detail stránky/lajna/{slug}(254 stránek)? Fotky/audio offline spíš ne. - iOS UX — když nejde chytit install event, kdy přesně spustit download?
- Aktualizace pmtiles — jak často přegenerovat a jak řešit cache-busting / verzování.
- Stažení jen na wifi? Desítky MB — nabídnout potvrzení / detekci typu připojení?
- PWA scope — instalovatelná celá appka, nebo „nainstaluj si mapu"?
Doporučení obsahu od userů (DEFERRED)
Stav: myšlenka k dořešení. User si není jistý, jestli celý koncept dává smysl — implementaci odložit. Sepsáno session 2026-06-11.
- Záměr: přihlášený user vloží YouTube odkaz (video / kanál / playlist) jako tip; po moderaci adminem se schválené objeví v sekci „Doporučeno komunitou".
- Rozhodnuto v konzultaci: sbírat videa + kanály + playlisty; schválené → vlastní sekce; default (k potvrzení) — doporučovat jen přihlášení, nic bez schválení adminem.
- Technika: oEmbed na validaci + metadata — 0 kvóty, bez klíče. Nová entita
ContentSuggestion(user, typ, YT id, metadata, status pending/approved/rejected). Admin moderační fronta. - OTEVŘENÉ (blokuje to): kde žije seznam zdrojů sekcí — config (
feed.yaml) vs DB + admin. Nerozhodnuto; proto je feature odložená.
Hotové (archiv)
Analytics
- Matomo self-hosted analytics (2026-07-09) —
analytics.slack.cz, native PHP+MariaDB (ne Docker, sedí na existující prod stack), cookieless tracking gated naapp.environment == 'prod'. Provisioning vscripts/setup-server.sh/check-server-env.sh+infra/Caddyfile, rollout popsaný vdeploy.md§ Analytics. Cestou nalezen a opravený leak (DB credentials soubor krátce dostupný přes web — přesunuto mimo Caddyroot). Rollout kompletně dokončen a ověřen na provozu.
Registrace + profil + ochrana osobních údajů (2026-07-09)
- Dostupnost emailu a nicku za běhu (2026-07-20) — Stimulus volá
POST /registrace/dostupnost; server znovu validuje vstup, odpovědi necachuje a compound limiter omezuje burst i hodinový provoz. Samotný submit má oddělený limit 5/h na IP. - Indikátor síly hesla (2026-07-19) —
password_strength_controller.jsdává okamžitou zpětnou vazbu, serverová validace zůstává autoritativní. - Volba emoji účtu (2026-07-17) — jediný zdroj palety
App\UserEmoji; používá ho registrace, profil a mapové markery. - Nick přesunut do registrace —
RegistrationFormmá nověnick(NotBlank+Length(max:30),UniqueEntitynaUserhlídá kolizi),UserForm(/profil/uprava) ho ztratil. Nick se dá nastavit jen při registraci a pak už ho v appce nejde změnit — vědomé rozhodnutí, ne opomenutí. - Redirect po registraci → rovnou na
app_profile_edit, flash zpráva přepsaná z anglického Symfony-scaffold textu na český: „Děkujeme za registraci! Jestli chceš, můžeš o sobě uvést víc informací. Ať se daří 🍀". Email-verifikační flow (verifyUserEmail()) záměrně beze změny (mimo scope). -
agreeTermscheckbox napojený na reálnou stránku — dřív odkazoval na neexistující „podmínky používání". Přelabelováno na souhlas se zpracováním osobních údajů, link na/ochrana-osobnich-udaju(form_row(..., {label_html: true})spath(), ne natvrdo napsaná URL). Validační hláška přeformulovaná odpovídajícně. - Nová stránka
/ochrana-osobnich-udaju(app_privacy,PagesController::privacy()) — plain-language shrnutí (ne právní review): co je povinné (email, nick) vs. nepovinné (jméno/příjmení/město/ročník/telefon), co je veřejné vs. jen pro přihlášené, že se nic nepředává třetím stranám (Matomo self-hosted bez cookies), poznámka k legacy účtům, kontaktinfo@slack.cz. Prolinkovaná z/o-projektua z registračního checkboxu. Text prošel dvěma koly oprav podle reality appky (nick byl označen jako nepovinný než se dal povinným, jméno/příjmení chybělo v seznamu veřejných údajů — obojí opraveno po review userem). - Info box v
/profil/uprava— Bootstrapalert+ inline SVG ikonka (stejný vzor jako ostatní ručně kreslené ikony v appce), text „Vyplň dle libosti. Všechny údaje jsou nepovinné." - Telefon — viditelnost omezená na přihlášené — dřív nikde veřejně nezobrazený (mrtvý údaj), teď na
/denik/{id}gated{% if app.user %}(komunitní sdílení kontaktu, ne veřejné — legacy slack.cz to takhle měl). Ostatní profilová pole (jméno/příjmení/město/ročník/nick) veřejná bez podmínky. - Telefon — validace formátu — iterováno přes 3 kola zpětné vazby na finální
Assert\Regex/^(\d{9}|(\+|00)?\d{12})$/: buď přesně 9 číslic bez prefixu, nebo+/00+ přesně 12 číslic (prefix se nesmí pojit s 9místným číslem — to byl mezikrok, který prošel testem a neměl). HTMLpattern+titleatribut zrcadlí server-side regex/hlášku, takže i nativní prohlížečová „Please match the requested format" bublina je srozumitelná. - Registrační formulář — pixel fix —
NewPasswordType(2 sub-pole) měl zdvojenýmb-3po druhém inputu (vlastní + outer<fieldset>row). Symfonyhorow_attr: {class: ''}override nefunguje (Twigídefault()filtr bere prázdný string jako "chybí"), funkční fix bylrow_attr: {class: 'mb-0'}na fieldsetu.
Line form — hodnocení, titulní fotka, GPS picker (2026-07-09)
- Hodnocení (
rating, 1–5★) — plnohodnotně v audit systému (LineCrudController::FIELDS/snapshot()/applySnapshot()), na rozdíl od cover fota jde přes proposal queue jako ostatní pole. Renderuje se jako klikacírating-pickerstar-widget (sdílený partialtemplates/_partials/_rating_picker.html.twig+rating_picker_controller.js), ne<select>— nasazeno stejně naLineCrossingForm(hodnocení přechodu). Field type jeHiddenType, neChoiceType— vykreslování přesform_widget(), protože Symfonyhoform_end()tiše dorenderuje nevykreslené pole navíc jako<select>(render_rest), což vedlo k duplicitnímunameatributu, dokud se na to nepřišlo. Vizuál sladěný s.hl-rating-largez detailu lajny přes tokeny ($brand,var(--bs-border-color)), ne přes půjčené třídy (BEM pravidlo). - Titulní fotka (
coverPhotoFile) — unmapped pole, mimo celý trust/proposal systém (aplikuje se vždy okamžitě, stejně jako existující/lajna/{slug}/fotky/pridatflow). Cestou odhalen a opravený bug: VichUploader directory namer proline_photopotřebujeline.id→ vnew()(vytvoření lajny) musí být lajna flushnutá před persist+flush fotky (dřív jeden společný flush →Directory name could not be generated: property line.id is empty). -
Line::heightpřestal předvyplňovat formulář nulou —private int $height = 0→?int $height = null(PHP-nullable, DB sloupec zůstává NOT NULL — stejný vzor jakoname, hlídáAssert\NotNull+ formrequired). Cestou doplněn null-safe cast doLineCrudController::applySnapshot()i doSyncLineFromAuditCommand(zrcadlová kopie, kde navíc chyběl iratingz předchozího bodu — doplněno). - Read-only délka + live redraw při tažení bodu —
<output>se live-updated délkou vedle výšky (wiring mimo Stimulus controller element přes „by-ID" trik, stejně jako lat/lng inputy). Marker měl jendragendlistener (čára/délka se překreslily až po puštění) → přidándraglistener,refreshLine()teď běží při každém pohybu myši (setLatLngs()místo remove+recreate polyline, kvůli frekvenci). Mapový distance badge vidět jen ve fullscreenu (.hl-form-map:fullscreen .hl-form-distance), mimo fullscreen stačí<output>. - Iniciální zoom/fit + refit po fullscreenu —
fitToKnownPoints()sestaví bounds ze všech umístěných bodů (bod 1, bod 2 i parkování — dřív jen natvrdozoom=15, u delší lajny ořízlo druhý bod/parkování mimo výřez), volá se přiconnect()i při opuštění fullscreenu (jiná aspect ratio → starý fit neseděl). - Wheel-zoom citlivost (
assets/map_scroll_zoom.js, sdílené napříč 4 vloženými mapami — homepage/deník/detail lajny/form lajny) —performZoom()byl 1:1 kopií Leafletí pixel-akumulace/sigmoid dampening matiky (naladěná na trackpad pinch), s klasickým kolečkem myši výrazně necitlivější než tlačítka. Zjednodušeno na jeden krokzoomDeltana debounced gesto — stejný krok jako tlačítka.
Mapa
- Homepage: auto-advance na dalším přechodu vytahoval scroll stránky (2026-07-09) —
hp_map_controller.js'sactivate()volaloitem.scrollIntoView({block:'nearest'}), což prolézá všechny scrollovatelné předky včetnědocument— i když má.hp-map__crossingsvlastníoverflow-y: auto. NahrazenoscrollItemIntoView(), co scrolluje ručně jen ten vnitřní box. - Deník už není „highline deník" (2026-07-09) — kategorizace přechodů byla mylně vázaná na highline, přitom
LineCrossingpokrývá všechny typy lajen.UserRepository::findDiaryRows()highlineCount→lineCrossingCount,/denickysloupec „Highline" → „Přechody", tab hash#highline→#denik(user_diary.html.twig). „Longline deník" (samostatný legacy systém, jiná tabulka) beze změny. - Desktop: panel na celou výšku sloupce (2026-07-09) —
.map-panelna desktopu bez drag úchytu a bez JS výšky, prostě vyplní.map-side(media-up(md)v_map.scss); collapse tlačítko na desktopu schované (sbalování zůstává mobilní koncept).map_panel_controller.jsmáisMobile()guardy, aby na desktopu nikdy nenastavil inline pixel výšku. - BUG: mapa nejde zoomovat Ctrl+kolečkem (2026-06-16) — sdílený helper
assets/map_scroll_zoom.js(enableCtrlScrollZoom): inline mapa = Ctrl/⌘ + kolečko zoomuje + hint overlay; fullscreen = plain kolečko. Nasazeno nahp_map,user_denik_map,line_detail_map,line_form_map. Dedikovaná/mapazáměrně ponechána se zoomem samotným kolečkem. - Redesign
/mapa— sreality styl (2026-07-03) — levý sloupec.map-side: box Lajny ve výřezu (abecedně, default otevřený) + box Přechody (default sbalené). Novýline_feed_controller.js,map_controllerbroadcastujeslack:viewport-linesnamoveend/zoomend. Žádný nový backend (app_line_map_data, filtr přesmap.getBounds()). - Mobil: přechody na
/mapa→ tabový.map-panel(2026-07-07) — boxy Lajny + Přechody sloučené do jednoho panelu s taby (desktop i mobil stejně). Novýmap_panel_controller.js(taby + collapse + drag výška + gradient, sessionStorage). Bloky přejmenované na skutečný BEM (map-panel__*--*,line-feed__*,crossing-feed__*). - Redesign boxu Lajny (2026-07-07) — vlastní BEM blok
.line-feed. Výška těla PEVNÁ, user-driven (drag úchyt / šipky), fit-to-content zavržen (nekonečná resize smyčka s mapou)./mapabez patičky a bez svislého scrollu. - Clustering markerů (2026-07-07) —
leaflet.markercluster,staticLayer=L.markerClusterGroup(radius 50,disableClusteringAtZoom=LINE_MIN_ZOOM). Vlastní ikona.map-cluster(BEM). Focus ze sidebaru přeszoomToShowLayer. - Opravy z code review
.map-panel(2026-07-08) — sdílenýassets/breakpoints.js(isMobile(), přesněmedia-down(md)) místo hardcoded matchMedia; sessionStorage try/catch; re-clamp výšky na resize; SVG ikony přejmenované na skutečný BEM; české komentáře v_map.scsspřeložené do EN. - Přeškrtnuté oko v tab-headeru Přechody (2026-07-08) —
map-panel__tab-eye, button nese buď počet přechodů, nebo oko. - Taby panelu = Bootstrap buttony (2026-07-08) —
btn btn-outline-primary btn-sm, JS řídí Bootstrap.active. Touch fix pro sticky:hoverpo tapu. - Kompaktní výpis přechodů + klik → marker (2026-07-08) — dvouřádkové hairline řádky, klik →
slack:crossing-focus→ focus markeru, skryté markery se klikem zviditelní. Vybraná položka podbarvená (__item--active). - Linie mezi
point1apoint2na hlavní mapě (viditelná od zoom ≥ 14). - Mapové zoom controly na
bottomright. - Crossing news-bar sidebar na
/mapa— eye toggle, collapse, time-travel režim. - ❌
Filtry na— nebude (2026-07-01, rozhodnutí usera)./mapa(typ, délka, výška)
Mobile-first Bootstrap rewrite (2026-07-01 → 07-04)
Pivot: mobil = priorita č. 1, custom CSS (30 partialů) označen jako nepoužitelný (feedback od kamaráda + usera). Desktop skoro nikdo.
- Fáze 0 — Bootstrap základ —
symfonycasts/sass-bundle+ Bootstrap 5 JS+Popper přes importmap. Brand vrstvaassets/styles/brand.scss(accent#e1005b). Wiring vapp.js: Bootstrap CSS → legacyapp.css→brand.scss(poslední = přebíjí). - Fáze 1 — Shell + mobil —
user_toolbar.twigna Bootstrap navbar + offcanvas, fixní výška hlavičky (--header-height: 72px). Mobil header jen „Přihlásit"; profil/odhlášení v offcanvasu. Flash → Bootstrap alerts. - Fáze 1 — bugfixy po headless kontrole (2026-07-03) — hlavička na mobilu se lámala na 2 řádky (logo scaling fix); search panel ujížděl mimo obrazovku (přesunut do offcanvasu).
- Mobilní header = jen logo + hamburger (2026-07-03) — search i „Přihlásit" v offcanvasu (inline search varianta +
w-100tlačítko). - Fáze 1 — cleanup (2026-07-03/04) — smazán mrtvý
nav_controller.js+_nav.css;_buttons.css/_flash.csssmazány (Bootstrap.btnpřevzal vzhled). - Breakpoint systém (2026-07-03) —
assets/styles/_breakpoints.scssjediný zdroj breakpointů (Bootstrap škála), mixinymedia-up($bp)/media-down($bp). Žádné nové hardcoded px v@media. - Fáze 3 — migrace zbylých stránek,
app.csssmazán (2026-07-04) — homepage/about/data_report, /tv taby, tokeny+base dobrand/_shell.scss, zbylých 11 partialů portnuto dobrand/.app.css+ 18 souborů smazáno — appka má jediný stylesheet.- Detail lajny → Bootstrap (2026-07-04) —
row/collayout, statycol-lg-4 order-lg-2,brand/_line-detail.scss. Smazán celý_line.css. - Formuláře → Bootstrap (2026-07-04) — všech 9 formulářových stránek + lajna form →
form-page+ card +form_row(). Novébrand/_forms.scss+brand/_line-form.scss. - Tabulky → Bootstrap (2026-07-03) —
/denicky+_longline_crossingspartial. Theme vrstva.tablevbrand.scss. - Deníček + panel→card všude (2026-07-04) —
user_diary.html.twigpřepsán, všichni konzumenti.panel→.card, theme rozsekaná doassets/styles/brand/partialů.
- Detail lajny → Bootstrap (2026-07-04) —
- Docs pryč z menu (2026-07-01) — odkaz přesunut do
/o-projektu.
Refaktoring a jazykové sjednocení
Pravidlo: kód anglicky, veřejné URL česky — appka je pro české uživatele.
- Rename
Highline→Line(2026-06-21) — entita + třídy, tabulky, routy, URL. Slovo „highline" záměrně zůstalo jako disciplína. 3 migrace, ověřeno lint/router/schema. - CSS split dokončen (2026-06-21) —
app.cssmonolit → 30 komponentních partialů. -
ImportHighlineCrossingsCommand→ImportLineCrossingsCommand+ doc rename (2026-06-21). - denik→diary + mapa→map cluster anglicizován (2026-06-30) — šablony, Stimulus, CSS, controller metody, route names. URL paths + UI text zůstávají CS.
- Dohledat zbylé CS identifikátory (2026-07-01) — cílený sken našel jediný zbylý:
redirectToDenik()→redirectToDiary(). Jazykové sjednocení tímto uzavřeno. - Veřejné URL zpět do CS (2026-06-30) —
/line/→/lajna/,/crossing/→/prechod/, verby česky, auth cesty česky. Jména rout zůstala EN. Mezinárodní termíny (/longline,/docs,/wiki,/tv,/intro,/data-report) ponechány EN.
Legacy import fotek
Foto stažené z legacy webu do ../old-slack-cz. Highline import hotový (make importLegacyPhotos).
-
app:import:line-photos(2026-06-16) — cover + galerie → WebP mastery. Ověřeno disk × legacy DB × živý web, 0 ztraceno. - Cover fotka lajny (2026-06-16) — self-hostovaná přes
Line.coverPhoto, legacy hotlink zrušen. - Nasadit
@photoscache blok zinfra/Caddyfilena betu (ověřeno 2026-07-05).
Galerie
- Samostatná stránka
/galerie— kronika po letech (2026-07-04) — roční sekce se scrollspy, justified grid (line_photo.width/height, nulový CLS). Liip filtrgallery_thumb. Ověřeno Playwright.
Rané funkce a migrace (do 2026-06-16)
- WebP/HEIC upload pipeline —
App\Service\PhotoNormalizer, každý upload → WebP master, EXIF datum/GPS do DB. - Veřejný rozcestník deníčků
/denicky— přehled aktivních uživatelů, fulltext filtr + sort. - Longline deník — tab na
/denik/{id}, entitaLonglineCrossing+ import + CRUD. - slackTV →
/tvstránka + redesign na sekce (Kanály / Playlisty / Hashtagy), YouTube Data API + cache. - Homepage panely — slackTV strip dole; „Highline mapa" + „Poslední přechody" sloučeny do jednoho panelu Mapa.
- Cleanup — smazán
App\Old\Entity\Uzivatel, oživen CI workflow + smoke testy. - Migrace legacy dat — kompletní (highlines/users/crossings). Detail v
migration.md. - Gender kompletně odstraněn (2026-06-12).
- Edit profile —
/profile/edit. - Infra: Caddyfile v repu + drift gate (2026-05-11).
- Galerie sociální vrstva + AJAX likes (2026-05-11) —
LinePhotoLike/LinePhotoComment. - Audit historie + stack-pop curation + verifikační merge (2026-05-10) —
/line/{slug}/history,LineEdit. Detaily vdocs/line-edits.md. - Slug stability na verified + rename slug regen na unverified (2026-05-10).
- Parking GPS import (2026-05-10) —
Line.parkingLatitude/Longitude. - Line CRUD + verifikační/proposal flow (2026-05-10) —
LineCrudController,LineEditaudit log. Detaily vdocs/line-edits.md. - Crossing form (CRUD pro přechody) — edit/delete vlastních přechodů z deníku.
- Deník uživatele
/denik/{id}— hlavička, mini-mapa, tabulka přechodů. - Single source of truth pro recent crossings —
LineCrossingRepository::RECENT_LIMIT. - Intro splash overlay — fullscreen logo + „Vstoupit".
- Line detail
/line/{slug}— slug, stat panel, mini-mapa, seznam přechodů. - Line
point1/point2GPS import z legacygps. - User import — 440 nových + 1 enriched + 6 dropped.
- Crossings import — 993/995.
-
MakefiletargetlegacyImport. - „Poslední přechody" panel na indexu.
- Line import 254/254 z legacy DB do Postgres.
- Mapa
/mapas Leaflet + OSM. - Light theme s magenta accent (
#e91e63). - Index page se 2 panely (mini mapa + slackTV teaser).
- slackTV — YouTube Data API v3 fetcher s mock fallbackem a cache TTL.
- About page
/o-projektu. - Restrukturalizace legacy mapování —
App\Entity\Old\*→App\Old\Entity\*. -
.envdeklarujeYOUTUBE_API_KEY=(prázdné, dokumentace).