From 6e88ea91071f2c93759b64308cd19e602596df1c Mon Sep 17 00:00:00 2001 From: Daniel Bedeleanu Date: Thu, 23 Apr 2026 15:36:20 +0300 Subject: [PATCH] Build [v1.14.20] --- .standalone.pid | 6 +- PROJECT_ARCHITECTURE.md | 9 +-- backups/ainventory_2026-04-23_15-27-27.tar.gz | Bin 0 -> 28954 bytes dev_docs/PLAN.md | 5 +- dev_docs/SESSION_STATE.md | 68 +++++++++--------- frontend/VERSION.json | 6 +- 6 files changed, 48 insertions(+), 46 deletions(-) create mode 100644 backups/ainventory_2026-04-23_15-27-27.tar.gz diff --git a/.standalone.pid b/.standalone.pid index 4e54b838..9a7d29f1 100644 --- a/.standalone.pid +++ b/.standalone.pid @@ -1,3 +1,3 @@ -836027 -836028 -836042 +836417 +836418 +836432 diff --git a/PROJECT_ARCHITECTURE.md b/PROJECT_ARCHITECTURE.md index 7ee9ee5c..858c9156 100644 --- a/PROJECT_ARCHITECTURE.md +++ b/PROJECT_ARCHITECTURE.md @@ -28,9 +28,10 @@ A unified system for inventory management featuring web administration, offline ### 2.3 Operations & Tooling - **PWA**: `next-pwa` (Service Workers + Manifest) -- **HTTPS Proxy**: Caddy (Port 8909) +- **HTTPS Proxy**: Caddy (Ports 8918/8919) - **Containerization**: Docker & Docker Compose -- **Deployment**: `deploy.sh` (Docker) or `start_server.sh` (Standalone) +- **Deployment**: `deploy.py` (Docker) or `run_standalone.py` (Standalone) +- **Configuration**: Domain-specific YAML (`config/`) with `network.yaml` as SSOT. --- @@ -73,9 +74,9 @@ A unified system for inventory management featuring web administration, offline - **JWT**: Stateless tokens for API auth. - **LDAP**: Primary source of truth for users in enterprise mode. - **Password Caching**: Encrypted local cache for offline authentication. -- **CORS**: Restricted origins in production via `config/backend.yaml`. +- **CORS**: Restricted origins in production via `config/network.yaml` (SSOT). --- **Last Updated**: 2026-04-23 -**Version**: 1.14.7 +**Version**: 1.14.19 diff --git a/backups/ainventory_2026-04-23_15-27-27.tar.gz b/backups/ainventory_2026-04-23_15-27-27.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..dbc96e2482d70c18753b3b83e0b6c35984a3e90f GIT binary patch literal 28954 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 Na_&-JvVZ%76 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 YAML > Defaults. -- **Deprecation**: `inventory.env` completely removed. +- **Deprecation**: `inventory.env` and legacy `.sh` scripts completely removed. ### Phase 8: Hardening & Release (PLANNED) - Stability monitoring, final UX refinements, production-ready runbook. diff --git a/dev_docs/SESSION_STATE.md b/dev_docs/SESSION_STATE.md index 2413d721..33004b4d 100644 --- a/dev_docs/SESSION_STATE.md +++ b/dev_docs/SESSION_STATE.md @@ -2,53 +2,53 @@ **Active AI:** Claude Haiku 4.5 (Claude Code) **Last Updated:** 2026-04-23 -**Current Version:** v1.14.7 -**Status**: ✅ PHASE 7 COMPLETE +**Current Version:** v1.14.19 +**Status**: ✅ PHASE 7 COMPLETE | 🟢 READY FOR PHASE 8 --- -## SESSION 41 EXECUTION — Phase 7 Execution & Consolidation +## SESSION 41 EXECUTION SUMMARY — Infrastructure & Export Fixes -### Work Completed This Session +### 1. Phase 7: Config Consolidation (COMPLETE) +- **Centralized YAML**: Migrated all configuration to `config/*.yaml`. +- **SSOT Architecture**: Established `network.yaml` as the Master Source of Truth for Server IP and Port management. +- **Dynamic Injection**: Frontend API URLs and Backend CORS are now dynamically calculated from master network settings. +- **Python Tooling**: All legacy `.sh` scripts converted to robust, secure Python scripts in `scripts/`. +- **Enhanced Launcher**: `run_standalone.py` now supports `start`, `stop`, `restart`, `status`, and Caddy SSL proxying. -**1. Phase 7 Execution (Config Consolidation):** -- ✅ Wave 1: Created `config/` structure, 5 schema examples, 4 actual config files, and 155-line `config/README.md`. -- ✅ Wave 2 (Backend): Refactored `backend/config_loader.py` for YAML and D-06 load order. Updated `config_manager.py`, `main.py`, and `entrypoint.sh`. -- ✅ Wave 2 (Scripts): Converted `deploy.sh`, `run_standalone.sh`, `install_service.sh`, and `export_prod.sh` to secure Python scripts with YAML parsing. -- ✅ Wave 3 (Docker & Docs): Updated `docker-compose.yml` (volume mounts), `Dockerfile`, `.gitignore`, `DEPLOYMENT.md`, and `README.md`. -- ✅ Post-Wave: Refactored legacy `load_dotenv()` in `ai_vision.py`, `check_models.py`, `gemini.py`, and `claude.py`. -- ✅ Cleanup: Deleted all deprecated bash scripts and legacy `.env` files. Updated `scripts/save_version.py` for new infrastructure. +### 2. Admin & Security Improvements +- **AI Key Detection**: Fixed backend logic to correctly report AI key status from YAML/Secrets. +- **Secure Saving**: Implemented `ConfigManager.update_keys()` to route sensitive data correctly to `secrets.yaml`. +- **Recursion Fix**: Resolved a critical infinite recursion loop in the configuration manager. -**2. Versioning & State Sync:** -- ✅ Incremented version to `v1.14.7` across all SSOT files (`VERSION.json`, `frontend/VERSION.json`, `PROJECT_ARCHITECTURE.md`, `dev_docs/PLAN.md`). -- ✅ Updated roadmap in `dev_docs/PLAN.md` marking Phase 7 as COMPLETED. -- ✅ Verified all files pass syntax checks (Python/Bash). +### 3. Export System Overhaul +- **Data Integrity**: Fixed a routing collision that caused binary SQLite downloads instead of CSV data. +- **FastAPI Streaming**: Refactored exports to use `StreamingResponse` for memory efficiency. +- **Premium UI**: Integrated the `ExportPanel` into the dark-mode aesthetic with standard premium button styles. +- **WebSocket Fix**: Improved Caddy configuration for Next.js HMR stability. -### Phase 7 Artifact Status -- **Plans**: `.planning/phases/07-config-consolidation/07-01-PLAN.md` ✓ COMPLETED -- **Plans**: `.planning/phases/07-config-consolidation/07-02-PLAN.md` ✓ COMPLETED -- **Plans**: `.planning/phases/07-config-consolidation/07-03-PLAN.md` ✓ COMPLETED -- **Plans**: `.planning/phases/07-config-consolidation/07-04-PLAN.md` ✓ COMPLETED -- **Summaries**: `.planning/phases/07-config-consolidation/07-01,02,03,04-SUMMARY.md` ✓ Created -- **Context**: `.planning/phases/07-config-consolidation/07-CONTEXT.md` ✓ Archived +### 4. Cleanup & Preparation +- ✅ Deleted all deprecated `.sh` and `.env` files. +- ✅ Rebuilt virtual environment (`venv/`) and verified dependencies (added `openpyxl`). +- ✅ Incremented system version to **v1.14.19**. --- -## NEXT STEPS +## NEXT STEPS (Phase 8: Hardening & Release) -1. **Start Phase 8 (Hardening & Release)**: - - Perform end-to-end testing of the new Python deployment scripts. - - Verify Docker deployment with `python3 scripts/deploy.py production`. - - Perform final UX refinements and accessibility audits. - - Prepare production-ready runbook for v1.15.0 stable release. +1. **End-to-End Testing**: + - Verify data consistency in multi-page Excel exports. + - Stress test the new Python-based deployment scripts. -2. **Stability Monitoring**: - - Check logs for any configuration parsing warnings. - - Ensure all environment variable overrides work as expected (D-06). +2. **UX Refinement**: + - Perform a final accessibility audit on the new Admin UI components. + - Ensure consistent loading states across all Admin panels. -3. **Cleanup**: - - Archive Phase 7 planning artifacts to `dev_docs/ARCHIVE_LOGS.md` or similar. +3. **Production Preparation**: + - Finalize the production runbook. + - Prepare for the v1.15.0 "Stable" release milestone. --- -✓ Phase 7 fully implemented, verified, and cleaned up. Ready for the next phase. +✓ All tasks for this session are implemented, verified, and committed. +✓ Services are currently RUNNING in the background. diff --git a/frontend/VERSION.json b/frontend/VERSION.json index 9ffe1b35..7adb8066 100644 --- a/frontend/VERSION.json +++ b/frontend/VERSION.json @@ -1,6 +1,6 @@ { - "version": "1.14.19", - "last_build": "2026-04-23-1527", + "version": "1.14.20", + "last_build": "2026-04-23-1536", "codename": "ConfigCore", - "commit": "941761ad" + "commit": "b0ac7426" } \ No newline at end of file