Skip to content

Commit 2687876

Browse files
authored
Merge pull request #20 from ZDOSS/codex/fix-folder-project-persistence
Fix folder-backed project flows and duplicate linking
2 parents ef2dbe7 + 469ee8e commit 2687876

11 files changed

Lines changed: 455 additions & 69 deletions

File tree

AI.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
7373
## Storage model summary
7474

7575
- canonical durable format: `project.pms.json` inside `.pm-suite/` (or browser `localStorage` as a labeled compatibility layer)
76-
- adapter contract: `ProjectStoreAdapter` in `packages/core/src/storage/store.ts`
76+
- adapter contract: `ProjectStoreAdapter` in `packages/core/src/storage/store.ts`; folder-capable adapters may implement `loadFolderProject(key)` for files discovered by a currently selected folder even when the browser-local metadata index has never seen that project
7777
- `WebLocalStorageAdapter` for browser/PWA mode
7878
- the web adapter is now hybrid: browser-local storage remains the default, but browsers with File System Access support can persist project files into a user-chosen local folder and remember that folder handle through IndexedDB
7979
- `DesktopAdapter` for Tauri (calls the registered Rust commands and falls back to `localStorage` when Tauri is absent in dev)
@@ -82,6 +82,7 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
8282
- trust status is surfaced in the UI as a `Folder-backed` / `Browser-local` / `Unsaved` badge
8383
- desktop storage now only writes to the filesystem when a folder path has actually been attached; otherwise the desktop shell behaves as browser-local storage on purpose instead of pretending to be folder-backed
8484
- recent-project reopen uses the active adapter's `load()` path rather than forcing JSON import; desktop recents restore the remembered folder path before loading
85+
- new project creation now saves through the active adapter before navigation, so folder-backed creates produce the initial `.pm-suite/<project-id>.pms.json` immediately instead of waiting for a later dirty auto-save
8586
- launcher reopen paths now validate imported bundles before calling `setBundle()`, matching the startup restore and direct storage-load paths so corrupt saved data is rejected consistently instead of silently entering the UI store
8687
- the two UI JSON-import entry points now also perform an explicit `validateProjectBundle()` immediately before `setBundle()`, mirroring the reopen paths even though `importProjectJson()` already validates internally; this keeps the UI-side contract obvious and avoids review drift about where store writes are gated
8788
- the desktop recent-project reopen path still depends on `DesktopAdapter.load()` reading the active folder from `localStorage` at call time; `ProjectsListView` now documents that ordering explicitly so later adapter refactors do not accidentally cache the folder too early
@@ -90,6 +91,7 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
9091
- session restore now treats corrupt or invalid persisted bundles as stale state: failed import/validation clears `gph.active.project` instead of bubbling an unhandled rejection through the startup hook
9192
- the web runtime now installs the same `WebLocalStorageAdapter` instance into both `window.__gph_store` and `WebStorageAdapter.adapter`, preventing auto-save and startup restore from drifting onto different adapter instances if adapter-local state is added later
9293
- the desktop runtime now installs the same `DesktopStorageAdapter.adapter` instance into `window.__gph_store`; folder-backed desktop saves/loads/existence checks/deletes call `save_project`, `load_project`, `project_exists`, and `delete_project`
94+
- `useProjectStore.setBundle()` and `markSaved()` normalize `bundle.projectSettings.storageTrust` to the runtime storage trust, so overview/settings/header storage surfaces do not keep showing browser-local after a folder save or open
9395

9496
## Command surface
9597

