docs: update admin modernization plan with Phase 2 completion

Updates to reflect current progress:
- Added progress overview showing Phase 2 complete
- Marked Task 3 (Project Form) as complete with implementation details
- Marked Task 6 (Autosave Store) as complete with feature summary
- Updated rollout strategy with phase completion status
- Documented 42% reduction in ProjectForm size (720 → 417 lines)

Phase 2 achievements:
- Composable form stores with Svelte 5 runes
- Reusable draft recovery and navigation guards
- Generic autosave store for all forms
- Manual QA complete

Next up: Phase 3 (List utilities & primitives)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Justin Edmund 2025-10-08 00:40:30 -07:00
parent 1339e81bf4
commit a0c8dda3d3

View file

@ -1,5 +1,22 @@
# Admin Interface Modernization Plan
## Progress Overview
**Current Status:** Phase 2 Complete ✅ (3 of 4 phases done)
- ✅ **Phase 0:** Runed integration (Task 0)
- ✅ **Phase 1:** Auth & data foundation (Tasks 1, 2)
- ✅ **Phase 2:** Form modernization (Tasks 3, 6)
- 🔄 **Phase 3:** List utilities & primitives (Tasks 4, 5) - **NEXT**
- 📋 **Phase 4:** Styling harmonization (Task 7)
**Recent Completion:** Task 3 - Project Form Modularization (Oct 7, 2025)
- Reduced ProjectForm from 720 → 417 lines (42%)
- Created reusable composable stores and helpers
- Manual QA complete
---
## Goals
- Deliver an admin surface that uses idiomatic Svelte 5 + Runes with first-class TypeScript.
- Replace client-side authentication fallbacks with server-validated sessions and consistent typing.
@ -94,29 +111,40 @@
---
## Task 3 Project Form Modularization & Store Extraction
## Task 3 Project Form Modularization & Store Extraction ✅
**Status:** ✅ **COMPLETED** (Oct 7, 2025) - Commit `34a3e37`
**Objective:** Split `ProjectForm.svelte` into composable, typed stores and view modules.
### Steps
1. Create `src/lib/components/admin/project-form/` folder with:
- `ProjectFormShell.svelte` (layout, header, actions).
- `ProjectMetadataSection.svelte`, `ProjectBrandingSection.svelte`, `ProjectAssetsSection.svelte` (each consuming a shared store).
- `CaseStudyEditor.svelte` for the composer panel.
2. Extract a store factory `createProjectFormStore(project?: Project)` in `src/lib/stores/project-form.ts` that returns typed read/write handles (`fields`, `validation`, `status`, `actions`).
3. Move autosave and draft recovery logic into dedicated helpers:
- `useProjectAutosave(store, { projectId })` (wraps Task 6 autosave store).
- `useDraftRecovery(store, draftKey)` to encapsulate prompt/timer behavior.
4. Rebuild the route components (`projects/new`, `[id]/edit`) to instantiate the store and pass it into the shell via props.
### Implementation Summary
Created reusable form patterns following Svelte 5 best practices:
**New Files:**
- `src/lib/stores/project-form.svelte.ts` (114 lines) - Store factory with `$state`, `$derived`, validation
- `src/lib/admin/useDraftRecovery.svelte.ts` (62 lines) - Generic draft restoration with auto-detection
- `src/lib/admin/useFormGuards.svelte.ts` (56 lines) - Navigation guards, beforeunload, Cmd+S shortcuts
- `src/lib/components/admin/DraftPrompt.svelte` (92 lines) - Reusable draft prompt UI component
**Refactored:**
- `src/lib/components/admin/ProjectForm.svelte` - Reduced from 720 → 417 lines (42% reduction)
### Key Achievements
- All form state centralized in composable store
- Draft recovery, navigation guards fully extracted and reusable
- Type-safe with full generic support (`useDraftRecovery<TPayload>`)
- Patterns ready for PostForm, MediaForm, etc.
- Build passes, manual QA complete
### Implementation Notes
- Expose store fields as `readonly` derived getters (`const title = $derived(store.fields.title)`) to stay idiomatic with runes.
- Use `z.infer<typeof projectSchema>` for the stores form type to stay aligned with validation.
- Prefer `export type ProjectFormStore = ReturnType<typeof createProjectFormStore>;` for downstream usage.
- State returned directly from factories (no `readonly` wrappers needed in Svelte 5)
- Used `$state`, `$derived`, `$effect` runes throughout
- Store factory uses `z.infer<typeof projectSchema>` for type alignment
- Exported `type ProjectFormStore = ReturnType<typeof createProjectFormStore>` for downstream usage
### Dependencies
- Depends on Task 2 actions for create/update to avoid duplicating mutation logic.
- Leverages Task 6 autosave refactor.
- ✅ Task 2 (data fetching) - complete
- ✅ Task 6 (autosave store) - complete
---
@ -163,25 +191,37 @@
---
## Task 6 Autosave Store & Draft Persistence
## Task 6 Autosave Store & Draft Persistence ✅
**Status:** ✅ **COMPLETED** (Earlier in Phase 2)
**Objective:** Turn autosave logic into a typed store for reuse across forms.
### Steps
1. Wrap `createAutoSaveController` into `createAutoSaveStore<TPayload, TResponse>(options)` that returns:
- Writable rune store for status (`$state`),
- Methods `schedule`, `flush`, `cancel`,
- Optional `onError` and `onSaved` callbacks.
2. Update `ProjectForm` (post-refactor) to consume the store instead of managing controller lifecycles manually.
3. Extend `draftStore.ts` with typed helpers (`loadDraft<T extends DraftPayload>()`) and integrate into the new store so persistence happens automatically when schedules run.
4. Document the pattern for future forms (e.g., post editor) in `docs/autosave-completion-guide.md`.
### Implementation Summary
Created `src/lib/admin/autoSave.svelte.ts` with:
- Generic `createAutoSaveStore<TPayload, TResponse>(options)` factory
- Reactive status using `$state<AutoSaveStatus>`
- Methods: `schedule()`, `flush()`, `destroy()`, `prime()`
- Debounced saves with abort controller support
- Online/offline detection with automatic retry
- Draft persistence fallback when offline
**Documented in:** `docs/autosave-completion-guide.md`
### Key Features
- Fully typed with TypeScript generics
- Integrates with `draftStore.ts` for localStorage fallback
- Used successfully in refactored ProjectForm
- Reusable across all admin forms
### Implementation Notes
- Use TypeScript overloads or generics for `save` to ensure the response type flows back to callers.
- Prefer rune subscriptions inside the store (`const status = $state<AutoSaveStatus>('idle')`).
- Returns reactive `$state` for status tracking
- Accepts `onSaved` callback with `prime()` helper for baseline updates
- Handles concurrent saves with abort controller
- Automatically transitions from 'saved' → 'idle' after delay
### Dependencies
- Requires Task 2 mutation path so autosave can call shared helpers.
- ✅ Task 2 (mutation endpoints) - complete
---
@ -205,10 +245,31 @@
---
## Rollout Strategy
0. **Phase 0:** Execute Task 0 to integrate Runed and document approved utility usage.
1. **Phase 1:** Complete Task 1 & Task 2 to stabilize auth/data flows (blocks others).
2. **Phase 2:** Execute Task 3 and Task 6 to modernize the heaviest form.
3. **Phase 3:** Apply Task 4 and Task 5 across lists; retrofit dropdowns and filters.
4. **Phase 4:** Finish with Task 7 styling clean-up and documentation updates.
### ✅ Phase 0: Runed Integration (Complete)
- ✅ Task 0: Runed utility layer integrated and documented
- Projects index page using `resource` for data fetching
- `onClickOutside` implemented for dropdowns
### ✅ Phase 1: Auth & Data Foundation (Complete)
- ✅ Task 1: Server-side authentication with session flow
- ✅ Task 2: Unified data fetching & mutation pipeline
- HttpOnly cookie authentication working
- Server loads with typed `satisfies` clauses
### ✅ Phase 2: Form Modernization (Complete)
- ✅ Task 6: Autosave store with draft persistence
- ✅ Task 3: Project form modularization with composable stores
- Reduced ProjectForm from 720 → 417 lines (42%)
- Reusable patterns ready for other forms
### 🔄 Phase 3: List Utilities & Primitives (Next)
- ⏳ Task 4: Shared list filtering utilities
- ⏳ Task 5: Dropdown, modal, and click-outside primitives
### 📋 Phase 4: Styling Harmonization (Future)
- ⏳ Task 7: Styling & theming cleanup
---
Each task section above can serve as a standalone issue. Ensure QA includes regression passes for projects, posts, and media operations after every phase.