diff --git a/docs/contribution/AI.md b/docs/contribution/AI.md index e69de29bb..8830fa4a9 100644 --- a/docs/contribution/AI.md +++ b/docs/contribution/AI.md @@ -0,0 +1,810 @@ +# 🤖 AI Contribution Guidelines for ProxmoxVE + +> **This documentation is intended for all AI assistants (GitHub Copilot, Claude, ChatGPT, etc.) contributing to this project.** + +## 🎯 Core Principles + +### 1. **Maximum Use of `tools.func` Functions** + +We have an extensive library of helper functions. **NEVER** implement your own solutions when a function already exists! + +### 2. **No Pointless Variables** + +Only create variables when they: + +- Are used multiple times +- Improve readability +- Are intended for configuration + +### 3. **Consistent Script Structure** + +All scripts follow an identical structure. Deviations are not acceptable. + +### 4. **Bare-Metal Installation** + +We do **NOT use Docker** for our installation scripts. All applications are installed directly on the system. + +--- + +## 📁 Script Types and Their Structure + +### CT Script (`ct/AppName.sh`) + +```bash +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: AuthorName (GitHubUsername) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://application-url.com + +APP="AppName" +var_tags="${var_tags:-tag1;tag2;tag3}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/appname ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "appname" "owner/repo"; then + msg_info "Stopping Service" + systemctl stop appname + msg_ok "Stopped Service" + + msg_info "Backing up Data" + cp -r /opt/appname/data /opt/appname_data_backup + msg_ok "Backed up Data" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" + + # Build steps... + + msg_info "Restoring Data" + cp -r /opt/appname_data_backup/. /opt/appname/data + rm -rf /opt/appname_data_backup + msg_ok "Restored Data" + + msg_info "Starting Service" + systemctl start appname + msg_ok "Started Service" + msg_ok "Updated successfully!" + 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}:PORT${CL}" +``` + +### Install Script (`install/AppName-install.sh`) + +```bash +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: AuthorName (GitHubUsername) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://application-url.com + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt-get install -y \ + dependency1 \ + dependency2 +msg_ok "Installed Dependencies" + +# Runtime Setup (ALWAYS use our functions!) +NODE_VERSION="22" setup_nodejs +# or +PG_VERSION="16" setup_postgresql +# or +setup_uv +# etc. + +fetch_and_deploy_gh_release "appname" "owner/repo" + +msg_info "Setting up Application" +cd /opt/appname +# Build/Setup Schritte... +msg_ok "Set up Application" + +msg_info "Creating Service" +cat </etc/systemd/system/appname.service +[Unit] +Description=AppName Service +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/appname +ExecStart=/path/to/executable +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now appname +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc +``` + +--- + +## 🔧 Available Helper Functions + +### Release Management + +| Function | Description | Example | +| ----------------------------- | ----------------------------------- | -------------------------------------------------- | +| `fetch_and_deploy_gh_release` | Fetches and installs GitHub Release | `fetch_and_deploy_gh_release "app" "owner/repo"` | +| `check_for_gh_release` | Checks for new version | `if check_for_gh_release "app" "owner/repo"; then` | + +**Modes for `fetch_and_deploy_gh_release`:** + +```bash +# Tarball/Source (Standard) +fetch_and_deploy_gh_release "appname" "owner/repo" + +# Binary (.deb) +fetch_and_deploy_gh_release "appname" "owner/repo" "binary" + +# Prebuilt Archive +fetch_and_deploy_gh_release "appname" "owner/repo" "prebuild" "latest" "/opt/appname" "filename.tar.gz" + +# Single Binary +fetch_and_deploy_gh_release "appname" "owner/repo" "singlefile" "latest" "/opt/appname" "binary-linux-amd64" +``` + +**Clean Install Flag:** + +```bash +CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" +``` + +### Runtime/Language Setup + +| Function | Variable(s) | Example | +| -------------- | ----------------------------- | ---------------------------------------------------- | +| `setup_nodejs` | `NODE_VERSION`, `NODE_MODULE` | `NODE_VERSION="22" setup_nodejs` | +| `setup_uv` | `UV_PYTHON` | `UV_PYTHON="3.12" setup_uv` | +| `setup_go` | `GO_VERSION` | `GO_VERSION="1.22" setup_go` | +| `setup_rust` | `RUST_VERSION`, `RUST_CRATES` | `RUST_CRATES="monolith" setup_rust` | +| `setup_ruby` | `RUBY_VERSION` | `RUBY_VERSION="3.3" setup_ruby` | +| `setup_java` | `JAVA_VERSION` | `JAVA_VERSION="21" setup_java` | +| `setup_php` | `PHP_VERSION`, `PHP_MODULES` | `PHP_VERSION="8.3" PHP_MODULES="redis,gd" setup_php` | + +### Database Setup + +| Function | Variable(s) | Example | +| --------------------- | ------------------------------------ | ----------------------------------------------------------- | +| `setup_postgresql` | `PG_VERSION`, `PG_MODULES` | `PG_VERSION="16" setup_postgresql` | +| `setup_postgresql_db` | `PG_DB_NAME`, `PG_DB_USER` | `PG_DB_NAME="mydb" PG_DB_USER="myuser" setup_postgresql_db` | +| `setup_mariadb_db` | `MARIADB_DB_NAME`, `MARIADB_DB_USER` | `MARIADB_DB_NAME="mydb" setup_mariadb_db` | +| `setup_mysql` | `MYSQL_VERSION` | `setup_mysql` | +| `setup_mongodb` | `MONGO_VERSION` | `setup_mongodb` | +| `setup_clickhouse` | - | `setup_clickhouse` | + +### Tools & Utilities + +| Function | Description | +| ------------------- | ---------------------------------- | +| `setup_adminer` | Installs Adminer for DB management | +| `setup_composer` | Install PHP Composer | +| `setup_ffmpeg` | Install FFmpeg | +| `setup_imagemagick` | Install ImageMagick | +| `setup_gs` | Install Ghostscript | +| `setup_hwaccel` | Configure hardware acceleration | + +### Helper Utilities + +| Function | Description | Example | +| ----------------------------- | ---------------------------- | ----------------------------------------- | +| `import_local_ip` | Sets `$LOCAL_IP` variable | `import_local_ip` | +| `ensure_dependencies` | Checks/installs dependencies | `ensure_dependencies curl jq` | +| `install_packages_with_retry` | APT install with retry | `install_packages_with_retry nginx redis` | + +--- + +## ❌ Anti-Patterns (NEVER use!) + +### 1. Pointless Variables + +```bash +# ❌ WRONG - unnecessary variables +APP_NAME="myapp" +APP_DIR="/opt/${APP_NAME}" +APP_USER="root" +APP_PORT="3000" +cd $APP_DIR + +# ✅ CORRECT - use directly +cd /opt/myapp +``` + +### 2. Custom Download Logic + +```bash +# ❌ WRONG - custom wget/curl logic +RELEASE=$(curl -s https://api.github.com/repos/owner/repo/releases/latest | jq -r '.tag_name') +wget https://github.com/owner/repo/archive/${RELEASE}.tar.gz +tar -xzf ${RELEASE}.tar.gz +mv repo-${RELEASE} /opt/myapp + +# ✅ CORRECT - use our function +fetch_and_deploy_gh_release "myapp" "owner/repo" +``` + +### 3. Custom Version-Check Logic + +```bash +# ❌ WRONG - custom version check +CURRENT=$(cat /opt/myapp/version.txt) +LATEST=$(curl -s https://api.github.com/repos/owner/repo/releases/latest | jq -r '.tag_name') +if [[ "$CURRENT" != "$LATEST" ]]; then + # update... +fi + +# ✅ CORRECT - use our function +if check_for_gh_release "myapp" "owner/repo"; then + # update... +fi +``` + +### 4. Docker-based Installation + +```bash +# ❌ WRONG - using Docker +docker pull myapp/myapp:latest +docker run -d --name myapp myapp/myapp:latest + +# ✅ CORRECT - Bare-Metal Installation +fetch_and_deploy_gh_release "myapp" "owner/repo" +npm install && npm run build +``` + +### 5. Custom Runtime Installation + +```bash +# ❌ WRONG - custom Node.js installation +curl -fsSL https://deb.nodesource.com/setup_22.x | bash - +apt install -y nodejs + +# ✅ CORRECT - use our function +NODE_VERSION="22" setup_nodejs +``` + +### 6. Redundant echo Statements + +```bash +# ❌ WRONG - custom logging messages +echo "Installing dependencies..." +apt install -y curl +echo "Done!" + +# ✅ CORRECT - use msg_info/msg_ok +msg_info "Installing Dependencies" +$STD apt install -y curl +msg_ok "Installed Dependencies" +``` + +### 7. Missing $STD Usage + +```bash +# ❌ WRONG - apt without $STD +apt install -y nginx + +# ✅ CORRECT - with $STD for silent output +$STD apt install -y nginx +``` + +### 8. Wrapping `tools.func` Functions in msg Blocks + +```bash +# ❌ WRONG - tools.func functions have their own msg_info/msg_ok! +msg_info "Installing Node.js" +NODE_VERSION="22" setup_nodejs +msg_ok "Installed Node.js" + +msg_info "Updating Application" +CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" +msg_ok "Updated Application" + +# ✅ CORRECT - call directly without msg wrapper +NODE_VERSION="22" setup_nodejs + +CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" +``` + +**Functions with built-in messages (NEVER wrap in msg blocks):** + +- `fetch_and_deploy_gh_release` +- `check_for_gh_release` +- `setup_nodejs` +- `setup_postgresql` / `setup_postgresql_db` +- `setup_mariadb` / `setup_mariadb_db` +- `setup_mongodb` +- `setup_mysql` +- `setup_ruby` +- `setup_go` +- `setup_java` +- `setup_php` +- `setup_uv` +- `setup_rust` +- `setup_composer` +- `setup_ffmpeg` +- `setup_imagemagick` +- `setup_gs` +- `setup_adminer` +- `setup_hwaccel` + +### 9. Creating Unnecessary System Users + +```bash +# ❌ WRONG - LXC containers run as root, no separate user needed +useradd -m -s /usr/bin/bash appuser +chown -R appuser:appuser /opt/appname +sudo -u appuser npm install + +# ✅ CORRECT - run directly as root +cd /opt/appname +$STD npm install +``` + +### 10. Using `export` in .env Files + +```bash +# ❌ WRONG - export is unnecessary in .env files +cat </opt/appname/.env +export DATABASE_URL=postgres://... +export SECRET_KEY=abc123 +export NODE_ENV=production +EOF + +# ✅ CORRECT - simple KEY=VALUE format (files are sourced with set -a) +cat </opt/appname/.env +DATABASE_URL=postgres://... +SECRET_KEY=abc123 +NODE_ENV=production +EOF +``` + +### 11. Using External Shell Scripts + +```bash +# ❌ WRONG - external script that gets executed +cat <<'EOF' >/opt/appname/install_script.sh +#!/bin/bash +cd /opt/appname +npm install +npm run build +EOF +chmod +x /opt/appname/install_script.sh +$STD bash /opt/appname/install_script.sh +rm -f /opt/appname/install_script.sh + +# ✅ CORRECT - run commands directly +cd /opt/appname +$STD npm install +$STD npm run build +``` + +### 12. Using `sudo` in LXC Containers + +```bash +# ❌ WRONG - sudo is unnecessary in LXC (already root) +sudo -u postgres psql -c "CREATE DATABASE mydb;" +sudo -u appuser npm install + +# ✅ CORRECT - use functions or run directly as root +PG_DB_NAME="mydb" PG_DB_USER="myuser" setup_postgresql_db + +cd /opt/appname +$STD npm install +``` + +### 13. Unnecessary `systemctl daemon-reload` + +```bash +# ❌ WRONG - daemon-reload is only needed when MODIFYING existing services +cat </etc/systemd/system/appname.service +# ... service config ... +EOF +systemctl daemon-reload # Unnecessary for new services! +systemctl enable -q --now appname + +# ✅ CORRECT - new services don't need daemon-reload +cat </etc/systemd/system/appname.service +# ... service config ... +EOF +systemctl enable -q --now appname +``` + +### 14. Creating Custom Credentials Files + +```bash +# ❌ WRONG - custom credentials file is not part of the standard template +msg_info "Saving Credentials" +cat <~/appname.creds +Database User: ${DB_USER} +Database Pass: ${DB_PASS} +EOF +msg_ok "Saved Credentials" + +# ✅ CORRECT - credentials are stored in .env or shown in final message only +# The .env file contains credentials, no need for separate file +``` + +### 15. Wrong Footer Pattern + +```bash +# ❌ WRONG - old cleanup pattern with msg blocks +motd_ssh +customize + +msg_info "Cleaning up" +$STD apt-get -y autoremove +$STD apt-get -y autoclean +msg_ok "Cleaned" + +# ✅ CORRECT - use cleanup_lxc function +motd_ssh +customize +cleanup_lxc +``` + +### 16. Manual Database Creation Instead of Functions + +```bash +# ❌ WRONG - manual database creation +DB_USER="myuser" +DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13) +$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';" +$STD sudo -u postgres psql -c "CREATE DATABASE mydb WITH OWNER $DB_USER;" +$STD sudo -u postgres psql -d mydb -c "CREATE EXTENSION IF NOT EXISTS postgis;" + +# ✅ CORRECT - use setup_postgresql_db function +# This sets PG_DB_USER, PG_DB_PASS, PG_DB_NAME automatically +PG_DB_NAME="mydb" PG_DB_USER="myuser" PG_DB_EXTENSIONS="postgis" setup_postgresql_db +``` + +### 17. Writing Files Without Heredocs + +```bash +# ❌ WRONG - echo / printf / tee +echo "# Config" > /opt/app/config.yml +echo "port: 3000" >> /opt/app/config.yml + +printf "# Config\nport: 3000\n" > /opt/app/config.yml +cat config.yml | tee /opt/app/config.yml +``` + +```bash +# ✅ CORRECT - always use a single heredoc +cat </opt/app/config.yml +# Config +port: 3000 +EOF +``` + +--- + +## 📝 Important Rules + +### Variable Declarations (CT Script) + +```bash +# Standard declarations (ALWAYS present) +APP="AppName" +var_tags="${var_tags:-tag1;tag2}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" +``` + +### Update-Script Pattern + +```bash +function update_script() { + header_info + check_container_storage + check_container_resources + + # 1. Check if installation exists + if [[ ! -d /opt/appname ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + # 2. Check for update + if check_for_gh_release "appname" "owner/repo"; then + # 3. Stop service + msg_info "Stopping Service" + systemctl stop appname + msg_ok "Stopped Service" + + # 4. Backup data (if present) + msg_info "Backing up Data" + cp -r /opt/appname/data /opt/appname_data_backup + msg_ok "Backed up Data" + + # 5. Perform clean install + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" + + # 6. Rebuild (if needed) + cd /opt/appname + $STD npm install + $STD npm run build + + # 7. Restore data + msg_info "Restoring Data" + cp -r /opt/appname_data_backup/. /opt/appname/data + rm -rf /opt/appname_data_backup + msg_ok "Restored Data" + + # 8. Start service + msg_info "Starting Service" + systemctl start appname + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit # IMPORTANT: Always end with exit! +} +``` + +### Systemd Service Pattern + +```bash +msg_info "Creating Service" +cat </etc/systemd/system/appname.service +[Unit] +Description=AppName Service +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/appname +Environment=NODE_ENV=production +ExecStart=/usr/bin/node /opt/appname/server.js +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now appname +msg_ok "Created Service" +``` + +### Installation Script Footer + +```bash +# ALWAYS at the end of the install script: +motd_ssh +customize +cleanup_lxc +``` + +--- + +## 🔍 Checklist Before PR Creation + +- [ ] No Docker installation used +- [ ] `fetch_and_deploy_gh_release` used for GitHub releases +- [ ] `check_for_gh_release` used for update checks +- [ ] `setup_*` functions used for runtimes (nodejs, postgresql, etc.) +- [ ] **`tools.func` functions NOT wrapped in msg_info/msg_ok blocks** +- [ ] No redundant variables +- [ ] `$STD` before all apt/npm/build commands +- [ ] `msg_info`/`msg_ok`/`msg_error` for logging (only for custom code) +- [ ] Correct script structure followed +- [ ] Update function present and functional +- [ ] Data backup implemented in update function +- [ ] `motd_ssh`, `customize`, `cleanup_lxc` at the end +- [ ] No custom download/version-check logic +- [ ] JSON metadata file created in `frontend/public/json/.json` + +--- + +## 📖 Reference: Good Example (Termix) + +### CT Script: [ct/termix.sh](../ct/termix.sh) + +- Uses `check_for_gh_release` for version checking +- Uses `CLEAN_INSTALL=1 fetch_and_deploy_gh_release` for clean updates +- Backup/restore of `/opt/termix/data` +- Correct structure with all required variables + +### Install Script: [install/termix-install.sh](../install/termix-install.sh) + +- `NODE_VERSION="22" setup_nodejs` instead of manual installation +- `fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix"` instead of wget/curl +- Clean service configuration +- Correct footer with `motd_ssh`, `customize`, `cleanup_lxc` + +--- + +## � JSON Metadata Files + +Every application requires a JSON metadata file in `frontend/public/json/.json`. + +### JSON Structure + +```json +{ + "name": "AppName", + "slug": "appname", + "categories": [1], + "date_created": "2026-01-16", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 3000, + "documentation": "https://docs.appname.com/", + "website": "https://appname.com/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/appname.webp", + "config_path": "/opt/appname/.env", + "description": "Short description of the application and its purpose.", + "install_methods": [ + { + "type": "default", + "script": "ct/appname.sh", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 8, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} +``` + +### Required Fields + +| Field | Type | Description | +| --------------------- | ------- | -------------------------------------------------- | +| `name` | string | Display name of the application | +| `slug` | string | Lowercase, no spaces, used for filenames | +| `categories` | array | Category ID(s) - see category list below | +| `date_created` | string | Creation date (YYYY-MM-DD) | +| `type` | string | `ct` for container, `vm` for virtual machine | +| `updateable` | boolean | Whether update_script is implemented | +| `privileged` | boolean | Whether container needs privileged mode | +| `interface_port` | number | Primary web interface port (or `null`) | +| `documentation` | string | Link to official docs | +| `website` | string | Link to official website | +| `logo` | string | URL to application logo (preferably selfhst icons) | +| `config_path` | string | Path to main config file (or empty string) | +| `description` | string | Brief description of the application | +| `install_methods` | array | Installation configurations | +| `default_credentials` | object | Default username/password (or null) | +| `notes` | array | Additional notes/warnings | + +### Categories + +| ID | Category | +| --- | ------------------------- | +| 0 | Miscellaneous | +| 1 | Proxmox & Virtualization | +| 2 | Operating Systems | +| 3 | Containers & Docker | +| 4 | Network & Firewall | +| 5 | Adblock & DNS | +| 6 | Authentication & Security | +| 7 | Backup & Recovery | +| 8 | Databases | +| 9 | Monitoring & Analytics | +| 10 | Dashboards & Frontends | +| 11 | Files & Downloads | +| 12 | Documents & Notes | +| 13 | Media & Streaming | +| 14 | \*Arr Suite | +| 15 | NVR & Cameras | +| 16 | IoT & Smart Home | +| 17 | ZigBee, Z-Wave & Matter | +| 18 | MQTT & Messaging | +| 19 | Automation & Scheduling | +| 20 | AI / Coding & Dev-Tools | +| 21 | Webservers & Proxies | +| 22 | Bots & ChatOps | +| 23 | Finance & Budgeting | +| 24 | Gaming & Leisure | +| 25 | Business & ERP | + +### Notes Format + +```json +"notes": [ + { + "text": "Change the default password after first login!", + "type": "warning" + }, + { + "text": "Requires at least 4GB RAM for optimal performance.", + "type": "info" + } +] +``` + +**Note types:** `info`, `warning`, `error` + +### Examples with Credentials + +```json +"default_credentials": { + "username": "admin", + "password": "admin" +} +``` + +Or no credentials: + +```json +"default_credentials": { + "username": null, + "password": null +} +``` + +--- + +## �💡 Tips for AI Assistants + +1. **Search `tools.func` first** before implementing custom solutions +2. **Use existing scripts as reference** (e.g., `linkwarden-install.sh`, `homarr-install.sh`) +3. **Ask when uncertain** instead of introducing wrong patterns +4. **Consistency > Creativity** - follow established patterns +5. **Test local variables** - use `${VAR:-default}` pattern for optional values + +--- + +## 📚 Further Documentation + +- [CONTRIBUTING.md](contribution/CONTRIBUTING.md) - General contribution guidelines +- [GUIDE.md](contribution/GUIDE.md) - Detailed developer documentation +- [TECHNICAL_REFERENCE.md](TECHNICAL_REFERENCE.md) - Technical details +- [EXIT_CODES.md](EXIT_CODES.md) - Exit code reference