Dokumentacija: ažurirani README, dodata start.sh skripta

- Readme.md i Readme_sr.md prošireni: demo mod, Docker uputstvo
  za produkciju i demo, promenljive okruženja (NTECH_SECRET,
  NTECH_TOTP_KEY), start.sh u strukturi projekta
- start.sh dodata u repozitorijum (uklonjena iz .git/info/exclude)
This commit is contained in:
2026-06-19 02:33:00 +02:00
parent b1bbe12734
commit fa1d6d4927
3 changed files with 443 additions and 31 deletions
+139 -6
View File
@@ -58,6 +58,7 @@ The goal is simple: everything the repair shop needs to track is located in one
- Charts — monthly revenue on reports (Chart.js) - Charts — monthly revenue on reports (Chart.js)
- Structured logging — `log/slog` (JSON in production, text in development); separate auth log in fail2ban format - Structured logging — `log/slog` (JSON in production, text in development); separate auth log in fail2ban format
- Automated tests — unit and integration over a SQLite database (crypto, RBAC, login flows, form validators, reports) - Automated tests — unit and integration over a SQLite database (crypto, RBAC, login flows, form validators, reports)
- **Demo mode** (`NTECH_ENV=demo`) — auto-created demo user, pre-filled login form, restricted backup count, blocked password/2FA changes
### Planned ### Planned
@@ -97,11 +98,143 @@ The goal is simple: everything the repair shop needs to track is located in one
git clone <repository-url> git clone <repository-url>
cd GoNtech cd GoNtech
# 2. Copy the configuration file # 2. Run in development mode (reads files from disk, no HTTPS required)
cp ntech.env.example ntech.env
# Open ntech.env and set the values (see the table below)
# 3. Load environment variables and run in the development environment
export $(grep -v '^#' ntech.env | xargs)
go run ./cmd/ntech go run ./cmd/ntech
``` ```
The application opens at `http://localhost:8080`. On first run the setup wizard starts automatically.
### Production Build
Use the interactive build script:
```bash
./start.sh
```
It asks for the version, environment (production/development), platform (Linux/Windows/both), optional UPX compression, and whether to push a Docker image to Gitea and GitHub Container Registry.
Or build manually:
```bash
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags "-X main.Verzija=1.0.0 -s -w" \
-trimpath \
-o ntech ./cmd/ntech
```
The result is a single static binary with no external dependencies.
---
## Environment Variables
The application reads environment variables on startup. In development, place them in `ntech.env` alongside the SQLite database file. In production/demo the program creates `ntech.env` automatically in the same directory as the database.
`ntech.env` is **never committed** to Git.
| Variable | Default | Description |
| ---------------- | ------------- | ----------------------------------------------------------------- |
| `NTECH_ENV` | `development` | Mode: `development`, `production`, or `demo` |
| `NTECH_PORT` | `8080` | HTTP port |
| `NTECH_DB` | `sqlite` | Database type: `sqlite` or `postgres` |
| `NTECH_SQLITE` | `ntech.db` | Path to the SQLite file |
| `NTECH_DSN` | — | PostgreSQL connection string |
| `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_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.
---
## Docker Deployment
Docker images are published to:
- `ghcr.io/dalibor31/ntech:latest`
- `git.vm-net.in.rs/dasko/ntech:latest`
### Production
```yaml
# docker-compose.yml
services:
ntech:
image: ghcr.io/dalibor31/ntech:latest
restart: unless-stopped
environment:
NTECH_ENV: production
NTECH_PORT: "8000"
NTECH_SQLITE: /app/data/ntech.db
volumes:
- ./data:/app/data # database + ntech.env (secrets)
- ./uploads:/app/uploads # uploaded images
- ./logs:/app/logs # structured + auth logs
- ./backups:/app/backups # automatic database backups
ports:
- "8000:8000"
```
On the **first start** the setup wizard runs and creates the first admin user. After that, `./data/ntech.env` contains the auto-generated secrets — **back it up**.
Place the app behind a reverse proxy (Caddy, nginx) that terminates HTTPS. Secure cookies require HTTPS.
Example Caddy config:
```
your.domain.com {
reverse_proxy ntech:8000
}
```
### Demo Mode
Demo mode runs a fully functional copy with a pre-created `Demo` / `Demo1234` admin account. Password and 2FA changes are blocked. Backup is limited to 2 copies.
```yaml
# docker-compose.yml (demo)
services:
ntech-demo:
image: ghcr.io/dalibor31/ntech:latest
restart: unless-stopped
environment:
NTECH_ENV: demo
NTECH_PORT: "8000"
NTECH_SQLITE: /app/data/ntech.db
volumes:
- ./data:/app/data
- ./uploads:/app/uploads
- ./logs:/app/logs
- ./backups:/app/backups
ports:
- "8000:8000"
```
Demo also requires HTTPS (Caddy or similar) because Secure cookies are enabled.
---
## Project Structure
```
ntech/
├── cmd/
│ └── ntech/ # entry point
├── internal/
│ ├── auth/ # login, sessions, fail2ban log
│ ├── config/ # settings, setup wizard
│ ├── db/ # database layer
│ │ └── sqlite/ # SQLite implementation
│ ├── handler/ # HTTP handlers
│ ├── middleware/ # CSRF, security headers, authentication
│ └── model/ # shared data types
├── web/
│ ├── static/ # CSS, JavaScript, images, logos
│ └── templates/ # HTML templates
├── migrations/ # SQL migrations (001_desc.sql, 002_desc.sql, ...)
├── logs/ # auth.log and other logs
├── backups/ # database backups
├── start.sh # interactive build and Docker push script
├── Dockerfile
├── go.mod
└── go.sum
```
+97 -25
View File
@@ -58,6 +58,7 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
- Grafikoni — mesečni prihod na izveštajima (Chart.js) - Grafikoni — mesečni prihod na izveštajima (Chart.js)
- Strukturisano logovanje — `log/slog` (JSON u produkciji, tekst u razvoju); zaseban auth log u fail2ban formatu - Strukturisano logovanje — `log/slog` (JSON u produkciji, tekst u razvoju); zaseban auth log u fail2ban formatu
- Automatski testovi — jedinični i integracioni nad SQLite bazom (kripto, RBAC, tokovi prijave, validatori forme, izveštaji) - Automatski testovi — jedinični i integracioni nad SQLite bazom (kripto, RBAC, tokovi prijave, validatori forme, izveštaji)
- **Demo mod** (`NTECH_ENV=demo`) — automatski kreiran demo korisnik, pre-popunjeni login, ograničen bekap, blokirana promena lozinke i 2FA
### Planirano ### Planirano
@@ -97,30 +98,29 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
git clone <url-repozitorijuma> git clone <url-repozitorijuma>
cd GoNtech cd GoNtech
# 2. Kopiranje konfiguracionog fajla # 2. Pokretanje u razvojnom modu (čita fajlove sa diska, ne zahteva HTTPS)
cp ntech.env.example ntech.env
# Otvori ntech.env i postavi vrednosti (videti tabelu ispod)
# 3. Učitavanje promenljivih i pokretanje u razvojnom okruženju
export $(grep -v '^#' ntech.env | xargs)
go run ./cmd/ntech go run ./cmd/ntech
``` ```
Program se otvara na `http://localhost:8080` (ili na portu definisanom u `ntech.env`). Program se otvara na `http://localhost:8080`. Pri prvom pokretanju automatski se pokreće setup wizard.
Pri prvom pokretanju automatski se pokreće setup wizard.
### Produkcioni build ### Produkcioni build
```bash Koristi interaktivnu skriptu:
# Pomoću build.sh skripte (prima opcioni argument verzije)
./build.sh 1.0.0
# Ili ručno ```bash
CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build \ ./start.sh
```
Skripta pita za verziju, okruženje (production/development), platformu (Linux/Windows/obe), opcionalnu UPX kompresiju i da li da gurne Docker image na Gitea i GitHub Container Registry.
Ili ručno:
```bash
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags "-X main.Verzija=1.0.0 -s -w" \ -ldflags "-X main.Verzija=1.0.0 -s -w" \
-trimpath \
-o ntech ./cmd/ntech -o ntech ./cmd/ntech
./ntech
``` ```
Rezultat je jedan statički binarni fajl bez zavisnosti. Rezultat je jedan statički binarni fajl bez zavisnosti.
@@ -129,15 +129,87 @@ Rezultat je jedan statički binarni fajl bez zavisnosti.
## Promenljive okruženja ## Promenljive okruženja
Kopirati `ntech.env.example` u `ntech.env` i popuniti vrednosti. Fajl `ntech.env` se **ne commituje** u Git. Program čita promenljive okruženja pri pokretanju. U razvojnom modu staviti ih u `ntech.env` pored SQLite baze. U production/demo modu program sam kreira `ntech.env` u istom folderu gde je baza.
| Promenljiva | Podrazumevano | Opis | Fajl `ntech.env` se **ne commituje** u Git.
| -------------- | ------------- | -------------------------------------------- |
| `NTECH_ENV` | `development` | Okruženje: `development` ili `production` | | Promenljiva | Podrazumevano | Opis |
| `NTECH_PORT` | `8080` | HTTP port | | ---------------- | ------------- | ------------------------------------------------------------------ |
| `NTECH_DB` | `sqlite` | Tip baze: `sqlite` ili `postgres` | | `NTECH_ENV` | `development` | Mod: `development`, `production` ili `demo` |
| `NTECH_SQLITE` | `ntech.db` | Putanja do SQLite fajla | | `NTECH_PORT` | `8080` | HTTP port |
| `NTECH_DSN` | — | PostgreSQL connection string | | `NTECH_DB` | `sqlite` | Tip baze: `sqlite` ili `postgres` |
| `NTECH_SQLITE` | `ntech.db` | Putanja do SQLite fajla |
| `NTECH_DSN` | — | PostgreSQL connection string |
| `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_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.
---
## Docker deployment
Docker image je dostupan na:
- `ghcr.io/dalibor31/ntech:latest`
- `git.vm-net.in.rs/dasko/ntech:latest`
### Produkcija
```yaml
# docker-compose.yml
services:
ntech:
image: ghcr.io/dalibor31/ntech:latest
restart: unless-stopped
environment:
NTECH_ENV: production
NTECH_PORT: "8000"
NTECH_SQLITE: /app/data/ntech.db
volumes:
- ./data:/app/data # baza + ntech.env (tajne)
- ./uploads:/app/uploads # uploadovane slike
- ./logs:/app/logs # strukturisani + auth log
- ./backups:/app/backups # automatski bekap baze
ports:
- "8000:8000"
```
Pri **prvom pokretanju** pokreće se setup wizard za kreiranje prvog admin korisnika. Nakon toga, `./data/ntech.env` sadrži auto-generisane tajne — **sačuvaj backup**.
Stavi program iza reverznog proksija (Caddy, nginx) koji terminira HTTPS. Secure kolačići zahtevaju HTTPS.
Primer Caddy konfiguracije:
```
tvoj.domen.com {
reverse_proxy ntech:8000
}
```
### Demo mod
Demo mod pokreće potpuno funkcionalnu kopiju sa pre-kreiranim nalogom `Demo` / `Demo1234` (admin). Promena lozinke i 2FA su blokirani. Bekap je ograničen na 2 kopije.
```yaml
# docker-compose.yml (demo)
services:
ntech-demo:
image: ghcr.io/dalibor31/ntech:latest
restart: unless-stopped
environment:
NTECH_ENV: demo
NTECH_PORT: "8000"
NTECH_SQLITE: /app/data/ntech.db
volumes:
- ./data:/app/data
- ./uploads:/app/uploads
- ./logs:/app/logs
- ./backups:/app/backups
ports:
- "8000:8000"
```
Demo takođe zahteva HTTPS (Caddy ili slično) jer su Secure kolačići uključeni.
--- ---
@@ -161,8 +233,8 @@ ntech/
├── migrations/ # SQL migracije (001_opis.sql, 002_opis.sql, ...) ├── migrations/ # SQL migracije (001_opis.sql, 002_opis.sql, ...)
├── logs/ # auth.log i ostali logovi ├── logs/ # auth.log i ostali logovi
├── backups/ # rezervne kopije baze ├── backups/ # rezervne kopije baze
├── build.sh # skripta za produkcioni build ├── start.sh # interaktivna skripta za build i Docker push
├── ntech.env # lokalna konfiguracija (ne commituje se) ├── Dockerfile
├── go.mod ├── go.mod
└── go.sum └── go.sum
``` ```
Executable
+207
View File
@@ -0,0 +1,207 @@
#!/bin/bash
set -e
GITEA_IMAGE="git.vm-net.in.rs/dasko/ntech"
GITHUB_IMAGE="ghcr.io/dalibor31/ntech"
VER_FAJL="VERSION"
clear
echo "╔══════════════════════════════════════╗"
echo "║ NTech — Build alat ║"
echo "╚══════════════════════════════════════╝"
echo ""
# 1. Verzija
VERZIJA_DEFAULT=$(cat "$VER_FAJL" 2>/dev/null || echo "0.0.0")
read -p "1) Verzija [${VERZIJA_DEFAULT}]: " VERZIJA
VERZIJA="${VERZIJA:-$VERZIJA_DEFAULT}"
if [ "$VERZIJA" != "$VERZIJA_DEFAULT" ]; then
echo "$VERZIJA" > "$VER_FAJL"
echo " → VERSION ažuriran na: $VERZIJA"
fi
echo ""
# 2. Okruženje
echo "2) Okruženje:"
echo " 1) Production (podrazumevano)"
echo " 2) Development"
read -p " Izbor [1/2]: " OKR_IZBOR
OKR_IZBOR="${OKR_IZBOR:-1}"
echo ""
# 3. Platforma
echo "3) Platforma:"
echo " 1) Linux (podrazumevano)"
echo " 2) Windows"
echo " 3) Obe"
read -p " Izbor [1/2/3]: " PLATFORMA_IZBOR
PLATFORMA_IZBOR="${PLATFORMA_IZBOR:-1}"
echo ""
# 4. UPX
read -p "4) Kompresovati UPX-om? [d/N]: " UPX_IZBOR
UPX_IZBOR="${UPX_IZBOR:-n}"
echo ""
# 5. Build
read -p "5) Pokrenuti build? [D/n]: " BUILD_IZBOR
BUILD_IZBOR="${BUILD_IZBOR:-d}"
echo ""
# 6. Docker push
read -p "6) Push Docker image (Gitea + GitHub)? [d/N]: " DOCKER_IZBOR
DOCKER_IZBOR="${DOCKER_IZBOR:-n}"
echo ""
# ── Izračunaj vrednosti ──────────────────────────
if [ "$OKR_IZBOR" = "2" ]; then
OKRUZENJE="development"
VERZIJA_BUILD="dev-${VERZIJA}"
LDFLAGS="-X main.Verzija=dev-${VERZIJA}"
TRIMPATH=""
else
OKRUZENJE="production"
VERZIJA_BUILD="${VERZIJA}"
LDFLAGS="-X main.Verzija=${VERZIJA} -s -w"
TRIMPATH="-trimpath"
fi
case "$PLATFORMA_IZBOR" in
2) PLATFORMA_NAZIV="Windows" ;;
3) PLATFORMA_NAZIV="Linux + Windows" ;;
*) PLATFORMA_NAZIV="Linux" ;;
esac
if [[ "$UPX_IZBOR" =~ ^[dDyY] ]]; then UPX_NAZIV="da"; else UPX_NAZIV="ne"; fi
if [[ "$BUILD_IZBOR" =~ ^[dDyY] ]]; then BUILD_NAZIV="da"; else BUILD_NAZIV="ne"; fi
if [[ "$DOCKER_IZBOR" =~ ^[dDyY] ]]; then DOCKER_NAZIV="da"; else DOCKER_NAZIV="ne"; fi
# ── Sažetak ──────────────────────────────────────
echo "──────────────────────────────────────────"
echo " Verzija : ${VERZIJA_BUILD}"
echo " Okruženje : ${OKRUZENJE}"
echo " Platforma : ${PLATFORMA_NAZIV}"
echo " UPX : ${UPX_NAZIV}"
echo " Build : ${BUILD_NAZIV}"
echo " Docker : ${DOCKER_NAZIV}"
echo "──────────────────────────────────────────"
echo ""
read -p "Pokrenuti? [D/n]: " POTVRDA
POTVRDA="${POTVRDA:-d}"
if [[ ! "$POTVRDA" =~ ^[dDyY] ]]; then
echo "Otkazano."
exit 0
fi
echo ""
# ── UPX: instaliraj ako treba ────────────────────
if [[ "$UPX_IZBOR" =~ ^[dDyY] ]] && [[ "$BUILD_IZBOR" =~ ^[dDyY] ]]; then
if ! command -v upx &>/dev/null; then
echo "→ UPX nije instaliran. Instaliram..."
if command -v apt-get &>/dev/null; then
sudo apt-get install -y upx
elif command -v dnf &>/dev/null; then
sudo dnf install -y upx
elif command -v pacman &>/dev/null; then
sudo pacman -S --noconfirm upx
elif command -v brew &>/dev/null; then
brew install upx
else
echo " UPOZORENJE: Ne mogu da instaliram UPX — nepoznat menadžer paketa. Kompresija preskočena."
UPX_IZBOR="n"
fi
echo ""
fi
fi
# ── Build funkcija ───────────────────────────────
build_za() {
local GOOS_VAL="$1"
local NAZIV="$2"
echo "→ Build ${GOOS_VAL}/amd64: ${NAZIV}"
CGO_ENABLED=0 GOOS="${GOOS_VAL}" GOARCH=amd64 go build \
-ldflags "${LDFLAGS}" \
${TRIMPATH} \
-o "${NAZIV}" \
./cmd/ntech
ls -lh "${NAZIV}"
if [[ "$UPX_IZBOR" =~ ^[dDyY] ]] && command -v upx &>/dev/null; then
echo " Kompresovanje sa UPX..."
upx --best "${NAZIV}"
ls -lh "${NAZIV}"
fi
}
# ── 5. Build ─────────────────────────────────────
if [[ "$BUILD_IZBOR" =~ ^[dDyY] ]]; then
echo "=== Build ==="
case "$PLATFORMA_IZBOR" in
2)
build_za "windows" "ntech.exe"
;;
3)
build_za "linux" "ntech" &
PID_LINUX=$!
build_za "windows" "ntech.exe" &
PID_WIN=$!
wait $PID_LINUX $PID_WIN
;;
*)
build_za "linux" "ntech"
;;
esac
echo ""
fi
# ── 6. Docker push ───────────────────────────────
if [[ "$DOCKER_IZBOR" =~ ^[dDyY] ]]; then
echo "=== Docker ==="
# Ako Linux binary nije izgrađen u ovom pozivu (build=ne ili platforma=Windows), izgradi ga
LINUX_VEC_IZGRADJEN=0
if [[ "$BUILD_IZBOR" =~ ^[dDyY] ]] && [ "$PLATFORMA_IZBOR" != "2" ]; then
LINUX_VEC_IZGRADJEN=1
fi
if [ "$LINUX_VEC_IZGRADJEN" = "0" ]; then
echo "→ Gradim Linux binary za Docker (sa UPX ako je uključen)..."
# instaliraj UPX ako treba, a još nije instaliran
if [[ "$UPX_IZBOR" =~ ^[dDyY] ]] && ! command -v upx &>/dev/null; then
echo "→ UPX nije instaliran. Instaliram..."
if command -v apt-get &>/dev/null; then
sudo apt-get install -y upx
elif command -v dnf &>/dev/null; then
sudo dnf install -y upx
elif command -v pacman &>/dev/null; then
sudo pacman -S --noconfirm upx
elif command -v brew &>/dev/null; then
brew install upx
else
echo " UPOZORENJE: Ne mogu da instaliram UPX — kompresija preskočena."
UPX_IZBOR="n"
fi
fi
build_za "linux" "ntech"
echo ""
fi
echo "→ Build Docker image..."
docker build --build-arg="VERZIJA=${VERZIJA}" \
-t "${GITEA_IMAGE}:${VERZIJA}" \
-t "${GITEA_IMAGE}:latest" \
-t "${GITHUB_IMAGE}:${VERZIJA}" \
-t "${GITHUB_IMAGE}:latest" \
.
echo "→ Push na Gitea..."
docker push "${GITEA_IMAGE}:${VERZIJA}"
docker push "${GITEA_IMAGE}:latest"
echo "→ Push na GitHub..."
docker push "${GITHUB_IMAGE}:${VERZIJA}"
docker push "${GITHUB_IMAGE}:latest"
echo ""
fi
echo "==> Gotovo! NTech v${VERZIJA_BUILD}"