# User Configuration Guide

Comprehensive guide to managing user accounts in Athenix.

## Table of Contents

- [Overview](#overview)
- [Quick Start](#quick-start)
- [Defining Users](#defining-users)
- [Enabling Users on Hosts](#enabling-users-on-hosts)
- [External User Configurations](#external-user-configurations)
- [Password Management](#password-management)
- [SSH Keys](#ssh-keys)
- [User Groups](#user-groups)
- [Examples](#examples)

## Overview

User accounts are defined in `users.nix` but are **not enabled by default**. Each host must explicitly enable users in `inventory.nix`.

**Always-enabled users:**
- `root` - System administrator (enable: true)
- `engr-ugaif` - Innovation Factory default account (enable: true)

All other users are disabled by default and must be explicitly enabled per-host.

## Quick Start

### 1. Define User in users.nix

```nix
athenix.users.myuser = {
  description = "John Doe";
  extraGroups = [ "wheel" "networkmanager" ];
  shell = pkgs.zsh;
  hashedPassword = "$6$...";  # Generate with: mkpasswd -m sha-512
  opensshKeys = [ "ssh-ed25519 AAAA..." ];
};
```

### 2. Enable on Hosts in inventory.nix

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

### 3. Users can now log in

Users defined and enabled this way are automatically created on the system.

## Defining Users

Define users in `users.nix` under `athenix.users`:

### Inline User Definition

```nix
athenix.users.myuser = {
  description = "My Full Name";
  extraGroups = [ "wheel" "networkmanager" ];
  shell = pkgs.zsh;
  hashedPassword = "$6$...";
  opensshKeys = [ "ssh-ed25519 AAAA..." ];
  useZshTheme = true;
  useNvimPlugins = true;
};
```

### External User Configuration

Reference an external Git repository (recommended for personal dotfiles):

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

The external repository should contain:
- `user.nix` (required) - User account options AND home-manager configuration
- `nixos.nix` (optional) - System-level configuration

See [External User Configurations](#external-user-configurations) section below.

## User Account Options

### `description`

Full name or description of the user.

**Type:** String

```nix
athenix.users.myuser.description = "John Doe";
```

### `extraGroups`

Additional Unix groups for the user. Default is empty.

**Type:** List of strings

**Common groups:**
- `"wheel"` - Sudo access
- `"networkmanager"` - Network configuration
- `"docker"` - Docker and Podman access
- `"video"` - Video device access (GPU, displays)
- `"audio"` - Audio device access
- `"input"` - Input devices (keyboards, mice)
- `"kvm"` - KVM virtual machine access
- `"libvirtd"` - Libvirt daemon access

```nix
athenix.users.myuser.extraGroups = [
  "wheel"
  "networkmanager"
  "docker"
  "video"
];
```

### `shell`

Login shell for the user.

**Type:** Package

**Default:** `pkgs.bash`

```nix
athenix.users.myuser.shell = pkgs.zsh;
# or
athenix.users.myuser.shell = pkgs.fish;
```

### `hashedPassword`

Password hash for the user. Use `!` to disable password login (SSH keys only).

**Type:** String (SHA-512 hash)

**Generation:**
```bash
# Generate a hashed password
mkpasswd -m sha-512

# Or interactively
mkpasswd -m sha-512 -c
```

```nix
athenix.users.myuser.hashedPassword = "$6$...";

# Disable password login (require SSH keys)
athenix.users.myuser.hashedPassword = "!";
```

### `opensshKeys`

SSH public keys for remote access. Users without SSH keys require password login.

**Type:** List of strings

```nix
athenix.users.myuser.opensshKeys = [
  "ssh-ed25519 AAAA... user@laptop"
  "ssh-rsa AAAA... user@desktop"
];
```

**Getting your SSH public key:**
```bash
# Print your public key
cat ~/.ssh/id_ed25519.pub

# Generate a new key if needed
ssh-keygen -t ed25519 -C "user@host"
```

### `useZshTheme`

Apply system Zsh theme configuration to this user (if using Zsh as shell).

**Type:** Boolean

**Default:** `true`

```nix
athenix.users.myuser.useZshTheme = true;
```

### `useNvimPlugins`

Apply system Neovim configuration and plugins to this user.

**Type:** Boolean

**Default:** `true`

```nix
athenix.users.myuser.useNvimPlugins = true;
```

## Enabling Users on Hosts

Users are **not enabled by default**. Enable them in `inventory.nix`:

### Enable on All Devices in a Group

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

### Enable on Specific Devices

```nix
nix-desktop = {
  devices = {
    "1".athenix.users.admin.enable = true;
    "2".athenix.users.staff.enable = true;
    "3".athenix.users.staff.enable = true;
  };
};
```

### Enable Multiple Users

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

### Using `athenix.forUser` Convenience

Quick setup for single-user systems (especially WSL):

```nix
nix-wsl = {
  devices = {
    "alice".athenix.forUser = "alice-uga";
    "bob".athenix.forUser = "bob-uga";
  };
};
```

This automatically enables the user and sets it as the default WSL user.

## External User Configurations

External user configurations (dotfiles) allow users to maintain their own home-manager setup in separate repositories.

### Repository Structure

```
my-dotfiles/
├── user.nix      # Required: User options + home-manager config
├── nixos.nix     # Optional: System-level configuration
└── config/       # Optional: Your actual dotfiles
    ├── bashrc
    ├── zshrc
    ├── vimrc
    └── ...
```

### user.nix (Required)

This file must provide BOTH user account options AND home-manager configuration:

```nix
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
  # ========== User Account Configuration ==========
  # These options define the user account itself
  athenix.users.myusername = {
    description = "My Full Name";
    extraGroups = [ "wheel" "docker" "networkmanager" ];
    shell = pkgs.zsh;
    hashedPassword = "!";  # SSH keys only
    opensshKeys = [
      "ssh-ed25519 AAAA... user@host"
    ];
    useZshTheme = true;
    useNvimPlugins = true;
  };

  # ========== Home Manager Configuration ==========
  # User environment, packages, and dotfiles
  
  home.packages = with pkgs; [
    vim
    ripgrep
    fzf
  ] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;

  programs.git = {
    enable = true;
    userName = "My Name";
    userEmail = "me@example.com";
    extraConfig = {
      init.defaultBranch = "main";
      core.editor = "vim";
    };
  };

  programs.zsh = {
    enable = true;
    initExtra = ''
      # Your Zsh configuration
    '';
  };

  # Manage dotfiles
  home.file.".config/zshrc".source = ./config/zshrc;
  home.file.".config/bashrc".source = ./config/bashrc;
  home.file.".vimrc".source = ./config/vimrc;
}
```

### nixos.nix (Optional)

System-level configuration for this user (rarely needed):

```nix
{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  # System-level configuration for this user
  users.users.myusername.extraGroups = [ "docker" ];
  environment.systemPackages = [ pkgs.docker ];
}
```

### Using External User Configuration

In `users.nix`:

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

Then enable on hosts in `inventory.nix`:

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

### External Module Parameters

The `user.nix` module receives:

- **`inputs`** - All flake inputs (nixpkgs, home-manager, etc.)
- **`config`** - Home-manager configuration
- **`lib`** - Nixpkgs library functions
- **`pkgs`** - Package set
- **`osConfig`** - OS-level configuration (read-only, can be used for conditional setup)

### Creating External User Configuration

Use the template:

```bash
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
```

## Password Management

### Generate Password Hash

```bash
# Interactive (won't echo)
mkpasswd -m sha-512 -c

# From string
echo "mypassword" | mkpasswd -m sha-512 -s
```

### Disable Password Login

Set `hashedPassword = "!"` and provide SSH keys:

```nix
athenix.users.myuser = {
  description = "SSH-only user";
  hashedPassword = "!";
  opensshKeys = [ "ssh-ed25519 AAAA..." ];
};
```

### Update User Password on Running System

```bash
# As the user
passwd

# As root (to change another user's password)
sudo passwd username
```

## SSH Keys

### Add SSH Keys to a User

```nix
athenix.users.myuser.opensshKeys = [
  "ssh-ed25519 AAAA... user@laptop"
  "ssh-ed25519 BBBB... user@desktop"
];
```

### Get Your SSH Public Key

```bash
# Display your public key
cat ~/.ssh/id_ed25519.pub

# Or for RSA
cat ~/.ssh/id_rsa.pub
```

### Generate New SSH Key

```bash
# Ed25519 (recommended)
ssh-keygen -t ed25519 -C "user@host"

# RSA (older systems)
ssh-keygen -t rsa -b 4096 -C "user@host"
```

## User Groups

### wheel

Allows passwordless sudo access.

```nix
athenix.users.myuser.extraGroups = [ "wheel" ];
```

### networkmanager

Configure network connections (requires `networkmanager` to be enabled):

```nix
athenix.users.myuser.extraGroups = [ "networkmanager" ];
```

### docker

Access Docker daemon (must have Docker enabled on system):

```nix
athenix.users.myuser.extraGroups = [ "docker" ];
```

### video and audio

Access GPU and audio devices:

```nix
athenix.users.myuser.extraGroups = [ "video" "audio" ];
```

## Examples

### Example 1: Basic Lab User

```nix
# users.nix
athenix.users.student = {
  description = "Student Account";
  extraGroups = [ "networkmanager" ];
  shell = pkgs.bash;
  hashedPassword = "$6$...";
  opensshKeys = [];  # Password login only
};

# inventory.nix
nix-laptop = {
  devices = 20;
  overrides.athenix.users.student.enable = true;
};
```

### Example 2: Developer with SSH Keys

```nix
# users.nix
athenix.users.developer = {
  description = "Developer";
  extraGroups = [ "wheel" "docker" "networkmanager" ];
  shell = pkgs.zsh;
  hashedPassword = "!";
  opensshKeys = [
    "ssh-ed25519 AAAA... dev@laptop"
  ];
  useZshTheme = true;
  useNvimPlugins = true;
};

# inventory.nix
nix-desktop = {
  devices = 3;
  overrides.athenix.users.developer.enable = true;
};
```

### Example 3: WSL User with Dotfiles

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

# inventory.nix
nix-wsl = {
  devices = {
    "alice".athenix.forUser = "alice-uga";
  };
};
```

### Example 4: Multiple Users on Single System

```nix
# users.nix
athenix.users = {
  admin = {
    description = "System Administrator";
    extraGroups = [ "wheel" ];
    shell = pkgs.bash;
    hashedPassword = "!";
    opensshKeys = [ "ssh-ed25519 AAAA..." ];
  };
  guest = {
    description = "Guest User";
    extraGroups = [];
    shell = pkgs.bash;
    hashedPassword = "$6$...";
  };
};

# inventory.nix
nix-desktop = {
  devices = {
    "admin-station" = {
      athenix.users.admin.enable = true;
    };
    "guest-station" = {
      athenix.users.guest.enable = true;
    };
  };
};
```

## See Also

- [INVENTORY.md](INVENTORY.md) - Host configuration
- [NAMESPACE.md](NAMESPACE.md) - All configuration options
- [EXTERNAL_MODULES.md](EXTERNAL_MODULES.md) - External modules in detail
- [README.md](../README.md) - Main documentation
  external = builtins.fetchGit { ... };   # External user module (see below)
  
  # === Theme Integration ===
  useZshTheme = true;                     # Apply system Zsh theme (default: true)
  useNvimPlugins = true;                  # Apply system Neovim config (default: true)
  
  # === System Enablement ===
  enable = false;                         # Enable on this system (set in inventory.nix)
};
```

## External User Configurations

Users can maintain their dotfiles and home-manager configuration in separate Git repositories.

### Basic External Configuration

In `users.nix`:

```nix
myuser = {
  # Basic options can be set here OR in the external module's user.nix
  description = "My Name";
  extraGroups = [ "wheel" ];
  hashedPassword = "$6$...";
  
  # Point to external configuration repository
  external = builtins.fetchGit {
    url = "https://git.factory.uga.edu/username/dotfiles";
    rev = "abc123...";  # Pin to specific commit
  };
};
```

### External Repository Structure

```
dotfiles/
├── user.nix     # Required: User options AND home-manager config
├── nixos.nix    # Optional: System-level configuration
└── config/      # Optional: Your dotfiles
    ├── bashrc
    ├── vimrc
    └── ...
```

**At least `user.nix` should be present for a functional user module.**

**user.nix (required):**
```nix
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
  # ========== User Account Configuration ==========
  # These options define the user account itself
  athenix.users.myuser = {
    description = "My Full Name";
    extraGroups = [ "wheel" "docker" ];
    shell = pkgs.zsh;
    hashedPassword = "!";
    opensshKeys = [
      "ssh-ed25519 AAAA... user@host"
    ];
    useZshTheme = true;
    useNvimPlugins = true;
  };

  # ========== Home Manager Configuration ==========
  # User environment, packages, and dotfiles
  
  home.packages = with pkgs; [
    vim
    ripgrep
  ] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;

  programs.git = {
    enable = true;
    userName = "My Name";
    userEmail = "me@example.com";
    extraConfig = {
      init.defaultBranch = "main";
    };
  };
  
  home.file.".bashrc".source = ./config/bashrc;
}
```

**nixos.nix (optional):**
```nix
{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  # System-level configuration
  users.users.myusername.extraGroups = [ "docker" ];
  environment.systemPackages = [ pkgs.docker ];
}
```

### What External Modules Receive

**In user.nix:**
- `inputs` - Flake inputs (nixpkgs, home-manager, etc.)
- `config` - Configuration (NixOS or home-manager depending on import context)
- `lib` - Nixpkgs library functions
- `pkgs` - Package set
- `osConfig` - (home-manager context only) OS-level configuration

### How External Modules Are Loaded

The `user.nix` module serves a dual purpose and is imported in **two contexts**:

1. **NixOS Module Context (User Options)**: The module is imported as a NixOS module where `athenix.users.<username>` options are read to define the user account (description, shell, groups, SSH keys, etc.). These options override any defaults set in `users.nix`.

2. **Home-Manager Context**: The same module is imported into home-manager where `home.*`, `programs.*`, and `services.*` options configure the user's environment, packages, and dotfiles.

**Key insight:** A single `user.nix` file contains both account configuration AND home environment configuration. The system automatically imports it in the appropriate contexts.

**Example:** The user account options (like `shell`, `extraGroups`) are read during NixOS evaluation, while home-manager options (like `home.packages`, `programs.git`) are used when building the user's home environment.

**In nixos.nix:**
- `inputs` - Flake inputs
- `config` - NixOS configuration
- `lib` - Nixpkgs library functions
- `pkgs` - Package set

### Alternative Configuration Methods

**Local path (for testing):**
```nix
external = /home/username/dev/dotfiles;
```

**Note:** User options can be set in users.nix OR in the external module's user.nix file. For custom packages and environment configuration without external modules, create a local module and reference it with `extraImports`.

### Create User Template

```bash
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
```

See [templates/user/README.md](../templates/user/README.md) for complete template.

## Enabling Users on Hosts

Users must be explicitly enabled on each host in `inventory.nix`.

### Method 1: Enable in Overrides (All Devices)

```nix
nix-laptop = {
  devices = 5;
  overrides = {
    athenix.users.student.enable = true;  # All 5 laptops get this user
  };
};
```

### Method 2: Enable per Device

```nix
nix-desktop = {
  devices = {
    "1".athenix.users.alice.enable = true;
    "2".athenix.users.bob.enable = true;
    "3" = {
      athenix.users.alice.enable = true;
      athenix.users.bob.enable = true;
    };
  };
};
```

### Method 3: Convenience Option (athenix.forUser)

Quick setup for single-user systems:

```nix
nix-wsl = {
  devices = {
    "alice".athenix.forUser = "alice-user";  # Automatically enables alice-user
    "bob".athenix.forUser = "bob-user";
  };
};
```

This is equivalent to `athenix.users.alice-user.enable = true`.

## Password Management

### Generate Hashed Password

```bash
mkpasswd -m sha-512
# Enter password when prompted
# Copy the output hash
```

### In users.nix

```nix
myuser = {
  hashedPassword = "$6$rounds=656000$...";  # Paste hash here
};
```

### Disable Password Login

```nix
myuser = {
  hashedPassword = "!";  # Locks password, SSH key only
  opensshKeys = [ "ssh-ed25519 ..." ];
};
```

### Change Password Later

On the system:
```bash
sudo passwd myuser
```

Or regenerate hash and update `users.nix`.

## SSH Keys

### Adding SSH Keys

```nix
myuser = {
  opensshKeys = [
    "ssh-ed25519 AAAAC3Nza... user@laptop"
    "ssh-rsa AAAAB3NzaC1... user@desktop"
  ];
};
```

### Generate SSH Key

```bash
ssh-keygen -t ed25519 -C "user@hostname"
cat ~/.ssh/id_ed25519.pub  # Copy this
```

### Multiple Keys

Users can have multiple SSH keys for different machines:

```nix
opensshKeys = [
  "ssh-ed25519 ... user@work-laptop"
  "ssh-ed25519 ... user@home-desktop"  
  "ssh-ed25519 ... user@tablet"
];
```

## Examples

### Basic User

```nix
student = {
  description = "Student Account";
  extraGroups = [ "networkmanager" ];
  shell = pkgs.bash;
  hashedPassword = "$6$...";
};
```

### Admin User with SSH

```nix
admin = {
  description = "System Administrator";
  extraGroups = [ "wheel" "networkmanager" "docker" ];
  shell = pkgs.zsh;
  hashedPassword = "$6$...";
  opensshKeys = [
    "ssh-ed25519 AAAA... admin@laptop"
  ];
};
```

### User with External Configuration

```nix
developer = {
  description = "Developer";
  extraGroups = [ "wheel" "docker" ];
  shell = pkgs.zsh;
  hashedPassword = "$6$...";
  external = builtins.fetchGit {
    url = "https://git.factory.uga.edu/username/dotfiles";
    rev = "abc123def456...";
  };
};
```

### WSL User

```nix
wsl-user = {
  description = "WSL User";
  extraGroups = [ "wheel" ];
  shell = pkgs.zsh;
  hashedPassword = "$6$...";
  external = builtins.fetchGit {
    url = "https://git.factory.uga.edu/username/dotfiles";
    rev = "abc123...";
  };
};
```

Enable in inventory.nix:
```nix
nix-wsl = {
  devices."my-wsl".athenix.forUser = "wsl-user";
};
```

### User Without System Themes

For users who want complete control over their shell/editor:

```nix
poweruser = {
  description = "Power User";
  extraGroups = [ "wheel" ];
  shell = pkgs.zsh;
  hashedPassword = "$6$...";
  useZshTheme = false;      # Don't apply system theme
  useNvimPlugins = false;   # Don't apply system nvim config
  external = builtins.fetchGit {
    url = "https://github.com/username/custom-dotfiles";
    rev = "abc123...";
  };
};
```

## Theme Integration

### System Zsh Theme

When `useZshTheme = true` (default), the system applies:
- Oh My Posh with custom theme
- History substring search
- Vi mode (for non-root users)
- Zsh plugins (zplug)

Disable if you want full control in your dotfiles.

### System Neovim Config

When `useNvimPlugins = true` (default), the system applies:
- LazyVim distribution
- TreeSitter parsers
- Language servers

Disable if you want to configure Neovim yourself.

## Troubleshooting

### User Can't Login

**Check if enabled on host:**
```bash
nix eval .#nixosConfigurations.nix-laptop1.config.athenix.users.myuser.enable
```

**Check if user exists:**
```bash
# On the system
id myuser
```

### SSH Key Not Working

**Check key in configuration:**
```bash
nix eval .#nixosConfigurations.nix-laptop1.config.users.users.myuser.openssh.authorizedKeys.keys
```

**Verify key format:**
- Should start with `ssh-ed25519`, `ssh-rsa`, or `ssh-dss`
- Should be all on one line
- Should end with comment (optional)

### External Config Not Loading

**Check repository access:**
```bash
git ls-remote https://git.factory.uga.edu/username/dotfiles
```

**Verify structure:**
- Must have `user.nix` at repository root
- `nixos.nix` is optional
- Check file permissions

**Test with local path first:**
```nix
external = /path/to/local/dotfiles;
```

## See Also

- [EXTERNAL_MODULES.md](EXTERNAL_MODULES.md) - External module guide
- [INVENTORY.md](INVENTORY.md) - Host configuration guide
- [NAMESPACE.md](NAMESPACE.md) - Configuration options reference
- [templates/user/](../templates/user/) - User module template
- [README.md](../README.md) - Main documentation
