feat: complete dockerization architecture with data/logs persistence and prod export script v1.3.0

This commit is contained in:
Daniel Bedeleanu
2026-04-11 12:32:06 +03:00
parent c71a815792
commit 2e5ce8d153
15 changed files with 485 additions and 23 deletions

2
.gitignore vendored
View File

@@ -4,3 +4,5 @@ __pycache__/
*.pyc
.env
.DS_Store
aInventory-PROD*
aInventory-PROD*.zip

12
Caddyfile Normal file
View File

@@ -0,0 +1,12 @@
# TFM aInventory - Caddy Self-Signed Internal Proxy
# This replaces the need for `local-ssl-proxy` in Node.
:3003 {
tls internal
reverse_proxy frontend:3000
}
:3002 {
tls internal
reverse_proxy backend:8000
}

View File

@@ -1,16 +1,15 @@
{
"version": "1.2.9",
"version": "1.3.0",
"last_build": "2026-04-11-1235",
"commit": "3b2f1",
"commit": "PENDING",
"changelog": [
"v1.3.0: Dockerization: Dual-mode architecture, standalone Next.js, Python logger, and prod export script",
"v1.2.9: Automatic IDE Entry Points (GEMINI.md, CLAUDE.md proxies)",
"v1.2.8: Absolute Documentation Consolidation (Unified ARCHITECTURE and AI_RULES)",
"v1.2.7: Documentation Refactor: Created TECH_STACK.md for SSOT and removed absolute paths",
"v1.2.6: Hotfix - Added missing icon imports (Layers, ChevronDown)",
"v1.2.5: Synchronized icons across UI (Layers for Categories, Package for Item Types)",
"v1.2.4: Offline LDAP auth support and UI affordance improvements (Dropdown chevrons, soft password dots)",
"v1.2.3: System-wide UI consistency (standardized font sizes, removed uppercase)",
"v1.2.2: UI Readability refactor (Removed uppercase/tracking, increased font sizes)",
"v1.2.1: Git path persistence, master/dev/vX branching, and UI case-sensitivity fix"
"v1.2.3: System-wide UI consistency (standardized font sizes, removed uppercase)"
]
}

35
backend/Dockerfile Normal file
View File

@@ -0,0 +1,35 @@
FROM python:3.12-slim
# Install system dependencies required for python-ldap (needed by backend)
RUN apt-get update && apt-get install -y \
build-essential \
libldap2-dev \
libsasl2-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy requirements and install
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Create non-root user
RUN adduser --system --group appuser
# Copy application files
COPY backend ./backend
# We define the data dir explicitly for Docker
ENV DATA_DIR="/app/data"
ENV LOGS_DIR="/app/logs"
# Ensure the appuser can write to data and logs if we pre-create them,
# although Docker volumes will handle ownership context.
RUN mkdir -p /app/data /app/logs && chown -R appuser:appuser /app
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"]

View File

@@ -4,9 +4,11 @@ import os
# Get absolute path for the backend directory
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data")
# Create data directory if it doesn't exist in the backend folder
# Use DATA_DIR from environment if running in Docker, otherwise fallback to local 'data' folder
DATA_DIR = os.environ.get("DATA_DIR", os.path.join(BASE_DIR, "data"))
# Create data directory if it doesn't exist
os.makedirs(DATA_DIR, exist_ok=True)
# Handle absolute path for SQLite (needs 4 slashes on Unix)

51
backend/logger.py Normal file
View File

