АРХ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: data contract двусторонней доски внешних контуров
This commit is contained in:
parent
969c218e99
commit
f12a3b7338
|
|
@ -113,6 +113,9 @@
|
||||||
|
|
||||||
Он нужен как стабильный контракт уровня доски.
|
Он нужен как стабильный контракт уровня доски.
|
||||||
|
|
||||||
|
Детализация этого контракта вынесена отдельно в:
|
||||||
|
- [13_STEP_external-contours-board-data-contract.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/13_STEP_external-contours-board-data-contract.md)
|
||||||
|
|
||||||
### 3. Сделать board как фиксированные системные представления
|
### 3. Сделать board как фиксированные системные представления
|
||||||
|
|
||||||
Первая версия не должна строиться как свободный пользовательский конструктор.
|
Первая версия не должна строиться как свободный пользовательский конструктор.
|
||||||
|
|
@ -195,3 +198,4 @@
|
||||||
|
|
||||||
Связанный документ:
|
Связанный документ:
|
||||||
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
||||||
|
- [13_STEP_external-contours-board-data-contract.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/13_STEP_external-contours-board-data-contract.md)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,460 @@
|
||||||
|
# Шаг 13. Технический контракт двусторонней доски внешних контуров
|
||||||
|
|
||||||
|
## Зачем нужен отдельный технический шаг
|
||||||
|
|
||||||
|
Продуктовое решение по двусторонней доске уже зафиксировано:
|
||||||
|
- нужны `Исходящие`
|
||||||
|
- нужны `Входящие`
|
||||||
|
- обе зоны должны фильтроваться единообразно
|
||||||
|
- открытие карточки должно вести в общий shell
|
||||||
|
- drag-and-drop между зонами не нужен и не должен появиться
|
||||||
|
|
||||||
|
Но текущая реализация проекта не дает собрать это одной UI-переоберткой.
|
||||||
|
|
||||||
|
Нужен отдельный технический контракт уровня board-layer.
|
||||||
|
|
||||||
|
## Что есть в коде сейчас
|
||||||
|
|
||||||
|
### 1. `external-contours` сейчас source-side only
|
||||||
|
|
||||||
|
Текущий endpoint:
|
||||||
|
- `GET /api/workspaces/:slug/projects/:project_id/external-contours/`
|
||||||
|
|
||||||
|
Сейчас возвращает только записи, где:
|
||||||
|
- `extra.bridge = external-contours`
|
||||||
|
- `extra.source_project_id = current project`
|
||||||
|
|
||||||
|
То есть это только исходящие запросы проекта-источника.
|
||||||
|
|
||||||
|
Следствие:
|
||||||
|
- текущий список не умеет входящие
|
||||||
|
- текущий detail endpoint тоже source-side only
|
||||||
|
|
||||||
|
### 2. Detail endpoint тоже завязан только на перспективу источника
|
||||||
|
|
||||||
|
Текущий detail:
|
||||||
|
- `GET /api/workspaces/:slug/projects/:project_id/external-contours/:request_id/`
|
||||||
|
|
||||||
|
Он тоже фильтрует по `extra.source_project_id = current project`.
|
||||||
|
|
||||||
|
Следствие:
|
||||||
|
- из проекта-цели нельзя открыть ту же сущность через тот же endpoint
|
||||||
|
- двусторонняя доска не может использовать один и тот же detail flow без нового контракта доступа
|
||||||
|
|
||||||
|
### 3. Frontend store внешних контуров слишком узкий
|
||||||
|
|
||||||
|
Текущий `ProjectExternalContoursStore` умеет:
|
||||||
|
- список запросов
|
||||||
|
- вкладки `open / closed`
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- source-side actions `accept / decline / reply`
|
||||||
|
|
||||||
|
Но он не умеет:
|
||||||
|
- фильтры по пользователям, статусам, датам и проектам
|
||||||
|
- сортировки
|
||||||
|
- две зоны в одной модели
|
||||||
|
- отдельные cursors по зонам
|
||||||
|
|
||||||
|
### 4. Входящая сторона живет в другом модуле
|
||||||
|
|
||||||
|
Входящие рабочие объекты сейчас живут в `intake`:
|
||||||
|
- у них свой store
|
||||||
|
- свой фильтровый тип
|
||||||
|
- своя пагинация
|
||||||
|
- своя модель выдачи
|
||||||
|
|
||||||
|
То есть сегодня `Исходящие` и `Входящие` — это две разные подсистемы.
|
||||||
|
|
||||||
|
### 5. Существующий `views` слой нельзя просто взять как есть
|
||||||
|
|
||||||
|
Слой `ProjectView` уже умеет:
|
||||||
|
- rich filters
|
||||||
|
- display filters
|
||||||
|
- display properties
|
||||||
|
|
||||||
|
Но он привязан к обычным `Issue` layouts проекта.
|
||||||
|
|
||||||
|
Он не является готовой моделью для межконтурной доски, потому что:
|
||||||
|
- колонка там означает layout/grouping issues
|
||||||
|
- а в `Внешних контурах` колонка должна означать направление или выборку
|
||||||
|
- и сама сущность там не сводится к plain `Issue`
|
||||||
|
|
||||||
|
## Технический вывод
|
||||||
|
|
||||||
|
Новая доска должна строиться не вокруг существующего `Issue board`, а вокруг отдельного board contract для сущности `External Contour Request`.
|
||||||
|
|
||||||
|
При этом сам доменный источник правды можно по-прежнему держать на `IntakeIssue + bridge metadata`.
|
||||||
|
|
||||||
|
## Что считаем единицей доски
|
||||||
|
|
||||||
|
Единица двусторонней доски — это не обычный `Issue`.
|
||||||
|
|
||||||
|
Единица доски — это `External Contour Board Item`, то есть проекция bridge-сущности на UI-слой внешнего контура.
|
||||||
|
|
||||||
|
Базовый идентификатор:
|
||||||
|
- `request_id = IntakeIssue.id`
|
||||||
|
|
||||||
|
Это важно, потому что:
|
||||||
|
- исходящий и входящий сценарии должны указывать на одну и ту же межконтурную сущность
|
||||||
|
- detail-shell должен открываться по одному стабильному id
|
||||||
|
|
||||||
|
## Целевой frontend type contract
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type TExternalContourBoardDirection = "outgoing" | "incoming";
|
||||||
|
|
||||||
|
type TExternalContourBoardStatus = "open" | "closed";
|
||||||
|
|
||||||
|
type TExternalContourBoardItem = {
|
||||||
|
id: string;
|
||||||
|
direction: TExternalContourBoardDirection;
|
||||||
|
status: TExternalContourBoardStatus;
|
||||||
|
has_unread_updates: boolean;
|
||||||
|
requested_at: string | null;
|
||||||
|
updated_at: string;
|
||||||
|
source_decision?: "accepted" | null;
|
||||||
|
issue: {
|
||||||
|
id: string;
|
||||||
|
sequence_id: number | null;
|
||||||
|
name: string;
|
||||||
|
description_html?: string | null;
|
||||||
|
priority?: "low" | "medium" | "high" | "urgent" | "none";
|
||||||
|
target_date?: string | null;
|
||||||
|
state_id?: string | null;
|
||||||
|
state_detail?: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
group: string;
|
||||||
|
color: string;
|
||||||
|
} | null;
|
||||||
|
assignee_details?: {
|
||||||
|
id: string;
|
||||||
|
display_name: string;
|
||||||
|
avatar_url?: string | null;
|
||||||
|
}[];
|
||||||
|
created_by_detail?: {
|
||||||
|
id: string;
|
||||||
|
display_name: string;
|
||||||
|
avatar_url?: string | null;
|
||||||
|
} | null;
|
||||||
|
label_details?: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
source_project: {
|
||||||
|
id: string;
|
||||||
|
identifier?: string | null;
|
||||||
|
name: string;
|
||||||
|
logo_props?: unknown;
|
||||||
|
} | null;
|
||||||
|
target_project: {
|
||||||
|
id: string;
|
||||||
|
identifier?: string | null;
|
||||||
|
name: string;
|
||||||
|
logo_props?: unknown;
|
||||||
|
} | null;
|
||||||
|
requested_by: {
|
||||||
|
id: string | null;
|
||||||
|
display_name: string | null;
|
||||||
|
} | null;
|
||||||
|
capabilities: {
|
||||||
|
can_open_detail: boolean;
|
||||||
|
can_open_target_issue: boolean;
|
||||||
|
can_edit_request: boolean;
|
||||||
|
can_reply: boolean;
|
||||||
|
can_source_decide: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Целевой filter contract
|
||||||
|
|
||||||
|
Это отдельный filter layer для board-level представления, а не копия `inbox` и не копия `project views`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type TExternalContourBoardFilter = {
|
||||||
|
direction?: TExternalContourBoardDirection[];
|
||||||
|
status?: ("open" | "closed")[];
|
||||||
|
state_ids?: string[];
|
||||||
|
priority?: ("low" | "medium" | "high" | "urgent" | "none")[];
|
||||||
|
assignee_ids?: string[];
|
||||||
|
created_by_ids?: string[];
|
||||||
|
requested_by_ids?: string[];
|
||||||
|
source_project_ids?: string[];
|
||||||
|
target_project_ids?: string[];
|
||||||
|
label_ids?: string[];
|
||||||
|
has_unread_updates?: boolean;
|
||||||
|
created_at?: string[];
|
||||||
|
updated_at?: string[];
|
||||||
|
target_date?: string[];
|
||||||
|
search?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TExternalContourBoardSorting = {
|
||||||
|
order_by?: "requested_at" | "updated_at" | "issue__sequence_id" | "target_date";
|
||||||
|
sort_by?: "asc" | "desc";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Почему фильтры именно такие
|
||||||
|
|
||||||
|
- `direction` нужен для будущих пользовательских представлений
|
||||||
|
- `status` нужен для рабочего деления `open / closed`
|
||||||
|
- `state_ids`, `assignee_ids`, `created_by_ids`, `label_ids`, `priority` повторяют рабочую логику внутренних контуров
|
||||||
|
- `source_project_ids` и `target_project_ids` нужны именно для межконтурной аналитики и наблюдения
|
||||||
|
- `requested_by_ids` нужен отдельно, потому что внешний инициатор и внутренний `created_by` обычной задачи не всегда совпадают по смыслу
|
||||||
|
- `has_unread_updates` нужен для рабочего мониторинга
|
||||||
|
|
||||||
|
## Целевой backend API
|
||||||
|
|
||||||
|
### 1. Board list endpoint
|
||||||
|
|
||||||
|
Нужен отдельный endpoint уровня доски:
|
||||||
|
|
||||||
|
`GET /api/workspaces/:slug/projects/:project_id/external-contours/board/`
|
||||||
|
|
||||||
|
Он не должен заменять текущий source-side list сразу.
|
||||||
|
|
||||||
|
Он должен стать новым контрактом именно для двусторонней доски.
|
||||||
|
|
||||||
|
### Query params
|
||||||
|
|
||||||
|
```text
|
||||||
|
direction=outgoing,incoming
|
||||||
|
status=open,closed
|
||||||
|
state_ids=<uuid>,<uuid>
|
||||||
|
priority=urgent,high
|
||||||
|
assignee_ids=<uuid>,<uuid>
|
||||||
|
created_by_ids=<uuid>,<uuid>
|
||||||
|
requested_by_ids=<uuid>,<uuid>
|
||||||
|
source_project_ids=<uuid>,<uuid>
|
||||||
|
target_project_ids=<uuid>,<uuid>
|
||||||
|
label_ids=<uuid>,<uuid>
|
||||||
|
has_unread_updates=true
|
||||||
|
created_at=<range>,<range>
|
||||||
|
updated_at=<range>,<range>
|
||||||
|
target_date=<range>,<range>
|
||||||
|
search=<string>
|
||||||
|
order_by=updated_at
|
||||||
|
sort_by=desc
|
||||||
|
outgoing_cursor=<cursor>
|
||||||
|
incoming_cursor=<cursor>
|
||||||
|
per_page=20
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response shape
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"filters": {
|
||||||
|
"direction": ["outgoing", "incoming"],
|
||||||
|
"status": ["open"],
|
||||||
|
"assignee_ids": [],
|
||||||
|
"source_project_ids": []
|
||||||
|
},
|
||||||
|
"sorting": {
|
||||||
|
"order_by": "updated_at",
|
||||||
|
"sort_by": "desc"
|
||||||
|
},
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"key": "outgoing",
|
||||||
|
"title": "Исходящие",
|
||||||
|
"total_count": 12,
|
||||||
|
"next_cursor": "abc",
|
||||||
|
"results": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "incoming",
|
||||||
|
"title": "Входящие",
|
||||||
|
"total_count": 7,
|
||||||
|
"next_cursor": "def",
|
||||||
|
"results": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Почему один endpoint на обе зоны
|
||||||
|
|
||||||
|
Потому что это дает:
|
||||||
|
- единый filter contract
|
||||||
|
- единые count values
|
||||||
|
- единый sorting contract
|
||||||
|
- отсутствие расхождений между двумя независимыми загрузками
|
||||||
|
|
||||||
|
При этом пагинация должна быть раздельной:
|
||||||
|
- отдельный cursor для `outgoing`
|
||||||
|
- отдельный cursor для `incoming`
|
||||||
|
|
||||||
|
## Целевой detail contract
|
||||||
|
|
||||||
|
Нужен новый detail endpoint с перспективой доступа, а не только source-side read.
|
||||||
|
|
||||||
|
Рекомендуемый вариант:
|
||||||
|
|
||||||
|
`GET /api/workspaces/:slug/projects/:project_id/external-contours/board-items/:request_id/`
|
||||||
|
|
||||||
|
Контракт должен сам определить perspective относительно текущего `project_id`:
|
||||||
|
- если проект совпадает с `source_project_id` — это `outgoing`
|
||||||
|
- если проект совпадает с `target_project_id` или с проектом bridge issue — это `incoming`
|
||||||
|
|
||||||
|
Следствие:
|
||||||
|
- detail-shell открывается по одному route-contract
|
||||||
|
- входящая зона не должна притворяться source-side проектом только ради открытия карточки
|
||||||
|
|
||||||
|
### Что важно не ломать
|
||||||
|
|
||||||
|
Текущие source-side mutation endpoints можно оставить отдельными:
|
||||||
|
- update
|
||||||
|
- decision
|
||||||
|
- reply
|
||||||
|
|
||||||
|
Но read-model detail для board должен быть общим.
|
||||||
|
|
||||||
|
## Рекомендуемая модель backend aggregation
|
||||||
|
|
||||||
|
### Базовый источник правды
|
||||||
|
|
||||||
|
Базовая сущность не меняется:
|
||||||
|
- `IntakeIssue`
|
||||||
|
- `Issue`
|
||||||
|
- `extra.bridge = external-contours`
|
||||||
|
|
||||||
|
### Агрегация по направлениям
|
||||||
|
|
||||||
|
`outgoing`:
|
||||||
|
- `extra.source_project_id = current project`
|
||||||
|
|
||||||
|
`incoming`:
|
||||||
|
- `project_id = current project`
|
||||||
|
- `extra.bridge = external-contours`
|
||||||
|
|
||||||
|
### Нормализованный serializer
|
||||||
|
|
||||||
|
Нужен отдельный serializer уровня board item.
|
||||||
|
|
||||||
|
Он должен:
|
||||||
|
- выдавать `direction`
|
||||||
|
- выдавать обе project references
|
||||||
|
- отдавать capabilities
|
||||||
|
- отдавать status и has_unread_updates
|
||||||
|
- нормализовать issue-поля в один и тот же формат для обеих сторон
|
||||||
|
|
||||||
|
## Frontend store design
|
||||||
|
|
||||||
|
Рекомендуется не расширять бесконечно текущий `ProjectExternalContoursStore`.
|
||||||
|
|
||||||
|
Нужен отдельный store:
|
||||||
|
|
||||||
|
`ProjectExternalContoursBoardStore`
|
||||||
|
|
||||||
|
### Что он хранит
|
||||||
|
|
||||||
|
- board filters
|
||||||
|
- board sorting
|
||||||
|
- map items by id
|
||||||
|
- columns:
|
||||||
|
- `outgoing`
|
||||||
|
- `incoming`
|
||||||
|
- per-column cursor
|
||||||
|
- per-column total_count
|
||||||
|
- selected board item id
|
||||||
|
- board loader states
|
||||||
|
|
||||||
|
### Что остается в текущем store
|
||||||
|
|
||||||
|
Текущий `ProjectExternalContoursStore` можно временно оставить для:
|
||||||
|
- create request
|
||||||
|
- source-side update
|
||||||
|
- source-side decision
|
||||||
|
- source-side reply
|
||||||
|
- target project options
|
||||||
|
|
||||||
|
То есть board store отвечает за read-model, а существующий store пока отвечает за mutations.
|
||||||
|
|
||||||
|
Это позволит не ломать уже рабочий runtime одним большим переносом.
|
||||||
|
|
||||||
|
## UI contract
|
||||||
|
|
||||||
|
### 1. Доска состоит из фиксированных системных колонок
|
||||||
|
|
||||||
|
- колонка `Исходящие`
|
||||||
|
- колонка `Входящие`
|
||||||
|
- дальше уже поверх них могут появиться пользовательские представления
|
||||||
|
|
||||||
|
### 2. Колонка — это выборка, а не workflow stage
|
||||||
|
|
||||||
|
Следовательно:
|
||||||
|
- нет drag handle
|
||||||
|
- нет `onDrop`
|
||||||
|
- нет optimistic move между колонками
|
||||||
|
|
||||||
|
### 3. Клик по карточке ведет в shell шага 11
|
||||||
|
|
||||||
|
Детали должны открываться через общий shell, а не через отдельный старый source-only right pane.
|
||||||
|
|
||||||
|
## Что сознательно не делаем на этом шаге
|
||||||
|
|
||||||
|
### 1. Не склеиваем две выдачи в браузере
|
||||||
|
|
||||||
|
Это проигрышно из-за:
|
||||||
|
- разных сортировок
|
||||||
|
- разных count values
|
||||||
|
- разных filter models
|
||||||
|
- разных правил пагинации
|
||||||
|
|
||||||
|
### 2. Не превращаем board в kanban по статусам
|
||||||
|
|
||||||
|
Это не тот продуктовый сценарий.
|
||||||
|
|
||||||
|
### 3. Не переносим пользовательские колонки в первый технический контракт
|
||||||
|
|
||||||
|
Для начала нужен стабильный системный board layer.
|
||||||
|
|
||||||
|
Пользовательские представления должны появиться только поверх уже работающего fixed contract.
|
||||||
|
|
||||||
|
## Порядок реализации
|
||||||
|
|
||||||
|
### Шаг A. Backend contract
|
||||||
|
|
||||||
|
- board list endpoint
|
||||||
|
- common board item serializer
|
||||||
|
- detail read endpoint для обеих перспектив
|
||||||
|
- filter parsing
|
||||||
|
- per-column pagination
|
||||||
|
|
||||||
|
### Шаг B. Frontend types and services
|
||||||
|
|
||||||
|
- новые types для board item, filters, sorting, response
|
||||||
|
- новый service layer
|
||||||
|
- новый board store
|
||||||
|
|
||||||
|
### Шаг C. UI board shell
|
||||||
|
|
||||||
|
- fixed `Исходящие / Входящие`
|
||||||
|
- фильтровая пипка
|
||||||
|
- counts
|
||||||
|
- открытие detail-shell
|
||||||
|
|
||||||
|
### Шаг D. Cut-over
|
||||||
|
|
||||||
|
- перевод `Внешних контуров` со старого sidebar/list режима на board mode
|
||||||
|
- сохранение работающих mutation flows
|
||||||
|
- последующее упрощение legacy source-only списка
|
||||||
|
|
||||||
|
## Критерий приемки технического шага
|
||||||
|
|
||||||
|
- у команды есть конкретный API contract для двусторонней доски
|
||||||
|
- у команды есть отдельный frontend type contract, не завязанный на plain `Issue`
|
||||||
|
- у detail-shell есть единый read endpoint для `incoming` и `outgoing`
|
||||||
|
- документ прямо фиксирует отказ от frontend-склейки и drag-and-drop
|
||||||
|
|
||||||
|
## Связанные документы
|
||||||
|
|
||||||
|
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
||||||
|
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
||||||
|
- [phase-roadmap.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/phase-roadmap.md)
|
||||||
|
|
@ -489,3 +489,4 @@
|
||||||
- [phase-roadmap.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/phase-roadmap.md)
|
- [phase-roadmap.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/phase-roadmap.md)
|
||||||
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
||||||
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
||||||
|
- [13_STEP_external-contours-board-data-contract.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/13_STEP_external-contours-board-data-contract.md)
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
Подробные архитектурные шаги вынесены в:
|
Подробные архитектурные шаги вынесены в:
|
||||||
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
|
||||||
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
||||||
|
- [13_STEP_external-contours-board-data-contract.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/13_STEP_external-contours-board-data-contract.md)
|
||||||
|
|
||||||
## Этап 0. Термины и навигация
|
## Этап 0. Термины и навигация
|
||||||
|
|
||||||
|
|
@ -338,6 +339,7 @@
|
||||||
|
|
||||||
Подробно описано в:
|
Подробно описано в:
|
||||||
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
|
||||||
|
- [13_STEP_external-contours-board-data-contract.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/13_STEP_external-contours-board-data-contract.md)
|
||||||
|
|
||||||
## Этап 8. Пользовательские представления поверх двусторонней доски
|
## Этап 8. Пользовательские представления поверх двусторонней доски
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue