Compare commits
10 Commits
96fe655f72
...
v1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb9df1d73f | ||
|
|
fe18fe01c6 | ||
|
|
91bdd791d2 | ||
|
|
ed06f0b56e | ||
|
|
df9468344d | ||
|
|
d87067e88c | ||
|
|
2e5ce8d153 | ||
|
|
c71a815792 | ||
|
|
0a9ea0f575 | ||
|
|
432cd28ca5 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -4,3 +4,7 @@ __pycache__/
|
|||||||
*.pyc
|
*.pyc
|
||||||
.env
|
.env
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
aInventory-PROD*
|
||||||
|
aInventory-PROD*.zip
|
||||||
|
logs/
|
||||||
|
backend/logs/
|
||||||
|
|||||||
78
AI_RULES.md
78
AI_RULES.md
@@ -1,43 +1,51 @@
|
|||||||
# AI AGENT RULES - SINGLE SOURCE OF TRUTH
|
# AI AGENT RULES - MANDATORY ENTRY POINT
|
||||||
|
|
||||||
This file is the single source of truth for ALL Artificial Intelligence agents working on this project (Claude, Gemini, etc.).
|
**READ THIS ENTIRE FILE BEFORE EXECUTING ANY TASK.**
|
||||||
Any AI or session MUST respect these mandatory rules.
|
This is the **Single Source of Truth** for ALL Artificial Intelligence agents (Claude, Gemini, etc.) working on this project.
|
||||||
|
(Automatic IDE entry points like `GEMINI.md` and `CLAUDE.md` exist solely to redirect agents to this main file).
|
||||||
|
For technical architecture, data models, and stack details, refer to [PROJECT_ARCHITECTURE.md](PROJECT_ARCHITECTURE.md).
|
||||||
|
|
||||||
## General Rules
|
## 1. Multi-AI Coordination & Memory
|
||||||
- **UI & Code Language**: All web interfaces, functions, variables, and any text inside the application MUST BE DIRECTLY AND ONLY IN ENGLISH.
|
|
||||||
- **Communication Language**: Conversation with the user will be in Romanian or English, preferably Romanian.
|
|
||||||
|
|
||||||
## Multi-AI Coordination & Handover
|
|
||||||
- **MANDATORY STARTUP**: Every AI session MUST first read `dev_docs/SESSION_STATE.md` to understand current context.
|
- **MANDATORY STARTUP**: Every AI session MUST first read `dev_docs/SESSION_STATE.md` to understand current context.
|
||||||
- **MANDATORY HANDOVER**: At the end of every task/session, create or update a handover note in `dev_docs/SESSION_STATE.md`. Specify: **Active AI**, **Current Status**, **Technical Context** (details not in code), and **Next Steps**.
|
- **MANDATORY HANDOVER**: At the end of every task/session, update the handover note in `dev_docs/SESSION_STATE.md`. Specify: **Active AI**, **Current Status**, **Technical Context**, and **Next Steps**.
|
||||||
- **ARCHIVAL RULE**: To prevent `SESSION_STATE.md` from bloating, incoming AI agents MUST move all content of the *previous* session handover into the top of `dev_docs/SESSION_HISTORY.md` before writing their own new state. This keeps `SESSION_STATE.md` focused only on the *active* session.
|
- **ARCHIVAL RULE**: Before writing new state, move all content of the *previous* session handover into the top of `dev_docs/SESSION_HISTORY.md` to prevent bloat.
|
||||||
- **NO INTERACTION OVERLAP**: Never modify a file if another AI session is explicitly working on it according to `SESSION_STATE.md`.
|
- **NO INTERACTION OVERLAP**: Never modify a file if another AI session is explicitly working on it.
|
||||||
|
|
||||||
## Implementation Completion
|
## 2. Global Operational Laws
|
||||||
- All code modifications MUST be committed in git before the task is considered finished. `VERSION.json` must be updated on EACH commit.
|
- **STRICT ENGLISH POLICY**: All web interfaces, code, variables, scripts, and documentation MUST BE DIRECTLY AND ONLY IN ENGLISH. If you find Romanian text in code, translate it immediately.
|
||||||
- **MANDATORY GIT RULE:** Never push to remote unless explicitly requested by the user. Only commit locally with proper messages. Always assume the user will handle all `git push` operations. If a task requires pushing, ask for explicit permission first.
|
- **COMMUNICATION LANGUAGE**: Conversation with the user will be in Romanian or English (preferably Romanian).
|
||||||
- **GIT BINARY PATH**: On this macOS environment, the system `git` (in `/usr/bin/git`) is often broken due to `xcode-select` issues. ALWAYS use the binary path stored in `.git_path` at the project root for all Git operations.
|
- **GIT BINARY PATH**: On this macOS environment, the system `git` is often broken. ALWAYS use the binary path stored in `.git_path` at the project root for all Git operations.
|
||||||
- **GIT BRANCHING STRUCTURE**:
|
- **COMMIT & PUSH STRICT RULE**:
|
||||||
- The main stable branch is `master`.
|
- Never push to remote (`git push`) or use force flags (`--hard`, `--force`) unless explicitly requested.
|
||||||
- All active development MUST occur in the `dev` branch.
|
- Always update `VERSION.json` on every commit.
|
||||||
- Every major version MUST have its own dedicated archival branch named `vX` (e.g., `v1`, `v2`) which copies the state of the major release.
|
- Do NOT add AI co-author signatures (e.g., `Co-Authored-By: AI...`) to commit messages.
|
||||||
- **MANDATORY GIT RULE**: NO AI is allowed to write in git commits that it is the author or co-author (e.g., DO NOT add texts like `Co-Authored-By: AI...`). Commits should only contain technical messages.
|
- Branching: `master` (stable), `dev` (active development), `vX` (archival releases).
|
||||||
- **MANDATORY LOGGING**: Any modification of code, architecture, or logic MUST be documented in `dev_docs/ARCHIVE_LOGS.md` at the end of the task. The log must include modified files, purpose of modification, and (if applicable) test results.
|
- **MANDATORY LOGGING**: Document coding/architecture changes in `dev_docs/ARCHIVE_LOGS.md` at the end of the task.
|
||||||
- **MANDATORY PLAN ARCHIVING**: Once a phase or task is confirmed as completed and verified, the Architect (Gemini/AI) MUST move these entries from `PLAN.md` into `dev_docs/PLAN_HISTORY.md`. This maintains the active plan's focus and prevents document bloat.
|
- **TRIPLE CONFIRMATION (Safe Forget)**: You cannot delete a physical location, item, or critical entity without explicit user permission three times.
|
||||||
- After finishing an entire job, end your final response on a separate line exactly with:
|
|
||||||
|
## 3. UI/UX Fidelity Specifications
|
||||||
|
- **Fidelity First**: Never simplify the UI unless asked. Density and aesthetics must remain "Premium".
|
||||||
|
- **Styling**: Tailwind CSS. Font weights/spacing must be consistent (Inter/Roboto).
|
||||||
|
- **Readability**: NO `uppercase` or `tracking-widest` styles. Use standard camel/Title case.
|
||||||
|
- **Icons**: Use **Lucide Icons** exclusively. NO emojis.
|
||||||
|
- **Interactive Affordance**: All select/dropdown boxes MUST have a `ChevronDown` icon. Masked passwords should have reduced opacity (`text-white/50`).
|
||||||
|
- **Iconography Standardization**:
|
||||||
|
- **Categories**: ALWAYS use `Layers` (Color: `text-primary`).
|
||||||
|
- **Item Types**: ALWAYS use `Package` (Color: `text-green-500`).
|
||||||
|
|
||||||
|
## 4. Documentation Maintenance
|
||||||
|
- **SSOT INTEGRITY**: Whenever a feature is added, modified, or removed, you MUST update all corresponding documentation files:
|
||||||
|
- `README.md` (General usage & technical modes).
|
||||||
|
- `USER_GUIDE.md` (End-user instructions).
|
||||||
|
- `PROJECT_ARCHITECTURE.md` (Technical logic & data models).
|
||||||
|
- `export_prod.sh` (If new scripts or files must be included in the production bundle).
|
||||||
|
- **REAL-TIME UPDATES**: Documentation updates are NOT optional and must be performed within the same session as the code changes.
|
||||||
|
|
||||||
|
## 5. End of Session Protocol
|
||||||
|
- Once a phase/task from `PLAN.md` is completed and verified, move that entry into `dev_docs/PLAN_HISTORY.md`.
|
||||||
|
- After finishing an entire job (including updating session state, architecture logs, and versioning), end your final response on a separate line exactly with:
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
✓ Done.
|
✓ Done.
|
||||||
```
|
```
|
||||||
- Do not provide unnecessary summaries of the code.
|
- Do not provide unnecessary verbatim summaries of the code.
|
||||||
|
|
||||||
## Triple Confirmation & Safety Limits
|
|
||||||
- **Safe Forget**: You cannot delete a physical location, item, or critical entity without a triple confirmation mechanism.
|
|
||||||
- **No Force Operations**: Never use destructive flags (e.g., `git reset --hard`, `git push --force`, `rm -rf`) without explicit user permission.
|
|
||||||
|
|
||||||
## UI/UX & Documentation Rules
|
|
||||||
- **STRICT ENGLISH POLICY**: ANY TEXT within the application (documentation, scripts, CLI, UI, internal comments, logs, etc.) MUST be strictly in English. NO Romanian characters (ăâîșț) or words are allowed in the repository.
|
|
||||||
- **MANDATORY TRANSLATION**: Any Romanian text found during an AI session (in any file) MUST be translated to English immediately.
|
|
||||||
- Use Bootstrap Icons (`<i class="bi bi-something"></i>`); never use emojis.
|
|
||||||
- The UI must remain fully functional offline (no external CDNs).
|
|
||||||
- **MANDATORY UI FIDELITY**: Any modification to UI components (headers, banners, cards, buttons) MUST comply with the specifications in `dev_docs/UI_FIDELITY_SPEC.md` to prevent regressions. All agents MUST read that document before modifying frontend code.
|
|
||||||
|
|||||||
11
CLAUDE.md
Normal file
11
CLAUDE.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# CLAUDE ENTRY POINT
|
||||||
|
|
||||||
|
You are Claude, operating on the TFM aInventory project.
|
||||||
|
|
||||||
|
**IMMEDIATE MANDATORY ACTION:**
|
||||||
|
Before taking any action or writing code, you MUST read the following Single Source of Truth files:
|
||||||
|
1. `AI_RULES.md` (Contains your operational constraints, Git rules, and UI fidelity laws).
|
||||||
|
2. `PROJECT_ARCHITECTURE.md` (Contains the tech stack, data models, and system logic).
|
||||||
|
3. `dev_docs/SESSION_STATE.md` (Contains the current handover status from the previous AI).
|
||||||
|
|
||||||
|
Do not proceed with any task until you have analyzed these three files.
|
||||||
12
Caddyfile
Normal file
12
Caddyfile
Normal 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
|
||||||
|
}
|
||||||
11
GEMINI.md
Normal file
11
GEMINI.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# GEMINI ENTRY POINT
|
||||||
|
|
||||||
|
You are Gemini (Antigravity), operating on the TFM aInventory project.
|
||||||
|
|
||||||
|
**IMMEDIATE MANDATORY ACTION:**
|
||||||
|
Before taking any action or writing code, you MUST read the following Single Source of Truth files:
|
||||||
|
1. `AI_RULES.md` (Contains your operational constraints, Git rules, and UI fidelity laws).
|
||||||
|
2. `PROJECT_ARCHITECTURE.md` (Contains the tech stack, data models, and system logic).
|
||||||
|
3. `dev_docs/SESSION_STATE.md` (Contains the current handover status from the previous AI).
|
||||||
|
|
||||||
|
Do not proceed with any task until you have analyzed these three files.
|
||||||
54
PLAN.md
54
PLAN.md
@@ -1,55 +1,13 @@
|
|||||||
# Inventory PWA System Architecture & Implementation Plan
|
# Active Development Plan
|
||||||
|
|
||||||
This document defines the technical architecture and rules for the InventoryAI System (2026 Edition).
|
This document tracks the immediate implementation checklist. For overarching design and constraints, see [PROJECT_ARCHITECTURE.md](PROJECT_ARCHITECTURE.md).
|
||||||
|
|
||||||
## 1. Core Architecture
|
|
||||||
|
|
||||||
### 1.1 Backend (Python 3.14+)
|
|
||||||
- **Framework:** FastAPI
|
|
||||||
- **Database:** SQLite (SQLAlchemy) - chosen for local performance and simplicity.
|
|
||||||
- **Organization:** Modular design with separate routers for Items and Operations.
|
|
||||||
|
|
||||||
### 1.2 Frontend (Next.js 15+ PWA)
|
|
||||||
- **State Management:** React Hooks + Dexie.js (IndexedDB wrapper).
|
|
||||||
- **Offline Engine:**
|
|
||||||
- Service Workers for asset caching.
|
|
||||||
- IndexedDB for local data persistence.
|
|
||||||
- Sync mechanism: Local changes are buffered and pushed to backend when online.
|
|
||||||
- **Scanner:** `html5-qrcode` for standard barcode/QR detection (Local-only).
|
|
||||||
|
|
||||||
## 2. AI Intelligence Strategy (Critical)
|
|
||||||
|
|
||||||
### 2.1 AI Usage Policy
|
|
||||||
- **New Item Onboarding:** AI-OCR is permitted. It analyzes complex label photos (SFP, hardware specs) and maps them to JSON fields.
|
|
||||||
- **Routine Operations (Check-in/Out/Audit):** **AI IS STRICTLY FORBIDDEN.**
|
|
||||||
- Use local barcode/QR scanning only.
|
|
||||||
- If a label is not recognized locally, the user is prompted to start the "AI Onboarding Assistant".
|
|
||||||
- Goal: $0 cost for 99% of daily operations.
|
|
||||||
|
|
||||||
### 2.2 Modular AI Providers Architecture
|
|
||||||
Located in `backend/ai/`, the system supports multiple providers through a managed orchestrator:
|
|
||||||
- **Provider Modules:** `gemini.py`, `claude.py`, etc.
|
|
||||||
- **SDK Update (v2):** Switched to `google-genai` (v2) for improved stability and response parsing.
|
|
||||||
- **Model Hardcoding Power:** Switched from dynamic discovery to fixed high-speed models (`gemini-2.0-flash`) for sub-second responses on cellular networks.
|
|
||||||
|
|
||||||
### 2.3 Hybrid Sync & Deduplication (New)
|
|
||||||
To ensure zero data loss during unstable mobile sessions:
|
|
||||||
- **UUID Labeling:** Every sync operation generated on a mobile device is tagged with a client-side UUID.
|
|
||||||
- **Idempotent Backend:** The `bulk_sync` endpoint checks UUIDs against `AuditLog` before applying increments, preventing double-counts.
|
|
||||||
|
|
||||||
## 3. Data Integrity & Audit
|
|
||||||
- **Immutable Audit Log:** Every change (Add, Remove, Edit) is logged with a timestamp, action, and previous/new state.
|
|
||||||
- **Validation Mask:** AI-extracted data is NEVER saved directly. It is presented to a human user in a validation UI for final confirmation.
|
|
||||||
|
|
||||||
## 4. Implementation Status
|
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
- [x] **Phase 1: Backend Foundation** (FastAPI, SQLite, Models).
|
- [x] **Phase 1: Backend Foundation** (FastAPI, SQLite, Models).
|
||||||
- [x] **Phase 2: Modular AI Integration** (Gemini & Claude support, v2 SDK).
|
- [x] **Phase 2: Modular AI Integration** (Gemini support, v2 SDK).
|
||||||
- [x] **Phase 3: AI Onboarding UI** (Validation Mask, Camera/Upload integration).
|
- [x] **Phase 3: AI Onboarding UI** (Validation Mask, Camera integration).
|
||||||
- [x] **Phase 4: Offline Synchronization** (Deduplicated Dexie -> SQL sync logic).
|
- [x] **Phase 4: Offline Synchronization** (Deduplicated Dexie -> SQL sync logic).
|
||||||
- [x] **Phase 5: Inventory Trash Management** (Waste/Discard/Damage workflow).
|
- [x] **Phase 5: Inventory Trash Management** (Waste/Discard/Damage workflow).
|
||||||
- [ ] **Phase 6: Audit Log Dashboard UI** (Visual historical interventions).
|
- [ ] **Phase 6: Audit Log Dashboard UI** (Visual historical interventions).
|
||||||
|
|
||||||
## 5. Security & Infrastructure
|
*(Note: Completed phases are periodically moved to `dev_docs/PLAN_HISTORY.md` according to AI_RULES)*
|
||||||
- **Unified SSL Proxy:** Integrated `local-ssl-proxy` for HTTPS access (Camera/Mic) on port 3003.
|
|
||||||
- **VENV Isolation:** Automated `.venv` management in `start_server.sh`.
|
|
||||||
|
|||||||
54
PROJECT_ARCHITECTURE.md
Normal file
54
PROJECT_ARCHITECTURE.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# TFM aInventory - Project Architecture & Requirements
|
||||||
|
|
||||||
|
This document is the **Single Source of Truth** for the project's technical architecture, business requirements, and core logic.
|
||||||
|
|
||||||
|
## 1. Application Overview
|
||||||
|
A unified system to maintain an inventory of "items" and their quantities, inclusive of a web administration interface, offline field operations, audit logging, and AI-powered label extraction functionalities.
|
||||||
|
|
||||||
|
## 2. Technical Stack
|
||||||
|
### 2.1 Backend (API & Data)
|
||||||
|
- **Language:** Python 3.12+ (Optimized for performance and type safety)
|
||||||
|
- **Framework:** FastAPI (Async ASGI)
|
||||||
|
- **Database:** SQLite (SQLAlchemy) - Local file-based persistence
|
||||||
|
- **Validation:** Pydantic v2
|
||||||
|
- **Auth:** Hybrid LDAP (python-ldap) + PBKDF2 local password hash caching
|
||||||
|
- **AI Engine:** Google GenAI SDK (Gemini 2.0 Flash) - Location: `backend/ai/`
|
||||||
|
|
||||||
|
### 2.2 Frontend (Web & PWA)
|
||||||
|
- **Architecture:** Next.js 15+ (App Router)
|
||||||
|
- **Styling:** Tailwind CSS (Readability-first config)
|
||||||
|
- **Icons:** Lucide Icons (React components)
|
||||||
|
- **Offline persistence:** Dexie.js (IndexedDB wrapper)
|
||||||
|
- **Scanner:** `html5-qrcode` (Client-side, offline-only)
|
||||||
|
- **Sync:** Axios with bulk-sync idempotency (UUID-based)
|
||||||
|
|
||||||
|
### 2.3 Operations & Tooling
|
||||||
|
- **PWA Deployment:** `next-pwa` (Service Workers + Manifest.json)
|
||||||
|
- **HTTPS Proxy:** `local-ssl-proxy` (Required for mobile camera access, Port 3003)
|
||||||
|
- **Servers:** Frontend (`npm run dev` on 3000), Backend (`./start_server.sh` on 8000)
|
||||||
|
|
||||||
|
## 3. Data Models & Entities
|
||||||
|
- **Item:** Name, Category Group (Structured), Item Type (Specific), Quantity, Barcode, Part Number.
|
||||||
|
- **Category:** Predefined groups for organizational structure.
|
||||||
|
- **Intervention:** Linked to a required items list.
|
||||||
|
- **Audit Log:** Immutable ledger detailing CRUD operations and stock fluctuations.
|
||||||
|
|
||||||
|
## 4. Scanning & Optimization Strategy (Crucial)
|
||||||
|
### 4.1 AI Usage Policy
|
||||||
|
- **Routine Operations (Check-in/Out):** Executes entirely on the local device unconditionally using `html5-qrcode` ($0 cost). No AI is allowed here.
|
||||||
|
- **New Item Onboarding (AI Label OCR):** Uses cloud AI (`gemini-2.0-flash`). The user takes a photo, AI extracts data based on strict templates.
|
||||||
|
- **Validation Mask:** AI-extracted data is NEVER saved directly. It is presented in a validation UI for human confirmation.
|
||||||
|
|
||||||
|
### 4.2 Scanner Technical Specs (FROZEN)
|
||||||
|
- **Hardware Access:** Direct `MediaStreamTrack` access. Zoom cycle: 1x -> 2x -> Max/2 -> Max.
|
||||||
|
- **Image Pre-processing:** Rescaling (1200px), 60% Center Crop, Grayscale/Contrast filters, JPEG (`0.85` quality).
|
||||||
|
- **OCR Matching Engine (`page.tsx`):**
|
||||||
|
- Noise Filtering: Ignores `< 3` chars, decimals, and dates.
|
||||||
|
- Scoring: Exact S/N (+500), Exact P/N (+200), Token match (+50), Category match (+20).
|
||||||
|
- Threshold: Minimum **40 points** for auto-match without user intervention.
|
||||||
|
|
||||||
|
## 5. Offline Sync Protocol
|
||||||
|
To prevent data loss in basements or unstable networks:
|
||||||
|
- **Offline Engine:** Service Workers cache assets. IndexedDB saves data.
|
||||||
|
- **UUID Labeling:** Every sync operation generated offline is tagged with a client-side UUID.
|
||||||
|
- **Idempotent Backend:** The `bulk_sync` endpoint checks UUIDs against `AuditLog` before applying increments, preventing double-counts.
|
||||||
53
README.md
Normal file
53
README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# TFM aInventory (2026 Edition)
|
||||||
|
|
||||||
|
A unified, offline-first Inventory Management System built as a Progressive Web App (PWA). Features include AI-powered label extraction (OCR), local barcode/QR scanning, and multi-user authentication with LDAP support.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠 Project Modes
|
||||||
|
|
||||||
|
This project supports three distinct operational modes:
|
||||||
|
|
||||||
|
### 1. 🚀 Development Mode (Bare-Metal)
|
||||||
|
Ideal for local development on macOS/Linux.
|
||||||
|
* **Command:** `./start_server.sh`
|
||||||
|
* **Details:** Runs FastAPI (backend) and Next.js (frontend) in development mode. Uses `local-ssl-proxy` for HTTPS.
|
||||||
|
* **Backend:** http://localhost:8000
|
||||||
|
* **Frontend:** https://localhost:3003
|
||||||
|
|
||||||
|
### 2. 🐳 Docker Mode (Recommended for Production)
|
||||||
|
Isolated and portable container stack.
|
||||||
|
* **Command:** `docker-compose up -d --build`
|
||||||
|
* **Details:** Uses Caddy as a reverse proxy for HTTPS. Persistent data and logs are mapped to `./data` and `./logs`.
|
||||||
|
* **Access:** https://localhost:3003
|
||||||
|
|
||||||
|
### 3. 🐧 Standalone Linux Mode (Systemd)
|
||||||
|
Native Linux installation (Alma/Debian/Ubuntu) without Docker dependencies.
|
||||||
|
* **Installation:** `sudo ./install_service.sh`
|
||||||
|
* **Execution:** `sudo systemctl start inventory`
|
||||||
|
* **Details:** Compiles the frontend for production and manages the entire stack as a system service.
|
||||||
|
* **Access:** https://<SERVER-IP>:3003
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Production Distribution
|
||||||
|
To generate a clean production package without AI-agent metadata or development artifacts:
|
||||||
|
1. Run `./export_prod.sh`
|
||||||
|
2. A `.zip` archive will be created (e.g., `aInventory-PROD-v1.3.2.zip`).
|
||||||
|
3. This archive contains a specialized `README.txt` with deployment-only instructions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗 Technical Overview
|
||||||
|
* **Backend:** FastAPI (Python 3.12+)
|
||||||
|
* **Frontend:** Next.js 15+ (React PWA)
|
||||||
|
* **Database:** SQLite (SQLAlchemy) with Dexie.js (IndexedDB) for client-side sync.
|
||||||
|
* **Proxy:** Caddy (Docker) or local-ssl-proxy (Standalone/Dev).
|
||||||
|
* **AI Engine:** Google Gemini (Generative AI SDK).
|
||||||
|
|
||||||
|
For more details, see [PROJECT_ARCHITECTURE.md](PROJECT_ARCHITECTURE.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📜 AI Operational Rules
|
||||||
|
AI agents working on this project MUST follow the guidelines in [AI_RULES.md](AI_RULES.md).
|
||||||
50
USER_GUIDE.md
Normal file
50
USER_GUIDE.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# TFM aInventory - User Guide (Ghid de Utilizare)
|
||||||
|
|
||||||
|
Bun venit în sistemul **TFM aInventory**. Acest document explică modul de utilizare a aplicației pentru gestionarea inventarului.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📱 Instalarea pe Telefon (PWA)
|
||||||
|
Aplicația este un **Progressive Web App**, ceea ce înseamnă că nu trebuie descărcată din App Store/Google Play.
|
||||||
|
1. Deschideți URL-ul aplicației în browser (ex: Safari pe iOS sau Chrome pe Android).
|
||||||
|
2. Apăsați butonul de **Share** (iOS) sau cele **trei puncte** (Android).
|
||||||
|
3. Selectați **"Add to Home Screen"** (Adaugă pe ecranul principal).
|
||||||
|
4. Aplicația va apărea acum ca o iconiță pe ecranul dvs. și va funcționa într-un mod imersiv (fără barele browserului).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Autentificarea
|
||||||
|
* **Utilizator Implicit:** La prima instalare, folosiți `Admin` / `admin`.
|
||||||
|
* **Vă recomandăm schimbarea parolei imediat din secțiunea de Admin.**
|
||||||
|
* **LDAP:** Dacă administratorul a configurat integrarea, vă puteți loga cu contul de domeniu/companie. Aplicația vă va reține hash-ul parolei pentru a permite logarea în zone fără semnal (ex: subsoluri).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Scanarea și Adăugarea de Obiecte
|
||||||
|
Aplicația suportă două moduri de scanare:
|
||||||
|
1. **Manual / Barcode:** Scanați un cod de bare existent pentru a găsi sau adăuga un obiect.
|
||||||
|
2. **AI Label Extraction (OCR):** Folosiți camera pentru a fotografia eticheta unui produs nou. AI-ul va încerca să extragă automat:
|
||||||
|
* Denumirea produsului (Model/Series)
|
||||||
|
* Producătorul (Brand)
|
||||||
|
* Specificațiile tehnice
|
||||||
|
* Codul de bare
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📂 Organizarea Inventarului
|
||||||
|
* **Category Groups:** Grupează categoriile (ex: IT, Papetărie, Mobilier).
|
||||||
|
* **Categories:** Subdiviziuni ale grupurilor.
|
||||||
|
* **Item Types:** Definește template-uri pentru obiecte (ex: Laptop, Scaun, Tonner).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📜 Jurnalul de Activitate (Audit Log)
|
||||||
|
Toate acțiunile (adăugări, modificări, ștergeri) sunt înregistrate în timp real. Puteți consulta istoricul în secțiunea **Logs** pentru a vedea cine și când a operat modificări în stoc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📶 Modul Offline
|
||||||
|
Aplicația este concepută să funcționeze chiar și atunci când nu aveți conexiune la internet în depozit. Datele sunt sincronizate automat când reveniți în zona de acoperire.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Pentru asistență tehnică, contactați administratorul de sistem.*
|
||||||
18
VERSION.json
18
VERSION.json
@@ -1,16 +1,10 @@
|
|||||||
{
|
{
|
||||||
"version": "1.2.6",
|
"version": "1.3.5",
|
||||||
"last_build": "2026-04-11-1206",
|
"last_build": "2026-04-11-1250",
|
||||||
"commit": "d9e2a",
|
"commit": "PENDING",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
"v1.2.6: Hotfix - Added missing icon imports (Layers, ChevronDown)",
|
"v1.3.5: Updated AI_RULES.md with mandatory documentation maintenance requirements for all agents",
|
||||||
"v1.2.5: Synchronized icons across UI (Layers for Categories, Package for Item Types)",
|
"v1.3.4: Created USER_GUIDE.md (Romanian) for end-users and integrated into export bundle",
|
||||||
"v1.2.4: Offline LDAP auth support and UI affordance improvements (Dropdown chevrons, soft password dots)",
|
"v1.3.3: Added comprehensive project README.md documenting all operational modes"
|
||||||
"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.0: Structured category management with grouping support",
|
|
||||||
"v1.1.0: Multi-user auth & LDAP framework integration",
|
|
||||||
"v1.0.0: Initial PWA inventory launch"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
35
backend/Dockerfile
Normal file
35
backend/Dockerfile
Normal 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"]
|
||||||
@@ -4,9 +4,11 @@ import os
|
|||||||
|
|
||||||
# Get absolute path for the backend directory
|
# Get absolute path for the backend directory
|
||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
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)
|
os.makedirs(DATA_DIR, exist_ok=True)
|
||||||
|
|
||||||
# Handle absolute path for SQLite (needs 4 slashes on Unix)
|
# Handle absolute path for SQLite (needs 4 slashes on Unix)
|
||||||
|
|||||||
51
backend/logger.py
Normal file
51
backend/logger.py
Normal 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()
|
||||||
@@ -3,11 +3,14 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||||||
from . import models
|
from . import models
|
||||||
from .database import engine
|
from .database import engine
|
||||||
from .routers import items, operations, users, categories
|
from .routers import items, operations, users, categories
|
||||||
|
from .logger import log
|
||||||
|
|
||||||
# Create the database tables
|
# Create the database tables
|
||||||
models.Base.metadata.create_all(bind=engine)
|
models.Base.metadata.create_all(bind=engine)
|
||||||
|
log.info("Database tables verified.")
|
||||||
|
|
||||||
app = FastAPI(title="TFM aInventory API", version="1.1.0")
|
app = FastAPI(title="TFM aInventory API", version="1.1.0")
|
||||||
|
log.info("TFM aInventory API process started.")
|
||||||
|
|
||||||
# Setup Cross-Origin for Client interaction (PWA)
|
# Setup Cross-Origin for Client interaction (PWA)
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ router = APIRouter(prefix="/users", tags=["users"])
|
|||||||
pwd_context = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")
|
pwd_context = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")
|
||||||
|
|
||||||
def get_ldap_config():
|
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):
|
if os.path.exists(config_path):
|
||||||
with open(config_path, "r") as f:
|
with open(config_path, "r") as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
@@ -209,7 +209,7 @@ def get_ldap_settings():
|
|||||||
|
|
||||||
@router.post("/ldap-config")
|
@router.post("/ldap-config")
|
||||||
def update_ldap_settings(config: dict):
|
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:
|
with open(config_path, "w") as f:
|
||||||
json.dump(config, f)
|
json.dump(config, f)
|
||||||
return {"message": "Config saved"}
|
return {"message": "Config saved"}
|
||||||
|
|||||||
@@ -1,10 +1,58 @@
|
|||||||
### [2026-04-11 12:05] v1.2.6: Hotfix - Missing Icon Imports
|
### [2026-04-11 12:45] v1.3.0: Dockerization & Export Script
|
||||||
**Purpose:** Fixed `ReferenceError: Layers is not defined` and `ChevronDown is not defined` errors by adding missing imports in `admin/page.tsx` and `app/page.tsx`.
|
**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:**
|
**Modified Files:**
|
||||||
- `frontend/app/admin/page.tsx`
|
- `backend/database.py`
|
||||||
- `frontend/app/page.tsx`
|
- `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`
|
- `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:**
|
||||||
|
- `GEMINI.md` (Recreated as proxy)
|
||||||
|
- `CLAUDE.md` (Created as proxy)
|
||||||
|
- `AI_RULES.md`
|
||||||
|
- `VERSION.json`
|
||||||
|
|
||||||
|
### [2026-04-11 12:25] v1.2.8: Absolute Documentation Consolidation
|
||||||
|
**Purpose:** Restructured all project documentation to completely eliminate redundancy and establish clear "Single Source of Truth" boundaries for humans and AI agents.
|
||||||
|
**Actions:**
|
||||||
|
- Created `PROJECT_ARCHITECTURE.md` uniting business requirements, tech stack, data models, and specific OCR algorithms.
|
||||||
|
- Unified all AI operational rules, constraints, and UI fidelities strictly inside `AI_RULES.md`.
|
||||||
|
- Removed redundant, overlapping files (`GEMINI.md`, `requirements.md`, `TECH_STACK.md`, `UI_FIDELITY_SPEC.md`, `SCANNER_LOGIC_SPEC.md`).
|
||||||
|
- Stripped `PLAN.md` down to just the active checklist.
|
||||||
|
**Modified Files:**
|
||||||
|
- `PROJECT_ARCHITECTURE.md` (New)
|
||||||
|
- `AI_RULES.md`
|
||||||
|
- `PLAN.md`
|
||||||
|
- `VERSION.json`
|
||||||
|
|
||||||
|
### [2026-04-11 12:15] v1.2.7: Documentation Refactor & Portability
|
||||||
|
**Purpose:** Consolidated technical stack information into a single source of truth (`dev_docs/TECH_STACK.md`) and removed absolute paths from all AI-facing documents to ensure the project can be moved across environments without breaking references.
|
||||||
|
**Modified Files:**
|
||||||
|
- `dev_docs/TECH_STACK.md` (New)
|
||||||
|
- `GEMINI.md` (Refined)
|
||||||
|
- `AI_RULES.md` (Cleaned)
|
||||||
|
- `PLAN.md` (Referenced tech stack)
|
||||||
|
- `requirements.md` (Referenced tech stack)
|
||||||
|
- `dev_docs/SESSION_STATE.md` (Path cleanup)
|
||||||
|
- `VERSION.json`
|
||||||
|
|
||||||
|
### [2026-04-11 12:05] v1.2.6: Hotfix - Missing Icon Imports
|
||||||
|
|
||||||
### [2026-04-11 11:58] v1.2.5: UI Icon Synchronization
|
### [2026-04-11 11:58] v1.2.5: UI Icon Synchronization
|
||||||
|
|
||||||
### [2026-04-11 11:45] v1.2.4: Offline Auth & UX Polish
|
### [2026-04-11 11:45] v1.2.4: Offline Auth & UX Polish
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
# TFM aInventory - Scanner Technical Specification (v1.2)
|
|
||||||
|
|
||||||
This document defines the "Frozen" parameters for the scanner component. Do NOT modify these values without explicit user approval.
|
|
||||||
|
|
||||||
## 1. Hardware Access
|
|
||||||
- **API**: Direct `MediaStreamTrack` access for high-performance camera control.
|
|
||||||
- **Zoom**: Dynamic detection of `capabilities.zoom.max`.
|
|
||||||
- **Zoom Cycle**: 1x -> 2x -> Max/2 -> Max.
|
|
||||||
|
|
||||||
## 2. Image Pre-processing (The OCR "Secret Sauce")
|
|
||||||
Before being sent to Tesseract.js, every frame undergoes these transformations:
|
|
||||||
- **Rescaling**: Fixed canvas width of **1200px** (Optimal for Mobile RAM/Accuracy).
|
|
||||||
- **Cropping**: **60% Center Crop** of the video stream (forces focus & removes peripheral noise).
|
|
||||||
- **Filters**: `grayscale(100%) contrast(180%) brightness(105%)`.
|
|
||||||
- **Format**: High-quality JPEG (`0.85` quality) via `toDataURL`.
|
|
||||||
|
|
||||||
## 3. OCR Matching Engine (page.tsx)
|
|
||||||
- **Sanitization**: Text normalized to UPPERCASE, non-alphanumeric replaced with spaces.
|
|
||||||
- **Noise Filtering**:
|
|
||||||
- Tokens < 3 chars ignored.
|
|
||||||
- Decimals (e.g., `0.11`, `0.18`) ignored via regex: `/^\d+\.\d+$/`.
|
|
||||||
- Dates (e.g., `2024-07-25`) ignored via regex: `/^\d{2,4}-\d{2}-\d{2}$/`.
|
|
||||||
- **Scoring System**:
|
|
||||||
- **Exact Serial Number Match**: +500 points (Instant Match).
|
|
||||||
- **Exact Part Number Match**: +200 points.
|
|
||||||
- **Token match (e.g., "LC" in "LC/UPC")**: +50 points.
|
|
||||||
- **Category Match**: +20 points.
|
|
||||||
- **Threshold**: Minimum **40 points** required for automatic match without user intervention.
|
|
||||||
|
|
||||||
## 4. UI/UX Flow
|
|
||||||
1. **Auto-Match**: Attempt to identify item immediately from raw text.
|
|
||||||
2. **Interactive Selection (Fallback)**: If match confidence is low, freeze frame and show clickable bounding boxes for manual word selection.
|
|
||||||
|
|
||||||
---
|
|
||||||
*Created: 2026-04-10*
|
|
||||||
*Status: FROZEN*
|
|
||||||
@@ -5,6 +5,21 @@ Entries are added here when a new AI session starts.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
**[Archived: 2026-04-11]**
|
||||||
|
**Status**: UI Readability Refactor Completed (v1.2.2). Ready for Phase 6.
|
||||||
|
**Current AI Agent**: Gemini (Antigravity)
|
||||||
|
**Context**:
|
||||||
|
- **UI Readability**: System-wide removal of `uppercase` and `tracking-*`. Font sizes increased from 9px/10px to xs/sm. Title Case applied to major buttons.
|
||||||
|
- **Rules Compliance**: All changes logged in `ARCHIVE_LOGS.md` and `VERSION.json`.
|
||||||
|
- **Git**: Working on branch `dev`. Path persisted in `.git_path`.
|
||||||
|
|
||||||
|
**Next Steps**:
|
||||||
|
1. **Proceed to Phase 6: Audit Log Dashboard UI**. The backend already has `Log` models, but the frontend needs a more comprehensive view beyond the current "Audit History" modal if requested, OR finalize the existing ones.
|
||||||
|
2. Enable LDAP and test with real server (from v1.2.1 goals).
|
||||||
|
3. Deploy v1.2.2 to stable branch if user confirms.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Handover Archive (Auto-Archived)
|
### Handover Archive (Auto-Archived)
|
||||||
**Status**: v1.2.1 Infrastructure Stable.
|
**Status**: v1.2.1 Infrastructure Stable.
|
||||||
**Current AI Agent**: Gemini (Antigravity)
|
**Current AI Agent**: Gemini (Antigravity)
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
# AI Session State - HANDOVER
|
# CURRENT AI WORKING SESSION
|
||||||
|
|
||||||
**Status**: UI Readability Refactor Completed (v1.2.2). Ready for Phase 6.
|
**Active AI:** Antigravity (Gemini)
|
||||||
**Current AI Agent**: Gemini (Antigravity)
|
**Last Updated:** 2026-04-11
|
||||||
**Context**:
|
**Current Version:** v1.3.0
|
||||||
- **UI Readability**: System-wide removal of `uppercase` and `tracking-*`. Font sizes increased from 9px/10px to xs/sm. Title Case applied to major buttons.
|
**Branch:** dev
|
||||||
- **Rules Compliance**: All changes logged in `ARCHIVE_LOGS.md` and `VERSION.json`.
|
|
||||||
- **Git**: Working on branch `dev`. Path persisted in `.git_path`.
|
|
||||||
|
|
||||||
**Next Steps**:
|
### Current Status
|
||||||
1. **Proceed to Phase 6: Audit Log Dashboard UI**. The backend already has `Log` models, but the frontend needs a more comprehensive view beyond the current "Audit History" modal if requested, OR finalize the existing ones.
|
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.
|
||||||
2. Enable LDAP and test with real server (from v1.2.1 goals).
|
|
||||||
3. Deploy v1.2.2 to stable branch if user confirms.
|
### 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.
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# UI Fidelity Specification
|
|
||||||
|
|
||||||
This document details the mandatory visual and structural specifications for UI components (headers, banners, cards, buttons) in the unified PWA interface.
|
|
||||||
|
|
||||||
## 1. General Principles
|
|
||||||
- Use TailwindCSS (or equivalent local vanilla CSS framework established).
|
|
||||||
- No emojis; strictly Bootstrap Icons.
|
|
||||||
- Standard spacing, consistent font weight (Inter or Roboto).
|
|
||||||
- Responsive: Viewport scaling for both Desktop dashboard and Mobile full-screen scanning modes.
|
|
||||||
|
|
||||||
## 2. Specific Components
|
|
||||||
*(To be populated as components are developed)*
|
|
||||||
53
docker-compose.yml
Normal file
53
docker-compose.yml
Normal 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
|
||||||
68
export_prod.sh
Executable file
68
export_prod.sh
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/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 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 .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 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>: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
48
frontend/Dockerfile
Normal 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"]
|
||||||
@@ -9,7 +9,7 @@ const withPWA = withPWAInit({
|
|||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
// Config options here
|
output: "standalone",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withPWA(nextConfig);
|
export default withPWA(nextConfig);
|
||||||
|
|||||||
69
install_service.sh
Executable file
69
install_service.sh
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/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."
|
||||||
17
inventory.service.template
Normal file
17
inventory.service.template
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=TFM aInventory Docker Stack
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=__WORKING_DIR__
|
||||||
|
ExecStart=/bin/bash __WORKING_DIR__/run_standalone.sh
|
||||||
|
# No explicit ExecStop needed as kill 0 in run_standalone handles it,
|
||||||
|
# but systemd handles SIGTERM by default anyway.
|
||||||
|
Restart=always
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Inventory Application Requirements
|
|
||||||
|
|
||||||
## 1. Description
|
|
||||||
A unified system to maintain an inventory of "items" and their quantities, inclusive of a web administration interface, offline field operations, audit logging, and AI-powered label extraction functionalities.
|
|
||||||
|
|
||||||
## 2. Core Constraints & System Elements
|
|
||||||
|
|
||||||
### 2.1 Main Application Server (Linux Backend)
|
|
||||||
* **Target Environment:** Dockerized Linux Environment.
|
|
||||||
* **Framework:** Python (FastAPI) + SQLite database.
|
|
||||||
* **Users & Security:** Support multiple authenticated users (PBKDF2 local + optional LDAP).
|
|
||||||
* **Audit Compliance:** All operations maintain a strict audit log (unique UUIDs, details).
|
|
||||||
|
|
||||||
### 2.2 Client Interface (PWA - Progressive Web App)
|
|
||||||
* **Unified Interface:** A single Web Application (Next.js or similar) that is fully responsive. It functions as the administration dashboard on desktop and as a mobile application on phones/tablets.
|
|
||||||
* **Installation:** Installed on mobile devices directly via the browser ("Add to Home Screen") to bypass App Stores. Completely managed by the main Linux Server.
|
|
||||||
* **Offline Mode:** Service Workers and local browser storage (IndexedDB) must cache the inventory catalog, allowing offline check-ins/check-outs. Modifications are synced to the Linux server upon network reconnection.
|
|
||||||
* **Hardware Access:** Must natively tap into the device's camera via HTML5 APIs to capture barcode data or full images.
|
|
||||||
|
|
||||||
### 2.3 Scanning & AI processing Cost-Optimization Strategy (Crucial)
|
|
||||||
* **Routine Operations (Check-in / Check-out):** Utilize client-side, offline Javascript libraries (e.g., `html5-qrcode`) to read 1D/2D barcodes directly in the browser's camera. This executes entirely on the local device unconditionally and uses no AI cloud credits.
|
|
||||||
* **New Item Onboarding (AI Label OCR):** When an unknown label is encountered or a specific new item is being created, the user takes a high-res photo. This photo is sent to the backend, which proxies a minimal request to a Cloud AI API (e.g., OpenAI / GPT-4 Vision).
|
|
||||||
* **Template Extraction:** The AI performs standard OCR & structure extraction based on strict prompting templates. The parsed elements are transmitted back to the client interface.
|
|
||||||
* **Validation Mask:** The client interface explicitly presents a selection mask. The user selects which parsed strings/fields map to specific Item properties (e.g., identifying the actual serial number while discarding vendor identifiers) before committing the Item to the database.
|
|
||||||
|
|
||||||
### 2.4 Data Models & Entities
|
|
||||||
* **Item:** Name, Category Group (Structured), Item Type (Specific), Quantity, Barcode, Part Number.
|
|
||||||
* **Category:** Predefined groups for organizational structure (e.g., Connectors, Tools).
|
|
||||||
* **Intervention:** Linked to a required items list.
|
|
||||||
* **Audit Log:** Immutable ledger detailing CRUD operations and stock fluctuations.
|
|
||||||
|
|
||||||
### 2.5 Workflows & Reporting
|
|
||||||
* **Reports:** Quantity aggregates across all items/categories, with historical tracking of item usage intervals (last month, last 6 months, last year).
|
|
||||||
* **Notifications:** Alert generation when stock drops below minimum quantities.
|
|
||||||
* **Intervention Planning:** Loading intervention lists (Text/Scanning). Check-outs must fulfill matching lists incrementally, while Check-ins reconcile unused stock.
|
|
||||||
49
run_standalone.sh
Executable file
49
run_standalone.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/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 (Match start_server.sh) ---
|
||||||
|
BACKEND_PORT=8000
|
||||||
|
FRONTEND_PORT=3001
|
||||||
|
BACKEND_SSL_PORT=3002
|
||||||
|
FRONTEND_SSL_PORT=3003
|
||||||
|
|
||||||
|
# 1. Activate Environment
|
||||||
|
if [ -d ".venv" ]; then
|
||||||
|
source .venv/bin/activate
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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