@@ -0,0 +1,51 @@
import logging
import os
from logging.handlers import RotatingFileHandler
# Define paths
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# Fallback to local 'logs' dir if not overridden in Docker
LOGS_DIR = os.environ.get("LOGS_DIR", os.path.join(BASE_DIR, "logs"))
# Ensure directory exists
os.makedirs(LOGS_DIR, exist_ok=True)
LOG_FILE_PATH = os.path.join(LOGS_DIR, "backend.log")
def setup_logger():
logger = logging.getLogger("ainventory")
logger.setLevel(logging.INFO)
# Avoid duplicate handlers if setup multiple times
if logger.handlers:
return logger
formatter = logging.Formatter(
"[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
# Console Handler
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
# File Handler (10MB max, keep 5 backups)
file_handler = RotatingFileHandler(
LOG_FILE_PATH, maxBytes=10*1024*1024, backupCount=5
)
file_handler.setFormatter(formatter)
# Attach handlers
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# Special redirect for uvicorn logs to also go to file
uvicorn_logger = logging.getLogger("uvicorn")
uvicorn_logger.addHandler(file_handler)
uvicorn_access_logger = logging.getLogger("uvicorn.access")
uvicorn_access_logger.addHandler(file_handler)
return logger
log = setup_logger()

174
backend/logs/backend.log Normal file
View File

@@ -0,0 +1,174 @@
[2026-04-11 12:25:22] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:25:22] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:25:22] [INFO] [uvicorn.error] Started server process [87758]
[2026-04-11 12:25:22] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:25:22] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:25:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:25:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:26:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:26:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:27:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:27:39] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:27:39] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:27:39] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:27:39] [INFO] [uvicorn.error] Finished server process [87758]
[2026-04-11 12:27:40] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:27:40] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:27:40] [INFO] [uvicorn.error] Started server process [87911]
[2026-04-11 12:27:40] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:27:40] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:27:41] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:27:41] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:27:41] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:27:41] [INFO] [uvicorn.error] Finished server process [87911]
[2026-04-11 12:27:42] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:27:42] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:27:42] [INFO] [uvicorn.error] Started server process [87914]
[2026-04-11 12:27:42] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:27:42] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:27:43] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:27:43] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:27:43] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:27:43] [INFO] [uvicorn.error] Finished server process [87914]
[2026-04-11 12:27:44] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:27:44] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:27:44] [INFO] [uvicorn.error] Started server process [87922]
[2026-04-11 12:27:44] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:27:44] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Finished server process [87922]
[2026-04-11 12:27:46] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:27:46] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Started server process [87926]
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:27:46] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Finished server process [87926]
[2026-04-11 12:27:52] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:27:52] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Started server process [87933]
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:27:52] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:27:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:28:02] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:02] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:02] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:02] [INFO] [uvicorn.error] Finished server process [87933]
[2026-04-11 12:28:03] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:03] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:03] [INFO] [uvicorn.error] Started server process [87948]
[2026-04-11 12:28:03] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:03] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:04] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:04] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:04] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:04] [INFO] [uvicorn.error] Finished server process [87948]
[2026-04-11 12:28:05] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:05] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:05] [INFO] [uvicorn.error] Started server process [87957]
[2026-04-11 12:28:05] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:05] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:06] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:07] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:07] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:07] [INFO] [uvicorn.error] Finished server process [87957]
[2026-04-11 12:28:07] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:07] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:07] [INFO] [uvicorn.error] Started server process [87958]
[2026-04-11 12:28:07] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:07] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Finished server process [87958]
[2026-04-11 12:28:09] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:09] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Started server process [87960]
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:09] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:11] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:11] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:11] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:11] [INFO] [uvicorn.error] Finished server process [87960]
[2026-04-11 12:28:12] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:12] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:12] [INFO] [uvicorn.error] Started server process [87968]
[2026-04-11 12:28:12] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:12] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:13] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:13] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:13] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:13] [INFO] [uvicorn.error] Finished server process [87968]
[2026-04-11 12:28:14] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:14] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:14] [INFO] [uvicorn.error] Started server process [87971]
[2026-04-11 12:28:14] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:14] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Finished server process [87971]
[2026-04-11 12:28:20] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:20] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Started server process [87989]
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:20] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:28:36] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:28:36] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:28:36] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:28:36] [INFO] [uvicorn.error] Finished server process [87989]
[2026-04-11 12:28:37] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:28:37] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:28:37] [INFO] [uvicorn.error] Started server process [88059]
[2026-04-11 12:28:37] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:28:37] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:28:37] [WARNING] [uvicorn.error] Invalid HTTP request received.
[2026-04-11 12:28:37] [INFO] [uvicorn.access] ::ffff:127.0.0.1:0 - "POST /exa.language_server_pb.LanguageServerService/GetUnleashData HTTP/1.1" 404
[2026-04-11 12:28:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:29:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:29:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:30:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:30:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:31:24] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200
[2026-04-11 12:31:30] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:31:30] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:31:30] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:31:30] [INFO] [uvicorn.error] Finished server process [88059]
[2026-04-11 12:31:31] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:31:31] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Started server process [88476]
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Finished server process [88476]
[2026-04-11 12:31:31] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:31:31] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Started server process [88477]
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:31:31] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:31:32] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:31:32] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:31:32] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:31:32] [INFO] [uvicorn.error] Finished server process [88477]
[2026-04-11 12:31:33] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:31:33] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:31:33] [INFO] [uvicorn.error] Started server process [88478]
[2026-04-11 12:31:33] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:31:33] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:31:34] [INFO] [uvicorn.error] Shutting down
[2026-04-11 12:31:34] [INFO] [uvicorn.error] Waiting for application shutdown.
[2026-04-11 12:31:34] [INFO] [uvicorn.error] Application shutdown complete.
[2026-04-11 12:31:34] [INFO] [uvicorn.error] Finished server process [88478]
[2026-04-11 12:31:35] [INFO] [ainventory] Database tables verified.
[2026-04-11 12:31:35] [INFO] [ainventory] TFM aInventory API process started.
[2026-04-11 12:31:35] [INFO] [uvicorn.error] Started server process [88490]
[2026-04-11 12:31:35] [INFO] [uvicorn.error] Waiting for application startup.
[2026-04-11 12:31:35] [INFO] [uvicorn.error] Application startup complete.
[2026-04-11 12:31:54] [INFO] [uvicorn.access] ::ffff:192.168.84.140:0 - "GET /items/ HTTP/1.1" 200

