{
  "_comment": [
    "The module registry: what each edition installs, and what can be added or",
    "removed afterwards. Read by hitechcloud-rustcli (`module`), by the",
    "installer, and by both panels. See website/docs/architecture/editions-and-modules.md.",
    "",
    "edition    community = installed on every server; enterprise = only on a",
    "           licensed one. This decides which *services exist*. Which",
    "           *features* an edition unlocks is the compiled list in",
    "           hitechcloudpanel/internal/core/licence/features.go, which is",
    "           pinned against hitechadmin/config/features.json by a test.",
    "components names `install` already understands (its --with values).",
    "units      systemd units the module owns; install/uninstall/repair act on",
    "           these, and status reads their live state and memory.",
    "detect     evidence the software is on the server when a unit and an",
    "           installed package are both silent about it - a program",
    "           installed from an archive rather than a package, a runtime",
    "           interpreter the distribution ships with no unit of its own, a",
    "           per-account unit file no single name in `units` could hold. An",
    "           entry starting with `/` is a path, taken literally or - with a",
    "           `*` in it - matched against a file name the way a shell glob",
    "           would (a different wildcard from `data`'s, which always stands",
    "           for a whole path component). Anything else is a command name,",
    "           resolved on PATH. Never a",
    "           customer-data path: an empty one proves nothing about whether",
    "           the module is there, which is what `data` is for instead.",
    "features   names from hitechadmin/config/features.json. Every feature the",
    "           published split marks enterprise belongs to exactly one module,",
    "           and a test fails when a new one has no home. A *Community*",
    "           feature may be carried by two modules where two things implement",
    "           it - `webmail` belongs to webmail-roundcube and to webmail,",
    "           because Roundcube and our own webmail both are one. A feature is",
    "           available when ANY module carrying it is installed, which is why",
    "           a licensed server running MailFlow offers webmail without having",
    "           Roundcube, and a Community server offers it with Roundcube alone.",
    "packages   distribution packages the module owns. uninstall removes only",
    "           the ones no other installed module also claims, and names the",
    "           ones it kept. A package that would take the server with it (an",
    "           interpreter the panel itself runs on) is deliberately absent.",
    "data       paths holding customer data. uninstall NEVER touches these.",
    "           --purge removes them only when the module has nothing in use.",
    "ram_mb     a published estimate of the resident memory the module's units",
    "           hold on a small server, so an operator can see what a removal",
    "           buys back before doing it. These are conservative figures for",
    "           the distribution defaults this panel installs - not measurements",
    "           of one particular host, and not a promise. `module status`",
    "           reports the live number from systemd's MemoryCurrent, so the",
    "           panel always shows what the server is actually using; the",
    "           estimate is only what the page offers before a module exists.",
    "removable  false for the core a server cannot run without, for modules",
    "           that install nothing (a licence gate over panel code), and",
    "           for real software this engine cannot yet uninstall safely.",
    "           Those appear in the list so an operator can see them, and",
    "           refuse install/uninstall with the reason. A module in the",
    "           third group is not core and not a licence gate - it is real",
    "           software that genuinely could be absent, so it MUST also",
    "           carry a `detect` entry: `is_installed` checks `detect` ahead",
    "           of the `removable: false` default (native/module.rs), and a",
    "           module with none reads `installed: true` unconditionally,",
    "           whether or not its installer ever ran. That was the bug in",
    "           `waf` and `container-stack` before this entry: both are",
    "           `removable: false` because their uninstall cannot yet be done",
    "           safely by the generic engine (see each module below for why,",
    "           in its own `_comment`-style note under `detect`), not because",
    "           either is part of every server the way PHP or MariaDB is.",
    "",
    "mail/webmail: a Community server runs Postfix, Dovecot, OpenDKIM and rspamd",
    "and offers Roundcube. Enterprise adds our own webmail (hitechcloud-webmail)",
    "beside it with the advanced mail features. An upgrade NEVER uninstalls",
    "webmail-roundcube: a customer who bookmarked Roundcube must keep it.",
    "",
    "webmail-roundcube's component is `roundcube`: the `roundcube` command installs",
    "Roundcube from the distribution's package where one is current, otherwise",
    "the project's own release archive verified by checksum, with its own",
    "MariaDB database, config.inc.php keyed with a DES key generated once per",
    "server, this server's own Dovecot and Postfix, a vhost on the mail",
    "hostname behind the front-end with the panel's certificate, and a",
    "PHP-FPM pool of its own. `module install`/`--edition` and a",
    "Community `install --with roundcube` (or `--with community`/`all`)",
    "all install it the same way, through `install`'s component",
    "dispatch. `remove` never drops the database; `--purge` refuses while",
    "any customer-data table still has rows in it."
  ],
  "modules": [
    {
      "name": "php",
      "title": "PHP",
      "edition": "community",
      "components": [],
      "units": [],
      "features": [
        "php",
        "php_ini",
        "php_options",
        "php_xray",
        "php_extensions"
      ],
      "packages": [],
      "data": [
        "/etc/hitechcloud/native/php"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": false
    },
    {
      "name": "mariadb",
      "title": "MariaDB",
      "edition": "community",
      "components": [
        "db"
      ],
      "units": [
        "mariadb"
      ],
      "features": [
        "mysql",
        "mysql_conf",
        "mysql_import",
        "remote_mysql",
        "phpmyadmin"
      ],
      "packages": [],
      "data": [
        "/var/lib/mysql"
      ],
      "ram_mb": 140,
      "requires": [],
      "removable": false
    },
    {
      "name": "redis",
      "title": "Redis",
      "edition": "community",
      "components": [
        "redis"
      ],
      "units": [
        "redis",
        "redis-server"
      ],
      "features": [
        "redis"
      ],
      "packages": [
        "redis-server",
        "redis"
      ],
      "data": [
        "/var/lib/redis"
      ],
      "ram_mb": 12,
      "requires": [],
      "removable": true
    },
    {
      "name": "valkey",
      "title": "Valkey",
      "edition": "community",
      "components": [
        "valkey"
      ],
      "units": [
        "valkey"
      ],
      "features": [
        "valkey"
      ],
      "packages": [
        "valkey",
        "valkey-server"
      ],
      "data": [
        "/var/lib/valkey"
      ],
      "ram_mb": 12,
      "requires": [],
      "removable": true
    },
    {
      "name": "memcached",
      "title": "Memcached",
      "edition": "community",
      "components": [
        "memcached"
      ],
      "units": [
        "memcached"
      ],
      "features": [
        "memcached"
      ],
      "packages": [
        "memcached"
      ],
      "data": [],
      "ram_mb": 64,
      "requires": [],
      "removable": true
    },
    {
      "name": "goaccess",
      "title": "Visitor statistics",
      "edition": "community",
      "components": [
        "goaccess"
      ],
      "units": [],
      "features": [
        "goaccess"
      ],
      "packages": [
        "goaccess"
      ],
      "data": [
        "/var/lib/hitechcloud/goaccess"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": true
    },
    {
      "name": "acme",
      "title": "Certificate client",
      "edition": "community",
      "components": [
        "acme"
      ],
      "units": [],
      "features": [
        "ssl",
        "ssl_generate",
        "ssl_install",
        "ssl_storage",
        "ssl_hosts",
        "ssl_tools"
      ],
      "packages": [],
      "data": [
        "/etc/hitechcloud/ssl",
        "/root/.acme.sh"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": false
    },
    {
      "name": "firewall",
      "title": "Firewall",
      "edition": "community",
      "components": [
        "firewall"
      ],
      "units": [
        "csf",
        "lfd"
      ],
      "features": [],
      "packages": [],
      "data": [
        "/etc/csf"
      ],
      "ram_mb": 40,
      "requires": [],
      "removable": true
    },
    {
      "name": "fail2ban",
      "title": "Fail2ban",
      "edition": "community",
      "components": [
        "fail2ban"
      ],
      "units": [
        "fail2ban"
      ],
      "features": [],
      "packages": [
        "fail2ban"
      ],
      "data": [
        "/var/lib/fail2ban"
      ],
      "ram_mb": 30,
      "requires": [],
      "removable": true
    },
    {
      "name": "mail",
      "title": "Email hosting",
      "edition": "community",
      "components": [
        "mail",
        "rspamd"
      ],
      "units": [
        "postfix",
        "dovecot",
        "rspamd",
        "opendkim"
      ],
      "features": [
        "emails",
        "email_aliases",
        "email_forwarders",
        "mail_log",
        "mail_trust"
      ],
      "packages": [
        "postfix",
        "dovecot-core",
        "dovecot-imapd",
        "dovecot-pop3d",
        "dovecot-lmtpd",
        "dovecot-sieve",
        "dovecot-managesieved",
        "dovecot",
        "opendkim",
        "opendkim-tools",
        "rspamd"
      ],
      "data": [
        "/etc/hitechcloud/mail",
        "/home/*/mail"
      ],
      "ram_mb": 420,
      "requires": [],
      "removable": true
    },
    {
      "name": "webmail-roundcube",
      "title": "Roundcube webmail",
      "edition": "community",
      "default_install": false,
      "components": [
        "roundcube"
      ],
      "units": [],
      "detect": [
        "/usr/share/roundcube/index.php",
        "/usr/share/roundcubemail/index.php",
        "/usr/share/hitechcloud/roundcube/index.php"
      ],
      "features": [
        "webmail"
      ],
      "packages": [
        "roundcube-core",
        "roundcube-mysql",
        "roundcube-plugins",
        "roundcubemail",
        "roundcubemail-mysql"
      ],
      "data": [
        "/etc/hitechcloud/native/roundcube",
        "/var/lib/roundcube"
      ],
      "ram_mb": 40,
      "requires": [
        "mail"
      ],
      "removable": true
    },
    {
      "name": "webmail",
      "title": "Webmail and advanced email",
      "edition": "enterprise",
      "components": [
        "webmail"
      ],
      "units": [
        "hitechcloud-webmail"
      ],
      "features": [
        "webmail",
        "dav_configure",
        "dav_manage",
        "dav_sharing",
        "email_autoresponder",
        "email_blocklist",
        "email_default",
        "email_deliverability",
        "email_disk_usage",
        "email_export",
        "email_filters",
        "email_greylisting",
        "email_import",
        "email_spam_filter",
        "spam_quarantine"
      ],
      "packages": [],
      "data": [
        "/etc/hitechcloud/native/webmail"
      ],
      "ram_mb": 180,
      "requires": [
        "mail"
      ],
      "removable": true
    },
    {
      "name": "ftp",
      "title": "FTP",
      "edition": "community",
      "components": [
        "ftp"
      ],
      "units": [
        "pure-ftpd"
      ],
      "features": [
        "ftp"
      ],
      "packages": [
        "pure-ftpd"
      ],
      "data": [
        "/etc/hitechcloud/ftp"
      ],
      "ram_mb": 20,
      "requires": [],
      "removable": true
    },
    {
      "name": "dns",
      "title": "Authoritative DNS",
      "edition": "enterprise",
      "components": [
        "dns"
      ],
      "units": [
        "named",
        "bind9"
      ],
      "features": [
        "dns",
        "dns_zones",
        "dnssec",
        "dynamic_dns",
        "bimi"
      ],
      "packages": [
        "bind9",
        "bind9-utils",
        "bind",
        "bind-utils"
      ],
      "data": [
        "/etc/hitechcloud/native/bind"
      ],
      "ram_mb": 70,
      "requires": [],
      "removable": true
    },
    {
      "name": "postgresql",
      "title": "PostgreSQL",
      "edition": "enterprise",
      "components": [
        "postgres"
      ],
      "units": [
        "postgresql"
      ],
      "features": [
        "postgresql",
        "postgresql_conf",
        "postgresql_import",
        "remote_postgresql"
      ],
      "packages": [
        "postgresql",
        "postgresql-contrib",
        "postgresql-server"
      ],
      "data": [
        "/var/lib/pgsql",
        "/var/lib/postgresql"
      ],
      "ram_mb": 120,
      "requires": [],
      "removable": true
    },
    {
      "name": "pgadmin",
      "title": "pgAdmin",
      "edition": "enterprise",
      "components": [
        "pgadmin"
      ],
      "units": [
        "hitechcloud-pgadmin"
      ],
      "features": [
        "pgadmin"
      ],
      "packages": [
        "pgadmin4-web",
        "pgadmin4"
      ],
      "data": [
        "/var/lib/pgadmin"
      ],
      "ram_mb": 150,
      "requires": [
        "postgresql"
      ],
      "removable": true
    },
    {
      "name": "mongodb",
      "title": "MongoDB",
      "edition": "enterprise",
      "components": [
        "mongodb"
      ],
      "units": [
        "mongod"
      ],
      "features": [
        "mongodb"
      ],
      "packages": [
        "mongodb-org"
      ],
      "data": [
        "/var/lib/mongo",
        "/var/lib/mongodb"
      ],
      "ram_mb": 200,
      "requires": [],
      "removable": true
    },
    {
      "name": "mssql",
      "title": "Microsoft SQL Server",
      "edition": "enterprise",
      "components": [
        "mssql"
      ],
      "units": [
        "mssql-server"
      ],
      "features": [],
      "packages": [
        "mssql-server"
      ],
      "data": [
        "/var/opt/mssql"
      ],
      "ram_mb": 900,
      "requires": [],
      "removable": true
    },
    {
      "name": "clamav",
      "title": "Malware scanner",
      "edition": "community",
      "default_install": false,
      "components": [
        "clamav"
      ],
      "units": [
        "clamav-daemon",
        "clamd@scan",
        "clamav-freshclam",
        "freshclam"
      ],
      "features": [
        "malware_scan"
      ],
      "packages": [
        "clamav",
        "clamav-daemon",
        "clamav-freshclam",
        "clamav-update",
        "clamd"
      ],
      "data": [
        "/var/lib/clamav",
        "/var/lib/hitechcloud/malwarescan"
      ],
      "ram_mb": 800,
      "requires": [],
      "removable": true
    },
    {
      "name": "varnish",
      "title": "Varnish cache",
      "edition": "enterprise",
      "components": [
        "varnish"
      ],
      "units": [
        "varnish"
      ],
      "features": [
        "varnish"
      ],
      "packages": [
        "varnish"
      ],
      "data": [
        "/etc/hitechcloud/native/varnish"
      ],
      "ram_mb": 110,
      "requires": [],
      "removable": true
    },
    {
      "name": "search",
      "title": "Search engine",
      "edition": "enterprise",
      "components": [
        "opensearch"
      ],
      "units": [
        "opensearch",
        "elasticsearch"
      ],
      "features": [
        "opensearch",
        "elasticsearch"
      ],
      "packages": [
        "opensearch",
        "elasticsearch"
      ],
      "data": [
        "/var/lib/opensearch",
        "/var/lib/elasticsearch"
      ],
      "ram_mb": 1024,
      "requires": [],
      "removable": true
    },
    {
      "name": "litespeed-enterprise",
      "title": "LiteSpeed Enterprise",
      "edition": "enterprise",
      "components": [],
      "units": [
        "lshttpd"
      ],
      "features": [],
      "packages": [],
      "data": [
        "/usr/local/lsws/conf"
      ],
      "ram_mb": 120,
      "requires": [],
      "removable": true
    },
    {
      "name": "runtime-nodejs",
      "title": "Node.js applications",
      "edition": "enterprise",
      "components": [
        "node"
      ],
      "units": [],
      "detect": [
        "node"
      ],
      "features": [
        "nodejs",
        "pm2"
      ],
      "packages": [
        "nodejs"
      ],
      "data": [
        "/opt/hitechcloud/runtimes/node"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": true
    },
    {
      "name": "runtime-python",
      "title": "Python applications",
      "edition": "enterprise",
      "components": [
        "python"
      ],
      "units": [],
      "detect": [
        "python3"
      ],
      "features": [
        "python"
      ],
      "packages": [],
      "data": [
        "/opt/hitechcloud/runtimes/python"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": true
    },
    {
      "name": "runtime-ruby",
      "title": "Ruby applications",
      "edition": "enterprise",
      "components": [
        "ruby"
      ],
      "units": [],
      "detect": [
        "ruby"
      ],
      "features": [
        "ruby"
      ],
      "packages": [],
      "data": [
        "/opt/hitechcloud/runtimes/ruby"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": true
    },
    {
      "name": "runtime-java",
      "title": "Java applications",
      "edition": "enterprise",
      "components": [
        "java"
      ],
      "units": [],
      "detect": [
        "java"
      ],
      "features": [
        "java"
      ],
      "packages": [],
      "data": [
        "/opt/hitechcloud/runtimes/java"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": true
    },
    {
      "name": "runtime-dotnet",
      "title": ".NET applications",
      "edition": "enterprise",
      "components": [
        "dotnet"
      ],
      "units": [],
      "detect": [
        "dotnet"
      ],
      "features": [
        "dotnet"
      ],
      "packages": [],
      "data": [
        "/opt/hitechcloud/runtimes/dotnet"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": true
    },
    {
      "name": "n8n",
      "title": "n8n workflow automation",
      "edition": "enterprise",
      "components": [],
      "units": [],
      "detect": [
        "/etc/systemd/system/hitechcloud-n8n@*.service",
        "/var/lib/hitechcloud/installed/n8n"
      ],
      "features": [
        "n8n"
      ],
      "packages": [],
      "data": [
        "/home/*/.n8n",
        "/home/*/.n8n-app"
      ],
      "ram_mb": 0,
      "requires": [
        "runtime-nodejs"
      ],
      "removable": true
    },
    {
      "_comment": [
        "removable: false, but not because this is core the way PHP or MariaDB",
        "is - hitechcloud-waf is real software with its own systemd unit and",
        "binary, installed by deploy/install-waf.sh (dispatched here through",
        "`install`'s `components`/`--with waf`, and by `module`'s",
        "own install path once this module is licensed). It stays non-",
        "removable because its unit file is not package-managed: the generic",
        "uninstall engine can `disable --now` it, but `mask` refuses to",
        "overwrite a real regular unit file without --force, so systemd never",
        "forgets the unit and `is_installed` would keep reading it as present",
        "after a supposedly-successful uninstall - the exact 'reported a",
        "removal that touched nothing' failure this round of work exists to",
        "avoid. `detect` is the binary path instead, so `is_installed` still",
        "tells the truth about whether the firewall is actually here.",
        "Uninstalling would also not be destructive if it were wired - the",
        "front-end serves every site directly if the service stops, ",
        "unprotected but up (see deploy/install-waf.sh) - so a future change",
        "that adds a real uninstall (stop, unmask by deleting the unit file,",
        "remove the binary) can flip this to removable: true once it exists;",
        "until then this stays false rather than promising a removal the",
        "engine cannot perform."
      ],
      "name": "waf",
      "title": "Web Application Firewall",
      "edition": "enterprise",
      "components": [
        "waf"
      ],
      "units": [
        "hitechcloud-waf"
      ],
      "detect": [
        "/usr/local/bin/hitechcloudwaf"
      ],
      "features": [
        "waf"
      ],
      "packages": [],
      "data": [
        "/etc/hitechcloud/waf"
      ],
      "ram_mb": 0,
      "requires": [],
      "removable": false
    },
    {
      "name": "panel-advanced",
      "title": "Advanced panel features",
      "edition": "enterprise",
      "components": [],
      "units": [],
      "features": [
        "api",
        "mcp",
        "passkeys",
        "terminal",
        "trash",
        "redirects",
        "temporary_links",
        "ip_blocker",
        "disk_usage",
        "inodes",
        "capitalize_domains",
        "domain_suspend",
        "edit_vhost"
      ],
      "packages": [],
      "data": [],
      "ram_mb": 0,
      "requires": [],
      "removable": false
    },
    {
      "_comment": [
        "removable: false for a different reason than waf: Podman itself is a",
        "genuine distribution package and `usercontainers` (native/docker.rs) can",
        "already install and uninstall it safely on its own - `usercontainers",
        "uninstall [--purge]` disables every account's rootless instance",
        "first, then only removes the podman/podman-compose packages, and",
        "does not touch a customer's containers (they live under each",
        "account's own home directory, never in a distribution package).",
        "What this generic engine cannot do is that per-account walk: its",
        "uninstall only stops `units` and removes `packages`, with no hook to",
        "run `usercontainers`'s own disable-every-account step first, so a bare",
        "`module uninstall container-stack` would remove the packages",
        "out from under any account still using them rather than gracefully",
        "disabling first. That is a real, if recoverable, break - not a data",
        "loss - but it is still worse than the honest 'not removable here,",
        "use hitechcloudcli usercontainers uninstall' this stays as. Install is",
        "wired to the real installer (`components`, below); a future change",
        "that gives this engine a per-module uninstall hook (mirroring",
        "install_extra) can flip this to removable: true and call",
        "`usercontainers`'s own uninstall through it. `detect` is the bare",
        "command `podman`, resolved on PATH exactly the way `usercontainers`'s",
        "own podman_installed() already checks it, so the two can never read",
        "two different answers from the same server."
      ],
      "name": "container-stack",
      "title": "Container stack",
      "edition": "enterprise",
      "components": [
        "docker"
      ],
      "units": [],
      "detect": [
        "podman"
      ],
      "features": [
        "docker",
        "change_db",
        "change_image",
        "change_ws"
      ],
      "packages": [],
      "data": [],
      "ram_mb": 0,
      "requires": [],
      "removable": false
    }
  ]
}