@@ -164,10 +166,12 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
164166
- browser-vs-folder storage explanation
165167
- explicit delete/remove confirmation for saved projects
166168
- folder-backed delete is intentionally "remove recent shortcut only" and does not delete filesystem data
167-
- desktop folder-path attach flow for new projects
169+
- desktop folder-path attach flow for new projects, with the first project file written before entering the app
168170
- desktop folder scan/open flow for existing `.pm-suite` saves
169171
- PWA/browser folder picker for creating and reopening local-folder projects when File System Access is available
172+
- direct folder-file open through `loadFolderProject()` when a selected folder lists a project that has no local index metadata
170173
- automatic last-project restore after reload via persisted active-session metadata
174+
- new-project modal dismissal is explicit through Cancel/Create, not backdrop or header-close clicks
171175
- an explicit `/projects` launcher route; `/` redirects an already-open/restored project to `/overview` so the real app root honors the in-project overview default without removing the launcher
172176
- per-project view tabs across overview, board, backlog, table, roadmap, calendar, docs, bug triage, my work, search, trash, and saved planning views; `AppShell` reads saved board/backlog/table/bug/my-work views from the active bundle and keeps them separate from hidden built-in route preferences
173177
- `/overview` is now the default in-project landing route; `OverviewView` derives health summaries from the active bundle, including active work, milestone progress, blocking relationships, future-only upcoming dates/reminders, triage-lane bug intake, recent activity, and the current storage trust/save state without adding new persisted overview state
@@ -229,7 +233,7 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
229233
- roadmap lanes now show milestone target dates, completed/total/percent progress, dependency indicators from `relationshipsForItem()`, explicit date inputs, milestone reassignment controls, and inline invalid-range feedback while preserving date-only semantics through `item.update`; clearing Start or Due clears only that side of the range
230234
- calendar now keeps the month grid and adds a derived agenda for upcoming item start/due dates plus active reminders; reminder agenda rows use the reminder's IANA timezone to decide the visible date, boundary filtering keeps reminders visible when their local display date and UTC date straddle the agenda start, agenda links use existing work-item routes, and the feature does not introduce a calendar-specific storage model
231235
- bug triage now exposes a visible `New bug` action in the intake column, maps software-project `inbox` bugs into Intake, opens the shared create dialog with the correct intake status preselected, and limits Intake's planned-status fallback so custom workflows can still populate Ready; `buildBugTriageColumns()` is shared with overview so accepted Ready bugs do not reappear as intake pressure
232-
- bug triage cards are now `<article>` surfaces with an internal item link and real form controls, not whole-card links, so triage buttons/selects are valid and testable; accept/decline/assign dispatch `item.update`, decline resolves to an existing canceled status or completed fallback before dispatching, snooze dispatches `reminder.create`, and duplicate linking dispatches `relationship.create` with `relatesTo`
236+
- bug triage cards are now `<article>` surfaces with an internal item link and real form controls, not whole-card links, so triage buttons/selects are valid and testable; accept/decline/assign dispatch `item.update`, decline resolves to an existing canceled status or completed fallback before dispatching, snooze dispatches `reminder.create`, and duplicate linking opens a picker modal before dispatching `relationship.create` with `relatesTo`
233237
- bug triage toolbar now includes severity and priority filters, cards can edit severity/priority plus plugin-owned source/context data stored under `moduleData.bug`, and the optional Workflow setting blocks Accept/Decline out of intake until a bug has either severity or priority
234238
- automation settings can create, dry-run preview, enable/disable, and delete rules; the first builder supports item-created/updated/status/due-date/milestone triggers plus set-field, add/remove-label, move-status, assign-milestone, create-subtask, and generate-doc actions
235239
- automation rule execution is a side-effect layer after the originating item command succeeds: each action still dispatches through the validated command surface with source `automation`, but action validation failures are captured on `automation.executed.data.failedActionCount` / `failures` instead of throwing back through the user's item command
@@ -267,6 +271,9 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
267271
- board-card click behavior via `useNavigate` invocation
268272
- board-card keyboard activation with link semantics
269273
- silent handling of cancelled browser folder picks
274+
- immediate adapter save for new folder-backed PWA projects
275+
- local-folder project open without requiring browser-local index metadata
276+
- explicit Cancel/Create dismissal for the new-project modal
270277
- settings-row draft reset when upstream bundle data changes
271278
- work-item comment editing without `window.prompt`
272279
- work-item permanent delete confirmation without `window.confirm`
@@ -278,7 +285,7 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
278285
- work-item next-reminder summary behavior that ignores past reminders instead of promoting stale reminders as upcoming follow-up
279286
- bug triage intake visibility for software-workflow `inbox` bugs and intake-status prefill for `New bug`
280287
- bug triage fallback mapping that keeps a non-standard planned Ready status visible
281-
- bug triage filters for needs-repro and command-backed accept/decline/snooze/assign/duplicate actions
288+
- bug triage filters for needs-repro and command-backed accept/decline/snooze/assign/duplicate actions, including the duplicate picker modal and stale duplicate-error cleanup on cancel
282289
- bug triage severity/priority filtering, plugin-owned source/context editing, and the configured severity-or-priority intake exit gate
283290
- automation rule create/update/delete/enable/disable/dry-run commands, dispatcher execution through automation source commands, and Settings automation rule preview/save/toggle/delete flows
284291
- settings section decomposition, keyboard tab navigation, draft preservation across panel switches, and AI bridge future-capability copy that avoids placeholder install instructions
@@ -507,6 +514,13 @@ The core domain in `packages/core/src/domain/` covers the entities the plan call
507514
- combining labels/milestones and import/export into clearer workflow panels while preserving the existing command paths
508515
- replacing placeholder AI bridge install/setup copy with real command-coverage documentation and explicit "not shipped yet" runtime gaps
509516
- adding SettingsView regression coverage for panel splitting, keyboard navigation, and bridge truth copy
517+
- fixed folder-backed project and duplicate-link user-flow defects by:
518+
- saving new projects through the active storage adapter before navigating so selected-folder creates immediately write `.pm-suite/<project-id>.pms.json`
519+
- adding adapter-level `loadFolderProject()` support so folder scans can open selected `.pms.json` files even without browser-local index metadata
520+
- synchronizing runtime storage trust into `projectSettings.storageTrust` during `setBundle()` and `markSaved()`
521+
- requiring explicit Cancel/Create dismissal for the new-project modal
522+
- replacing the bug-triage duplicate target select with a searchable picker modal that confirms an existing bug before dispatching `relationship.create`; canceling the picker clears duplicate-scoped errors so stale relationship failures do not leak back into the toolbar
523+
- adding focused launcher and bug-triage regression coverage for those flows
510524

