Просмотр исходного кода

refactor: completely remove schema system and sorting - v0.1.3 fully self-contained

- Remove all schema-related code: module_specs, merged_specs, _validate_schema_version()
- Delete cli/core/schema/ and library/schemas/ directories completely
- Simplify template variable collection to use only template specs directly
- Remove section sorting - preserve order from template.yaml files
- Simplify _merge_specs() and _filter_specs_to_used() methods
- Remove all @property decorators for schema-related attributes
- All 70 templates now fully self-contained with explicit variable definitions
- Templates maintain schema: "1.2" property for backwards compatibility with old clients
- No functional impact - all tests passing, all modules working correctly
xcad 1 месяц назад
Родитель
Сommit
e64034c8f8

+ 0 - 4
cli/core/module/base_commands.py

@@ -220,9 +220,6 @@ def show_template(module_instance, id: str, var: list[str] | None = None, var_fi
         apply_var_file(template, var_file, module_instance.display)
         apply_cli_overrides(template, var)
 
-        # Re-sort sections after applying overrides (toggle values may have changed)
-        template.variables.sort_sections()
-
         # Reset disabled bool variables to False to prevent confusion
         reset_vars = template.variables.reset_disabled_bool_variables()
         if reset_vars:
@@ -391,7 +388,6 @@ def _prepare_template(
     apply_cli_overrides(template, var)
 
     if template.variables:
-        template.variables.sort_sections()
         reset_vars = template.variables.reset_disabled_bool_variables()
         if reset_vars:
             logger.debug(f"Reset {len(reset_vars)} disabled bool variables to False")

+ 0 - 17
cli/core/schema/__init__.py

@@ -1,17 +0,0 @@
-"""Schema loading and management for boilerplate modules."""
-
-from .loader import (
-    SchemaLoader,
-    get_loader,
-    has_schema,
-    list_versions,
-    load_schema,
-)
-
-__all__ = [
-    "SchemaLoader",
-    "get_loader",
-    "has_schema",
-    "list_versions",
-    "load_schema",
-]

+ 0 - 15
cli/core/schema/ansible/v1.0.json

@@ -1,15 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "target_hosts",
-        "description": "Target hosts",
-        "type": "str",
-        "required": true
-      }
-    ]
-  }
-]

+ 0 - 229
cli/core/schema/compose/v1.0.json

@@ -1,229 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "service_name",
-        "description": "Service name",
-        "type": "str"
-      },
-      {
-        "name": "container_name",
-        "description": "Container name",
-        "type": "str"
-      },
-      {
-        "name": "container_timezone",
-        "description": "Container timezone (e.g., Europe/Berlin)",
-        "type": "str",
-        "default": "UTC"
-      },
-      {
-        "name": "user_uid",
-        "description": "User UID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "user_gid",
-        "description": "User GID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "restart_policy",
-        "description": "Container restart policy",
-        "type": "enum",
-        "options": ["unless-stopped", "always", "on-failure", "no"],
-        "default": "unless-stopped"
-      }
-    ]
-  },
-  {
-    "key": "network",
-    "title": "Network",
-    "toggle": "network_enabled",
-    "vars": [
-      {
-        "name": "network_enabled",
-        "description": "Enable custom network block",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "network_name",
-        "description": "Docker network name",
-        "type": "str",
-        "default": "bridge"
-      },
-      {
-        "name": "network_external",
-        "description": "Use existing Docker network",
-        "type": "bool",
-        "default": true
-      }
-    ]
-  },
-  {
-    "key": "ports",
-    "title": "Ports",
-    "toggle": "ports_enabled",
-    "vars": [
-      {
-        "name": "ports_enabled",
-        "description": "Expose ports via 'ports' mapping",
-        "type": "bool",
-        "default": true
-      }
-    ]
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik reverse proxy integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_network",
-        "description": "Traefik network name",
-        "type": "str",
-        "default": "traefik"
-      },
-      {
-        "name": "traefik_host",
-        "description": "Domain name for your service (e.g., app.example.com)",
-        "type": "str"
-      },
-      {
-        "name": "traefik_entrypoint",
-        "description": "HTTP entrypoint (non-TLS)",
-        "type": "str",
-        "default": "web"
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": "traefik",
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_entrypoint",
-        "description": "TLS entrypoint",
-        "type": "str",
-        "default": "websecure"
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare"
-      }
-    ]
-  },
-  {
-    "key": "swarm",
-    "title": "Docker Swarm",
-    "toggle": "swarm_enabled",
-    "description": "Deploy service in Docker Swarm mode with replicas.",
-    "vars": [
-      {
-        "name": "swarm_enabled",
-        "description": "Enable Docker Swarm mode",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "swarm_replicas",
-        "description": "Number of replicas in Swarm",
-        "type": "int",
-        "default": 1
-      },
-      {
-        "name": "swarm_placement_mode",
-        "description": "Swarm placement mode",
-        "type": "enum",
-        "options": ["global", "replicated"],
-        "default": "replicated"
-      },
-      {
-        "name": "swarm_placement_host",
-        "description": "Limit placement to specific node",
-        "type": "str"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["postgres", "mysql"],
-        "default": "postgres"
-      },
-      {
-        "name": "database_external",
-        "description": "Use an external database server?",
-        "extra": "skips creation of internal database container",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "default": "database"
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int"
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str"
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str"
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "default": "",
-        "sensitive": true,
-        "autogenerated": true
-      }
-    ]
-  }
-]

+ 0 - 312
cli/core/schema/compose/v1.1.json

@@ -1,312 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "service_name",
-        "description": "Service name",
-        "type": "str"
-      },
-      {
-        "name": "container_name",
-        "description": "Container name",
-        "type": "str"
-      },
-      {
-        "name": "container_hostname",
-        "description": "Container internal hostname",
-        "type": "str"
-      },
-      {
-        "name": "container_timezone",
-        "description": "Container timezone (e.g., Europe/Berlin)",
-        "type": "str",
-        "default": "UTC"
-      },
-      {
-        "name": "user_uid",
-        "description": "User UID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "user_gid",
-        "description": "User GID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "container_loglevel",
-        "description": "Container log level",
-        "type": "enum",
-        "options": ["debug", "info", "warn", "error"],
-        "default": "info"
-      },
-      {
-        "name": "restart_policy",
-        "description": "Container restart policy",
-        "type": "enum",
-        "options": ["unless-stopped", "always", "on-failure", "no"],
-        "default": "unless-stopped"
-      }
-    ]
-  },
-  {
-    "key": "network",
-    "title": "Network",
-    "vars": [
-      {
-        "name": "network_mode",
-        "description": "Docker network mode",
-        "type": "enum",
-        "options": ["bridge", "host", "macvlan"],
-        "default": "bridge",
-        "extra": "bridge=default Docker networking, host=use host network stack, macvlan=dedicated MAC address on physical network"
-      },
-      {
-        "name": "network_name",
-        "description": "Docker network name",
-        "type": "str",
-        "default": "bridge",
-        "needs": "network_mode=bridge,macvlan"
-      },
-      {
-        "name": "network_external",
-        "description": "Use existing Docker network (external)",
-        "type": "bool",
-        "default": false,
-        "needs": "network_mode=bridge,macvlan"
-      },
-      {
-        "name": "network_macvlan_ipv4_address",
-        "description": "Static IP address for container",
-        "type": "str",
-        "default": "192.168.1.253",
-        "needs": "network_mode=macvlan"
-      },
-      {
-        "name": "network_macvlan_parent_interface",
-        "description": "Host network interface name",
-        "type": "str",
-        "default": "eth0",
-        "needs": "network_mode=macvlan"
-      },
-      {
-        "name": "network_macvlan_subnet",
-        "description": "Network subnet in CIDR notation",
-        "type": "str",
-        "default": "192.168.1.0/24",
-        "needs": "network_mode=macvlan"
-      },
-      {
-        "name": "network_macvlan_gateway",
-        "description": "Network gateway IP address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": "network_mode=macvlan"
-      }
-    ]
-  },
-  {
-    "key": "ports",
-    "title": "Ports",
-    "needs": "network_mode=bridge",
-    "vars": []
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "needs": "network_mode=bridge",
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik reverse proxy integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_network",
-        "description": "Traefik network name",
-        "type": "str",
-        "default": "traefik"
-      },
-      {
-        "name": "traefik_host",
-        "description": "Domain name for your service (e.g., app.example.com)",
-        "type": "str"
-      },
-      {
-        "name": "traefik_entrypoint",
-        "description": "HTTP entrypoint (non-TLS)",
-        "type": "str",
-        "default": "web"
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": "traefik_enabled=true;network_mode=bridge",
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_entrypoint",
-        "description": "TLS entrypoint",
-        "type": "str",
-        "default": "websecure"
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare"
-      }
-    ]
-  },
-  {
-    "key": "swarm",
-    "title": "Docker Swarm",
-    "toggle": "swarm_enabled",
-    "needs": "network_mode=bridge",
-    "description": "Deploy service in Docker Swarm mode.",
-    "vars": [
-      {
-        "name": "swarm_enabled",
-        "description": "Enable Docker Swarm mode",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "swarm_placement_mode",
-        "description": "Swarm placement mode",
-        "type": "enum",
-        "options": ["replicated", "global"],
-        "default": "replicated"
-      },
-      {
-        "name": "swarm_replicas",
-        "description": "Number of replicas",
-        "type": "int",
-        "default": 1,
-        "needs": "swarm_placement_mode=replicated"
-      },
-      {
-        "name": "swarm_placement_host",
-        "description": "Target hostname for placement constraint",
-        "type": "str",
-        "default": "",
-        "optional": true,
-        "needs": "swarm_placement_mode=replicated",
-        "extra": "Constrains service to run on specific node by hostname"
-      },
-      {
-        "name": "swarm_volume_mode",
-        "description": "Swarm volume storage backend",
-        "type": "enum",
-        "options": ["local", "mount", "nfs"],
-        "default": "local",
-        "extra": "WARNING: 'local' only works on single-node deployments!"
-      },
-      {
-        "name": "swarm_volume_mount_path",
-        "description": "Host path for bind mount",
-        "type": "str",
-        "default": "/mnt/storage",
-        "needs": "swarm_volume_mode=mount",
-        "extra": "Useful for shared/replicated storage"
-      },
-      {
-        "name": "swarm_volume_nfs_server",
-        "description": "NFS server address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": "swarm_volume_mode=nfs",
-        "extra": "IP address or hostname of NFS server"
-      },
-      {
-        "name": "swarm_volume_nfs_path",
-        "description": "NFS export path",
-        "type": "str",
-        "default": "/export",
-        "needs": "swarm_volume_mode=nfs",
-        "extra": "Path to NFS export on the server"
-      },
-      {
-        "name": "swarm_volume_nfs_options",
-        "description": "NFS mount options",
-        "type": "str",
-        "default": "rw,nolock,soft",
-        "needs": "swarm_volume_mode=nfs",
-        "extra": "Comma-separated NFS mount options"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["default", "sqlite", "postgres", "mysql"],
-        "default": "default"
-      },
-      {
-        "name": "database_external",
-        "description": "Use an external database server?",
-        "extra": "skips creation of internal database container",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "default": "database"
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int"
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str"
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str"
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "default": "",
-        "sensitive": true,
-        "autogenerated": true
-      }
-    ]
-  }
-]

