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 05cac3c5..00000000 Binary files a/data/inventory.db and /dev/null differ 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 &