diff --git a/docs/APP-ct.md b/docs/APP-ct.md
index aa6793f29..e5dfa42e5 100644
--- a/docs/APP-ct.md
+++ b/docs/APP-ct.md
@@ -1,273 +1,493 @@
-# **AppName.sh Scripts**
+# π **Application Container Scripts (ct/AppName.sh)**
- `AppName.sh` scripts found in the `/ct` directory. These scripts are responsible for the installation of the desired application. For this guide we take `/ct/snipeit.sh` as example.
+**Modern Guide to Creating LXC Container Installation Scripts**
-## Table of Contents
+> **Updated**: December 2025
+> **Context**: Fully integrated with build.func, advanced_settings wizard, and defaults system
+> **Example Used**: `/ct/pihole.sh`, `/ct/docker.sh`
-- [**AppName.sh Scripts**](#appnamesh-scripts)
- - [Table of Contents](#table-of-contents)
- - [1. **File Header**](#1-file-header)
- - [1.1 **Shebang**](#11-shebang)
- - [1.2 **Import Functions**](#12-import-functions)
- - [1.3 **Metadata**](#13-metadata)
- - [2 **Variables and function import**](#2-variables-and-function-import)
- - [2.1 **Default Values**](#21-default-values)
- - [2.2 **π App output \& base settings**](#22--app-output--base-settings)
- - [2.3 **π Core functions**](#23--core-functions)
- - [3 **Update function**](#3-update-function)
- - [3.1 **Function Header**](#31-function-header)
- - [3.2 **Check APP**](#32-check-app)
- - [3.3 **Check version**](#33-check-version)
- - [3.4 **Verbosity**](#34-verbosity)
- - [3.5 **Backups**](#35-backups)
- - [3.6 **Cleanup**](#36-cleanup)
- - [3.7 **No update function**](#37-no-update-function)
- - [4 **End of the script**](#4-end-of-the-script)
- - [5. **Contribution checklist**](#5-contribution-checklist)
+---
-## 1. **File Header**
+## π Table of Contents
-### 1.1 **Shebang**
+- [Overview](#overview)
+- [Architecture & Flow](#architecture--flow)
+- [File Structure](#file-structure)
+- [Complete Script Template](#complete-script-template)
+- [Function Reference](#function-reference)
+- [Advanced Features](#advanced-features)
+- [Real Examples](#real-examples)
+- [Troubleshooting](#troubleshooting)
+- [Contribution Checklist](#contribution-checklist)
-- Use `#!/usr/bin/env bash` as the shebang.
+---
+
+## Overview
+
+### Purpose
+
+Container scripts (`ct/AppName.sh`) are **entry points for creating LXC containers** with specific applications pre-installed. They:
+
+1. Define container defaults (CPU, RAM, disk, OS)
+2. Call the main build orchestrator (`build.func`)
+3. Implement application-specific update mechanisms
+4. Provide user-facing success messages
+
+### Execution Context
+
+```
+Proxmox Host
+ β
+ct/AppName.sh sourced (runs as root on host)
+ β
+build.func: Creates LXC container + runs install script inside
+ β
+install/AppName-install.sh (runs inside container)
+ β
+Container ready with app installed
+```
+
+### Key Integration Points
+
+- **build.func** - Main orchestrator (container creation, storage, variable management)
+- **install.func** - Container-specific setup (OS update, package management)
+- **tools.func** - Tool installation helpers (repositories, GitHub releases)
+- **core.func** - UI/messaging functions (colors, spinners, validation)
+- **error_handler.func** - Error handling and signal management
+
+---
+
+## Architecture & Flow
+
+### Container Creation Flow
+
+```
+START: bash ct/pihole.sh
+ β
+[1] Set APP, var_*, defaults
+ β
+[2] header_info() β Display ASCII art
+ β
+[3] variables() β Parse arguments & load build.func
+ β
+[4] color() β Setup ANSI codes
+ β
+[5] catch_errors() β Setup trap handlers
+ β
+[6] install_script() β Show mode menu (5 options)
+ β
+ ββ INSTALL_MODE="0" (Default)
+ ββ INSTALL_MODE="1" (Advanced - 19-step wizard)
+ ββ INSTALL_MODE="2" (User Defaults)
+ ββ INSTALL_MODE="3" (App Defaults)
+ ββ INSTALL_MODE="4" (Settings Menu)
+ β
+[7] advanced_settings() β Collect user configuration (if mode=1)
+ β
+[8] start() β Confirm or re-edit settings
+ β
+[9] build_container() β Create LXC + execute install script
+ β
+[10] description() β Set container description
+ β
+[11] SUCCESS β Display access URL
+ β
+END
+```
+
+### Default Values Precedence
+
+```
+Priority 1 (Highest): Environment Variables (var_cpu, var_ram, etc.)
+Priority 2: App-Specific Defaults (/defaults/AppName.vars)
+Priority 3: User Global Defaults (/default.vars)
+Priority 4 (Lowest): Built-in Defaults (in build.func)
+```
+
+---
+
+## File Structure
+
+### Minimal ct/AppName.sh Template
+
+```
+#!/usr/bin/env bash # [1] Shebang
+ # [2] Copyright/License
+source <(curl -s .../misc/build.func) # [3] Import functions
+ # [4] APP metadata
+APP="AppName" # [5] Default values
+var_tags="tag1;tag2"
+var_cpu="2"
+var_ram="2048"
+...
+
+header_info "$APP" # [6] Display header
+variables # [7] Process arguments
+color # [8] Setup colors
+catch_errors # [9] Setup error handling
+
+function update_script() { ... } # [10] Update function (optional)
+
+start # [11] Launch container creation
+build_container
+description
+msg_ok "Completed Successfully!\n"
+```
+
+---
+
+## Complete Script Template
+
+### 1. File Header & Imports
```bash
#!/usr/bin/env bash
-```
-
-### 1.2 **Import Functions**
-
-- Import the build.func file.
-- When developing your own script, change the URL to your own repository.
-
-> [!IMPORTANT]
-> You also need to change all apperances of this URL in `misc/build.func` and `misc/install.func`
-
-
-Example for development:
-
-```bash
-source <(curl -s https://raw.githubusercontent.com/[USER]/[REPO]/refs/heads/[BRANCH]/misc/build.func)
-```
-
-Final script:
-
-```bash
-source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
-```
-
-> [!CAUTION]
-> Before opening a Pull Request, change the URL to point to the community-scripts repo.
-
-### 1.3 **Metadata**
-
-- Add clear comments for script metadata, including author, copyright, and license information.
-
-Example:
-
-```bash
# Copyright (c) 2021-2025 community-scripts ORG
-# Author: [YourUserName]
-# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
-# Source: [SOURCE_URL]
+# Author: YourUsername
+# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
+# Source: https://github.com/example/project
+
+# Import main orchestrator
+source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
```
-> [!NOTE]:
->
-> - Add your username and source URL
-> - For existing scripts, add "| Co-Author [YourUserName]" after the current author
+> **β οΈ IMPORTANT**: Before opening a PR, change URL to `community-scripts` repo!
----
-
-## 2 **Variables and function import**
->
-> [!NOTE]
-> You need to have all this set in your script, otherwise it will not work!
-
-### 2.1 **Default Values**
-
-- This section sets the default values for the container.
-- `APP` needs to be set to the application name and must be equal to the filenames of your scripts.
-- `var_tags`: You can set Tags for the CT wich show up in the Proxmox UI. DonΒ΄t overdo it!
-
->[!NOTE]
->Description for all Default Values
->
->| Variable | Description | Notes |
->|----------|-------------|-------|
->| `APP` | Application name | Must match ct\AppName.sh |
->| `TAGS` | Proxmox display tags without Spaces, only ; | Limit the number |
->| `var_cpu` | CPU cores | Number of cores |
->| `var_ram` | RAM | In MB |
->| `var_disk` | Disk capacity | In GB |
->| `var_os` | Operating system | alpine, debian, ubuntu |
->| `var_version` | OS version | e.g., 3.20, 11, 12, 20.04 |
->| `var_unprivileged` | Container type | 1 = Unprivileged, 0 = Privileged |
-
-Example:
+### 2. Application Metadata
```bash
-APP="SnipeIT"
-var_tags="asset-management;foss"
-var_cpu="2"
-var_ram="2048"
-var_disk="4"
-var_os="debian"
-var_version="12"
-var_unprivileged="1"
+# Application Configuration
+APP="ApplicationName"
+var_tags="tag1;tag2;tag3" # Max 3-4 tags, no spaces, semicolon-separated
+
+# Container Resources
+var_cpu="2" # CPU cores
+var_ram="2048" # RAM in MB
+var_disk="10" # Disk in GB
+
+# Container Type & OS
+var_os="debian" # Options: alpine, debian, ubuntu
+var_version="12" # Alpine: 3.20+, Debian: 11-13, Ubuntu: 20.04+
+var_unprivileged="1" # 1=unprivileged (secure), 0=privileged (rarely needed)
```
-## 2.2 **π App output & base settings**
+**Variable Naming Convention**:
+- Variables exposed to user: `var_*` (e.g., `var_cpu`, `var_hostname`, `var_ssh`)
+- Internal variables: lowercase (e.g., `container_id`, `app_version`)
+
+### 3. Display & Initialization
```bash
-# App Output & Base Settings
+# Display header ASCII art
header_info "$APP"
-base_settings
-```
-- `header_info`: Generates ASCII header for APP
-- `base_settings`: Allows overwriting variable values
-
-## 2.3 **π Core functions**
-
-```bash
-# Core
+# Process command-line arguments and load configuration
variables
+
+# Setup ANSI color codes and formatting
color
+
+# Initialize error handling (trap ERR, EXIT, INT, TERM)
catch_errors
```
-- `variables`: Processes input and prepares variables
-- `color`: Sets icons, colors, and formatting
-- `catch_errors`: Enables error handling
-
----
-
-## 3 **Update function**
-
-### 3.1 **Function Header**
-
-- If applicable write a function that updates the application and the OS in the container.
-- Each update function starts with the same code:
+### 4. Update Function (Highly Recommended)
```bash
function update_script() {
header_info
+
+ # Always start with these checks
check_container_storage
check_container_resources
-```
-### 3.2 **Check APP**
-
-- Before doing anything update-wise, check if the app is installed in the container.
-
-Example:
-
-```bash
-if [[ ! -d /opt/snipe-it ]]; then
+ # Verify app is installed
+ if [[ ! -d /opt/appname ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
-```
-### 3.3 **Check version**
+ # Get latest version from GitHub
+ RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
+ grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
-- Before updating, check if a new version exists.
- - We use the `${APPLICATION}_version.txt` file created in `/opt` during the install to compare new versions against the currently installed version.
-
-Example with a Github Release:
-
-```bash
- RELEASE=$(curl -fsSL https://api.github.com/repos/snipe/snipe-it/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
+ # Compare with saved version
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
msg_info "Updating ${APP} to v${RELEASE}"
- #DO UPDATE
+
+ # Backup user data
+ cp -r /opt/appname /opt/appname-backup
+
+ # Perform update
+ cd /opt
+ wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app-${RELEASE}.tar.gz"
+ tar -xzf app-${RELEASE}.tar.gz
+
+ # Restore user data
+ cp /opt/appname-backup/config/* /opt/appname/config/
+
+ # Cleanup
+ rm -rf app-${RELEASE}.tar.gz /opt/appname-backup
+
+ # Save new version
+ echo "${RELEASE}" > /opt/${APP}_version.txt
+
+ msg_ok "Updated ${APP} to v${RELEASE}"
+ else
+ msg_ok "No update required. ${APP} is already at v${RELEASE}."
+ fi
+
+ exit
+}
+```
+
+### 5. Script Launch
+
+```bash
+# Start the container creation workflow
+start
+
+# Build the container with selected configuration
+build_container
+
+# Set container description/notes in Proxmox UI
+description
+
+# Display success message
+msg_ok "Completed Successfully!\n"
+echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
+echo -e "${INFO}${YW} Access it using the following URL:${CL}"
+echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
+```
+
+---
+
+## Function Reference
+
+### Core Functions (From build.func)
+
+#### `variables()`
+
+**Purpose**: Initialize container variables, load user arguments, setup orchestration
+
+**Triggered by**: Called automatically at script start
+
+**Behavior**:
+1. Parse command-line arguments (if any)
+2. Generate random UUID for session tracking
+3. Load container storage from Proxmox
+4. Initialize application-specific defaults
+5. Setup SSH/environment configuration
+
+**Example Output**:
+```
+Setting up variables...
+Container ID: 100
+Storage: local-lvm
+Install method: Default
+```
+
+#### `start()`
+
+**Purpose**: Launch the container creation menu with 5 installation modes
+
+**Triggered by**: Called just before `build_container()`
+
+**Menu Options**:
+```
+1. Default Installation (Quick setup, predefined settings)
+2. Advanced Installation (19-step wizard with full control)
+3. User Defaults (Load ~/.community-scripts/default.vars)
+4. App Defaults (Load /defaults/AppName.vars)
+5. Settings Menu (Interactive mode selection)
+```
+
+**User Flow**:
+```
+Select installation mode:
+1) Default
+2) Advanced
+3) User Defaults
+4) App Defaults
+5) Settings Menu
+Enter choice: 2
+```
+
+#### `build_container()`
+
+**Purpose**: Main orchestrator for LXC container creation
+
+**Operations**:
+1. Validates all variables
+2. Creates LXC container via `pct create`
+3. Executes `install/AppName-install.sh` inside container
+4. Monitors installation progress
+5. Handles errors and rollback on failure
+
+**Exit Codes**:
+- `0` - Success
+- `1-255` - Various error conditions (see error_handler.func)
+
+#### `description()`
+
+**Purpose**: Set container description/notes visible in Proxmox UI
+
+**Format**:
+```
+AppName
+IP: [IP]
+Version: [Version]
+Tags: [Tags]
+```
+
+#### `header_info()`
+
+**Purpose**: Display ASCII art header for application
+
+**Sources**:
+- Tries `/usr/local/community-scripts/headers/ct/appname` (cached)
+- Falls back to remote fetch from GitHub
+- Returns silently if not found
+
+---
+
+## Advanced Features
+
+### 1. Integration with Defaults System
+
+#### Save App Defaults After Installation
+
+```bash
+# At end of install script, after successful setup:
+maybe_offer_save_app_defaults
+
+# Output:
+# "Save these settings as App Defaults for AppName? (Y/n)"
+# Yes β Saves to /defaults/appname.vars
+# No β Skips saving
+```
+
+#### Load Saved Defaults During Container Creation
+
+```bash
+# In ct/AppName.sh, user selects "App Defaults" mode
+# Automatically loads /defaults/appname.vars
+# Container uses previously saved configuration
+```
+
+### 2. Custom Configuration Menus
+
+If your app has additional setup beyond standard vars:
+
+```bash
+# In ct/AppName.sh, after variables()
+custom_app_settings() {
+ CONFIGURE_DB=$(whiptail --title "Database Setup" \
+ --yesno "Would you like to configure a custom database?" 8 60)
+
+ if [[ $? -eq 0 ]]; then
+ DB_HOST=$(whiptail --inputbox "Database Host:" 8 60 3>&1 1>&2 2>&3)
+ DB_PORT=$(whiptail --inputbox "Database Port:" 8 60 "3306" 3>&1 1>&2 2>&3)
+ fi
+}
+
+custom_app_settings
+```
+
+### 3. Version Tracking
+
+Save installed version for update checks:
+
+```bash
+# In install script, after successful app download:
+RELEASE="1.2.3"
+echo "${RELEASE}" > /opt/${APP}_version.txt
+
+# In update function, compare:
+CURRENT=$(cat /opt/${APP}_version.txt 2>/dev/null)
+LATEST=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | jq -r '.tag_name')
+
+if [[ "$LATEST" != "$CURRENT" ]]; then
+ echo "Update available: $CURRENT β $LATEST"
+fi
+```
+
+### 4. Health Check Functions
+
+Add custom validation:
+
+```bash
+function health_check() {
+ header_info
+
+ if [[ ! -d /opt/appname ]]; then
+ msg_error "Application not found!"
+ exit 1
+ fi
+
+ if ! systemctl is-active --quiet appname; then
+ msg_error "Application service not running"
+ exit 1
+ fi
+
+ msg_ok "Health check passed"
+}
+
+# Called via: bash ct/appname.sh health_check
+```
+
+---
+
+## Real Examples
+
+### Example 1: Simple Web App (Debian-based)
+
+```bash
+#!/usr/bin/env bash
+source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
+
+APP="Homarr"
+var_tags="dashboard;homepage"
+var_cpu="2"
+var_ram="1024"
+var_disk="5"
+var_os="debian"
+var_version="12"
+var_unprivileged="1"
+
+header_info "$APP"
+variables
+color
+catch_errors
+
+function update_script() {
+ header_info
+ check_container_storage
+ check_container_resources
+
+ if [[ ! -d /opt/homarr ]]; then
+ msg_error "No ${APP} Installation Found!"
+ exit
+ fi
+
+ RELEASE=$(curl -fsSL https://api.github.com/repos/ajnart/homarr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}')
+
+ if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
+ msg_info "Updating ${APP} to v${RELEASE}"
+ systemctl stop homarr
+
+ cd /opt/homarr
+ wget -q "https://github.com/ajnart/homarr/releases/download/v${RELEASE}/docker-compose.yml"
+ docker-compose up -d
+
+ echo "${RELEASE}" > /opt/${APP}_version.txt
+ msg_ok "Updated ${APP} to v${RELEASE}"
else
msg_ok "No update required. ${APP} is already at v${RELEASE}."
fi
exit
}
-```
-### 3.4 **Verbosity**
-
-- Use the appropriate flag (**-q** in the examples) for a command to suppress its output.
-Example:
-
-```bash
-wget -q
-unzip -q
-```
-
-- If a command does not come with this functionality use `&>/dev/null` to suppress it's output.
-
-Example:
-
-```bash
-php artisan migrate --force &>/dev/null
-php artisan config:clear &>/dev/null
-```
-
-### 3.5 **Backups**
-
-- Backup user data if necessary.
-- Move all user data back in the directory when the update is finished.
-
->[!NOTE]
->This is not meant to be a permanent backup
-
-Example backup:
-
-```bash
- mv /opt/snipe-it /opt/snipe-it-backup
-```
-
-Example config restore:
-
-```bash
- cp /opt/snipe-it-backup/.env /opt/snipe-it/.env
- cp -r /opt/snipe-it-backup/public/uploads/ /opt/snipe-it/public/uploads/
- cp -r /opt/snipe-it-backup/storage/private_uploads /opt/snipe-it/storage/private_uploads
-```
-
-### 3.6 **Cleanup**
-
-- Do not forget to remove any temporary files/folders such as zip-files or temporary backups.
-Example:
-
-```bash
- rm -rf /opt/v${RELEASE}.zip
- rm -rf /opt/snipe-it-backup
-```
-
-### 3.7 **No update function**
-
-- In case you can not provide a update function use the following code to provide user feedback.
-
-```bash
-function update_script() {
- header_info
- check_container_storage
- check_container_resources
- if [[ ! -d /opt/snipeit ]]; then
- msg_error "No ${APP} Installation Found!"
- exit
- fi
- msg_error "There is currently no automatic update function for ${APP}."
- exit
-}
-```
-
----
-
-## 4 **End of the script**
-
-- `start`: Launches Whiptail dialogue
-- `build_container`: Collects and integrates user settings
-- `description`: Sets LXC container description
-- With `echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"` you can point the user to the IP:PORT/folder needed to access the app.
-
-```bash
start
build_container
description
@@ -275,18 +495,223 @@ description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
-echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
+echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5100${CL}"
+```
+
+### Example 2: Database App (Alpine-based)
+
+```bash
+#!/usr/bin/env bash
+source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
+
+APP="PostgreSQL"
+var_tags="database;sql"
+var_cpu="4"
+var_ram="4096"
+var_disk="20"
+var_os="alpine"
+var_version="3.20"
+var_unprivileged="1"
+
+header_info "$APP"
+variables
+color
+catch_errors
+
+function update_script() {
+ header_info
+ check_container_storage
+
+ if ! command -v psql &>/dev/null; then
+ msg_error "PostgreSQL not installed!"
+ exit
+ fi
+
+ msg_info "Updating Alpine packages"
+ apk update
+ apk upgrade
+ msg_ok "Updated Alpine packages"
+ exit
+}
+
+start
+build_container
+description
+
+msg_ok "Completed Successfully!\n"
+echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
+echo -e "${INFO}${YW} Connect using:${CL}"
+echo -e "${TAB}${GATEWAY}${BGN}psql -h ${IP} -U postgres${CL}"
```
---
-## 5. **Contribution checklist**
+## Troubleshooting
-- [ ] Shebang is correctly set (`#!/usr/bin/env bash`).
-- [ ] Correct link to *build.func*
-- [ ] Metadata (author, license) is included at the top.
-- [ ] Variables follow naming conventions.
-- [ ] Update function exists.
-- [ ] Update functions checks if app is installed an for new version.
-- [ ] Update function up temporary files.
-- [ ] Script ends with a helpful message for the user to reach the application.
+### Container Creation Fails
+
+**Symptom**: `pct create` exits with error code 209
+
+**Causes**:
+1. CTID already exists: `pct list` shows duplicate
+2. Storage full: Check storage space
+3. Network template unavailable
+
+**Solution**:
+```bash
+# Check existing containers
+pct list | grep CTID
+
+# Remove conflicting container
+pct destroy CTID
+
+# Retry ct/AppName.sh
+```
+
+### Update Function Doesn't Detect New Version
+
+**Symptom**: Update available but script says "already at latest"
+
+**Causes**:
+1. Version file missing: `/opt/AppName_version.txt`
+2. GitHub API rate limit exceeded
+3. Release tag format mismatch
+
+**Debug**:
+```bash
+# Check version file
+cat /opt/AppName_version.txt
+
+# Test GitHub API
+curl -fsSL https://api.github.com/repos/user/repo/releases/latest | grep tag_name
+
+# Inside container
+bash ct/appname.sh update_script
+```
+
+### Header ASCII Art Not Displaying
+
+**Symptom**: Container script runs but no header shown
+
+**Causes**:
+1. Header file not in repository
+2. Caching issue
+
+**Solution**:
+```bash
+# Create header file manually
+mkdir -p /usr/local/community-scripts/headers/ct
+echo "Your ASCII art here" > /usr/local/community-scripts/headers/ct/appname
+
+# Or remove cache to force re-download
+rm -f /usr/local/community-scripts/headers/ct/appname
+```
+
+---
+
+## Contribution Checklist
+
+Before submitting a PR:
+
+### Script Structure
+- [ ] Shebang is `#!/usr/bin/env bash`
+- [ ] Imports `build.func` from community-scripts repo (not personal fork)
+- [ ] Copyright header with author and source URL
+- [ ] APP variable matches filename
+- [ ] `var_tags` are semicolon-separated (no spaces)
+
+### Default Values
+- [ ] `var_cpu` set appropriately (2-4 for most apps)
+- [ ] `var_ram` set appropriately (1024-4096 MB minimum)
+- [ ] `var_disk` sufficient for app + data (5-20 GB)
+- [ ] `var_os` is realistic (Alpine if lightweight, Debian/Ubuntu otherwise)
+- [ ] `var_unprivileged="1"` unless app absolutely needs privileges
+
+### Functions
+- [ ] `update_script()` implemented (or marked as unavailable)
+- [ ] Update function checks if app installed
+- [ ] Update function checks for new version
+- [ ] Update function performs cleanup after update
+- [ ] Proper error handling with `msg_error` on failure
+
+### Output
+- [ ] Success message displayed with access URL
+- [ ] URL format: `http://IP:PORT/path` (if web-based)
+- [ ] Uses `msg_ok`, `msg_info`, `msg_error` for feedback
+
+### Testing
+- [ ] Script tested with default installation
+- [ ] Script tested with advanced (19-step) installation
+- [ ] Update function tested on existing installation
+- [ ] Error handling tested (invalid settings, network issues)
+
+---
+
+## Best Practices
+
+### β
DO:
+
+1. **Use meaningful defaults**
+ ```bash
+ var_cpu="2" # β
Good: Typical workload
+ var_cpu="128" # β Bad: Unrealistic
+ ```
+
+2. **Implement version tracking**
+ ```bash
+ echo "${RELEASE}" > /opt/${APP}_version.txt # β
Good
+ # β Bad: No version tracking
+ ```
+
+3. **Handle edge cases**
+ ```bash
+ if [[ ! -f /opt/${APP}_version.txt ]]; then
+ msg_info "First installation detected"
+ fi
+ ```
+
+4. **Use proper messaging**
+ ```bash
+ msg_info "Updating..." # β
Good: Clear status
+ echo "Updating..." # β Bad: No formatting
+ ```
+
+### β DON'T:
+
+1. **Hardcode versions**
+ ```bash
+ RELEASE="1.2.3" # β Bad: Won't auto-update
+ ```
+
+2. **Use custom color codes**
+ ```bash
+ echo -e "\033[32mSuccess" # β Bad: Use $GN instead
+ ```
+
+3. **Forget error handling**
+ ```bash
+ wget file.zip # β Bad: No error check
+ if ! wget -q file.zip; then # β
Good
+ msg_error "Download failed"
+ fi
+ ```
+
+4. **Leave temporary files**
+ ```bash
+ rm -rf /opt/file.zip # β
Always cleanup
+ ```
+
+---
+
+## Related Documentation
+
+- [install/AppName-install.sh Guide](UPDATED_APP-install.md)
+- [build.func Wiki](../misc/build.func.md)
+- [tools.func Wiki](../misc/tools.func.md)
+- [Defaults System Guide](../DEFAULTS_SYSTEM_GUIDE.md)
+
+---
+
+**Last Updated**: December 2025
+**Compatibility**: ProxmoxVED with build.func v3+
+**Questions?** Open an issue in the repository
diff --git a/docs/APP-install.md b/docs/APP-install.md
index 8a9c7e65a..a754e3316 100644
--- a/docs/APP-install.md
+++ b/docs/APP-install.md
@@ -1,78 +1,128 @@
+# π οΈ **Application Installation Scripts (install/AppName-install.sh)**
-# **AppName-install.sh Scripts**
+**Modern Guide to Writing In-Container Installation Scripts**
- `AppName-install.sh` scripts found in the `/install` directory. These scripts are responsible for the installation of the application. For this guide we take `/install/snipeit-install.sh` as example.
+> **Updated**: December 2025
+> **Context**: Integrated with tools.func, error_handler.func, and install.func
+> **Examples Used**: `/install/pihole-install.sh`, `/install/mealie-install.sh`
-## Table of Contents
+---
-- [**AppName-install.sh Scripts**](#appname-installsh-scripts)
- - [Table of Contents](#table-of-contents)
- - [1. **File header**](#1-file-header)
- - [1.1 **Shebang**](#11-shebang)
- - [1.2 **Comments**](#12-comments)
- - [1.3 **Variables and function import**](#13-variables-and-function-import)
- - [2. **Variable naming and management**](#2-variable-naming-and-management)
- - [2.1 **Naming conventions**](#21-naming-conventions)
- - [3. **Dependencies**](#3-dependencies)
- - [3.1 **Install all at once**](#31-install-all-at-once)
- - [3.2 **Collapse dependencies**](#32-collapse-dependencies)
- - [4. **Paths to application files**](#4-paths-to-application-files)
- - [5. **Version management**](#5-version-management)
- - [5.1 **Install the latest release**](#51-install-the-latest-release)
- - [5.2 **Save the version for update checks**](#52-save-the-version-for-update-checks)
- - [6. **Input and output management**](#6-input-and-output-management)
- - [6.1 **User feedback**](#61-user-feedback)
- - [6.2 **Verbosity**](#62-verbosity)
- - [7. **String/File Manipulation**](#7-stringfile-manipulation)
- - [7.1 **File Manipulation**](#71-file-manipulation)
- - [8. **Security practices**](#8-security-practices)
- - [8.1 **Password generation**](#81-password-generation)
- - [8.2 **File permissions**](#82-file-permissions)
- - [9. **Service Configuration**](#9-service-configuration)
- - [9.1 **Configuration files**](#91-configuration-files)
- - [9.2 **Credential management**](#92-credential-management)
- - [9.3 **Enviroment files**](#93-enviroment-files)
- - [9.4 **Services**](#94-services)
- - [10. **Cleanup**](#10-cleanup)
- - [10.1 **Remove temporary files**](#101-remove-temporary-files)
- - [10.2 **Autoremove and autoclean**](#102-autoremove-and-autoclean)
- - [11. **Best Practices Checklist**](#11-best-practices-checklist)
- - [Example: High-Level Script Flow](#example-high-level-script-flow)
+## π Table of Contents
-## 1. **File header**
+- [Overview](#overview)
+- [Execution Context](#execution-context)
+- [File Structure](#file-structure)
+- [Complete Script Template](#complete-script-template)
+- [Installation Phases](#installation-phases)
+- [Function Reference](#function-reference)
+- [Best Practices](#best-practices)
+- [Real Examples](#real-examples)
+- [Troubleshooting](#troubleshooting)
+- [Contribution Checklist](#contribution-checklist)
-### 1.1 **Shebang**
+---
-- Use `#!/usr/bin/env bash` as the shebang.
+## Overview
-```bash
-#!/usr/bin/env bash
+### Purpose
+
+Installation scripts (`install/AppName-install.sh`) **run inside the LXC container** and are responsible for:
+
+1. Setting up the container OS (updates, packages)
+2. Installing application dependencies
+3. Downloading and configuring the application
+4. Setting up services and systemd units
+5. Creating version tracking files for updates
+6. Generating credentials/configurations
+7. Final cleanup and validation
+
+### Key Characteristics
+
+- Runs as **root inside container** (not on Proxmox host)
+- Executed automatically by `build_container()` from ct/AppName.sh
+- Uses `$FUNCTIONS_FILE_PATH` for function library access
+- Interactive elements via **whiptail** (GUI menus)
+- Version-aware for update tracking
+
+### Execution Flow
+
+```
+ct/AppName.sh (Proxmox Host)
+ β
+build_container()
+ β
+pct exec CTID bash -c "$(cat install/AppName-install.sh)"
+ β
+install/AppName-install.sh (Inside Container)
+ β
+Container Ready with App Installed
```
-### 1.2 **Comments**
+---
-- Add clear comments for script metadata, including author, copyright, and license information.
-- Use meaningful inline comments to explain complex commands or logic.
+## Execution Context
-Example:
+### Environment Variables Available
```bash
+# From Proxmox/Container
+CTID # Container ID (100, 101, etc.)
+PCT_OSTYPE # OS type (alpine, debian, ubuntu)
+HOSTNAME # Container hostname
+
+# From build.func
+FUNCTIONS_FILE_PATH # Bash functions library (core.func + tools.func)
+VERBOSE # Verbose mode (yes/no)
+STD # Standard redirection variable (silent/empty)
+
+# From install.func
+APP # Application name
+NSAPP # Normalized app name (lowercase, no spaces)
+METHOD # Installation method (ct/install)
+RANDOM_UUID # Session UUID for telemetry
+```
+
+### Access to Functions
+
+```bash
+# All functions from core.func available:
+source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
+color # ANSI colors
+catch_errors # Error handling
+msg_info # Display messages
+msg_ok
+msg_error
+
+# All functions from tools.func available:
+setup_nodejs # Tool installation
+setup_php
+setup_python
+setup_docker
+# ... many more
+
+# All functions from install.func available:
+motd_ssh # Final setup
+customize
+cleanup_lxc
+```
+
+---
+
+## File Structure
+
+### Minimal install/AppName-install.sh Template
+
+```bash
+#!/usr/bin/env bash # [1] Shebang
+
+# [2] Copyright/Metadata
# Copyright (c) 2021-2025 community-scripts ORG
-# Author: [YourUserName]
-# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
-# Source: [SOURCE_URL]
-```
+# Author: YourUsername
+# License: MIT
+# Source: https://example.com
-> [!NOTE]:
->
-> - Add your username
-> - When updating/reworking scripts, add "| Co-Author [YourUserName]"
-
-### 1.3 **Variables and function import**
-
-- This sections adds the support for all needed functions and variables.
-
-```bash
+# [3] Load functions
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
@@ -80,274 +130,992 @@ catch_errors
setting_up_container
network_check
update_os
+
+# [4] Installation steps
+msg_info "Installing Dependencies"
+$STD apt-get install -y package1 package2
+msg_ok "Installed Dependencies"
+
+# [5] Final setup
+motd_ssh
+customize
+cleanup_lxc
```
---
-## 2. **Variable naming and management**
+## Complete Script Template
-### 2.1 **Naming conventions**
-
-- Use uppercase names for constants and environment variables.
-- Use lowercase names for local script variables.
-
-Example:
+### Phase 1: Header & Initialization
```bash
-DB_NAME=snipeit_db # Environment-like variable (constant)
-db_user="snipeit" # Local variable
+#!/usr/bin/env bash
+# Copyright (c) 2021-2025 community-scripts ORG
+# Author: YourUsername
+# Co-Author: AnotherAuthor (for updates)
+# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
+# Source: https://github.com/application/repo
+
+# Load all available functions (from core.func + tools.func)
+source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
+
+# Initialize environment
+color # Setup ANSI colors and icons
+verb_ip6 # Configure IPv6 (if needed)
+catch_errors # Setup error traps
+setting_up_container # Verify OS is ready
+network_check # Verify internet connectivity
+update_os # Update packages (apk/apt)
```
----
-
-## 3. **Dependencies**
-
-### 3.1 **Install all at once**
-
-- Install all dependencies with a single command if possible
-
-Example:
-
-```bash
-$STD apt-get install -y \
- curl \
- composer \
- git \
- sudo \
- mc \
- nginx
-```
-
-### 3.2 **Collapse dependencies**
-
-Collapse dependencies to keep the code readable.
-
-Example:
-Use
-
-```bash
-php8.2-{bcmath,common,ctype}
-```
-
-instead of
-
-```bash
-php8.2-bcmath php8.2-common php8.2-ctype
-```
-
----
-
-## 4. **Paths to application files**
-
-If possible install the app and all necessary files in `/opt/`
-
----
-
-## 5. **Version management**
-
-### 5.1 **Install the latest release**
-
-- Always try and install the latest release
-- Do not hardcode any version if not absolutely necessary
-
-Example for a git release:
-
-```bash
-RELEASE=$(curl -fsSL https://api.github.com/repos/snipe/snipe-it/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
-wget -q "https://github.com/snipe/snipe-it/archive/refs/tags/v${RELEASE}.zip"
-```
-
-### 5.2 **Save the version for update checks**
-
-- Write the installed version into a file.
-- This is used for the update function in **AppName.sh** to check for if a Update is needed.
-
-Example:
-
-```bash
-echo "${RELEASE}" >"/opt/AppName_version.txt"
-```
-
----
-
-## 6. **Input and output management**
-
-### 6.1 **User feedback**
-
-- Use standard functions like `msg_info`, `msg_ok` or `msg_error` to print status messages.
-- Each `msg_info` must be followed with a `msg_ok` before any other output is made.
-- Display meaningful progress messages at key stages.
-
-Example:
+### Phase 2: Dependency Installation
```bash
msg_info "Installing Dependencies"
-$STD apt-get install -y ...
+$STD apt-get install -y \
+ curl \
+ wget \
+ git \
+ nano \
+ build-essential \
+ libssl-dev \
+ python3-dev
msg_ok "Installed Dependencies"
```
-### 6.2 **Verbosity**
+**Guidelines**:
+- Use `\` for line continuation (readability)
+- Group related packages together
+- Collapse repeated prefixes: `php8.4-{bcmath,curl,gd,intl,mbstring}`
+- Use `-y` flag for non-interactive installation
+- Silence output with `$STD` unless debugging
-- Use the appropiate flag (**-q** in the examples) for a command to suppres its output
-Example:
+### Phase 3: Tool Setup (Using tools.func)
```bash
-wget -q
-unzip -q
+# Setup specific tool versions
+NODE_VERSION="22" setup_nodejs
+
+# Or for databases
+MYSQL_VERSION="8.0" setup_mysql
+
+# Or for languages
+PHP_VERSION="8.4" PHP_MODULE="redis,imagick" setup_php
+
+# Or for version control
+setup_composer
```
-- If a command dose not come with such a functionality use `$STD` (a custom standard redirection variable) for managing output verbosity.
-
-Example:
-
+**Available Tool Functions**:
```bash
-$STD apt-get install -y nginx
+setup_nodejs # Node.js from official repo
+setup_php # PHP with optional modules
+setup_python # Python 3
+setup_mariadb # MariaDB database
+setup_mysql # MySQL database
+setup_postgresql # PostgreSQL database
+setup_mongodb # MongoDB database
+setup_docker # Docker Engine
+setup_nodejs # Node.js runtime
+setup_composer # PHP Composer
+setup_ruby # Ruby runtime
+setup_rust # Rust toolchain
+setup_go # Go language
+setup_java # Java/Temurin
+# ... many more in tools.func.md
```
----
-
-## 7. **String/File Manipulation**
-
-### 7.1 **File Manipulation**
-
-- Use `sed` to replace placeholder values in configuration files.
-
-Example:
+### Phase 4: Application Download & Setup
```bash
-sed -i -e "s|^DB_DATABASE=.*|DB_DATABASE=$DB_NAME|" \
- -e "s|^DB_USERNAME=.*|DB_USERNAME=$DB_USER|" \
- -e "s|^DB_PASSWORD=.*|DB_PASSWORD=$DB_PASS|" .env
+# Method A: Download from GitHub releases
+msg_info "Downloading ${APP}"
+RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
+ grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
+
+wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app-${RELEASE}.tar.gz" \
+ -O /opt/app-${RELEASE}.tar.gz
+
+cd /opt
+tar -xzf app-${RELEASE}.tar.gz
+rm -f app-${RELEASE}.tar.gz
+msg_ok "Downloaded and extracted ${APP}"
+
+# Method B: Clone from Git
+git clone https://github.com/user/repo /opt/appname
+
+# Method C: Download single file
+fetch_and_deploy_gh_release "AppName" "user/repo" "tarball"
```
----
-
-## 8. **Security practices**
-
-### 8.1 **Password generation**
-
-- Use `openssl` to generate random passwords.
-- Use only alphanumeric values to not introduce unknown behaviour.
-
-Example:
+### Phase 5: Configuration Files
```bash
-DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
-```
-
-### 8.2 **File permissions**
-
-Explicitly set secure ownership and permissions for sensitive files.
-
-Example:
-
-```bash
-chown -R www-data: /opt/snipe-it
-chmod -R 755 /opt/snipe-it
-```
-
----
-
-## 9. **Service Configuration**
-
-### 9.1 **Configuration files**
-
-Use `cat </etc/nginx/conf.d/snipeit.conf
+# Method A: Using cat << EOF (multiline)
+cat <<'EOF' >/etc/nginx/sites-available/appname
server {
listen 80;
- root /opt/snipe-it/public;
- index index.php;
+ server_name _;
+ root /opt/appname/public;
+ index index.php index.html;
+
+ location ~ \.php$ {
+ fastcgi_pass unix:/run/php-fpm.sock;
+ include fastcgi_params;
+ }
}
EOF
+
+# Method B: Using sed for replacements
+sed -i -e "s|^DB_HOST=.*|DB_HOST=localhost|" \
+ -e "s|^DB_USER=.*|DB_USER=appuser|" \
+ /opt/appname/.env
+
+# Method C: Using echo for simple configs
+echo "APP_KEY=base64:$(openssl rand -base64 32)" >> /opt/appname/.env
```
-### 9.2 **Credential management**
-
-Store the generated credentials in a file.
-
-Example:
+### Phase 6: Database Setup (If Needed)
```bash
-USERNAME=username
-PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
-{
- echo "Application-Credentials"
- echo "Username: $USERNAME"
- echo "Password: $PASSWORD"
-} >> ~/application.creds
+msg_info "Setting up Database"
+
+DB_NAME="appname_db"
+DB_USER="appuser"
+DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
+
+# For MySQL/MariaDB
+mysql -u root <> ~/appname.creds
+Database Credentials
+Database: ${DB_NAME}
+Username: ${DB_USER}
+Password: ${DB_PASS}
+EOF
+
+msg_ok "Database setup complete"
```
-### 9.3 **Enviroment files**
-
-Use `cat </path/to/.env
-VARIABLE="value"
-PORT=3000
-DB_NAME="${DB_NAME}"
+msg_info "Setting permissions"
+
+# Web applications typically run as www-data
+chown -R www-data:www-data /opt/appname
+chmod -R 755 /opt/appname
+chmod -R 644 /opt/appname/*
+chmod 755 /opt/appname/*/.*
+
+# For apps with specific requirements
+find /opt/appname/storage -type f -exec chmod 644 {} \;
+find /opt/appname/storage -type d -exec chmod 755 {} \;
+
+msg_ok "Permissions set"
+```
+
+### Phase 8: Service Configuration
+
+```bash
+# Enable systemd service
+systemctl enable -q --now appname
+
+# Or for OpenRC (Alpine)
+rc-service appname start
+rc-update add appname default
+
+# Verify service is running
+if systemctl is-active --quiet appname; then
+ msg_ok "Service running successfully"
+else
+ msg_error "Service failed to start"
+ journalctl -u appname -n 20
+ exit 1
+fi
+```
+
+### Phase 9: Version Tracking
+
+```bash
+# Essential for update detection
+echo "${RELEASE}" > /opt/${APP}_version.txt
+
+# Or with additional metadata
+cat > /opt/${APP}_version.txt < /opt/${APP}_version.txt
+```
+
+### Phase 5: Configuration
+
+```bash
+# Application-specific configuration
+cat > /opt/appname/.env < /opt/appname/config.yml < /opt/${APP}_version.txt
+
+# β Bad: No version file
+# (Update function won't work)
+```
+
+#### 6. Handle Alpine vs Debian Differences
+
+```bash
+# β
Good: Detect OS
+if grep -qi 'alpine' /etc/os-release; then
+ apk add package
+else
+ apt-get install -y package
+fi
+
+# β Bad: Assumes Debian
+apt-get install -y package
+```
+
+#### 7. Use Proper Messaging
+
+```bash
+# β
Good: Clear status progression
+msg_info "Installing Dependencies"
+$STD apt-get install -y package
+msg_ok "Installed Dependencies"
+
+msg_info "Configuring Application"
+# ... configuration ...
+msg_ok "Application configured"
+
+# β Bad: No status messages
+apt-get install -y package
+# ... configuration ...
+```
+
+### β DON'T:
+
+#### 1. Hardcode Versions
+
+```bash
+# β Bad: Won't auto-update
+VERSION="1.2.3"
+wget https://example.com/app-1.2.3.tar.gz
+
+# β
Good: Fetch latest
+RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | jq -r '.tag_name')
+wget https://example.com/app-${RELEASE}.tar.gz
+```
+
+#### 2. Use Root Without Password
+
+```bash
+# β Bad: Allows unprompted root access
+mysql -u root < /etc/systemd/system/appname.service < /opt/${APP}_version.txt
+
+motd_ssh
+customize
+cleanup_lxc
+```
+
+### Example 2: Database Application (PHP + MySQL)
+
+```bash
+#!/usr/bin/env bash
+source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
+color
+catch_errors
+setting_up_container
+network_check
+update_os
+
+msg_info "Installing Dependencies"
+$STD apt-get install -y git curl nginx supervisor
+msg_ok "Installed Dependencies"
+
+msg_info "Setting up PHP"
+PHP_VERSION="8.4" PHP_MODULE="bcmath,curl,gd,intl,mbstring,pdo_mysql,redis" setup_php
+msg_ok "PHP installed"
+
+msg_info "Setting up Database"
+MARIADB_VERSION="11.4" setup_mariadb
+msg_ok "MariaDB installed"
+
+DB_NAME="appname_db"
+DB_USER="appuser"
+DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
+
+mysql -u root < /opt/${APP}_version.txt
+
+motd_ssh
+customize
+cleanup_lxc
+```
+
+---
+
+## Troubleshooting
+
+### Installation Hangs
+
+**Symptom**: Script appears to freeze at particular step
+
+**Causes**:
+1. Network connectivity lost
+2. Repository server timing out
+3. Interactive prompt waiting for input
+
+**Debug**:
+```bash
+# Check if process still running
+ps aux | grep -i appname
+
+# Check network
+ping -c 1 8.8.8.8
+
+# Check apt lock
+lsof /var/lib/apt/lists/lock
+```
+
+### Package Installation Fails
+
+**Symptom**: `E: Unable to locate package xyz`
+
+**Causes**:
+1. Repository not updated
+2. Package name incorrect for OS version
+3. Conflicting repository configuration
+
+**Solution**:
+```bash
+# Force update
+apt-get update --allow-releaseinfo-change
+apt-cache search package | grep exact_name
+```
+
+### Permission Denied on Files
+
+**Symptom**: Application can't write to `/opt/appname`
+
+**Causes**:
+1. Wrong owner
+2. Wrong permissions (644 for files, 755 for directories)
+
+**Fix**:
+```bash
+chown -R www-data:www-data /opt/appname
+chmod -R 755 /opt/appname
+find /opt/appname -type f -exec chmod 644 {} \;
+find /opt/appname -type d -exec chmod 755 {} \;
+```
+
+### Service Won't Start
+
+**Symptom**: `systemctl status appname` shows failed
+
+**Debug**:
+```bash
+# Check service status
+systemctl status appname
+
+# View logs
+journalctl -u appname -n 50
+
+# Check configuration
+systemctl cat appname
+```
+
+---
+
+## Contribution Checklist
+
+Before submitting a PR:
+
+### Script Structure
+- [ ] Shebang is `#!/usr/bin/env bash`
+- [ ] Copyright header with author and source URL
+- [ ] Functions loaded via `$FUNCTIONS_FILE_PATH`
+- [ ] Initial setup: `color`, `catch_errors`, `setting_up_container`, `network_check`, `update_os`
+
+### Installation Flow
+- [ ] Dependencies installed with `$STD apt-get install -y \`
+- [ ] Package names collapsed (`php-{bcmath,curl}`)
+- [ ] Tool setup uses functions from tools.func (not manual installation)
+- [ ] Application version fetched dynamically (not hardcoded)
+- [ ] Version saved to `/opt/${APP}_version.txt`
+
+### Configuration
+- [ ] Configuration files created properly (heredoc or sed)
+- [ ] Credentials generated randomly (`openssl rand`)
+- [ ] Credentials stored in creds file
+- [ ] Passwords use alphanumeric only (no special chars)
+- [ ] Proper file permissions set
+
+### Messaging
+- [ ] `msg_info` followed by action then `msg_ok`
+- [ ] Error cases use `msg_error` and exit
+- [ ] No bare `echo` statements for status (use msg_* functions)
+
+### Cleanup
+- [ ] Temporary files removed
+- [ ] Package manager cache cleaned (`autoremove`, `autoclean`)
+- [ ] `cleanup_lxc` called at end
+- [ ] `motd_ssh` called before `customize`
+- [ ] `customize` called before exit
+
+### Testing
+- [ ] Script tested with default OS (Debian 12/Ubuntu 22.04)
+- [ ] Script tested with Alpine (if applicable)
+- [ ] Script tested with verbose mode (`VERBOSE=yes`)
+- [ ] Error handling tested (network interruption, missing packages)
+- [ ] Cleanup verified (disk space reduced, temp files removed)
+
+---
+
+## Related Documentation
+
+- [ct/AppName.sh Guide](UPDATED_APP-ct.md)
+- [tools.func Wiki](../misc/tools.func.md)
+- [install.func Wiki](../misc/install.func.md)
+- [error_handler.func Wiki](../misc/error_handler.func.md)
+
+---
+
+**Last Updated**: December 2025
+**Compatibility**: ProxmoxVED with tools.func v2+
+**Questions?** Open an issue in the repository
diff --git a/docs/UPDATED_APP-ct.md b/docs/UPDATED_APP-ct.md
deleted file mode 100644
index e7a12ea7e..000000000
--- a/docs/UPDATED_APP-ct.md
+++ /dev/null
@@ -1,717 +0,0 @@
-# π **Application Container Scripts (ct/AppName.sh)**
-
-**Modern Guide to Creating LXC Container Installation Scripts**
-
-> **Updated**: December 2025
-> **Context**: Fully integrated with build.func, advanced_settings wizard, and defaults system
-> **Example Used**: `/ct/pihole.sh`, `/ct/docker.sh`
-
----
-
-## π Table of Contents
-
-- [Overview](#overview)
-- [Architecture & Flow](#architecture--flow)
-- [File Structure](#file-structure)
-- [Complete Script Template](#complete-script-template)
-- [Function Reference](#function-reference)
-- [Advanced Features](#advanced-features)
-- [Real Examples](#real-examples)
-- [Troubleshooting](#troubleshooting)
-- [Contribution Checklist](#contribution-checklist)
-
----
-
-## Overview
-
-### Purpose
-
-Container scripts (`ct/AppName.sh`) are **entry points for creating LXC containers** with specific applications pre-installed. They:
-
-1. Define container defaults (CPU, RAM, disk, OS)
-2. Call the main build orchestrator (`build.func`)
-3. Implement application-specific update mechanisms
-4. Provide user-facing success messages
-
-### Execution Context
-
-```
-Proxmox Host
- β
-ct/AppName.sh sourced (runs as root on host)
- β
-build.func: Creates LXC container + runs install script inside
- β
-install/AppName-install.sh (runs inside container)
- β
-Container ready with app installed
-```
-
-### Key Integration Points
-
-- **build.func** - Main orchestrator (container creation, storage, variable management)
-- **install.func** - Container-specific setup (OS update, package management)
-- **tools.func** - Tool installation helpers (repositories, GitHub releases)
-- **core.func** - UI/messaging functions (colors, spinners, validation)
-- **error_handler.func** - Error handling and signal management
-
----
-
-## Architecture & Flow
-
-### Container Creation Flow
-
-```
-START: bash ct/pihole.sh
- β
-[1] Set APP, var_*, defaults
- β
-[2] header_info() β Display ASCII art
- β
-[3] variables() β Parse arguments & load build.func
- β
-[4] color() β Setup ANSI codes
- β
-[5] catch_errors() β Setup trap handlers
- β
-[6] install_script() β Show mode menu (5 options)
- β
- ββ INSTALL_MODE="0" (Default)
- ββ INSTALL_MODE="1" (Advanced - 19-step wizard)
- ββ INSTALL_MODE="2" (User Defaults)
- ββ INSTALL_MODE="3" (App Defaults)
- ββ INSTALL_MODE="4" (Settings Menu)
- β
-[7] advanced_settings() β Collect user configuration (if mode=1)
- β
-[8] start() β Confirm or re-edit settings
- β
-[9] build_container() β Create LXC + execute install script
- β
-[10] description() β Set container description
- β
-[11] SUCCESS β Display access URL
- β
-END
-```
-
-### Default Values Precedence
-
-```
-Priority 1 (Highest): Environment Variables (var_cpu, var_ram, etc.)
-Priority 2: App-Specific Defaults (/defaults/AppName.vars)
-Priority 3: User Global Defaults (/default.vars)
-Priority 4 (Lowest): Built-in Defaults (in build.func)
-```
-
----
-
-## File Structure
-
-### Minimal ct/AppName.sh Template
-
-```
-#!/usr/bin/env bash # [1] Shebang
- # [2] Copyright/License
-source <(curl -s .../misc/build.func) # [3] Import functions
- # [4] APP metadata
-APP="AppName" # [5] Default values
-var_tags="tag1;tag2"
-var_cpu="2"
-var_ram="2048"
-...
-
-header_info "$APP" # [6] Display header
-variables # [7] Process arguments
-color # [8] Setup colors
-catch_errors # [9] Setup error handling
-
-function update_script() { ... } # [10] Update function (optional)
-
-start # [11] Launch container creation
-build_container
-description
-msg_ok "Completed Successfully!\n"
-```
-
----
-
-## Complete Script Template
-
-### 1. File Header & Imports
-
-```bash
-#!/usr/bin/env bash
-# Copyright (c) 2021-2025 community-scripts ORG
-# Author: YourUsername
-# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
-# Source: https://github.com/example/project
-
-# Import main orchestrator
-source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
-```
-
-> **β οΈ IMPORTANT**: Before opening a PR, change URL to `community-scripts` repo!
-
-### 2. Application Metadata
-
-```bash
-# Application Configuration
-APP="ApplicationName"
-var_tags="tag1;tag2;tag3" # Max 3-4 tags, no spaces, semicolon-separated
-
-# Container Resources
-var_cpu="2" # CPU cores
-var_ram="2048" # RAM in MB
-var_disk="10" # Disk in GB
-
-# Container Type & OS
-var_os="debian" # Options: alpine, debian, ubuntu
-var_version="12" # Alpine: 3.20+, Debian: 11-13, Ubuntu: 20.04+
-var_unprivileged="1" # 1=unprivileged (secure), 0=privileged (rarely needed)
-```
-
-**Variable Naming Convention**:
-- Variables exposed to user: `var_*` (e.g., `var_cpu`, `var_hostname`, `var_ssh`)
-- Internal variables: lowercase (e.g., `container_id`, `app_version`)
-
-### 3. Display & Initialization
-
-```bash
-# Display header ASCII art
-header_info "$APP"
-
-# Process command-line arguments and load configuration
-variables
-
-# Setup ANSI color codes and formatting
-color
-
-# Initialize error handling (trap ERR, EXIT, INT, TERM)
-catch_errors
-```
-
-### 4. Update Function (Highly Recommended)
-
-```bash
-function update_script() {
- header_info
-
- # Always start with these checks
- check_container_storage
- check_container_resources
-
- # Verify app is installed
- if [[ ! -d /opt/appname ]]; then
- msg_error "No ${APP} Installation Found!"
- exit
- fi
-
- # Get latest version from GitHub
- RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
- grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
-
- # Compare with saved version
- if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
- msg_info "Updating ${APP} to v${RELEASE}"
-
- # Backup user data
- cp -r /opt/appname /opt/appname-backup
-
- # Perform update
- cd /opt
- wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app-${RELEASE}.tar.gz"
- tar -xzf app-${RELEASE}.tar.gz
-
- # Restore user data
- cp /opt/appname-backup/config/* /opt/appname/config/
-
- # Cleanup
- rm -rf app-${RELEASE}.tar.gz /opt/appname-backup
-
- # Save new version
- echo "${RELEASE}" > /opt/${APP}_version.txt
-
- msg_ok "Updated ${APP} to v${RELEASE}"
- else
- msg_ok "No update required. ${APP} is already at v${RELEASE}."
- fi
-
- exit
-}
-```
-
-### 5. Script Launch
-
-```bash
-# Start the container creation workflow
-start
-
-# Build the container with selected configuration
-build_container
-
-# Set container description/notes in Proxmox UI
-description
-
-# Display success message
-msg_ok "Completed Successfully!\n"
-echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
-echo -e "${INFO}${YW} Access it using the following URL:${CL}"
-echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
-```
-
----
-
-## Function Reference
-
-### Core Functions (From build.func)
-
-#### `variables()`
-
-**Purpose**: Initialize container variables, load user arguments, setup orchestration
-
-**Triggered by**: Called automatically at script start
-
-**Behavior**:
-1. Parse command-line arguments (if any)
-2. Generate random UUID for session tracking
-3. Load container storage from Proxmox
-4. Initialize application-specific defaults
-5. Setup SSH/environment configuration
-
-**Example Output**:
-```
-Setting up variables...
-Container ID: 100
-Storage: local-lvm
-Install method: Default
-```
-
-#### `start()`
-
-**Purpose**: Launch the container creation menu with 5 installation modes
-
-**Triggered by**: Called just before `build_container()`
-
-**Menu Options**:
-```
-1. Default Installation (Quick setup, predefined settings)
-2. Advanced Installation (19-step wizard with full control)
-3. User Defaults (Load ~/.community-scripts/default.vars)
-4. App Defaults (Load /defaults/AppName.vars)
-5. Settings Menu (Interactive mode selection)
-```
-
-**User Flow**:
-```
-Select installation mode:
-1) Default
-2) Advanced
-3) User Defaults
-4) App Defaults
-5) Settings Menu
-Enter choice: 2
-```
-
-#### `build_container()`
-
-**Purpose**: Main orchestrator for LXC container creation
-
-**Operations**:
-1. Validates all variables
-2. Creates LXC container via `pct create`
-3. Executes `install/AppName-install.sh` inside container
-4. Monitors installation progress
-5. Handles errors and rollback on failure
-
-**Exit Codes**:
-- `0` - Success
-- `1-255` - Various error conditions (see error_handler.func)
-
-#### `description()`
-
-**Purpose**: Set container description/notes visible in Proxmox UI
-
-**Format**:
-```
-AppName
-IP: [IP]
-Version: [Version]
-Tags: [Tags]
-```
-
-#### `header_info()`
-
-**Purpose**: Display ASCII art header for application
-
-**Sources**:
-- Tries `/usr/local/community-scripts/headers/ct/appname` (cached)
-- Falls back to remote fetch from GitHub
-- Returns silently if not found
-
----
-
-## Advanced Features
-
-### 1. Integration with Defaults System
-
-#### Save App Defaults After Installation
-
-```bash
-# At end of install script, after successful setup:
-maybe_offer_save_app_defaults
-
-# Output:
-# "Save these settings as App Defaults for AppName? (Y/n)"
-# Yes β Saves to /defaults/appname.vars
-# No β Skips saving
-```
-
-#### Load Saved Defaults During Container Creation
-
-```bash
-# In ct/AppName.sh, user selects "App Defaults" mode
-# Automatically loads /defaults/appname.vars
-# Container uses previously saved configuration
-```
-
-### 2. Custom Configuration Menus
-
-If your app has additional setup beyond standard vars:
-
-```bash
-# In ct/AppName.sh, after variables()
-custom_app_settings() {
- CONFIGURE_DB=$(whiptail --title "Database Setup" \
- --yesno "Would you like to configure a custom database?" 8 60)
-
- if [[ $? -eq 0 ]]; then
- DB_HOST=$(whiptail --inputbox "Database Host:" 8 60 3>&1 1>&2 2>&3)
- DB_PORT=$(whiptail --inputbox "Database Port:" 8 60 "3306" 3>&1 1>&2 2>&3)
- fi
-}
-
-custom_app_settings
-```
-
-### 3. Version Tracking
-
-Save installed version for update checks:
-
-```bash
-# In install script, after successful app download:
-RELEASE="1.2.3"
-echo "${RELEASE}" > /opt/${APP}_version.txt
-
-# In update function, compare:
-CURRENT=$(cat /opt/${APP}_version.txt 2>/dev/null)
-LATEST=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | jq -r '.tag_name')
-
-if [[ "$LATEST" != "$CURRENT" ]]; then
- echo "Update available: $CURRENT β $LATEST"
-fi
-```
-
-### 4. Health Check Functions
-
-Add custom validation:
-
-```bash
-function health_check() {
- header_info
-
- if [[ ! -d /opt/appname ]]; then
- msg_error "Application not found!"
- exit 1
- fi
-
- if ! systemctl is-active --quiet appname; then
- msg_error "Application service not running"
- exit 1
- fi
-
- msg_ok "Health check passed"
-}
-
-# Called via: bash ct/appname.sh health_check
-```
-
----
-
-## Real Examples
-
-### Example 1: Simple Web App (Debian-based)
-
-```bash
-#!/usr/bin/env bash
-source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
-
-APP="Homarr"
-var_tags="dashboard;homepage"
-var_cpu="2"
-var_ram="1024"
-var_disk="5"
-var_os="debian"
-var_version="12"
-var_unprivileged="1"
-
-header_info "$APP"
-variables
-color
-catch_errors
-
-function update_script() {
- header_info
- check_container_storage
- check_container_resources
-
- if [[ ! -d /opt/homarr ]]; then
- msg_error "No ${APP} Installation Found!"
- exit
- fi
-
- RELEASE=$(curl -fsSL https://api.github.com/repos/ajnart/homarr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}')
-
- if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
- msg_info "Updating ${APP} to v${RELEASE}"
- systemctl stop homarr
-
- cd /opt/homarr
- wget -q "https://github.com/ajnart/homarr/releases/download/v${RELEASE}/docker-compose.yml"
- docker-compose up -d
-
- echo "${RELEASE}" > /opt/${APP}_version.txt
- msg_ok "Updated ${APP} to v${RELEASE}"
- else
- msg_ok "No update required. ${APP} is already at v${RELEASE}."
- fi
- exit
-}
-
-start
-build_container
-description
-
-msg_ok "Completed Successfully!\n"
-echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
-echo -e "${INFO}${YW} Access it using the following URL:${CL}"
-echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5100${CL}"
-```
-
-### Example 2: Database App (Alpine-based)
-
-```bash
-#!/usr/bin/env bash
-source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
-
-APP="PostgreSQL"
-var_tags="database;sql"
-var_cpu="4"
-var_ram="4096"
-var_disk="20"
-var_os="alpine"
-var_version="3.20"
-var_unprivileged="1"
-
-header_info "$APP"
-variables
-color
-catch_errors
-
-function update_script() {
- header_info
- check_container_storage
-
- if ! command -v psql &>/dev/null; then
- msg_error "PostgreSQL not installed!"
- exit
- fi
-
- msg_info "Updating Alpine packages"
- apk update
- apk upgrade
- msg_ok "Updated Alpine packages"
- exit
-}
-
-start
-build_container
-description
-
-msg_ok "Completed Successfully!\n"
-echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
-echo -e "${INFO}${YW} Connect using:${CL}"
-echo -e "${TAB}${GATEWAY}${BGN}psql -h ${IP} -U postgres${CL}"
-```
-
----
-
-## Troubleshooting
-
-### Container Creation Fails
-
-**Symptom**: `pct create` exits with error code 209
-
-**Causes**:
-1. CTID already exists: `pct list` shows duplicate
-2. Storage full: Check storage space
-3. Network template unavailable
-
-**Solution**:
-```bash
-# Check existing containers
-pct list | grep CTID
-
-# Remove conflicting container
-pct destroy CTID
-
-# Retry ct/AppName.sh
-```
-
-### Update Function Doesn't Detect New Version
-
-**Symptom**: Update available but script says "already at latest"
-
-**Causes**:
-1. Version file missing: `/opt/AppName_version.txt`
-2. GitHub API rate limit exceeded
-3. Release tag format mismatch
-
-**Debug**:
-```bash
-# Check version file
-cat /opt/AppName_version.txt
-
-# Test GitHub API
-curl -fsSL https://api.github.com/repos/user/repo/releases/latest | grep tag_name
-
-# Inside container
-bash ct/appname.sh update_script
-```
-
-### Header ASCII Art Not Displaying
-
-**Symptom**: Container script runs but no header shown
-
-**Causes**:
-1. Header file not in repository
-2. Caching issue
-
-**Solution**:
-```bash
-# Create header file manually
-mkdir -p /usr/local/community-scripts/headers/ct
-echo "Your ASCII art here" > /usr/local/community-scripts/headers/ct/appname
-
-# Or remove cache to force re-download
-rm -f /usr/local/community-scripts/headers/ct/appname
-```
-
----
-
-## Contribution Checklist
-
-Before submitting a PR:
-
-### Script Structure
-- [ ] Shebang is `#!/usr/bin/env bash`
-- [ ] Imports `build.func` from community-scripts repo (not personal fork)
-- [ ] Copyright header with author and source URL
-- [ ] APP variable matches filename
-- [ ] `var_tags` are semicolon-separated (no spaces)
-
-### Default Values
-- [ ] `var_cpu` set appropriately (2-4 for most apps)
-- [ ] `var_ram` set appropriately (1024-4096 MB minimum)
-- [ ] `var_disk` sufficient for app + data (5-20 GB)
-- [ ] `var_os` is realistic (Alpine if lightweight, Debian/Ubuntu otherwise)
-- [ ] `var_unprivileged="1"` unless app absolutely needs privileges
-
-### Functions
-- [ ] `update_script()` implemented (or marked as unavailable)
-- [ ] Update function checks if app installed
-- [ ] Update function checks for new version
-- [ ] Update function performs cleanup after update
-- [ ] Proper error handling with `msg_error` on failure
-
-### Output
-- [ ] Success message displayed with access URL
-- [ ] URL format: `http://IP:PORT/path` (if web-based)
-- [ ] Uses `msg_ok`, `msg_info`, `msg_error` for feedback
-
-### Testing
-- [ ] Script tested with default installation
-- [ ] Script tested with advanced (19-step) installation
-- [ ] Update function tested on existing installation
-- [ ] Error handling tested (invalid settings, network issues)
-
----
-
-## Best Practices
-
-### β
DO:
-
-1. **Use meaningful defaults**
- ```bash
- var_cpu="2" # β
Good: Typical workload
- var_cpu="128" # β Bad: Unrealistic
- ```
-
-2. **Implement version tracking**
- ```bash
- echo "${RELEASE}" > /opt/${APP}_version.txt # β
Good
- # β Bad: No version tracking
- ```
-
-3. **Handle edge cases**
- ```bash
- if [[ ! -f /opt/${APP}_version.txt ]]; then
- msg_info "First installation detected"
- fi
- ```
-
-4. **Use proper messaging**
- ```bash
- msg_info "Updating..." # β
Good: Clear status
- echo "Updating..." # β Bad: No formatting
- ```
-
-### β DON'T:
-
-1. **Hardcode versions**
- ```bash
- RELEASE="1.2.3" # β Bad: Won't auto-update
- ```
-
-2. **Use custom color codes**
- ```bash
- echo -e "\033[32mSuccess" # β Bad: Use $GN instead
- ```
-
-3. **Forget error handling**
- ```bash
- wget file.zip # β Bad: No error check
- if ! wget -q file.zip; then # β
Good
- msg_error "Download failed"
- fi
- ```
-
-4. **Leave temporary files**
- ```bash
- rm -rf /opt/file.zip # β
Always cleanup
- ```
-
----
-
-## Related Documentation
-
-- [install/AppName-install.sh Guide](UPDATED_APP-install.md)
-- [build.func Wiki](../misc/build.func.md)
-- [tools.func Wiki](../misc/tools.func.md)
-- [Defaults System Guide](../DEFAULTS_SYSTEM_GUIDE.md)
-
----
-
-**Last Updated**: December 2025
-**Compatibility**: ProxmoxVED with build.func v3+
-**Questions?** Open an issue in the repository
diff --git a/docs/UPDATED_APP-install.md b/docs/UPDATED_APP-install.md
deleted file mode 100644
index c012aba5c..000000000
--- a/docs/UPDATED_APP-install.md
+++ /dev/null
@@ -1,1121 +0,0 @@
-# π οΈ **Application Installation Scripts (install/AppName-install.sh)**
-
-**Modern Guide to Writing In-Container Installation Scripts**
-
-> **Updated**: December 2025
-> **Context**: Integrated with tools.func, error_handler.func, and install.func
-> **Examples Used**: `/install/pihole-install.sh`, `/install/mealie-install.sh`
-
----
-
-## π Table of Contents
-
-- [Overview](#overview)
-- [Execution Context](#execution-context)
-- [File Structure](#file-structure)
-- [Complete Script Template](#complete-script-template)
-- [Installation Phases](#installation-phases)
-- [Function Reference](#function-reference)
-- [Best Practices](#best-practices)
-- [Real Examples](#real-examples)
-- [Troubleshooting](#troubleshooting)
-- [Contribution Checklist](#contribution-checklist)
-
----
-
-## Overview
-
-### Purpose
-
-Installation scripts (`install/AppName-install.sh`) **run inside the LXC container** and are responsible for:
-
-1. Setting up the container OS (updates, packages)
-2. Installing application dependencies
-3. Downloading and configuring the application
-4. Setting up services and systemd units
-5. Creating version tracking files for updates
-6. Generating credentials/configurations
-7. Final cleanup and validation
-
-### Key Characteristics
-
-- Runs as **root inside container** (not on Proxmox host)
-- Executed automatically by `build_container()` from ct/AppName.sh
-- Uses `$FUNCTIONS_FILE_PATH` for function library access
-- Interactive elements via **whiptail** (GUI menus)
-- Version-aware for update tracking
-
-### Execution Flow
-
-```
-ct/AppName.sh (Proxmox Host)
- β
-build_container()
- β
-pct exec CTID bash -c "$(cat install/AppName-install.sh)"
- β
-install/AppName-install.sh (Inside Container)
- β
-Container Ready with App Installed
-```
-
----
-
-## Execution Context
-
-### Environment Variables Available
-
-```bash
-# From Proxmox/Container
-CTID # Container ID (100, 101, etc.)
-PCT_OSTYPE # OS type (alpine, debian, ubuntu)
-HOSTNAME # Container hostname
-
-# From build.func
-FUNCTIONS_FILE_PATH # Bash functions library (core.func + tools.func)
-VERBOSE # Verbose mode (yes/no)
-STD # Standard redirection variable (silent/empty)
-
-# From install.func
-APP # Application name
-NSAPP # Normalized app name (lowercase, no spaces)
-METHOD # Installation method (ct/install)
-RANDOM_UUID # Session UUID for telemetry
-```
-
-### Access to Functions
-
-```bash
-# All functions from core.func available:
-source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
-color # ANSI colors
-catch_errors # Error handling
-msg_info # Display messages
-msg_ok
-msg_error
-
-# All functions from tools.func available:
-setup_nodejs # Tool installation
-setup_php
-setup_python
-setup_docker
-# ... many more
-
-# All functions from install.func available:
-motd_ssh # Final setup
-customize
-cleanup_lxc
-```
-
----
-
-## File Structure
-
-### Minimal install/AppName-install.sh Template
-
-```bash
-#!/usr/bin/env bash # [1] Shebang
-
-# [2] Copyright/Metadata
-# Copyright (c) 2021-2025 community-scripts ORG
-# Author: YourUsername
-# License: MIT
-# Source: https://example.com
-
-# [3] Load functions
-source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
-color
-verb_ip6
-catch_errors
-setting_up_container
-network_check
-update_os
-
-# [4] Installation steps
-msg_info "Installing Dependencies"
-$STD apt-get install -y package1 package2
-msg_ok "Installed Dependencies"
-
-# [5] Final setup
-motd_ssh
-customize
-cleanup_lxc
-```
-
----
-
-## Complete Script Template
-
-### Phase 1: Header & Initialization
-
-```bash
-#!/usr/bin/env bash
-# Copyright (c) 2021-2025 community-scripts ORG
-# Author: YourUsername
-# Co-Author: AnotherAuthor (for updates)
-# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
-# Source: https://github.com/application/repo
-
-# Load all available functions (from core.func + tools.func)
-source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
-
-# Initialize environment
-color # Setup ANSI colors and icons
-verb_ip6 # Configure IPv6 (if needed)
-catch_errors # Setup error traps
-setting_up_container # Verify OS is ready
-network_check # Verify internet connectivity
-update_os # Update packages (apk/apt)
-```
-
-### Phase 2: Dependency Installation
-
-```bash
-msg_info "Installing Dependencies"
-$STD apt-get install -y \
- curl \
- wget \
- git \
- nano \
- build-essential \
- libssl-dev \
- python3-dev
-msg_ok "Installed Dependencies"
-```
-
-**Guidelines**:
-- Use `\` for line continuation (readability)
-- Group related packages together
-- Collapse repeated prefixes: `php8.4-{bcmath,curl,gd,intl,mbstring}`
-- Use `-y` flag for non-interactive installation
-- Silence output with `$STD` unless debugging
-
-### Phase 3: Tool Setup (Using tools.func)
-
-```bash
-# Setup specific tool versions
-NODE_VERSION="22" setup_nodejs
-
-# Or for databases
-MYSQL_VERSION="8.0" setup_mysql
-
-# Or for languages
-PHP_VERSION="8.4" PHP_MODULE="redis,imagick" setup_php
-
-# Or for version control
-setup_composer
-```
-
-**Available Tool Functions**:
-```bash
-setup_nodejs # Node.js from official repo
-setup_php # PHP with optional modules
-setup_python # Python 3
-setup_mariadb # MariaDB database
-setup_mysql # MySQL database
-setup_postgresql # PostgreSQL database
-setup_mongodb # MongoDB database
-setup_docker # Docker Engine
-setup_nodejs # Node.js runtime
-setup_composer # PHP Composer
-setup_ruby # Ruby runtime
-setup_rust # Rust toolchain
-setup_go # Go language
-setup_java # Java/Temurin
-# ... many more in tools.func.md
-```
-
-### Phase 4: Application Download & Setup
-
-```bash
-# Method A: Download from GitHub releases
-msg_info "Downloading ${APP}"
-RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
- grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
-
-wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app-${RELEASE}.tar.gz" \
- -O /opt/app-${RELEASE}.tar.gz
-
-cd /opt
-tar -xzf app-${RELEASE}.tar.gz
-rm -f app-${RELEASE}.tar.gz
-msg_ok "Downloaded and extracted ${APP}"
-
-# Method B: Clone from Git
-git clone https://github.com/user/repo /opt/appname
-
-# Method C: Download single file
-fetch_and_deploy_gh_release "AppName" "user/repo" "tarball"
-```
-
-### Phase 5: Configuration Files
-
-```bash
-# Method A: Using cat << EOF (multiline)
-cat <<'EOF' >/etc/nginx/sites-available/appname
-server {
- listen 80;
- server_name _;
- root /opt/appname/public;
- index index.php index.html;
-
- location ~ \.php$ {
- fastcgi_pass unix:/run/php-fpm.sock;
- include fastcgi_params;
- }
-}
-EOF
-
-# Method B: Using sed for replacements
-sed -i -e "s|^DB_HOST=.*|DB_HOST=localhost|" \
- -e "s|^DB_USER=.*|DB_USER=appuser|" \
- /opt/appname/.env
-
-# Method C: Using echo for simple configs
-echo "APP_KEY=base64:$(openssl rand -base64 32)" >> /opt/appname/.env
-```
-
-### Phase 6: Database Setup (If Needed)
-
-```bash
-msg_info "Setting up Database"
-
-DB_NAME="appname_db"
-DB_USER="appuser"
-DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
-
-# For MySQL/MariaDB
-mysql -u root <> ~/appname.creds
-Database Credentials
-Database: ${DB_NAME}
-Username: ${DB_USER}
-Password: ${DB_PASS}
-EOF
-
-msg_ok "Database setup complete"
-```
-
-### Phase 7: Permission & Ownership
-
-```bash
-msg_info "Setting permissions"
-
-# Web applications typically run as www-data
-chown -R www-data:www-data /opt/appname
-chmod -R 755 /opt/appname
-chmod -R 644 /opt/appname/*
-chmod 755 /opt/appname/*/.*
-
-# For apps with specific requirements
-find /opt/appname/storage -type f -exec chmod 644 {} \;
-find /opt/appname/storage -type d -exec chmod 755 {} \;
-
-msg_ok "Permissions set"
-```
-
-### Phase 8: Service Configuration
-
-```bash
-# Enable systemd service
-systemctl enable -q --now appname
-
-# Or for OpenRC (Alpine)
-rc-service appname start
-rc-update add appname default
-
-# Verify service is running
-if systemctl is-active --quiet appname; then
- msg_ok "Service running successfully"
-else
- msg_error "Service failed to start"
- journalctl -u appname -n 20
- exit 1
-fi
-```
-
-### Phase 9: Version Tracking
-
-```bash
-# Essential for update detection
-echo "${RELEASE}" > /opt/${APP}_version.txt
-
-# Or with additional metadata
-cat > /opt/${APP}_version.txt < /opt/${APP}_version.txt
-```
-
-### Phase 5: Configuration
-
-```bash
-# Application-specific configuration
-cat > /opt/appname/.env < /opt/appname/config.yml < /opt/${APP}_version.txt
-
-# β Bad: No version file
-# (Update function won't work)
-```
-
-#### 6. Handle Alpine vs Debian Differences
-
-```bash
-# β
Good: Detect OS
-if grep -qi 'alpine' /etc/os-release; then
- apk add package
-else
- apt-get install -y package
-fi
-
-# β Bad: Assumes Debian
-apt-get install -y package
-```
-
-#### 7. Use Proper Messaging
-
-```bash
-# β
Good: Clear status progression
-msg_info "Installing Dependencies"
-$STD apt-get install -y package
-msg_ok "Installed Dependencies"
-
-msg_info "Configuring Application"
-# ... configuration ...
-msg_ok "Application configured"
-
-# β Bad: No status messages
-apt-get install -y package
-# ... configuration ...
-```
-
-### β DON'T:
-
-#### 1. Hardcode Versions
-
-```bash
-# β Bad: Won't auto-update
-VERSION="1.2.3"
-wget https://example.com/app-1.2.3.tar.gz
-
-# β
Good: Fetch latest
-RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | jq -r '.tag_name')
-wget https://example.com/app-${RELEASE}.tar.gz
-```
-
-#### 2. Use Root Without Password
-
-```bash
-# β Bad: Allows unprompted root access
-mysql -u root < /etc/systemd/system/appname.service < /opt/${APP}_version.txt
-
-motd_ssh
-customize
-cleanup_lxc
-```
-
-### Example 2: Database Application (PHP + MySQL)
-
-```bash
-#!/usr/bin/env bash
-source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
-color
-catch_errors
-setting_up_container
-network_check
-update_os
-
-msg_info "Installing Dependencies"
-$STD apt-get install -y git curl nginx supervisor
-msg_ok "Installed Dependencies"
-
-msg_info "Setting up PHP"
-PHP_VERSION="8.4" PHP_MODULE="bcmath,curl,gd,intl,mbstring,pdo_mysql,redis" setup_php
-msg_ok "PHP installed"
-
-msg_info "Setting up Database"
-MARIADB_VERSION="11.4" setup_mariadb
-msg_ok "MariaDB installed"
-
-DB_NAME="appname_db"
-DB_USER="appuser"
-DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
-
-mysql -u root < /opt/${APP}_version.txt
-
-motd_ssh
-customize
-cleanup_lxc
-```
-
----
-
-## Troubleshooting
-
-### Installation Hangs
-
-**Symptom**: Script appears to freeze at particular step
-
-**Causes**:
-1. Network connectivity lost
-2. Repository server timing out
-3. Interactive prompt waiting for input
-
-**Debug**:
-```bash
-# Check if process still running
-ps aux | grep -i appname
-
-# Check network
-ping -c 1 8.8.8.8
-
-# Check apt lock
-lsof /var/lib/apt/lists/lock
-```
-
-### Package Installation Fails
-
-**Symptom**: `E: Unable to locate package xyz`
-
-**Causes**:
-1. Repository not updated
-2. Package name incorrect for OS version
-3. Conflicting repository configuration
-
-**Solution**:
-```bash
-# Force update
-apt-get update --allow-releaseinfo-change
-apt-cache search package | grep exact_name
-```
-
-### Permission Denied on Files
-
-**Symptom**: Application can't write to `/opt/appname`
-
-**Causes**:
-1. Wrong owner
-2. Wrong permissions (644 for files, 755 for directories)
-
-**Fix**:
-```bash
-chown -R www-data:www-data /opt/appname
-chmod -R 755 /opt/appname
-find /opt/appname -type f -exec chmod 644 {} \;
-find /opt/appname -type d -exec chmod 755 {} \;
-```
-
-### Service Won't Start
-
-**Symptom**: `systemctl status appname` shows failed
-
-**Debug**:
-```bash
-# Check service status
-systemctl status appname
-
-# View logs
-journalctl -u appname -n 50
-
-# Check configuration
-systemctl cat appname
-```
-
----
-
-## Contribution Checklist
-
-Before submitting a PR:
-
-### Script Structure
-- [ ] Shebang is `#!/usr/bin/env bash`
-- [ ] Copyright header with author and source URL
-- [ ] Functions loaded via `$FUNCTIONS_FILE_PATH`
-- [ ] Initial setup: `color`, `catch_errors`, `setting_up_container`, `network_check`, `update_os`
-
-### Installation Flow
-- [ ] Dependencies installed with `$STD apt-get install -y \`
-- [ ] Package names collapsed (`php-{bcmath,curl}`)
-- [ ] Tool setup uses functions from tools.func (not manual installation)
-- [ ] Application version fetched dynamically (not hardcoded)
-- [ ] Version saved to `/opt/${APP}_version.txt`
-
-### Configuration
-- [ ] Configuration files created properly (heredoc or sed)
-- [ ] Credentials generated randomly (`openssl rand`)
-- [ ] Credentials stored in creds file
-- [ ] Passwords use alphanumeric only (no special chars)
-- [ ] Proper file permissions set
-
-### Messaging
-- [ ] `msg_info` followed by action then `msg_ok`
-- [ ] Error cases use `msg_error` and exit
-- [ ] No bare `echo` statements for status (use msg_* functions)
-
-### Cleanup
-- [ ] Temporary files removed
-- [ ] Package manager cache cleaned (`autoremove`, `autoclean`)
-- [ ] `cleanup_lxc` called at end
-- [ ] `motd_ssh` called before `customize`
-- [ ] `customize` called before exit
-
-### Testing
-- [ ] Script tested with default OS (Debian 12/Ubuntu 22.04)
-- [ ] Script tested with Alpine (if applicable)
-- [ ] Script tested with verbose mode (`VERBOSE=yes`)
-- [ ] Error handling tested (network interruption, missing packages)
-- [ ] Cleanup verified (disk space reduced, temp files removed)
-
----
-
-## Related Documentation
-
-- [ct/AppName.sh Guide](UPDATED_APP-ct.md)
-- [tools.func Wiki](../misc/tools.func.md)
-- [install.func Wiki](../misc/install.func.md)
-- [error_handler.func Wiki](../misc/error_handler.func.md)
-
----
-
-**Last Updated**: December 2025
-**Compatibility**: ProxmoxVED with tools.func v2+
-**Questions?** Open an issue in the repository
diff --git a/docs/api.func.md b/docs/api.func.md
new file mode 100644
index 000000000..17c635400
--- /dev/null
+++ b/docs/api.func.md
@@ -0,0 +1,670 @@
+# API.func Wiki
+
+A telemetry and diagnostics module providing anonymous statistics collection and API integration with the Community-Scripts infrastructure for tracking container/VM creation metrics and installation success/failure data.
+
+---
+
+## π Table of Contents
+
+- [Overview](#overview)
+- [Exit Code Reference](#exit-code-reference)
+- [Telemetry Functions](#telemetry-functions)
+- [API Payload Structure](#api-payload-structure)
+- [Privacy & Opt-Out](#privacy--opt-out)
+- [Error Mapping](#error-mapping)
+- [Best Practices](#best-practices)
+- [API Integration](#api-integration)
+- [Contributing](#contributing)
+
+---
+
+## Overview
+
+The API.func module provides anonymous telemetry reporting to Community-Scripts infrastructure, enabling:
+
+- β
Container/VM creation statistics collection
+- β
Installation success/failure tracking
+- β
Comprehensive exit code mapping and explanation
+- β
Anonymous session-based tracking (UUID)
+- β
Privacy-respecting data collection (no personal data)
+- β
Opt-out capability via DIAGNOSTICS setting
+- β
Consistent error reporting across all scripts
+
+### Integration Points
+
+```bash
+# In container build scripts (on Proxmox host):
+source <(curl -fsSL .../api.func)
+post_to_api # Report container creation
+post_update_to_api # Report installation completion
+
+# Error handling (in all scripts):
+source <(curl -fsSL .../error_handler.func)
+# explain_exit_code shared for consistent mappings
+```
+
+### Data Flow
+
+```
+Container/VM Creation
+ β
+ post_to_api()
+ β
+Community-Scripts API
+ β
+Anonymous Statistics
+(No personal data)
+```
+
+---
+
+## Exit Code Reference
+
+### Category 1: Generic / Shell Errors
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 1 | General error / Operation not permitted | Check permissions, re-run command |
+| 2 | Misuse of shell builtins (syntax error) | Fix shell syntax, validate script |
+| 126 | Command invoked cannot execute | Fix file permissions (chmod +x) |
+| 127 | Command not found | Install missing package or tool |
+| 128 | Invalid argument to exit | Check exit code parameter (0-255) |
+| 130 | Terminated by Ctrl+C (SIGINT) | User interrupted - retry manually |
+| 137 | Killed (SIGKILL / Out of memory) | Insufficient RAM - increase allocation |
+| 139 | Segmentation fault (core dumped) | Serious application bug - contact support |
+| 143 | Terminated (SIGTERM) | System shutdown or manual termination |
+
+### Category 2: Package Manager Errors
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 100 | APT: Package manager error (broken packages) | Run `apt --fix-broken install` |
+| 101 | APT: Configuration error (bad sources.list) | Fix /etc/apt/sources.list, re-run apt update |
+| 255 | DPKG: Fatal internal error | Run `dpkg --configure -a` |
+
+### Category 3: Node.js / npm Errors
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 243 | Node.js: Out of memory (heap out of memory) | Increase container RAM, reduce workload |
+| 245 | Node.js: Invalid command-line option | Check node/npm arguments |
+| 246 | Node.js: Internal JavaScript Parse Error | Update Node.js version |
+| 247 | Node.js: Fatal internal error | Check Node.js installation integrity |
+| 248 | Node.js: Invalid C++ addon / N-API failure | Rebuild native modules |
+| 249 | Node.js: Inspector error | Disable debugger, retry |
+| 254 | npm/pnpm/yarn: Unknown fatal error | Check package.json, clear cache |
+
+### Category 4: Python Errors
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 210 | Python: Virtualenv / uv environment missing | Recreate virtual environment |
+| 211 | Python: Dependency resolution failed | Check package versions, fix conflicts |
+| 212 | Python: Installation aborted (EXTERNALLY-MANAGED) | Use venv or remove marker file |
+
+### Category 5: Database Errors
+
+#### PostgreSQL
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 231 | Connection failed (server not running) | Start PostgreSQL service |
+| 232 | Authentication failed (bad user/password) | Verify credentials |
+| 233 | Database does not exist | Create database: `createdb dbname` |
+| 234 | Fatal error in query / syntax error | Fix SQL syntax |
+
+#### MySQL / MariaDB
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 241 | Connection failed (server not running) | Start MySQL/MariaDB service |
+| 242 | Authentication failed (bad user/password) | Reset password, verify credentials |
+| 243 | Database does not exist | Create database: `CREATE DATABASE dbname;` |
+| 244 | Fatal error in query / syntax error | Fix SQL syntax |
+
+#### MongoDB
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 251 | Connection failed (server not running) | Start MongoDB daemon |
+| 252 | Authentication failed (bad user/password) | Verify credentials, reset if needed |
+| 253 | Database not found | Create database in MongoDB shell |
+| 254 | Fatal query error | Check query syntax |
+
+### Category 6: Proxmox Custom Codes
+
+| Code | Meaning | Recovery |
+|------|---------|----------|
+| 200 | Failed to create lock file | Check /tmp permissions |
+| 203 | Missing CTID variable | CTID must be provided to script |
+| 204 | Missing PCT_OSTYPE variable | OS type not detected |
+| 205 | Invalid CTID (<100) | Container ID must be >= 100 |
+| 206 | CTID already in use | Check `pct list`, remove conflicting container |
+| 207 | Password contains special characters | Use alphanumeric only for passwords |
+| 208 | Invalid configuration format | Check DNS/MAC/Network format |
+| 209 | Container creation failed | Check pct create output for details |
+| 210 | Cluster not quorate | Ensure cluster nodes are online |
+| 211 | Timeout waiting for template lock | Wait for concurrent downloads to finish |
+| 214 | Not enough storage space | Free up disk space or expand storage |
+| 215 | Container created but not listed | Check /etc/pve/lxc/ for config files |
+| 216 | RootFS entry missing in config | Incomplete container creation |
+| 217 | Storage does not support rootdir | Use compatible storage backend |
+| 218 | Template corrupted or incomplete | Re-download template |
+| 220 | Unable to resolve template path | Verify template availability |
+| 221 | Template not readable | Fix file permissions |
+| 222 | Template download failed (3 attempts) | Check network/storage |
+| 223 | Template not available after download | Storage sync issue |
+| 225 | No template for OS/Version | Run `pveam available` to see options |
+| 231 | LXC stack upgrade/retry failed | Update pve-container package |
+
+---
+
+## Telemetry Functions
+
+### `explain_exit_code()`
+
+**Purpose**: Maps numeric exit codes to human-readable error descriptions. Shared between api.func and error_handler.func for consistency.
+
+**Signature**:
+```bash
+explain_exit_code()
+```
+
+**Parameters**:
+- `$1` - Numeric exit code (0-255)
+
+**Returns**: Human-readable description string
+
+**Supported Codes**:
+- 1-2, 126-128, 130, 137, 139, 143 (Shell)
+- 100-101, 255 (Package managers)
+- 210-212 (Python)
+- 231-234 (PostgreSQL)
+- 241-244 (MySQL/MariaDB)
+- 243-249, 254 (Node.js/npm)
+- 251-254 (MongoDB)
+- 200-231 (Proxmox custom)
+
+**Default**: Returns "Unknown error" for unmapped codes
+
+**Usage Examples**:
+
+```bash
+# Example 1: Common error
+explain_exit_code 127
+# Output: "Command not found"
+
+# Example 2: Database error
+explain_exit_code 241
+# Output: "MySQL/MariaDB: Connection failed (server not running / wrong socket)"
+
+# Example 3: Custom Proxmox error
+explain_exit_code 206
+# Output: "Custom: CTID already in use (check 'pct list' and /etc/pve/lxc/)"
+
+# Example 4: Unknown code
+explain_exit_code 999
+# Output: "Unknown error"
+```
+
+---
+
+### `post_to_api()`
+
+**Purpose**: Sends LXC container creation statistics to Community-Scripts telemetry API.
+
+**Signature**:
+```bash
+post_to_api()
+```
+
+**Parameters**: None (uses global environment variables)
+
+**Returns**: No explicit return value (curl result stored in RESPONSE if diagnostics enabled)
+
+**Requirements** (Silent fail if not met):
+- `curl` command available
+- `DIAGNOSTICS="yes"`
+- `RANDOM_UUID` is set
+- Executed on Proxmox host (has access to `pveversion`)
+
+**Environment Variables Used**:
+- `CT_TYPE` - Container type (privileged=1, unprivileged=0)
+- `DISK_SIZE` - Allocated disk in GB
+- `CORE_COUNT` - CPU core count
+- `RAM_SIZE` - RAM allocated in MB
+- `var_os` - Operating system name
+- `var_version` - OS version
+- `NSAPP` - Normalized application name
+- `METHOD` - Installation method (default, template, etc.)
+- `DIAGNOSTICS` - Enable telemetry (yes/no)
+- `RANDOM_UUID` - Session UUID for tracking
+
+**API Endpoint**: `http://api.community-scripts.org/dev/upload`
+
+**Payload Structure**:
+```json
+{
+ "ct_type": 1, // Privileged (1) or Unprivileged (0)
+ "type": "lxc", // Always "lxc" for containers
+ "disk_size": 8, // GB
+ "core_count": 2, // CPU cores
+ "ram_size": 2048, // MB
+ "os_type": "debian", // OS name
+ "os_version": "12", // OS version
+ "nsapp": "myapp", // Application name
+ "method": "default", // Setup method
+ "pve_version": "8.2.2", // Proxmox VE version
+ "status": "installing", // Current status
+ "random_id": "550e8400-e29b" // Session UUID (anonymous)
+}
+```
+
+**Usage Examples**:
+
+```bash
+# Example 1: Successful API post
+CT_TYPE=1
+DISK_SIZE=20
+CORE_COUNT=4
+RAM_SIZE=4096
+var_os="ubuntu"
+var_version="22.04"
+NSAPP="jellyfin"
+METHOD="default"
+DIAGNOSTICS="yes"
+RANDOM_UUID="550e8400-e29b-41d4-a716-446655440000"
+
+post_to_api
+# Result: Statistics sent to API (silently, no output)
+
+# Example 2: Diagnostics disabled (opt-out)
+DIAGNOSTICS="no"
+post_to_api
+# Result: Function returns immediately, no API call
+
+# Example 3: Missing curl
+DIAGNOSTICS="yes"
+# curl not available in PATH
+post_to_api
+# Result: Function returns silently (curl requirement not met)
+```
+
+---
+
+### `post_to_api_vm()`
+
+**Purpose**: Sends VM creation statistics to Community-Scripts API (similar to post_to_api but for virtual machines).
+
+**Signature**:
+```bash
+post_to_api_vm()
+```
+
+**Parameters**: None (uses global environment variables)
+
+**Returns**: No explicit return value
+
+**Requirements**: Same as `post_to_api()`
+
+**Environment Variables Used**:
+- `VMID` - Virtual machine ID
+- `VM_TYPE` - VM type (kvm, etc.)
+- `VM_CORES` - CPU core count
+- `VM_RAM` - RAM in MB
+- `VM_DISK` - Disk in GB
+- `VM_OS` - Operating system
+- `VM_VERSION` - OS version
+- `VM_APP` - Application name
+- `DIAGNOSTICS` - Enable telemetry
+- `RANDOM_UUID` - Session UUID
+
+**Payload Structure** (similar to containers but for VMs):
+```json
+{
+ "vm_id": 100,
+ "type": "qemu",
+ "vm_cores": 4,
+ "vm_ram": 4096,
+ "vm_disk": 20,
+ "vm_os": "ubuntu",
+ "vm_version": "22.04",
+ "vm_app": "jellyfin",
+ "pve_version": "8.2.2",
+ "status": "installing",
+ "random_id": "550e8400-e29b"
+}
+```
+
+---
+
+### `post_update_to_api()`
+
+**Purpose**: Reports installation completion status (success/failure) for container or VM.
+
+**Signature**:
+```bash
+post_update_to_api()
+```
+
+**Parameters**: None (uses global environment variables)
+
+**Returns**: No explicit return value
+
+**Requirements**: Same as `post_to_api()`
+
+**Environment Variables Used**:
+- `RANDOM_UUID` - Session UUID (must match initial post_to_api call)
+- `DIAGNOSTICS` - Enable telemetry
+- Installation status parameters
+
+**Payload Structure**:
+```json
+{
+ "status": "completed", // "completed" or "failed"
+ "random_id": "550e8400-e29b", // Session UUID
+ "exit_code": 0, // 0 for success, error code for failure
+ "error_explanation": "" // Error description if failed
+}
+```
+
+---
+
+## API Payload Structure
+
+### Container Creation Payload
+
+```json
+{
+ "ct_type": 1, // 1=Privileged, 0=Unprivileged
+ "type": "lxc", // Always "lxc"
+ "disk_size": 20, // GB
+ "core_count": 4, // CPU cores
+ "ram_size": 4096, // MB
+ "os_type": "debian", // Distribution name
+ "os_version": "12", // Version number
+ "nsapp": "jellyfin", // Application name
+ "method": "default", // Setup method
+ "pve_version": "8.2.2", // Proxmox VE version
+ "status": "installing", // Current phase
+ "random_id": "550e8400" // Unique session ID
+}
+```
+
+### VM Creation Payload
+
+```json
+{
+ "vm_id": 100,
+ "type": "qemu",
+ "vm_cores": 4,
+ "vm_ram": 4096,
+ "vm_disk": 20,
+ "vm_os": "ubuntu",
+ "vm_version": "22.04",
+ "vm_app": "jellyfin",
+ "pve_version": "8.2.2",
+ "status": "installing",
+ "random_id": "550e8400"
+}
+```
+
+### Update/Completion Payload
+
+```json
+{
+ "status": "completed",
+ "random_id": "550e8400",
+ "exit_code": 0,
+ "error_explanation": ""
+}
+```
+
+---
+
+## Privacy & Opt-Out
+
+### Privacy Policy
+
+Community-Scripts telemetry is designed to be **privacy-respecting**:
+
+- β
**Anonymous**: No personal data collected
+- β
**Session-based**: UUID allows correlation without identification
+- β
**Aggregated**: Only statistics are stored, never raw logs
+- β
**Opt-out capable**: Single environment variable disables all telemetry
+- β
**No tracking**: UUID cannot be linked to user identity
+- β
**No credentials**: Passwords, SSH keys never transmitted
+
+### Opt-Out Methods
+
+**Method 1: Environment Variable (Single Script)**
+
+```bash
+DIAGNOSTICS="no" bash ct/myapp.sh
+```
+
+**Method 2: Script Header (Persistent)**
+
+```bash
+#!/bin/bash
+export DIAGNOSTICS="no"
+# Rest of script continues without telemetry
+```
+
+**Method 3: System-wide Configuration**
+
+```bash
+# In /etc/environment or ~/.bashrc
+export DIAGNOSTICS="no"
+```
+
+### What Data Is Collected
+
+| Data | Why | Shared? |
+|------|-----|---------|
+| Container/VM specs (cores, RAM, disk) | Understand deployment patterns | Yes, aggregated |
+| OS type/version | Track popular distributions | Yes, aggregated |
+| Application name | Understand popular apps | Yes, aggregated |
+| Method (standard vs. custom) | Measure feature usage | Yes, aggregated |
+| Success/failure status | Identify issues | Yes, aggregated |
+| Exit codes | Debug failures | Yes, anonymized |
+
+### What Data Is NOT Collected
+
+- β Container/VM hostnames
+- β IP addresses
+- β User credentials
+- β SSH keys or secrets
+- β Application data
+- β System logs
+- β Any personal information
+
+---
+
+## Error Mapping
+
+### Mapping Strategy
+
+Exit codes are categorized by source:
+
+```
+Exit Code Range | Source | Handling
+0 | Success | Not reported to API
+1-2 | Shell/Script | Generic error
+100-101, 255 | Package managers | APT/DPKG specific
+126-128 | Command execution | Permission/not found
+130, 143 | Signals | User interrupt/termination
+137, 139 | Kernel | OOM/segfault
+200-231 | Proxmox custom | Container creation issues
+210-212 | Python | Python environment issues
+231-234 | PostgreSQL | Database connection issues
+241-244 | MySQL/MariaDB | Database connection issues
+243-249, 254 | Node.js/npm | Runtime errors
+251-254 | MongoDB | Database connection issues
+```
+
+### Custom Exit Code Usage
+
+Scripts can define custom exit codes:
+
+```bash
+# Example: Custom validation failure
+if [[ "$CTID" -lt 100 ]]; then
+ echo "Container ID must be >= 100"
+ exit 205 # Custom Proxmox code
+fi
+```
+
+---
+
+## Best Practices
+
+### 1. **Always Initialize RANDOM_UUID**
+
+```bash
+# Generate unique session ID for tracking
+RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
+
+# Use first 8 chars for short session ID (logs)
+SESSION_ID="${RANDOM_UUID:0:8}"
+BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log"
+```
+
+### 2. **Call post_to_api Early**
+
+```bash
+# Call post_to_api right after container creation starts
+# This tracks attempt, even if installation fails
+
+variables() {
+ RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
+ # ... other variables ...
+}
+
+# Later, in main script:
+post_to_api # Report container creation started
+# ... perform installation ...
+post_update_to_api # Report completion
+```
+
+### 3. **Handle Graceful Failures**
+
+```bash
+# Wrap API calls to handle network issues
+if command -v curl &>/dev/null; then
+ post_to_api || true # Don't fail if API unavailable
+else
+ msg_warn "curl not available, telemetry skipped"
+fi
+```
+
+### 4. **Respect User Opt-Out**
+
+```bash
+# Check DIAGNOSTICS early and skip all API calls if disabled
+if [[ "${DIAGNOSTICS}" != "yes" ]]; then
+ msg_info "Anonymous diagnostics disabled"
+ return 0 # Skip telemetry
+fi
+```
+
+### 5. **Maintain Session Consistency**
+
+```bash
+# Use same RANDOM_UUID throughout lifecycle
+RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
+
+post_to_api # Initial report
+# ... installation ...
+post_update_to_api # Final report (same UUID links them)
+```
+
+---
+
+## API Integration
+
+### Connecting to API
+
+The API endpoint is:
+
+```
+http://api.community-scripts.org/dev/upload
+```
+
+### API Response Handling
+
+```bash
+# Capture HTTP response code
+RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" \
+ -H "Content-Type: application/json" \
+ -d "$JSON_PAYLOAD") || true
+
+# Extract status code (last 3 digits)
+HTTP_CODE="${RESPONSE: -3}"
+
+if [[ "$HTTP_CODE" == "200" ]]; then
+ msg_ok "Telemetry submitted successfully"
+elif [[ "$HTTP_CODE" == "429" ]]; then
+ msg_warn "API rate limited, skipping telemetry"
+else
+ msg_info "Telemetry API unreachable (this is OK)"
+fi
+```
+
+### Network Resilience
+
+API calls are **best-effort** and never block installation:
+
+```bash
+# Telemetry should never cause container creation to fail
+if post_to_api 2>/dev/null; then
+ msg_info "Diagnostics transmitted"
+fi
+# If API unavailable, continue anyway
+```
+
+---
+
+## Contributing
+
+### Adding New Exit Codes
+
+1. Document in the appropriate category section
+2. Update `explain_exit_code()` in both api.func and error_handler.func
+3. Add recovery suggestions
+4. Test mapping with scripts that use the new code
+
+### Testing API Integration
+
+```bash
+# Test with mock curl (local testing)
+DIAGNOSTICS="yes"
+RANDOM_UUID="test-uuid-12345678"
+curl -X POST http://localhost:8000/dev/upload \
+ -H "Content-Type: application/json" \
+ -d '{"test": "payload"}'
+
+# Verify payload structure
+post_to_api 2>&1 | head -20
+```
+
+### Telemetry Reporting Improvements
+
+Suggestions for improvement:
+
+1. Installation duration tracking
+2. Package version compatibility data
+3. Feature usage analytics
+4. Performance metrics
+5. Custom error codes
+
+---
+
+## Notes
+
+- API calls are **silent by default** and never display sensitive information
+- Telemetry can be **completely disabled** via `DIAGNOSTICS="no"`
+- **RANDOM_UUID must be generated** before calling any post functions
+- Exit code mappings are **shared** between api.func and error_handler.func for consistency
+- API is **optional** - containers work perfectly without telemetry
+