feat: complete monorepo structure with frontend and shared resources

- Add complete backend/ directory with full Django application
- Add frontend/ directory with Vite + TypeScript setup ready for Next.js
- Add comprehensive shared/ directory with:
  - Complete documentation and memory-bank archives
  - Media files and avatars (letters, park/ride images)
  - Deployment scripts and automation tools
  - Shared types and utilities
- Add architecture/ directory with migration guides
- Configure pnpm workspace for monorepo development
- Update .gitignore to exclude .django_tailwind_cli/ build artifacts
- Preserve all historical documentation in shared/docs/memory-bank/
- Set up proper structure for full-stack development with shared resources
This commit is contained in:
pacnpal
2025-08-23 18:40:07 -04:00
parent b0e0678590
commit d504d41de2
762 changed files with 142636 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
#!/usr/bin/env python3
"""
Validate autoinstall configuration against Ubuntu's schema.
This script provides basic validation to check if our autoinstall config
complies with the official schema structure.
"""
import yaml
import sys
from pathlib import Path
def load_autoinstall_config(template_path: str) -> dict:
"""Load the autoinstall configuration from the template file."""
with open(template_path, "r") as f:
content = f.read()
# Parse the cloud-config YAML
config = yaml.safe_load(content)
# Extract the autoinstall section
if "autoinstall" in config:
return config["autoinstall"]
else:
raise ValueError("No autoinstall section found in cloud-config")
def validate_required_fields(config: dict) -> list:
"""Validate required fields according to schema."""
errors = []
# Check version field (required)
if "version" not in config:
errors.append("Missing required field: version")
elif not isinstance(config["version"], int) or config["version"] != 1:
errors.append("Invalid version: must be integer 1")
return errors
def validate_identity_section(config: dict) -> list:
"""Validate identity section."""
errors = []
if "identity" in config:
identity = config["identity"]
required_fields = ["username", "hostname", "password"]
for field in required_fields:
if field not in identity:
errors.append(f"Identity section missing required field: {field}")
# Additional validation
if "username" in identity and not isinstance(identity["username"], str):
errors.append("Identity username must be a string")
if "hostname" in identity and not isinstance(identity["hostname"], str):
errors.append("Identity hostname must be a string")
return errors
def validate_network_section(config: dict) -> list:
"""Validate network section."""
errors = []
if "network" in config:
network = config["network"]
if "version" not in network:
errors.append("Network section missing required field: version")
elif network["version"] != 2:
errors.append("Network version must be 2")
return errors
def validate_keyboard_section(config: dict) -> list:
"""Validate keyboard section."""
errors = []
if "keyboard" in config:
keyboard = config["keyboard"]
if "layout" not in keyboard:
errors.append("Keyboard section missing required field: layout")
return errors
def validate_ssh_section(config: dict) -> list:
"""Validate SSH section."""
errors = []
if "ssh" in config:
ssh = config["ssh"]
if "install-server" in ssh and not isinstance(ssh["install-server"], bool):
errors.append("SSH install-server must be boolean")
if "authorized-keys" in ssh and not isinstance(ssh["authorized-keys"], list):
errors.append("SSH authorized-keys must be an array")
if "allow-pw" in ssh and not isinstance(ssh["allow-pw"], bool):
errors.append("SSH allow-pw must be boolean")
return errors
def validate_packages_section(config: dict) -> list:
"""Validate packages section."""
errors = []
if "packages" in config:
packages = config["packages"]
if not isinstance(packages, list):
errors.append("Packages must be an array")
else:
for i, package in enumerate(packages):
if not isinstance(package, str):
errors.append(f"Package at index {i} must be a string")
return errors
def validate_commands_sections(config: dict) -> list:
"""Validate early-commands and late-commands sections."""
errors = []
for section_name in ["early-commands", "late-commands"]:
if section_name in config:
commands = config[section_name]
if not isinstance(commands, list):
errors.append(f"{section_name} must be an array")
else:
for i, command in enumerate(commands):
if not isinstance(command, (str, list)):
errors.append(
f"{section_name} item at index {i} must be string or array"
)
elif isinstance(command, list):
for j, cmd_part in enumerate(command):
if not isinstance(cmd_part, str):
errors.append(
f"{section_name}[{i}][{j}] must be a string"
)
return errors
def validate_shutdown_section(config: dict) -> list:
"""Validate shutdown section."""
errors = []
if "shutdown" in config:
shutdown = config["shutdown"]
valid_values = ["reboot", "poweroff"]
if shutdown not in valid_values:
errors.append(f"Shutdown must be one of: {valid_values}")
return errors
def main():
"""Main validation function."""
template_path = Path(__file__).parent / "cloud-init-template.yaml"
if not template_path.exists():
print(f"Error: Template file not found at {template_path}")
sys.exit(1)
try:
# Load the autoinstall configuration
print(f"Loading autoinstall config from {template_path}")
config = load_autoinstall_config(str(template_path))
# Run validation checks
all_errors = []
all_errors.extend(validate_required_fields(config))
all_errors.extend(validate_identity_section(config))
all_errors.extend(validate_network_section(config))
all_errors.extend(validate_keyboard_section(config))
all_errors.extend(validate_ssh_section(config))
all_errors.extend(validate_packages_section(config))
all_errors.extend(validate_commands_sections(config))
all_errors.extend(validate_shutdown_section(config))
# Report results
if all_errors:
print("\n❌ Validation failed with the following errors:")
for error in all_errors:
print(f" - {error}")
sys.exit(1)
else:
print("\n✅ Autoinstall configuration validation passed!")
print("Configuration appears to comply with Ubuntu autoinstall schema.")
# Print summary of detected sections
sections = list(config.keys())
print(f"\nDetected sections: {', '.join(sorted(sections))}")
except Exception as e:
print(f"Error during validation: {e}")
sys.exit(1)
if __name__ == "__main__":
main()