Početna / Radovi
Chrono — Praćenje vremena i upravljanje odsustvima
Interni SaaS alat

ChronoPraćenje vremena i upravljanje odsustvima

Chrono je višestanarska aplikacija za praćenje vremena i upravljanje odsustvima — Laravel API iza Vue single-page aplikacije, gdje timovi bilježe sate po aktivnostima, traže i odobravaju odsustva te prepuštaju sustavu računanje datuma. Teški dijelovi nisu obrasci, nego pravila ispod njih: brojanje stvarnih radnih dana, održavanje svakog stanja odsustava usklađivim iz predznačenih transakcija te zaključavanje dovršenih razdoblja evidencije kako bi prošlost ostala prošlost.

Chrono je krenuo iz jednostavne frustracije: alati za evidenciju i odsustva ili pohranjuju stanja kao promjenjive brojače koji tiho odlaze u krivu vrijednost, ili tretiraju “pet dana slobodno” kao pet kalendarskih dana bez obzira na vikende i praznike. Stoga je projektna odluka ispod cijele aplikacije ta da se zanimljivi brojevi nikad ne pohranjuju — oni se računaju. Stanje odsustava je dodjela uvećana za predznačeni zbroj knjige transakcija. Trajanje odsustva je prolazak kroz raspon datuma koji preskače vikende i pravi skup neradnih dana. Oboje se može u svakom trenutku ponovno izvesti iz izvora, što ih čini revidiranima umjesto tajanstvenima.

Iznad te domenske jezgre sjedi prilično običan, namjerno dosadan oblik: Laravel 13 API osiguran Sanctumom i Vue 3 TypeScript SPA koji s njim komunicira preko TanStack Queryja, zapakiran kao instalabilna PWA. Višestanarska je od prve migracije — organizacije ograničavaju sve, uloge štite pristup, a ljudi se uvode kroz tokenizirane pozivnice s istekom. Doista mišljenima dijelovi — izračun radnih dana, mehanizam stanja i prijenosa, zaključavanje razdoblja te idempotentna predaja zasebnom servisu za tiketiranje — izolirani su u tankom sloju servisa, pa kontroleri ostaju tanki, a pravila ostaju ispitiva.

Živa okosnica — unos vremena, tijek odsustava, stanja i kalendar radnih dana — izgrađena je i radi s kraja na kraj. Sloj zaključavanja razdoblja modeliran je i migriran, uz provedbu koja se još uvijek povezuje u put pisanja.

UlogaDesign + full-stack
Godina2026
TehnologijeLaravel 13 · Vue 3 · TypeScript
PovršinaREST API + installable PWA
StatusIn active development
Chronoov ekran godišnjeg pregleda — kalendarska mreža evidentiranih sati po danu s osjenčanim vikendima i državnim praznicima, uz panel sa stanjem odsustava
Snimka uskoro
Unos vremena

Bilježenje sati na način na koji organizacija radi

Svaka organizacija bira kako njezini ljudi evidentiraju vrijeme — rasponi početka/kraja ili obična trajanja — a obrazac za unos i validacija prilagođavaju se tom načinu. Batch endpoint prihvaća cijeli tjedan unosa u jednom zahtjevu, pa klijent može spremiti mrežu u jednom prolazu.

  • Način rasponi ili trajanja po organizaciji
  • Pojedinačni i batch (/time-entries/batch) zapisi
  • Trajanja ograničena i validirana na strani poslužitelja
Snimka uskoro
Zahtjevi za odsustvo

Zatraži, odobri, oduzmi

Članovi prijavljuju odsustvo po vrsti odsustva za raspon datuma; administratori odobravaju ili odbijaju iz reda na razini cijele organizacije. Pri odobrenju sustav razvija raspon u stvarne radne dane i bilježi oduzimanje, pa se zahtjev i stanje nikad ne razilaze.

  • Tijek statusa s administratorskim pregledom na razini organizacije
  • Rasponi razvijeni u radne dane pri odobrenju
  • Podržani su i samostalni zapisi korištenja
Snimka uskoro
Stanja

Svako stanje je zbroj, a ne pohranjeni broj

Korisnikovo stanje za vrstu odsustva u godini jest godišnja dodjela uvećana za predznačeni zbroj svake transakcije odsustva — pripisi pozitivni, korištenje negativno. Ništa se ne mijenja na mjestu, pa se svako stanje može ponovno izvesti i revidirati iz povijesti transakcija.

  • Dodjela + zbroj predznačenih transakcija
  • Decimalni iznosi za pola dana
  • Prijenos s datumom isteka
Snimka uskoro
Kalendari

Radni dani, ne kalendarski dani

Kalkulator dana prolazi rasponom datuma preskačući vikende i svaki neradni dan koji se odnosi na korisnika — prilagođena zatvaranja njegove organizacije te državni praznici njegove zemlje, razriješeni preko koda zemlje. Ista mapa pokreće i oduzimanja i kalendarsko sučelje.

  • Neradni dani specifični za organizaciju i za zemlju
  • Praznici razriješeni po organizacijskom country_code
  • Jedan izvor istine za izračun i prikaz
Snimka uskoro
Administracija

Višestanarska od prve migracije

