xcad 9 месяцев назад
Родитель
Сommit
abb018d4b2
92 измененных файлов с 1321 добавлено и 872 удалено
  1. 31 5
      AGENTS.md
  2. 151 33
      cli/core/module.py
  3. 4 3
      cli/core/prompt.py
  4. 21 4
      cli/core/template.py
  5. 30 9
      cli/core/variables.py
  6. 0 20
      library/compose/alloy/compose.yaml.j2
  7. 21 0
      library/compose/alloy/template.yaml
  8. 0 13
      library/compose/ansiblesemaphore/compose.yaml.j2
  9. 21 0
      library/compose/ansiblesemaphore/template.yaml
  10. 0 48
      library/compose/authentik/compose.yaml.j2
  11. 21 0
      library/compose/authentik/template.yaml
  12. 0 13
      library/compose/bind9/compose.yaml.j2
  13. 21 0
      library/compose/bind9/template.yaml
  14. 0 13
      library/compose/cadvisor/compose.yaml.j2
  15. 21 0
      library/compose/cadvisor/template.yaml
  16. 0 13
      library/compose/checkmk/compose.yaml.j2
  17. 21 0
      library/compose/checkmk/template.yaml
  18. 0 13
      library/compose/clamav/compose.yaml.j2
  19. 21 0
      library/compose/clamav/template.yaml
  20. 0 13
      library/compose/dockge/compose.yaml.j2
  21. 21 0
      library/compose/dockge/template.yaml
  22. 0 14
      library/compose/gitea/compose.yaml.j2
  23. 21 0
      library/compose/gitea/template.yaml
  24. 0 14
      library/compose/gitlab-runner/compose.yaml.j2
  25. 21 0
      library/compose/gitlab-runner/template.yaml
  26. 0 14
      library/compose/gitlab/compose.yaml.j2
  27. 21 0
      library/compose/gitlab/template.yaml
  28. 0 20
      library/compose/grafana/compose.yaml.j2
  29. 22 0
      library/compose/grafana/template.yaml
  30. 0 14
      library/compose/heimdall/compose.yaml.j2
  31. 21 0
      library/compose/heimdall/template.yaml
  32. 0 14
      library/compose/homeassistant/compose.yaml.j2
  33. 21 0
      library/compose/homeassistant/template.yaml
  34. 0 13
      library/compose/homepage/compose.yaml.j2
  35. 21 0
      library/compose/homepage/template.yaml
  36. 0 20
      library/compose/homer/compose.yaml.j2
  37. 21 0
      library/compose/homer/template.yaml
  38. 0 46
      library/compose/influxdb/compose.yaml.j2
  39. 21 0
      library/compose/influxdb/template.yaml
  40. 0 13
      library/compose/loki/compose.yaml.j2
  41. 21 0
      library/compose/loki/template.yaml
  42. 0 13
      library/compose/mariadb/compose.yaml.j2
  43. 21 0
      library/compose/mariadb/template.yaml
  44. 0 77
      library/compose/n8n/compose.yaml.backup
  45. 0 21
      library/compose/n8n/compose.yaml.j2
  46. 21 0
      library/compose/n8n/template.yaml
  47. 0 43
      library/compose/nextcloud/compose.yaml.j2
  48. 21 0
      library/compose/nextcloud/template.yaml
  49. 0 13
      library/compose/nginxproxymanager/compose.yaml.j2
  50. 21 0
      library/compose/nginxproxymanager/template.yaml
  51. 0 22
      library/compose/nodeexporter/compose.yaml
  52. 9 0
      library/compose/nodeexporter/compose.yaml.j2
  53. 21 0
      library/compose/nodeexporter/template.yaml
  54. 0 13
      library/compose/openwebui/compose.yaml.j2
  55. 21 0
      library/compose/openwebui/template.yaml
  56. 0 13
      library/compose/passbolt/compose.yaml.j2
  57. 21 0
      library/compose/passbolt/template.yaml
  58. 0 46
      library/compose/pihole/compose.yaml.j2
  59. 21 0
      library/compose/pihole/template.yaml
  60. 0 28
      library/compose/portainer/compose.yaml.j2
  61. 21 0
      library/compose/portainer/template.yaml
  62. 0 28
      library/compose/postgres/compose.yaml.j2
  63. 22 0
      library/compose/postgres/template.yaml
  64. 0 13
      library/compose/prometheus/compose.yaml.j2
  65. 21 0
      library/compose/prometheus/template.yaml
  66. 0 13
      library/compose/promtail/compose.yaml.j2
  67. 21 0
      library/compose/promtail/template.yaml
  68. 0 13
      library/compose/teleport/compose.yaml.j2
  69. 21 0
      library/compose/teleport/template.yaml
  70. 18 0
      library/compose/traefik.authentik-middleware/middleware.yaml.j2
  71. 26 0
      library/compose/traefik.authentik-middleware/template.yaml
  72. 21 0
      library/compose/traefik.external-service/external-service.yaml.j2
  73. 17 0
      library/compose/traefik.external-service/router.yaml.j2
  74. 41 0
      library/compose/traefik.external-service/template.yaml
  75. 26 0
      library/compose/traefik.grafana/router.yaml.j2
  76. 15 0
      library/compose/traefik.guacamole/router.yaml.j2
  77. 6 0
      library/compose/traefik.ldap-middleware/middleware.yaml.j2
  78. 31 0
      library/compose/traefik.nextcloud/router.yaml.j2
  79. 23 0
      library/compose/traefik.pihole/router.yaml.j2
  80. 26 0
      library/compose/traefik.proxmox/router.yaml.j2
  81. 15 0
      library/compose/traefik.vaultwarden/router.yaml.j2
  82. 0 70
      library/compose/traefik/compose.yaml
  83. 36 0
      library/compose/traefik/compose.yaml.j2
  84. 37 0
      library/compose/traefik/template.yaml
  85. 0 13
      library/compose/twingate_connector/compose.yaml.j2
  86. 21 0
      library/compose/twingate_connector/template.yaml
  87. 0 13
      library/compose/uptimekuma/compose.yaml.j2
  88. 21 0
      library/compose/uptimekuma/template.yaml
  89. 0 13
      library/compose/wazuh/compose.yaml.j2
  90. 21 0
      library/compose/wazuh/template.yaml
  91. 0 25
      library/compose/whoami/compose.yaml.j2
  92. 21 0
      library/compose/whoami/template.yaml

+ 31 - 5
AGENTS.md