View File

@@ -3,11 +3,14 @@ from fastapi.middleware.cors import CORSMiddleware
from . import models
from .database import engine
from .routers import items, operations, users, categories
from .logger import log
# Create the database tables
models.Base.metadata.create_all(bind=engine)
log.info("Database tables verified.")
app = FastAPI(title="TFM aInventory API", version="1.1.0")
log.info("TFM aInventory API process started.")
# Setup Cross-Origin for Client interaction (PWA)
app.add_middleware(

View File

@@ -11,7 +11,7 @@ router = APIRouter(prefix="/users", tags=["users"])
pwd_context = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")
def get_ldap_config():
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "ldap_config.json")
config_path = os.path.join(database.DATA_DIR, "ldap_config.json")
if os.path.exists(config_path):
with open(config_path, "r") as f:
return json.load(f)
@@ -209,7 +209,7 @@ def get_ldap_settings():
@router.post("/ldap-config")
def update_ldap_settings(config: dict):
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "ldap_config.json")
config_path = os.path.join(database.DATA_DIR, "ldap_config.json")
with open(config_path, "w") as f:
json.dump(config, f)
return {"message": "Config saved"}

View File

@@ -1,3 +1,24 @@
### [2026-04-11 12:45] v1.3.0: Dockerization & Export Script
**Purpose:** Upgraded the system architecture to support seamless dual-mode execution (Dockerized or Bare-Metal/Local). Extracted data and logic persistence layers to external volumes (`/data`, `/logs`). Added a dedicated production compiler.
**Actions:**
- `backend/database.py` and `users.py` now support `DATA_DIR` environment overrides.
- Implemented `backend/logger.py` for standard Python rotating logs mapped to `/app/logs`.
- Next.js configured for `standalone` output mode to strictly optimize containerized PWA size.
- Orchestrated full environment with `docker-compose.yml`, using Caddy for local self-signed HTTPS termination.
- Created `export_prod.sh` to extract a clean release bundle without AI/Dev files (using optimized `rsync`).
**Modified Files:**
- `backend/database.py`
- `backend/routers/users.py`
- `backend/logger.py` (New)
- `backend/main.py`
- `frontend/next.config.mjs`
- `frontend/Dockerfile` (New)
- `backend/Dockerfile` (New)
- `docker-compose.yml` (New)
- `Caddyfile` (New)
- `export_prod.sh` (New)
- `VERSION.json`
### [2026-04-11 12:35] v1.2.9: Automatic IDE Entry Points
**Purpose:** Restored specific ID-based entry points (`GEMINI.md` and `CLAUDE.md`) as "Proxy Pointers" to ensure modern AI extensions (Cursor, Windsurf, Gemini IDE) naturally pick them up as system prompt injections.
**Modified Files:**

View File

@@ -1,15 +1,18 @@
# AI Session State - HANDOVER
# CURRENT AI WORKING SESSION
**Status**: v1.2.6 Hotfixed & UX Polished. Persistent Gemini Context Created.
**Current AI Agent**: Gemini (Antigravity)
**Context**:
- **Offline Auth**: LDAP users now have local password hash caching (v1.2.4).
- **UI Affordance**: Added `ChevronDown` to selects and softened password dots.
- **Icon Sync**: Unified iconography (Layers = Categories, Package = Item Types).
- **Memory**: Created [GEMINI.md](../GEMINI.md) as the persistent entry point for this agent.
- **Version**: Currently at **v1.2.6**. Commit log in `ARCHIVE_LOGS.md`.
**Active AI:** Antigravity (Gemini)
**Last Updated:** 2026-04-11
**Current Version:** v1.3.0
**Branch:** dev
**Next Steps**:
1. **Phase 6: Advanced Audit Dashboard**. Current logs exist but could use a dedicated page with filtering.
2. Final testing of offline LDAP login (Basement simulation).
3. Verification of icon consistency in any new screens.
### Current Status
Finalized the system refactoring by implementing a complete, portable **Dockerization Architecture**. Introduced the `export_prod.sh` bundle compiler, centralized technical documentation into a Single Source Of Truth (`PROJECT_ARCHITECTURE.md`), and ensured exact reverse compatibility so that bare-metal development using `./start_server.sh` operates identically to previous versions.
### Technical Context
- **Persistence Mapping:** Local database (`inventory.db`) and `ldap_config.json` now persist through the environmental variable `DATA_DIR` (mapped to local `/data` volume).
- **Log System:** Created `backend/logger.py` with Python's RotatingFileHandler. Streamed locally into `/logs`.
- **Standalone:** Next.js uses `output: standalone` configuration specifically to support the Node alpine dockerfile. Caddy replaces `local-ssl-proxy` only inside the Docker environment.
### Next Steps / Blockers
1. Testing actual AI flow in production mode (using the exported Production Bundle zip).
2. Implementing the Advanced Audit log Dashboard inside the UI.

