# План: убрать канал «Push» из портала (G4)

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Убрать неработающий канал Push из вкладки «Настройки → Уведомления», оставив каналы inapp и email.

**Architecture:** Чистое удаление одного элемента из массива каналов плюс правка пояснения и CSS-сетки в одном Vue-компоненте; тест приводится к новому контракту (2 канала). Backend, БД и тип `NotificationChannel` не трогаются.

**Tech Stack:** Vue 3 + Vuetify 3, Vitest, TypeScript.

---

## Цель

Убрать канал Push из UI настроек уведомлений; матрица остаётся 8 событий × 2 канала (inapp/email), остальная логика без изменений.

```skills-json
["test-driven-development"]
```

```steps-json
[
  {"op":"Edit","object":"app/tests/Frontend/NotificationsTab.spec.ts","ref":"D4"},
  {"op":"Edit","object":"app/resources/js/views/settings/NotificationsTab.vue","ref":"D2"},
  {"op":"Bash","object":"npx vitest run --root app NotificationsTab","ref":"D5"},
  {"op":"Bash","object":"npx vitest run --root app","ref":"D5"}
]
```

```verified-context-json
[
  {"id":"vc1","kind":"EXTRACTED","ref":"app/resources/js/views/settings/NotificationsTab.vue","anchor":"{ id: 'push', label: 'Push'"}
]
```

---

### Task 1: привести тест к контракту «2 канала» (ref D4)

**Files:**
- Modify: `app/tests/Frontend/NotificationsTab.spec.ts:71-78`

- [ ] **Step 1: переписать тест каналов**

Заменить блок:

```ts
    it('содержит ровно 3 канала (inapp/push/email) — НЕ sms', () => {
        const wrapper = factory();
        const text = wrapper.text();
        expect(text).toContain('В приложении');
        expect(text).toContain('Push');
        expect(text).toContain('Email');
        expect(text).not.toContain('SMS');
    });
```

на:

```ts
    it('содержит ровно 2 канала (inapp/email) — без push и sms', () => {
        const wrapper = factory();
        const text = wrapper.text();
        expect(text).toContain('В приложении');
        expect(text).toContain('Email');
        expect(text).not.toContain('Push');
        expect(text).not.toContain('SMS');
    });
```

Тест написан до правки компонента (TDD): пока push в компоненте есть, новый ассерт `not.toContain('Push')` красный.

### Task 2: убрать push из компонента (ref D2)

**Files:**
- Modify: `app/resources/js/views/settings/NotificationsTab.vue` (массив `CHANNELS`, пояснение, CSS)

- [ ] **Step 2a: удалить элемент push из `CHANNELS`**

Удалить строку:

```ts
    { id: 'push', label: 'Push', description: 'Web-push в браузер (включится в Post-MVP).' },
```

В массиве остаются `inapp` и `email`.

- [ ] **Step 2b: поправить пояснительный текст**

Заменить:

```html
                Матрица 8 событий × 3 каналов (соответствует
                <code>users.notification_preferences</code> в БД). Push активируется в Post-MVP.
```

на:

```html
                Матрица 8 событий × 2 каналов (соответствует
                <code>users.notification_preferences</code> в БД).
```

- [ ] **Step 2c: поправить CSS-сетку**

Заменить:

```css
    grid-template-columns: 1fr 110px 110px 130px;
```

на:

```css
    grid-template-columns: 1fr 110px 130px;
```

### Task 3: проверка (ref D5)

- [ ] **Step 3: прогон теста вкладки**

Run: `npx vitest run --root app NotificationsTab`
Expected: PASS — push отсутствует, inapp/email и 8 событий на месте.

- [ ] **Step 4: полный фронтовый прогон (регрессия)**

Run: `npx vitest run --root app`
Expected: PASS — без новых падений.

### Task 4: коммит

Коммит выполняется после зелёного прогона через owner-escape (не шаг этого плана). Сообщение без скобок, трейлер `Co-Authored-By: Claude Opus 4.8`.

---

## Переговоры

### Круг 1

Возражений по существу нет. Канал push не доставляет сообщения (нет ServiceWorker, пустые VAPID) и удаляется только из пользовательского интерфейса; хранимые данные `notification_preferences` и backend не затрагиваются, тип `NotificationChannel` сохраняется ради совместимости.
