# Contributing to TuxMate

Thank you for your interest in contributing! This guide ensures high-quality, error-free contributions.

---

## ⚠️ Before You Start

**Your PR will be rejected if you:**
- ❌ Submit unverified package names
- ❌ Use wrong package name casing (e.g., `firefox` vs `MozillaFirefox`)
- ❌ Put `pacman` packages in `arch` when they're AUR-only
- ❌ Use partial Flatpak IDs instead of full App IDs
- ❌ Forget `--classic` for Snap packages that require it
- ❌ Include PPAs or unofficial repos for apt packages
- ❌ Incorrect Homebrew format (GUI apps require `'--cask name'` with a space separator)

---

## 📦 Adding Applications

All applications are defined in [`src/lib/data.ts`](src/lib/data.ts).

### Mandatory Research Protocol

**You MUST verify every package on these official sources before submitting:**

| Source | What to Check | URL |
|--------|--------------|-----|
| **Repology** | Global package index (check first!) | `https://repology.org/project/[app-name]/versions` |
| **Arch Linux** | Official repos (`core`, `extra`) | [archlinux.org/packages](https://archlinux.org/packages/) |
| **AUR** | User repos (only if not in official!) | [aur.archlinux.org](https://aur.archlinux.org/) |
| **Ubuntu/Debian** | Main/Universe repos only, **NO PPAs** | [packages.ubuntu.com](https://packages.ubuntu.com/) / [packages.debian.org](https://packages.debian.org/) |
| **Fedora** | Official packages | [packages.fedoraproject.org](https://packages.fedoraproject.org/) |
| **OpenSUSE** | Official packages | [software.opensuse.org](https://software.opensuse.org/) |
| **NixOS** | Nix packages | [search.nixos.org](https://search.nixos.org/packages) |
| **Flathub** | Flatpak apps (get the App ID!) | [flathub.org](https://flathub.org/) |
| **Snapcraft** | Snap packages | [snapcraft.io](https://snapcraft.io/) |
| **Homebrew Formulae** | CLI tools (works on macOS + Linux) | [formulae.brew.sh](https://formulae.brew.sh/) |
| **Homebrew Casks** | GUI apps (macOS only) | [formulae.brew.sh/cask](https://formulae.brew.sh/cask/) |

---

### Entry Structure

```typescript
{
  id: 'app-id',                        // Unique, lowercase, kebab-case
  name: 'App Name',                    // Official display name  
  description: 'Short description',    // Max ~25 characters
  category: 'Category',                // Must match valid categories
  iconUrl: si('icon-slug', '#color'),  // See Icon System section
  targets: {
    ubuntu: 'exact-package-name',      // apt package (official repos ONLY)
    debian: 'exact-package-name',      // apt package (official repos ONLY)
    arch: 'exact-package-name',        // pacman OR AUR package name
    fedora: 'exact-package-name',      // dnf package
    opensuse: 'exact-package-name',    // zypper package (CASE SENSITIVE!)
    nix: 'exact-package-name',         // nix package
    flatpak: 'com.vendor.AppId',       // FULL Flatpak App ID (reverse DNS)
    snap: 'snap-name',                 // Add --classic if needed
    homebrew: 'formula-name',          // Formula (CLI) or '--cask cask-name' (GUI)
  },
  unavailableReason?: 'Markdown install instructions'
}
```

---

### ⛔ Strict Rules (Read Carefully!)

#### Package Name Rules

| Rule | ✅ Correct | ❌ Wrong |
|------|-----------|---------|
| **Case sensitivity** | `MozillaFirefox` (openSUSE) | `firefox` |
| **Exact package name** | `firefox-esr` (Debian) | `firefox` |
| **OpenJDK versions** | `openjdk-21-jdk` (Ubuntu) | `openjdk` |
| **Arch package** | `firefox` | `firefox-bin` (when official exists) |

#### Arch Linux: `arch` vs AUR

| Situation | Field to Use | Example |
|-----------|-------------|---------|
| Package in official repos (`core`/`extra`) | `arch: 'package'` | `arch: 'firefox'` |
| Package NOT in official repos | `arch: 'package-bin'` | `arch: 'brave-bin'` |
| NEVER mix both | Use only ONE | — |

**How to check:**
1. Search [archlinux.org/packages](https://archlinux.org/packages/)
2. If found → use `arch` field
3. If NOT found → search [aur.archlinux.org](https://aur.archlinux.org/) → use `arch` field with AUR package name
4. Prefer `-bin` suffix packages in AUR (pre-built, faster install)
5. **IMPORTANT**: If your AUR package name does **NOT** end in `-bin`, `-git`, or `-appimage`, you **MUST** add it to `KNOWN_AUR_PACKAGES` in [`src/lib/aur.ts`](src/lib/aur.ts) so the app knows it's from AUR.

#### Ubuntu/Debian: Official Repos Only

| ✅ Allowed | ❌ NOT Allowed |
|-----------|---------------|
| Main repository packages | PPAs |
| Universe repository packages | Third-party repos |
| Packages on packages.ubuntu.com | Manual .deb downloads |

**If a package requires a PPA:** Leave the field empty and add install instructions to `unavailableReason`.

#### Flatpak: Full App ID Required

| ✅ Correct | ❌ Wrong |
|-----------|---------|
| `com.spotify.Client` | `spotify` |
| `org.mozilla.firefox` | `firefox` |
| `app.zen_browser.zen` | `zen-browser` |

**How to find:** Go to [flathub.org](https://flathub.org/), search the app, copy the full App ID from the app page.

#### Snap: Classic Confinement

Some snaps require `--classic` flag. Check [snapcraft.io](https://snapcraft.io/) for the app and look for "classic" confinement.

| App Type | Format |
|----------|--------|
| Regular snap | `'snap-name'` |
| Classic confinement | `'snap-name --classic'` |

#### Homebrew: Formulae vs Casks

Homebrew has two types of packages:

| Type | What It Is | Platform | Format in `targets` |
|------|-----------|----------|--------------------|
| **Formula** | CLI tools, libraries | macOS + Linux | `'package-name'` |
| **Cask** | GUI applications (.app) | macOS only | `'--cask package-name'` |

**Examples:**

| App | Type | Correct Format |
|-----|------|----------------|
| Git | Formula (CLI) | `homebrew: 'git'` |
| Node.js | Formula (CLI) | `homebrew: 'node'` |
| Python | Formula (versioned) | `homebrew: 'python@3.12'` |
| Firefox | Cask (GUI) | `homebrew: '--cask firefox'` |
| VS Code | Cask (GUI) | `homebrew: '--cask visual-studio-code'` |
| Discord | Cask (GUI) | `homebrew: '--cask discord'` |
| VLC | Cask (GUI) | `homebrew: '--cask vlc'` |

**How to verify package names:**

1. **Formulae**: Search [formulae.brew.sh](https://formulae.brew.sh/) or run `brew search <name>`
2. **Casks**: Search [formulae.brew.sh/cask](https://formulae.brew.sh/cask/) or run `brew search --cask <name>`
3. Check the exact name on the package page (e.g., `visual-studio-code` not `vscode`)

**Important notes:**
- Casks are **macOS-only** — the generated script will skip them on Linux
- Always prefix GUI apps with `--cask ` (note the space after)
- Some apps exist as both formula AND cask (e.g., `emacs` formula vs `emacs-app` cask) — choose based on user expectation
- For versioned packages, use the explicit version: `python@3.12`, `node@20`

---

### Empty Fields

**If a package doesn't exist in a source, leave the field empty (omit it entirely):**

```typescript
// ✅ Correct - Discord not in apt repos
targets: {
  arch: 'discord',
  flatpak: 'com.discordapp.Discord',
  snap: 'discord'
}

// ❌ Wrong - Empty strings clutter the code
targets: {
  ubuntu: '',
  debian: '',
  arch: 'discord',
  fedora: '',
  opensuse: '',
  nix: '',
  flatpak: 'com.discordapp.Discord',
  snap: 'discord'
}
```

---

### The `unavailableReason` Field

Use this to provide helpful installation alternatives when an app isn't available in most package managers.

**Format:** Markdown with clickable links

```typescript
// ✅ Good example
unavailableReason: 'Not in official repos. Use [Flatpak](https://flathub.org/apps/com.example.App) or download from [example.com](https://example.com/download).'

// ❌ Bad examples
unavailableReason: 'Not available'           // No helpful info
unavailableReason: 'Download from website'   // No link provided
```

---

### Valid Categories

Use **exactly** one of these:

```
Web Browsers • Communication • Dev: Languages • Dev: Editors • Dev: Tools
Terminal • CLI Tools • Media • Creative • Gaming • Office
VPN & Network • Security • File Sharing • System
```

---

## 🎨 Icon System

TuxMate uses the [Iconify API](https://iconify.design/) for icons. Icon helpers are defined in [`src/lib/data.ts`](src/lib/data.ts).

### Helper Functions

| Function | Use Case | Example |
|----------|----------|---------|
| `si('slug', '#color')` | Simple Icons (brands) | `si('firefox', '#FF7139')` |
| `lo('slug')` | Logos (already colorful) | `lo('chrome')` |
| `vs('slug')` | VS Code file icons | `vs('file-type-shell')` |
| `mdi('slug', '#color')` | Material Design icons | `mdi('console', '#57F287')` |

### Finding Icon Slugs

| Source | URL | Notes |
|--------|-----|-------|
| **Simple Icons** | [simpleicons.org](https://simpleicons.org/) | Use lowercase slug, add hex color |
| **Material Design** | [pictogrammers.com/library/mdi](https://pictogrammers.com/library/mdi/) | Use icon name |
| **Iconify Search** | [icon-sets.iconify.design](https://icon-sets.iconify.design/) | Search all sets |
| **Fallback** | — | Use `mdi('application', '#color')` |

### Icon Requirements

- ✅ Must be recognizable at 24×24px
- ✅ Use [official brand colors](https://simpleicons.org) - click icon to copy hex
- ✅ Monochrome icons (si, mdi) require a color parameter
- ✅ Colorful icons (lo, sk, vs) don't need color
- ❌ Don't use blurry or low-quality external URLs

---

## 🔀 Pull Request Checklist

**Before submitting, verify ALL of these:**

### Package Verification
- [ ] Checked [Repology](https://repology.org/) for global package availability
- [ ] Verified **exact** package names on each distro's official package search
- [ ] Confirmed case sensitivity (especially openSUSE: `MozillaFirefox`, `MozillaThunderbird`)
- [ ] Arch packages confirmed in [official repos](https://archlinux.org/packages/) OR [AUR](https://aur.archlinux.org/)
- [ ] Ubuntu/Debian packages are in **Main/Universe only** (no PPAs)
- [ ] Flatpak uses **full App ID** from [Flathub](https://flathub.org/)
- [ ] Snap packages checked for `--classic` requirement
- [ ] Nix packages checked for unfree license (add to `KNOWN_UNFREE_PACKAGES` if needed)
- [ ] Homebrew uses correct format: `'formula'` for CLI, `'--cask name'` for GUI apps

### Code Quality
- [ ] Tested locally with `npm run dev`
- [ ] Production build passes: `npm run build`
- [ ] Lint passes: `npm run lint`
- [ ] Unit tests pass: `npm run test`
- [ ] Apps added in **alphabetical order** within their category
- [ ] Icons display correctly at small sizes


---

## 📝 Pull Request Template

Use the following template when submitting a pull request:

```markdown
## Summary

Brief description of changes made.

## Changes

### Apps Added
| App Name | Category | Package Sources |
|----------|----------|-----------------|
| Example App | Dev: Tools | apt, pacman, flatpak, homebrew |

### Apps Modified
- `app-id`: Description of change

## Verification

> All package names have been verified against official sources.

| Source | Verification Link |
|--------|-------------------|
| Repology | [repology.org/project/...](https://repology.org/) |
| Arch Linux | [archlinux.org/packages/...](https://archlinux.org/packages/) |
| AUR | [aur.archlinux.org/packages/...](https://aur.archlinux.org/) |
| Ubuntu | [packages.ubuntu.com/...](https://packages.ubuntu.com/) |
| Fedora | [packages.fedoraproject.org/...](https://packages.fedoraproject.org/) |
| openSUSE | [software.opensuse.org/...](https://software.opensuse.org/) |
| NixOS | [search.nixos.org/packages/...](https://search.nixos.org/packages) |
| Flathub | [flathub.org/apps/...](https://flathub.org/) |
| Snapcraft | [snapcraft.io/...](https://snapcraft.io/) |
| Homebrew | [formulae.brew.sh/...](https://formulae.brew.sh/) |

## Testing

- [ ] `npm run dev` — Local development server works
- [ ] `npm run build` — Production build passes
- [ ] `npm run lint` — No linting errors
- [ ] `npm run test` — All unit tests pass
- [ ] Verified in browser — UI renders correctly

## Screenshots (if applicable)

<!-- Add screenshots for UI changes -->
```

---

## 💻 Development Workflow

### Initial Setup

```bash
# Clone the repository
git clone https://github.com/abusoww/tuxmate.git
cd tuxmate

# Install dependencies
npm install

# Start development server
npm run dev
```

The development server will be available at `http://localhost:5173`.

### Quality Assurance

Run these commands before every commit:

| Command | Purpose |
|---------|---------|
| `npm run lint` | Check for code style issues |
| `npm run lint -- --fix` | Auto-fix linting errors |
| `npm run test` | Run unit test suite |
| `npm run build` | Verify production build |

### Branch Naming Convention

| Type | Format | Example |
|------|--------|---------|
| New feature | `feature/description` | `feature/add-homebrew-support` |
| Bug fix | `fix/description` | `fix/arch-aur-detection` |
| Documentation | `docs/description` | `docs/update-contributing` |
| Refactor | `refactor/description` | `refactor/script-generation` |

### Commit Message Format

Follow [Conventional Commits](https://www.conventionalcommits.org/):

```
<type>(<scope>): <description>

[optional body]

[optional footer]
```

**Types:**

| Type | Description |
|------|-------------|
| `feat` | New feature or functionality |
| `fix` | Bug fix |
| `docs` | Documentation changes |
| `style` | Code style (formatting, no logic change) |
| `refactor` | Code restructuring (no feature change) |
| `test` | Adding or updating tests |
| `chore` | Maintenance tasks |

**Examples:**

```bash
feat(data): add Homebrew support for 50+ apps

fix(scripts): correct AUR package detection for -git suffix

docs(contributing): add Homebrew verification guidelines
```

---

## 🐧 Adding Distributions

Distributions are defined in [`src/lib/data.ts`](src/lib/data.ts).

### Distro Structure
```typescript
{
  id: 'distro-id',
  name: 'Display Name',
  iconUrl: si('distro-slug', '#color'),
  color: '#HexColor',
  installPrefix: 'sudo pkg install -y'
}
```

### After Adding a Distro
1. Add the distro ID to the `DistroId` type in `src/lib/data.ts`
2. Create a new script generator file: `src/lib/scripts/[distro].ts`
3. Export the generator from `src/lib/scripts/index.ts`
4. Add the case in `src/lib/generateInstallScript.ts` (both functions)
5. Handle distro-specific logic (repo setup, package detection, etc.)
6. Add `targets.[distro]` entries to relevant apps in `data.ts`

---

## ⚙️ Script Generation

Script generation is modular. Each distro has its own generator:

```
src/lib/
├── generateInstallScript.ts    # Main entry point
├── aur.ts                      # AUR package detection
└── scripts/
    ├── index.ts                # Exports all generators
    ├── shared.ts               # Colors, progress bars, utilities
    ├── arch.ts                 # Arch + AUR (yay)
    ├── debian.ts               # Debian apt
    ├── ubuntu.ts               # Ubuntu apt + PPA handling
    ├── fedora.ts               # Fedora dnf + RPM Fusion
    ├── opensuse.ts             # openSUSE zypper
    ├── nix.ts                  # Nix declarative config generator
    ├── flatpak.ts              # Flatpak (parallel install)
    ├── snap.ts                 # Snap packages
    └── homebrew.ts             # Homebrew (formulae + casks)
```

### Nix Unfree Packages

When adding Nix packages, check if they require `allowUnfree = true`. Unfree packages are detected in [`src/lib/nixUnfree.ts`](src/lib/nixUnfree.ts).

**Known unfree packages** (add new ones to `KNOWN_UNFREE_PACKAGES`):
- Communication: `discord`, `slack`, `zoom-us`, `teams`, `skypeforlinux`
- Browsers: `google-chrome`, `vivaldi`, `opera`
- Media: `spotify`
- Gaming: `steam`
- Dev: `vscode`, `sublime-text`, `postman`, `code-cursor`, `vagrant`, JetBrains IDEs
- Creative: `davinci-resolve`
- Other: `obsidian`, `dropbox`, `1password`

**How it works:**
1. User selects unfree packages with Nix distro
2. UI shows amber warning listing affected apps
3. Downloaded `configuration.nix` includes comment with `allowUnfree` instructions

### Script Generator Features

Each script generator implements these core capabilities:

| Feature | Description | Implementation |
|---------|-------------|----------------|
| **Package Detection** | Skip already-installed packages | Distro-specific checks (e.g., `dpkg -l`, `brew list`) |
| **AUR Handling** | Auto-install `yay`/`paru` helper for Arch | See [`aur.ts`](src/lib/aur.ts) for detection patterns |
| **RPM Fusion** | Auto-enable repos for Fedora multimedia | Enabled when proprietary codecs needed |
| **Parallel Install** | Concurrent package installation | Flatpak uses background jobs for speed |
| **Network Retry** | Exponential backoff on failures | `with_retry()` in [`shared.ts`](src/lib/scripts/shared.ts) |
| **Progress UI** | Colored output with ETA | Progress bars, timing, summary |
| **Shell Escaping** | Prevent command injection | `escapeShellString()` in [`shared.ts`](src/lib/scripts/shared.ts) |
| **Homebrew Casks** | Platform-aware formula/cask handling | Separate commands, skip casks on Linux |

### Testing Script Changes

#### Automated Testing

```bash
# Run the full test suite
npm run test

# Run tests in watch mode during development
npm run test -- --watch

# Run specific test file
npm run test -- src/__tests__/aur.test.ts
```

#### Manual Testing Workflow

| Step | Action | Purpose |
|------|--------|---------|
| 1 | `npm run dev` | Start development server |
| 2 | Select test packages | Choose mix of package types |
| 3 | Copy generated script | Use "Copy" button |
| 4 | Test in isolated environment | VM or container (see below) |
| 5 | Verify installation | Check packages installed correctly |

#### Container Testing

Use Docker containers for safe, isolated testing:

```bash
# Arch Linux
docker run -it --rm archlinux:latest bash -c "pacman -Sy && bash"

# Ubuntu
docker run -it --rm ubuntu:latest bash -c "apt update && bash"

# Fedora  
docker run -it --rm fedora:latest bash -c "dnf check-update; bash"

# Debian
docker run -it --rm debian:latest bash -c "apt update && bash"
```

> [!TIP]
> For Homebrew testing, use a macOS environment or [Homebrew on Linux](https://docs.brew.sh/Homebrew-on-Linux).

---

## 🐛 Reporting Issues

### Bug Reports — Include:
- Browser & OS (e.g., Firefox 120 on Arch Linux)
- Steps to reproduce (numbered list)
- Expected vs actual behavior
- Console errors (F12 → Console tab)
- Screenshots if UI-related

### Feature Requests — Include:
- Use case and why it's needed
- Proposed solution
- Alternatives considered

---

## ❓ Questions?

Open a [Discussion](https://github.com/abusoww/tuxmate/discussions) or create an [Issue](https://github.com/abusoww/tuxmate/issues).
