README: ažurirani opisi funkcionalnosti i nove sekcije
- ispravljena Go verzija zahteva (1.24 -> 1.26, usklađeno sa go.mod) - dodate BE_ENABLED/BE_PORT env varijable - nova sekcija "Kako radi"/"How It Works" — arhitektura, tok zahteva, javne stranice za klijente, štampani dokumenti - nove sekcije Health Check, Testing, Security Notes, License - fiskalizacija prebačena iz "U toku" u "Implementirano" — bila je zastarela (opisivala kao "u planu" nešto što je u potpunosti implementirano i integrisano); "U toku" sada tačnije opisuje da nedostaje samo test na pravom sertifikovanom uređaju - eksplicitno pomenut QR kod + mobilno praćenje statusa servisa (ranije nejasno "putem jedinstvenog linka"), ispravljeno pogrešno pominjanje obaveštenja koja nisu implementirana - dodat EAN/barkod po artiklu i skeniranje barkoda u prodaji
This commit is contained in:
@@ -23,6 +23,22 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
**Server-rendered, no build step.** Pages are rendered on the server with Go's `html/template` (auto-escaping, no client-side templating engine). [HTMX](https://htmx.org) swaps page fragments over plain HTTP for SPA-like navigation, and [Alpine.js](https://alpinejs.dev) handles small bits of client-side interactivity (live totals, dynamic form rows, autocomplete). There is no `npm`/webpack build — the browser gets plain HTML/CSS/JS, and a single page load is enough to use the whole app.
|
||||||
|
|
||||||
|
**Single binary, no runtime dependencies.** Templates, static assets (CSS/JS/images) and SQL migrations are embedded into the compiled binary with `go:embed`. Deploying is copying one file (or running one Docker image) — there's no separate asset build, no template files to ship alongside the executable. In development the same code reads straight from disk instead, so template/CSS/JS edits are visible on refresh without a rebuild.
|
||||||
|
|
||||||
|
**Request flow.** `chi` routes each request through a middleware chain — security headers → CSRF (double-submit cookie) → session lookup → role/permission check — before it reaches a handler. Permission checks run at the router level (so a route can't accidentally ship unprotected) and again inside the handler as defense in depth. Handlers talk to the database through a repository layer (plain SQL, no ORM) and pass plain Go structs to templates.
|
||||||
|
|
||||||
|
**Database.** SQLite via a pure-Go driver (`modernc.org/sqlite`, no CGO) is the default and only dependency — a single file, no separate database server to run or back up. Every startup applies any new SQL migration files in order and records them in a `migracije` table, so upgrades are just "replace the binary and restart." An optional PostgreSQL backend (via `pgx/v5`) is planned for multi-user setups.
|
||||||
|
|
||||||
|
**Client-facing public pages.** Two flows don't require a login, only a unique unguessable token in the URL: the service-status page (a client can check repair progress and get a QR code straight from their receipt) and the parts/service proposal approval page (a client accepts or rejects an estimate with a comment). Both are capability-based — whoever has the link has access to that one order, nothing else.
|
||||||
|
|
||||||
|
**Printable documents.** Work orders, pre-invoices, dispatch notes, return slips, and device labels are separate, self-contained HTML pages styled for A4 printing (`@media print`), each with a "Print" button that opens the browser's native print dialog — no PDF library, no headless-browser rendering step. Documents that don't fit one page paginate themselves client-side (measuring content height and inserting page breaks with running page numbers).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Implemented
|
### Implemented
|
||||||
@@ -39,12 +55,13 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
- Login attempt logging — history by user, IP, reason, date
|
- Login attempt logging — history by user, IP, reason, date
|
||||||
- Users and roles — admin panel, user management
|
- Users and roles — admin panel, user management
|
||||||
- Inventory — items, categories, filtering, critical stock levels, per-item stock card, supplier links, item transfers
|
- Inventory — items, categories, filtering, critical stock levels, per-item stock card, supplier links, item transfers
|
||||||
|
- Barcode (EAN) per item — searchable by barcode in inventory; in the sales screen, scanning a barcode (any USB/Bluetooth scanner that types + Enter) looks the item up and adds it to the order automatically
|
||||||
- Service orders:
|
- Service orders:
|
||||||
- Intake form, status bar, archive
|
- Intake form, status bar, archive
|
||||||
- Diagnostic workflow — fault description, technician notes, work done, diagnostic fee
|
- Diagnostic workflow — fault description, technician notes, work done, diagnostic fee
|
||||||
- Parts and services — used items deducted from stock; suggested items (proposal to client)
|
- Parts and services — used items deducted from stock; suggested items (proposal to client)
|
||||||
- Client proposal approval — client receives a public link (QR code) to accept or reject a parts/service proposal with a comment
|
- Client proposal approval — client receives a public link (QR code) to accept or reject a parts/service proposal with a comment
|
||||||
- Public status page — client can check order status and receive notifications via a unique link
|
- Public status tracking via QR code — the device label and every printed document carry a QR code the client scans with their phone; it opens a mobile-optimized page (no login, no app) showing the current repair status, which they can revisit any time by the same link/code
|
||||||
- Documents — work order, pre-invoice (estimate), dispatch note, return slip, device label (QR + Code128 barcode)
|
- Documents — work order, pre-invoice (estimate), dispatch note, return slip, device label (QR + Code128 barcode)
|
||||||
- Pickup with payment — tracks payment method and advance amount
|
- Pickup with payment — tracks payment method and advance amount
|
||||||
- Guarantee period, expected completion date, technician assignment, client notes
|
- Guarantee period, expected completion date, technician assignment, client notes
|
||||||
@@ -58,6 +75,7 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
- VAT records (KIR/KPR) — books of issued and received invoices, auto-filled from sales and procurement
|
- VAT records (KIR/KPR) — books of issued and received invoices, auto-filled from sales and procurement
|
||||||
- VAT calculation per period + mapping to the PP-PDV form; imports (customs declaration) tracked in fields 006/106
|
- VAT calculation per period + mapping to the PP-PDV form; imports (customs declaration) tracked in fields 006/106
|
||||||
- VAT rate code list
|
- VAT rate code list
|
||||||
|
- **Fiscalization (ESIR/L-PFR)** — full Go client for the Teron fiscal device API: connection test, invoice issuing (sale/service, including advances and refunds on cancellation), daily till summary, end-of-day closure, PDF fiscal reports, QR-code invoice verification (public `/v/` page), automatic retry on failed fiscalization with a visible error state, and a card-emulator status/reset panel (talks to the signing device over TCP). Currently verified against the Teron mock server (`Fisk/`); not yet tested against real certified hardware.
|
||||||
- Clients and suppliers — contact database
|
- Clients and suppliers — contact database
|
||||||
- Reminders — records with deadlines
|
- Reminders — records with deadlines
|
||||||
- Reports — revenue overview, inventory status, inventory value report, stock movement list, stocktake (physical count)
|
- Reports — revenue overview, inventory status, inventory value report, stock movement list, stocktake (physical count)
|
||||||
@@ -74,7 +92,7 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
|
|
||||||
### In Progress
|
### In Progress
|
||||||
|
|
||||||
- **Fiscalization (ESIR/PFR)** — Teron L-PFR mock server included in `Fisk/`; Go client integration planned
|
- **Fiscalization on real hardware** — the full flow (issuing, refunds, daily till, closure, reports) is implemented and verified against the Teron mock server; testing against a real certified L-PFR device is still pending.
|
||||||
|
|
||||||
### Planned
|
### Planned
|
||||||
|
|
||||||
@@ -104,7 +122,7 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
- Go 1.24 or newer
|
- Go 1.26 or newer
|
||||||
- Git
|
- Git
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
@@ -158,6 +176,8 @@ The application reads environment variables on startup. In development, place th
|
|||||||
| `NTECH_DSN` | — | PostgreSQL connection string |
|
| `NTECH_DSN` | — | PostgreSQL connection string |
|
||||||
| `NTECH_SECRET` | — | Session signing key (min. 32 bytes); auto-generated if missing |
|
| `NTECH_SECRET` | — | Session signing key (min. 32 bytes); auto-generated if missing |
|
||||||
| `NTECH_TOTP_KEY` | — | AES-256 key for TOTP secret encryption; auto-generated if missing |
|
| `NTECH_TOTP_KEY` | — | AES-256 key for TOTP secret encryption; auto-generated if missing |
|
||||||
|
| `BE_ENABLED` | `true` | Enables the built-in card-emulator (fiscalization signing device) |
|
||||||
|
| `BE_PORT` | `4567` | TCP port for the built-in card-emulator |
|
||||||
|
|
||||||
`NTECH_SECRET` and `NTECH_TOTP_KEY` are generated automatically on the first run and saved to `ntech.env`. **Back this file up** — losing `NTECH_TOTP_KEY` invalidates all 2FA secrets stored in the database.
|
`NTECH_SECRET` and `NTECH_TOTP_KEY` are generated automatically on the first run and saved to `ntech.env`. **Back this file up** — losing `NTECH_TOTP_KEY` invalidates all 2FA secrets stored in the database.
|
||||||
|
|
||||||
@@ -323,6 +343,20 @@ Demo also requires HTTPS (Caddy or similar) because Secure cookies are enabled.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
|
||||||
|
The app exposes an unauthenticated `GET /healthz` endpoint that pings the database and returns `200 OK` (or `503` if the database is unreachable). Use it for a Docker `HEALTHCHECK` or a reverse-proxy/orchestrator liveness probe:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://localhost:8000/healthz"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -348,3 +382,34 @@ ntech/
|
|||||||
├── go.mod
|
├── go.mod
|
||||||
└── go.sum
|
└── go.sum
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
The project has unit and integration tests (against a real SQLite database) covering crypto, RBAC, login flows, form validators, and reports.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
Migrations are numbered SQL files (`migrations/NNN_description.sql`) applied in order at startup and tracked in a `migracije` table, so they run exactly once and are safe to ship inside the same binary.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- Sessions are server-side (random token in an `HttpOnly`, `SameSite=Strict` cookie), not JWT — revocation is immediate (delete the row).
|
||||||
|
- CSRF tokens and the card-emulator PIN are compared in constant time (`crypto/subtle`).
|
||||||
|
- Brute-force locking applies to both the password step and the TOTP/backup-code step, keyed by client IP.
|
||||||
|
- `X-Real-IP` / `X-Forwarded-For` are only trusted when the connection itself comes from a loopback or private address (i.e. a reverse proxy on the same host/Docker network) — otherwise the raw connection IP is used, so the header can't be spoofed from the internet to bypass the lockout.
|
||||||
|
- TOTP secrets are encrypted at rest (AES-256-GCM); the key (`NTECH_TOTP_KEY`) is kept outside the database.
|
||||||
|
- This is a single-tenant, single-organization application by design — there is no cross-tenant data isolation to reason about.
|
||||||
|
|
||||||
|
See [`SECURITY.md`](SECURITY.md) for how to report a vulnerability.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE) © Dalibor Marković
|
||||||
|
|||||||
+68
-3
@@ -23,6 +23,22 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Kako radi
|
||||||
|
|
||||||
|
**Serversko renderovanje, bez build koraka.** Stranice se renderuju na serveru preko Go-ovog `html/template` (automatski escape, bez klijentskog šablonskog engine-a). [HTMX](https://htmx.org) menja delove stranice preko običnog HTTP-a za SPA-nalik navigaciju, a [Alpine.js](https://alpinejs.dev) pokriva manje delove klijentske interaktivnosti (live zbirovi, dinamički redovi u formama, autocomplete). Nema `npm`/webpack build korak — brauzer dobija čist HTML/CSS/JS, i jedno učitavanje stranice je dovoljno da se koristi cela aplikacija.
|
||||||
|
|
||||||
|
**Jedan binarni fajl, bez runtime zavisnosti.** Šabloni, statika (CSS/JS/slike) i SQL migracije su ugrađeni u kompajlirani binarni fajl preko `go:embed`. Deployment znači kopiranje jednog fajla (ili pokretanje jednog Docker image-a) — nema odvojenog build-a statike, nema fajlova šablona koje treba nositi uz izvršni fajl. U razvojnom modu isti kod čita direktno sa diska, pa su izmene šablona/CSS/JS-a odmah vidljive posle osvežavanja stranice, bez rebuild-a.
|
||||||
|
|
||||||
|
**Tok zahteva.** `chi` ruter provlači svaki zahtev kroz lanac middleware-a — bezbednosni headeri → CSRF (double-submit cookie) → provera sesije → provera uloge/dozvole — pre nego što stigne do handlera. Provera dozvola se izvršava na nivou rutera (da ruta ne bi slučajno ostala nezaštićena) i ponovo unutar handlera kao dodatni sloj zaštite. Handleri komuniciraju sa bazom kroz repository sloj (čist SQL, bez ORM-a) i prosleđuju obične Go strukture šablonima.
|
||||||
|
|
||||||
|
**Baza podataka.** SQLite preko čistog Go drajvera (`modernc.org/sqlite`, bez CGO-a) je podrazumevana i jedina zavisnost — jedan fajl, bez odvojenog servera baze koji treba pokretati ili bekapovati. Svako pokretanje primeni sve nove SQL migracione fajlove po redu i upiše ih u tabelu `migracije`, pa je nadogradnja samo "zameni binarni fajl i restartuj". Opcioni PostgreSQL backend (preko `pgx/v5`) je planiran za višekorisnička okruženja.
|
||||||
|
|
||||||
|
**Javne stranice za klijente.** Dva toka ne zahtevaju prijavu, samo jedinstven token koji se ne može pogoditi u URL-u: stranica statusa servisa (klijent prati napredak popravke i dobija QR kod direktno sa reversa) i stranica odobravanja predloga delova/usluga (klijent prihvata ili odbija procenu uz komentar). Oba su capability-bazirana — ko god ima link ima pristup tom jednom nalogu, ničemu drugom.
|
||||||
|
|
||||||
|
**Štampani dokumenti.** Radni nalog, predračun, otpremnica, revers i nalepnica uređaja su zasebne, samostalne HTML stranice stilizovane za A4 štampu (`@media print`), svaka sa dugmetom „Štampaj" koje otvara nativni dijalog za štampu u brauzeru — bez PDF biblioteke, bez headless-browser koraka za renderovanje. Dokumenti koji ne stanu na jednu stranicu sami se paginiraju na strani klijenta (merenjem visine sadržaja i ubacivanjem prekida strane sa brojevima strana).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Funkcionalnosti
|
## Funkcionalnosti
|
||||||
|
|
||||||
### Implementirano
|
### Implementirano
|
||||||
@@ -39,12 +55,13 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
- Evidencija pokušaja prijave — istorija po korisniku, IP, razlog, datum
|
- Evidencija pokušaja prijave — istorija po korisniku, IP, razlog, datum
|
||||||
- Korisnici i uloge — admin panel, upravljanje korisnicima
|
- Korisnici i uloge — admin panel, upravljanje korisnicima
|
||||||
- Magacin — artikli, kategorije, filtriranje, kritični nivoi zaliha, magacinska kartica po artiklu, veza sa dobavljačima, premeštanje artikala
|
- Magacin — artikli, kategorije, filtriranje, kritični nivoi zaliha, magacinska kartica po artiklu, veza sa dobavljačima, premeštanje artikala
|
||||||
|
- Barkod (EAN) po artiklu — pretraživ u magacinu; na ekranu prodaje, skeniranje barkoda (bilo kojim USB/Bluetooth skenerom koji „kuca" kod + Enter) automatski pronalazi artikal i dodaje ga u nalog
|
||||||
- Servisni nalozi:
|
- Servisni nalozi:
|
||||||
- Forma prijema, statusna traka, arhiva
|
- Forma prijema, statusna traka, arhiva
|
||||||
- Tok dijagnostike — opis kvara, napomene servisera, urađeno, cena dijagnostike
|
- Tok dijagnostike — opis kvara, napomene servisera, urađeno, cena dijagnostike
|
||||||
- Delovi i radovi — ugrađeni artikli se skidaju sa lagera; predloženi artikli (ponuda klijentu)
|
- Delovi i radovi — ugrađeni artikli se skidaju sa lagera; predloženi artikli (ponuda klijentu)
|
||||||
- Odobravanje predloga — klijent dobija javni link (QR kod) da prihvati ili odbije predlog sa komentarom
|
- Odobravanje predloga — klijent dobija javni link (QR kod) da prihvati ili odbije predlog sa komentarom
|
||||||
- Javna statusna stranica — klijent prati status naloga putem jedinstvenog linka
|
- Praćenje statusa putem QR koda — nalepnica na uređaju i svaki štampani dokument nose QR kod koji klijent skenira telefonom; otvara se mobilno optimizovana stranica (bez prijave, bez aplikacije) sa trenutnim statusom popravke, kojoj klijent može ponovo da pristupi u bilo kom trenutku istim linkom/kodom
|
||||||
- Dokumenti — radni nalog, predračun, otpremnica, revers, nalepnica za uređaj (QR + Code128 barkod)
|
- Dokumenti — radni nalog, predračun, otpremnica, revers, nalepnica za uređaj (QR + Code128 barkod)
|
||||||
- Preuzimanje sa naplatom — način plaćanja i iznos avansa
|
- Preuzimanje sa naplatom — način plaćanja i iznos avansa
|
||||||
- Garancija, predviđen datum završetka, serviser, napomena klijentu
|
- Garancija, predviđen datum završetka, serviser, napomena klijentu
|
||||||
@@ -58,6 +75,7 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
- PDV evidencija (KIR/KPR) — knjige izdatih i primljenih računa, automatsko punjenje iz prodaje i nabavke
|
- PDV evidencija (KIR/KPR) — knjige izdatih i primljenih računa, automatsko punjenje iz prodaje i nabavke
|
||||||
- PDV obračun za period + mapiranje na obrazac PP-PDV; uvoz robe (JCI) se vodi u poljima 006/106
|
- PDV obračun za period + mapiranje na obrazac PP-PDV; uvoz robe (JCI) se vodi u poljima 006/106
|
||||||
- Šifarnik PDV stopa
|
- Šifarnik PDV stopa
|
||||||
|
- **Fiskalizacija (ESIR/L-PFR)** — pun Go klijent za Teron API fiskalnog uređaja: test konekcije, izdavanje računa (prodaja/servis, uključujući avanse i refund pri stornu), dnevni pazar, zaključenje fiskalnog dana, PDF fiskalni izveštaji, QR verifikacija računa (javna `/v/` stranica), automatski retry pri neuspešnoj fiskalizaciji sa vidljivim statusom greške, i panel za status/reset kartica-emulatora (komunicira sa uređajem za potpisivanje preko TCP-a). Trenutno provereno protiv Teron mock servera (`Fisk/`); nije još testirano na pravom sertifikovanom uređaju.
|
||||||
- Klijenti i dobavljači — baza kontakata
|
- Klijenti i dobavljači — baza kontakata
|
||||||
- Podsetnici — evidencija sa rokom
|
- Podsetnici — evidencija sa rokom
|
||||||
- Izveštaji — pregled prihoda, stanje magacina, vrednost zaliha, prometni list, popis (inventura)
|
- Izveštaji — pregled prihoda, stanje magacina, vrednost zaliha, prometni list, popis (inventura)
|
||||||
@@ -74,7 +92,7 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
|
|
||||||
### U toku
|
### U toku
|
||||||
|
|
||||||
- **Fiskalizacija (ESIR/PFR)** — Teron L-PFR mock server dostupan u `Fisk/`; integracija Go klijenta u planu
|
- **Fiskalizacija na pravom uređaju** — ceo tok (izdavanje, refund, dnevni pazar, zaključenje, izveštaji) je implementiran i proveren protiv Teron mock servera; testiranje na pravom sertifikovanom L-PFR uređaju još nije urađeno.
|
||||||
|
|
||||||
### Planirano
|
### Planirano
|
||||||
|
|
||||||
@@ -104,7 +122,7 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
|
|
||||||
### Zahtevi
|
### Zahtevi
|
||||||
|
|
||||||
- Go 1.24 ili noviji
|
- Go 1.26 ili noviji
|
||||||
- Git
|
- Git
|
||||||
|
|
||||||
### Koraci
|
### Koraci
|
||||||
@@ -158,6 +176,8 @@ Fajl `ntech.env` se **ne commituje** u Git.
|
|||||||
| `NTECH_DSN` | — | PostgreSQL connection string |
|
| `NTECH_DSN` | — | PostgreSQL connection string |
|
||||||
| `NTECH_SECRET` | — | Ključ za potpisivanje sesija (min. 32 bajta); auto-generiše se |
|
| `NTECH_SECRET` | — | Ključ za potpisivanje sesija (min. 32 bajta); auto-generiše se |
|
||||||
| `NTECH_TOTP_KEY` | — | AES-256 ključ za šifrovanje TOTP tajni; auto-generiše se |
|
| `NTECH_TOTP_KEY` | — | AES-256 ključ za šifrovanje TOTP tajni; auto-generiše se |
|
||||||
|
| `BE_ENABLED` | `true` | Uključuje ugrađeni kartica-emulator (uređaj za potpisivanje pri fiskalizaciji) |
|
||||||
|
| `BE_PORT` | `4567` | TCP port ugrađenog kartica-emulatora |
|
||||||
|
|
||||||
`NTECH_SECRET` i `NTECH_TOTP_KEY` se automatski generišu pri prvom pokretanju i upisuju u `ntech.env`. **Sačuvaj backup ovog fajla** — gubitak `NTECH_TOTP_KEY` onemogućuje prijavu svim korisnicima koji imaju 2FA.
|
`NTECH_SECRET` i `NTECH_TOTP_KEY` se automatski generišu pri prvom pokretanju i upisuju u `ntech.env`. **Sačuvaj backup ovog fajla** — gubitak `NTECH_TOTP_KEY` onemogućuje prijavu svim korisnicima koji imaju 2FA.
|
||||||
|
|
||||||
@@ -323,6 +343,20 @@ Demo takođe zahteva HTTPS (Caddy ili slično) jer su Secure kolačići uključe
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Health check
|
||||||
|
|
||||||
|
Aplikacija izlaže neautentifikovan `GET /healthz` endpoint koji proverava dostupnost baze i vraća `200 OK` (ili `503` ako baza nije dostupna). Koristiti za Docker `HEALTHCHECK` ili proveru živosti u reverse proxy-ju/orkestratoru:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://localhost:8000/healthz"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Struktura projekta
|
## Struktura projekta
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -348,3 +382,34 @@ ntech/
|
|||||||
├── go.mod
|
├── go.mod
|
||||||
└── go.sum
|
└── go.sum
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testiranje
|
||||||
|
|
||||||
|
Projekat ima jedinične i integracione testove (nad pravom SQLite bazom) koji pokrivaju kripto funkcije, RBAC, tokove prijave, validatore formi i izveštaje.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
Migracije su numerisani SQL fajlovi (`migrations/NNN_opis.sql`) koji se primenjuju redom pri pokretanju i prate se u tabeli `migracije` — izvršavaju se tačno jednom i bezbedno je da putuju unutar istog binarnog fajla.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bezbednosne napomene
|
||||||
|
|
||||||
|
- Sesije se čuvaju na serveru (nasumičan token u `HttpOnly`, `SameSite=Strict` kolačiću), ne JWT — opoziv je trenutan (brisanje reda).
|
||||||
|
- CSRF token i PIN kartica-emulatora se porede konstantno-vremenski (`crypto/subtle`).
|
||||||
|
- Bruteforce zaključavanje važi i za korak lozinke i za korak TOTP/rezervnog koda, po IP adresi klijenta.
|
||||||
|
- `X-Real-IP` / `X-Forwarded-For` se veruje samo kada sama konekcija dolazi sa loopback ili privatne adrese (tj. reverse proxy na istom hostu/Docker mreži) — inače se koristi sirovi IP konekcije, pa se header ne može lažirati sa interneta radi zaobilaženja zaključavanja.
|
||||||
|
- TOTP tajne su šifrovane u mirovanju (AES-256-GCM); ključ (`NTECH_TOTP_KEY`) se čuva van baze.
|
||||||
|
- Ovo je namerno jednokorisnička/jednoorganizaciona aplikacija — nema izolacije podataka između više firmi (multi-tenant) o kojoj treba brinuti.
|
||||||
|
|
||||||
|
Pogledaj [`SECURITY.md`](SECURITY.md) za način prijave bezbednosnog propusta.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Licenca
|
||||||
|
|
||||||
|
[MIT](LICENSE) © Dalibor Marković
|
||||||
|
|||||||
Reference in New Issue
Block a user