diff --git a/docs/superpowers/plans/2026-05-16-sprint3b-dashboard-deeplinks.md b/docs/superpowers/plans/2026-05-16-sprint3b-dashboard-deeplinks.md
new file mode 100644
index 00000000..870d7d5f
--- /dev/null
+++ b/docs/superpowers/plans/2026-05-16-sprint3b-dashboard-deeplinks.md
@@ -0,0 +1,823 @@
+# Sprint 3B — Dashboard & Deep-links Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Закрыть аудит-эпики C1+J3 (живой дашборд через новый backend-эндпоинт) и C8+F3 (deep-link `/deals?openId=` из напоминаний и колокольчика).
+
+**Architecture:** J3 — новый `DashboardController::summary` с агрегацией по `deals` + `tenants` (RLS-обёртка `SET LOCAL app.current_tenant_id`, паттерн `DealController`). C1 — `DashboardView` фетчит endpoint и пробрасывает данные в уже-prop-driven компоненты (`DashboardKpiRow`/`DashboardBalance`/`ActivityChart`/`FunnelChart`), при ошибке — fallback на mock. C8/F3 — три точки навигации переводятся на `query: { openId }`, а `DealsView` читает `route.query.openId` и открывает drawer найденной сделки.
+
+**Tech Stack:** PHP 8.3 + Laravel 13, PostgreSQL 16 (партиционированная `deals`), Pest 4; Vue 3 `
+```
+
+Шаблон `` менять минимально — заменить статичные `:kpis="kpis"` / `:balance="balance"` на reactive-ref'ы (Vue разворачивает `.value` в шаблоне автоматически, синтаксис `:kpis="kpis"` не меняется) и пробросить чарт-props + funnel + degradation-alert. Заменить блок `` на:
+
+```html
+
+ Не удалось обновить данные дашборда — показаны последние известные значения.
+
+
+
+
+
+
+
+
+
+
+```
+
+(`FunnelChart` prop `counts` опциональный — `undefined` оставит его mock-default; при успехе API передаст реальные counts.)
+
+- [ ] **Step 5: Запустить тест — убедиться, что проходит**
+
+Run (из `app/`): `npx vitest run tests/Frontend/DashboardView.spec.ts`
+Expected: PASS — 4 теста зелёные.
+
+- [ ] **Step 6: type-check + lint**
+
+Run (из `app/`): `npm run type-check` и `npm run lint:vue`
+Expected: 0 ошибок. `ActivityChart` prop `points` non-optional при передаче — ок; `FunnelChart` `counts?: Record` принимает `undefined`.
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add app/resources/js/api/dashboard.ts app/resources/js/views/DashboardView.vue app/tests/Frontend/DashboardView.spec.ts
+git commit -m "feat(dashboard): DashboardView на real API /api/dashboard/summary (audit C1)
+
+Co-Authored-By: Claude Opus 4.7 (1M context) "
+```
+
+---
+
+## Task 3: C8 + F3 — deep-link `/deals?openId=`
+
+**Files:**
+
+- Modify: `app/resources/js/views/DealsView.vue`
+- Modify: `app/resources/js/views/RemindersView.vue`
+- Modify: `app/resources/js/components/layout/AppTopbar.vue`
+- Test: `app/tests/Frontend/DealsView.spec.ts`, `app/tests/Frontend/RemindersView.spec.ts`
+
+- [ ] **Step 1: Написать падающие тесты**
+
+**1a.** В `app/tests/Frontend/DealsView.spec.ts` добавить тест: при `route.query.openId` совпадающем с id сделки в `dealsState` — drawer открыт. Использовать установленный в файле паттерн mount'а DealsView с роутером; если файл монтирует без роутера — добавить memory-router с маршрутом `/deals` и `push('/deals?openId=')` до mount. Тест (адаптировать имена под фактический mount-helper файла):
+
+```ts
+ it('route.query.openId открывает drawer соответствующей сделки', async () => {
+ // mount DealsView на /deals?openId=<существующий id из MOCK_DEALS>
+ // после loadDeals() (flushPromises) — drawerOpen=true, selectedDeal.id === openId
+ const openId = MOCK_DEALS[0].id;
+ const wrapper = await mountDealsViewAt(`/deals?openId=${openId}`);
+ await flushPromises();
+ const vm = wrapper.vm as unknown as { drawerOpen: boolean; selectedDeal: { id: number } | null };
+ expect(vm.drawerOpen).toBe(true);
+ expect(vm.selectedDeal?.id).toBe(openId);
+ });
+
+ it('openId не найден среди сделок — drawer не открывается, без ошибки', async () => {
+ const wrapper = await mountDealsViewAt('/deals?openId=99999999');
+ await flushPromises();
+ const vm = wrapper.vm as unknown as { drawerOpen: boolean };
+ expect(vm.drawerOpen).toBe(false);
+ });
+```
+
+`drawerOpen` и `selectedDeal` добавить в `defineExpose` DealsView (Step 3).
+
+**1b.** В `app/tests/Frontend/RemindersView.spec.ts` добавить тест: `openDeal(42)` вызывает `router.push` с `{ path: '/deals', query: { openId: 42 } }`. Использовать `vi.spyOn(router, 'push')` по паттерну файла.
+
+- [ ] **Step 2: Запустить тесты — убедиться, что падают**
+
+Run (из `app/`): `npx vitest run tests/Frontend/DealsView.spec.ts tests/Frontend/RemindersView.spec.ts`
+Expected: FAIL — DealsView не реагирует на `openId`; RemindersView пушит `/deals` без query.
+
+- [ ] **Step 3: DealsView — читать `route.query.openId`**
+
+В `app/resources/js/views/DealsView.vue`:
+
+**3a.** В импортах добавить `useRoute`:
+
+```ts
+import { useRoute } from 'vue-router';
+```
+
+и в `