Files
alla-tms/docs/organizers-module-enhancement-report.md
2026-07-16 09:53:14 +07:00

165 lines
6.0 KiB
Markdown

# Organizers Module Enhancement Report
## Executive Summary
The organizers module was upgraded from a minimal create-and-list page into a CRUD-oriented management flow that supports soft delete, shared validation, audit logging, and runtime filtering for inactive organizers. The implementation keeps the existing Auth.js and Drizzle architecture intact and avoids introducing a new permission pattern that would conflict with the current super-admin entry flow.
## Current Architecture
- Next.js App Router with route handlers under `src/app/api`
- Auth.js session enrichment in `src/auth.ts`
- Drizzle ORM schema in `src/db/schema.ts`
- Feature-owned API/query/mutation contracts in `src/features/organizers`
- Shared UI stack with `Sheet`, `DropdownMenu`, `AlertModal`, and `PageContainer`
## Current Limitation
Before this enhancement, organizers only supported create and basic list rendering. There was no edit action, no soft delete, no inactive filtering in session flows, no feature API layer, and no organizer-specific audit events.
## Root Cause Analysis
- The original organizers page used direct `fetch()` calls and local state instead of the shared feature API/query pattern.
- The database schema did not include soft-delete metadata for organizations.
- Auth session enrichment loaded organizations without filtering inactive records.
- Route handlers existed only for `GET` and `POST`, so update and delete behavior was missing.
## Feature Comparison
Before
- View organizers
- Create organizer
After
- View active and inactive organizers
- Create organizer
- Edit organizer name
- Soft delete organizer
- Validation for required, trim, duplicate, length, and invalid characters
- Audit log for create, update, and soft delete
- Session and switcher filtering for inactive organizers
## Files Modified
- `src/db/schema.ts`
- `drizzle/0017_organizers_soft_delete.sql`
- `src/features/audit-logs/server/audit-service.ts`
- `src/features/organizers/api/types.ts`
- `src/features/organizers/api/service.ts`
- `src/features/organizers/api/queries.ts`
- `src/features/organizers/api/mutations.ts`
- `src/features/organizers/schemas/organizer.ts`
- `src/features/organizers/server/organizer-data.ts`
- `src/app/api/organizations/route.ts`
- `src/app/api/organizations/[id]/route.ts`
- `src/app/api/organizations/active/route.ts`
- `src/auth.ts`
- `src/lib/auth/session.ts`
- `src/features/users/server/user-data.ts`
- `src/components/modal/alert-modal.tsx`
- `src/components/org-switcher.tsx`
- `src/features/organizers/components/organizer-form-sheet.tsx`
- `src/features/organizers/components/organizer-card-actions.tsx`
- `src/features/organizers/components/organizer-listing.tsx`
- `src/features/organizers/components/organizers-page.tsx`
- `src/app/dashboard/organizers/page.tsx`
## Database Changes
- Added `organizations.is_active`
- Added `organizations.deleted_at`
- Added `organizations.deleted_by`
- Added foreign key from `deleted_by` to `users.id`
## API Changes
- `GET /api/organizations` supports organizer status filtering
- `POST /api/organizations` uses shared zod validation and duplicate checks
- `PATCH /api/organizations/[id]` updates organizer name
- `DELETE /api/organizations/[id]` performs soft delete only
- `PATCH /api/organizations/active` rejects inactive organizers
## UI Changes
- Replaced the local-state page with a React Query driven listing
- Added shared `Sheet` form for create and edit
- Added shared dropdown row actions
- Added confirmation modal for soft delete
- Added active/inactive status display and management notes
## Permission Changes
- Read access remains aligned to the existing page gate for HRD and super admin
- Create, edit, and soft delete are restricted to `requireSuperAdmin()` in the current architecture
- The implementation intentionally did not force org-scoped permission helpers onto the organizer entry flow because they depend on an active organization
## Validation Changes
- Organizer name is required
- Input is trimmed
- Maximum length is enforced
- Invalid characters are rejected
- Duplicate active organizer names are rejected
- Inactive and missing records are rejected on update/delete
## Soft Delete Design
- Soft delete updates the organizer record instead of physically deleting it
- Disabled organizers are marked with `is_active = false`
- Deletion metadata is stored in `deleted_at` and `deleted_by`
- Related users, memberships, training data, permissions, and audit history remain intact
- Inactive organizers are filtered out from runtime session and switcher flows
## Audit Log
- Added `ORGANIZATIONS` module
- Added `ORGANIZATION_CREATE`
- Added `ORGANIZATION_UPDATE`
- Added `ORGANIZATION_SOFT_DELETE`
## Testing Result
### Create
- Added backend validation and duplicate checks
- Manual runtime verification still required
### Edit
- Added update route and audit logging
- Manual runtime verification still required
### Delete
- Soft delete only
- Inactive organizers are blocked from re-delete
### Permission
- Management actions remain server-protected by super-admin checks
- UI hides management actions for non-managing users
### Regression
- Session loading now excludes inactive organizers
- Organization switching now rejects inactive organizers
- User management lookups now reject inactive target organizations
## Risks
- Existing data with duplicate organizer names may need manual review before relying on new duplicate constraints operationally
- Super-admin users who disable many organizers should still be tested against real seeded data to confirm expected fallback behavior
## Recommendations
- Add focused route-handler tests for organizers create/update/delete flows
- Add browser-level regression coverage for the organizers page and organization switcher
- Consider introducing a dedicated system-scoped permission helper if organizer administration expands beyond super admin
## Future Improvements
- Add search and status filtering controls on the organizers page
- Surface audit history for an organizer directly from the management UI
- Support organization metadata expansion when the schema grows beyond name and plan