Un club sportiv și patru aplicații legate
Site public, aplicație de jucător, panou de administrare și terminal de check-in. De ce trebuie să fie un singur sistem de date și ce se rupe când nu e.
Într-o sâmbătă de octombrie, la un club sportiv cu unsprezece terenuri, patru lucruri se întâmplă în același minut. Cineva rezervă de pe telefon un teren pentru seara asta. Altcineva sună la recepție pentru exact același interval. Un jucător intră pe poartă și scanează un cod. Iar administratorul închide două terenuri, pentru că a plouat.
Dacă cele patru acțiuni nu ajung în aceeași bază de date, cel puțin una dintre ele produce un conflict pe care îl rezolvă un om, la telefon, cu scuze.
Ăsta e tot proiectul, rezumat într-un paragraf. Restul e execuție.
Ce a cerut clubul și ce s-a dovedit că îi trebuie
Cererea inițială a fost „vrem o aplicație de mobil pentru jucători”. Formulată așa, suna ca un singur proiect: un ecran cu terenurile, un buton de rezervare, gata.
Am întrebat cine face rezervările azi: recepția, pe WhatsApp și la telefon, într-un tabel. Am întrebat cine știe seara cine a intrat în club: omul de la poartă, dacă își aduce aminte.
Aplicația de jucător era piesa vizibilă. Problema reală era că informația despre un singur teren, la o singură oră, trăia în trei capete și într-un fișier.
Am renunțat și la altceva ce clubul ceruse explicit: prezența în magazinele de aplicații. Pentru un club local, asta înseamnă conturi de dezvoltator, procese de aprobare și o versiune de întreținut separat pentru fiecare sistem. Aplicația instalabilă direct din browser face același lucru pentru jucător — iconiță pe ecran, notificări, fără browser vizibil — fără taxa aia. Am explicat de ce, a fost acceptată, și după șase luni nimeni n-a mai adus vorba de magazine.
Patru ferestre către același sistem
Ceea ce am construit nu sunt patru aplicații independente. Sunt patru interfețe peste o singură bază de date, fiecare făcută pentru un om care stă în altă poziție și are alt timp la dispoziție.
Site-ul public are o singură treabă: să ducă pe cineva care caută „teren de tenis” direct în rezervare. Arată prețurile, programul și disponibilitatea fără autentificare — un vizitator care trebuie să-și facă întâi cont ca să vadă dacă e liber sâmbătă la 18 pleacă.
Aplicația de jucător e pentru cineva care e deja client. Rezervă, își vede abonamentul, plătește, anulează, vede istoricul. Aici contează numărul de apăsări: o rezervare repetată — același teren, aceeași oră, săptămâna viitoare — trebuie să se facă din două atingeri, pentru că asta e ce fac oamenii în realitate.
Panoul de administrare e pentru recepție și administrator: toate terenurile pe o grilă de timp, blocarea unui interval pentru turneu, închiderea unui teren pentru ploaie, și rezervarea făcută în numele cuiva care a sunat. Ultima e obligatorie. Orice sistem care presupune că toți clienții rezervă singuri, de pe telefon, se lovește de primul om care sună.
Terminalul din locație e un ecran la intrare, care citește un cod și confirmă prezența. Are cea mai puțină logică și cele mai multe probleme practice, din motive la care ajung mai jos.
Ce se strică atunci când sunt patru sisteme separate
Varianta cu piese separate — un site, un modul de rezervări cumpărat, un Excel pentru abonamente, un caiet la poartă — nu e teoretică. E exact ce înlocuiește proiectul ăsta.
| Ce se întâmplă | Cu sisteme separate | Cu un singur sistem |
|---|---|---|
| Doi oameni cer același interval | Recepția află a doua zi și sună să reprogrameze pe cineva | A doua cerere vede intervalul ocupat, în aceeași secundă |
| Terenul se închide pentru ploaie | Rezervările online rămân valabile, oamenii vin degeaba | Rezervările afectate sunt marcate și anunțate automat |
| Un jucător cu abonament intră în club | Poarta nu știe nimic despre abonament | Codul lui e valid pentru că abonamentul e activ, nu pentru că îl știe cineva |
| Abonamentul expiră | Se vede la următoarea plată, dacă își aduce aminte cineva | Se vede la check-in și în aplicație, înainte să expire |
| Vine o cerere pentru un turneu | Se blochează în calendar, dar site-ul arată în continuare liber | Blocarea e o rezervare ca oricare alta, vizibilă peste tot |
Rândul care costă cel mai mult bani, pe termen lung, e al patrulea. Un abonament expirat despre care nu află nimeni e un client pierdut fără ca cineva să observe că l-a pierdut.
Rezervarea: partea grea nu e calendarul
Afișarea unei grile cu ore libere e muncă de o zi. Partea care ia timp e ce se întâmplă când două cereri ajung în același moment.
Verificarea făcută în aplicație — „citește rezervările, vezi dacă e liber, scrie” — merge perfect cu un singur utilizator. Cu doi care apasă simultan, ambii citesc „liber” înainte ca vreunul să scrie. Rezultatul e un teren vândut de două ori. Verificarea trebuie să stea în baza de date, ca o constrângere pe care baza o refuză ea însăși, nu ca un if în cod.
Al doilea lucru care ne-a dat bătăi de cap: ora de vară. În ultima duminică din octombrie, între 3 și 4 dimineața, ora se repetă, deci există două intervale distincte cu aceeași etichetă. Clubul nu are terenuri rezervate la 3 noaptea, așa că nu s-a manifestat în producție — dar rapoartele lunare pe octombrie ieșeau cu o oră în plus, până am stocat totul în timp absolut și am convertit doar la afișare.
Plățile, abonamentele și cei care nu se prezintă
Sunt trei feluri de bani în club și au nevoie de trei mecanisme diferite.
Rezervarea unică se plătește online sau în locație. La plata în locație, rezervarea e ținută, dar riscul e al clubului. Am pus un indicator în panou pentru cine are rezervări neplătite repetat — nu ca să blocheze automat, ci ca administratorul să decidă.
Abonamentul e o plată recurentă și tot ce ține de el se învârte în jurul unei singure date: până când e valid. Verificarea aia e apelată din aplicație, din panou și din terminal. Dacă logica ei ar fi duplicată în trei locuri, la prima schimbare de politică două ar rămâne în urmă.
Neprezentarea e cazul pe care nimeni nu îl cere în prima discuție și pe care îl cer toți după două luni. Un teren rezervat și neocupat e un teren pe care nu l-a putut lua altcineva. Sistemul îl marchează prin lipsa check-inului; ce face clubul cu informația aia e decizie comercială. Am construit evidența și am lăsat decizia la ei.
Terminalul din locație
Cea mai simplă aplicație din patru și cea care a avut cele mai multe surprize.
Prima: codul QR static, generat pe rezervare și valabil până la ora de început. A funcționat exact până când primul jucător a făcut o captură de ecran și a trimis-o unui prieten. Codul e acum dinamic, se reîmprospătează la câteva zeci de secunde și e legat de cont, nu doar de rezervare.
A doua: internetul din club. Într-o hală cu structură metalică, semnalul cade. Un terminal care nu poate valida offline blochează intrarea. Ține acum o copie locală a rezervărilor zilei și sincronizează când revine legătura, iar dacă cineva intră în fereastra fără legătură, check-inul pleacă mai târziu, cu ora reală, nu cu ora sincronizării.
A treia, cea mai banală: jucătorul vine cu rachetă, geantă și telefonul în buzunar. Ecranul trebuie să răspundă din prima, cu un singur gest. Am scos o casetă de confirmare care ni se păruse prudentă. Era doar în plus.
Ce a rămas mai greu decât părea
Nu partea tehnică. Partea de date vechi.
Clubul avea abonamente în desfășurare, cu date de început diferite, unele plătite în avans, unele negociate verbal. Nu există import automat pentru așa ceva. Cineva de la club a stat două zile și le-a trecut pe fiecare prin panou, iar noi am făcut o verificare care compara totalul din sistem cu evidența lor. Nu s-au potrivit din prima. Diferențele erau reale și existau dinainte de noi.
Asta e treaba cea mai puțin spectaculoasă dintr-un proiect ca ăsta și e singura care decide dacă sistemul e crezut în prima lună.
Dacă ai un club, o sală sau orice afacere unde același interval de timp poate fi vândut o singură dată, discuția e despre software la comandă — sau, dacă vrei doar partea de înscrieri și plăți recurente, despre Înscrie.ro, produsul nostru care face exact asta pentru cluburi și școli. Când vrei să vezi cum arată fluxul tău desenat pe o pagină, cere o radiografie.