diff --git a/docs/feature-specs/project-program-identity.md b/docs/feature-specs/project-program-identity.md new file mode 100644 index 000000000..d80611d3a --- /dev/null +++ b/docs/feature-specs/project-program-identity.md @@ -0,0 +1,47 @@ + + +# Программа и статусы проекта + +Пользователь утвердил макет плашек 04.10.2026 и попросил показывать, к какой программе относится проект. Цель — изменение Angular/API в dev, без изменения правил сдачи и доступа. + +## Текущее поведение + +«Мои проекты» показывает четыре состояния с приоритетом submitted > program > draft > published. Привязка отображается как «В программе» фиолетовым; сдача — золотым. Название программы уже есть в `GET /auth/users/projects/` и `/auth/users/projects/leader/`, но не выводится. `GET /projects/{id}/` возвращает выбранную legacy-связь с минимальным PK без названия программы. + +## Целевое поведение и роли + +- Привязка: «Привязан к программе», нейтральная плашка с существующей иконкой `program`. +- Сдача: «Сдан в программу», `green-dark` на `green-light`, существующая иконка `lock`. +- «Черновик» и «Опубликован» сохраняются; не появляется состояние «Не сдан» или «На проверке». +- В карточках «Моих проектов» при известном названии есть строка «Программа: …». Длинная строка сокращается многоточием, полное название есть в title и доступном названии ссылки проекта. +- В детали проекта в существующем блоке «Основное» есть поле «Программа»: полное название с переносом и ссылкой на `/office/program/{program_id}`. Оно доступно тем же пользователям, которые уже могут читать эту деталь. +- Карточка остаётся 156×180, аватар 70, действие «Открыть» и нижний блок доступа сохраняются. При добавлении строки программы описание занимает одну строку вместо двух. +- Роль, права редактирования, приоритет статусов, выбранная legacy-связь, фильтры и маршруты не меняются. Неизвестный `is_submitted` не даёт права редактирования. + +## Контракт API и совместимость + +`GET /projects/{id}/` (а также ответы уже использующего этот serializer CRUD) добавляет read-only `partner_program.name` из `PartnerProgram.name`. Существующие `program_id`, `program_link_id`, `is_submitted`, `can_submit`, поля заявки и `null` сохраняются. Выбор связи остаётся по минимальному PK. Request, validation, permissions и errors не меняются; миграции не нужны. + +Angular DTO/model получает optional `name`, чтобы старый сервер оставался совместимым. Если имени в старом ответе нет, статус и доступ сохраняются; строка карточки отсутствует, в детали явно показано «Название не указано». Ссылка использует `program_id`, а не ID связи или проекта. Backend следует выпустить раньше Angular, чтобы имя сразу было доступно на обоих экранах. React не изменяется: добавление read-only поля не меняет его существующий контракт. + +## Acceptance criteria + +| AC | Предусловие и действие | Наблюдаемый результат / проверка | +| --- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| AC1 | Лидер или участник открывает «Мои проекты» с привязанным/сданным проектом | Согласованные подписи, разные иконки; lifecycle и права остаются независимыми. Component/HTTP integration tests и browser fixture. | +| AC2 | Ответ списка содержит название программы | Карточка показывает именно это название; весь проект остаётся одной ссылкой без вложенных ссылок/кнопок. Integration/component tests. | +| AC3 | Пользователь с действующим read access открывает деталь проекта со связью | Полное название программы и переход по program_id в «Основное». Component/API tests и browser fixture. | +| AC4 | Нет связи или имя отсутствует в legacy payload | Нет выдуманной программы или ошибок; прежние статус, доступ и маршрут работают. Component/API tests. | +| AC5 | У проекта несколько legacy-связей или программа переименована | Имя соответствует той же минимальной по PK связи, что статус и IDs; чтение не создаёт дополнительных запросов. Backend contract tests. | +| AC6 | Длинные имена/названия, ширина 320 и desktop | Нет наложений, размеры карточки/CTA сохранены; название на детали переносится. Browser geometry checks. | + +## План реализации и источники + +1. API: расширить `PartnerProgramProjectSerializer`, проверить parity list/detail, rename, выбор связи и существующие permissions/query-count tests (AC3–AC5). +2. Angular: DTO/model; `InfoCardComponent` и fixtures; поле в `ProjectsLeftSideComponent` (AC1–AC4). +3. Выполнить targeted tests, Angular build, проверки изменённых TS/SCSS и browser fixture реальных компонентов на representative widths (AC6). +4. Проверить финальный diff и подготовить отдельные API/Angular PR в dev. + +Визуальные источники: утверждённый макет текущего чата, Angular `_colors.scss`/Mont, существующий `InfoCard` и `ProjectsLeftSide`, `procollab-design-system-v1/docs/design-system/components/status.md`. Новые DS tokens/components не вводятся. Дополнение имени использует существующее metadata field и сохраняет композицию, поэтому не является отдельным редизайном. + +Не проверяется в этом scope: live production/deployment и изменение правил редактирования/сдачи. Loading/error/empty сохраняются в существующих контейнерах; новая metadata не вызывает дополнительных frontend запросов. diff --git a/projects/social_platform/src/app/domain/project/project.model.ts b/projects/social_platform/src/app/domain/project/project.model.ts index b08a904eb..3a1124123 100644 --- a/projects/social_platform/src/app/domain/project/project.model.ts +++ b/projects/social_platform/src/app/domain/project/project.model.ts @@ -14,6 +14,8 @@ import { Resource } from "./resource.model"; export class PartnerProgramInfo { id!: number; + /** Имя из list/detail API; optional для совместимости со старым сервером. */ + name?: string; programLinkId!: number; programId!: number; isSubmitted!: boolean; diff --git a/projects/social_platform/src/app/infrastructure/adapters/project/dto/project-program.dto.ts b/projects/social_platform/src/app/infrastructure/adapters/project/dto/project-program.dto.ts index 137444505..438c44706 100644 --- a/projects/social_platform/src/app/infrastructure/adapters/project/dto/project-program.dto.ts +++ b/projects/social_platform/src/app/infrastructure/adapters/project/dto/project-program.dto.ts @@ -2,6 +2,7 @@ export interface PartnerProgramInfoDto { id: number; + name?: string; programLinkId: number; programId: number; isSubmitted: boolean; diff --git a/projects/social_platform/src/app/ui/pages/projects/detail/info/components/projects-left-side/projects-left-side.component.html b/projects/social_platform/src/app/ui/pages/projects/detail/info/components/projects-left-side/projects-left-side.component.html index e2e498cf8..c01d687f8 100644 --- a/projects/social_platform/src/app/ui/pages/projects/detail/info/components/projects-left-side/projects-left-side.component.html +++ b/projects/social_platform/src/app/ui/pages/projects/detail/info/components/projects-left-side/projects-left-side.component.html @@ -8,6 +8,33 @@
+ {{ program.name?.trim() || "Название не указано" }} +
+ } ++ @if (presentation.lifecycle === "program") { + + } @else if (presentation.lifecycle === "submitted") { + + } {{ presentation.statusLabel }}
} @@ -67,6 +91,9 @@ } @else {Программа: {{ name }}
+ }