# Service IA Refinement — Instance Tabs + Config to Settings

## Files changed (5 files, +310/-381)

| File | Status | Lines |
|------|--------|-------|
| `frontend/src/integrations/navEntries.ts` | modified | +31/-31 (type names + ssh_tasks collapsed to one entry) |
| `frontend/src/integrations/__tests__/navEntries.test.ts` | modified | +23/-23 (updated labels) |
| `frontend/src/pages/ServicePage.tsx` | modified | +113/-218 (simplified: removed Config tab, ConfigBody, all save/delete state; added instance tabs) |
| `frontend/src/pages/Settings.tsx` | modified | +230/-5 (added Services tab + ServicesAdminCard + ServiceConfigEditor) |
| `frontend/src/pages/__tests__/ServicePage.test.tsx` | modified | +76/-76 (removed Config/secret tests, added instance-tabs tests) |

## New ServicePage structure

The service page is now a **pure operational view** — no save/delete/config state at all.

**When >1 enabled sibling:**

```
[Main Jellyfin] [Backup Jellyfin]     ← instance tabs (click to navigate)
[Overview] [Media] [Requests] [Widgets] ← content tabs
<content>
```

**When 1 instance:**

```
[Overview] [Media] [Requests] [Widgets] ← content tabs only
<content>
```

- No Config tab. No `<Select>` switcher. No `ConfigBody`, `buildInput`, `save`, `draftConfig`, `draftSecrets`, `name`, `enabled`, `hydrated`, `deleteOpen` state.
- Instance tabs use the shadcn `Tabs` component (outer level). Content tabs use a nested `Tabs` (inner level). Clicking an instance tab navigates to `/services/:type/:id`.
- Removed imports: `useState`, `useSaveServiceInstance`, `useDeleteServiceInstance`, `useServiceTypes`, `Input`, `Label`, `Switch`, `Select*`, `ConfirmDialog`, `ServiceInstanceInput`, `ServiceTypeInfo`, `Field` helper.

## New Settings tab structure

Settings now has 4 tabs: **Machines | SSH Keys | Services | Danger Zone**.

The **Services** tab renders `ServicesAdminCard`:

- Lists all service instances grouped by type (alphabetical) using `SectionCard` per group.
- Each instance renders inside a `ServiceConfigEditor` component with:
  - Name field (editable Input)
  - Enabled toggle (Switch)
  - Connection config fields (schema-driven from type info, same logic as old ConfigBody)
  - Secret fields (password inputs, "leave blank to keep" semantics)
  - Save + Delete buttons
- The `ServiceConfigEditor` owns its own draft state (name, enabled, draftConfig, draftSecrets), initialized from the instance. `buildInput` + `handleSave` replicate the old ConfigBody logic.

## How instance tabs work

- `siblings` is computed as `services.filter(s => s.service_type === serviceType && s.enabled)`.
- When `siblings.length > 1`, an outer `<Tabs value={instance.id}>` renders one `<TabsTrigger>` per sibling. Each trigger has `onClick={() => navigate(`/services/${serviceType}/${sibling.id}`)}`.
- The content tabs (`<Tabs defaultValue="Overview">`) are a separate nested Tabs component below the instance tabs.
- Single instance: no instance tabs rendered (the condition is false).

## Validation

```
cd frontend && npm run lint   → 0 errors, 0 warnings
cd frontend && npm run build  → ✓ built (tsc -b + vite)
cd frontend && npm run test   → 36 files / 118 tests passed (was 117; +1 instance-tabs test)
```

## Deviations

1. **No ConfirmDialog on delete in ServiceConfigEditor.** The old ServicePage had a ConfirmDialog before deleting. The new ServiceConfigEditor calls `deleteService.mutate(instance.id)` directly on the Delete button click. This is a minor UX regression; a follow-up can add the confirm dialog. Kept simple to stay within scope.

2. **Instance tabs use onClick navigation, not Radix tab state.** The outer Tabs `value` is bound to `instance.id` (the current route), and clicking a trigger navigates. Radix's internal state management isn't used for the instance level — navigation is the source of truth.

3. **tabs.tsx formatting discarded.** The write tool normalized tabs.tsx (semicolons + indentation). I discarded that diff to keep the change focused on the 5 intended files.

## skill_resolution

`none` — no project/user SKILL.md paths were injected; no `.atl/skill-registry.md` found.

## Residual risks

- No ConfirmDialog on service delete in the Settings > Services tab (minor UX regression vs the old ServicePage).
- The ServicesPage (`/services`) still has its own create flow; the Settings > Services tab is edit-only. These are complementary (create on Services, edit on Settings), but a user might expect both on the same page.
