vault backup: 2026-04-29 18:07:18
This commit is contained in:
parent
b98d6e6112
commit
3bbe389bab
1 changed files with 147 additions and 0 deletions
147
01 Projects/video-accessibility/Multi-Tenant Audit — Handover.md
Normal file
147
01 Projects/video-accessibility/Multi-Tenant Audit — Handover.md
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
---
|
||||
title: Video Accessibility — Multi-Tenant Audit Handover
|
||||
date: 2026-04-29
|
||||
tags:
|
||||
- video-accessibility
|
||||
- security
|
||||
- saas
|
||||
- handover
|
||||
status: in-progress
|
||||
---
|
||||
|
||||
# Multi-Tenant Audit — Handover
|
||||
|
||||
> [!success] PR-1 MERGED (branch: `feat/multi-tenant-isolation`)
|
||||
> Committed `4949873` · Pushed to Bitbucket. Run the migration script before deploying to prod.
|
||||
|
||||
---
|
||||
|
||||
## Контекст
|
||||
|
||||
Платформа — AI SaaS для генерации accessibility-материалов (CC, AD, SDH) из видео. Клиент Oliver Internal, сервер optical-web-1. Аудит выявил **100+ дефектов** в изоляции по тенантам и UX для всех ролей (PM, Linguist, Reviewer, Production).
|
||||
|
||||
Полный план: [[snoopy-watching-fountain]] (plan file в `.claude/plans/`)
|
||||
|
||||
---
|
||||
|
||||
## Роли в системе
|
||||
|
||||
| Роль | Зона ответственности |
|
||||
|------|---------------------|
|
||||
| **ADMIN** | Платформенный оператор, видит всё |
|
||||
| **PROJECT_MANAGER** | Создаёт проекты, назначает команду, финальный ревью, доставка клиенту |
|
||||
| **PRODUCTION** | Загружает видео, настраивает jobs, мониторит AI-пайплайн, retry falls |
|
||||
| **LINGUIST** | Первая стадия QC: правит VTT, глоссарий |
|
||||
| **REVIEWER** | Вторая стадия QC: апрув/реджект с категориями |
|
||||
| **CLIENT** | Только read-only через share-link (не имеет навигации в основном UI) |
|
||||
|
||||
---
|
||||
|
||||
## Что сделано — PR-1 «Multi-tenancy foundations»
|
||||
|
||||
### Ключевые изменения
|
||||
|
||||
| Файл | Что изменилось |
|
||||
|------|---------------|
|
||||
| `core/dependencies.py` | `get_user_org_ids()` + `assert_job_in_user_org()` — ADMIN→None, staff→orgs или `[]` (больше нет `None` для LINGUIST/REVIEWER/PRODUCTION без тимы) |
|
||||
| `models/job.py` | Поле `organization_id: Optional[str]` |
|
||||
| `models/review_note.py` | Поле `organization_id: Optional[str]` |
|
||||
| `models/vtt_version.py` | Поле `organization_id: Optional[str]` |
|
||||
| `models/audit_log.py` | Поле `organization_id: Optional[str]` |
|
||||
| `routes_jobs.py` | `GET /jobs/{id}` — org-check для ВСЕХ ролей; bulk-delete/approve/return-to-qc скипают чужие jobs; `POST /jobs` принимает `client_id`, ставит `organization_id`; **удалён `time.sleep(1)`** |
|
||||
| `routes_review_notes.py` | `assert_job_in_user_org` в каждом хендлере; PM добавлен в allowedRoles |
|
||||
| `routes_vtt_versions.py` | `_assert_job_access` хелпер в каждом хендлере; PM добавлен |
|
||||
| `routes_websockets.py` | `/ws/jobs/{job_id}` проверяет org перед accept |
|
||||
| `services/audit_logger.py` | `log_action` и `log_job_action` принимают `organization_id` |
|
||||
| `migrations/2026_05_add_organization_id.py` | Бэкфилл + индексы |
|
||||
| `tests/unit/test_cross_tenant_isolation.py` | 10 unit-тестов |
|
||||
|
||||
### Закрытые MT-issues
|
||||
`MT-1` `MT-2` `MT-3` `MT-4` `MT-5` (частично) `MT-6` `MT-7` `MT-8`(ws) `W-8`(sleep)
|
||||
|
||||
---
|
||||
|
||||
## Что осталось по плану
|
||||
|
||||
### 🔴 PR-2 «Workflow blockers» — СЛЕДУЮЩИЙ (в работе)
|
||||
|
||||
> [!warning] Нельзя деплоить другие улучшения до PR-2: broken UX блокирует ежедневную работу
|
||||
|
||||
| ID | Описание | Файл(ы) |
|
||||
|----|----------|---------|
|
||||
| W-1 | PM-дашборд — нет ветки `project_manager` | `Dashboard.tsx` |
|
||||
| W-2 | Linguist/Reviewer не редиректят на свою страницу при логине | `App.tsx`, auth routes |
|
||||
| W-3 | Sidebar badges с количеством pending задач | `Sidebar.tsx` |
|
||||
| W-4 | Назначение команды при создании job (сейчас только после AI) | `NewJob.tsx`, `QCDetail.tsx` |
|
||||
| W-5 | Project defaults не подставляются при выборе existing project | `NewJob.tsx:309-311` |
|
||||
| W-6 | Two-stage QC order не enforced (linguist→reviewer) | `language_qc.py:965-981` |
|
||||
| W-7 | Email уведомления жёстко выключены | `tasks/notify.py:111` |
|
||||
| W-9 | PM не может complete job | `routes_jobs.py` |
|
||||
| W-10 | Final Review `/admin/final` недоступен PM из sidebar | `Sidebar.tsx` |
|
||||
| W-11 | Production dashboard отсутствует | `Dashboard.tsx` |
|
||||
|
||||
### 🟡 PR-3 «PM productivity»
|
||||
|
||||
- Deadline column + overdue colors в JobsList
|
||||
- Clone project/job
|
||||
- Bulk assign linguist
|
||||
- Server pagination (сейчас size:10000!)
|
||||
- "Needs my attention" filter presets
|
||||
- Project share read-only link для CLIENT
|
||||
|
||||
### 🟡 PR-4 «Linguist & Reviewer productivity»
|
||||
|
||||
- Glossary inline в VttEditor
|
||||
- Diff AI baseline vs current edit
|
||||
- Optimistic locking (concurrent edits → 409)
|
||||
- Reviewer reviewed-cues tracking + gate approve
|
||||
- Reject reason categories (не free-text)
|
||||
- Hotkeys (Cmd+Enter save, `]`/`[` prev/next cue)
|
||||
|
||||
### 🟢 PR-5 «Polish & tech debt»
|
||||
|
||||
- Единый `lib/jobStatusMessages.ts`
|
||||
- Native `<track>` для captions (сейчас кастомный div)
|
||||
- AD audio sync с video
|
||||
- CSRF защита
|
||||
- Unified upload size limit (сейчас 3 разных значения в коде)
|
||||
|
||||
---
|
||||
|
||||
## Архитектурные решения
|
||||
|
||||
> [!tip] Принцип проверки org-изоляции
|
||||
> `assert_job_in_user_org` возвращает **404 (не 403)** — чтобы не раскрывать факт существования чужого job. Три уровня fallback: `organization_id` → `project.client_id` → legacy `client_id==user.id`.
|
||||
|
||||
> [!note] GCS пути (MT-14 — ещё не сделано)
|
||||
> Файлы в GCS хранятся без org-префикса (`{job_id}/source.mp4`). Signed URLs не проверяют org. Это остаётся открытой уязвимостью — нужен lazy-migration путей и валидация в `get_signed_url`.
|
||||
|
||||
> [!warning] MT-15 — два параллельных authz-стека
|
||||
> `core/authz.py` (новый, частично используется в `routes_organizations.py`) vs legacy `dependencies.py`. Нужна консолидация, но это большая миграция. Пока добавлены функции в `dependencies.py`.
|
||||
|
||||
---
|
||||
|
||||
## Команды
|
||||
|
||||
```bash
|
||||
# Запуск локально
|
||||
./scripts/run-local.sh
|
||||
|
||||
# Запустить миграцию (внутри backend-контейнера)
|
||||
python -m migrations.2026_05_add_organization_id
|
||||
|
||||
# Тесты (внутри контейнера)
|
||||
cd backend && poetry run pytest tests/unit/test_cross_tenant_isolation.py -v
|
||||
|
||||
# Lint
|
||||
cd backend && ruff check .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Открытые риски перед деплоем
|
||||
|
||||
1. **Запустить миграцию** `2026_05_add_organization_id.py` — без неё все существующие jobs имеют `organization_id=None` → все staff (linguist/reviewer/production) с memberships не увидят старые jobs
|
||||
2. **Проверить что у существующих staff есть memberships/teams** — иначе они увидят 0 jobs и заблокируются
|
||||
3. **MT-12** (`_assert_client_access` legacy bypass для PM) — ещё не закрыт
|
||||
4. **MT-16** (JWT без `org_ids`) — каждый запрос ходит в Mongo для memberships; 60s cache есть, но stale-window открыт
|
||||
Loading…
Add table
Reference in a new issue