diff --git a/APP/openvpn_api_v3.py b/APP/openvpn_api_v3.py
index 1923b7f..2eb282a 100644
--- a/APP/openvpn_api_v3.py
+++ b/APP/openvpn_api_v3.py
@@ -26,7 +26,9 @@ class OpenVPNAPI:
self.config = configparser.ConfigParser()
self.config.read(config_file)
self.certificates_path = self.config.get('certificates', 'certificates_path', fallback='/etc/openvpn/certs')
+ self.certificates_path = self.config.get('certificates', 'certificates_path', fallback='/etc/openvpn/certs')
self.cert_extensions = self.config.get('certificates', 'certificate_extensions', fallback='crt,pem,key').split(',')
+ self._cert_cache = {} # Cache structure: {filepath: {'mtime': float, 'data': dict}}
def get_db_connection(self):
"""Get a database connection"""
@@ -90,13 +92,42 @@ class OpenVPNAPI:
def get_certificates_info(self):
cert_path = Path(self.certificates_path)
if not cert_path.exists(): return []
+
cert_files = []
for ext in self.cert_extensions:
cert_files.extend(cert_path.rglob(f'*.{ext.strip()}'))
+
+ current_valid_files = set()
cert_data = []
- for cert_file in cert_files:
- data = self.extract_cert_info(str(cert_file))
- if data: cert_data.append(data)
+
+ for cert_file_path in cert_files:
+ cert_file = str(cert_file_path)
+ current_valid_files.add(cert_file)
+
+ try:
+ mtime = os.path.getmtime(cert_file)
+
+ # Check cache
+ cached = self._cert_cache.get(cert_file)
+ if cached and cached['mtime'] == mtime:
+ cert_data.append(cached['data'])
+ else:
+ # Parse and update cache
+ parsed_data = self.extract_cert_info(cert_file)
+ if parsed_data:
+ self._cert_cache[cert_file] = {
+ 'mtime': mtime,
+ 'data': parsed_data
+ }
+ cert_data.append(parsed_data)
+ except OSError:
+ continue
+
+ # Prune cache for deleted files
+ for cached_file in list(self._cert_cache.keys()):
+ if cached_file not in current_valid_files:
+ del self._cert_cache[cached_file]
+
return cert_data
# -----------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ce05d12
--- /dev/null
+++ b/README.md
@@ -0,0 +1,158 @@
+# OpenVPN Monitor UI & API
+
+A modern, reactive dashboard for monitoring OpenVPN server status, traffic history, and certificate validity. Built with Vue.js 3 and Python (Flask).
+
+## 🚀 Quick Start
+
+### Prerequisites
+* **Backend**: Python 3.9+ (`pip`, `venv`)
+* **Frontend**: Node.js 18+ (for building only), any Web Server (Nginx/Apache) for production.
+
+### 1. Backend Setup
+Run the API and Data Gatherer.
+
+```bash
+# Ubuntu/Debian
+sudo apt update && sudo apt install python3-venv python3-pip
+
+# Alpine
+apk add python3 py3-pip
+
+# Setup
+cd /path/to/app/APP
+python3 -m venv venv
+source venv/bin/activate
+pip install -r requirements.txt
+
+# Run (Manual testing)
+python3 openvpn_api_v3.py &
+python3 openvpn_gatherer_v3.py &
+```
+
+### 2. Frontend Setup
+Build the SPA and deploy to your web server.
+
+```bash
+cd /path/to/app/UI/client
+npm install
+npm run build
+
+# Deploy (Example)
+sudo cp -r dist/* /var/www/html/
+```
+
+---
+
+## 🛠 Service Configuration
+
+### Debian / Ubuntu (Systemd)
+Create service files in `/etc/systemd/system/`.
+
+**1. API Service (`/etc/systemd/system/ovpmon-api.service`)**
+```ini
+[Unit]
+Description=OpenVPN Monitor API
+After=network.target
+
+[Service]
+User=root
+WorkingDirectory=/opt/ovpmon/APP
+ExecStart=/opt/ovpmon/APP/venv/bin/python3 openvpn_api_v3.py
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+```
+
+**2. Gatherer Service (`/etc/systemd/system/ovpmon-gatherer.service`)**
+```ini
+[Unit]
+Description=OpenVPN Monitor Data Gatherer
+After=network.target
+
+[Service]
+User=root
+WorkingDirectory=/opt/ovpmon/APP
+ExecStart=/opt/ovpmon/APP/venv/bin/python3 openvpn_gatherer_v3.py
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+```
+
+**Enable & Start:**
+```bash
+sudo systemctl daemon-reload
+sudo systemctl enable --now ovpmon-api ovpmon-gatherer
+```
+
+### Alpine Linux (OpenRC)
+For Alpine, create scripts in `/etc/init.d/` (e.g., `ovpmon-api`) using `openrc-run`.
+```bash
+#!/sbin/openrc-run
+description="OpenVPN Monitor API"
+command="/opt/ovpmon/APP/venv/bin/python3"
+command_args="/opt/ovpmon/APP/openvpn_api_v3.py"
+directory="/opt/ovpmon/APP"
+command_background=true
+pidfile="/run/ovpmon-api.pid"
+```
+Make executable (`chmod +x`) and start: `rc-service ovpmon-api start`.
+
+---
+
+## 🌐 Web Server Configuration
+
+**Recommendation: Nginx** is preferred for its performance and simple SPA configuration (`try_files`).
+
+### Nginx Config
+```nginx
+server {
+ listen 80;
+ server_name vpn-monitor.local;
+ root /var/www/html;
+ index index.html;
+
+ # SPA Fallback
+ location / {
+ try_files $uri $uri/ /index.html;
+ }
+
+ # Proxy API requests (Optional, if not exposing 5001 directly)
+ location /api/ {
+ proxy_pass http://127.0.0.1:5001;
+ }
+}
+```
+
+### Apache Config
+Ensure `mod_rewrite` is enabled. The project includes a `.htaccess` file for routing.
+**VirtualHost Config:**
+```apache
+
+ DocumentRoot "/var/www/html"
+
+ Options Indexes FollowSymLinks
+ AllowOverride All # CRITICAL for .htaccess
+ Require all granted
+
+
+```
+
+---
+
+## 📚 API Reference
+
+**Base URL:** `http://:5001/api/v1`
+
+| Method | Endpoint | Description |
+| :--- | :--- | :--- |
+| **GET** | `/stats` | Current status of all clients (Real-time). |
+| **GET** | `/stats/system` | Server-wide totals (Total traffic, active count). |
+| **GET** | `/stats/` | Detailed client stats + History. Params: `range` (24h, 7d), `resolution`. |
+| **GET** | `/certificates` | List of all certificates with expiration status. **Cached (Fast)**. |
+| **GET** | `/analytics` | Dashboard data (Trends, Traffic distribution, Top clients). |
+| **GET** | `/health` | API Health check. |
+
+---
+*Generated by Antigravity Agent*
diff --git a/UI/client/.gitignore b/UI/client/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/UI/client/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/UI/client/.vscode/extensions.json b/UI/client/.vscode/extensions.json
new file mode 100644
index 0000000..a7cea0b
--- /dev/null
+++ b/UI/client/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["Vue.volar"]
+}
diff --git a/UI/client/README.md b/UI/client/README.md
new file mode 100644
index 0000000..1511959
--- /dev/null
+++ b/UI/client/README.md
@@ -0,0 +1,5 @@
+# Vue 3 + Vite
+
+This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `
+