Files
PaperClipAI/doc/STORYBOOK-DEPLOYMENT.md
T
DottaandPaperclip 96bba78fba feat: add readable Storybook branch bookmarks (#13231)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Maintainers use Storybook previews to review the board UI.
> - Branch previews need stable bookmarks that people can read.
> - The current publisher only provides a hashed branch path.
> - This pull request adds a readable branch bookmark after each
successful upload.
> - Existing branch and build links keep working.

## Linked Issues or Issue Description

Refs #13226.

**What existing behavior does this improve?**

Manual Storybook publication for repository branches.

**Current behavior**

The stable branch path contains a hash. The expected
`/storybook/branches/master/` URL does not exist.

**Proposed behavior**

Each publication updates a readable bookmark. The action summary and
Markdown artifact link it. Master uses `/storybook/branches/master/`.
Other names use a safe path segment that preserves case and escapes
special characters.

**Reason and benefit**

Maintainers can save and share a readable URL that opens the latest
published branch build.

**Breaking changes**

None. Existing hashed branch entries still update. Existing build URLs
remain valid.

**Additional context**

This follows the publisher in #13226. A duplicate search found no
related bookmark change. It does not overlap planned core work in
ROADMAP.md.

## What Changed

- Generate readable branch bookmarks without collisions with existing
build directories.
- Upload the bookmark only after the full build and compatibility entry
uploads succeed.
- Link the bookmark in the existing summary and Markdown artifact.
- Document branch-name escaping and test path isolation, stable links,
and upload order.

## Verification

- `node --test scripts/__tests__/storybook-deploy.test.mjs`: 20 tests
pass.
- `actionlint .github/workflows/storybook-deploy.yml
.github/workflows/storybook-visual.yml`: passes.
- `git diff --check`: passes.
- [Master bookmark
publication](https://github.com/paperclipai/paperclip/actions/runs/34613344758):
passed. Opened `/storybook/branches/master/` in the browser and
confirmed a story renders. Downloaded the Markdown report and verified
its bookmark link.
- [Feature branch bookmark
publication](https://github.com/paperclipai/paperclip/actions/runs/34613449034):
passed. Its separate bookmark uses `codex~2Fstorybook-bookmarks`.
- Greptile: 5/5 on `dccaf10413ecf447cb34e622b6b3c505791abb51`, with no
unresolved review threads. All current-head Paperclip CI gates pass,
including typecheck, tests, build, browser suites, and the canary dry
run.
- Full local repository checks were not repeated for this focused
publisher change. The preceding run passed typecheck but encountered
unrelated native-session test failures.

## Risks

- Special characters in branch names use `~HH` byte escapes. For
example, `feature/foo` becomes `feature~2Ffoo`.
- Names that could overlap an existing hashed build directory escape the
final hyphen. Very long names retain a hash suffix.
- The two branch entries update separately. If the final upload fails,
the workflow fails and a rerun can repair the bookmark.

## Model Used

OpenAI GPT-6 via Codex, with reasoning, shell tools, and live deployment
verification. The exact runtime model ID and context-window size are not
exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-11 10:19:36 -05:00

88 lines
4.1 KiB
Markdown

# Storybook branch hosting
The `Storybook Deploy` workflow publishes public static Storybook builds to the
existing private S3 bucket behind CloudFront. It does not deploy to GitHub Pages.
## Current destination
- AWS account: `078455283791`, region `us-east-1`
- Bucket: `paperclipai-runner-e2e-history-078455283791-us-east-1`
- Allowed upload prefix: `storybook/branches/`
- Distribution: `E3GTU28BBO2SFR`
- Public origin: `https://d1p6rlowie26tp.cloudfront.net`
- Role: `arn:aws:iam::078455283791:role/paperclip-storybook-github`
The distribution's default behavior disables edge caching and rewrites directory
URLs to `index.html`. Stable branch indexes send `no-cache`; unique build objects
send `immutable`. No invalidations or CloudFront write permissions are needed.
Each publication updates a readable bookmark, such as
`https://d1p6rlowie26tp.cloudfront.net/storybook/branches/master/`, after the
immutable build upload completes. It also updates the previous hashed branch
entry for compatibility. The run summary and Markdown artifact link the bookmark.
Branch names use one escaped path segment, preserving case and separating slashes
from hyphens; see [the branch publishing guide](DEVELOPING.md#publish-a-branch-storybook)
for the encoding. No additional AWS permissions or distribution changes are needed.
## GitHub configuration
Create environment `storybook-deploy` with required reviewers set to the
individual CODEOWNERS accounts. Disable administrator bypass, allow self-review,
and allow repository branches. Keep these reviewers synchronized with CODEOWNERS.
The workflow rejects environments with no required reviewers, non-owner reviewers
or administrator bypass enabled. The AWS role trusts only this repository and
this environment, so a branch cannot obtain upload access through an unprotected
environment.
Set repository variables:
| Variable | Value |
| --- | --- |
| `STORYBOOK_AWS_ROLE_ARN` | `arn:aws:iam::078455283791:role/paperclip-storybook-github` |
| `STORYBOOK_AWS_REGION` | `us-east-1` |
| `STORYBOOK_S3_BUCKET` | `paperclipai-runner-e2e-history-078455283791-us-east-1` |
| `STORYBOOK_PUBLIC_BASE_URL` | `https://d1p6rlowie26tp.cloudfront.net` |
No stored AWS access keys are needed. Leave the runner dashboard variables and
GitHub Pages configuration unchanged.
## Operator setup
Use the `paperclip-dev` operator AWS profile. Review the checked-in policies in
`.github/storybook-deploy/` before applying them. The existing GitHub OIDC provider
must be present in this account.
```sh
aws sts get-caller-identity --profile paperclip-dev
aws iam create-role --profile paperclip-dev \
--role-name paperclip-storybook-github \
--assume-role-policy-document file://.github/storybook-deploy/trust-policy.json
aws iam put-role-policy --profile paperclip-dev \
--role-name paperclip-storybook-github --policy-name StorybookBranchUpload \
--policy-document file://.github/storybook-deploy/upload-policy.json
```
For an existing role, use `update-assume-role-policy` instead of `create-role`.
Add the statement from `cloudfront-read-statement.json` to the existing bucket
policy's `Statement` array. Preserve every other statement, including the HTTPS
requirement and runner report access. Keep all S3 public-access blocks enabled;
only CloudFront receives read access to this public-content prefix.
The role has no delete, bucket policy, IAM, CloudFront, or root-object permissions.
The workflow never runs `sync --delete`. Builds accumulate; any retention cleanup
must preserve the build referenced by each branch entry.
## Verification
```sh
node --test scripts/__tests__/storybook-deploy.test.mjs
actionlint .github/workflows/storybook-deploy.yml .github/workflows/storybook-visual.yml
```
Dispatch two source branches, approve each deployment, and check their distinct
branch URLs and each build's `deployment.json`. Redeploy one branch and confirm
its stable URL now points to the new build while the other branch is unchanged.
The publisher checks the public build metadata against the selected source SHA
and verifies that the public branch entry points to this exact build. It retries
brief propagation delays and fails if the branch URL remains stale.