@@ -102,6 +102,37 @@ library/compose/my-nginx-template/
     └── README.md
 ```
 
+#### Sub-Templates
+
+Sub-templates are specialized templates that use dot notation in their directory names to create related template variations or components. They provide a way to organize templates hierarchically and create focused, reusable configurations.
+
+**Directory Naming Convention:**
+- Sub-templates use dot notation: `parent.sub-name`
+- Example: `traefik.authentik-middleware`, `traefik.external-service`
+- The parent name should match an existing template for logical grouping
+
+**Visibility:**
+- By default, sub-templates are hidden from the standard `list` command
+- Use `list --all` to show all templates including sub-templates
+- This keeps the default view clean while providing access to specialized templates
+
+**Usage Examples:**
+```bash
+# Show only main templates (default behavior)
+python3 -m cli compose list
+
+# Show all templates including sub-templates
+python3 -m cli compose list --all
+
+# Generate a sub-template
+python3 -m cli compose generate traefik.authentik-middleware
+```
+
+**Common Use Cases:**
+- Configuration variations (e.g., `service.production`, `service.development`)
+- Component templates (e.g., `traefik.middleware`, `traefik.router`)
+- Environment-specific templates (e.g., `app.docker`, `app.kubernetes`)
+
 #### Variables
 
 Variables are a cornerstone of the CLI, allowing for dynamic and customizable template generation. They are defined and processed with a clear precedence and logic.
@@ -153,14 +184,9 @@ After creating the issue, update the TODO line in the `AGENTS.md` file with the
 
 ### Work in Progress
 
-* TODO[1242-secret-support] Consider creating a "secret" variable type that automatically handles sensitive data and masks input during prompts, which also should be set via .env file and not directly in the compose files or other templates.
-* TODO[1244-mask-secrets] Mask secrets in rendering output (e.g. when displaying the final docker-compose file, mask secret values)
-* TODO[1245-out-directory] Add support for --out to specify a directory
-* TODO[1246-validation-rules] Add support for more complex validation rules for environment variables, such as regex patterns or value ranges.
 * TODO[1247-user-overrides] Add configuration support to allow users to override module and template spec with their own (e.g. defaults -> compose -> spec -> general ...)
 * TODO[1248-installation-script] Add an installation script when cloning the repo and setup necessary commands
 * TODO[1249-update-script] Add an automatic update script to keep the tool up-to-date with the latest version from the repository.
 * TODO[1250-compose-deploy] Add compose deploy command to deploy a generated compose project to a local or remote docker environment
 * TODO[1251-centralize-display-logic] Create a DisplayManager class to handle all rich rendering.
-* TODO[1252-simplify-variable-handling] Refactor Variable and VariableCollection classes to simplify validation and initialization.
 * TODO[1253-streamline-prompting] Refactor PromptHandler to streamline validation and default value logic.

+ 151 - 33
cli/core/module.py

@@ -3,11 +3,11 @@ from __future__ import annotations
 import logging
 from abc import ABC
 from pathlib import Path
-from typing import Any, Dict, List, Optional
+from typing import Any, Optional
 
 from rich.console import Console
 from rich.panel import Panel
-from rich.prompt import Prompt
+from rich.prompt import Confirm
 from rich.table import Table
 from rich.tree import Tree
 from typer import Argument, Context, Option, Typer
@@ -62,9 +62,6 @@ def parse_var_inputs(var_options: list[str], extra_args: list[str]) -> dict[str,
 
 class Module(ABC):
   """Streamlined base module that auto-detects variables from templates."""
-  
-  name: str | None = None
-  description: str | None = None
 
   def __init__(self) -> None:
     if not all([self.name, self.description]):
@@ -80,9 +77,13 @@ class Module(ABC):
   # SECTION: Public Commands
   # --------------------------
 
-  def list(self) -> list[Template]:
-    """List all templates."""
-    logger.debug(f"Listing templates for module '{self.name}'")
+  def list(
+    self, 
+    filter_name: Optional[str] = Argument(None, help="Filter templates by name (e.g., 'traefik' shows traefik.*)"),
+    all_templates: bool = Option(False, "--all", "-a", help="Show all templates including sub-templates")
+  ) -> list[Template]:
+    """List templates with optional filtering."""
+    logger.debug(f"Listing templates for module '{self.name}' with filter='{filter_name}', all={all_templates}")
     templates = []
 
     entries = self.libraries.find(self.name, sort_results=True)
@@ -94,30 +95,39 @@ class Module(ABC):
         logger.error(f"Failed to load template from {template_dir}: {exc}")
         continue
     
-    if templates:
-      logger.info(f"Listing {len(templates)} templates for module '{self.name}'")
+    # Apply filtering logic
+    filtered_templates = self._filter_templates(templates, filter_name, all_templates)
+    
+    if filtered_templates:
+      # Group templates for hierarchical display
+      grouped_templates = self._group_templates(filtered_templates)
+      
+      logger.info(f"Listing {len(filtered_templates)} templates for module '{self.name}'")
       table = Table(title=f"{self.name.capitalize()} templates")
       table.add_column("ID", style="bold", no_wrap=True)
       table.add_column("Name")
       table.add_column("Description")
       table.add_column("Version", no_wrap=True)
-      table.add_column("Tags")
       table.add_column("Library", no_wrap=True)
 
-      for template in templates:
+      for template_info in grouped_templates:
+        template = template_info['template']
+        indent = template_info['indent']
         name = template.metadata.name or 'Unnamed Template'
         desc = template.metadata.description or 'No description available'
         version = template.metadata.version or ''
-        tags_list = template.metadata.tags or []
-        tags = ", ".join(tags_list) if isinstance(tags_list, list) else str(tags_list)
         library = template.metadata.library or ''
-        table.add_row(template.id, name, desc, version, tags, library)
+
+        # Add indentation for sub-templates
+        template_id = f"{indent}{template.id}"
+        table.add_row(template_id, name, desc, version, library)
 
       console.print(table)
     else:
-      logger.info(f"No templates found for module '{self.name}'")
+      filter_msg = f" matching '{filter_name}'" if filter_name else ""
+      logger.info(f"No templates found for module '{self.name}'{filter_msg}")
 
-    return templates
+    return filtered_templates
 
   def show(
     self,
@@ -176,14 +186,23 @@ class Module(ABC):
       if template.variables:
         template.variables.validate_all()
       
-      rendered_files = template.render(variable_values)
+      rendered_files = template.render(template.variables)
       logger.info(f"Successfully rendered template '{id}'")
+      output_dir = out or Path(".")
+
+      # Check if the directory is empty and confirm overwrite if necessary
+      if output_dir.exists() and any(output_dir.iterdir()):
+        if interactive:
+          if not Confirm.ask(f"Output directory '{output_dir}' is not empty. Overwrite files?", default=False):
+            console.print("[yellow]Generation cancelled.[/yellow]")
+            return
+        else:
+          logger.warning(f"Output directory '{output_dir}' is not empty. Existing files may be overwritten.")
       
-      output_dir = out
-      if not output_dir:
-        output_dir_str = Prompt.ask("Enter output directory", default=".")
-        output_dir = Path(output_dir_str)
-      
+      # Create the output directory if it doesn't exist
+      output_dir.mkdir(parents=True, exist_ok=True)
+
+      # Write rendered files to the output directory
       for file_path, content in rendered_files.items():
         full_path = output_dir / file_path
         full_path.parent.mkdir(parents=True, exist_ok=True)
@@ -193,6 +212,13 @@ class Module(ABC):
       
       logger.info(f"Template written to directory: {output_dir}")
 
+      # If no output directory was specified, print the masked content to the console
+      if not out:
+        console.print("\n[bold]Rendered output (sensitive values masked):[/bold]")
+        masked_files = template.mask_sensitive_values(rendered_files, template.variables)
+        for file_path, content in masked_files.items():
+          console.print(Panel(content, title=file_path, border_style="green"))
+
     except Exception as e:
       logger.error(f"Error rendering template '{id}': {e}")
       console.print(f"[red]Error generating template: {e}[/red]")
@@ -226,6 +252,89 @@ class Module(ABC):
 
   # !SECTION
 
+  # --------------------------
+  # SECTION: Template Organization Methods
+  # --------------------------
+
+  def _filter_templates(self, templates: list[Template], filter_name: Optional[str], all_templates: bool) -> list[Template]:
+    """Filter templates based on name and sub-template visibility."""
+    filtered = []
+    
+    for template in templates:
+      template_id = template.id
+      is_sub_template = '.' in template_id
+      
+      # If we have a filter, apply it
+      if filter_name:
+        if is_sub_template:
+          # For sub-templates, check if they start with filter_name.
+          if template_id.startswith(f"{filter_name}."):
+            filtered.append(template)
+        else:
+          # For main templates, exact match
+          if template_id == filter_name:
+            filtered.append(template)
+      else:
+        # No filter - include based on all_templates flag
+        if not all_templates and is_sub_template:
+          continue
+        filtered.append(template)
+    
+    return filtered
+
+  def _group_templates(self, templates: list[Template]) -> list[dict]:
+    """Group templates hierarchically for display."""
+    grouped = []
+    main_templates = {}
+    sub_templates = []
+    
+    # Separate main templates and sub-templates
+    for template in templates:
+      if '.' in template.id:
+        sub_templates.append(template)
+      else:
+        main_templates[template.id] = template
+        grouped.append({
+          'template': template,
+          'indent': '',
+          'is_main': True
+        })
+    
+    # Sort sub-templates by parent
+    sub_templates.sort(key=lambda t: t.id)
+    
+    # Insert sub-templates after their parents
+    for sub_template in sub_templates:
+      parent_name = sub_template.id.split('.')[0]
+      
+      # Find where to insert this sub-template
+      insert_index = -1
+      for i, item in enumerate(grouped):
+        if item['template'].id == parent_name:
+          # Find the last sub-template for this parent
+          j = i + 1
+          while j < len(grouped) and not grouped[j]['is_main']:
+            j += 1
+          insert_index = j
+          break
+      
+      sub_name = sub_template.id.split('.', 1)[1]  # Get part after first dot
+      sub_template_info = {
+        'template': sub_template,
+        'indent': '├─ ' if insert_index < len(grouped) - 1 else '└─ ',
+        'is_main': False
+      }
+      
+      if insert_index >= 0:
+        grouped.insert(insert_index, sub_template_info)
+      else:
+        # Parent not found, add at end
+        grouped.append(sub_template_info)
+    
+    return grouped
+
+  # !SECTION
+
   # --------------------------
   # SECTION: Private Methods
   # --------------------------
@@ -249,12 +358,16 @@ class Module(ABC):
   def _display_template_details(self, template: Template, template_id: str) -> None:
     """Display template information panel and variables table."""
     
-    # Print the main panel
-    console.print(Panel(
-      f"[bold]{template.metadata.name or 'Unnamed Template'}[/bold]\n\n{template.metadata.description or 'No description available'}", 
-      title=f"Template: {template_id}", 
-      subtitle=f"Module: {self.name}"
-    ))
+    # Build metadata info text
+    info_lines = []
+    info_lines.append(f"{template.metadata.description or 'No description available'}")
+    info_lines.append("")  # Empty line
+    
+    # Print template information with simple heading
+    template_name = template.metadata.name or 'Unnamed Template'
+    console.print(f"[bold blue]{template_name} ({template_id} - [cyan]{template.metadata.version or 'Not specified'}[/cyan])[/bold blue]")
+    for line in info_lines:
+      console.print(line)
     
     # Build the file structure tree
     file_tree = Tree("[bold blue]Template File Structure:[/bold blue]")
@@ -289,11 +402,14 @@ class Module(ABC):
         console.print() # Add spacing
         console.print(file_tree) # Print the Tree object directly
 
-    if template.variables and template.variables._set:
+    if template.variables and template.variables.has_sections():
       console.print()  # Add spacing
       
+      # Print variables heading
+      console.print(f"[bold blue]Template Variables:[/bold blue]")
+      
       # Create variables table
-      variables_table = Table(title="Template Variables", show_header=True, header_style="bold blue")
+      variables_table = Table(show_header=True, header_style="bold blue")
       variables_table.add_column("Variable", style="cyan", no_wrap=True)
       variables_table.add_column("Type", style="magenta")
       variables_table.add_column("Default", style="green")
@@ -302,7 +418,7 @@ class Module(ABC):
       
       # Add variables grouped by section
       first_section = True
-      for section_key, section in template.variables._set.items():
+      for section_key, section in template.variables.get_sections().items():
         if section.variables:
           # Add spacing between sections (except before first section)
           if not first_section:
@@ -348,7 +464,9 @@ class Module(ABC):
             
             # Format default value
             default_val = str(variable.value) if variable.value is not None else ""
-            if len(default_val) > 30:
+            if variable.sensitive:
+              default_val = "********"
+            elif len(default_val) > 30:
               default_val = default_val[:27] + "..."
             
             variables_table.add_row(

+ 4 - 3
cli/core/prompt.py

@@ -41,7 +41,7 @@ class PromptHandler:
     collected: Dict[str, Any] = {}
 
     # Process each section
-    for section_key, section in variables._set.items():
+    for section_key, section in variables.get_sections().items():
       if not section.variables:
         continue
 
@@ -127,17 +127,18 @@ class PromptHandler:
       "int": self._prompt_int,
       "enum": lambda text, default: self._prompt_enum(text, variable.options or [], default),
     }
-    return handlers.get(variable.type, self._prompt_string)
+    return handlers.get(variable.type, lambda text, default: self._prompt_string(text, default, is_sensitive=variable.sensitive))
 
   def _show_validation_error(self, message: str) -> None:
     """Display validation feedback consistently."""
     self.console.print(f"[red]{message}[/red]")
 
-  def _prompt_string(self, prompt_text: str, default: Any = None) -> str:
+  def _prompt_string(self, prompt_text: str, default: Any = None, is_sensitive: bool = False) -> str:
     value = Prompt.ask(
       prompt_text,
       default=str(default) if default is not None else "",
       show_default=True,
+      password=is_sensitive
     )
     return value.strip() if value else ""
 

+ 21 - 4
cli/core/template.py

@@ -211,7 +211,11 @@ class Template:
       if "vars" in section_data and isinstance(section_data["vars"], dict):
         filtered_vars = {}
         for var_name, var_data in section_data["vars"].items():
-          if var_name in used_variables:
+          is_used = var_name in used_variables
+          is_sensitive = var_data.get("sensitive", False)
+          
+          # Include variables that are either used in templates OR marked as sensitive
+          if is_used or is_sensitive:
             module_has_var = var_name in module_specs.get(section_key, {}).get("vars", {})
             template_has_var = var_name in template_specs.get(section_key, {}).get("vars", {})
             
@@ -286,15 +290,16 @@ class Template:
       keep_trailing_newline=False,
     )
 
-  def render(self, variables: dict[str, Any]) -> Dict[str, str]:
+  def render(self, variables: VariableCollection) -> Dict[str, str]:
     """Render all .j2 files in the template directory."""
-    logger.debug(f"Rendering template '{self.id}' with variables: {variables}")
+    variable_values = variables.get_all_values()
+    logger.debug(f"Rendering template '{self.id}' with variables: {variable_values}")
     rendered_files = {}
     for template_file in self.template_files: # Iterate over TemplateFile objects
       if template_file.file_type == 'j2':
         try:
           template = self.jinja_env.get_template(str(template_file.relative_path)) # Use lazy-loaded jinja_env
-          rendered_content = template.render(**variables)
+          rendered_content = template.render(**variable_values)
           rendered_files[str(template_file.output_path)] = rendered_content
         except Exception as e:
           logger.error(f"Error rendering template file {template_file.relative_path}: {e}")
@@ -312,6 +317,18 @@ class Template:
               raise
           
     return rendered_files
+
+  def mask_sensitive_values(self, rendered_files: Dict[str, str], variables: VariableCollection) -> Dict[str, str]:
+    """Mask sensitive values in rendered files."""
+    masked_files = {}
+    sensitive_vars = variables.get_sensitive_variables()
+    
+    for file_path, content in rendered_files.items():
+      for var_name, var_value in sensitive_vars.items():
+        content = content.replace(str(var_value), "********")
+      masked_files[file_path] = content
+      
+    return masked_files
   
   # !SECTION
 

+ 30 - 9
cli/core/variables.py

@@ -53,6 +53,7 @@ class Variable:
     self.value: Any = data.get("value") if data.get("value") is not None else data.get("default")
     self.section: Optional[str] = data.get("section")
     self.origin: Optional[str] = data.get("origin")
+    self.sensitive: bool = data.get("sensitive", False)
 
     # Validate and convert the default/initial value if present
     if self.value is not None:
@@ -298,11 +299,20 @@ class VariableCollection:
       self._variable_map[var_name] = variable
 
   # -------------------------
-  # SECTION: Helper Methods
+  # SECTION: Public API Methods
   # -------------------------
 
-  # NOTE: These helper methods reduce code duplication across module.py and prompt.py
-  # by centralizing common variable collection operations
+  def get_sections(self) -> Dict[str, VariableSection]:
+    """Get all sections in the collection."""
+    return self._sections.copy()
+  
+  def get_section(self, key: str) -> Optional[VariableSection]:
+    """Get a specific section by its key."""
+    return self._sections.get(key)
+  
+  def has_sections(self) -> bool:
+    """Check if the collection has any sections."""
+    return bool(self._sections)
 
   def get_all_values(self) -> dict[str, Any]:
     """Get all variable values as a dictionary."""
@@ -313,6 +323,19 @@ class VariableCollection:
       all_values[var_name] = variable.get_typed_value()
     return all_values
 
+  def get_sensitive_variables(self) -> Dict[str, Any]:
+    """Get only the sensitive variables with their values."""
+    return {name: var.value for name, var in self._variable_map.items() if var.sensitive and var.value}
+
+  # !SECTION
+
+  # -------------------------
+  # SECTION: Helper Methods
+  # -------------------------
+
+  # NOTE: These helper methods reduce code duplication across module.py and prompt.py
+  # by centralizing common variable collection operations
+
   def apply_overrides(self, overrides: dict[str, Any], origin_suffix: str = " -> cli") -> list[str]:
     """Apply multiple variable overrides at once."""
     # NOTE: This method uses the _variable_map for a significant performance gain,
@@ -347,7 +370,7 @@ class VariableCollection:
     
     if errors:
       logger.warning(f"Some CLI overrides failed: {'; '.join(errors)}")
-    
+  
   def validate_all(self) -> None:
     """Validate all variables in the collection, skipping disabled sections."""
     for section in self._sections.values():
@@ -358,11 +381,9 @@ class VariableCollection:
           logger.debug(f"Skipping validation for disabled section: '{section.key}'")
           continue  # Skip this entire section
 
-      for var_name, variable in section.variables.items():
-        try:
-          variable.validate(variable.value)
-        except ValueError as e:
-          raise ValueError(f"Validation failed for variable '{var_name}': {e}") from e
+      # NOTE: Skip individual variable validation since we removed the validate method
+      # All validation now happens during conversion in the Variable.convert() method
+      pass
 
   # !SECTION
 

+ 0 - 20
library/compose/alloy/compose.yaml → library/compose/alloy/compose.yaml.j2

@@ -1,23 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Grafana Alloy"
-  description: "A lightweight and flexible service mesh"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "grafana"
-    - "alloy"
-    - "monitoring"
-    - "http"
-    - "traefik"
-variables:
-  container_hostname:
-    description: "Sets the container's internal hostname (this will show up in the collected logs)"
-    type: "string"
-    required: true
----
 services:
   {{ service_name | default("alloy") }}:
     image: grafana/alloy:v1.10.2

+ 21 - 0
library/compose/alloy/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Alloy
+  description: Docker compose setup for alloy
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - alloy
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      alloy_version:
+        type: string
+        description: Alloy version
+        default: latest
+
+---

+ 0 - 13
library/compose/ansiblesemaphore/compose.yaml → library/compose/ansiblesemaphore/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Ansible Semaphore"
-  description: "A powerful and flexible automation tool"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "ansible"
-    - "automation"
-    - "semaphore"
----
 volumes:
   semaphore-mysql:
     driver: local

+ 21 - 0
library/compose/ansiblesemaphore/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Volumes
+  description: Docker compose setup for volumes
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - volumes
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      volumes_version:
+        type: string
+        description: Volumes version
+        default: latest
+
+---

+ 0 - 48
library/compose/authentik/compose.yaml → library/compose/authentik/compose.yaml.j2

@@ -1,51 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Authentik"
-  description: "An open-source identity and access management solution"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "authentik"
-    - "identity"
-    - "access"
-    - "management"
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for Authentik web interface"
-        type: int
-        default: 9000
-      ports_https:
-        description: "HTTPS port for Authentik web interface"
-        type: int
-        default: 9443
-  authentik:
-    vars:
-      authentik_secret_key:
-        description: "Authentik secret key (generate with: openssl rand -base64 32)"
-        type: str
-        default: ""
-      authentik_error_reporting:
-        description: "Enable Authentik error reporting"
-        type: bool
-        default: false
-  database:
-    required: true
-    vars:
-      database_external:
-        description: "Use an external database (if true, the internal postgres service will not be created)"
-        type: bool
-        default: false
-  email:
-    vars:
-      email_timeout:
-        description: "Email timeout in seconds"
-        type: int
-        default: 10
----
 services:
   {{ service_name | default('authentik-server') }}:
     image: ghcr.io/goauthentik/server:2025.6.3

+ 21 - 0
library/compose/authentik/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Authentik-Server
+  description: Docker compose setup for authentik-server
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - authentik-server
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      authentik-server_version:
+        type: string
+        description: Authentik-Server version
+        default: latest
+
+---

+ 0 - 13
library/compose/bind9/compose.yaml → library/compose/bind9/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "BIND9"
-  description: "A powerful and flexible DNS server"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "bind9"
-    - "dns"
-    - "server"
----
 services:
   bind9:
     image: docker.io/ubuntu/bind9:9.20-24.10_edge

+ 21 - 0
library/compose/bind9/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Bind9
+  description: Docker compose setup for bind9
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - bind9
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      bind9_version:
+        type: string
+        description: Bind9 version
+        default: latest
+
+---

+ 0 - 13
library/compose/cadvisor/compose.yaml → library/compose/cadvisor/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "cAdvisor"
-  description: "A tool for monitoring container performance"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "cadvisor"
-    - "monitoring"
-    - "containers"
----
 services:
   cadvisor:
     image: gcr.io/cadvisor/cadvisor:v0.52.1

+ 21 - 0
library/compose/cadvisor/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Cadvisor
+  description: Docker compose setup for cadvisor
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - cadvisor
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      cadvisor_version:
+        type: string
+        description: Cadvisor version
+        default: latest
+
+---

+ 0 - 13
library/compose/checkmk/compose.yaml → library/compose/checkmk/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Checkmk"
-  description: "A powerful monitoring solution"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "checkmk"
-    - "monitoring"
-    - "observability"
----
 services:
   monitoring:
     image: checkmk/check-mk-raw:2.4.0-latest

+ 21 - 0
library/compose/checkmk/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Monitoring
+  description: Docker compose setup for monitoring
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - monitoring
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      monitoring_version:
+        type: string
+        description: Monitoring version
+        default: latest
+
+---

+ 0 - 13
library/compose/clamav/compose.yaml → library/compose/clamav/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "ClamAV"
-  description: "An open-source antivirus engine"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "clamav"
-    - "antivirus"
-    - "security"
----
 services:
   clamav:
     image: docker.io/clamav/clamav:1.4.3

+ 21 - 0
library/compose/clamav/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Clamav
+  description: Docker compose setup for clamav
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - clamav
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      clamav_version:
+        type: string
+        description: Clamav version
+        default: latest
+
+---

+ 0 - 13
library/compose/dockge/compose.yaml → library/compose/dockge/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Dockge"
-  description: "A Docker GUI for managing your containers"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "dockge"
-    - "docker"
-    - "management"
----
 services:
   dockge:
     container_name: dockge

+ 21 - 0
library/compose/dockge/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Dockge
+  description: Docker compose setup for dockge
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - dockge
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      dockge_version:
+        type: string
+        description: Dockge version
+        default: latest
+
+---

+ 0 - 14
library/compose/gitea/compose.yaml → library/compose/gitea/compose.yaml.j2

@@ -1,17 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Gitea"
-  description: "A self-hosted Git service"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - gitea
-    - git
-    - code
-    - repository
----
 services:
   server:
     image: docker.io/gitea/gitea:1.24.5

+ 21 - 0
library/compose/gitea/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Server
+  description: Docker compose setup for server
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - server
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      server_version:
+        type: string
+        description: Server version
+        default: latest
+
+---

+ 0 - 14
library/compose/gitlab-runner/compose.yaml → library/compose/gitlab-runner/compose.yaml.j2

@@ -1,17 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "GitLab Runner"
-  description: "A self-hosted CI/CD automation tool"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - gitlab-runner
-    - ci
-    - cd
-    - automation
----
 services:
   gitlab-runner:
     image: docker.io/gitlab/gitlab-runner:alpine-v17.9.1

+ 21 - 0
library/compose/gitlab-runner/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Gitlab-Runner
+  description: Docker compose setup for gitlab-runner
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - gitlab-runner
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      gitlab-runner_version:
+        type: string
+        description: Gitlab-Runner version
+        default: latest
+
+---

+ 0 - 14
library/compose/gitlab/compose.yaml → library/compose/gitlab/compose.yaml.j2

@@ -1,17 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "GitLab"
-  description: "A self-hosted Git repository manager"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - gitlab
-    - git
-    - repository
-    - management
----
 services:
   gitlab:
     image: docker.io/gitlab/gitlab-ce:18.3.1-ce.0

+ 21 - 0
library/compose/gitlab/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Gitlab
+  description: Docker compose setup for gitlab
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - gitlab
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      gitlab_version:
+        type: string
+        description: Gitlab version
+        default: latest
+
+---

+ 0 - 20
library/compose/grafana/compose.yaml → library/compose/grafana/compose.yaml.j2

@@ -1,23 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Grafana"
-  description: "An open-source platform for monitoring and observability"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - grafana
-    - monitoring
-    - observability
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for Grafana web interface"
-        type: int
-        default: 3000
----
 services:
   {{ service_name | default('grafana') }}:
     image: docker.io/grafana/grafana-oss:12.1.1

+ 22 - 0
library/compose/grafana/template.yaml

@@ -0,0 +1,22 @@
+---
+kind: compose
+metadata:
+  name: Grafana
+  description: Open-source platform for monitoring and observability
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - grafana
+  - monitoring
+  - observability
+  - dashboard
+spec:
+  general:
+    vars:
+      grafana_version:
+        type: string
+        description: Grafana version
+        default: latest
+
+---

+ 0 - 14
library/compose/heimdall/compose.yaml → library/compose/heimdall/compose.yaml.j2

@@ -1,17 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Heimdall"
-  description: "An open-source dashboard for your web applications"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - heimdall
-    - dashboard
-    - monitoring
-    - observability
----
 services:
   heimdall:
     image: lscr.io/linuxserver/heimdall:2.7.4

+ 21 - 0
library/compose/heimdall/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Heimdall
+  description: Docker compose setup for heimdall
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - heimdall
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      heimdall_version:
+        type: string
+        description: Heimdall version
+        default: latest
+
+---

+ 0 - 14
library/compose/homeassistant/compose.yaml → library/compose/homeassistant/compose.yaml.j2

@@ -1,17 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Home Assistant"
-  description: "A self-hosted home automation platform"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - homeassistant
-    - automation
-    - monitoring
-    - observability
----
 services:
   homeassistant:
     container_name: homeassistant

+ 21 - 0
library/compose/homeassistant/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Homeassistant
+  description: Docker compose setup for homeassistant
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - homeassistant
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      homeassistant_version:
+        type: string
+        description: Homeassistant version
+        default: latest
+
+---

+ 0 - 13
library/compose/homepage/compose.yaml → library/compose/homepage/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Homepage"
-  description: "A self-hosted homepage for your web applications"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - homepage
-    - web
-    - dashboard
----
 services:
   homepage:
     image: ghcr.io/gethomepage/homepage:v1.4.6

+ 21 - 0
library/compose/homepage/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Homepage
+  description: Docker compose setup for homepage
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - homepage
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      homepage_version:
+        type: string
+        description: Homepage version
+        default: latest
+
+---

+ 0 - 20
library/compose/homer/compose.yaml → library/compose/homer/compose.yaml.j2

@@ -1,23 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Homer"
-  description: "A simple homepage for your services"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "homer"
-    - "http"
-    - "testing"
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for Homer web interface"
-        type: int
-        default: 8080
----
 services:
   {{ service_name | default('homer') }}:
     image: docker.io/b4bz/homer:v25.08.1

+ 21 - 0
library/compose/homer/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Homer
+  description: Docker compose setup for homer
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - homer
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      homer_version:
+        type: string
+        description: Homer version
+        default: latest
+
+---

+ 0 - 46
library/compose/influxdb/compose.yaml → library/compose/influxdb/compose.yaml.j2

@@ -1,49 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "InfluxDB"
-  description: "An open-source time series database"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - influxdb
-    - monitoring
-    - database
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for InfluxDB web interface and API"
-        type: int
-        default: 8086
-  influxdb:
-    vars:
-      influxdb_init_username:
-        description: "Initial InfluxDB admin username"
-        type: str
-        default: "admin"
-      influxdb_init_password:
-        description: "Initial InfluxDB admin password"
-        type: str
-        default: "password"
-      influxdb_init_org:
-        description: "Initial InfluxDB organization name"
-        type: str
-        default: "myorg"
-      influxdb_init_bucket:
-        description: "Initial InfluxDB bucket name"
-        type: str
-        default: "mybucket"
-      influxdb_init_retention:
-        description: "Data retention period (e.g., 1w, 30d, 1y)"
-        type: str
-        default: "0"
-      influxdb_init_token:
-        description: "Admin token for InfluxDB (leave empty for auto-generation)"
-        type: str
-        default: ""
----
 services:
   {{ service_name | default('influxdb') }}:
     container_name: {{ container_name | default('influxdb') }}

+ 21 - 0
library/compose/influxdb/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Influxdb
+  description: Docker compose setup for influxdb
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - influxdb
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      influxdb_version:
+        type: string
+        description: Influxdb version
+        default: latest
+
+---

+ 0 - 13
library/compose/loki/compose.yaml → library/compose/loki/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Loki"
-  description: "An open-source log aggregation system"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - loki
-    - monitoring
-    - logging
----
 services:
   loki:
     container_name: loki

+ 21 - 0
library/compose/loki/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Loki
+  description: Docker compose setup for loki
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - loki
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      loki_version:
+        type: string
+        description: Loki version
+        default: latest
+
+---

+ 0 - 13
library/compose/mariadb/compose.yaml → library/compose/mariadb/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "MariaDB"
-  description: "An open-source relational database management system"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - mariadb
-    - database
-    - sql
----
 # (Optional) when using custom network
 # networks:
 #   yournetwork:

+ 21 - 0
library/compose/mariadb/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Volumes
+  description: Docker compose setup for volumes
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - volumes
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      volumes_version:
+        type: string
+        description: Volumes version
+        default: latest
+
+---

+ 0 - 77
library/compose/n8n/compose.yaml.backup

@@ -1,77 +0,0 @@
----
-name: "n8n"
-description: "Workflow automation and integration tool"
-version: "0.0.1"
-date: "2025-09-03"
-author: "Christian Lempa"
-tags:
-  - n8n
-  - automation
-  - workflows
-  - compose
-variables:
-  template.custom_config:
-    description: "Custom configuration for n8n"
-    hint: "Additional environment variables or settings"
-    type: "string"
-    default: ""
----
-services:
-  {{ service_name }}:
-    image: n8nio/n8n:1.110.1
-    environment:
-      - N8N_LOG_LEVEL={{ container_loglevel | default('info') }}
-      - GENERIC_TIMEZONE={{ container_timezone }}
-      - TZ={{ container_timezone }}
-      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
-      - N8N_RUNNERS_ENABLED=true
-      {% if traefik %}
-      {% if traefik.tls %}
-      - N8N_EDITOR_BASE_URL=https://{{ traefik.host }}
-      {% else %}
-      - N8N_EDITOR_BASE_URL=http://{{ traefik.host }}
-      {% endif %}
-      {% endif %}
-      {% if postgres %}
-      - DB_TYPE=postgresdb
-      - DB_POSTGRESDB_HOST={{ postgres.host }}
-      - DB_POSTGRESDB_PORT=${DB_POSTGRESDB_PORT:-5432}
-      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
-      - DB_POSTGRESDB_USER=${POSTGRES_USER}
-      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
-      {% endif %}
-    volumes:
-      - /etc/localtime:/etc/localtime:ro
-      - data:/home/node/.n8n
-    {% if network %}
-    networks:
-      - {{ network.name | default('bridge') }}
-    {% endif %}
-    {% if traefik %}
-    labels:
-      - traefik.enable={{ traefik | default('true') }}
-      - traefik.http.routers.{{ service_name }}.rule=Host(`{{ traefik.host }}`)
-      {% if traefik.tls %}
-      - traefik.http.routers.{{ service_name }}.entrypoints={{ traefik.tls.entrypoint | default('websecure') }}
-      - traefik.http.routers.{{ service_name }}.tls=true
-      - traefik.http.routers.{{ service_name }}.tls.certresolver={{ traefik.tls.certresolver }}
-      {% else %}
-      - traefik.http.routers.{{ service_name }}.entrypoints={{ traefik.entrypoint | default('web') }}
-      {% endif %}
-      - traefik.http.services.{{ service_name }}.loadbalancer.server.port=5678
-    {% endif %}
-    restart: {{ restart_policy | default('unless-stopped') }}
-    {% if ports %}
-
-volumes:
-  data:
-    driver: local
-
-{% if network %}
-networks:
-  {{ network.name | default('bridge') }}:
-  {% if network.external %}
-    external: true
-  {% endif %}
-{% endif %}
-{% endif %}

+ 0 - 21
library/compose/n8n/compose.yaml → library/compose/n8n/compose.yaml.j2

@@ -1,24 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "n8n"
-  description: "Workflow automation and integration tool"
-  version: "0.0.1"
-  date: "2025-09-03"
-  author: "Christian Lempa"
-  tags:
-    - n8n
-    - automation
-    - workflows
-    - compose
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for n8n web interface"
-        type: int
-        default: 5678
----
 services:
   {{ service_name | default('n8n') }}:
     image: n8nio/n8n:1.110.1

+ 21 - 0
library/compose/n8n/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: N8N
+  description: Docker compose setup for n8n
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - n8n
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      n8n_version:
+        type: string
+        description: N8N version
+        default: latest
+
+---

+ 0 - 43
library/compose/nextcloud/compose.yaml → library/compose/nextcloud/compose.yaml.j2

@@ -1,46 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Nextcloud"
-  description: "A self-hosted file sync and share platform"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - nextcloud
-    - web
-    - file-storage
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for Nextcloud web interface"
-        type: int
-        default: 80
-  database:
-    vars:
-      database_type:
-        description: "Database type (mysql or postgres)"
-        type: enum
-        options: ["mysql", "postgres"]
-        default: "mysql"
-      mysql_user:
-        description: "MySQL username"
-        type: str
-        default: "nextcloud"
-      mysql_password:
-        description: "MySQL password"
-        type: str
-        default: "nextcloud"
-      mysql_database:
-        description: "MySQL database name"
-        type: str
-        default: "nextcloud"
-      mysql_root_password_random:
-        description: "Use random MySQL root password"
-        type: bool
-        default: true
----
 services:
   {{ service_name | default('nextcloud-app') }}:
     image: docker.io/library/nextcloud:31.0.8-apache

+ 21 - 0
library/compose/nextcloud/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Nextcloud-App
+  description: Docker compose setup for nextcloud-app
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - nextcloud-app
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      nextcloud-app_version:
+        type: string
+        description: Nextcloud-App version
+        default: latest
+
+---

+ 0 - 13
library/compose/nginxproxymanager/compose.yaml → library/compose/nginxproxymanager/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Nginx Proxy Manager"
-  description: "An open-source reverse proxy manager"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - nginx
-    - reverse-proxy
-    - web
----
 volumes:
   nginxproxymanager-data:
   nginxproxymanager-ssl:

+ 21 - 0
library/compose/nginxproxymanager/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Volumes
+  description: Docker compose setup for volumes
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - volumes
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      volumes_version:
+        type: string
+        description: Volumes version
+        default: latest
+
+---

+ 0 - 22
library/compose/nodeexporter/compose.yaml

@@ -1,22 +0,0 @@
----
-kind: "compose"
-metadata:
-  name: "Node Exporter"
-  description: "A Prometheus exporter for hardware and OS metrics"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - prometheus
-    - monitoring
-    - metrics
----
-services:
-  node_exporter:
-    image: quay.io/prometheus/node-exporter:v1.9.1
-    container_name: node_exporter
-    command: "--path.rootfs=/host"
-    pid: host
-    restart: unless-stopped
-    volumes:
-      - /:/host:ro,rslave

+ 9 - 0
library/compose/nodeexporter/compose.yaml.j2

@@ -0,0 +1,9 @@
+services:
+  node_exporter:
+    image: quay.io/prometheus/node-exporter:v1.9.1
+    container_name: node_exporter
+    command: "--path.rootfs=/host"
+    pid: host
+    restart: unless-stopped
+    volumes:
+      - /:/host:ro,rslave

+ 21 - 0
library/compose/nodeexporter/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Node_Exporter
+  description: Docker compose setup for node_exporter
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - node_exporter
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      node_exporter_version:
+        type: string
+        description: Node_Exporter version
+        default: latest
+
+---

+ 0 - 13
library/compose/openwebui/compose.yaml → library/compose/openwebui/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Open Web UI"
-  description: "A web-based user interface for managing various services"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - openwebui
-    - web
-    - user-interface
----
 services:
   openwebui:
     image: ghcr.io/open-webui/open-webui:v0.6.26

+ 21 - 0
library/compose/openwebui/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Openwebui
+  description: Docker compose setup for openwebui
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - openwebui
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      openwebui_version:
+        type: string
+        description: Openwebui version
+        default: latest
+
+---

+ 0 - 13
library/compose/passbolt/compose.yaml → library/compose/passbolt/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Passbolt"
-  description: "An open-source password manager"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - passbolt
-    - password-manager
-    - web
----
 volumes:
   passbolt-db:
   passbolt-data-gpg:

+ 21 - 0
library/compose/passbolt/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Volumes
+  description: Docker compose setup for volumes
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - volumes
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      volumes_version:
+        type: string
+        description: Volumes version
+        default: latest
+
+---

+ 0 - 46
library/compose/pihole/compose.yaml → library/compose/pihole/compose.yaml.j2

@@ -1,49 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Pi-hole"
-  description: "An open-source DNS sinkhole"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - pihole
-    - dns
-    - ad-blocker
-spec:
-  ports:
-    vars:
-      ports_dns_tcp:
-        description: "DNS TCP port"
-        type: int
-        default: 53
-      ports_dns_udp:
-        description: "DNS UDP port"
-        type: int
-        default: 53
-      ports_dhcp:
-        description: "DHCP port"
-        type: int
-        default: 67
-      ports_http:
-        description: "HTTP port for Pi-hole web interface"
-        type: int
-        default: 8081
-      ports_https:
-        description: "HTTPS port for Pi-hole web interface"
-        type: int
-        default: 8443
-  pihole:
-    vars:
-      pihole_webpassword:
-        description: "Pi-hole web admin password"
-        type: str
-        default: ""
-      pihole_dns_upstreams:
-        description: "Pi-hole upstream DNS servers"
-        type: str
-        default: "8.8.8.8;8.8.4.4"
----
 services:
   {{ service_name | default('pihole') }}:
     container_name: {{ container_name | default('pihole') }}

+ 21 - 0
library/compose/pihole/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Pihole
+  description: Docker compose setup for pihole
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - pihole
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      pihole_version:
+        type: string
+        description: Pihole version
+        default: latest
+
+---

+ 0 - 28
library/compose/portainer/compose.yaml → library/compose/portainer/compose.yaml.j2

@@ -1,31 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Portainer"
-  description: "An open-source container management tool"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - portainer
-    - container-management
-    - web
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for Portainer web interface"
-        type: int
-        default: 9000
-      ports_https:
-        description: "HTTPS port for Portainer web interface"
-        type: int
-        default: 9443
-      ports_edge:
-        description: "Edge agent port for Portainer"
-        type: int
-        default: 8000
----
 services:
   {{ service_name | default('portainer') }}:
     container_name: {{ container_name | default('portainer') }}

+ 21 - 0
library/compose/portainer/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Portainer
+  description: Docker compose setup for portainer
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - portainer
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      portainer_version:
+        type: string
+        description: Portainer version
+        default: latest
+
+---

+ 0 - 28
library/compose/postgres/compose.yaml → library/compose/postgres/compose.yaml.j2

@@ -1,31 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "PostgreSQL"
-  description: "An open-source relational database management system"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - postgres
-    - database
-    - sql
-spec:
-  postgres:
-    vars:
-      postgres_initdb_args:
-        description: "PostgreSQL initdb arguments"
-        type: str
-        default: "--data-checksums"
-      postgres_host_auth_method:
-        description: "PostgreSQL host authentication method"
-        type: str
-        default: ""
-      postgres_secrets_enabled:
-        description: "Use PostgreSQL secrets file for password"
-        type: bool
-        default: true
----
 services:
   {{ service_name | default('postgres') }}:
     image: docker.io/library/postgres:17.6

+ 22 - 0
library/compose/postgres/template.yaml

@@ -0,0 +1,22 @@
+---
+kind: compose
+metadata:
+  name: PostgreSQL
+  description: Advanced open-source relational database
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - postgresql
+  - database
+  - sql
+  - relational
+spec:
+  general:
+    vars:
+      postgres_version:
+        type: string
+        description: PostgreSQL version
+        default: latest
+
+---

+ 0 - 13
library/compose/prometheus/compose.yaml → library/compose/prometheus/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Prometheus"
-  description: "An open-source monitoring and alerting toolkit"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - prometheus
-    - monitoring
-    - alerting
----
 volumes:
   prometheus-data:
     driver: local

+ 21 - 0
library/compose/prometheus/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Volumes
+  description: Docker compose setup for volumes
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - volumes
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      volumes_version:
+        type: string
+        description: Volumes version
+        default: latest
+
+---

+ 0 - 13
library/compose/promtail/compose.yaml → library/compose/promtail/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Promtail"
-  description: "An open-source log collection agent"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - promtail
-    - logging
-    - grafana
----
 services:
   promtail:
     image: docker.io/grafana/promtail:3.5.3

+ 21 - 0
library/compose/promtail/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Promtail
+  description: Docker compose setup for promtail
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - promtail
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      promtail_version:
+        type: string
+        description: Promtail version
+        default: latest
+
+---

+ 0 - 13
library/compose/teleport/compose.yaml → library/compose/teleport/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Teleport"
-  description: "An open-source access plane for managing SSH access"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - teleport
-    - ssh
-    - access-management
----
 # -- (Optional) When using Traefik, use this section
 # networks:
 #   your-traefik-network:

+ 21 - 0
library/compose/teleport/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Teleport
+  description: Docker compose setup for teleport
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - teleport
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      teleport_version:
+        type: string
+        description: Teleport version
+        default: latest
+
+---

+ 18 - 0
library/compose/traefik.authentik-middleware/middleware.yaml.j2

@@ -0,0 +1,18 @@
+http:
+  middlewares:
+    {{ middleware_name }}:
+      forwardAuth:
+        address: {{ authentik_outpost_url }}/outpost.goauthentik.io/auth/traefik
+        trustForwardHeader: true
+        authResponseHeaders:
+          - X-authentik-username
+          - X-authentik-groups
+          - X-authentik-email
+          - X-authentik-name
+          - X-authentik-uid
+          - X-authentik-jwt
+          - X-authentik-meta-jwks
+          - X-authentik-meta-outpost
+          - X-authentik-meta-provider
+          - X-authentik-meta-app
+          - X-authentik-meta-version

+ 26 - 0
library/compose/traefik.authentik-middleware/template.yaml

@@ -0,0 +1,26 @@
+---
+kind: "compose"
+metadata:
+  name: "Traefik Authentik Middleware"
+  description: "Authentication middleware for Traefik using Authentik forward auth"
+  version: "0.1.0"
+  author: "Christian Lempa"
+  date: "2025-09-28"
+  tags:
+    - traefik
+    - authentik
+    - middleware
+    - authentication
+    - forward-auth
+spec:
+  general:
+    vars:
+      authentik_outpost_url:
+        type: "url"
+        description: "Authentik outpost URL"
+        default: "http://your-authentik-outpost-fqdn:9000"
+      middleware_name:
+        type: "string"
+        description: "Name of the middleware"
+        default: "authentik-middleware"
+---

+ 21 - 0
library/compose/traefik.external-service/external-service.yaml.j2

@@ -0,0 +1,21 @@
+http:
+  # Router Configuration
+  routers:
+    {{ service_name }}-router:
+      rule: "Host(`{{ service_host }}`)"
+      service: {{ service_name }}
+      priority: {{ router_priority }}
+      entryPoints:
+        - web
+        {% if tls_enabled %}
+        - websecure
+      tls:
+        certResolver: {{ cert_resolver }}
+        {% endif %}
+
+  # Service Configuration
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "{{ service_url }}"

+ 17 - 0
library/compose/traefik.external-service/router.yaml.j2

@@ -0,0 +1,17 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+      middlewares:
+        - {{ middleware_name }}@file
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "http://{{ backend_ip }}:{{ backend_port }}"

+ 41 - 0
library/compose/traefik.external-service/template.yaml

@@ -0,0 +1,41 @@
+---
+kind: "compose"
+metadata:
+  name: "Traefik External Service Config"
+  description: "Configuration for routing external services through Traefik"
+  version: "0.1.0"
+  author: "Christian Lempa"
+  date: "2025-09-28"
+  tags:
+    - traefik
+    - external-service
+    - routing
+    - config
+spec:
+  general:
+    vars:
+      service_name:
+        type: "string"
+        description: "Name of the external service"
+        default: "your-local-service"
+      service_host:
+        type: "hostname"
+        description: "Domain for the service (e.g., service.yourdomain.com)"
+        default: "your-service.your-domain.com"
+      service_url:
+        type: "url"
+        description: "URL of the external service"
+        default: "http://your-local-service:port"
+      router_priority:
+        type: "int"
+        description: "Router priority (higher = more precedence)"
+        default: 1000
+      tls_enabled:
+        type: "bool"
+        description: "Enable TLS/SSL"
+        default: true
+      cert_resolver:
+        type: "string"
+        description: "Certificate resolver name"
+        default: "cloudflare"
+---

+ 26 - 0
library/compose/traefik.grafana/router.yaml.j2

@@ -0,0 +1,26 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+      middlewares:
+{% if enable_auth_middleware %}
+        - {{ auth_middleware_name }}@file
+{% endif %}
+        - {{ service_name }}-headers
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "http://{{ grafana_backend_ip }}:{{ grafana_backend_port }}/"
+
+  middlewares:
+    {{ service_name }}-headers:
+      headers:
+        customRequestHeaders:
+          X-WEBAUTH-USER: "{{ grafana_username }}"

+ 15 - 0
library/compose/traefik.guacamole/router.yaml.j2

@@ -0,0 +1,15 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "http://{{ guacamole_backend_ip }}:{{ guacamole_backend_port }}/"

+ 6 - 0
library/compose/traefik.ldap-middleware/middleware.yaml.j2

@@ -0,0 +1,6 @@
+http:
+  middlewares:
+    {{ middleware_name }}:
+      forwardAuth:
+        address: "http://{{ ldap_auth_backend_ip }}:{{ ldap_auth_backend_port }}/auth"
+        trustForwardHeader: true

+ 31 - 0
library/compose/traefik.nextcloud/router.yaml.j2

@@ -0,0 +1,31 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+      middlewares:
+        - {{ service_name }}-dav
+        - {{ service_name }}-secure-headers
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "http://{{ nextcloud_backend_ip }}:{{ nextcloud_backend_port }}/"
+
+  middlewares:
+    {{ service_name }}-dav:
+      redirectRegex:
+        regex: "https://(.*)/.well-known/(?:card|cal)dav"
+        replacement: "https://${1}/remote.php/dav/"
+
+    {{ service_name }}-secure-headers:
+      headers:
+        accessControlMaxAge: 100
+        hostsProxyHeaders:
+          - "X-Forwarded-Host"
+        referrerPolicy: "same-origin"

+ 23 - 0
library/compose/traefik.pihole/router.yaml.j2

@@ -0,0 +1,23 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+      middlewares:
+        - {{ service_name }}-headers
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "http://{{ pihole_backend_ip }}:{{ pihole_backend_port }}/"
+
+  middlewares:
+    {{ service_name }}-headers:
+      headers:
+        customRequestHeaders:
+          Host: "{{ hostname }}"

+ 26 - 0
library/compose/traefik.proxmox/router.yaml.j2

@@ -0,0 +1,26 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+      middlewares:
+{% if enable_auth_middleware %}
+        - {{ auth_middleware_name }}@file
+{% endif %}
+        - {{ service_name }}-headers
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "https://{{ proxmox_backend_ip }}:{{ proxmox_backend_port }}/"
+
+  middlewares:
+    {{ service_name }}-headers:
+      headers:
+        customRequestHeaders:
+          Host: "{{ hostname }}"

+ 15 - 0
library/compose/traefik.vaultwarden/router.yaml.j2

@@ -0,0 +1,15 @@
+http:
+  routers:
+    {{ service_name }}:
+      rule: "Host(`{{ hostname }}`)"
+      entryPoints:
+        - https
+      tls:
+        certResolver: {{ cert_resolver }}
+      service: {{ service_name }}
+
+  services:
+    {{ service_name }}:
+      loadBalancer:
+        servers:
+          - url: "http://{{ vaultwarden_backend_ip }}:{{ vaultwarden_backend_port }}/"

+ 0 - 70
library/compose/traefik/compose.yaml

@@ -1,70 +0,0 @@
----
-kind: "compose"
-metadata:
-  name: "Traefik"
-  description: "An open-source edge router for microservices"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - traefik
-    - reverse-proxy
-    - load-balancer
-files:
-  - config/traefik.yaml
-spec:
-  traefik:
-    vars:
-      acme_email:
-        description: "Email address for ACME (Let's Encrypt) registration"
-        type: str
-        default: ""
-  database:
-    vars:
-      database_name:
-        description: "Name of the database"
-        type: str
-        default: ""
----
-services:
-  {{ service_name | default('traefik') }}:
-    image: docker.io/library/traefik:v3.5.1
-    container_name: {{ container_name | default('traefik') }}
-    {% if ports_enabled %}
-    ports:
-      - 80:80
-      - 443:443
-      # --> (Optional) Enable Dashboard, don't do in production
-      # - 8080:8080
-      # <--
-    {% endif %}
-    volumes:
-      - /run/docker.sock:/run/docker.sock:ro
-      - ./config/:/etc/traefik/:ro
-      - ./certs/:/var/traefik/certs/:rw
-    environment:
-      - TZ={{ container_timezone | default('UTC') }}
-      {% if acme_email -%}
-      - CF_DNS_API_TOKEN={{ acme_email }}
-      {% endif %}
-      {% if traefik_host -%}
-      - TRAEFIK_HOST={{ traefik_host }}
-      {% endif %}
-      {% if database_name -%}
-      - DB_NAME={{ database_name }}
-      {% endif %}
-    {% if network_enabled %}
-    networks:
-      - {{ network_name | default('frontend') }}
-    {% endif %}
-    restart: {{ restart_policy | default('unless-stopped') }}
-
-{% if network_enabled %}
-networks:
-  {{ network_name | default('frontend') }}:
-    {% if network_external %}
-    external: true
-    {% else %}
-    driver: bridge
-    {% endif %}
-{% endif %}

+ 36 - 0
library/compose/traefik/compose.yaml.j2

@@ -0,0 +1,36 @@
+services:
+  {{ service_name }}:
+    image: docker.io/library/traefik:{{ traefik_version }}
+    container_name: {{ container_name }}
+    {% if ports_enabled %}
+    ports:
+      - "80:80"
+      - "443:443"
+      {% if dashboard_enabled %}
+      - "8080:8080"  # Dashboard (don't use in production)
+      {% endif %}
+    {% endif %}
+    volumes:
+      - /var/run/docker.sock:/var/run/docker.sock:ro
+      - ./config/:/etc/traefik/:ro
+      - ./certs/:/var/traefik/certs/:rw
+    environment:
+      - TZ={{ container_timezone }}
+      {% if acme_email %}
+      - ACME_EMAIL={{ acme_email }}
+      {% endif %}
+    {% if network_enabled %}
+    networks:
+      - {{ network_name }}
+    {% endif %}
+    restart: {{ restart_policy }}
+
+{% if network_enabled %}
+networks:
+  {{ network_name }}:
+    {% if network_external %}
+    external: true
+    {% else %}
+    driver: bridge
+    {% endif %}
+{% endif %}

+ 37 - 0
library/compose/traefik/template.yaml

@@ -0,0 +1,37 @@
+---
+kind: "compose"
+metadata:
+  name: "Traefik"
+  description: "Modern reverse proxy and load balancer for microservices"
+  version: "0.1.0"
+  author: "Christian Lempa"
+  date: "2025-09-28"
+  tags:
+    - traefik
+    - reverse-proxy
+    - load-balancer
+    - edge-router
+spec:
+  general:
+    vars:
+      traefik_version:
+        type: "string"
+        description: "Traefik version"
+        default: "v3.5.1"
+      acme_email:
+        type: "email"
+        description: "Email address for ACME (Let's Encrypt) registration"
+        default: ""
+  ports:
+    prompt: "Expose ports via 'ports' mapping?"
+    toggle: "ports_enabled"
+    vars:
+      ports_enabled:
+        type: "bool"
+        description: "Expose ports via 'ports' mapping"
+        default: true
+      dashboard_enabled:
+        type: "bool"
+        description: "Enable Traefik dashboard (don't use in production)"
+        default: false
+---

+ 0 - 13
library/compose/twingate_connector/compose.yaml → library/compose/twingate_connector/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Twingate Connector"
-  description: "A connector for Twingate"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - twingate
-    - connector
-    - networking
----
 services:
   twingate_connector:
     container_name: twingate_connector

+ 21 - 0
library/compose/twingate_connector/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Twingate_Connector
+  description: Docker compose setup for twingate_connector
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - twingate_connector
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      twingate_connector_version:
+        type: string
+        description: Twingate_Connector version
+        default: latest
+
+---

+ 0 - 13
library/compose/uptimekuma/compose.yaml → library/compose/uptimekuma/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Uptime Kuma"
-  description: "A self-hosted status monitoring solution"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - uptime-kuma
-    - monitoring
-    - self-hosted
----
 volumes:
   uptimekuma-data:
     driver: local

+ 21 - 0
library/compose/uptimekuma/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Volumes
+  description: Docker compose setup for volumes
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - volumes
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      volumes_version:
+        type: string
+        description: Volumes version
+        default: latest
+
+---

+ 0 - 13
library/compose/wazuh/compose.yaml → library/compose/wazuh/compose.yaml.j2

@@ -1,16 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Wazuh"
-  description: "A security monitoring platform"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - wazuh
-    - security
-    - monitoring
----
 services:
   wazuh.manager:
     image: docker.io/wazuh/wazuh-manager:4.12.0

+ 21 - 0
library/compose/wazuh/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Wazuh.Manager
+  description: Docker compose setup for wazuh.manager
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - wazuh.manager
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      wazuh.manager_version:
+        type: string
+        description: Wazuh.Manager version
+        default: latest
+
+---

+ 0 - 25
library/compose/whoami/compose.yaml → library/compose/whoami/compose.yaml.j2

@@ -1,28 +1,3 @@
----
-kind: "compose"
-metadata:
-  name: "Whoami"
-  description: "Simple HTTP service that returns information about the request"
-  version: "0.0.1"
-  date: "2023-10-01"
-  author: "Christian Lempa"
-  tags:
-    - "traefik"
-    - "whoami"
-    - "http"
-    - "testing"
-spec:
-  ports:
-    vars:
-      ports_http:
-        description: "HTTP port for whoami service"
-        type: int
-        default: 8080
-      ports_https:
-        description: "HTTPS port for whoami service"
-        type: int
-        default: 8443
----
 services:
   {{ service_name | default('whoami') }}:
     image: traefik/whoami

+ 21 - 0
library/compose/whoami/template.yaml

@@ -0,0 +1,21 @@
+---
+kind: compose
+metadata:
+  name: Whoami
+  description: Docker compose setup for whoami
+  version: 0.1.0
+  author: Christian Lempa
+  date: '2025-09-28'
+  tags:
+  - whoami
+  - docker
+  - compose
+spec:
+  general:
+    vars:
+      whoami_version:
+        type: string
+        description: Whoami version
+        default: latest
+
+---