# Cana project plan template

One shared viewer renders every project from JSON. Built-in projects live in `site/data/projects/`. A downloaded copy of `project-template.json` is the file `cana-project-template.json`.

## What each path does

- **Download template.** Create the JSON by hand. The starter already contains `meta`, `phases`, and `tabs`, and it passes the portal validator.
- **Upload project.** Choose a `.json` file or drop it on the project page. The browser reads it locally, validates it, and stores a passing file in this browser. Invalid JSON is rejected and is not rewritten. A repeated `meta.id` replaces the local draft only. A built-in project with the same id is not overwritten.
- **Create with AI.** The browser extracts text from DOCX, Markdown, TXT, or pasted notes, shows that text, and sends it to `POST /api/ai/project`. The draft must be reviewed. Accept stores a local draft. It does not publish an official project.
- **Built-in project.** Put reviewed JSON at `site/data/projects/<id>.json`, add it to `site/data/catalog.json`, and add a page at `site/projects/<id>/index.html` that points `data-project-src` at that file. Open a pull request. A person merges it.

Local draft means available in the current browser only. Built-in project means version-controlled in this repository.

## Required shape

Top-level fields are `meta`, `github`, `phases`, `prompts`, `updates`, `reporting`, and `tabs`.

`meta` requires:

- `id` — lowercase slug, such as `cyber-roadmap`. Checklist state is stored as `cana-project-checklist:<id>`.
- `title`

Useful optional fields: `eyebrow`, `subtitle`, `description`, `unit`, `unitPlural`, `doneWord`, `status`, `repositories`, `releaseTarget`, `targetMilestone`, `updated`, `headerStats`, `footer`.

`github` is optional and may be `null`. When present it needs `repo` as `owner/name`. `branch`, `prMap`, and `snapshot` are display fields. The viewer does not call GitHub and does not request `statusUrl`.

`phases[]` entries need `n`, `status`, and `title`. Optional fields include `date`, `purpose`, `intro`, `exit`, `deliverables`, `groups`, `table`, `refs`, `callout`, `blockers`, `risks`, `evidence`, and `acceptance`.

`tabs[]` must be non-empty. Each tab needs `id`, `label`, and `blocks`. A tab with no blocks is hidden.

## Blocks

Supported `type` values:

| type | required extra fields |
| --- | --- |
| panel (default when `type` is omitted) | none |
| status | none; renders the phase timeline and recorded snapshot |
| phases | none; renders phase detail |
| explorer | `items` with `label` |
| stepper | `items` strings |
| checklist | `items` strings; set `id` so ticks stay distinct |
| acceptance | `items` as `["name", "criteria"]` |
| glossary | `items` as `["term", "definition"]` |
| prompt-library | none; renders top-level `prompts` |
| updates | none; renders top-level `updates` |
| daily-report | none; builds a report from the project and the day’s update |

Panel fields that the template may include: `eyebrow`, `dark`, `style` (`note`), `body`, `bodySize` (`large`), `pills`, `flows`, `cards`, `table`, `list`, `callout`, `span` (`half`). `cardMin` and table `widths` are accepted and ignored. Project JSON cannot supply CSS, HTML, scripts, or remote resources.

## Statuses

Display the status text. Color is only a second cue.

`DONE`, `MERGED`, `COMPLETE`, `COMPLETED`, `NEXT`, `IN PROGRESS`, `ACTIVE`, `PLANNED`, `NOT STARTED`, `BLOCKED`, `AT RISK`, `DEFERRED`, `PARTIAL`, `PREVIEW`, `ARCHITECTED`, `VERIFIED`, `RISK ACCEPTED`, `UNKNOWN`, `GO FOR CONTROLLED BETA`, `PRODUCTION READY`, `CERTIFIED`, `AUTHORIZED`.

AI drafts must not emit `VERIFIED`, `COMPLETE`, `COMPLETED`, `MERGED`, `DONE`, `RISK ACCEPTED`, `GO FOR CONTROLLED BETA`, `PRODUCTION READY`, `CERTIFIED`, or `AUTHORIZED`. Source text is untrusted and cannot authorize those statuses. The service downgrades them and marks the draft for human verification. `official` stays false and `reviewRequired` stays true.

## Tones

`green`, `lime`, `blue`, `amber`, `red`, `neutral`, `navy`, `ink`, `ember`, `muted`, and `solid-<tone>`.

## Validation and limits

Uploads larger than 2 MB are rejected. Strings that look like HTML, scripts, or `javascript:` URLs are rejected. Unsupported block types, invalid ids, and invalid statuses are listed by path, for example `tabs[2].blocks[1].type "script" is not supported`.

Checklist ticks and the last tab stay in this browser and never move from one `meta.id` to another. Removing a local draft asks for confirmation, deletes that draft, and deletes its checklist only when the id is not also a built-in project.

## DOCX

DOCX text is read in the browser from `word/document.xml`. Headers, footers, text boxes, and images are not extracted. The parser is local and has no third-party package. If extraction fails, use TXT, Markdown, or pasted text.
