Guests can Finalize without a magic-link wall. The published rule gets a real public URL, stays off the catalog until someone owns it, and can be attached to an account later by signing in on the same browser.
This also removes the login modal kebab that was acting as a second Close control.
Changes
POST /api/rules no longer requires a session. Guests create an unlisted row (userId null), rate-limited to one anonymous publish per IP per minute. Stakeholder invite emails in the body are ignored without a session.
Guest publish stores a hashed claim secret and sets httpOnly cr_rule_claim (30 days). Signing in (createSessionForUser) attaches matching ownerless rows to that account and clears the cookie.
GET /api/rules lists only owned rules. /rules/{id} still works for guest rows.
Completed: no Edit unless signed in; warning banner to sign in on this browser (or that stakeholder invites were skipped).
Login modal: more-options kebab hidden.
Cookies and privacy copy mention cr_rule_claim.
Prisma: nullable unique PublishedRule.claimTokenHash plus migration 20260826160000_add_published_rule_claim_token.
How to Test
Apply the new Prisma migration (npx prisma migrate deploy or npx prisma migrate dev) before a local run.
Signed out, go through create and Finalize. Confirm there is no login wall, you land on completed, Share / Export / Exit work, and Edit is hidden.
Confirm the completed warning about signing in on this same browser. If the draft had stakeholder emails, confirm the invites-skipped warning instead.
Open the public /rules/{id} URL in another tab. Confirm it loads. Confirm the id is not in GET /api/rules.
From this same browser, Log in via magic link. Confirm the rule appears on Profile as owner, GET /api/rules/{id} returns viewerIsOwner: true, completed shows Edit, and the id is in GET /api/rules.
Repeat Finalize while signed in: rule is owned immediately, no claim banner, invites still send when emails are present.
Open the login overlay (header Log in or /login). Confirm Close is present and there is no more-options kebab. Clicking the kebab must not dismiss the dialog (it should not render).
Confirm /cookies mentions cr_rule_claim.
Notes
Claim is possession of cr_rule_claim, not knowledge of /rules/{id}. Another browser, or clearing this site’s cookies, cannot attach the rule. Cookie lasts 30 days.
Any sign-in on that browser silently claims matching ownerless rows. Shared computers can attach a guest rule to the next account that signs in.
Not in this PR: confirm-before-claim, or emailing a claim link for another device.
Staging/prod need the new migration before guest Finalize will succeed.
## Overview
Guests can Finalize without a magic-link wall. The published rule gets a real public URL, stays off the catalog until someone owns it, and can be attached to an account later by signing in on the same browser.
This also removes the login modal kebab that was acting as a second Close control.
## Changes
- `POST /api/rules` no longer requires a session. Guests create an unlisted row (`userId` null), rate-limited to one anonymous publish per IP per minute. Stakeholder invite emails in the body are ignored without a session.
- Guest publish stores a hashed claim secret and sets httpOnly `cr_rule_claim` (30 days). Signing in (`createSessionForUser`) attaches matching ownerless rows to that account and clears the cookie.
- `GET /api/rules` lists only owned rules. `/rules/{id}` still works for guest rows.
- Completed: no Edit unless signed in; warning banner to sign in on this browser (or that stakeholder invites were skipped).
- Login modal: more-options kebab hidden.
- Cookies and privacy copy mention `cr_rule_claim`.
- Prisma: nullable unique `PublishedRule.claimTokenHash` plus migration `20260826160000_add_published_rule_claim_token`.
## How to Test
Apply the new Prisma migration (`npx prisma migrate deploy` or `npx prisma migrate dev`) before a local run.
1. Signed out, go through create and Finalize. Confirm there is no login wall, you land on completed, Share / Export / Exit work, and Edit is hidden.
2. Confirm the completed warning about signing in on this same browser. If the draft had stakeholder emails, confirm the invites-skipped warning instead.
3. Open the public `/rules/{id}` URL in another tab. Confirm it loads. Confirm the id is **not** in `GET /api/rules`.
4. From this same browser, Log in via magic link. Confirm the rule appears on Profile as owner, `GET /api/rules/{id}` returns `viewerIsOwner: true`, completed shows Edit, and the id **is** in `GET /api/rules`.
5. Repeat Finalize while signed in: rule is owned immediately, no claim banner, invites still send when emails are present.
6. Open the login overlay (header Log in or `/login`). Confirm Close is present and there is no more-options kebab. Clicking the kebab must not dismiss the dialog (it should not render).
7. Confirm `/cookies` mentions `cr_rule_claim`.
## Notes
- Claim is possession of `cr_rule_claim`, not knowledge of `/rules/{id}`. Another browser, or clearing this site’s cookies, cannot attach the rule. Cookie lasts 30 days.
- Any sign-in on that browser silently claims matching ownerless rows. Shared computers can attach a guest rule to the next account that signs in.
- Not in this PR: confirm-before-claim, or emailing a claim link for another device.
- Staging/prod need the new migration before guest Finalize will succeed.
Finalize no longer requires a magic link. Guest rows stay off the catalog until sign-in on the same browser attaches ownership, and the login modal kebab no longer acts as a second close.
Co-authored-by: Cursor <cursoragent@cursor.com>
an.di
self-assigned this 2026-08-26 17:02:08 +00:00
an.di
merged commit 2e995cb5f7 into main2026-08-26 17:02:20 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Overview
Guests can Finalize without a magic-link wall. The published rule gets a real public URL, stays off the catalog until someone owns it, and can be attached to an account later by signing in on the same browser.
This also removes the login modal kebab that was acting as a second Close control.
Changes
POST /api/rulesno longer requires a session. Guests create an unlisted row (userIdnull), rate-limited to one anonymous publish per IP per minute. Stakeholder invite emails in the body are ignored without a session.cr_rule_claim(30 days). Signing in (createSessionForUser) attaches matching ownerless rows to that account and clears the cookie.GET /api/ruleslists only owned rules./rules/{id}still works for guest rows.cr_rule_claim.PublishedRule.claimTokenHashplus migration20260826160000_add_published_rule_claim_token.How to Test
Apply the new Prisma migration (
npx prisma migrate deployornpx prisma migrate dev) before a local run./rules/{id}URL in another tab. Confirm it loads. Confirm the id is not inGET /api/rules.GET /api/rules/{id}returnsviewerIsOwner: true, completed shows Edit, and the id is inGET /api/rules./login). Confirm Close is present and there is no more-options kebab. Clicking the kebab must not dismiss the dialog (it should not render)./cookiesmentionscr_rule_claim.Notes
cr_rule_claim, not knowledge of/rules/{id}. Another browser, or clearing this site’s cookies, cannot attach the rule. Cookie lasts 30 days.