53
docker-compose.yml Normal file
View File

@@ -0,0 +1,53 @@
version: '3.8'
services:
backend:
build:
context: .
dockerfile: backend/Dockerfile
networks:
- inventory_net
ports:
- "8000:8000"
volumes:
- ./data:/app/data
- ./logs:/app/logs
environment:
- DATA_DIR=/app/data
- LOGS_DIR=/app/logs
restart: unless-stopped
frontend:
build:
context: .
dockerfile: frontend/Dockerfile
networks:
- inventory_net
ports:
- "3000:3000"
volumes:
- ./logs:/app/logs
# Write Next.js logs to both stdout (docker logs) and file (mapped volume)
command: sh -c "mkdir -p /app/logs && node server.js 2>&1 | tee -a /app/logs/frontend.log"
restart: unless-stopped
proxy:
image: caddy:alpine
networks:
- inventory_net
ports:
- "3002:3002"
- "3003:3003"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
# Persist the internal Caddy certificates so users don't get new certificate warnings constantly
- ./data/caddy_data:/data
- ./data/caddy_config:/config
depends_on:
- frontend
- backend
restart: unless-stopped
networks:
inventory_net:
driver: bridge

59
export_prod.sh Executable file
View File

@@ -0,0 +1,59 @@
#!/bin/bash
# export_prod.sh - Generates a clean production bundle for distribution
echo "📦 Preparing TFM aInventory Production Bundle..."
# Extract version from VERSION.json using grep to avoid macOS python/xcode stubs
VERSION=$(grep '"version"' VERSION.json | head -n 1 | awk -F '"' '{print $4}')
PROD_DIR="aInventory-PROD-v${VERSION}"
# Clean previous run if it exists
rm -rf "$PROD_DIR"
rm -f "${PROD_DIR}.zip"
mkdir -p "$PROD_DIR"
echo "📂 Copying application components (excluding dev artifacts)..."
# Core application
rsync -a --exclude 'node_modules' --exclude '.next' frontend/ "$PROD_DIR/frontend/"
rsync -a --exclude '__pycache__' --exclude '.pytest_cache' --exclude '.venv' backend/ "$PROD_DIR/backend/"
# Orchestration & Scripts
cp docker-compose.yml "$PROD_DIR/"
cp Caddyfile "$PROD_DIR/"
cp start_server.sh "$PROD_DIR/"
cp .git_path "$PROD_DIR/" 2>/dev/null || true
cp VERSION.json "$PROD_DIR/"
# Setup persistent volume skeleton
mkdir -p "$PROD_DIR/data"
mkdir -p "$PROD_DIR/logs"
# Place a README in the root of the release
cat <<EOF > "$PROD_DIR/README.txt"
TFM aInventory - v${VERSION}
=============================
This is a clean production build, free of development or AI-agent constraints.
TO RUN VIA DOCKER (Recommended):
1. Install Docker Desktop or Docker Engine.
2. Run: docker-compose build
3. Run: docker-compose up -d
4. Access via https://<YOUR-IP>:3003 (Accept the internal security warning).
TO RUN BARE-METAL (No Docker):
1. Install Python 3.12+ and Node.js 20+.
2. Ensure you have network access for npm installs.
3. Run: ./start_server.sh
4. Access via https://<YOUR-IP>:3003
Note: Database and Logs will persist in the /data and /logs directories.
EOF
echo "🗜️ Zipping the final bundle..."
zip -r -q "${PROD_DIR}.zip" "$PROD_DIR"
# Optional: cleanup the directory to leave just the zip
# rm -rf "$PROD_DIR"
echo "✅ SUCCESS: The clean production archive is ready: ${PROD_DIR}.zip"

48
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,48 @@
FROM node:20-alpine AS base
# Step 1: Install dependencies
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# We run this from the frontend folder context
COPY package.json package-lock.json* ./
RUN npm ci
# Step 2: Build the source code
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Disable telemetry during build
ENV NEXT_TELEMETRY_DISABLED 1
RUN npm run build
# Step 3: Production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
# Add nextjs user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy standalone output
COPY --from=builder /app/public ./public
# Set proper permissions for the Next.js cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
# Note: The server.js is created by next build from the standalone output
CMD ["node", "server.js"]

View File

@@ -9,7 +9,7 @@ const withPWA = withPWAInit({
/** @type {import('next').NextConfig} */
const nextConfig = {
// Config options here
output: "standalone",
};
export default withPWA(nextConfig);