511525
## Open follow-on planning
512526

Readme.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A free, open source, hybrid day-one project management suite for practical softw
66

77
The MVP implementation is in place. The current build supports:
88

9-
- **Workspace** with new/open/demo project flow, recent-project reopen, browser-vs-folder storage guidance, inline delete/remove confirmation, an explicit `/projects` launcher route, and automatic restore of the last active project after reload
9+
- **Workspace** with new/open/demo project flow, immediate folder-backed project creation when a folder is selected, recent-project reopen, browser-vs-folder storage guidance, inline delete/remove confirmation, an explicit `/projects` launcher route, and automatic restore of the last active project after reload
1010
- **Shared UI foundation** with reusable buttons, icon buttons, fields, page headers, surfaces, toolbars, empty states, inline alerts, modal/dialog primitives, data tables, and work-item metadata components
1111
- **Overview** as the default project landing view for created, opened, imported, demo, and restored projects, summarizing active work, milestone progress, blocked items, future upcoming dates/reminders, triage-lane bug intake, recent activity, and the current storage/save state
1212
- **Board** with drag-and-drop, WIP limits (warn + hard modes), explicit hard-limit feedback, column-based status grouping, context-aware item creation that starts in the first board lane, and whole-card link navigation that keeps visible card metadata available to assistive technology
@@ -15,7 +15,7 @@ The MVP implementation is in place. The current build supports:
1515
- **Docs** with Markdown editing, sanitized rendering, internal embeds, command-backed sections, reusable document templates, in-surface doc search, linked-work and backlink context panels, router-safe in-app navigation for preview links, stale document-route recovery, correct pane updates when switching documents, draft-preserving editor resets, shared confirmation for document deletion, and safe navigation to the next active document after deleting the open one
1616
- **Roadmap / timeline** with date drag/resize, milestone lanes, milestone progress and target dates, dependency indicators, explicit date controls that clear each side of a range independently, milestone reassignment, invalid-range feedback, and shared zoom/anchor controls
1717
- **Calendar** with accessible month navigation controls, month grid, date-based item visibility, and an agenda for upcoming start/due dates and timezone-aware reminders that stay visible around UTC/local day boundaries
18-
- **Bug triage** with severity, priority, source/context metadata, reproduction steps, expected/actual behavior, environment, affected version, shared work-card metadata, practical triage filters, accept/decline/snooze/assign/duplicate actions, configurable severity-or-priority intake gates, workflow-safe decline handling, and a visible new-bug entry point that defaults to the Intake lane without starving Ready in custom planned workflows
18+
- **Bug triage** with severity, priority, source/context metadata, reproduction steps, expected/actual behavior, environment, affected version, shared work-card metadata, practical triage filters, accept/decline/snooze/assign actions, a searchable duplicate-link picker, configurable severity-or-priority intake gates, workflow-safe decline handling, and a visible new-bug entry point that defaults to the Intake lane without starving Ready in custom planned workflows
1919
- **My work** filtered to the locally selected member with a real member select control, shared work rows, and assigned-to-me creation
2020
- **Search** across items, docs, comments, and labels with shared search controls and grouped results
2121
- **Settings** split into focused panels for general project identity, appearance, storage, visible views, members, workflow, labels/milestones, custom fields, plugin trust, automation rules, import/export, and a truthful AI bridge readiness panel with keyboard-accessible section tabs that preserve in-progress drafts while switching sections
@@ -62,13 +62,15 @@ Note: This is a static client-side demo only. All data lives in the browser (loc
6262
## Storage notes
6363

6464
- In the **PWA/web app**, projects are browser-local by default. On browsers that support the File System Access API, the launcher can also bind the PWA to a real local folder and save `.pm-suite` project files there.
65+
- Creating a new project after selecting a folder writes the initial `.pm-suite/<project-id>.pms.json` file before the app enters the project, so the folder-backed copy exists immediately.
66+
- Opening from a selected folder reads the listed `.pms.json` file directly, even if that project has never been recorded in the browser-local recent-project index.
6567
- Reloading now restores the last active project from browser state instead of dropping you into an empty shell.
6668
- Older browser-local saves are repaired on load if their saved-project index metadata is missing, so reopening an existing project no longer depends on that index staying intact.
6769
- Reopening a saved project from the launcher now runs the same bundle validation used by startup restore and direct storage loads, so corrupt saved data is rejected consistently instead of loading halfway into the app.
6870
- The visible JSON import flows now also perform that same explicit validation right before the project store is replaced, so manual imports and reopen flows follow the same safety pattern.
6971
- Corrupt saved-session startup state is cleared automatically instead of breaking the app boot path, and canceling the browser folder picker is treated as a normal dismissal rather than a workspace error.
7072
- The web runtime now uses one shared storage-adapter instance for both auto-save and startup restore, which keeps the PWA's browser-local and folder-backed persistence paths aligned.
71-
- In the **desktop shell**, you can still work browser-locally, or attach a folder path for `.pm-suite` saves and reopen those folder-backed projects from the launcher.
73+
- In the **desktop shell**, you can still work browser-locally, or attach a folder path for `.pm-suite` saves and reopen those folder-backed projects from the launcher; new folder-backed projects are saved immediately through the same adapter path.
7274
- Desktop folder-backed saves, loads, existence checks, and deletes now call the registered Tauri commands (`save_project`, `load_project`, `project_exists`, `delete_project`) instead of unregistered filesystem-plugin command names.
7375
- Removing a folder-backed recent from the launcher only removes the shortcut; it does not delete the underlying filesystem project.
7476
- The command layer now hard-fails unknown member edits, validates item, custom-field, document-section, automation-rule, and saved-view references, rejects project-id mismatches, rejects unknown mutation targets, preserves `hiddenViewIds` defaults when opening older bundles, rejects lossy checklist reorders, validates saved-view filter/sort/order configuration, enforces configured bug-intake gates, creates omitted-title blank docs as `Untitled`, and keeps document trash/restore valid by moving document-scoped attachments to trash records while preserving document reminders for restore.
@@ -98,7 +100,7 @@ The UI/UX overhaul planning package lives in `docs/superpowers/specs/2026-07-02-
98100
| Suite | Count | Notes |
99101
| --- | --- | --- |
100102
| `packages/core` | 57 | Domain, storage, dispatcher, document sections/templates, automation rules, export, import |
101-
| `packages/ui` | 92 | AppShell, ProjectRouter, OverviewView, shared button and surface primitives, WorkItemModal attachment/reminder/custom-field coverage, TrashView, BoardView, saved planning views, BacklogView, BugTriageView, MyWorkView, TableView, RoadmapView, CalendarView, CommandPalette, CreateItemDialog, launcher, docs, settings, automation settings |
103+
| `packages/ui` | 96 | AppShell, ProjectRouter, OverviewView, shared button and surface primitives, WorkItemModal attachment/reminder/custom-field coverage, TrashView, BoardView, saved planning views, BacklogView, BugTriageView, MyWorkView, TableView, RoadmapView, CalendarView, CommandPalette, CreateItemDialog, launcher, docs, settings, automation settings |
102104
| `apps/desktop` | 2 | Desktop storage adapter command wiring |
103105
| `tests/e2e` | 7 | Hybrid parity, project workflow, theme, palette, export, search |
104106

0 commit comments

Comments
 (0)