# Unified Current Project API

Single source of truth for "the selected project" across the app. All project selection, share-link creation, guides, frameworks, and checklist use this API so the share page and app stay in sync.

**Cursor rule:** `.cursor/rules/UNIFIED_CURRENT_PROJECT_API.mdc` (use when editing app.js, share-links, guide/framework modules, storage, app-ui, app-init, app-data).

For **where and how to read/write project data** (stakeholders, checklist, etc.), see [Data Layer](DATA_LAYER.md).

## API (app.js)

- **Getter:** `getResolvedCurrentProjectId()`  
  Resolution order: `#project-select` value → `Blueprint.state.currentProjectId` → `window.currentProjectId` → in-memory `currentProjectId`.  
  **Guarantee:** If that would return null/empty/`__new__`/`__demo__` but there are projects, the getter sets and returns a valid project (single project, or saved/first) so the app is always "on a project" when projects exist.

- **Setter:** `setCurrentProjectId(id)`  
  Updates: in-memory `currentProjectId`, `Blueprint.currentProjectId`, `Blueprint.state.currentProjectId`, `window.currentProjectId`, `#project-select` value, `localStorage`, and server (when signed in) via `persistSelectedProjectIdToServer`.

- **Namespace:** `Blueprint.currentProject.get` / `Blueprint.currentProject.set`  
  Same as above; use when `window` is not preferred.

- **Exposed on window:** `window.getResolvedCurrentProjectId`, `window.setCurrentProjectId`

## Share link creation

Share links require a **saved project (UUID)**. There is no find-by-name or id replacement:

- If the current project id is not a UUID, creation fails with: *"Save your project first. Open the Project panel, edit the project name (or any field), wait for it to save, then create the share link again."*
- This keeps share-link creation simple and avoids mutating project or guide ids.

## Stakeholders and share page

- **Stakeholders** are persisted via `persistProjectStakeholders(projectId, stakeholders)` whenever the project has a UUID and the client exists (no extra gate like `projectsLoadedFromSupabase`). The share page reads `stakeholders` from `get_project_via_share_link` (migration 075).
- **Guides:** If a guide was left with a local project id (`proj_*`), `ensureGuideLinked` (app-guide-linking.js) allows re-linking to the current project UUID when the user saves, so the share page can show the guide after one save.
- **Guide insert 409:** New guides are inserted with `is_primary = false`, then promoted in a follow-up update if they should be primary, to avoid violating the unique index (one primary per project).

## Who uses it

| Module / file | Usage |
|---------------|--------|
| **app.js** | Defines getter/setter; all project selection (refreshUIAfterSupabaseLoad, create/delete/restore, delayed restore, applyStateFromShare) uses `setCurrentProjectId` or `getResolvedCurrentProjectId`. |
| **js/app-init.js** | `loadProject()` calls `window.setCurrentProjectId(projectId)` when available; `getStakeholderProjectId()` and `populateProjectSelect` use `getResolvedCurrentProjectId()` first. |
| **js/app-share-links.js** | `getCurrentProjectId()` returns `getResolvedCurrentProjectId()` first. |
| **js/app-guide-project.js** | `getCurrentProjectId()` returns `getResolvedCurrentProjectId()` first. |
| **js/app-guide-linking.js** | Same. |
| **js/app-framework-project.js** | Same. |
| **js/app-framework-linking.js** | Same. |
| **js/app-framework-management.js** | Same. |
| **js/storage.js** | `getCurrentProjectIdForStorage()` uses `getResolvedCurrentProjectId()` first (checklist get/set). |
| **js/app-ui.js** | Checklist render, quick-start select, framework grid/header: read via `getResolvedCurrentProjectId()` when available; when setting project (e.g. after create or quick-start select) calls `setCurrentProjectId(id)` when available. |

## Rules

1. **Read** current project only through `getResolvedCurrentProjectId()` (or `Blueprint.currentProject.get()`).
2. **Write** current project only through `setCurrentProjectId(id)` (or `Blueprint.currentProject.set(id)`), except the single declaration in app.js (`var currentProjectId = null`) and the implementation inside `setCurrentProjectId` itself.
3. **No override by guide/framework:** On load, current project comes only from persisted selection (server/localStorage) or, when there is exactly one project, that project. The selected guide’s project is never used to change the current project.

## Share page

The public share page (`/share/<token>`) does **not** use this API. It gets the project from `get_project_via_share_link(link_token)` and guides from `get_guides_via_share_link` / `get_guides_via_project_id` (migration 073). The unified API is for the main app only; share-link creation and management use it so the link is for the selected project, and stakeholders/guides persist to the same project the share page shows.