+ 0 - 528
cli/core/schema/compose/v1.2.json

@@ -1,528 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "vars": [
-      {
-        "name": "service_name",
-        "description": "Service name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "container_name",
-        "description": "Container name",
-        "type": "str"
-      },
-      {
-        "name": "container_hostname",
-        "description": "Container internal hostname",
-        "type": "str"
-      },
-      {
-        "name": "container_timezone",
-        "description": "Container timezone (e.g., Europe/Berlin)",
-        "type": "str"
-      },
-      {
-        "name": "user_uid",
-        "description": "User UID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "user_gid",
-        "description": "User GID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "container_loglevel",
-        "description": "Container log level",
-        "type": "enum",
-        "options": ["debug", "info", "warn", "error"]
-      },
-      {
-        "name": "restart_policy",
-        "description": "Container restart policy",
-        "type": "enum",
-        "options": ["unless-stopped", "always", "on-failure", "no"],
-        "default": "unless-stopped",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "network",
-    "title": "Network",
-    "vars": [
-      {
-        "name": "network_mode",
-        "description": "Docker network mode",
-        "type": "enum",
-        "options": ["bridge", "host", "macvlan"],
-        "extra": "bridge=default Docker networking, host=use host network stack, macvlan=dedicated MAC address on physical network"
-      },
-      {
-        "name": "network_name",
-        "description": "Docker network name",
-        "type": "str",
-        "default": "bridge",
-        "needs": ["network_mode=bridge,macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_external",
-        "description": "Use existing Docker network (external)",
-        "type": "bool",
-        "default": false,
-        "needs": ["network_mode=bridge,macvlan"]
-      },
-      {
-        "name": "network_macvlan_ipv4_address",
-        "description": "Static IP address for container",
-        "type": "str",
-        "default": "192.168.1.253",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_macvlan_parent_interface",
-        "description": "Host network interface name",
-        "type": "str",
-        "default": "eth0",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_macvlan_subnet",
-        "description": "Network subnet in CIDR notation",
-        "type": "str",
-        "default": "192.168.1.0/24",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_macvlan_gateway",
-        "description": "Network gateway IP address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "ports",
-    "title": "Ports",
-    "needs": ["network_mode!=host,macvlan"],
-    "description": "Expose service ports to the host.",
-    "vars": [
-      {
-        "name": "ports_http",
-        "description": "HTTP port on host",
-        "type": "int",
-        "needs": ["traefik_enabled=false"],
-        "default": 8080,
-        "required": true
-      },
-      {
-        "name": "ports_https",
-        "description": "HTTPS port on host",
-        "type": "int",
-        "needs": ["traefik_enabled=false"],
-        "default": 8443,
-        "required": true
-      },
-      {
-        "name": "ports_ssh",
-        "description": "SSH port on host",
-        "type": "int",
-        "default": 22,
-        "required": true
-      },
-      {
-        "name": "ports_dns",
-        "description": "DNS port on host",
-        "type": "int",
-        "default": 53,
-        "required": true
-      },
-      {
-        "name": "ports_dhcp",
-        "description": "DHCP port on host",
-        "type": "int",
-        "default": 67,
-        "required": true
-      },
-      {
-        "name": "ports_smtp",
-        "description": "SMTP port on host",
-        "type": "int",
-        "default": 25,
-        "required": true
-      },
-      {
-        "name": "ports_snmp",
-        "description": "SNMP trap port",
-        "type": "int",
-        "default": 162,
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "needs": ["network_mode!=host,macvlan"],
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik reverse proxy integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_network",
-        "description": "Traefik network name",
-        "type": "str",
-        "default": "traefik",
-        "required": true
-      },
-      {
-        "name": "traefik_host",
-        "description": "Service subdomain or full hostname (e.g., 'app' or 'app.example.com')",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "traefik_domain",
-        "description": "Base domain (e.g., example.com)",
-        "type": "str",
-        "default": "home.arpa",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": ["traefik_enabled=true", "network_mode!=host,macvlan"],
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "volume",
-    "title": "Volume Storage",
-    "description": "Configure persistent storage for your service.",
-    "vars": [
-      {
-        "name": "volume_mode",
-        "description": "Volume storage backend",
-        "type": "enum",
-        "options": ["local", "mount", "nfs"],
-        "default": "local",
-        "required": true
-      },
-      {
-        "name": "volume_mount_path",
-        "description": "Host path for bind mounts",
-        "type": "str",
-        "default": "/mnt/storage",
-        "needs": ["volume_mode=mount"],
-        "required": true
-      },
-      {
-        "name": "volume_nfs_server",
-        "description": "NFS server address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": ["volume_mode=nfs"],
-        "required": true
-      },
-      {
-        "name": "volume_nfs_path",
-        "description": "NFS export path",
-        "type": "str",
-        "default": "/export",
-        "needs": ["volume_mode=nfs"],
-        "required": true
-      },
-      {
-        "name": "volume_nfs_options",
-        "description": "NFS mount options (comma-separated)",
-        "type": "str",
-        "default": "rw,nolock,soft",
-        "needs": ["volume_mode=nfs"],
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "resources",
-    "title": "Resource Limits",
-    "toggle": "resources_enabled",
-    "description": "Set CPU and memory limits for the service.",
-    "vars": [
-      {
-        "name": "resources_enabled",
-        "description": "Enable resource limits",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "resources_cpu_limit",
-        "description": "Maximum CPU cores (e.g., 0.5, 1.0, 2.0)",
-        "type": "str",
-        "default": "1.0",
-        "required": true
-      },
-      {
-        "name": "resources_cpu_reservation",
-        "description": "Reserved CPU cores",
-        "type": "str",
-        "default": "0.25",
-        "needs": ["swarm_enabled=true"],
-        "required": true
-      },
-      {
-        "name": "resources_memory_limit",
-        "description": "Maximum memory (e.g., 512M, 1G, 2G)",
-        "type": "str",
-        "default": "1G",
-        "required": true
-      },
-      {
-        "name": "resources_memory_reservation",
-        "description": "Reserved memory",
-        "type": "str",
-        "default": "512M",
-        "needs": ["swarm_enabled=true"],
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "swarm",
-    "title": "Docker Swarm",
-    "toggle": "swarm_enabled",
-    "needs": ["network_mode!=host,macvlan"],
-    "description": "Deploy service in Docker Swarm mode.",
-    "vars": [
-      {
-        "name": "swarm_enabled",
-        "description": "Enable Docker Swarm mode",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "swarm_placement_mode",
-        "description": "Swarm placement mode",
-        "type": "enum",
-        "options": ["replicated", "global"],
-        "default": "replicated",
-        "required": true
-      },
-      {
-        "name": "swarm_replicas",
-        "description": "Number of replicas",
-        "type": "int",
-        "default": 1,
-        "needs": ["swarm_placement_mode=replicated"],
-        "required": true
-      },
-      {
-        "name": "swarm_placement_host",
-        "description": "Target hostname for placement constraint",
-        "type": "str",
-        "default": "",
-        "needs": ["swarm_placement_mode=replicated"],
-        "extra": "Constrains service to run on specific node by hostname"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["sqlite", "postgres", "mysql"],
-        "default": "sqlite",
-        "required": true
-      },
-      {
-        "name": "database_external",
-        "description": "Use an external database server?",
-        "extra": "skips creation of internal database container",
-        "type": "bool",
-        "needs": ["database_type=postgres,mysql"],
-        "default": false
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "needs": ["database_external=true;database_type=postgres,mysql"],
-        "required": true
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int",
-        "needs": ["database_external=true;database_type=postgres,mysql"],
-        "required": true
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str",
-        "needs": ["database_type=postgres,mysql"],
-        "required": true
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str",
-        "needs": ["database_type=postgres,mysql"],
-        "required": true
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "needs": ["database_type=postgres,mysql"],
-        "sensitive": true,
-        "autogenerated": true,
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "email",
-    "title": "Email Server",
-    "toggle": "email_enabled",
-    "description": "Configure email server for notifications and user management.",
-    "vars": [
-      {
-        "name": "email_enabled",
-        "description": "Enable email server configuration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "email_host",
-        "description": "SMTP server hostname",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_port",
-        "description": "SMTP server port",
-        "type": "int",
-        "default": 25,
-        "required": true
-      },
-      {
-        "name": "email_username",
-        "description": "SMTP username",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_password",
-        "description": "SMTP password",
-        "type": "str",
-        "sensitive": true,
-        "required": true
-      },
-      {
-        "name": "email_from",
-        "description": "From email address",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_encryption",
-        "description": "Email encryption method to use",
-        "type": "enum",
-        "options": ["none", "starttls", "ssl"]
-      }
-    ]
-  },
-  {
-    "key": "authentik",
-    "title": "Authentik SSO",
-    "toggle": "authentik_enabled",
-    "description": "Integrate with Authentik for Single Sign-On authentication.",
-    "vars": [
-      {
-        "name": "authentik_enabled",
-        "description": "Enable Authentik SSO integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "authentik_url",
-        "description": "Authentik base URL (e.g., https://auth.example.com)",
-        "type": "url",
-        "required": true
-      },
-      {
-        "name": "authentik_slug",
-        "description": "Authentik application slug",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "authentik_traefik_middleware",
-        "description": "Traefik middleware name for Authentik authentication",
-        "type": "str",
-        "default": "authentik-middleware@file",
-        "needs": ["traefik_enabled=true"],
-        "required": true
-      },
-      {
-        "name": "authentik_client_id",
-        "description": "Authentik OAuth2 client ID",
-        "type": "str",
-        "sensitive": true,
-        "required": true
-      },
-      {
-        "name": "authentik_client_secret",
-        "description": "Authentik OAuth2 client secret",
-        "type": "str",
-        "sensitive": true,
-        "required": true
-      }
-    ]
-  }
-]

+ 0 - 202
cli/core/schema/helm/v1.0.json

@@ -1,202 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "release_name",
-        "description": "Helm release name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "namespace",
-        "description": "Kubernetes namespace",
-        "type": "str"
-      }
-    ]
-  },
-  {
-    "key": "networking",
-    "title": "Networking",
-    "vars": [
-      {
-        "name": "network_mode",
-        "description": "Kubernetes service type",
-        "type": "enum",
-        "options": ["ClusterIP", "NodePort", "LoadBalancer"],
-        "default": "ClusterIP"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database Configuration",
-    "toggle": "database_enabled",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database configuration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["postgres", "mysql", "mariadb"],
-        "default": "postgres"
-      },
-      {
-        "name": "database_host",
-        "description": "Database hostname",
-        "type": "hostname"
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int",
-        "default": 5432
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str"
-      },
-      {
-        "name": "database_user",
-        "description": "Database username",
-        "type": "str"
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "sensitive": true
-      }
-    ]
-  },
-  {
-    "key": "email",
-    "title": "Email Configuration",
-    "toggle": "email_enabled",
-    "vars": [
-      {
-        "name": "email_enabled",
-        "description": "Enable email configuration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "email_host",
-        "description": "SMTP server hostname",
-        "type": "hostname"
-      },
-      {
-        "name": "email_port",
-        "description": "SMTP server port",
-        "type": "int",
-        "default": 587
-      },
-      {
-        "name": "email_username",
-        "description": "SMTP username",
-        "type": "str"
-      },
-      {
-        "name": "email_password",
-        "description": "SMTP password",
-        "type": "str",
-        "sensitive": true
-      },
-      {
-        "name": "email_from",
-        "description": "From email address",
-        "type": "email"
-      },
-      {
-        "name": "email_use_tls",
-        "description": "Use TLS encryption",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "email_use_ssl",
-        "description": "Use SSL encryption",
-        "type": "bool",
-        "default": false
-      }
-    ]
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik Ingress",
-    "toggle": "traefik_enabled",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik ingress",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_host",
-        "description": "Ingress hostname (FQDN)",
-        "type": "hostname"
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "needs": "traefik",
-    "toggle": "traefik_tls_enabled",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable TLS for ingress",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_certmanager",
-        "description": "Use cert-manager for TLS certificates",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "certmanager_issuer",
-        "description": "Cert-manager cluster issuer name",
-        "type": "str",
-        "needs": "traefik_tls_certmanager=true",
-        "default": "letsencrypt-prod"
-      },
-      {
-        "name": "traefik_tls_secret",
-        "description": "TLS secret name",
-        "type": "str"
-      }
-    ]
-  },
-  {
-    "key": "volumes",
-    "title": "Persistent Volumes",
-    "vars": [
-      {
-        "name": "volumes_mode",
-        "description": "Volume configuration mode",
-        "type": "enum",
-        "options": ["dynamic-pvc", "existing-pvc"],
-        "default": "dynamic-pvc",
-        "extra": "dynamic-pvc=auto-provision storage, existing-pvc=use existing PVC"
-      },
-      {
-        "name": "volumes_pvc_name",
-        "description": "Existing PVC name",
-        "type": "str",
-        "needs": "volumes_mode=existing-pvc"
-      }
-    ]
-  }
-]

+ 0 - 247
cli/core/schema/kubernetes/v1.0.json

@@ -1,247 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "resource_name",
-        "description": "Kubernetes resource name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "namespace",
-        "description": "Kubernetes namespace",
-        "type": "str",
-        "default": "default",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "resources",
-    "title": "Resource Limits",
-    "toggle": "resources_enabled",
-    "description": "Set CPU and memory limits for the resource.",
-    "vars": [
-      {
-        "name": "resources_enabled",
-        "description": "Enable resource limits",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "resources_cpu_limit",
-        "description": "Maximum CPU cores (e.g., 100m, 500m, 1, 2)",
-        "type": "str",
-        "default": "1",
-        "required": true
-      },
-      {
-        "name": "resources_cpu_request",
-        "description": "Requested CPU cores",
-        "type": "str",
-        "default": "250m",
-        "required": true
-      },
-      {
-        "name": "resources_memory_limit",
-        "description": "Maximum memory (e.g., 512Mi, 1Gi, 2Gi)",
-        "type": "str",
-        "default": "1Gi",
-        "required": true
-      },
-      {
-        "name": "resources_memory_request",
-        "description": "Requested memory",
-        "type": "str",
-        "default": "512Mi",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik ingress configuration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_host",
-        "description": "Service subdomain or full hostname (e.g., 'app' or 'app.example.com')",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "traefik_domain",
-        "description": "Base domain (e.g., example.com)",
-        "type": "str",
-        "default": "home.arpa",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": ["traefik"],
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["sqlite", "postgres", "mysql", "mariadb"],
-        "default": "postgres",
-        "required": true
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "default": "database",
-        "required": true
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int",
-        "required": true
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "default": "",
-        "sensitive": true,
-        "autogenerated": true,
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "email",
-    "title": "Email Server",
-    "toggle": "email_enabled",
-    "description": "Configure email server for notifications and user management.",
-    "vars": [
-      {
-        "name": "email_enabled",
-        "description": "Enable email server configuration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "email_host",
-        "description": "SMTP server hostname",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_port",
-        "description": "SMTP server port",
-        "type": "int",
-        "default": 25,
-        "required": true
-      },
-      {
-        "name": "email_username",
-        "description": "SMTP username",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_password",
-        "description": "SMTP password",
-        "type": "str",
-        "sensitive": true,
-        "required": true
-      },
-      {
-        "name": "email_from",
-        "description": "From email address",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_encryption",
-        "description": "Email encryption method to use",
-        "type": "enum",
-        "options": ["none", "starttls", "ssl"]
-      }
-    ]
-  },
-  {
-    "key": "authentik",
-    "title": "Authentik SSO",
-    "toggle": "authentik_enabled",
-    "description": "Integrate with Authentik for Single Sign-On authentication.",
-    "vars": [
-      {
-        "name": "authentik_enabled",
-        "description": "Enable Authentik SSO integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "authentik_url",
-        "description": "Authentik base URL (e.g., https://auth.example.com)",
-        "type": "url",
-        "required": true
-      },
-      {
-        "name": "authentik_slug",
-        "description": "Authentik application slug",
-        "type": "str",
-        "required": true
-      }
-    ]
-  }
-]

+ 0 - 220
cli/core/schema/loader.py

@@ -1,220 +0,0 @@
-"""JSON Schema Loading and Validation.
-
-This module provides functionality to load, cache, and validate JSON schemas
-for boilerplate modules. Schemas are stored in cli/core/schema/<module>/v*.json files.
-"""
-
-import json
-from pathlib import Path
-from typing import Any
-
-from cli.core.exceptions import SchemaError
-
-
-class SchemaLoader:
-    """Loads and validates JSON schemas for modules."""
-
-    def __init__(self, schema_dir: Path | None = None):
-        """Initialize schema loader.
-
-        Args:
-            schema_dir: Directory containing schema files. If None, uses cli/core/schema/
-        """
-        if schema_dir is None:
-            # Use path relative to this file (in cli/core/schema/)
-            # __file__ is cli/core/schema/loader.py, parent is cli/core/schema/
-            self.schema_dir = Path(__file__).parent
-        else:
-            self.schema_dir = schema_dir
-
-    def load_schema(self, module: str, version: str) -> list[dict[str, Any]]:
-        """Load a JSON schema from file.
-
-        Args:
-            module: Module name (e.g., 'compose', 'ansible')
-            version: Schema version (e.g., '1.0', '1.2')
-
-        Returns:
-            Schema as list of section specifications
-
-        Raises:
-            SchemaError: If schema file not found or invalid JSON
-        """
-        schema_file = self.schema_dir / module / f"v{version}.json"
-
-        if not schema_file.exists():
-            raise SchemaError(
-                f"Schema file not found: {schema_file}",
-                details=f"Module: {module}, Version: {version}",
-            )
-
-        try:
-            with schema_file.open(encoding="utf-8") as f:
-                schema = json.load(f)
-        except json.JSONDecodeError as e:
-            raise SchemaError(
-                f"Invalid JSON in schema file: {schema_file}",
-                details=f"Error: {e}",
-            ) from e
-        except Exception as e:
-            raise SchemaError(
-                f"Failed to read schema file: {schema_file}",
-                details=f"Error: {e}",
-            ) from e
-
-        # Validate schema structure
-        self._validate_schema_structure(schema, module, version)
-
-        return schema
-
-    def _validate_schema_structure(self, schema: Any, module: str, version: str) -> None:
-        """Validate that schema has correct structure.
-
-        Args:
-            schema: Schema to validate
-            module: Module name for error messages
-            version: Version for error messages
-
-        Raises:
-            SchemaError: If schema structure is invalid
-        """
-        if not isinstance(schema, list):
-            raise SchemaError(
-                f"Schema must be a list, got {type(schema).__name__}",
-                details=f"Module: {module}, Version: {version}",
-            )
-
-        for idx, section in enumerate(schema):
-            if not isinstance(section, dict):
-                raise SchemaError(
-                    f"Section {idx} must be a dict, got {type(section).__name__}",
-                    details=f"Module: {module}, Version: {version}",
-                )
-
-            # Check required fields
-            if "key" not in section:
-                raise SchemaError(
-                    f"Section {idx} missing required field 'key'",
-                    details=f"Module: {module}, Version: {version}",
-                )
-
-            if "vars" not in section:
-                raise SchemaError(
-                    f"Section '{section.get('key')}' missing required field 'vars'",
-                    details=f"Module: {module}, Version: {version}",
-                )
-
-            if not isinstance(section["vars"], list):
-                raise SchemaError(
-                    f"Section '{section['key']}' vars must be a list",
-                    details=f"Module: {module}, Version: {version}",
-                )
-
-            # Validate variables
-            for var_idx, var in enumerate(section["vars"]):
-                if not isinstance(var, dict):
-                    raise SchemaError(
-                        f"Variable {var_idx} in section '{section['key']}' must be a dict",
-                        details=f"Module: {module}, Version: {version}",
-                    )
-
-                if "name" not in var:
-                    raise SchemaError(
-                        f"Variable {var_idx} in section '{section['key']}' missing 'name'",
-                        details=f"Module: {module}, Version: {version}",
-                    )
-
-                if "type" not in var:
-                    raise SchemaError(
-                        f"Variable '{var.get('name')}' in section '{section['key']}' missing 'type'",
-                        details=f"Module: {module}, Version: {version}",
-                    )
-
-    def list_versions(self, module: str) -> list[str]:
-        """List available schema versions for a module.
-
-        Args:
-            module: Module name
-
-        Returns:
-            List of version strings (e.g., ['1.0', '1.1', '1.2'])
-        """
-        module_dir = self.schema_dir / module
-
-        if not module_dir.exists():
-            return []
-
-        versions = []
-        for file in module_dir.glob("v*.json"):
-            # Extract version from filename (v1.0.json -> 1.0)
-            version = file.stem[1:]  # Remove 'v' prefix
-            versions.append(version)
-
-        return sorted(versions)
-
-    def has_schema(self, module: str, version: str) -> bool:
-        """Check if a schema exists.
-
-        Args:
-            module: Module name
-            version: Schema version
-
-        Returns:
-            True if schema exists
-        """
-        schema_file = self.schema_dir / module / f"v{version}.json"
-        return schema_file.exists()
-
-
-# Global schema loader instance
-_loader: SchemaLoader | None = None
-
-
-def get_loader() -> SchemaLoader:
-    """Get global schema loader instance.
-
-    Returns:
-        SchemaLoader instance
-    """
-    global _loader  # noqa: PLW0603
-    if _loader is None:
-        _loader = SchemaLoader()
-    return _loader
-
-
-def load_schema(module: str, version: str) -> list[dict[str, Any]]:
-    """Load a schema using the global loader.
-
-    Args:
-        module: Module name
-        version: Schema version
-
-    Returns:
-        Schema as list of section specifications
-    """
-    return get_loader().load_schema(module, version)
-
-
-def list_versions(module: str) -> list[str]:
-    """List available versions for a module.
-
-    Args:
-        module: Module name
-
-    Returns:
-        List of version strings
-    """
-    return get_loader().list_versions(module)
-
-
-def has_schema(module: str, version: str) -> bool:
-    """Check if a schema exists.
-
-    Args:
-        module: Module name
-        version: Schema version
-
-    Returns:
-        True if schema exists
-    """
-    return get_loader().has_schema(module, version)

+ 0 - 14
cli/core/schema/packer/v1.0.json

@@ -1,14 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "playbook_name",
-        "description": "Ansible playbook name",
-        "type": "str"
-      }
-    ]
-  }
-]

+ 0 - 87
cli/core/schema/terraform/v1.0.json

@@ -1,87 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "resource_name",
-        "description": "Terraform resource name (alphanumeric and underscores only)",
-        "type": "str",
-        "default": "resource"
-      }
-    ]
-  },
-  {
-    "key": "depends_on",
-    "title": "Dependencies",
-    "toggle": "depends_on_enabled",
-    "required": false,
-    "vars": [
-      {
-        "name": "depends_on_enabled",
-        "description": "Enable resource dependencies",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "dependencies",
-        "description": "Comma-separated list of resource dependencies",
-        "type": "str",
-        "default": ""
-      }
-    ]
-  },
-  {
-    "key": "lifecycle",
-    "title": "Lifecycle",
-    "toggle": "lifecycle_enabled",
-    "required": false,
-    "vars": [
-      {
-        "name": "lifecycle_enabled",
-        "description": "Enable lifecycle rules",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "prevent_destroy",
-        "description": "Prevent resource destruction",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "create_before_destroy",
-        "description": "Create replacement before destroying",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "ignore_changes",
-        "description": "Comma-separated list of attributes to ignore changes for",
-        "type": "str",
-        "default": ""
-      }
-    ]
-  },
-  {
-    "key": "tags",
-    "title": "Tags",
-    "toggle": "tags_enabled",
-    "required": false,
-    "vars": [
-      {
-        "name": "tags_enabled",
-        "description": "Enable resource tags",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "tags_json",
-        "description": "Resource tags in JSON format (e.g., {\"Environment\": \"Production\"})",
-        "type": "str",
-        "default": "{}"
-      }
-    ]
-  }
-]

