6.16.3 Backend — thread `publicTagline`/`publicTags`/`viewerCanManage` through read/write
Estimate: 55m · Type: code · Depends on: 6.16.2
Thread publicTagline + publicTags + viewerCanManage through read + write (4-layer).
Read: add publicTagline: string | null and publicTags: string[] to PublicProjectOverviewDto + mapper (public-safe, only when public); surface via publicProjectsService.getOverview / lib/publicProjects/viewerContext. Add viewerCanManage: boolean (from the actor session + projectAccessService canManage) so the page can gate the Edit affordance server-side.
Write: generalize the 6.12.8 write path to author all three fields — extend projectsService.setPublicOverview (accept optional publicTagline, publicTags alongside publicOverviewMd) + projectRepository.setPublicOverview + the updateProjectOverviewAction input. Validation: trim; empty tagline → null; cap tagline at PUBLIC_TAGLINE_MAX_LENGTH; tags: trim each, drop empties, dedupe, cap count at PUBLIC_TAGS_MAX_COUNT and each at PUBLIC_TAG_MAX_LENGTH; typed errors (ProjectTaglineTooLongError, ProjectTagsInvalidError). Admin-gated via assertCanManage; one transaction.
Acceptance criteria
- Public overview DTO carries
publicTagline,publicTags,viewerCanManage; non-public / non-admin reads never leak edit ability. - One server action persists all three; validated + admin-gated; returns a DTO (no raw Prisma); typed errors mapped.
- Service/unit tests for the gate + tagline length + tags count/length (per-file coverage gate).
Context refs
lib/dto/publicProjects.ts,lib/mappers/publicProjectsMappers.ts,lib/services/publicProjectsService.ts,lib/publicProjects/viewerContext.tslib/services/projectsService.tssetPublicOverview (~664-685),lib/repositories/projectRepository.ts(~293-298)app/(authed)/settings/project/actions.tsupdateProjectOverviewAction (~84-112);projectAccessService.assertCanManage