Add multi-project support: projects entity, picker home page, project context

Projects become the top-level container; SOPs and Work Packages belong to one.

Backend:
- New projects table + CRUD (/api/projects).
- sops.project_id (FK, cascade) and work_packages.project_id added;
  list/latest/metrics endpoints accept a project_id filter.

Front end (now under html/):
- project-data.js: shared API-first ProjectData adapter with localStorage
  fallback + active-project helpers.
- Home page: removed "About This Suite"; added a Project picker (create /
  use sample / select). Tool cards stay hidden until a project is active and
  carry &project=<id>; hero shows the active project.
- Suite reads ?project, resolves it, shows it in the header, and prefills the
  SOP project fields; passes &project into the WP-creator iframe.
- WP creator stamps projectId onto saved packages.

SOP/WP localStorage is not yet namespaced per project (next step).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 15:39:45 -07:00
parent 4d111d608d
commit 3c40b58ff8
9 changed files with 437 additions and 39 deletions

View File

@@ -130,6 +130,42 @@ to `fetch('/api/wps…')` in Phase 2 and the UI is unchanged.
> real data this is fine; once there is, add Alembic (see open question #2) and
> migrate rather than relying on `create_all`.
## Multi-project support
> **Note on layout:** the IT admin moved all static files into **`html/`** and
> added a Docker/NGINX deployment (`Dockerfile`, `docker-compose.yml`, `nginx/`).
> Front-end paths below are under `html/`. `server/` stayed at the repo root.
The suite is now multi-project. **Projects are the top-level container**; every
SOP and Work Package belongs to one.
- **Backend:** new `projects` table + CRUD (`/api/projects`). `sops` gained
`project_id` (FK, cascade) and `work_packages` gained `project_id`; list/latest/
metrics endpoints accept a `project_id` filter.
- **Project layer:** [html/project-data.js](html/project-data.js) — a shared,
**API-first** `ProjectData` adapter (`list/get/save/remove` hit `/api/projects`)
that **falls back to a localStorage mirror** (`wp_projects`) when the API is
unreachable, plus active-project helpers (`getActive`/`setActive`, stored in
`wp_active_project` / `wp_active_project_obj`).
- **Home page** ([html/index.html](html/index.html)): "About This Suite" removed;
a **Project** picker added. With no projects it offers *Create Project* / *Use
Sample Project*; otherwise a dropdown to select. The tool cards stay hidden
until a project is active and then carry `&project=<id>`; the hero shows the
active project.
- **Suite** ([html/work-package-suite-app.js](html/work-package-suite-app.js)):
reads `?project=<id>`, resolves it via `ProjectData`, shows it in the header,
and **prefills the SOP project fields** (step 1) from the project record when
empty. Passes `&project` into the WP-creator iframe.
- **WP creator:** stamps `projectId` onto every saved package (for API sync).
**Not yet done (the next fork):** SOP/WP *localStorage* is still global, not
namespaced per project — selecting a different project locally still shows the
same `wp_suite_sop` / `wp_iwp_v1` data. The intended end state is per-project
data via the API (`GET /api/sops/latest?project_id=…`, `GET /api/wps?project_id=…`).
Decide whether to (a) namespace the local keys by project id with a migration of
existing un-namespaced data into a "default" project, or (b) jump straight to the
API for SOP/WP reads. See the open question below.
**Pending — Phase 2: wire the front end to the API**
- SOP: on *SOP Complete*, `POST /api/sops`; on load, `GET /api/sops/latest` to hydrate the Creator (currently uses `localStorage` key `wp_suite_sop`).
- WP Creator: save packages via `POST /api/wps`; list/load via `GET /api/wps`