Commit Graph

129 Commits

Author SHA1 Message Date
Dasko 55375da5a9 Merge grane feature/nazad-link-poravnanje: ujednačen kompaktan .nazad-link 2026-06-13 09:45:32 +02:00
Dasko c204631d39 fix(css): .nazad-link kompaktan u flex-column kontejnerima
U .kolona (flex-column) se .nazad-link zbog default align-items:stretch
rastezao na punu širinu, što je sa novom staklenom pill-podlogom odudaralo
od kompaktnog izgleda na formama. Dodato align-self:flex-start — kompaktan
svuda, no-op u ne-flex roditeljima.
2026-06-13 09:45:32 +02:00
Dasko 9e351346cd Merge grane feature/vidljivost-pozadina: vidljivost elemenata preko pozadinske slike 2026-06-13 09:39:53 +02:00
Dasko 16a590150b fix(ui): vidljivost elemenata van kartica preko pozadinske slike
Glass override je davao svetli tekst i staklenu podlogu samo karticama,
tabelama i sidebaru — elementi van kartica (.nazad-link, .btn-sekundarno,
.btn-obrisi-ghost, checkbox-traka „Samo aktivni") i goli <div> napomene
(„maksimum N MB") ostajali su u prigušenoj boji i jedva se videli.

Dodata pravila u glass blok: pomenuti elementi dobijaju sopstvenu staklenu
pill-podlogu (poluprovidna + blur + svetli border + svetli tekst), pa se
vide bez obzira da li je slika tamna ili svetla. Napomene dobile klasu
.pomocni-tekst da ih override dohvati; checkbox-traka klasu .cek-filter.
2026-06-13 09:39:53 +02:00
Dasko 8c666e6979 Merge grane feature/kartica-hover-i-animiraj: hover na svim karticama + animiraj na nabavka-detalji 2026-06-13 09:21:34 +02:00
Dasko 62d786d86c fix(css): hover lift na svim karticama + animiraj na nabavka-detalji karticama
Hover lift (.kartica:hover translateY) nije radio na karticama sa .animiraj
jer je fadeInUp imao fill-mode both, koji forwards zaključa transform i
nadjača hover. Prebačeno na backwards: i dalje nema treperenja na ulazu, a
hover sad radi na svim karticama u programu.

Kartice „Stavke nabavke" i „Brisanje nabavke" u nabavka_detalji nisu imale
.animiraj (previd — stagger u <style> je predviđao tri kartice). Dodato, i
stagger pomeren na nth-child(2-4) jer je prvi child .kolone „Nazad" link.
2026-06-13 09:21:28 +02:00
Dasko 85ce46bb16 Merge grane feature/stagger-stranica: stagger kartica profila/podešavanja u main.css 2026-06-13 08:33:13 +02:00
Dasko d5b4c820f3 refactor(css): stagger kartica na stranicama profila/podešavanja na jedno mesto
Isti .animiraj:nth-child stagger (korak 0.06s) bio je dupliran u 7
template <style> blokova (admin_profil, admin_login_istorija, profil_tema,
podesavanja i 3 podstranice). Prebačen u main.css kao
.stranica-stack .animiraj:nth-child(N); descendant selektor čuva isto
ponašanje po neposrednom roditelju, a klasa .stranica-stack sprečava
curenje na ostatak programa. Sad radi i pod HTMX navigacijom, menja se
na jednom mestu.
2026-06-13 08:33:13 +02:00
Dasko dc6c04cf0a Merge grane feature/status-badge-konsolidacija: bedž statusa u main.css 2026-06-13 08:22:52 +02:00
Dasko ac9fadcdc2 refactor(css): bedž statusa servisa na jedno mesto u main.css
Status bedž (.status-badge i .status-* boje) je bio dupliran u
servis.html i servis_detalji.html sa sitnom razlikom u veličini.
Ujednačena veličina i prebačeno u main.css — sad se menja na jednom
mestu i radi pod HTMX navigacijom. Uklonjen i prazan <style> blok
iz magacin.html.
2026-06-13 08:22:47 +02:00
Dasko 720cea71ee Merge grane feature/stagger-kartice: stagger lista-kartica u main.css 2026-06-13 01:32:44 +02:00
Dasko 40ac5e4632 refactor(css): stagger mobilnih lista-kartica na jedno mesto u main.css
Mobilni parnjak prethodnog (tabele): 7 lista-kartica klasa (prodaja/servis/magacin/
pod/klijent/dobavljac/nabavka-kartica) imale su identičan :nth-child stagger
(0.06s korak do 5). Uvedeno jedno pravilo [class*="-kartice"] > .animiraj:nth-child
u main.css; uklonjeni per-page blokovi. Drugi tipovi kartica (detalji/forma/
dashboard/izvestaji) imaju svoj stagger i ostaju po strani.

4 strane (nabavke/klijenti/prodaja/dobavljaci) ostale prazan dodatni-css blok →
uklonjen. Bez HTML izmena u sadržaju; radi i pod HTMX-om. Animacija lista-kartica
se sada menja na JEDNOM mestu.
2026-06-13 01:32:44 +02:00
Dasko 40975904f6 Merge grane feature/stagger-tabele: stagger redova tabela u main.css 2026-06-13 01:26:09 +02:00
Dasko ff5f282981 refactor(css): stagger animacija redova tabela na jedno mesto u main.css
Svaka lista-strana je imala identičan tbody tr:nth-child stagger (0.04s korak do
10), samo sa drugim prefiksom klase (.prodaja-tabela, .servis-tabela...). Uvedeno
JEDNO univerzalno pravilo .tabela tbody tr:nth-child(1..10) u main.css (sve tabele
već imaju .tabela, redovi .animiraj). Uklonjeni per-page blokovi iz 10 strana
(uklj. duplikat .dozvole-tabela iz admin_dozvole — kopija ostaje u main.css).

Pogađa samo redove koji se animiraju; nije bilo HTML izmena. Bonus: sada radi i
pod HTMX navigacijom (page <style> blokovi se odbacuju sa <head>, main.css ostaje).
Animacija redova se sada menja na JEDNOM mestu.

Mobilni card stagger (.X-kartica:nth-child) je zaseban — ostaje za sledeći korak.
2026-06-13 01:26:09 +02:00
Dasko 87bc36ee31 Merge grane feature/animacije-konsolidacija: animacije poruka u main.css 2026-06-13 01:13:17 +02:00
Dasko 5f60964b7e refactor(css): animacije poruka iz dupliranih <style> u main.css
.poruka-animacija (10 fajlova) i .greska-animacija (7 fajlova) bile su identično
duplirane po stranicama; keyframes (slideDown/shake) su već bili u main.css.
Izdvojene klase u main.css uz keyframes, uklonjeni duplikati. Forma-strane
(dobavljac/podsetnik/magacin/servis_forma) ostale prazan dodatni-css blok →
uklonjen (base.html koristi {{block}} sa difoltom, pa je bezbedno izostaviti).

HTML class= upotrebe netaknute; build, handler testovi i parsiranje prolaze.
2026-06-13 01:11:50 +02:00
Dasko 9440740c61 Merge grane feature/toast-konsolidacija: toast sistem u main.css 2026-06-13 01:07:03 +02:00
Dasko ca6cd95c52 refactor(css): toast sistem iz dupliranih <style> blokova u main.css
Toast obaveštenja (.toast, .toast-greska, .toast-uspeh, .toast.nestaje,
@keyframes toastIn/Out) bila su identično duplirana u podesavanja.html i
podesavanja_opste.html. Izdvojeno jednom u main.css; uklonjeno iz oba <style>
bloka. Obe strane idu kroz base.html (učitavaju main.css), pa rade nepromenjeno.

Standalone .greska (prijava/totp_provera/setup) NAMERNO ostavljene — te strane
ne učitavaju main.css (samostalne, minimalne).
2026-06-13 01:07:03 +02:00
Dasko 490078164d Merge grane feature/btn-obrisi-ghost: ghost-obriši dugme na klasu 2026-06-13 01:02:37 +02:00
Dasko 60f1d757f3 refactor(css): ghost-obriši dugme na .btn-obrisi-ghost klasu
Nova klasa .btn-obrisi-ghost (providna pozadina, #fca5a5 ivica, #dc2626 tekst) —
ghost varijanta brisanja, drugačija od pune .btn-obrisi-malo. Zamenjeno 6 inline
pojava u: admin_korisnici, podesavanja (2x), podesavanja_sistem, podesavanja_izgled,
profil_tema. Mala veličina je default klase; srednje (7px 14px / radius 8px /
font 13px) dobile kontekstualni override. Dodat suptilan hover (ranije ga nije bilo).

Preostali #fca5a5 su error/toast poruke (.greska/.toast-greska) — nisu dugmad.
2026-06-13 01:02:37 +02:00
Dasko 50aeae2949 Merge grane feature/refaktor-layout: layout utili .kolona/.red-izmedju 2026-06-13 00:57:07 +02:00
Dasko 261dc52b32 refactor(css): layout utili .kolona i .red-izmedju
Nove utility klase: .kolona (display:flex;flex-direction:column) i .red-izmedju
(display:flex;justify-content:space-between) — struktura bez razmaka. Izdvojena
strukturna flex deklaracija iz 50 elemenata (32 kolona + 18 red-izmedju); gap/
margin ostaju kao kontekstualni override po instanci.

Visoko varirani page-header redovi (sa border-bottom/flex-wrap) ostavljeni —
jednokratni. Bez promene izgleda; šabloni parsiraju.
2026-06-13 00:57:07 +02:00
Dasko a33b426599 Merge grane feature/refaktor-tekst: sporedni tekst na .pomocni-tekst 2026-06-13 00:50:10 +02:00
Dasko 03e5e39dbb refactor(css): sporedni tekst na .pomocni-tekst klasu
39 inline elemenata (span/div) sa font-size:13px;color:var(--tekst-sporedni)
(identično postojećoj .pomocni-tekst) zamenjeno klasom; ukupno 40.

Razdelnici (border-bottom:0.5px na <tr>) NISU dirani: mešavina su thead redova
(redundantni — .tabela ih daje) i tbody data redova (gde je ivica separator i
POTREBNA), pa blanket-promena nije bezbedna. Naglašeni naslovi (font-weight:500;
color:glavni) imaju raznolik font-size (14/15/16/22px) — ne mapiraju se na jednu
klasu, ostavljeni.
2026-06-13 00:50:10 +02:00
Dasko b90bd7e779 Merge grane feature/refaktor-tabele: inline <table> na .tabela 2026-06-13 00:45:41 +02:00
Dasko d1d75fa8ac refactor(css): inline <table> na .tabela klasu
Tabele su koristile inline width:100%;border-collapse:collapse (identično .tabela).
21 tabela sada koristi .tabela (named tabele dobile ' tabela' uz postojeću klasu).
Preostale 2 imaju samo kontekstualni font-size:13px override.

th/td/thead-tr ostavljeni inline: th/td su kontekstualni (poravnanje/širina/boja
po koloni, raznoliki), a thead tr border je redundantan-ali-bezopasan (klasa daje
isti border:0.5px var(--ivica), inline ga samo nadjačava istom vrednošću).

Bez promene izgleda; šabloni parsiraju.
2026-06-13 00:45:41 +02:00
Dasko d573b30dd6 Merge grane feature/refaktor-forme: inline labele na .polje-labela 2026-06-13 00:07:19 +02:00
Dasko bdbb28566e refactor(css): inline labele forme na .polje-labela klasu
59 inline labela (font-size:13px; color:--tekst-sporedni; display:block;
margin-bottom:6px — identično .polje-labela) zamenjeno klasom; ukupno 67 labela
sada koristi .polje-labela. Inputi se već globalno stilizuju (main.css 635-679),
pa nije bilo punih inline input-stilova. Preostale labele (12px/4px, 8px, flex
checkbox/radio) su namerne varijante — ostavljene.

Bez promene izgleda. Napomena: redundantni inline width:100% na inputima (globalni
stil ga već postavlja) ostavljen za kasnije (bezbedno uklanjanje traži ciljanje
po elementu jer je width:100% legitiman na tabelama).
2026-06-13 00:07:13 +02:00
Dasko 6947a2e554 Merge grane feature/refaktor-dugmad: inline dugmad na .btn-* klase 2026-06-12 23:58:06 +02:00
Dasko 0c23b0d721 refactor(css): inline dugmad na semantičke .btn-* klase
Dodate klase .btn-opasno (puno crveno) i .btn-upozorenje (narandžasto/storno);
.btn-primarno-malo dobio cursor:pointer (nedostajao). Inline dugmad zamenjena
klasama u: admin_profil (lozinka/2FA/regeneriši/podesi/deaktiviraj), prodaja/
servis/nabavka_detalji (obriši/storno), servis (traži), magacin (premesti),
admin_login_istorija (nazad). Override-i tipa class=btn-primarno style=background
uklonjeni u korist .btn-opasno/.btn-upozorenje.

Ostala samo kontekstualna inline svojstva (width/align-self/veličina po instanci).
Bez promene izgleda — samo izdvajanje ponovljenog stila. Šabloni parsiraju.
2026-06-12 23:58:00 +02:00
Dasko eec9562995 Merge grane feature/rezervni-kodovi: rezervni (jednokratni) kodovi za 2FA 2026-06-12 23:44:22 +02:00
Dasko b112d46e4e feat(2fa): rezervni (jednokratni) kodovi za 2FA
Alternativa TOTP-u kada uređaj nije dostupan. Po CLAUDE.md specifikaciji:
10 kodova pri aktivaciji, čuvani kao bcrypt heš.

Backend:
- migracija 039 (tabela rezervni_kodovi, FK CASCADE)
- auth.GenerisiRezervneKodove (Crockford base32, XXXX-XXXX) + NormalizujRezervniKod
- RezervniKodoviRepository (Zameni/Iskoristi/BrojPreostalih/Obrisi) + SQLite impl
- žičenje u Handler (+ reinicijalizuj)

Prijava:
- VerifikujTotp prvo proba TOTP, pa rezervni kod (isto polje); kod je jednokratni
- totp_provera.html: input opušten (slova/crtica), napomena o rezervnom kodu

Profil:
- aktivacija generiše i prikazuje kodove JEDNOM; dugme Regeneriši; brojač preostalo X/10
- deaktivacija briše kodove

Testovi: auth (generisanje/format/normalizacija), repo (jednokratnost/regeneracija),
prijava rezervnim kodom end-to-end. Ukupno 36 test funkcija.
2026-06-12 23:44:09 +02:00
Dasko ba78f243c0 Merge grane feature/readme-azuriranje: ažuriran README 2026-06-12 23:19:13 +02:00
Dasko 799972ab74 docs(readme): ažuriran spisak funkcija (srpski i engleski)
Dodato/ispravljeno u oba README-a:
- TOTP: tajna šifrovana u bazi (AES-256-GCM) umesto netačne tvrdnje o rezervnim
  kodovima (nisu implementirani — premešteni u Planirano)
- RBAC: naglašeno sprovođenje provere na nivou ruta i u handlerima
- Backup: dodato vraćanje baze iz kopije (bezbedno, bez prekida rada)
- Dodato: strukturisano logovanje (slog) i automatski testovi
2026-06-12 23:19:07 +02:00
Dasko 5b4a3f50ad Merge grane feature/testovi-parseformu: testovi validatora forme 2026-06-12 23:12:56 +02:00
Dasko d545fad6d2 test: validatori forme (parseFormu*)
internal/handler/parseformu_test.go — tabelarni testovi za:
- parseFormuArtikla (naziv obavezan, negativna količina, neispravna cena)
- parseFormuKlijenta (fizičko/pravno obavezna polja, email, podrazumevani tip)
- parseFormuProdaje (bez stavki, količina 0, neispravan artikal, nesklad, validno)
- parseFormuNaloga (uređaj/opis obavezni, podrazumevani status)

Ukupno 32 test funkcije u repozitorijumu.
2026-06-12 23:12:56 +02:00
Dasko 850dc30856 Merge grane feature/testovi-prijava: integracioni testovi tokova prijave 2026-06-12 23:10:00 +02:00
Dasko 5da055a949 test: integracioni testovi tokova prijave
internal/handler/prijava_test.go — Handler nad privremenom SQLite bazom (prave
migracije), TemplatesFS na korenu repo-a za standalone render. Pokrivено:
- uspešna prijava (303 -> /dashboard + sesijski kolačić)
- pogrešna lozinka (greska=1, bez kolačića, zabeležen neuspeh)
- nepostojeći korisnik i neaktivan nalog (bez sesije)
- zaključavanje IP-a posle 5 neuspeha (ni ispravna lozinka ne daje sesiju)
- TOTP tok: prijava -> /prijava/totp -> validan kod -> /dashboard (potvrđeno)
- pogrešan TOTP kod (greska=1, sesija ostaje nepotvrđena)

Ukupno 28 test funkcija u repozitorijumu.
2026-06-12 23:09:55 +02:00
Dasko ff5e5b1602 Merge grane feature/izvestaj-repo: IzvestajRepository (dashboard/izveštaji) 2026-06-12 22:53:21 +02:00
Dasko 9aaafa2358 refactor(izvestaji): direktan SQL dashboard/izveštaja u IzvestajRepository
dashboard.go i izvestaji.go više ne sadrže direktan SQL — svih 12 upita
prebačeno u novi IzvestajRepository (internal/db/sqlite/izvestaj.go). Repo vraća
sirove redove (model.*Red tipovi), a handleri zadržavaju prezentaciju
(formatiranje datuma, boje tačaka, rang, sklapanje niza 12 meseci). Žičenje kroz
Handler.IzvestajRepo (+ reinicijalizuj).

Dobici: testabilnost (dodati integracioni testovi izvestaj_test.go) i put ka
Postgres-u bez prepravke handlera. dashboard.prihod provera ostaje u handleru.

Van obima: middleware/flash.go i backup VACUUM INTO (ne pripadaju repo sloju).
2026-06-12 22:53:15 +02:00
Dasko 53c06b6db4 Merge grane feature/slog-logovanje: strukturisano logovanje (log/slog) 2026-06-12 22:34:02 +02:00
Dasko b77a8857e6 refactor(log): prelazak sa log na log/slog (strukturisano logovanje)
Uveden podrazumevani slog logger u main.go (podesiLog): JSON u produkciji,
tekst u razvoju, nivo Info. Svih ~70 poziva log.Printf/Println/Fatalf zamenjeno
slog.Error/Warn/Info: greška se prosleđuje kao atribut "error", informativne
vrednosti kao imenovani atributi (port, broj, putanja...), Fatalf -> Error +
os.Exit(1). Upozorenja (inicijalizacija/čišćenje dozvola, migracija kolone) idu
kao slog.Warn.

Auth log (internal/auth/log.go) namerno NIJE diran — ostaje zaseban *log.Logger
u fail2ban formatu. (slog.SetDefault usput preusmerava i standardni log paket.)
2026-06-12 22:33:42 +02:00
Dasko 47fab264b5 Merge grane feature/testovi: prva grupa testova 2026-06-12 22:07:38 +02:00
Dasko 2fb7c2d529 test: prva grupa testova (kripto, model, RBAC, helperi, TOTP repo)
Dodati testovi pored koda:
- internal/model: CenaBezPdv/PdvIznos, Klijent.PunoIme, PreostaloZaNaplatu
- internal/middleware: ImaDozvolu matrica po ulogama + SveDozvole
- internal/handler: izvuciIP, parseOpcionuCenu, validnoImeBackupa (anti path-traversal)
- internal/db/sqlite: integracioni nad privremenom SQLite bazom + prave migracije
  (TOTP šifrovan u mirovanju, brisanje, ZasifrujPostojeceTotp + idempotentnost)

19 test funkcija, prolaze i sa -race. Dopunjava kripto_test.go iz ranije.
2026-06-12 22:07:32 +02:00
Dasko aa5cb62138 Merge grane feature/backup-gorutine-svez-db: pozadinske gorutine koriste svežu konekciju 2026-06-12 21:56:28 +02:00
Dasko 125fc4772a fix(backup): pozadinske gorutine koriste svežu konekciju posle obnove
Auto-backup i čišćenje sesija/pokušaja su koristili originalni db handle iz
main.go, koji posle obnove backupa (VratiBackup) ostaje zatvoren — gorutine bi
prestale da rade do restarta. Sada rade preko novog helpera h.SaBazom, koji pod
deljenim zaključavanjem prosleđuje trenutnu h.DB, pa vide zamenjenu konekciju.
Gorutine su premeštene da startuju posle kreiranja h. time.Sleep je van
zaključavanja da ne odlaže obnovu.
2026-06-12 21:56:17 +02:00
Dasko 70ddfb2476 Merge grane feature/backup-swap-lock: bezbedna zamena baze pri obnovi 2026-06-12 19:43:48 +02:00
Dasko 2dc2cf5245 fix(backup): bezbedna zamena baze pri obnovi (sync.RWMutex + drain)
Obnova backupa (VratiBackup) je menjala Handler.DB i repozitorijume bez
zaključavanja dok drugi zahtevi rade — data race i moguć upit nad zatvorenom
konekcijom. Uveden Handler.mu (sync.RWMutex): zahtevi drže deljeno zaključavanje
preko middleware-a ZakljucajCitanje, a sama zamena (close+copy+reopen+reinit)
uzima ekskluzivno zaključavanje u zasebnoj gorutini, pa sačeka da svi tekući
zahtevi završe (drain) pre zamene. Zasebna gorutina je nužna jer zahtev još
drži deljeno zaključavanje (inače deadlock).

Poznato ograničenje: pozadinske gorutine i dalje koriste stari db handle iz
main.go — zaseban slučaj za kasnije.
2026-06-12 19:43:40 +02:00
Dasko 4e40dd7296 Merge grane feature/rbac-ruter: RBAC zaštita mutacija na ruteru 2026-06-12 19:34:23 +02:00
Dasko 4c461522d3 feat(rbac): zaštita mutirajućih ruta na ruteru (RequireDozvolaMut)
Mutirajuće rute (POST + brisanja preko GET-a) više se ne oslanjaju samo na
ručnu proveru u handleru. Uvedena middleware RequireDozvolaMut koja na odbijanje
vraća 403 (za razliku od RequireDozvola koja redirektuje, a ostaje za GET
preglede). U main.go svaka mutacija je obmotana helperom doz("modul.akcija"),
pa je ruter sada garantovani sloj zaštite — zaboravljena provera u handleru ne
ostavlja endpoint nezaštićenim.

Mapiranje rute->dozvola izvučeno iz postojećih provera u handlerima. Ručne
provere (zahtevajDozvolu) zadržane kao odbrana u dubinu. Namerni izuzeci:
javne rute, /podsetnici/* (bez dozvole po dizajnu), /admin/* (RequireAdmin po
ulozi) i lične profil-akcije.
2026-06-12 19:34:16 +02:00