diff --git a/docs/admin-modernization-plan.md b/docs/admin-modernization-plan.md index 8fe91c0..ab20e12 100644 --- a/docs/admin-modernization-plan.md +++ b/docs/admin-modernization-plan.md @@ -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`) +- 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` for the store’s form type to stay aligned with validation. -- Prefer `export type ProjectFormStore = ReturnType;` 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` for type alignment +- Exported `type ProjectFormStore = ReturnType` 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(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()`) 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(options)` factory +- Reactive status using `$state` +- 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('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.