Clone
1
Arhitektura
Dasko edited this page 2026-06-21 02:16:00 +02:00

Arhitektura

Struktura direktorijuma

ntech/
├── assets.go                 # //go:embed za migrations, web/static, web/templates
├── cmd/ntech/main.go         # ulazna tačka: ENV, FS izbor, migracije, ruter
├── go.mod                    # modul ntech, Go 1.26
├── internal/
│   ├── auth/                 # bcrypt, TOTP, generisanje tokena, auth log
│   │   ├── auth.go           # HashujLozinku, ProveriLozinku, TOTP operacije
│   │   └── log.go            # fail2ban-kompatibilan format loga
│   ├── config/               # Prvo pokretanje (setup wizard)
│   │   ├── firstrun.go       # JelPrvoPokretanje
│   │   └── setup.go          # PokreniSetup (poseban HTTP server)
│   ├── db/
│   │   ├── repository.go     # SVI interfejsi (ArtikalRepo, ServisRepo, ...)
│   │   ├── errors.go         # ErrNedovoljnoKolicine
│   │   └── sqlite/           # SQLite implementacije (28 fajlova)
│   ├── handler/              # HTTP handleri — jedan fajl po domenu (26)
│   ├── middleware/            # Auth, CSRF, RBAC, bezbednost, flash
│   └── model/                # Domenske strukture i konstante (19 fajlova)
├── migrations/               # 61 SQL migracija (001-061), idempotentne
└── web/
    ├── static/               # CSS, JS, slike + uploads/
    └── templates/            # Go html/template šabloni (komponente, stranice)

Slojevi i zavisnosti

main.go
  └─> handler/      → zna za: middleware, db (interfejsi), db/sqlite, model, auth
        └─> middleware/  → zna za: db/sqlite, model
        └─> db (interfejsi)  → implementira: db/sqlite/
              └─> model/   → ne zna ni za koga — čist domen, nula internih importa
        └─> auth/    → samostalan, ne zavisi od handler/db

Pravilo: model je list (nema unutrašnje zavisnosti). handler je koren — svi putevi vode kroz njega. Nijedan drugi sloj ne sme da uvozi handler.

Tok pokretanja programa

  1. MIME tipovi.jstext/javascript, .csstext/css
  2. godotenv.Load(ntech.env) — učitava ENV iz fajla
  3. auth.InitAuthLog() — auth log u fail2ban formatu
  4. Izbor fajl-sistema — disk-first za razvoj, embed za produkciju/demo
  5. Prvo pokretanje? → Setup Wizard na portu 8080
  6. Baza + migracijesql.Open("sqlite", ...), WAL mod, migracije redom
  7. Init seme — dozvole, TOTP ključ, bcrypt dummy hash, admin korisnik
  8. Chi ruter — middleware stack, rute sa RBAC omotačima
  9. http.ListenAndServe — server kreće

Middleware stack

Redosled na chi ruteru:

1. middleware.RequestID          # ID svakog zahteva
2. middleware.RealIP             # Prava IP iz X-Forwarded-For
3. middleware.Logger             # Slog logovanje
4. middleware.Recoverer          # panic → 500
5. middleware.Compress(5, gzip)  # GZip kompresija (nivo 5)
6. BezbednosniHeaderi            # CSP, HSTS, X-Frame-Options, ...
7. CSRF                          # Double-submit cookie obrazac
8. FlashPoruke                   # Flash poruke u template kontekstu
--- (javne rute) ---
9. RequireAuth                   # Sesija → korisnik u context
10. RequireDozvola / RequireDozvolaMut  # RBAC (zaštićene rute)

Repository obrazac

Handleri ne pišu SQL. Sva komunikacija sa bazom ide preko interfejsa definisanih u internal/db/repository.go.

Primer interfejsa:

// internal/db/repository.go
type ArtikalRepository interface {
    Lista(ctx context.Context, filter ArtikalFilter) ([]model.ArtikalSaKategorijom, error)
    DohvatiID(ctx context.Context, id int64) (*model.Artikal, error)
    Kreiraj(ctx context.Context, a *model.Artikal) (int64, error)
    Izmeni(ctx context.Context, a *model.Artikal) error
    Obrisi(ctx context.Context, id int64) error
    // ...
}

Implementacija:

// internal/db/sqlite/artikal.go
type ArtikalRepo struct { db *sql.DB }

func NoviArtikalRepo(db *sql.DB) *ArtikalRepo { ... }
func (r *ArtikalRepo) Lista(ctx context.Context, f db.ArtikalFilter) ([]model.ArtikalSaKategorijom, error) {
    // SELECT ... FROM artikli JOIN kategorije ...
}

Handler koristi interfejs:

// internal/handler/magacin.go
type MagacinHandler struct {
    Artikli    db.ArtikalRepository
    Kategorije db.KategorijaRepository
}

Ovakav dizajn omogućava:

  • Testiranje — mock-ovanje repozitorijuma
  • Zamenu baze — iste interfejse može implementirati PostgreSQL drajver
  • Jasne granice — handler ne zavisi od SQL dijalekta

Repozitorijumi (interfejsi)

Interfejs Domen
ArtikalRepository Artikli, kategorije, cene, dobavljači, arhiviranje
KategorijaRepository Kategorije artikala
PdvStopaRepository Šifarnik PDV stopa
DobavljacRepository Dobavljači
KlijentRepository Klijenti (firme i fizička lica)
ServisRepository Servisni nalozi, delovi, javni token
ProdajaRepository Prodajni nalozi i stavke
NabavkaRepository Nabavke, zavisni troškovi, nivelacije
MagacinRepository Stanje zaliha, prometne kartice
KorisniciRepository Korisnici i dozvole
SesijeRepository Server-side sesije
LoginIstorijaRepository Istorija prijava
PokusajiPrijaveRepository Brute-force evidencija
PodesavanjaRepository Sva sistemska podešavanja
PodsetniciRepository Podsetnici
PdvEvidencijaRepository PDV KIR/KPR evidencija
IzvestajRepository Izveštajni upiti
RezervniKodoviRepository Rezervni kodovi za 2FA

Handleri

Svaki handler je jedan Go fajl u internal/handler/:

Fajl Domen
admin.go Admin panel: korisnici, dozvole
dashboard.go Početna tabla sa statistikama
dobavljac.go CRUD dobavljača
izvestaji.go Izveštaji (promet, stanje, inventura, prihod)
kategorija.go CRUD kategorija
klijent.go CRUD klijenata, filteri
magacin.go Magacin — pregled, pretraga, korekcija
magacin_forma.go Forma za artikal
nabavka.go Nabavke, nivelacije
pdv_kir.go PDV KIR (knjiga izdatih računa)
pdv_kpr.go PDV KPR (knjiga primljenih računa)
pdv_obracun.go PDV obračun
pdv_stopa.go Šifarnik PDV stopa
podesavanja.go Sistemska podešavanja
podsetnici.go Podsetnici
prijava.go Prijava, odjava, TOTP, 2FA
prodaja.go Prodajni nalozi
profil.go Profil korisnika (lozinka, TOTP)
servis.go Servisni nalozi
handler.go Render helperi, Render, RenderStranicu
kes.go Keširanje šablona
utils.go Pomoćne funkcije (parsiranje, prikaz)

Frontend arhitektura

Frontend koristi tri biblioteke:

  • HTMX — navigacija bez punog reload-a (hx-get, hx-post, hx-target, hx-swap)
  • Alpine.js — reaktivnost na klijentu (x-data, x-show, x-model, x-bind)
  • Chart.js — grafikoni (dashboard, izveštaji)

Stilovi su organizovani u web/static/:

  • main.css — glavni stil (≈4000 linija)
  • glass.css — glassmorphism efekti
  • login.css — stilovi za prijavnu stranicu

Šabloni u web/templates/:

templates/
├── stranice/       # Kompletne stranice (dashboard.html, magacin.html, ...)
├── komponente/     # Deljive komponente (navbar.html, sidebar.html, modal.html)
├── teme/           # Varijacije tema
├── setup/          # Setup wizard
└── layout/         # Osnovni layout (base.html)

HTMX pravila

  • hx-select odbacuje <head> — stil koji mora da radi posle navigacije ide u main.css
  • hx-target sa #sadrzaj — glavni kontejner za dinamički sadržaj
  • hx-push-url — ažurira URL u adresnoj traci
  • hx-indicator — prikazuje loader tokom zahteva