Rent-a-car back-office koji je više od deset godina radio na PHP-u 5.6, prepisan kao moderan multi-tenant SaaS — s desetljećem rezervacija, ugovora i dokumenata prenesenim bez ijednog zahtjeva korisniku da resetira lozinku. A onda odveden mnogo dalje nego što je stari sustav ikad mogao.
FlexiRent nije bio pokvaren. Desetljeće je svaki dan vodio stvarnu rent-a-car tvrtku. Samo je stajao na stacku s kojeg je svijet otišao — a to je teži problem od prepisivanja nečega što nitko ne koristi.
Uobičajen je pristup pročitati stari kod, pogađati poslovna pravila i isporučiti nešto što izgleda bolje, ali potiho griješi u detaljima. Korisnik to primijeti u drugom tjednu, kad ugovor ispiše krivi polog.
Desetljeće ponašanja u produkciji ne nalazi se u kodu. Ono je u rubnim slučajevima, zaobilaznim rješenjima i brojkama koje ljudi provjeravaju svako jutro. To je ono što prepisivanje mora prvo sačuvati.
FlexiRent nismo naslijedili od nekoga drugog. Izradio ga je LumiVerse, a zatim ga više od deset godina održavao u produkciji, dok ga je stvarni upravitelj voznog parka koristio svaki dan.
To je deset godina gledanja kako se posao stvarno odvija: koji se ekrani otvaraju prvi ujutro, koja polja uvijek ostaju prazna, što djelatnik radi kad se kombi u nedjelju vrati oštećen. Ništa od toga nigdje nije zapisano. Zato je prepisivanje moglo preskočiti fazu otkrivanja i krenuti ravno u izradu.
Pravilo koje je ovo učinilo sigurnim: mijenjaj tehnologiju ili mijenjaj proizvod, nikad oboje odjednom. Novi je sustav morao biti dokazivo istovjetan prije nego što je smio biti bolji.
Potpuna sigurnosna kopija produkcije, samo za čitanje: 2.855 datoteka, cijela baza, konfiguracija web poslužitelja. Živi poslužitelj nikad nije mijenjan. Svaka se kasnija odluka mogla provjeriti na zamrznutoj, provjerenoj kopiji.
PHP 5.6, Apache i MySQL zapakirani u Docker da naslijeđeni sustav radi na prijenosniku. Ne da ga se održi na životu — nego da postoji referentna izvedba za usporedbu, ekran po ekran, broj po broj.
Svaka tablica preslikana na ciljni entitet, svaka implicitna veza dokumentirana, svaki rizik popisan prije ijednog retka novog koda: JSON blobovi, neispravni nul-datumi, CSV dopuštenja, generator PDF-ova.
Vjerna replika na novom stacku — isti ekrani, isti brojevi, nijedna nova ideja — označena i zamrznuta kao točka povratka. Poboljšanja nisu bila dopuštena dok se ta verzija nije poklopila sa starom.
Iz MySQL-a u PostgreSQL: JSON blobovi normalizirani, dodani pravi strani ključevi, neispravni datumi pretvoreni. Zatim su automatske provjere integriteta između baza uspoređivale broj redaka i zapise s izvorom dok se nisu poklopili.
Zapisani postupak s povratkom na staro u svakoj fazi: zamrzni staru aplikaciju, ponovno migriraj svježe podatke, provjeri s brojkama prije zamrzavanja, pa prebaci. Uvježbavanje u cijelosti, bez diranja produkcije.
Naslijeđeni je sustav lozinke spremao kao bcrypt sažetke. Bcrypt je bcrypt — novi backend te iste sažetke provjerava izravno. Svaki je korisnik zadržao točno ono korisničko ime i lozinku koje je već imao. Bez e-mailova za resetiranje, bez poziva podršci i bez poruke „migrirali smo, evo Vaših novih podataka za prijavu". Datoteke iz starog sustava prenesene su na isti način: isti dokumenti, iste poveznice, i dalje se preuzimaju.
Ista poslovna pravila. Posve drukčiji temelj.
Vjerna je replika bila sigurnosni uvjet, a ne cilj. Kad su podaci bili dokazani, a stari sustav i dalje stajao kao točka povratka, novi se temelj počeo isplaćivati — mogućnostima koje PHP 5.6 nikad ne bi ponio.
Većina softvera za vozne parkove prikazuje prihod. Rentalica prikazuje ono što ostane. Svaki se trošak unosi jednom, s razdobljem — jednokratno, mjesečno ili godišnje — pa se raspoređuje po mjesecima koje stvarno pokriva i tereti vozilo koje ga je izazvalo. Leasing, AO i kasko, registracija, gume, servis i gorivo slijeću na pravi kombi.
Fotografirajte račun ili potvrdu s benzinske. Snimka se čita na licu mjesta, a zatim se izvlače iznos, datum, izdavatelj, OIB dobavljača, broj računa i registracijska oznaka, predlaže se kategorija troška i pronalazi vozilo. Uključujući hrvatski zapis decimala. Ništa se ne sprema dok čovjek ne potvrdi.
Pitajte na običnom hrvatskom koji putnički kombi mjesečno prijeđe najmanje kilometara i dobit ćete tri stvari: odgovor, tablicu iz koje je došao i točan upit koji ga je proizveo. Ništa nije skriveno iza oblačića za chat — korisnik može provjeriti rad prije nego što mu povjeruje.
Vozačke dozvole, osobne iskaznice, putovnice i prometne dozvole razvrstava i čita OCR servis na vlastitim poslužiteljima, pa snimke ostaju na Vašoj infrastrukturi. Strojno čitljive zone obrađuju se s ICAO kontrolnim znamenkama — čisto očitanje samo sebe potvrđuje.
Svaka priložena datoteka slijeće na jedno mjesto i pretraživa je po onome što u njoj piše, jer se izdvojeni tekst sprema uz datoteku. Tablica poveznica bilježi uz što je svaki dokument vezan — pa možete iz dokumenta natrag do njegova vozila, troška ili ugovora, i pronaći one koji nisu vezani ni uz što.
Jedan imenik za kupce, tvrtke i partnere, razvrstan grupama i oznakama. Svaki kontakt otvara cijeli profil: svaki najam, svaki ugovor, što još duguje, uz povezane zadatke i dokumente. Brojevi dozvola, kategorije i datumi isteka stoje na samom zapisu.
Popisi zadataka po osobi i zajednički za tim, svaki zadatak prikvačen uz vozilo, rezervaciju ili kupca na koje se odnosi, s nositeljem, prioritetom i rokom. Istek registracije, osiguranja i tehničkog pregleda sam podiže podsjetnik, a da se itko ne mora sjetiti pogledati.
Asistent koji piše upite nad živim poslovanjem vrijedan je povjerenja onoliko koliko i ono što stoji između njega i podataka. Ova se ograničenja provode u kodu i u PostgreSQL-u — a ne uljudno traže u promptu.
Svaka se generirana naredba raščlanjuje u sintaksno stablo i popisuje se svaka tablica koje se dotiče — uključujući one zakopane u podupitima i spojevima preko zareza. Sve izvan odobrenog skupa odbija se prije nego što dođe do baze. Računi djelatnika i sažeci lozinki trajno su izvan dosega.
Prije izvršavanja svaka se navedena tablica prepisuje u filtrirani pogled na retke tog korisnika, pa se neprecizan upit razrješava na prave podatke samom izvedbom, a ne dobrim ponašanjem. Zajednički tablični izrazi odbijaju se u startu — inače bi mogli redefinirati taj filtar.
Upiti se izvršavaju unutar transakcije samo za čitanje, s vremenskim ograničenjem naredbe i tvrdim ograničenjem broja redaka, a ta se transakcija uvijek poništava. Upis ne odbija modelova bolja prosudba — on se na toj vezi jednostavno ne može dogoditi.
Ako je softver koji vodi Vaše poslovanje star, nedokumentiran i prevažan da bi se smio pokvariti, to je problem koji rješavamo. Prvo istovjetnost, dokazano netaknuti podaci i prelazak koji se može poništiti.
Trenutačno smo popunjeni za nove razvojne projekte i embedded angažmane — pišite nam na tihomir.jauk@lumiverse.hr pa Vas kontaktiramo čim se oslobodimo. Zanima Vas neki od naših proizvoda — Tvrtko.ai, Moj Kolega, Titlomat i ostali? Oni su dostupni odmah — javite se i pomoći ćemo Vam da krenete.