Dasko e99dd50273 Prava ispravka: usluge/troskovi.datum_unosa promenjen na DATETIME u šemi
Umesto ručnog parsiranja (prethodni commit), migracija 103 rekreira obe
tabele sa DATETIME kolonom (kao svuda drugde u šemi) — SQLite ne podržava
ALTER COLUMN, pa je urađeno kreiraj-novu/prebaci-podatke/obriši-staru/
preimenuj. Fizički format podataka se ne menja (SQLite nema pravi numerički
afinitet za DATETIME nad ovakvim stringom), menja se samo deklarisani tip
kolone koji driver čita da odluči string vs time.Time pri Scan-u.

Uklonjen parseDatumUnosa workaround iz utils.go — skenirajUslugu/skenirajTrosak
sada rade identično kao svi ostali skenirajX helperi (direktan Scan u time.Time).

Potvrđeno: migracija testirana na praznoj i na postojećoj bazi sa podacima
(6 usluga, ID-jevi i datumi netaknuti), /usluge i /troskovi vraćaju 200.
2026-07-04 00:09:32 +02:00
2026-06-20 01:11:29 +02:00
2026-06-24 22:27:06 +02:00

NTech

🇷🇸 Srpska verzija

Go Version License

image

A business application for computer repair shop management, parts inventory tracking, and sales. Built with Go, it runs in the browser and requires no internet connection or external services.

⚠️ The project is under active development. It is not ready for production use.

Live demo: https://demo.vm-net.in.rs — log in with Demo / Demo1234 (admin role; password and 2FA changes are disabled in demo mode).


About the Project

NTech is an internal application built for a specific user — a computer repair shop that, in addition to repairs, manages a parts inventory, sales of components and pre-built configurations, as well as client and supplier records.

The goal is simple: everything the repair shop needs to track is located in one place, without relying on Excel spreadsheets or paper records.


Features

Implemented

  • Initial setup on first run (setup wizard)
  • Database migration system
  • User interface — sidebar navigation, theme system (dark/light), dashboard with statistics
  • User login — server-side sessions, account locking
  • Two-factor authentication (TOTP) — activation with a QR code; secret encrypted at rest (AES-256-GCM, key kept outside the database)
  • Backup (one-time) codes for 2FA — generated on activation, stored as bcrypt hashes; a fallback to TOTP at login
  • Brute-force protection — IP locking after 5 failed attempts within 15 minutes
  • CSRF protection — double-submit cookie pattern, automatic token injection into all forms
  • Security HTTP headers (CSP, X-Frame-Options, Referrer-Policy, nosniff...)
  • Login attempt logging — history by user, IP, reason, date
  • Users and roles — admin panel, user management
  • Inventory — items, categories, filtering, critical stock levels, per-item stock card, supplier links, item transfers
  • Service orders:
    • Intake form, status bar, archive
    • Diagnostic workflow — fault description, technician notes, work done, diagnostic fee
    • 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
    • Public status page — client can check order status and receive notifications via a unique link
    • Documents — work order, pre-invoice (estimate), dispatch note, return slip, device label (QR + Code128 barcode)
    • Pickup with payment — tracks payment method and advance amount
    • Guarantee period, expected completion date, technician assignment, client notes
  • Sales orders — items, calculation, receipt with company and client details
  • Services catalog — service price list used for billing in service orders
  • Expenses — expense records with category and amount
  • Procurement — records of purchases from suppliers
  • Sales price calculation on procurement — markup (global, per category, per item), landed costs (customs, shipping...) allocated across items, two-way markup↔price computation; respects VAT-payer status
  • Price revaluation (nivelacija) — sales price changes with an audit trail (old→new, reason, source, user)
  • Company profile and modules — features toggle based on company type and VAT-payer status
  • 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 rate code list
  • Clients and suppliers — contact database
  • Reminders — records with deadlines
  • Reports — revenue overview, inventory status, inventory value report, stock movement list, stocktake (physical count)
  • Settings — company name, address, Tax ID (PIB), logo; theme toggle
  • Background images — login page and app, with blur, transparency and glass effect
  • Personal theme and background — each user can set their own theme and background image
  • Permission matrix (RBAC) — admin panel for permissions by role; enforced at the route level (both mutations and views) and in handlers
  • Flash messages — one-time feedback after an action
  • Automatic SQLite backup — with configurable number of retained copies; restore from a copy (safe, with no downtime)
  • Charts — monthly revenue on reports (Chart.js)
  • 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)
  • Demo mode (NTECH_ENV=demo) — auto-created demo user, pre-filled login form, restricted backup count, blocked password/2FA changes

