# Development Guide

Comprehensive guide for maintaining and extending Athenix.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Development Workflow](#development-workflow)
- [Testing Changes](#testing-changes)
- [Continuous Integration](#continuous-integration)
- [Common Tasks](#common-tasks)
- [Debugging](#debugging)
- [Troubleshooting](#troubleshooting)

## Prerequisites

### Install Nix with Flakes

```bash
# Recommended: Determinate Systems installer
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

# Or official installer
sh <(curl -L https://nixos.org/nix/install) --daemon

# Enable flakes in existing installation
mkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf
```

### Clone Repository

```bash
git clone https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git
cd athenix

# Optional: enable direnv for automatic Nix environment
direnv allow
```

## Development Workflow

### Making Changes

1. **Edit configuration files** - Modify `inventory.nix`, `users.nix`, or host/software config

2. **Validate** - Check syntax and configuration

```bash
nix flake check
```

3. **Format code** - Apply consistent formatting

```bash
nix fmt
```

4. **Test** - Build specific artifacts or configurations

```bash
# Test specific host
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel

# Or build an artifact
nix build .#installer-iso-nix-laptop1
```

5. **Commit and push**

```bash
git add .
git commit -m "Brief description of changes"
git push
```

### Example: Adding a New User

1. Define user in `users.nix`:

```nix
athenix.users.newuser = {
  description = "New User";
  extraGroups = [ "wheel" "networkmanager" ];
  shell = pkgs.zsh;
  hashedPassword = "...";  # mkpasswd -m sha-512
};
```

2. Enable on fleet in `inventory.nix`:

```nix
nix-laptop = {
  devices = 5;
  overrides.athenix.users.newuser.enable = true;
};
```

3. Validate and commit:

```bash
nix flake check
nix fmt
git add . && git commit -m "Add newuser account"
git push
```

## Testing Changes

### Validate Configuration Syntax

Always run before committing:

```bash
nix flake check
```

Shows any configuration errors across all ~50+ hosts. Output:

```
checking 50 configurations...
✓ All checks passed
```

### Test Specific Host Build

```bash
# Build specific host (shows if config actually compiles)
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel

# Shorter form
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel -L
```

### Test Installer Build

```bash
# Test that installer ISO builds
nix build .#installer-iso-nix-laptop1 -L
```

### Test on Running NixOS System

If you're on a NixOS system managed by Athenix:

```bash
# Test changes temporarily (won't survive reboot)
sudo nixos-rebuild test --flake .

# Apply and switch (persistent)
sudo nixos-rebuild switch --flake .

# Build without switching
sudo nixos-rebuild build --flake .

# Show what will change
sudo nixos-rebuild dry-activate --flake .
```

### Rollback

If a build breaks your system:

```bash
# List recent generations
nix-env --list-generations

# Rollback to previous generation
nix-env --rollback

# Or switch to specific generation
nix-env --switch-generation 42
```

## Continuous Integration

### CI Pipeline

All pushes and pull requests trigger automated tests on the self-hosted `nix-builder`:

1. **Flake Check** - `nix flake check` validates all 50+ configurations
2. **Format Check** - Verifies code formatted with `nix fmt`
3. **Build Key Hosts** - Builds `nix-builder`, `nix-laptop1`, `nix-desktop1`
4. **Build Artifacts** - Tests `lxc-nix-builder` and `installer-iso-nix-laptop1`

### Viewing CI Status

```bash
# Web interface
https://git.factory.uga.edu/UGA-Innovation-Factory/athenix/actions

# Or check locally
git log --oneline -n 5
# Look for ✓ or ✗ next to commits
```

### Running CI Checks Locally

Test before pushing:

```bash
# Flake check
nix flake check --show-trace

# Format check
nix fmt --check

# Format code
nix fmt **/*.nix

# Build key configurations
nix build .#nixosConfigurations.nix-builder.config.system.build.toplevel -L
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel -L
```

## Common Tasks

### Adding a New Host

Edit `inventory.nix`:

```nix
nix-surface = {
  devices = 3;  # Creates nix-surface1, nix-surface2, nix-surface3
  overrides = {
    athenix.sw.type = "tablet-kiosk";
    athenix.sw.kioskUrl = "https://dashboard.example.com";
  };
};
```

Test:

```bash
nix flake check
nix build .#installer-iso-nix-surface1 -L
```

### Modifying Software Configuration

Edit appropriate file in `sw/`:

```bash
# Desktop software
vim sw/desktop/programs.nix

# Or for all systems
vim sw/default.nix
```

Use `athenix.sw.extraPackages` for host-specific additions:

```nix
nix-laptop = {
  devices = 5;
  overrides.athenix.sw.extraPackages = with pkgs; [ special-tool ];
};
```

### Adding a System Type

Create new type in `sw/`:

```bash
mkdir -p sw/my-type
touch sw/my-type/{default.nix,programs.nix,services.nix}
```

Then reference in `sw/default.nix`:

```nix
{
  imports = [
    ./my-type/default.nix
    # ... other types
  ];
}
```

### Using External Configurations

For user dotfiles:

```nix
# users.nix
athenix.users.myuser.external = builtins.fetchGit {
  url = "https://git.factory.uga.edu/username/dotfiles";
  rev = "abc123...";  # Pin to commit
};
```

For system config:

```nix
# inventory.nix
nix-lxc = {
  devices."server".external = builtins.fetchGit {
    url = "https://git.factory.uga.edu/org/server-config";
    rev = "abc123...";
  };
};
```

### Updating Dependencies

```bash
# Update all flake inputs
nix flake update

# Update specific input
nix flake update nixpkgs

# Show what changed
git diff flake.lock

# Test after update
nix flake check --show-trace

# If tests pass, commit
git add flake.lock && git commit -m "Update dependencies"
```

## Debugging

### Verbose Output

Get detailed error messages:

```bash
# Show full error traces
nix flake check --show-trace

# With maximum verbosity
nix build .#installer-iso-nix-laptop1 -vvv

# Show build log
nix build .#installer-iso-nix-laptop1 -L
```

### Inspect Configuration

```bash
# Evaluate configuration for specific host
nix eval .#nixosConfigurations.nix-laptop1.config.athenix.sw --json

# Get all host names
nix eval .#nixosConfigurations --apply builtins.attrNames

# Check specific option
nix eval .#nixosConfigurations.nix-laptop1.config.users.users
```

### Test Module Loading

```bash
# Evaluate specific module
nix-build -A nixosConfigurations.nix-laptop1.config.system.build.toplevel

# Or with flakes
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel --verbose
```

### Check Derivation Dependencies

```bash
# Show what dependencies a build needs
nix show-derivation .#installer-iso-nix-laptop1

# Or human-readable
nix build .#installer-iso-nix-laptop1 --dry-run
```

## Troubleshooting

### Common Errors

#### "Evaluation error"

```
error: evaluation aborted with the following error message: '...'
```

**Solution:** Check syntax in modified files. Use `nix fmt` and `nix flake check --show-trace`.

#### "Unknown variable" or "Option does not exist"

```
error: The option `athenix.xyz' does not exist.
```

**Solution:** Check NAMESPACE.md for available options. Options must be in `athenix.*` namespace.

#### "Hash mismatch" (for external modules)

```
error: Hash mismatch in fetched input
```

**Solution:** Update the pin. For `builtins.fetchGit`, use actual commit hash. Or:

```bash
nix flake update
```

#### Build runs out of memory

```bash
# Reduce parallel jobs
nix build . --max-jobs 1
```

#### "No such file or directory" in build

```bash
# Check path exists
ls -la /path/to/file

# Or check relative to repo
ls -la sw/my-file.nix
```

### Helpful Diagnostics

```bash
# List all hosts
nix eval .#nixosConfigurations --apply builtins.attrNames

# Show flake structure
nix flake show | head -50

# Check Nix store size
du -sh /nix/store

# List top space users in store
nix store du --human-readable | head -20

# Find store paths for a package
nix store path-info -rS $(which some-package)
```

### Getting Help

1. **Check documentation** - Review relevant doc file
2. **Look at existing examples** - Check `inventory.nix` or `users.nix`
3. **Search for similar patterns** - `grep -r "athenix.option" .`
4. **Run tests locally** - `nix flake check --show-trace` with full output
5. **Review git history** - `git log --patch -- filename.nix`

## See Also

- [BUILDING.md](BUILDING.md) - Building artifacts
- [INVENTORY.md](INVENTORY.md) - Host configuration
- [NAMESPACE.md](NAMESPACE.md) - Configuration options
- [USER_CONFIGURATION.md](USER_CONFIGURATION.md) - User management
- [EXTERNAL_MODULES.md](EXTERNAL_MODULES.md) - External modules
- [README.md](../README.md) - Main documentation