+ 22 - 151
cli/core/template/template.py

@@ -1,14 +1,11 @@
 from __future__ import annotations
 
-import base64
-import importlib
 import logging
 import os
 import re
 import secrets
 import string
 from dataclasses import dataclass, field
-from functools import lru_cache
 from pathlib import Path
 from typing import Any, Literal
 
@@ -29,7 +26,6 @@ from jinja2.exceptions import (
 from jinja2.sandbox import SandboxedEnvironment
 
 from ..exceptions import (
-    IncompatibleSchemaVersionError,
     RenderErrorContext,
     TemplateLoadError,
     TemplateRenderError,
@@ -37,7 +33,6 @@ from ..exceptions import (
     TemplateValidationError,
     YAMLParseError,
 )
-from ..version import is_compatible
 from .variable_collection import VariableCollection
 
 logger = logging.getLogger(__name__)
@@ -319,13 +314,10 @@ class Template:
         self.library_type = library_type
 
         # Initialize caches for lazy loading
-        self.__module_specs: dict | None = None
-        self.__merged_specs: dict | None = None
         self.__jinja_env: Environment | None = None
         self.__used_variables: set[str] | None = None
         self.__variables: VariableCollection | None = None
         self.__template_files: list[TemplateFile] | None = None  # New attribute
-        self._schema_deprecation_warned: bool = False  # Track if deprecation warning shown
 
         try:
             # Find and parse the main template file (template.yaml or template.yml)
@@ -356,14 +348,6 @@ class Template:
             # Validate 'kind' field (always needed)
             self._validate_kind(self._template_data)
 
-            # DEPRECATION (v0.1.3): Schema property is ignored for backwards compatibility
-            # Templates are now self-contained and never use schemas
-            # The schema property may still exist in template.yaml for older client compatibility
-            self.schema_version = None
-            logger.debug("Template is self-contained (schemas are no longer used)")
-
-            # Note: Schema loading and validation removed in v0.1.3
-
             # NOTE: File collection is now lazy-loaded via the template_files property
             # This significantly improves performance when listing many templates
 
@@ -397,81 +381,24 @@ class Template:
                 return path
         raise FileNotFoundError(f"Main template file (template.yaml or template.yml) not found in {self.template_dir}")
 
-    @staticmethod
-    @lru_cache(maxsize=32)
-    def _load_module_specs_for_schema(kind: str, schema_version: str) -> dict:
-        """Load specifications from the corresponding module for a specific schema version.
-
-        DEPRECATION NOTICE (v0.1.3): Module schemas are being deprecated. Templates should define
-        all variables in their template.yaml spec section. In future versions, this method will
-        return an empty dict and templates will need to be self-contained.
-
-        Uses LRU cache to avoid re-loading the same module spec multiple times.
-        This significantly improves performance when listing many templates of the same kind.
-
-        Args:
-            kind: The module kind (e.g., 'compose', 'terraform')
-            schema_version: The schema version to load (e.g., '1.0', '1.1')
-
-        Returns:
-            Dictionary containing the module's spec for the requested schema version,
-            or empty dict if kind is empty
-
-        Raises:
-            ValueError: If module cannot be loaded or spec is invalid
+    def _merge_specs(self) -> dict:
+        """Process template specs into merged format.
+        
+        Since schemas are no longer used, this just uses the template specs directly
+        and warns about unused variables.
         """
-        if not kind:
+        if not self.template_specs:
             return {}
-
-        # Log cache statistics for performance monitoring
-        cache_info = Template._load_module_specs_for_schema.cache_info()
-        logger.debug(
-            f"Loading module spec: kind='{kind}', schema={schema_version} "
-            f"(cache: hits={cache_info.hits}, misses={cache_info.misses}, size={cache_info.currsize})"
-        )
-
-        try:
-            module = importlib.import_module(f"cli.modules.{kind}")
-
-            # Check if module has schema-specific specs (multi-schema support)
-            # Try SCHEMAS constant first (uppercase), then schemas attribute
-            schemas = getattr(module, "SCHEMAS", None) or getattr(module, "schemas", None)
-            if schemas and schema_version in schemas:
-                spec = schemas[schema_version]
-                logger.debug(f"Loaded and cached module spec for kind '{kind}' schema {schema_version}")
-            else:
-                # Fallback to default spec if schema mapping not available
-                spec = getattr(module, "spec", {})
-                logger.debug(f"Loaded and cached module spec for kind '{kind}' (default/no schema mapping)")
-
-            return spec
-        except Exception as e:
-            raise ValueError(f"Error loading module specifications for kind '{kind}': {e}") from e
-
-    def _merge_specs(self, module_specs: dict, template_specs: dict) -> dict:
-        """Deep merge template specs with module specs using VariableCollection.
-
-        Uses VariableCollection's native merge() method for consistent merging logic.
-        Module specs are base, template specs override with origin tracking.
-        """
-        # Create VariableCollection from module specs (base)
-        module_collection = VariableCollection(module_specs) if module_specs else VariableCollection({})
-
-        # Set origin for module variables
-        for section in module_collection.get_sections().values():
-            for variable in section.variables.values():
-                if not variable.origin:
-                    variable.origin = "module"
-
-        # Merge template specs into module specs (template overrides)
-        if template_specs:
-            merged_collection = module_collection.merge(template_specs, origin="template")
-        else:
-            merged_collection = module_collection
-
+        
+        # Warn about unused variables in spec
+        self._warn_about_unused_variables(self.template_specs)
+        
+        # Create VariableCollection from template specs
+        collection = VariableCollection(self.template_specs)
+        
         # Convert back to dict format
         merged_spec = {}
-        for section_key, section in merged_collection.get_sections().items():
+        for section_key, section in collection.get_sections().items():
             merged_spec[section_key] = section.to_dict()
 
         return merged_spec
@@ -580,8 +507,6 @@ class Template:
     def _filter_specs_to_used(
         self,
         used_variables: set,
-        merged_specs: dict,
-        _module_specs: dict,
         template_specs: dict,
     ) -> dict:
         """Filter specs to only include variables used in templates using VariableCollection.
@@ -595,15 +520,15 @@ class Template:
             if isinstance(section_data, dict) and "vars" in section_data:
                 template_defined_vars.update(section_data["vars"].keys())
 
-        # Create VariableCollection from merged specs
-        merged_collection = VariableCollection(merged_specs)
+        # Create VariableCollection from template specs
+        template_collection = VariableCollection(template_specs)
 
         # Filter to only used variables (and sensitive ones that are template-defined)
         # We keep sensitive variables that are either:
         # 1. Actually used in template files, OR
         # 2. Explicitly defined in the template spec (even if not yet used)
         variables_to_keep = used_variables | template_defined_vars
-        filtered_collection = merged_collection.filter_to_used(variables_to_keep, keep_sensitive=False)
+        filtered_collection = template_collection.filter_to_used(variables_to_keep, keep_sensitive=False)
 
         # Convert back to dict format
         filtered_specs = {}
@@ -612,43 +537,6 @@ class Template:
 
         return filtered_specs
 
-    def _validate_schema_version(self, module_schema: str, module_name: str) -> None:
-        """Validate that template schema version is supported by the module.
-
-        Self-contained templates (with schema=None) don't require validation.
-
-        Args:
-            module_schema: Schema version supported by the module
-            module_name: Name of the module (for error messages)
-
-        Raises:
-            IncompatibleSchemaVersionError: If template schema > module schema
-        """
-        template_schema = self.schema_version
-
-        # Self-contained templates (no schema property) don't need validation
-        if template_schema is None:
-            logger.debug(f"Template '{self.id}' is self-contained (no schema inheritance)")
-            return
-
-        # Compare schema versions
-        if not is_compatible(module_schema, template_schema):
-            logger.error(
-                f"Template '{self.id}' uses schema version {template_schema}, "
-                f"but module '{module_name}' only supports up to {module_schema}"
-            )
-            raise IncompatibleSchemaVersionError(
-                template_id=self.id,
-                template_schema=template_schema,
-                module_schema=module_schema,
-                module_name=module_name,
-            )
-
-        logger.debug(
-            f"Template '{self.id}' schema version compatible: "
-            f"template uses {template_schema}, module supports {module_schema}"
-        )
-
     @staticmethod
     def _validate_kind(template_data: dict) -> None:
         """Validate that template has required 'kind' field.
@@ -915,23 +803,6 @@ class Template:
         """Get the spec section from template YAML data."""
         return self._template_data.get("spec", {})
 
-    @property
-    def module_specs(self) -> dict:
-        """Get the spec from the module (always empty in v0.1.3+).
-        
-        Schemas are no longer used. All templates are self-contained.
-        This property returns empty dict for backwards compatibility.
-        """
-        if self.__module_specs is None:
-            self.__module_specs = {}
-    @property
-    def merged_specs(self) -> dict:
-        if self.__merged_specs is None:
-            # Warn about unused variables in spec
-            self._warn_about_unused_variables(self.template_specs)
-            self.__merged_specs = self._merge_specs(self.module_specs, self.template_specs)
-        return self.__merged_specs
-
     @property
     def jinja_env(self) -> Environment:
         if self.__jinja_env is None:
@@ -947,19 +818,19 @@ class Template:
     @property
     def variables(self) -> VariableCollection:
         if self.__variables is None:
+            # Process template specs (merge and warn about unused variables)
+            merged_specs = self._merge_specs()
+            
             # Validate that all used variables are defined
-            self._validate_variable_definitions(self.used_variables, self.merged_specs)
+            self._validate_variable_definitions(self.used_variables, merged_specs)
+            
             # Filter specs to only used variables
             filtered_specs = self._filter_specs_to_used(
                 self.used_variables,
-                self.merged_specs,
-                self.module_specs,
                 self.template_specs,
             )
 
             self.__variables = VariableCollection(filtered_specs)
-            # Sort sections: required first, then enabled, then disabled
-            self.__variables.sort_sections()
         return self.__variables
 
     @property

+ 0 - 14
library/schemas/ansible/v1.0.json

@@ -1,14 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "playbook_name",
-        "description": "Ansible playbook name",
-        "type": "str"
-      }
-    ]
-  }
-]

+ 0 - 229
library/schemas/compose/v1.0.json

@@ -1,229 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "service_name",
-        "description": "Service name",
-        "type": "str"
-      },
-      {
-        "name": "container_name",
-        "description": "Container name",
-        "type": "str"
-      },
-      {
-        "name": "container_timezone",
-        "description": "Container timezone (e.g., Europe/Berlin)",
-        "type": "str",
-        "default": "UTC"
-      },
-      {
-        "name": "user_uid",
-        "description": "User UID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "user_gid",
-        "description": "User GID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "restart_policy",
-        "description": "Container restart policy",
-        "type": "enum",
-        "options": ["unless-stopped", "always", "on-failure", "no"],
-        "default": "unless-stopped"
-      }
-    ]
-  },
-  {
-    "key": "network",
-    "title": "Network",
-    "toggle": "network_enabled",
-    "vars": [
-      {
-        "name": "network_enabled",
-        "description": "Enable custom network block",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "network_name",
-        "description": "Docker network name",
-        "type": "str",
-        "default": "bridge"
-      },
-      {
-        "name": "network_external",
-        "description": "Use existing Docker network",
-        "type": "bool",
-        "default": true
-      }
-    ]
-  },
-  {
-    "key": "ports",
-    "title": "Ports",
-    "toggle": "ports_enabled",
-    "vars": [
-      {
-        "name": "ports_enabled",
-        "description": "Expose ports via 'ports' mapping",
-        "type": "bool",
-        "default": true
-      }
-    ]
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik reverse proxy integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_network",
-        "description": "Traefik network name",
-        "type": "str",
-        "default": "traefik"
-      },
-      {
-        "name": "traefik_host",
-        "description": "Domain name for your service (e.g., app.example.com)",
-        "type": "str"
-      },
-      {
-        "name": "traefik_entrypoint",
-        "description": "HTTP entrypoint (non-TLS)",
-        "type": "str",
-        "default": "web"
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": ["traefik"],
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_entrypoint",
-        "description": "TLS entrypoint",
-        "type": "str",
-        "default": "websecure"
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare"
-      }
-    ]
-  },
-  {
-    "key": "swarm",
-    "title": "Docker Swarm",
-    "toggle": "swarm_enabled",
-    "description": "Deploy service in Docker Swarm mode with replicas.",
-    "vars": [
-      {
-        "name": "swarm_enabled",
-        "description": "Enable Docker Swarm mode",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "swarm_replicas",
-        "description": "Number of replicas in Swarm",
-        "type": "int",
-        "default": 1
-      },
-      {
-        "name": "swarm_placement_mode",
-        "description": "Swarm placement mode",
-        "type": "enum",
-        "options": ["global", "replicated"],
-        "default": "replicated"
-      },
-      {
-        "name": "swarm_placement_host",
-        "description": "Limit placement to specific node",
-        "type": "str"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["postgres", "mysql"],
-        "default": "postgres"
-      },
-      {
-        "name": "database_external",
-        "description": "Use an external database server?",
-        "extra": "skips creation of internal database container",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "default": "database"
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int"
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str"
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str"
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "default": "",
-        "sensitive": true,
-        "autogenerated": true
-      }
-    ]
-  }
-]

+ 0 - 312
library/schemas/compose/v1.1.json

@@ -1,312 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "service_name",
-        "description": "Service name",
-        "type": "str"
-      },
-      {
-        "name": "container_name",
-        "description": "Container name",
-        "type": "str"
-      },
-      {
-        "name": "container_hostname",
-        "description": "Container internal hostname",
-        "type": "str"
-      },
-      {
-        "name": "container_timezone",
-        "description": "Container timezone (e.g., Europe/Berlin)",
-        "type": "str",
-        "default": "UTC"
-      },
-      {
-        "name": "user_uid",
-        "description": "User UID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "user_gid",
-        "description": "User GID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "container_loglevel",
-        "description": "Container log level",
-        "type": "enum",
-        "options": ["debug", "info", "warn", "error"],
-        "default": "info"
-      },
-      {
-        "name": "restart_policy",
-        "description": "Container restart policy",
-        "type": "enum",
-        "options": ["unless-stopped", "always", "on-failure", "no"],
-        "default": "unless-stopped"
-      }
-    ]
-  },
-  {
-    "key": "network",
-    "title": "Network",
-    "vars": [
-      {
-        "name": "network_mode",
-        "description": "Docker network mode",
-        "type": "enum",
-        "options": ["bridge", "host", "macvlan"],
-        "default": "bridge",
-        "extra": "bridge=default Docker networking, host=use host network stack, macvlan=dedicated MAC address on physical network"
-      },
-      {
-        "name": "network_name",
-        "description": "Docker network name",
-        "type": "str",
-        "default": "bridge",
-        "needs": ["network_mode=bridge,macvlan"]
-      },
-      {
-        "name": "network_external",
-        "description": "Use existing Docker network (external)",
-        "type": "bool",
-        "default": false,
-        "needs": ["network_mode=bridge,macvlan"]
-      },
-      {
-        "name": "network_macvlan_ipv4_address",
-        "description": "Static IP address for container",
-        "type": "str",
-        "default": "192.168.1.253",
-        "needs": ["network_mode=macvlan"]
-      },
-      {
-        "name": "network_macvlan_parent_interface",
-        "description": "Host network interface name",
-        "type": "str",
-        "default": "eth0",
-        "needs": ["network_mode=macvlan"]
-      },
-      {
-        "name": "network_macvlan_subnet",
-        "description": "Network subnet in CIDR notation",
-        "type": "str",
-        "default": "192.168.1.0/24",
-        "needs": ["network_mode=macvlan"]
-      },
-      {
-        "name": "network_macvlan_gateway",
-        "description": "Network gateway IP address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": ["network_mode=macvlan"]
-      }
-    ]
-  },
-  {
-    "key": "ports",
-    "title": "Ports",
-    "needs": ["network_mode=bridge"],
-    "vars": []
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "needs": ["network_mode=bridge"],
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik reverse proxy integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_network",
-        "description": "Traefik network name",
-        "type": "str",
-        "default": "traefik"
-      },
-      {
-        "name": "traefik_host",
-        "description": "Domain name for your service (e.g., app.example.com)",
-        "type": "str"
-      },
-      {
-        "name": "traefik_entrypoint",
-        "description": "HTTP entrypoint (non-TLS)",
-        "type": "str",
-        "default": "web"
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": ["traefik_enabled=true;network_mode=bridge"],
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_entrypoint",
-        "description": "TLS entrypoint",
-        "type": "str",
-        "default": "websecure"
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare"
-      }
-    ]
-  },
-  {
-    "key": "swarm",
-    "title": "Docker Swarm",
-    "toggle": "swarm_enabled",
-    "needs": ["network_mode=bridge"],
-    "description": "Deploy service in Docker Swarm mode.",
-    "vars": [
-      {
-        "name": "swarm_enabled",
-        "description": "Enable Docker Swarm mode",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "swarm_placement_mode",
-        "description": "Swarm placement mode",
-        "type": "enum",
-        "options": ["replicated", "global"],
-        "default": "replicated"
-      },
-      {
-        "name": "swarm_replicas",
-        "description": "Number of replicas",
-        "type": "int",
-        "default": 1,
-        "needs": ["swarm_placement_mode=replicated"]
-      },
-      {
-        "name": "swarm_placement_host",
-        "description": "Target hostname for placement constraint",
-        "type": "str",
-        "default": "",
-        "optional": true,
-        "needs": ["swarm_placement_mode=replicated"],
-        "extra": "Constrains service to run on specific node by hostname"
-      },
-      {
-        "name": "swarm_volume_mode",
-        "description": "Swarm volume storage backend",
-        "type": "enum",
-        "options": ["local", "mount", "nfs"],
-        "default": "local",
-        "extra": "WARNING: 'local' only works on single-node deployments!"
-      },
-      {
-        "name": "swarm_volume_mount_path",
-        "description": "Host path for bind mount",
-        "type": "str",
-        "default": "/mnt/storage",
-        "needs": ["swarm_volume_mode=mount"],
-        "extra": "Useful for shared/replicated storage"
-      },
-      {
-        "name": "swarm_volume_nfs_server",
-        "description": "NFS server address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": ["swarm_volume_mode=nfs"],
-        "extra": "IP address or hostname of NFS server"
-      },
-      {
-        "name": "swarm_volume_nfs_path",
-        "description": "NFS export path",
-        "type": "str",
-        "default": "/export",
-        "needs": ["swarm_volume_mode=nfs"],
-        "extra": "Path to NFS export on the server"
-      },
-      {
-        "name": "swarm_volume_nfs_options",
-        "description": "NFS mount options",
-        "type": "str",
-        "default": "rw,nolock,soft",
-        "needs": ["swarm_volume_mode=nfs"],
-        "extra": "Comma-separated NFS mount options"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["default", "sqlite", "postgres", "mysql"],
-        "default": "default"
-      },
-      {
-        "name": "database_external",
-        "description": "Use an external database server?",
-        "extra": "skips creation of internal database container",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "default": "database"
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int"
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str"
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str"
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "default": "",
-        "sensitive": true,
-        "autogenerated": true
-      }
-    ]
-  }
-]

+ 0 - 512
library/schemas/compose/v1.2.json

@@ -1,512 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "vars": [
-      {
-        "name": "service_name",
-        "description": "Service name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "container_name",
-        "description": "Container name",
-        "type": "str"
-      },
-      {
-        "name": "container_hostname",
-        "description": "Container internal hostname",
-        "type": "str"
-      },
-      {
-        "name": "container_timezone",
-        "description": "Container timezone (e.g., Europe/Berlin)",
-        "type": "str"
-      },
-      {
-        "name": "user_uid",
-        "description": "User UID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "user_gid",
-        "description": "User GID for container process",
-        "type": "int",
-        "default": 1000
-      },
-      {
-        "name": "container_loglevel",
-        "description": "Container log level",
-        "type": "enum",
-        "options": ["debug", "info", "warn", "error"]
-      },
-      {
-        "name": "restart_policy",
-        "description": "Container restart policy",
-        "type": "enum",
-        "options": ["unless-stopped", "always", "on-failure", "no"],
-        "default": "unless-stopped",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "network",
-    "title": "Network",
-    "vars": [
-      {
-        "name": "network_mode",
-        "description": "Docker network mode",
-        "type": "enum",
-        "options": ["bridge", "host", "macvlan"],
-        "extra": "bridge=default Docker networking, host=use host network stack, macvlan=dedicated MAC address on physical network"
-      },
-      {
-        "name": "network_name",
-        "description": "Docker network name",
-        "type": "str",
-        "default": "bridge",
-        "needs": ["network_mode=bridge,macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_external",
-        "description": "Use existing Docker network (external)",
-        "type": "bool",
-        "default": false,
-        "needs": ["network_mode=bridge,macvlan"]
-      },
-      {
-        "name": "network_macvlan_ipv4_address",
-        "description": "Static IP address for container",
-        "type": "str",
-        "default": "192.168.1.253",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_macvlan_parent_interface",
-        "description": "Host network interface name",
-        "type": "str",
-        "default": "eth0",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_macvlan_subnet",
-        "description": "Network subnet in CIDR notation",
-        "type": "str",
-        "default": "192.168.1.0/24",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      },
-      {
-        "name": "network_macvlan_gateway",
-        "description": "Network gateway IP address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": ["network_mode=macvlan"],
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "ports",
-    "title": "Ports",
-    "needs": ["network_mode!=host,macvlan"],
-    "description": "Expose service ports to the host.",
-    "vars": [
-      {
-        "name": "ports_http",
-        "description": "HTTP port on host",
-        "type": "int",
-        "needs": ["traefik_enabled=false"],
-        "default": 8080,
-        "required": true
-      },
-      {
-        "name": "ports_https",
-        "description": "HTTPS port on host",
-        "type": "int",
-        "needs": ["traefik_enabled=false"],
-        "default": 8443,
-        "required": true
-      },
-      {
-        "name": "ports_ssh",
-        "description": "SSH port on host",
-        "type": "int",
-        "default": 22,
-        "required": true
-      },
-      {
-        "name": "ports_dns",
-        "description": "DNS port on host",
-        "type": "int",
-        "default": 53,
-        "required": true
-      },
-      {
-        "name": "ports_dhcp",
-        "description": "DHCP port on host",
-        "type": "int",
-        "default": 67,
-        "required": true
-      },
-      {
-        "name": "ports_smtp",
-        "description": "SMTP port on host",
-        "type": "int",
-        "default": 25,
-        "required": true
-      },
-      {
-        "name": "ports_snmp",
-        "description": "SNMP trap port",
-        "type": "int",
-        "default": 162,
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "traefik",
-    "title": "Traefik",
-    "toggle": "traefik_enabled",
-    "needs": ["network_mode!=host,macvlan"],
-    "description": "Traefik routes external traffic to your service.",
-    "vars": [
-      {
-        "name": "traefik_enabled",
-        "description": "Enable Traefik reverse proxy integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "traefik_network",
-        "description": "Traefik network name",
-        "type": "str",
-        "default": "traefik",
-        "required": true
-      },
-      {
-        "name": "traefik_host",
-        "description": "Service subdomain or full hostname (e.g., 'app' or 'app.example.com')",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "traefik_domain",
-        "description": "Base domain (e.g., example.com)",
-        "type": "str",
-        "default": "home.arpa",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "traefik_tls",
-    "title": "Traefik TLS/SSL",
-    "toggle": "traefik_tls_enabled",
-    "needs": ["traefik_enabled=true", "network_mode!=host,macvlan"],
-    "description": "Enable HTTPS/TLS for Traefik with certificate management.",
-    "vars": [
-      {
-        "name": "traefik_tls_enabled",
-        "description": "Enable HTTPS/TLS",
-        "type": "bool",
-        "default": true
-      },
-      {
-        "name": "traefik_tls_certresolver",
-        "description": "Traefik certificate resolver name",
-        "type": "str",
-        "default": "cloudflare",
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "volume",
-    "title": "Volume Storage",
-    "description": "Configure persistent storage for your service.",
-    "vars": [
-      {
-        "name": "volume_mode",
-        "description": "Volume storage backend",
-        "type": "enum",
-        "options": ["local", "mount", "nfs"],
-        "default": "local",
-        "required": true
-      },
-      {
-        "name": "volume_mount_path",
-        "description": "Host path for bind mounts",
-        "type": "str",
-        "default": "/mnt/storage",
-        "needs": ["volume_mode=mount"],
-        "required": true
-      },
-      {
-        "name": "volume_nfs_server",
-        "description": "NFS server address",
-        "type": "str",
-        "default": "192.168.1.1",
-        "needs": ["volume_mode=nfs"],
-        "required": true
-      },
-      {
-        "name": "volume_nfs_path",
-        "description": "NFS export path",
-        "type": "str",
-        "default": "/export",
-        "needs": ["volume_mode=nfs"],
-        "required": true
-      },
-      {
-        "name": "volume_nfs_options",
-        "description": "NFS mount options (comma-separated)",
-        "type": "str",
-        "default": "rw,nolock,soft",
-        "needs": ["volume_mode=nfs"],
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "resources",
-    "title": "Resource Limits",
-    "toggle": "resources_enabled",
-    "description": "Set CPU and memory limits for the service.",
-    "vars": [
-      {
-        "name": "resources_enabled",
-        "description": "Enable resource limits",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "resources_cpu_limit",
-        "description": "Maximum CPU cores (e.g., 0.5, 1.0, 2.0)",
-        "type": "str",
-        "default": "1.0",
-        "required": true
-      },
-      {
-        "name": "resources_cpu_reservation",
-        "description": "Reserved CPU cores",
-        "type": "str",
-        "default": "0.25",
-        "needs": ["swarm_enabled=true"],
-        "required": true
-      },
-      {
-        "name": "resources_memory_limit",
-        "description": "Maximum memory (e.g., 512M, 1G, 2G)",
-        "type": "str",
-        "default": "1G",
-        "required": true
-      },
-      {
-        "name": "resources_memory_reservation",
-        "description": "Reserved memory",
-        "type": "str",
-        "default": "512M",
-        "needs": ["swarm_enabled=true"],
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "swarm",
-    "title": "Docker Swarm",
-    "toggle": "swarm_enabled",
-    "needs": ["network_mode!=host,macvlan"],
-    "description": "Deploy service in Docker Swarm mode.",
-    "vars": [
-      {
-        "name": "swarm_enabled",
-        "description": "Enable Docker Swarm mode",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "swarm_placement_mode",
-        "description": "Swarm placement mode",
-        "type": "enum",
-        "options": ["replicated", "global"],
-        "default": "replicated",
-        "required": true
-      },
-      {
-        "name": "swarm_replicas",
-        "description": "Number of replicas",
-        "type": "int",
-        "default": 1,
-        "needs": ["swarm_placement_mode=replicated"],
-        "required": true
-      },
-      {
-        "name": "swarm_placement_host",
-        "description": "Target hostname for placement constraint",
-        "type": "str",
-        "default": "",
-        "needs": ["swarm_placement_mode=replicated"],
-        "extra": "Constrains service to run on specific node by hostname"
-      }
-    ]
-  },
-  {
-    "key": "database",
-    "title": "Database",
-    "toggle": "database_enabled",
-    "description": "Connect to external database (PostgreSQL or MySQL)",
-    "vars": [
-      {
-        "name": "database_enabled",
-        "description": "Enable external database integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "database_type",
-        "description": "Database type",
-        "type": "enum",
-        "options": ["sqlite", "postgres", "mysql"],
-        "default": "sqlite",
-        "required": true
-      },
-      {
-        "name": "database_external",
-        "description": "Use an external database server?",
-        "extra": "skips creation of internal database container",
-        "type": "bool",
-        "needs": ["database_type=postgres,mysql"],
-        "default": false
-      },
-      {
-        "name": "database_host",
-        "description": "Database host",
-        "type": "str",
-        "needs": ["database_external=true"],
-        "default": "database",
-        "required": true
-      },
-      {
-        "name": "database_port",
-        "description": "Database port",
-        "type": "int",
-        "required": true
-      },
-      {
-        "name": "database_name",
-        "description": "Database name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "database_user",
-        "description": "Database user",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "database_password",
-        "description": "Database password",
-        "type": "str",
-        "default": "",
-        "sensitive": true,
-        "autogenerated": true,
-        "required": true
-      }
-    ]
-  },
-  {
-    "key": "email",
-    "title": "Email Server",
-    "toggle": "email_enabled",
-    "description": "Configure email server for notifications and user management.",
-    "vars": [
-      {
-        "name": "email_enabled",
-        "description": "Enable email server configuration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "email_host",
-        "description": "SMTP server hostname",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_port",
-        "description": "SMTP server port",
-        "type": "int",
-        "default": 25,
-        "required": true
-      },
-      {
-        "name": "email_username",
-        "description": "SMTP username",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "email_password",
-        "description": "SMTP password",
-        "type": "str",
-        "sensitive": true,
-        "required": true
-      },
-      {
-        "name": "email_from",
-        "description": "From email address",
-        "type": "email",
-        "required": true
-      },
-      {
-        "name": "email_encryption",
-        "description": "Email encryption method to use",
-        "type": "enum",
-        "options": ["none", "starttls", "ssl"]
-      }
-    ]
-  },
-  {
-    "key": "authentik",
-    "title": "Authentik SSO",
-    "toggle": "authentik_enabled",
-    "description": "Integrate with Authentik for Single Sign-On authentication.",
-    "vars": [
-      {
-        "name": "authentik_enabled",
-        "description": "Enable Authentik SSO integration",
-        "type": "bool",
-        "default": false
-      },
-      {
-        "name": "authentik_url",
-        "description": "Authentik base URL (e.g., https://auth.example.com)",
-        "type": "url",
-        "required": true
-      },
-      {
-        "name": "authentik_slug",
-        "description": "Authentik application slug",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "authentik_traefik_middleware",
-        "description": "Traefik middleware name for Authentik authentication",
-        "type": "str",
-        "default": "authentik-middleware@file",
-        "needs": ["traefik_enabled=true"],
-        "required": true
-      }
-    ]
-  }
-]

+ 0 - 14
library/schemas/helm/v1.0.json

@@ -1,14 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "playbook_name",
-        "description": "Ansible playbook name",
-        "type": "str"
-      }
-    ]
-  }
-]

+ 0 - 14
library/schemas/kubernetes/v1.0.json

@@ -1,14 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "playbook_name",
-        "description": "Ansible playbook name",
-        "type": "str"
-      }
-    ]
-  }
-]

+ 0 - 14
library/schemas/packer/v1.0.json

@@ -1,14 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "playbook_name",
-        "description": "Ansible playbook name",
-        "type": "str"
-      }
-    ]
-  }
-]

+ 0 - 28
library/schemas/script/v1.0.json

@@ -1,28 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "script_name",
-        "description": "Script name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "script_type",
-        "description": "Script type/runtime",
-        "type": "enum",
-        "options": ["bash", "python"],
-        "default": "bash",
-        "required": true
-      },
-      {
-        "name": "description",
-        "description": "Script description",
-        "type": "str"
-      }
-    ]
-  }
-]

+ 0 - 36
library/schemas/terraform/v1.0.json

@@ -1,36 +0,0 @@
-[
-  {
-    "key": "general",
-    "title": "General",
-    "required": true,
-    "vars": [
-      {
-        "name": "project_name",
-        "description": "Terraform project name",
-        "type": "str",
-        "required": true
-      },
-      {
-        "name": "description",
-        "description": "Project description",
-        "type": "str"
-      }
-    ]
-  },
-  {
-    "key": "providers",
-    "title": "Providers",
-    "description": "Terraform provider configuration",
-    "required": true,
-    "vars": [
-      {
-        "name": "providers",
-        "description": "Required Terraform providers (JSON array of {name, version})",
-        "type": "str",
-        "required": true,
-        "default": "[]",
-        "extra": "JSON array of provider objects, e.g., [{\"name\":\"aws\",\"version\":\"~> 5.0\"}]"
-      }
-    ]
-  }
-]