In Progress

  • Fiscalization (ESIR/PFR) — Teron L-PFR mock server included in Fisk/; Go client integration planned

Planned

  • KPO book and double-entry bookkeeping (optional, later phase)
  • PostgreSQL support (for multi-user environments)
  • WebAuthn / Passkey login (database schema is already prepared)
  • Notifications (email / WhatsApp) — deferred to a later phase
  • Barcode scanning via camera — deferred to a later phase

Technologies

Technology Role
Go backend language
chi HTTP router
html/template server-side templates
HTMX dynamic HTML over HTTP
Alpine.js client-side UI logic
SQLite + modernc.org/sqlite main database (pure Go, no CGO)
PostgreSQL + pgx/v5 optional production database

Running the Application

Requirements

  • Go 1.24 or newer
  • Git

Steps

# 1. Clone the repository
git clone <repository-url>
cd GoNtech

# 2. Run in development mode (reads files from disk, no HTTPS required)
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:

./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:

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

# 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
}

With Teron L-PFR Mock (Fiscalization Testing)

The Fisk/ directory contains a Python mock server that simulates a Teron L-PFR fiscal device (port 4566). It implements the Teron HTTP API — invoice signing, PDV calculation, QR code generation, and per-type counters — without requiring real hardware or a certificate.

Use it alongside NTech for fiscalization development and testing:

# docker-compose.yml
services:
  ntech:
    image: ghcr.io/dalibor31/ntech:latest
    container_name: ntech
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      NTECH_ENV: production
      NTECH_PORT: "8000"
      NTECH_SQLITE: /app/data/ntech.db
    volumes:
      - ./data:/app/data
      - ./uploads:/app/web/static/uploads
      - ./logs:/var/log/ntech
      - ./backups:/app/backups
    networks:
      - ntech-net

  teron-mock:
    image: ghcr.io/dalibor31/ntech-fisk:latest
    container_name: teron_mock
    restart: unless-stopped
    volumes:
      - teron-data:/app/data
    networks:
      - ntech-net

volumes:
  teron-data:

networks:
  ntech-net:

The teron-mock service is reachable from ntech at http://teron-mock:4566 over the internal Docker network — the port is not exposed to the host.

To run as a standalone Docker container:

# docker-compose.fisk.yml
services:
  teron-mock:
    image: ghcr.io/dalibor31/ntech-fisk:latest
    container_name: teron_mock
    restart: unless-stopped
    ports:
      - "4566:4566"
    volumes:
      - teron-data:/app/data

volumes:
  teron-data:
docker compose -f docker-compose.fisk.yml up -d

To run the mock server locally (without Docker):

cd Fisk
pip install -r requirements.txt
python server.py
# or: ./start.sh

Teron Mock Endpoints

Method Path Description
GET /api/status Device status and last invoice number
GET /api/attention Active alerts
POST /api/pin PIN verification (BE unlock)
GET /api/settings Device settings
POST /api/invoices Issue a fiscal invoice
POST /api/invoices/final Finalize an advance invoice
GET /api/invoices/last Last issued invoice
GET /api/invoices/:invoiceNumber Invoice by number
POST /api/invoices/search Search invoices

Counters, signed receipts, QR codes, and JSON invoice data are persisted in Fisk/data/.


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.

# 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
S
Description
Servisni informacioni sistem za upravljanje servisom, magacinom i prodajom. Go + SQLite, jedan binarni fajl.
https://demo.vm-net.in.rs
Readme MIT
2.6 MiB
Languages
Go 49.3%
HTML 42.4%
Python 3.1%
CSS 2.6%
JavaScript 2%
Other 0.6%