Svaki zapis ograničen je na organizaciju. Pristup je temeljen na ulogama, uvođenje teče kroz tokenizirane pozivnice s istekom, a zaključavanja razdoblja po organizaciji i mjesecu postoje za zamrzavanje predanih evidencija — s eksplicitnim zapisima otključavanja kada zatvoreno razdoblje opravdano treba ponovno otvoriti.

  • Ograničavanje na organizaciju + pristup temeljen na ulogama
  • Token pozivnice s prihvaćanjem + istekom
  • Zapisi zaključavanja / otključavanja razdoblja po organizacijskom mjesecu
Snimka uskoro
Integracija

Povratna informacija u aplikaciji postaje tiket

Povratna informacija predana u Chronou šalje se zasebnoj aplikaciji za tiketiranje (TickIt) putem autenticiranog HTTP poziva. Zahtjev nosi Idempotency-Key koji dostavlja klijent, pa ponovljeno slanje nikad ne može stvoriti duplicirani tiket među dvama sustavima.

  • Bearer-autenticirani POST između aplikacija
  • Idempotency-Key validiran pa proslijeđen od kraja do kraja
  • Greške veze i 5xx prikazane zasebno
Arhitektura

Konvencionalna podjela API/SPA, ali težina leži u tankom domenskom sloju između kontrolera i baze podataka — pravila datuma i stanja žive u servisima, a ne raspršena kroz endpointe.

Klijent
Vue 3 SPA / PWA
TypeScript komponente s TanStack Query za stanje poslužitelja i TanStack Table za mreže; shadcn-vue i Tailwind za sučelje; instalabilna kao PWA.
Aplikacija
Laravel REST API
56 ruta zaštićenih Sanctumom. Form requesti validiraju i prilagođavaju se po organizaciji; admin i super-admin middleware štite povlaštene radnje.
Domenska logika
Servisi za izračun
LeaveDaysCalculator, LeaveBalanceService i LeaveTransactionService vlasnici su pravila radnih dana, stanja i knjige; TicketingClient vlasnik je izlazne integracije.
Podaci
MariaDB preko Eloquenta
13 modela kroz 19 migracija — organizacije, korisnici, uloge, aktivnosti, unosi vremena te tablice dodjele / transakcija / neradnih dana odsustava koje servisi čitaju.
Riješeni izazovi
01

Brojanje radnog dana

Problem

"Koliko dana traje ovo odsustvo?" nema fiksni odgovor — ovisi o vikendima, vlastitim zatvaranjima organizacije i državnim praznicima zemlje u kojoj ta organizacija posluje. Pogrešan izračun tiho kvari svako stanje nizvodno.

Rješenje

Jedan LeaveDaysCalculator jednom razrješava primjenjive neradne dane — specifične za organizaciju plus državne praznike usklađene po kodu zemlje — pa zatim prolazi rasponom preskačući vikende i taj skup. Potpuno ista mapa hrani kalendarsko sučelje, pa se broj koji korisnik vidi i broj koji se oduzima računaju na isti način.

02

Stanja koja se uvijek usklađuju

Problem

Pohranjeni brojač "preostalih dana" odlazi u krivu vrijednost čim se propusti odobrenje, prilagodba ili ispravak, a nema načina objasniti kako je do toga došlo.

Rješenje

Stanja se nikad ne pohranjuju. Svako se računa kao godišnja dodjela uvećana za predznačeni zbroj svake transakcije odsustva za tog korisnika i vrstu, s decimalnim iznosima za pola dana. Knjiga je izvor istine, pa se svako stanje može ponovno izvesti i revidirati iz svoje povijesti.

03

Prijenos koji istječe

Problem

Dani preneseni iz prošle godine ne bi smjeli živjeti zauvijek — istječu na određeni datum, i samo dani koji još nisu iskorišteni trebaju i dalje vrijediti.

Rješenje

Prijenos se drži na dodjeli s datumom isteka; servis vraća nulu kada taj datum prođe, a inače obračunava preneseni iznos s godišnjim korištenjem tako da ostaju samo stvarno neiskorišteni dani — ograničeno tako da korištenje nikad ne može gurnuti vrijednost u negativno.

04

Idempotentni tiketi između aplikacija

Problem

Povratne informacije Chronoa hrane zasebni servis za tiketiranje preko mreže. Izgubljeni odgovor ili korisnikov dvostruki klik inače bi mogli prijaviti istu pritužbu dvaput, u sustavu koji Chrono ne posjeduje.

Rješenje

Endpoint za povratne informacije zahtijeva Idempotency-Key (validiran u strogi format), a zatim ga prosljeđuje kao zaglavlje na Bearer-autenticiranom POST-u prema TickIt-ovom integracijskom API-ju. Ponovljeni pokušaji koriste isti ključ, pa primateljska strana može sažeti duplikate; greške veze i 5xx odgovori podižu se kao zasebne, ponovljive greške umjesto da se progutaju.

Kako je izrađeno
API i autentikacija
PHP 8.3, Laravel 13, Sanctum, MariaDB
Single-page klijent
Vue 3, TypeScript, Pinia, TanStack Query, TanStack Table, shadcn-vue
Build i isporuka
Vite, Tailwind CSS, PWA

Obrasci na vrhu, knjiga i kalendar ispod — i disciplina da svaki broj bude reproducibilan iz svojeg izvora.