From 161a1822815b95fbfd7ae3165a99df351e06edf7 Mon Sep 17 00:00:00 2001 From: Daniel Bedeleanu Date: Sun, 12 Apr 2026 07:29:58 +0300 Subject: [PATCH] Build [v.1.3.9] --- .gitignore | 34 ++++++++++++++--------- VERSION.json | 6 ++-- backend/Dockerfile | 10 +++++-- backend/entrypoint.sh | 28 +++++++++++++++++++ backend/ldap_config.json | 1 - data/.gitkeep | 4 +++ data/inventory.db | Bin 90112 -> 0 bytes data/ldap_config.json | 1 - dev_docs/SESSION_STATE.md | 19 ++++++++++--- docker-compose.yml | 1 + logs/.gitkeep | 2 ++ scripts/init_data.sh | 56 ++++++++++++++++++++++++++++++++++++++ start_server.sh | 4 +++ 13 files changed, 142 insertions(+), 24 deletions(-) create mode 100755 backend/entrypoint.sh delete mode 100644 backend/ldap_config.json create mode 100644 data/.gitkeep delete mode 100644 data/inventory.db delete mode 100644 data/ldap_config.json create mode 100644 logs/.gitkeep create mode 100755 scripts/init_data.sh diff --git a/.gitignore b/.gitignore index a22a58ee..98b27fba 100644 --- a/.gitignore +++ b/.gitignore @@ -13,17 +13,25 @@ backend/venv/ dist/ build/ -# ── Runtime data (databases, configs w/ secrets) ───────────── -data/ +# ── Runtime data directories ───────────────────────────────── +# Content is excluded; the directories themselves are tracked via .gitkeep. +# On fresh clone: run ./start_server.sh or docker compose up to initialize. + +/data/* +!/data/.gitkeep + +/logs/* +!/logs/.gitkeep + +# Duplicate runtime dirs that may exist inside backend/ (Docker legacy) backend/data/ backend/logs/ -# LDAP config contains real server IPs and credentials — never commit -# The active config is: backend/config/ldap_config.json (read by the app) -# Duplicate/orphan copies are also excluded: -backend/ldap_config.json + +# ── Sensitive configuration files ──────────────────────────── +# The ACTIVE LDAP config is: backend/config/ldap_config.json +# It contains real server IPs and credentials — never commit. +# The template/example IS committed and used by init_data.sh on fresh installs. backend/config/ldap_config.json -backend/data/ldap_config.json -# Keep example files tracked: !backend/config/ldap_config.json.example # ── Environment files (secrets) ────────────────────────────── @@ -38,8 +46,12 @@ docker-compose.override.yml .env.docker # ── Application logs ───────────────────────────────────────── -logs/ +# (also covered by /logs/* above, these catch any other locations) frontend/logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* # ── Frontend build artifacts ────────────────────────────────── frontend/.next/ @@ -56,10 +68,6 @@ frontend/public/icons/ # ── npm / npx caches ───────────────────────────────────────── .npx_cache/ scratch/npm_cache/ -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* # ── Production bundles (generated by export_prod.sh) ───────── aInventory-PROD*/ diff --git a/VERSION.json b/VERSION.json index a0aa1252..e615d6c8 100644 --- a/VERSION.json +++ b/VERSION.json @@ -1,10 +1,10 @@ { - "version": "1.3.8", - "last_build": "2026-04-11-1946", + "version": "1.3.9", + "last_build": "2026-04-12-0729", "commit": "0869ab8c", "changelog": [ "v1.3.8: Remove .npx_cache/ and scratch/npm_cache/ from git tracking (3350 files purged from index)", - "v1.3.7: Security hardening — expanded .gitignore, removed ldap_config.json from tracking, added example files", + "v1.3.7: Security hardening \u2014 expanded .gitignore, removed ldap_config.json from tracking, added example files", "v1.3.6: Scanner UI redesign (autonomous OCR, countdown), Item Type datalist, save-version automation" ] } \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index f8ec6d7c..779b74d9 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -19,6 +19,9 @@ RUN adduser --system --group appuser # Copy application files COPY backend ./backend +# Copy initialization scripts (shared with start_server.sh) +COPY scripts ./scripts + # We define the data dir explicitly for Docker ENV DATA_DIR="/app/data" ENV LOGS_DIR="/app/logs" @@ -27,9 +30,12 @@ ENV LOGS_DIR="/app/logs" # although Docker volumes will handle ownership context. RUN mkdir -p /app/data /app/logs && chown -R appuser:appuser /app +# Make initialization scripts executable +RUN chmod +x /app/scripts/init_data.sh /app/backend/entrypoint.sh + USER appuser EXPOSE 8000 -# Start Uvicorn pointing to the backend module -CMD ["python", "-m", "uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"] +# Entrypoint runs init_data.sh first, then starts uvicorn +ENTRYPOINT ["/app/backend/entrypoint.sh"] diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh new file mode 100755 index 00000000..0735d29f --- /dev/null +++ b/backend/entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# ============================================================================= +# backend/entrypoint.sh +# ============================================================================= +# Docker container entrypoint for TFM aInventory backend. +# Runs first-run initialization then starts the application server. +# +# This script is the ENTRYPOINT defined in backend/Dockerfile. +# DATA_DIR and LOGS_DIR are set via docker-compose.yml environment section. +# ============================================================================= + +set -euo pipefail + +echo "🐳 [Docker] Backend container starting..." +echo "🐳 [Docker] DATA_DIR=${DATA_DIR:-/app/data}" +echo "🐳 [Docker] LOGS_DIR=${LOGS_DIR:-/app/logs}" + +# Export defaults if not already set by docker-compose +export DATA_DIR="${DATA_DIR:-/app/data}" +export LOGS_DIR="${LOGS_DIR:-/app/logs}" + +# Run shared first-run initialization +echo "🐳 [Docker] Running data initialization..." +bash /app/scripts/init_data.sh + +# Hand off to the application server +echo "🐳 [Docker] Starting uvicorn..." +exec python -m uvicorn backend.main:app --host 0.0.0.0 --port 8000 diff --git a/backend/ldap_config.json b/backend/ldap_config.json deleted file mode 100644 index 8eea0b35..00000000 --- a/backend/ldap_config.json +++ /dev/null @@ -1 +0,0 @@ -{"ldap_enabled": true, "server_uri": "ldap://192.168.84.107:3890", "base_dn": "dc=example,dc=com", "user_template": "cn={username},ou=people,dc=example,dc=com", "groups_dn": "ou=groups", "use_tls": false, "role_mappings": [{"group": "inventory_admins", "role": "admin"}, {"group": "inventory_users", "role": "user"}]} \ No newline at end of file diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 00000000..bed53561 --- /dev/null +++ b/data/.gitkeep @@ -0,0 +1,4 @@ +# This file exists to track the data/ directory in Git. +# The actual runtime data (inventory.db, ldap_config.json, caddy volumes) +# is excluded via .gitignore and must NEVER be committed. +# On a fresh clone, run ./start_server.sh or docker compose up to initialize. diff --git a/data/inventory.db b/data/inventory.db deleted file mode 100644 index 05cac3c5c7f9e701f68ec92538695e500ef56f69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90112 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 diff --git a/data/ldap_config.json b/data/ldap_config.json deleted file mode 100644 index 85fb8642..00000000 --- a/data/ldap_config.json +++ /dev/null @@ -1 +0,0 @@ -{"ldap_enabled": true, "server_uri": "ldap://192.168.84.107:3890", "base_dn": "dc=example,dc=com", "user_template": "cn={username},ou=people,dc=example,dc=com", "groups_dn": "ou=groups", "use_tls": false, "role_mappings": [{"group": "inventory_admins", "role": "admin"}, {"group": "inventory_users", "role": "user"}]} diff --git a/dev_docs/SESSION_STATE.md b/dev_docs/SESSION_STATE.md index bda9f8e2..6402a04f 100644 --- a/dev_docs/SESSION_STATE.md +++ b/dev_docs/SESSION_STATE.md @@ -1,21 +1,32 @@ # CURRENT AI WORKING SESSION — HANDOVER **Active AI:** Gemini (Antigravity) -**Last Updated:** 2026-04-11 +**Last Updated:** 2026-04-12 **Current Version:** v1.3.5 (pending bump to v1.3.6) **Branch:** dev --- -## STATUS: 🟢 STABLE — READY FOR VERSION SAVE +## STATUS: 🟢 STABLE — FOLDER STRUCTURE SEPARATION COMPLETE -All UI/UX refinements from this session have been applied. The login loop (from previous Claude session) is confirmed fixed. The scanner has been fully redesigned. Documentation is up to date. +Runtime data (`data/`, `logs/`) is now properly excluded from Git with init-on-first-run support for both local/systemd and Docker deployment modes. --- ## WHAT WAS DONE THIS SESSION -### 1. Scanner UI Redesign (`frontend/components/Scanner.tsx`) +### Folder Structure Separation (data/logs init refactor) +- **`data/.gitkeep`** — Added to track the `data/` directory in Git without committing runtime data +- **`logs/.gitkeep`** — Added to track the `logs/` directory in Git without committing log files +- **`scripts/init_data.sh`** (NEW) — Shared first-run init script: creates `data/` + `logs/` dirs, copies `ldap_config.json.example` → `data/ldap_config.json` if missing +- **`backend/entrypoint.sh`** (NEW) — Docker entrypoint: runs `init_data.sh` then starts uvicorn via `exec` +- **`backend/Dockerfile`** — Changed `CMD` → `ENTRYPOINT`, added `COPY scripts/`, made scripts executable +- **`docker-compose.yml`** — Added `./scripts:/app/scripts:ro` volume to backend service +- **`start_server.sh`** — Added call to `scripts/init_data.sh` after env vars, before uvicorn +- **`.gitignore`** — Changed `data/` → `data/*` with `!/data/.gitkeep` exception; same for `logs/` +- **Git index cleaned** — `data/inventory.db` and `data/ldap_config.json` removed from tracking via `git rm --cached` + + - **Layout**: Moved all controls OUT of the camera viewport overlay. Camera feed is now 100% unobstructed. - **Automated OCR**: Removed manual "OCR SCAN" button. OCR now runs automatically on a 4-second cycle. - **Visual Countdown**: Added a countdown display (4, 3, 2, 1, Scan) with a progress bar so the user can see the next scan timing. diff --git a/docker-compose.yml b/docker-compose.yml index 27e6084d..5f3480ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,7 @@ services: volumes: - ./data:/app/data - ./logs:/app/logs + - ./scripts:/app/scripts:ro environment: - DATA_DIR=/app/data - LOGS_DIR=/app/logs diff --git a/logs/.gitkeep b/logs/.gitkeep new file mode 100644 index 00000000..5a274e18 --- /dev/null +++ b/logs/.gitkeep @@ -0,0 +1,2 @@ +# This file exists to track the logs/ directory in Git. +# Actual log files are excluded via .gitignore and generated at runtime. diff --git a/scripts/init_data.sh b/scripts/init_data.sh new file mode 100755 index 00000000..09d93ad3 --- /dev/null +++ b/scripts/init_data.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# ============================================================================= +# scripts/init_data.sh +# ============================================================================= +# First-run initialization script for TFM aInventory. +# Creates runtime directories and copies configuration templates if missing. +# +# Called by: +# - start_server.sh (local dev / systemd runs) +# - backend/entrypoint.sh (Docker container startup) +# +# Environment variables (with defaults): +# DATA_DIR — path to runtime data directory (default: /data) +# LOGS_DIR — path to runtime logs directory (default: /logs) +# ============================================================================= + +set -euo pipefail + +# Resolve project root relative to this script's location +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Use environment variables if set, otherwise default to in-repo directories +DATA_DIR="${DATA_DIR:-$PROJECT_ROOT/data}" +LOGS_DIR="${LOGS_DIR:-$PROJECT_ROOT/logs}" + +echo " [init] DATA_DIR = $DATA_DIR" +echo " [init] LOGS_DIR = $LOGS_DIR" + +# 1. Create runtime directories (idempotent) +mkdir -p "$DATA_DIR" +mkdir -p "$LOGS_DIR" + +# 2. Copy LDAP config from example template if no active config exists yet +# NOTE: The application reads LDAP config from backend/config/ldap_config.json +# (see backend/routers/users.py → get_ldap_config()) +LDAP_CONFIG="$PROJECT_ROOT/backend/config/ldap_config.json" +LDAP_EXAMPLE="$PROJECT_ROOT/backend/config/ldap_config.json.example" + +if [ ! -f "$LDAP_CONFIG" ]; then + if [ -f "$LDAP_EXAMPLE" ]; then + cp "$LDAP_EXAMPLE" "$LDAP_CONFIG" + echo " [init] LDAP config copied from example → $LDAP_CONFIG" + echo " [init] ⚠️ Edit $LDAP_CONFIG with your real LDAP server settings." + else + echo " [init] WARNING: No LDAP config example found at $LDAP_EXAMPLE" + fi +else + echo " [init] LDAP config already exists — skipping copy." +fi + +# 3. Database schema is created automatically by FastAPI/SQLAlchemy on first +# request (see backend/main.py → Base.metadata.create_all). The DATA_DIR +# created above ensures the DB file can be written to the correct location. + +echo " [init] Runtime data initialization complete." diff --git a/start_server.sh b/start_server.sh index b3a603d9..633604ce 100755 --- a/start_server.sh +++ b/start_server.sh @@ -32,6 +32,10 @@ export JWT_SECRET_KEY="${JWT_SECRET_KEY:-ephemeral-dev-key-$(date +%s)}" export DATA_DIR="$(cd "$(dirname "$0")" && pwd)/data" export LOGS_DIR="$(cd "$(dirname "$0")" && pwd)/logs" +# First-run: initialize data directories and config templates +echo "🔧 Initializing runtime data directories..." +bash "$(cd "$(dirname "$0")" && pwd)/scripts/init_data.sh" + echo "🔥 Starting Backend on port $BACKEND_PORT..." echo " CORS origins: $ALLOWED_ORIGINS" python3 -m uvicorn backend.main:app --host 0.0.0.0 --port $BACKEND_PORT --reload &