chore(07): remove deprecated bash scripts and legacy env files
This commit is contained in:
48
.planning/phases/07-config-consolidation/07-02-SUMMARY.md
Normal file
48
.planning/phases/07-config-consolidation/07-02-SUMMARY.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Phase 7 Wave 2 Summary: Backend Config Refactoring (07-02)
|
||||
|
||||
**Completed:** 2026-04-23
|
||||
**Status:** [COMPLETED]
|
||||
**Commits:** ae61fa63, 28cdc900, 938fd2da, 225972b8
|
||||
|
||||
---
|
||||
|
||||
## Accomplishments
|
||||
|
||||
1. **backend/config_loader.py Refactored**
|
||||
- Implemented YAML parsing using PyYAML
|
||||
- Enforced D-06 load order: System Env Vars > `config/backend.yaml` > `config/secrets.yaml` > Defaults
|
||||
- Added robust validation for required fields (JWT_SECRET_KEY, primary_ai_provider)
|
||||
- Masked sensitive values in logs
|
||||
|
||||
2. **backend/config_manager.py Updated**
|
||||
- Refactored to handle YAML file operations (`read_config`, `update_config`)
|
||||
- Removed legacy `.env` file manipulation logic
|
||||
|
||||
3. **backend/main.py Updated**
|
||||
- Switched from direct `os.environ` access to the centralized `get_config()` dict
|
||||
- Removed `load_dotenv()` and `inventory.env` references
|
||||
|
||||
4. **backend/entrypoint.sh Updated**
|
||||
- Updated to document the new YAML configuration structure
|
||||
- Added safety checks for the existence of `backend.yaml`
|
||||
|
||||
5. **Additional Backend Files Cleaned Up**
|
||||
- Refactored `backend/ai_vision.py`, `backend/check_models.py`, `backend/ai/gemini.py`, and `backend/ai/claude.py` to use `config_loader`
|
||||
- Completely removed `python-dotenv` dependency from backend
|
||||
|
||||
---
|
||||
|
||||
## Technical Details
|
||||
|
||||
- **Load Order (D-06):** Env Vars override YAML, YAML overrides Defaults.
|
||||
- **Deprecation (D-04):** `inventory.env` is no longer used by the backend application logic.
|
||||
- **Security:** Sensitive configuration values are masked in application logs to prevent data leaks.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- [x] All updated Python files passed `py_compile` checks
|
||||
- [x] No `load_dotenv()` or `inventory.env` references remain in backend code
|
||||
- [x] Configuration loading logs which source was used for each value
|
||||
- [x] Environment variables correctly override YAML values in `config_loader.py`
|
||||
45
.planning/phases/07-config-consolidation/07-03-SUMMARY.md
Normal file
45
.planning/phases/07-config-consolidation/07-03-SUMMARY.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Phase 7 Wave 2 Summary: Python Deployment Scripts (07-03)
|
||||
|
||||
**Completed:** 2026-04-23
|
||||
**Status:** [COMPLETED]
|
||||
**Commits:** ce79c919, 1621625b, 63f72c11, 9253eb65
|
||||
|
||||
---
|
||||
|
||||
## Accomplishments
|
||||
|
||||
1. **scripts/deploy.py Created**
|
||||
- Replaces `deploy.sh` with a secure, robust Python implementation
|
||||
- Implements pre-flight checks, port availability validation, and health check polling
|
||||
- Parses YAML config from `config/docker.yaml` and `config/network.yaml`
|
||||
|
||||
2. **scripts/run_standalone.py Created**
|
||||
- Replaces `run_standalone.sh` for multi-process management without Docker
|
||||
- Handles graceful shutdown (SIGINT/SIGTERM) of both backend and frontend
|
||||
- Provides prefixed, colored console output for logs
|
||||
|
||||
3. **scripts/install_service.py Created**
|
||||
- Replaces `install_service.sh` for systemd service setup
|
||||
- Generates service file from template with correct YAML-based paths
|
||||
|
||||
4. **scripts/export_prod.py Created**
|
||||
- Replaces `export_prod.sh` for production data backups
|
||||
- Explicitly excludes `config/secrets.yaml` to ensure security in backups
|
||||
|
||||
---
|
||||
|
||||
## Technical Details
|
||||
|
||||
- **YAML Parsing (D-05):** All scripts use PyYAML to read the new centralized configuration structure.
|
||||
- **Security:** Subprocess calls use `shell=False` with list arguments to prevent injection attacks.
|
||||
- **Tooling:** Implemented consistent logging and color output for developer experience.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- [x] All 4 Python scripts are executable (`chmod +x`)
|
||||
- [x] All scripts use the proper shebang (`#!/usr/bin/env python3`)
|
||||
- [x] All scripts correctly parse the YAML configuration files
|
||||
- [x] Subprocess execution follows security best practices
|
||||
- [x] Error handling and helpful feedback messages are present in all tools
|
||||
44
.planning/phases/07-config-consolidation/07-04-SUMMARY.md
Normal file
44
.planning/phases/07-config-consolidation/07-04-SUMMARY.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Phase 7 Wave 3 Summary: Docker Integration & Documentation (07-04)
|
||||
|
||||
**Completed:** 2026-04-23
|
||||
**Status:** [COMPLETED]
|
||||
**Commits:** 9f267a53, 5b3a23f9, 6b7becfe, 0c6f571a, 22343941, 01e30ba7
|
||||
|
||||
---
|
||||
|
||||
## Accomplishments
|
||||
|
||||
1. **docker-compose.yml Updated (D-07)**
|
||||
- Removed `inventory.env` `env_file` references
|
||||
- Added `./config:/app/config:ro` volume mounts for `backend`, `frontend`, and `proxy`
|
||||
- Documented environment variable override behavior in comments
|
||||
|
||||
2. **Dockerfile and entrypoint.sh Updated**
|
||||
- Backend `Dockerfile` and `entrypoint.sh` refactored to use the new `/app/config/` paths
|
||||
- Implemented config validation check during container startup
|
||||
|
||||
3. **.gitignore Rules Finalized (D-08)**
|
||||
- Marked `inventory.env` as deprecated
|
||||
- Confirmed rules to ignore actual configurations while tracking `.example` schema files
|
||||
|
||||
4. **Comprehensive Documentation (D-08)**
|
||||
- **DEPLOYMENT.md:** Completely rewritten to reflect the new YAML configuration system and Python-based tooling
|
||||
- **README.md:** Updated Quick Start and onboarding with the new configuration steps
|
||||
- Cross-referenced all documents for consistent developer experience
|
||||
|
||||
---
|
||||
|
||||
## Technical Details
|
||||
|
||||
- **Single Source of Truth:** `config/` folder is now established as the central point for all configuration.
|
||||
- **Security:** `secrets.yaml` is strictly ignored by git, and the Docker volume is mounted as read-only.
|
||||
- **Deprecation:** All references to `inventory.env` in the deployment infrastructure have been removed.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- [x] `docker compose config` passes with valid YAML syntax
|
||||
- [x] `.gitignore` rules correctly protect sensitive configuration files
|
||||
- [x] `DEPLOYMENT.md` and `README.md` provide clear, updated instructions
|
||||
- [x] All deployment paths integrated with the new YAML structure
|
||||
@@ -2,9 +2,11 @@ import os
|
||||
import anthropic
|
||||
import json
|
||||
import base64
|
||||
from ..config_loader import get_config
|
||||
|
||||
def extract(image_bytes: bytes, prompt: str):
|
||||
api_key = os.environ.get("CLAUDE_API_KEY")
|
||||
config = get_config()
|
||||
api_key = config.get("ai", {}).get("claude_api_key")
|
||||
if not api_key:
|
||||
return None
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import logging
|
||||
from PIL import Image
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
from ..config_loader import get_config
|
||||
|
||||
log = logging.getLogger("ainventory")
|
||||
|
||||
@@ -18,9 +19,10 @@ def get_best_models():
|
||||
]
|
||||
|
||||
def extract(image_bytes: bytes, prompt: str):
|
||||
api_key = os.environ.get("GEMINI_API_KEY")
|
||||
config = get_config()
|
||||
api_key = config.get("ai", {}).get("gemini_api_key")
|
||||
if not api_key:
|
||||
log.error("CRITICAL: GEMINI_API_KEY is MISSING in environment!")
|
||||
log.error("CRITICAL: gemini_api_key is MISSING in configuration!")
|
||||
return None
|
||||
|
||||
# Log partial key for safety debug
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
import time
|
||||
from dotenv import load_dotenv
|
||||
from . import models
|
||||
from .database import SessionLocal
|
||||
from .ai import gemini, claude
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import os
|
||||
import google.generativeai as genai
|
||||
from dotenv import load_dotenv
|
||||
try:
|
||||
from backend.config_loader import get_config
|
||||
except ImportError:
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from backend.config_loader import get_config
|
||||
|
||||
load_dotenv()
|
||||
API_KEY = os.environ.get("GEMINI_API_KEY")
|
||||
config = get_config()
|
||||
API_KEY = config.get("ai", {}).get("gemini_api_key")
|
||||
|
||||
if not API_KEY:
|
||||
print("Error: GEMINI_API_KEY not found in .env")
|
||||
print("Error: gemini_api_key not found in config/backend.yaml, config/secrets.yaml or GEMINI_API_KEY environment variable")
|
||||
exit(1)
|
||||
|
||||
genai.configure(api_key=API_KEY)
|
||||
|
||||
@@ -72,6 +72,12 @@ def _apply_env_overrides(config):
|
||||
"LOGS_DIR": (("application", "logs_dir"), str),
|
||||
"BACKEND_APPLICATION_CORS_ORIGINS": (("application", "cors_origins"), str),
|
||||
"EXTRA_ALLOWED_ORIGINS": (("application", "cors_origins"), str),
|
||||
"ALLOWED_ORIGINS": (("application", "cors_origins"), str),
|
||||
"SERVER_IP": (("application", "server_ip"), str),
|
||||
"FRONTEND_PORT": (("application", "frontend_port"), str),
|
||||
"FRONTEND_SSL_PORT": (("application", "frontend_ssl_port"), str),
|
||||
"BACKEND_PORT": (("application", "backend_port"), str),
|
||||
"BACKEND_SSL_PORT": (("application", "backend_ssl_port"), str),
|
||||
}
|
||||
|
||||
sensitive_vars = [
|
||||
@@ -136,7 +142,12 @@ def load_config() -> dict:
|
||||
"application": {
|
||||
"data_dir": "./data",
|
||||
"logs_dir": "./logs",
|
||||
"cors_origins": "http://localhost:8917"
|
||||
"cors_origins": "http://localhost:8917",
|
||||
"server_ip": "localhost",
|
||||
"frontend_port": "8917",
|
||||
"frontend_ssl_port": "8919",
|
||||
"backend_port": "8918",
|
||||
"backend_ssl_port": "8918"
|
||||
},
|
||||
"features": {
|
||||
"ai_extraction_enabled": True,
|
||||
|
||||
222
deploy.sh
222
deploy.sh
@@ -1,222 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Phase 6, Plan 1, Task 4: Automated Deployment Script
|
||||
# Usage: ./deploy.sh [production|staging|development] [--rebuild]
|
||||
# Purpose: Single-command deployment with Docker Compose, pre-flight checks, and health validation
|
||||
|
||||
DEPLOYMENT_ENV="${1:-production}"
|
||||
REBUILD_FLAG="${2:---no-rebuild}"
|
||||
|
||||
# Color output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
||||
|
||||
log_info "=== TFM aInventory Deployment Script ==="
|
||||
log_info "Environment: $DEPLOYMENT_ENV"
|
||||
log_info "Rebuild: $REBUILD_FLAG"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 1: Pre-flight checks
|
||||
# ============================================================================
|
||||
log_info "Step 1/10: Running pre-flight checks..."
|
||||
|
||||
command -v docker &> /dev/null || log_error "Docker not installed. Please install Docker 24.0+"
|
||||
log_success " ✓ Docker is installed"
|
||||
|
||||
command -v docker-compose &> /dev/null || log_error "Docker Compose not installed. Please install Docker Compose 2.0+"
|
||||
log_success " ✓ Docker Compose is installed"
|
||||
|
||||
[[ -f "docker-compose.yml" ]] || log_error "docker-compose.yml not found in current directory"
|
||||
log_success " ✓ docker-compose.yml found"
|
||||
|
||||
[[ -f "inventory.env" ]] || log_warn "inventory.env not found; attempting to create from template..."
|
||||
if [[ ! -f "inventory.env" ]] && [[ -f "inventory.env.template" ]]; then
|
||||
cp inventory.env.template inventory.env
|
||||
log_success " ✓ inventory.env created from template (review and customize)"
|
||||
elif [[ ! -f "inventory.env" ]]; then
|
||||
log_error "inventory.env not found and no template available. Create inventory.env before deploying."
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# STEP 2: Validate environment file
|
||||
# ============================================================================
|
||||
log_info "Step 2/10: Validating inventory.env..."
|
||||
|
||||
if [[ ! -f ".env.validation.sh" ]]; then
|
||||
log_warn " .env.validation.sh not found; skipping validation"
|
||||
else
|
||||
bash .env.validation.sh || log_error "Environment validation failed"
|
||||
fi
|
||||
|
||||
log_success " ✓ Environment variables validated"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 3: Check port availability
|
||||
# ============================================================================
|
||||
log_info "Step 3/10: Checking port availability..."
|
||||
|
||||
# Source inventory.env to get port values
|
||||
source inventory.env
|
||||
|
||||
BACKEND_PORT=${BACKEND_PORT:-8000}
|
||||
FRONTEND_PORT=${FRONTEND_PORT:-3000}
|
||||
BACKEND_SSL_PORT=${BACKEND_SSL_PORT:-8918}
|
||||
FRONTEND_SSL_PORT=${FRONTEND_SSL_PORT:-8919}
|
||||
|
||||
for port in "$BACKEND_PORT" "$FRONTEND_PORT" "$BACKEND_SSL_PORT" "$FRONTEND_SSL_PORT"; do
|
||||
if command -v netstat &> /dev/null; then
|
||||
if netstat -tuln 2>/dev/null | grep -q ":$port "; then
|
||||
log_error "Port $port is already in use. Choose a different port in inventory.env"
|
||||
fi
|
||||
else
|
||||
log_warn " netstat not available; skipping port check (ensure ports are available)"
|
||||
fi
|
||||
done
|
||||
|
||||
log_success " ✓ All required ports are available"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 4: Check disk space
|
||||
# ============================================================================
|
||||
log_info "Step 4/10: Checking disk space..."
|
||||
|
||||
AVAILABLE_SPACE=$(df . | awk 'NR==2 {print $4}')
|
||||
REQUIRED_SPACE=$((10 * 1024 * 1024)) # 10GB in KB
|
||||
|
||||
if [[ $AVAILABLE_SPACE -lt $REQUIRED_SPACE ]]; then
|
||||
log_warn " Available space: $(($AVAILABLE_SPACE / 1024 / 1024))GB (recommended: 10GB+)"
|
||||
else
|
||||
log_success " ✓ Sufficient disk space available ($(($AVAILABLE_SPACE / 1024 / 1024))GB)"
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# STEP 5: Build or pull images
|
||||
# ============================================================================
|
||||
log_info "Step 5/10: Building Docker images..."
|
||||
|
||||
if [[ "$REBUILD_FLAG" == "--rebuild" ]]; then
|
||||
log_info " Building with --no-cache (full rebuild)..."
|
||||
docker-compose build --no-cache || log_error "Docker build failed"
|
||||
else
|
||||
log_info " Building with layer cache (incremental)..."
|
||||
docker-compose build || log_error "Docker build failed"
|
||||
fi
|
||||
|
||||
log_success " ✓ Docker images built successfully"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 6: Create data directories
|
||||
# ============================================================================
|
||||
log_info "Step 6/10: Preparing data directories..."
|
||||
|
||||
mkdir -p data logs config
|
||||
mkdir -p data/caddy_data data/caddy_config
|
||||
chmod -R 777 data logs config
|
||||
|
||||
log_success " ✓ Data directories created with proper permissions"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 7: Initialize database
|
||||
# ============================================================================
|
||||
log_info "Step 7/10: Checking database initialization..."
|
||||
|
||||
if [[ ! -f "data/inventory.db" ]]; then
|
||||
log_info " Database not found; will be initialized on first backend startup"
|
||||
log_success " ✓ Database initialization scheduled"
|
||||
else
|
||||
log_success " ✓ Existing database found; reusing"
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# STEP 8: Start services
|
||||
# ============================================================================
|
||||
log_info "Step 8/10: Starting Docker services..."
|
||||
|
||||
docker-compose up -d || log_error "Failed to start Docker services"
|
||||
log_success " ✓ Services started in background"
|
||||
|
||||
# ============================================================================
|
||||
# STEP 9: Wait for health checks
|
||||
# ============================================================================
|
||||
log_info "Step 9/10: Waiting for services to become healthy (max 60 seconds)..."
|
||||
|
||||
max_attempts=30
|
||||
attempt=0
|
||||
all_healthy=false
|
||||
|
||||
while [[ $attempt -lt $max_attempts ]]; do
|
||||
# Check if all 3 services are healthy
|
||||
if docker-compose ps | grep -q "healthy.*healthy.*healthy"; then
|
||||
all_healthy=true
|
||||
break
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
remaining=$((max_attempts - attempt))
|
||||
log_info " Waiting... ($remaining attempts remaining)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [[ "$all_healthy" == true ]]; then
|
||||
log_success " ✓ All services are healthy"
|
||||
else
|
||||
log_warn "Services did not become healthy within timeout. Checking logs..."
|
||||
docker-compose logs --tail=50 || true
|
||||
log_error "Service health check timeout. Review logs above."
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# STEP 10: Verify connectivity
|
||||
# ============================================================================
|
||||
log_info "Step 10/10: Verifying service connectivity..."
|
||||
|
||||
if curl -sf "http://localhost:${BACKEND_PORT}/health" &> /dev/null; then
|
||||
log_success " ✓ Backend API responding at http://localhost:${BACKEND_PORT}/health"
|
||||
else
|
||||
log_warn " Backend health check failed; services may still be initializing"
|
||||
fi
|
||||
|
||||
if curl -sf "http://localhost:${FRONTEND_PORT}/" &> /dev/null; then
|
||||
log_success " ✓ Frontend responding at http://localhost:${FRONTEND_PORT}"
|
||||
else
|
||||
log_warn " Frontend check failed; container may still be initializing"
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# Summary
|
||||
# ============================================================================
|
||||
echo ""
|
||||
echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║${NC} Deployment completed successfully! ${GREEN}║${NC}"
|
||||
echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo "Access points:"
|
||||
echo " Frontend (HTTP): http://localhost:${FRONTEND_PORT}"
|
||||
echo " Backend (HTTP): http://localhost:${BACKEND_PORT}"
|
||||
echo " API Docs: http://localhost:${BACKEND_PORT}/docs"
|
||||
echo " Frontend (HTTPS): https://localhost:${FRONTEND_SSL_PORT}"
|
||||
echo " Backend (HTTPS): https://localhost:${BACKEND_SSL_PORT}"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " View logs: docker-compose logs -f"
|
||||
echo " Stop services: docker-compose down"
|
||||
echo " Restart: docker-compose restart"
|
||||
echo " Status: docker-compose ps"
|
||||
echo ""
|
||||
echo "For deployment in production ($DEPLOYMENT_ENV):"
|
||||
echo " • Review and update JWT_SECRET_KEY in inventory.env"
|
||||
echo " • Configure firewall to expose only required ports"
|
||||
echo " • Set up automated backups (see docs/DEPLOYMENT_QUICKSTART.md)"
|
||||
echo " • Monitor logs regularly: docker-compose logs -f"
|
||||
echo ""
|
||||
log_success "Deployment ready!"
|
||||
@@ -1,73 +0,0 @@
|
||||
#!/bin/bash
|
||||
# export_prod.sh - Generates a clean production bundle for distribution
|
||||
|
||||
echo "📦 Preparing TFM aInventory Production Bundle..."
|
||||
|
||||
# Extract version from frontend/VERSION.json
|
||||
VERSION=$(grep '"version"' frontend/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' --exclude 'tests' backend/ "$PROD_DIR/backend/"
|
||||
|
||||
# Orchestration, Config & Scripts
|
||||
mkdir -p "$PROD_DIR/config" "$PROD_DIR/scripts"
|
||||
cp docker-compose.yml "$PROD_DIR/"
|
||||
rsync -a config/ "$PROD_DIR/config/"
|
||||
rsync -a scripts/ "$PROD_DIR/scripts/"
|
||||
cp start_server.sh "$PROD_DIR/"
|
||||
cp run_standalone.sh "$PROD_DIR/"
|
||||
cp install_service.sh "$PROD_DIR/"
|
||||
cp inventory.service.template "$PROD_DIR/"
|
||||
cp USER_GUIDE.md "$PROD_DIR/"
|
||||
cp README.md "$PROD_DIR/INSTALLATION_GUIDE.md"
|
||||
cp inventory.env "$PROD_DIR/"
|
||||
cp deploy.sh "$PROD_DIR/"
|
||||
cp .git_path "$PROD_DIR/" 2>/dev/null || true
|
||||
cp frontend/VERSION.json "$PROD_DIR/"
|
||||
cp frontend/VERSION.json "$PROD_DIR/frontend/"
|
||||
|
||||
# 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>:8909 (Accept the internal security warning).
|
||||
|
||||
TO INSTALL AS A LINUX SYSTEM SERVICE (Optional):
|
||||
1. sudo ./install_service.sh
|
||||
2. sudo systemctl start inventory
|
||||
|
||||
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>:8909
|
||||
|
||||
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"
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/bin/bash
|
||||
# install_service.sh - Installs the inventory system as a standalone systemd service
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "🚫 This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "⚙️ Installing TFM aInventory as a Standalone Linux service..."
|
||||
|
||||
# Detect working directory
|
||||
WORKING_DIR="$(pwd)"
|
||||
|
||||
# 1. Dependency Checks
|
||||
echo "🔍 Checking dependencies..."
|
||||
for cmd in python3 node npm; do
|
||||
if ! command -v $cmd &> /dev/null; then
|
||||
echo "❌ $cmd not found! Please install it before proceeding."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. Setup Backend Environment
|
||||
echo "🐍 Setting up Python Virtual Environment..."
|
||||
if [ ! -d ".venv" ]; then
|
||||
python3 -m venv .venv
|
||||
fi
|
||||
source .venv/bin/activate
|
||||
pip install -q --upgrade pip
|
||||
pip install -q -r backend/requirements.txt
|
||||
|
||||
# 3. Setup Frontend Environment
|
||||
echo "📦 Installing Node dependencies (this may take a minute)..."
|
||||
cd frontend
|
||||
npm install --quiet
|
||||
echo "🏗️ Building Frontend for Production (Next.js build)..."
|
||||
npm run build
|
||||
cd ..
|
||||
|
||||
# 4. Create the final service file from template
|
||||
TEMPLATE="inventory.service.template"
|
||||
TARGET="/etc/systemd/system/inventory.service"
|
||||
|
||||
if [ ! -f "$TEMPLATE" ]; then
|
||||
echo "❌ Template file $TEMPLATE not found in current directory!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed "s|__WORKING_DIR__|$WORKING_DIR|g" "$TEMPLATE" > "$TARGET"
|
||||
|
||||
echo "📝 Service file created at $TARGET"
|
||||
|
||||
# 5. Reload and enable
|
||||
systemctl daemon-reload
|
||||
systemctl enable inventory.service
|
||||
|
||||
# 6. Ensure scripts are executable
|
||||
chmod +x run_standalone.sh
|
||||
chmod +x start_server.sh
|
||||
|
||||
echo ""
|
||||
echo "🚀 TFM aInventory Standalone service installed and enabled!"
|
||||
echo " Commands:"
|
||||
echo " 👉 sudo systemctl start inventory"
|
||||
echo " 👉 sudo systemctl status inventory"
|
||||
echo " 👉 sudo systemctl stop inventory"
|
||||
echo ""
|
||||
echo "Note: The service is currently ENABLED to start on boot, but NOT started."
|
||||
echo " Run 'sudo systemctl start inventory' to launch it now."
|
||||
@@ -1,32 +0,0 @@
|
||||
# =============================================================================
|
||||
# TFM aInventory - Docker Compose Environment
|
||||
# =============================================================================
|
||||
# This file is used by Docker Compose for host-side port mapping.
|
||||
# It should match the values in config/network_config.env
|
||||
# =============================================================================
|
||||
|
||||
SERVER_IP=192.168.84.131
|
||||
|
||||
# Backend Ports
|
||||
BACKEND_PORT=8916
|
||||
BACKEND_SSL_PORT=8918
|
||||
|
||||
# Frontend Ports
|
||||
FRONTEND_PORT=8917
|
||||
FRONTEND_SSL_PORT=8919
|
||||
|
||||
# Security
|
||||
JWT_SECRET_KEY=change_me_in_production
|
||||
|
||||
# AI
|
||||
GEMINI_API_KEY=AIzaSyAajthWG2agpDLyJHY11U5qFLP4WnV5z0w
|
||||
CLAUDE_API_KEY=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
|
||||
|
||||
# External Access (CORS)
|
||||
# Comma-separated list of extra IPs or FQDNs allowed to connect (e.g. Tailscale, VPN)
|
||||
EXTRA_ALLOWED_ORIGINS=100.78.182.0/24
|
||||
|
||||
# Data and Logging (for standalone deployment)
|
||||
DATA_DIR=./data
|
||||
LOGS_DIR=./logs
|
||||
LOG_LEVEL=INFO
|
||||
@@ -1,37 +0,0 @@
|
||||
# =============================================================================
|
||||
# TFM aInventory — Master Environment Configuration (v1.10.15)
|
||||
# =============================================================================
|
||||
# 1. Copy this file to 'inventory.env'
|
||||
# 2. Fill in your real values
|
||||
# 3. 'inventory.env' is ignored by Git to protect your secrets.
|
||||
#
|
||||
# SYSTEM REQUIREMENTS (before running ./start_server.sh):
|
||||
# - Node.js v20+ (required for frontend build)
|
||||
# - Python 3.12+ with python3.12-venv package
|
||||
# On Debian/Ubuntu: sudo apt install python3.12-venv
|
||||
# =============================================================================
|
||||
|
||||
# --- Network & Identity ---
|
||||
# Use your LAN IP (e.g., 192.168.1.10) for mobile access.
|
||||
SERVER_IP=localhost
|
||||
|
||||
# --- AI API Keys ---
|
||||
# Google Gemini API Key (Required for AI label OCR onboarding)
|
||||
# Get one at: https://aistudio.google.com/
|
||||
GEMINI_API_KEY=your_gemini_api_key_here
|
||||
|
||||
# --- Security ---
|
||||
# JWT secret key — generate a strong random value for production:
|
||||
# python3 -c "import secrets; print(secrets.token_urlsafe(64))"
|
||||
JWT_SECRET_KEY=change_me_in_production
|
||||
|
||||
# --- Infrastructure Ports (Host-side mapping) ---
|
||||
BACKEND_PORT=8916
|
||||
BACKEND_SSL_PORT=8918
|
||||
FRONTEND_PORT=8917
|
||||
FRONTEND_SSL_PORT=8919
|
||||
|
||||
# --- External Access (CORS) ---
|
||||
# Comma-separated list of extra IPs or FQDNs allowed (e.g. Tailscale, VPN)
|
||||
# Example: EXTRA_ALLOWED_ORIGINS=100.78.182.27,inventory.my-domain.com
|
||||
EXTRA_ALLOWED_ORIGINS=
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
# run_standalone.sh - Headless production launcher for TFM aInventory
|
||||
# manages Backend, Frontend, and SSL Proxies in a single process group.
|
||||
|
||||
echo "🚀 Starting TFM aInventory in Standalone Mode..."
|
||||
|
||||
# Trapping termination signals to clean up child processes
|
||||
trap "echo 'Stopping all processes...'; kill 0" SIGINT SIGTERM EXIT
|
||||
|
||||
# --- CONFIGURATION (Default values, overridden by network_configinventory.env) ---
|
||||
BACKEND_PORT=8000
|
||||
FRONTEND_PORT=3001
|
||||
BACKEND_SSL_PORT=3002
|
||||
FRONTEND_SSL_PORT=3003
|
||||
SERVER_IP="localhost"
|
||||
|
||||
# Load Configuration from file if it exists
|
||||
CONFIG_PATH="$(cd "$(dirname "$0")" && pwd)/inventory.env"
|
||||
if [ -f "$CONFIG_PATH" ]; then
|
||||
echo "⚙️ Loading network configuration from $CONFIG_PATH..."
|
||||
export $(grep -v '^#' "$CONFIG_PATH" | xargs)
|
||||
fi
|
||||
|
||||
# 1. Activate Environment
|
||||
if [ -d ".venv" ]; then
|
||||
source .venv/bin/activate
|
||||
fi
|
||||
|
||||
# 1.5 Sync Network Config to Frontend
|
||||
echo "🔌 Syncing network configuration to frontend..."
|
||||
mkdir -p frontend/public
|
||||
cat <<EOF > frontend/public/network.json
|
||||
{
|
||||
"SERVER_IP": "$SERVER_IP",
|
||||
"BACKEND_PORT": $BACKEND_PORT,
|
||||
"BACKEND_SSL_PORT": $BACKEND_SSL_PORT,
|
||||
"FRONTEND_PORT": $FRONTEND_PORT,
|
||||
"FRONTEND_SSL_PORT": $FRONTEND_SSL_PORT
|
||||
}
|
||||
EOF
|
||||
|
||||
# 2. Start Backend (No Reload for Prod)
|
||||
echo "🔥 Starting Backend (Uvicorn)..."
|
||||
python3 -m uvicorn backend.main:app --host 0.0.0.0 --port $BACKEND_PORT &
|
||||
|
||||
# 3. Start Frontend (Production Start)
|
||||
echo "💻 Starting Frontend (Next.js Prod)..."
|
||||
cd frontend
|
||||
npm run start -- -p $FRONTEND_PORT &
|
||||
cd ..
|
||||
|
||||
# 4. Start Proxies (via npx)
|
||||
echo "🛡️ Starting HTTPS Proxies..."
|
||||
npx local-ssl-proxy --source $BACKEND_SSL_PORT --target $BACKEND_PORT --hostname 0.0.0.0 > /dev/null 2>&1 &
|
||||
npx local-ssl-proxy --source $FRONTEND_SSL_PORT --target $FRONTEND_PORT --hostname 0.0.0.0 > /dev/null 2>&1 &
|
||||
|
||||
# 5. Detection of IP for logs
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
LOCAL_IP=$(ipconfig getifaddr en0 || ipconfig getifaddr en1 || echo "localhost")
|
||||
else
|
||||
LOCAL_IP=$(hostname -I | awk '{print $1}')
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ TFM aInventory is active at https://$LOCAL_IP:$FRONTEND_SSL_PORT"
|
||||
echo " Processes are running in background. Monitoring logs..."
|
||||
echo ""
|
||||
|
||||
# Wait for children
|
||||
wait
|
||||
Reference in New Issue
Block a user