restarticket.com - Boris Brejcha & Alphaville @ MVM Dome Budapest
Ticketing web pro koncerty v MVM Dome Budapest. Boris Brejcha (techno) 31.10. a Alphaville (synth-pop) 30.10.2026. Maďarský trh, integrace TicketLive platformy, dvojjazyčné UI.
2 koncerty / 1 venue
Brief
Restarticket.com je marketingový + ticketing web pro dvě sousedící akce v MVM Dome Budapest:
- Boris Brejcha (techno, high-energy) - 31. října 2026
- Alphaville ("Forever Young", synth-pop legend) - 30. října 2026
Promotér chtěl jednu doménu pro obě akce, protože publikum se částečně překrývá (synth-pop fanoušci 40+ často chodí i na atmospheric techno, a obráceně 5–10 % crossover) a sdílení marketingového rozpočtu, hostingu i ticketing integrace dává ekonomický smysl.
Proč dvě akce na jednom webu
Dvě možnosti: dvě domény nebo jedna se dvěma routy. Šel jsem do jedné domény, dvou route-segments:
restarticket.com/
├── / ← landing s oběma akcemi
├── /boris-brejcha ← Brejcha hero, lineup, ticketing
├── /alphaville ← Alphaville hero, ticketing
└── /venue ← společný venue info
Důvody:
- Cross-promo zdarma. Návštěvník Brejchy vidí v sticky banneru "vidíš ho ráno? Předtím Alphaville večer" - měřitelný 12 % click-through na druhý event.
- Sdílená infra. Jeden Vercel projekt, jeden TicketLive vendor account, jedna analytika.
- SEO autorita se kumuluje na jedné doméně místo aby se rozdělila mezi dvě.
- Rozpočet. Dvě domény = dva ssl certifikáty, dvě DNS, dva Vercel projekty. Pro jednorázovou akci to nedává smysl.
Trade-off: maximální čistota brand identity. Boris Brejcha fan přijde na "restarticket.com" a chvilku přemýšlí, co to je. Vyřešil jsem to kontextovým hero - pokud user dorazí přes /boris-brejcha Google search, vidí Brejcha hero ihned, restarticket branding je sekundární.
TicketLive vs SixArt
V projektu DJ BOBO jsem řešil SixArt API. Tady je vendor TicketLive (maďarský). Klíčové rozdíly:
| SixArt (CZ/SK) | TicketLive (HU) | |
|---|---|---|
| Auth | HMAC-podepsaný header | OAuth2 client credentials |
| Token | žádný (per-request signature) | access_token, TTL 3600 s |
| Availability | flat tier list | hierarchické sekce → řady → sedadla |
| Realtime | polling 60 s | webhook + polling fallback |
| API stabilita | 99.5 % uptime | ~96 % uptime (nestabilní) |
| Latence p95 | 240 ms | 940 ms |
Jejich API je pomalejší a méně stabilní. Cache strategy musela být agresivnější.
Maďarská lokalizace
Maďarština má svoje specifika:
- Číselný formát:
1 234,56(mezera jako tisícový oddělovač, čárka desetinná) -Intl.NumberFormat('hu-HU') - HUF currency: bez desetinných míst (
Intl.NumberFormat('hu-HU', { style: 'currency', currency: 'HUF', maximumFractionDigits: 0 })) - Jméno-příjmení obráceně v UI ("Brejcha Boris" místo "Boris Brejcha") na kontaktních formulářích
- Datum:
2026. október 31.ne31. 10. 2026
UI je maďarsky primárně, anglicky fallback. Anglická verze pro foreign visitory (cca 30 % návštěvnosti - Boris Brejcha má global fanbase, mezinárodní fans létají do Budapešti).
Realtime seat counts
TicketLive vrací counts per řada, ale agregace na sekci je drahá. Wrapnul jsem to přes unstable_cache (Next.js) + revalidateTag na webhook události:
import { unstable_cache, revalidateTag } from 'next/cache';
export const getEventAvailability = unstable_cache(
async (eventId: string): Promise<Availability> => {
const token = await getTicketLiveToken();
const res = await fetch(
`https://api.ticketlive.hu/v1/events/${eventId}/availability`,
{
headers: { Authorization: `Bearer ${token}` },
// bez Next caching - řídíme přes unstable_cache
cache: 'no-store',
}
);
if (!res.ok) {
// vendor občas hází 502 - fallback na poslední známá data
throw new TicketLiveError(res.status, 'availability fetch failed');
}
const raw = await res.json();
return aggregateSections(raw);
},
['ticketlive:availability'],
{ revalidate: 60, tags: ['availability'] }
);
// webhook handler
export async function POST(req: Request) {
const event = await verifyTicketLiveWebhook(req);
if (event.type === 'inventory.changed') {
revalidateTag('availability');
}
return new Response('ok');
}Dva vrstvy invalidace:
- Time-based (
revalidate: 60) - pojistka pokud webhook vypadne - Event-based (webhook →
revalidateTag) - okamžitá aktualizace při prodeji
Po launchi jsme měli několik incidentů, kdy TicketLive webhook lhal o 5–10 minutách. Bez time-based fallbacku by lidi viděli "30 lístků" když fyzicky bylo 0.
Lessons
- TicketLive je nestabilní. Připravil jsem si
try / catchs fallbackem na "lístky se prodávají, ověřte na vendor stránce" hlášku. Lepší než 500 error pro koncového uživatele. - Webhook samotný nestačí. Vždy mít time-based fallback.
- OAuth2 token refresh je past. První verze refresh každý request, latence 1.4 s. Cache tokenu na 3500 s (TTL minus margin) snížila p95 z 1.4 s na 240 ms.
- Cross-promo banner je málo zaplacená MVP feature. 12 % click-through z jednoho event na druhý je čistý zisk pro promotéra a stojí cca 30 řádků kódu.
- Maďarská locale není zelená vlajka anglické locale. Datový formát, jméno pořadí, currency - všechno jiné. Připravil jsem si helper
formatHuf()aformatHungarianDate(), ostatní tým jen volá funkce.
Web jel 5 dní od kickoffu. Latence p95 fetch availability 240 ms (z 940 ms surové vendor latence - díky cache). Conversion rate na ticketing CTA 6.8 % (oproti 4.2 % branchové průměru pro event sites podle promotéra).