Lepší nástroj pro upload fotek
Kontext
Nechceme všechny obrázky strkat do hlavního repa projektu (web, blog, …), protože to zbytečně nafukuje jeho velikost a zpomaluje všechny běžné operace typu CI/CD, testy a podobně. Uživatelé obecně z pohledu UX potřebují něco jako imgur.com – přijdu, přetáhnu obrázek, během pár sekund mám veřejné URL vhodné pro libovolné použití.
Současné řešení
Pro uložení obrázků používáme repo https://github.com/cesko-digital/assets, odkud se data přesypávají pomocí GitHub Action do S3 a veřejně jsou pak vidět na data.cesko.digital. Tohle nastavení jsme zvolili jednak proto, abychom lidem nemuseli dávat jednotlivě přístup do AWS (takhle používáme prostě autentizaci a autorizaci na GitHubu), jednak proto, abychom měli autoritativní zdroj dat (repo) a nemohli o data přijít například omylem smazáním jednoho S3 kyblíčku.
Problémy
Současné řešení má následující problémy:
- Špatné UX. Nahrávání obrázků na GitHub má furt relativně vysoký práh. Mysleli jsme si, že to časem bude pro členy týmu prkotina, ale dlouhodobě se nestalo, pořád je to bariéra. Často narážíme například na špatné pojmenování souborů (mezery, diakritika, zvláštní znaky). Zároveň je pro uživatele pořád špatně srozumitelné, na jakém veřejném URL skončí soubor nahraný do zdrojového repa.
- Je to pomalé. Po commitu se spustí GitHub Action, která synchronizuje soubory z repa do S3. Zatímco samotný upload souboru někam do cloudu by zabral řádově sekundy, tady jsme určitě na minutě, což je v praxi opruz.
- Nemáme žádné integrované řešení pro zmenšování obrázků a metadata (rozlišení, blurhash, popisek, autorská práva, …). Zmenšování si řeší každý konzument sám, což je v něčem škoda, a pokud tahle pipeline neumí klientovi předem sdělit rozměry obrázku, tak budeme skoro vždycky řešit layout shift.
Alternativy
Vlastní nástroj pro upload do S3
Mohli bychom udělat jednoduchou webovou aplikaci, které uživatel předhodí fotku a dostane veřejné URL. Výsledek by byl výrazně rychlejší a měl by lepší UX, ale ztratili bychom „bezpečné“ uložení souborů v repository a neuděláme žádný velký pokrok ve sledování metadat (rozlišení, blurhash).
Pro autentizaci můžeme využít například presigned URLs – kdo bude chtít uploadovat, dostane od nás presigned URL, kterým se do aplikace „přihlásí“ (a aplikace si může přihlášení pamatovat v cookie). Pokud soubor před uploadem automaticky přejmenujeme třeba přes prefix jeho SHA1, odpadnou problémy s pojmenováním.
Také je možné využít autentizaci přihlášením přes Slack (případně rovnou aplikaci integrovat do autentizované verze webu č.d?).
Drobná variace na tohle téma by byl Slack bot, kterému by uživatelé nějak poslali obrázek (upload do Slacku) a on by odpověděl jeho veřejným URL na data.cesko.digital.
TBD: Komerční služby
Imgix, …
Rozhodli jsme se to jakkoliv posunout, abychom se nezasekli na hledání nějakého teoretického ideálu. Udělám ten upload do naší AWS S3, tedy jen lepší UI pro upload na data.cesko.digital, zejména tedy bez možnosti načíst rozměry nebo blur hash obrázku.
Pokud jde o UI, chtěl jsem to udělat jako Slack slash command pro bota, tedy že by uživatelé poslali obrázek botovi a dostali od něj veřejné URL. To ale zřejmě nijak jednoduše nejde, protože nám Slack neposílá ty přílohy, když kontaktuje náš server s informací o slash commandu. Takže uděláme jednoduchou webovou aplikaci na našem webu, kudy půjde ten obrázek nahrát. Technické poznámky:
- Potřebujeme uploadovat přímo z klienta do S3, zejména abychom obešli limit na velikost těla serverless funkcí. K tomu slouží presigned upload URLs, viz například tady. Přístupové údaje pro AWS budou tedy uložené na Vercelu, odkud si klient z backendu vyžádá předem podepsané URL pro upload a může nasypat soubor do S3.
- V S3 máme z historických důvodů kolem té domény data.cesko.digital relativně složitou infrastrukturu. TLDR: soubory je potřeba nahrát do kyblíku
cesko-digital-data-automated, zřejmě ideálně do podadresářeimg, výsledné URL budehttps://data.cesko.digital/img/${hash}.${extension}, kdehashje prvních 8 znaků z SHA1 souboru. - Celá služba musí být autentizovaná. Ideálně to samozřejmě nějak hezky udělejme už na klientovi, ale především ten API endpoint pro vytvoření presigned URL pro post do S3 si musí zkontrolovat, že je klient přihlášený, abychom umožnili upload do S3 pouze členům komunity. (TBD: kdybychom to chtěli ještě víc zavřít, můžeme v tabulce
Volunteer Managementzavést novou roli à laImageUpload, kterou bude API endpoint ověřovat.) - Můžeme jako součást metadat obrázku uložit informaci o tom, kdo soubor nahrál?