# Announcement Pin Action Enhancement Report ## 1. Existing Structure Review - Reused the existing `announcements` feature structure under `src/features/announcements/` with the current `api/service/mutations/types`, route handlers, React Query, and form workflow. - Reused the existing database field `isPin` / `is_pin`; no new pin table or parallel state model was introduced. - Reused the current content workflow helpers from `src/features/content-approval/lib/workflow.ts` for publish/archive gating. - Reused the existing audit infrastructure in `src/features/audit-logs/server/audit-service.ts` and `src/features/audit-logs/server/audit-log-data.ts`. - Extended the existing announcements list/detail UI instead of creating a new action framework. - Refactored create/edit form behavior so pin state is no longer part of form submission. ## 2. Files Changed - `src/features/announcements/api/types.ts` - `src/features/announcements/api/service.ts` - `src/features/announcements/api/mutations.ts` - `src/features/announcements/schemas/announcement.ts` - `src/features/announcements/components/announcement-form.tsx` - `src/features/announcements/components/announcements-page.tsx` - `src/features/announcements/components/announcement-view-page.tsx` - `src/features/announcements/server/announcement-data.ts` - `src/features/announcements/lib/pin.ts` - `src/app/api/announcements/route.ts` - `src/app/api/announcements/[id]/route.ts` - `src/app/api/announcements/[id]/pin/route.ts` - `src/app/api/announcements/[id]/unpin/route.ts` - `src/features/audit-logs/server/audit-service.ts` - `src/features/audit-logs/server/audit-log-data.ts` - `src/features/audit-logs/constants/audit-log-options.ts` ## 3. UI Changes - Removed the pin checkbox/section from both create and edit announcement forms. - Added pin status badge on announcement list cards and detail header. - Added pin/unpin actions to the announcement list action area. - Added pin/unpin actions to the announcement detail action area. - Kept the existing responsive card layout and action button patterns. ## 4. Business Rules - Only published announcements that have already started and are not expired can be pinned. - Archived announcements are automatically unpinned in the existing workflow update route. - Expired or otherwise ineligible pinned announcements are filtered out from pinned-first behavior and pinned-only filtering. - Announcement ordering now prioritizes only active pinned announcements instead of every row with `is_pin = true`. - Multiple pinned announcements remain supported; ordering among them still follows existing recency ordering. ## 5. Permission - Reused `announcement:publish` as the permission for managing pin/unpin actions. - Client-side checks use `canManageAnnouncementPin(...)` to hide unavailable actions. - Server-side checks in `/api/announcements/[id]/pin` and `/api/announcements/[id]/unpin` enforce the same permission and eligibility rules. ## 6. Database and API Changes - No schema migration was added because the existing `isPin` field already supports the feature. - Create now defaults pin state to `false`. - Create/edit payloads no longer send `isPin` from the form. - Added dedicated endpoints: - `POST /api/announcements/:id/pin` - `POST /api/announcements/:id/unpin` - Kept the existing workflow route focused on content state transitions instead of pin state changes. ## 7. Audit Log - Added `ANNOUNCEMENT_PINNED` - Added `ANNOUNCEMENT_UNPINNED` - Added formatted Thai audit messages and filter options for both actions. ## 8. Testing Result - Functional: implemented and code-reviewed against the requested workflow. - Permission: client/server checks were added for restricted pin management. - Responsive: list/detail changes follow existing flex-wrap action layouts and badge patterns. - Regression: create/edit/workflow logic was kept on the same route and helper stack, with pin logic isolated into dedicated endpoints. - Validation status: `lint` and `build` should be used as final verification for this change set. ## 9. Remaining Improvements - Add explicit pin priority if the business wants manual ordering among multiple pinned announcements. - Add optional automatic cleanup to clear `is_pin` when announcements expire, not only filter them out. - Add a dedicated `announcement:pin` permission if pin management needs to diverge from publish authority later. - Consider a dropdown action menu if the announcement action area grows further.