offplan · online
Plan · stage1

Stage 1 — Wave 2 Chunk 3: §4 Access

Approvedplanstage1priority P0
Ratified
2026-05-08
Created
2026-05-08
Priority
P0
Tags
permissions, rbac, plan-rework

Goal

Доработать §4 Access чтобы закрыть 3 пробела из CONV-22 What's Next:

  1. Internal/External Sales Agent split — сейчас оба упомянуты только в §1 entity glossary; в §4 (permissions matrix + scoping + stock allocation) различие не surface'ится явно.
  2. «Actions column» — оказалось это новые строки в §4.2 permissions matrix для invite/remove Sales Agent action'ов которых сейчас нет (Sales Manager должен мочь добавлять internal SA в свою команду; Admin — приглашать external SA через guest org).
  3. View-as-Agent — admin debug tool «посмотреть как видит Иван». Отдельная фича от «Preview as Buyer» (последняя — в presentation builder, не входит в §4).

ADR 0009 (Tenancy) остаётся placeholder — Chunk 3 уточняет surface, не пишет ADR.

Locked Decisions (CONV-24 interview)

# Тема Решение
Q1 «Actions column» что это Новые строки в §4.2 permissions matrix для invite/remove SA actions, которых сейчас нет: «Invite/remove internal Sales Agents» (Owner ✅, Admin ✅, Sales Manager ✅) + «Invite/remove External Sales Agents (через guest org)» (Owner ✅, Admin ✅).
Q2 View-as-Agent сценарий Доступно: Owner / Admin / Sales Manager. Sales Agent — нет (their own view = normal login, viewer state #4). Use cases: manager debug + onboarding/training. UX: persistent toggle с баннером «Viewing as Иван — Exit». Read-only (никаких действий «от имени» — это не impersonation).
Q2.5 Preview as Buyer (related but separate) Отдельная фича в presentation builder (кнопка «Preview» перед «Send»). Не часть §4. Упоминается одной строкой как cross-reference в §4 View-as-Agent subsection.
Q3 Internal vs External SA — что отличается Базовые permissions в §4.2 — одинаковые. Различия на 5 других осях: stock pool default (§4.4), cross-team visibility, invitation source, removal authority, reports/analytics scope. Закрепляется в новой comparison table в §4.

Strategic insight: Internal vs External SA — это не «разные роли», а одна роль с разным operational context. Базовый rule «Sales Agent» одинаков; разница в orbital concerns (откуда пришёл, что видит по дефолту, кто им управляет).

Approach

Surgical правки + 1 новая subsection в §4. Все изменения внутри launch-plan-stage-1.html + changelog v4.7 + workstream update. ADR 0009 placeholder сохраняется.

Pattern Chunk 2 (CONV-24): анchor IDs, cross-links, comparison table, callout style.

Steps

A. §4.2 Permissions matrix — добавить 2 новых action rows

A1. Add 2 строки после «Add/remove team members» (line 875), перед «Invite guest organisations» (line 876):

A2. Update header line (line 870) — добавить small note: «Sales Agent column применяется к обоим Internal и External — базовые permissions идентичны (различия — в §4.5 ниже).»

B. §4.2 → renumber subsections (§4.5/§4.6 будут добавлены)

Текущая структура §4: 4.1 Invitations, 4.2 Permissions matrix, 4.3 Scoping, 4.4 Stock allocation. План добавляет 4.5 (Internal/External SA split) + 4.6 (View-as-Agent).

C. New §4.5 — Internal vs External Sales Agent split

C1. Insert new subsection после §4.4 Stock allocation (после line 928 закрывающего </details>):

<h4 style="color:var(--navy); margin:20px 0 10px;">4.5 — Internal vs External Sales Agent</h4>
<p>Sales Agent — одна role с двумя operational контекстами: <strong>Internal</strong> (Client из team самой Organisation) и <strong>External</strong> (Client из guest organisation, приглашённой через guest-org invite). Базовые permissions в §4.2 одинаковы; различия — на orbital осях:</p>

<table>
  <thead><tr><th>Ось</th><th>Internal SA</th><th>External SA</th></tr></thead>
  <tbody>
    <tr><td>Stock pool default (Closed mode, см. §4.4)</td><td>Видит Internal pool</td><td>Не видит Internal pool — только assigned</td></tr>
    <tr><td>Cross-team visibility</td><td>Видит коллег-Internal SA в своей Organisation</td><td>Видит только своих в guest organisation</td></tr>
    <tr><td>Invitation source</td><td>Personal invite (см. §4.1) от Owner / Admin / Sales Manager</td><td>Член guest organisation, добавлен через org-invite от Owner / Admin</td></tr>
    <tr><td>Removal authority</td><td>Owner / Admin / Sales Manager (revoke personal invite)</td><td>Admin (revoke guest-org membership) или Admin своей guest org удаляет user'а</td></tr>
    <tr><td>Reports / analytics</td><td>Видит aggregate Organisation-level (own performance + team performance, без других guest orgs)</td><td>Видит только свои продажи + own guest organisation aggregate</td></tr>
  </tbody>
</table>

<p>Cross-link: §1 Sales Agent definition + §4.4 Stock allocation Closed pool table.</p>

D. New §4.6 — View-as-Agent (admin debug tool)

D1. Insert new subsection после §4.5:

<h4 style="color:var(--navy); margin:20px 0 10px;">4.6 — View-as-Agent (admin debug + training)</h4>
<p><strong>Use cases:</strong> Sales Manager хочет проверить что Иван видит правильно после assignment'ов; Admin отлаживает permissions setup перед onboarding; obвучение нового Sales Manager'а («давайте посмотрим как видит работу новый коллега»).</p>

<ul>
  <li><strong>Кому доступен:</strong> Owner / Admin / Sales Manager. Sales Agent — нет (свой view = normal login, см. viewer state #4 в §5).</li>
  <li><strong>UI:</strong> в шапке админки toggle/dropdown «View as...» → выбрать Sales Agent / другого Sales Manager. После выбора — admin panel перерисовывается с perspective этого user'а; вверху страницы фиксированный banner: «Viewing as Иван (Sales Agent) · Exit view-as-mode →».</li>
  <li><strong>Read-only mode:</strong> в view-as-режиме все действия залочены (Save / Edit / Delete / Send / Assign — все disabled с тултипом «Disabled in view-as mode»). Это explicit decision — НЕ impersonation. Для actual impersonation (login as user) — отдельный operator flow в Phase 1.4, deferred to Stage 4.</li>
  <li><strong>Что показывается:</strong> stock filtered как для target user, list юнитов с их visibility/availability, buyer profiles target user'а, его сейлз-метрики. Permissions matrix фильтрует UI элементы.</li>
  <li><strong>Audit log:</strong> entry «User X viewed as User Y at TIMESTAMP, duration N min». Compliance — important чтобы знать кто и когда смотрел чужие views.</li>
  <li><strong>Cross-link:</strong> Preview-as-Buyer (отдельная фича в presentation builder, не часть §4) — для проверки как выглядит email-презентация для конкретного buyer'а перед отправкой. Cм. <a href="#phase-1-11">Phase 1.11</a>.</li>
</ul>

E. §1 Sales Agent definition — minor update

E1. Update existing line (line 619) для добавления cross-link на §4.5:

<tr><td><strong>Sales Agent</strong></td><td>Buyer / presentation flow. Меняет status assigned units через verification form (см. <a href="#phase-1-10">Phase 1.10</a>). Не редактирует контент. Делится на <strong>Internal</strong> (Client из команды самой Organisation) и <strong>External</strong> (Client из другой Organisation, приглашён через guest-organisation invite) — operational различия в <a href="#fd-access">§4.5</a>.</td></tr>

F. Phase callouts touchpoints (audit + light updates)

F1. Phase 1.3 (Tenancy) — RBAC engineering brief должен учитывать Internal/External SA differentiation в данных (e.g., membership_type field или derived через organisation_id link). Add bullet в существующий v4.4 callout: «Internal/External Sales Agent operational split formalised in §4.5 — RBAC должен exposing both via API + UI permissions filter».

F2. Phase 1.4 (Operator Dashboard) — View-as-Agent НЕ путать с operator impersonation (последний deferred Stage 4). Add note: «View-as-Agent (§4.6) — это team-level admin tool, ≠ Stage 4 operator impersonation».

F3. Phase 1.10 (Sales App) — view-as-state в sales-app UI должен respect View-as-Agent toggle. Add bullet: «Sales Agent unit list view rendering должен поддерживать "view-as" mode когда Sales Manager инспектирует team-member view (§4.6)».

F4. Phase 1.11 (Presentation Layer) — Preview-as-Buyer placeholder. Add bullet: «Preview-as-Buyer feature (отдельный от §4.6 View-as-Agent) — кнопка в presentation builder перед Send. Render buyer-tokenised view с тестовым token'ом для preview only».

G. Changelog v4.7 entry

G1. Append v4.7 entry в launch-plan-changelog.html:

H. Workstream update

H1. workstreams/stage1-roman-integration.md:

I. Preview repo sync

I1. Sync 2 файла в ~/code/offplan-online/preview/plan/:

Commit + push в preview (analogous Chunk 2 sync).

Files

Dependencies

Testing

Risks

  1. §4.6 View-as-Agent vs Stage 4 operator impersonation — terminologically близко, легко смешать. Mitigate: explicit «НЕ impersonation» note в §4.6 + cross-link в Phase 1.4.
  2. Audit log requirement в §4.6 — может перетянуть scope в Phase 1.8 (Security & Infrastructure). Mitigate: упомянуть в §4.6 как requirement, без deep dive в схему таблицы — это уровень Phase 1.3 implementation.
  3. Reports/analytics row в §4.5 — самая мутная (заочно подтверждено пользователем но детали не зафиксированы). Mitigate: формулировка осторожная, точная имплементация → Phase 1.4 Operator Dashboard или ADR 0009.
  4. Phase callouts могут разрастаться при /build, особенно 1.10 + 1.11 (где view-as логика может pull в UX тесты). Mitigate: surgical bullets, не глубокий rewrite — глубокие phase callouts отдельно в Wave 2 Chunk 7.

Workstreams

Evaluation

Done when:

Definition of NOT done (deferred):