Magic-link sign in UI and APIs
This commit is contained in:
+122
-56
@@ -6,7 +6,7 @@ Copy each block into Linear (or your tracker) as a separate issue, **in order**.
|
||||
|
||||
### Review sync (relevant feedback only)
|
||||
|
||||
A backend review was merged into **[docs/backend-roadmap.md](backend-roadmap.md)** after checking the repo. **Incorporated:** custom session lifecycle follow-ups (not a mandate to adopt Auth.js/Lucia), in-memory OTP limits until multi-instance + shared store, `RuleDraft` already has `updatedAt` (no migration to add it), **prefer external web vitals** over product Postgres by default, API error shape + request-id observability targets, **authorization v1** aligned with `app/api/rules`, Prisma **never edit applied migrations**. **Excluded:** requiring NextAuth/Lucia; “add `updatedAt` on drafts”; hard ban on DB for vitals (softened to default external). **Parallel Linear issues:** **CR-84** (API errors, blocked by CR-73), **CR-85** (session lifecycle, blocked by CR-75)—see **Linear** table at the end of this doc.
|
||||
A backend review was merged into **[docs/backend-roadmap.md](backend-roadmap.md)** after checking the repo. **Incorporated:** custom session lifecycle follow-ups (not a mandate to adopt Auth.js/Lucia), **passwordless email (magic-link request)** rate limits in-memory until multi-instance + shared store, `RuleDraft` already has `updatedAt` (no migration to add it), **prefer external web vitals** over product Postgres by default, API error shape + request-id observability targets, **authorization v1** aligned with `app/api/rules`, Prisma **never edit applied migrations**, **profile / my rules / account** scope from Figma profile (`22143:900069`) as **Ticket 15** (change email deferred). **Excluded:** requiring NextAuth/Lucia; “add `updatedAt` on drafts”; hard ban on DB for vitals (softened to default external). **Parallel Linear issues:** **CR-84** (API errors, blocked by CR-73), **CR-85** (session lifecycle, blocked by CR-75)—see **Linear** table at the end of this doc.
|
||||
|
||||
---
|
||||
|
||||
@@ -16,7 +16,7 @@ Use this if you **do not** have SSH or hosting access yet. Most engineering tick
|
||||
|
||||
### You do **not** need the server admin for
|
||||
|
||||
- **Tickets 1–8, 10:** Everything runs on your machine: `docker compose up -d postgres mailhog`, `.env`, `npm run dev`, `npx prisma migrate dev`. OTP email can use Mailhog or dev log (no real SMTP).
|
||||
- **Tickets 1–8, 10:** Everything runs on your machine: `docker compose up -d postgres mailhog`, `.env`, `npm run dev`, `npx prisma migrate dev`. **Magic-link** sign-in email can use Mailhog or **dev server logs** (verify URL) when `SMTP_URL` is unset—no real SMTP required locally.
|
||||
- **Verifying APIs:** Use `localhost` and the same Docker Postgres—no production host.
|
||||
|
||||
### The **first** time you need someone with hosting access
|
||||
@@ -29,9 +29,9 @@ Ask the admin to provide (or do for you) the items below—**Ticket 12** turns t
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Postgres** | Managed instance or container; a **`DATABASE_URL`** you can plug into the deployed app. |
|
||||
| **Run migrations** | Someone runs **`npx prisma migrate deploy`** against that database **before** the new app version serves traffic (or gives you a secure way to run it in CI/CD). |
|
||||
| **`SESSION_SECRET`** | Long random string in production env (sessions + OTP hashing). |
|
||||
| **SMTP** | **`SMTP_URL`** + **`SMTP_FROM`** for real OTP email; not required on laptop if you use logs/Mailhog. |
|
||||
| **DNS for mail** | Often **SPF/DKIM** so OTP messages are not spam—admin or whoever owns DNS. |
|
||||
| **`SESSION_SECRET`** | Long random string in production env (sessions **+ hashed magic-link tokens**). |
|
||||
| **SMTP** | **`SMTP_URL`** + **`SMTP_FROM`** for real **sign-in link** email; not required on laptop if you use logs/Mailhog. |
|
||||
| **DNS for mail** | Often **SPF/DKIM** so **magic-link** messages are not spam—admin or whoever owns DNS. |
|
||||
| **TLS + hostname** | HTTPS URL for the site; reverse proxy (nginx, Caddy, etc.) in front of Node. |
|
||||
| **Health check** | Load balancer or platform should probe **`GET /api/health`** (or your chosen path). |
|
||||
| **Secrets storage** | Env vars or secret manager—never commit `.env` with secrets. |
|
||||
@@ -44,7 +44,7 @@ Optional: **Docker image deploy** using the repo [Dockerfile](Dockerfile)—admi
|
||||
| Ticket | Need server admin? | What for |
|
||||
| ------ | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1–2 | **No** | Docs and app code only. |
|
||||
| 3 | **No** to build/test; **Yes** when OTP must work on a **deployed** env | Real **SMTP** + DNS on staging/prod (same as table above). |
|
||||
| 3 | **No** to build/test; **Yes** when **magic-link email** must work on a **deployed** env | Real **SMTP** + DNS on staging/prod (same as table above). |
|
||||
| 4–8 | **No** | Local or staging URL is still “your” deploy—admin only if that URL is on their infra. |
|
||||
| 9 | **No** to implement; **Yes** when **production** uses multiple instances or read-only FS | **Default** is external RUM/log drain; Postgres vitals only if ops explicitly wants one datastore—may need vendor keys for SaaS. |
|
||||
| 10 | **No** to code | Same deploy pipeline as the rest of the app. |
|
||||
@@ -113,31 +113,44 @@ Optional: **Docker image deploy** using the repo [Dockerfile](Dockerfile)—admi
|
||||
|
||||
---
|
||||
|
||||
## Ticket 3 — Email OTP sign-in UI (end-to-end with existing APIs)
|
||||
## Ticket 3 — Email magic-link sign-in UI (end-to-end with existing APIs)
|
||||
|
||||
**Depends on:** Ticket 2 (soft dependency: types help name fields you might store post-login; can start in parallel if needed).
|
||||
|
||||
**Server / admin:** **Not required** to build and test (Mailhog or console OTP locally). **Required** when OTP must work on **staging/production**: admin provides **SMTP** + usually **DNS (SPF/DKIM)** and sets env on the host (see top table).
|
||||
**Server / admin:** **Not required** to build and test (Mailhog or verify URL in server logs locally). **Required** when **magic-link email** must work on **staging/production**: admin provides **SMTP** + usually **DNS (SPF/DKIM)** and sets env on the host (see top table). **Residual:** links in email use the app origin—reverse proxy / `Host` must match the URL users open.
|
||||
|
||||
**Goal:** Let a user request a code and verify it in the browser using existing endpoints.
|
||||
**Goal:** Let a user request a **sign-in link** and complete sign-in in the browser using existing endpoints.
|
||||
|
||||
**Context:** APIs exist: `POST /api/auth/otp/request`, `POST /api/auth/otp/verify`, `GET /api/auth/session`, `POST /api/auth/logout`. Client helpers: [lib/create/api.ts](lib/create/api.ts).
|
||||
**Context:** APIs: `POST /api/auth/magic-link/request`, `GET /api/auth/magic-link/verify`, `GET /api/auth/session`, `POST /api/auth/logout`. Prisma: `MagicLinkToken`. Client: [`requestMagicLink`](lib/create/api.ts).
|
||||
|
||||
**Implementation:**
|
||||
**Implementation (shipped):**
|
||||
|
||||
1. Add a **route** (e.g. `app/(marketing)/login/page.tsx`) or a **modal** from the main header, designer-approved.
|
||||
2. Flow: email → “Send code” → 6-digit code → “Verify” → success closes UI or redirects to `/create` (product decision).
|
||||
3. Surface API errors: invalid email, 429 `retryAfterMs`, wrong code, network failure (accessible copy).
|
||||
4. Ensure `fetch` calls use `credentials: "include"` (already in `lib/create/api.ts`).
|
||||
5. **Dev:** document that without `SMTP_URL`, OTP prints to server logs; with Mailhog, use [docker-compose.yml](docker-compose.yml) and `SMTP_URL=smtp://localhost:1025`.
|
||||
1. **`/login`** route and/or **modal** from the header (designer-approved)—[app/login/page.tsx](app/login/page.tsx), [app/login/LoginPageClient.tsx](app/login/LoginPageClient.tsx), [app/components/modals/Login/](app/components/modals/Login/) (`LoginForm.tsx`, container/view).
|
||||
2. Flow: email → “Send link” → user opens link (email, Mailhog, or dev log) → `GET /api/auth/magic-link/verify?token=...` sets session and redirects; optional `next` for post-login path.
|
||||
3. Surface API errors: invalid email, 429 `retryAfterMs`, expired/invalid token, network failure (accessible copy).
|
||||
4. Ensure `fetch` calls use `credentials: "include"` where needed (see [lib/create/api.ts](lib/create/api.ts)).
|
||||
5. **Dev:** without `SMTP_URL`, verify URL is logged; with Mailhog, use [docker-compose.yml](docker-compose.yml) and `SMTP_URL=smtp://localhost:1025`.
|
||||
6. **Marketing header:** When signed in (`fetchAuthSession`), **Log in** becomes **Profile** linking to [`/profile`](app/profile/page.tsx) (placeholder until Ticket 15 / CR-86). Implemented in [TopNavWithPathname.tsx](app/components/navigation/TopNav/TopNavWithPathname.tsx) + [TopNav.container.tsx](app/components/navigation/TopNav/TopNav.container.tsx).
|
||||
|
||||
**Acceptance criteria:**
|
||||
|
||||
- [ ] Happy path: user can complete OTP and `GET /api/auth/session` returns user in the same browser session.
|
||||
- [ ] Keyboard + screen-reader friendly forms (labels, errors associated with fields).
|
||||
- [ ] No secrets in client bundle.
|
||||
- [x] Happy path: user completes magic-link verify and `GET /api/auth/session` returns `user` in the same browser session.
|
||||
- [x] Keyboard + screen-reader friendly forms (labels, errors associated with fields).
|
||||
- [x] No secrets in client bundle.
|
||||
- [x] Header shows **Profile** → placeholder `/profile` when session present; **Log in** when anonymous.
|
||||
|
||||
**Files:** new page/components under `app/` and `app/components/…`, optional [messages/en/…](messages/en/) JSON for i18n, [lib/create/api.ts](lib/create/api.ts) only if you need new helpers.
|
||||
**Status:** [CR-74](https://linear.app/community-rule/issue/CR-74/backend-email-otp-sign-in-ui-existing-apis) **Done** for shipped UI/APIs. **Residual checklist** below: repo doc items are **done**; use Linear (CR-74 or child issue) to track **per-environment** staging URL checks.
|
||||
|
||||
**Files:** [app/login/](app/login/), [app/profile/](app/profile/) (placeholder), [app/components/modals/Login/](app/components/modals/Login/), [messages/en/pages/login.json](messages/en/pages/login.json), [messages/en/pages/profile.json](messages/en/pages/profile.json), [messages/en/components/header.json](messages/en/components/header.json), [app/components/navigation/TopNav/TopNav.container.tsx](app/components/navigation/TopNav/TopNav.container.tsx), [app/components/navigation/TopNav/TopNavWithPathname.tsx](app/components/navigation/TopNav/TopNavWithPathname.tsx), [lib/create/api.ts](lib/create/api.ts), [app/api/auth/magic-link/request/route.ts](app/api/auth/magic-link/request/route.ts), [app/api/auth/magic-link/verify/route.ts](app/api/auth/magic-link/verify/route.ts), [prisma/schema.prisma](prisma/schema.prisma) (`MagicLinkToken`), [lib/server/mail.ts](lib/server/mail.ts). Onboarding: [CONTRIBUTING.md](CONTRIBUTING.md), [`.env.example`](.env.example).
|
||||
|
||||
### Residual / before CR-75 (create-flow session UI)
|
||||
|
||||
**Intent:** [Ticket 4](#ticket-4--session-affordances-in-the-create-flow-signed-in-state--sign-out) (**CR-75**) needs a reliable signed-in story across marketing + `/create`. Below: what is **done in repo** vs what to **verify per environment**.
|
||||
|
||||
1. **Contributor / onboarding** — **Done:** [CONTRIBUTING.md](CONTRIBUTING.md) API table and sign-in section describe **magic-link** request/verify, dev log URL, and Mailhog. [`.env.example`](.env.example) comments match.
|
||||
2. **Smoke checklist** — **Done:** **Email magic link (sign-in)** in [CONTRIBUTING.md](CONTRIBUTING.md); build-order §9 in [docs/backend-roadmap.md](backend-roadmap.md) includes the same happy path + session check.
|
||||
3. **Staging / production URLs** — **Verify on each deploy:** emails use `request.nextUrl.origin`; confirm reverse proxy and **`Host`** so links in mail match the public site (CONTRIBUTING + roadmap §9 spell this out).
|
||||
4. **Docs alignment** — **Done:** [docs/backend-roadmap.md](backend-roadmap.md) and this doc treat magic link as primary; CR-72/CR-73 schema work is not a blocker for CR-75.
|
||||
|
||||
---
|
||||
|
||||
@@ -290,6 +303,8 @@ Optional: **Docker image deploy** using the repo [Dockerfile](Dockerfile)—admi
|
||||
|
||||
**Goal:** Shareable link for a published rule.
|
||||
|
||||
**Note:** Complements **Ticket 15** profile cards: users can open a **public** detail URL from a rule listed on their dashboard; the profile page does **not** replace this ticket.
|
||||
|
||||
**Implementation:**
|
||||
|
||||
1. Add `GET /api/rules/[id]/route.ts` returning `{ rule }` or 404 (public read; no secrets).
|
||||
@@ -303,6 +318,8 @@ Optional: **Docker image deploy** using the repo [Dockerfile](Dockerfile)—admi
|
||||
|
||||
**Files:** new route handler, new page, optional layout.
|
||||
|
||||
**Linear:** [CR-81](https://linear.app/community-rule/issue/CR-81/backend-public-rule-detail-page-get-apirulesid-optional). **Related in Linear:** [CR-86](https://linear.app/community-rule/issue/CR-86/backend-profile-dashboard-account-figma-profile) (Ticket 15 — profile cards linking to public detail).
|
||||
|
||||
---
|
||||
|
||||
## Ticket 11 — CI: database migration smoke (optional, runner-dependent)
|
||||
@@ -389,7 +406,7 @@ Optional: **Docker image deploy** using the repo [Dockerfile](Dockerfile)—admi
|
||||
|
||||
**Implementation:**
|
||||
|
||||
1. **Policy:** On new OTP login, decide whether to **delete other `Session` rows** for that user (single active session) or allow multiple devices (document choice).
|
||||
1. **Policy:** On **new sign-in** (magic-link verification / session creation), decide whether to **delete other `Session` rows** for that user (single active session) or allow multiple devices (document choice).
|
||||
2. **Rotation (optional v1.1):** Issue new token on privilege-sensitive actions if product requires.
|
||||
3. **Cleanup:** Delete or mark expired sessions (scheduled job, or prune on read with occasional batch).
|
||||
4. **Docs:** Add short ADR or comment block in `lib/server/session.ts`.
|
||||
@@ -399,52 +416,101 @@ Optional: **Docker image deploy** using the repo [Dockerfile](Dockerfile)—admi
|
||||
- [ ] Documented behavior matches implementation.
|
||||
- [ ] Expired sessions do not accumulate unbounded in production over months.
|
||||
|
||||
**Files:** [lib/server/session.ts](lib/server/session.ts), [app/api/auth/otp/verify/route.ts](app/api/auth/otp/verify/route.ts) if invalidating siblings, optional `prisma` migration if new columns (unlikely).
|
||||
**Files:** [lib/server/session.ts](lib/server/session.ts), [app/api/auth/magic-link/verify/route.ts](app/api/auth/magic-link/verify/route.ts), optional `prisma` migration if new columns (unlikely).
|
||||
|
||||
**Linear:** [CR-85](https://linear.app/community-rule/issue/CR-85/backend-custom-session-lifecycle-cleanup-invalidation-policy) (blocked by **CR-75**).
|
||||
|
||||
---
|
||||
|
||||
## Ticket 15 — Profile dashboard + account (Figma profile)
|
||||
|
||||
**Depends on:** Ticket 3 (auth), **Ticket 4** (session in UI), **Ticket 6** (publish so users have rules to list). Soft optional: Tickets 7–8 for “create from template” CTA parity.
|
||||
|
||||
**Goal:** Signed-in **profile** experience matching [Figma — Profile](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22143-900069): **Your CommunityRules** (list **own** published rules), **duplicate** / **delete** per rule, CTAs into create flow (custom + from template), **logout** (existing API), **delete account** (policy + API + confirmation UX).
|
||||
|
||||
**Out of scope for this ticket**
|
||||
|
||||
- **Change your account email** (shown in Figma options): **deferred**—no backend in this slice. Product may **hide** the row, show **“Coming soon,”** or backlog until a **future ticket** (verified email change, conflicts, sessions).
|
||||
- **`displayName` / new `User` fields:** not required—use **static** welcome copy, generic greeting, or **email local-part in UI only** until a later schema/product decision.
|
||||
|
||||
**Context:** Today `GET /api/rules` is a **public** list of all published rules; there is no authenticated **my rules** endpoint, no owner **DELETE** / **duplicate**, and no **delete user** API. See [docs/backend-roadmap.md](backend-roadmap.md) §1 “profile / account — not implemented yet” and §6.
|
||||
|
||||
**Implementation (sketch):**
|
||||
|
||||
1. **API:** Authenticated route(s) to list rules **where `userId` = session user**; owner-only `DELETE` (and duplicate via `POST` reuse or dedicated handler); `DELETE` user (or equivalent) with explicit Prisma policy—cascade vs orphan `PublishedRule` (today `onDelete: SetNull` on user) and cleanup of `Session` / `RuleDraft`.
|
||||
2. **UI:** Marketing route (e.g. `/profile`), rule cards (title, summary, artwork from `document` as needed), **IN PROGRESS** badge per roadmap §4 (derive from JSON / future `status` / UI-only).
|
||||
3. **Nav:** Link from header when signed in if design requires.
|
||||
4. **i18n** for strings; legal/product review for **delete account** copy.
|
||||
|
||||
**Acceptance criteria:**
|
||||
|
||||
- [ ] Signed-in user sees **only their** published rules (not the global public list).
|
||||
- [ ] Duplicate and delete actions work for **owner** only; errors are clear.
|
||||
- [ ] Logout still works from profile context.
|
||||
- [ ] Delete account flow matches agreed policy and is confirmed in UI.
|
||||
- [ ] No verified **email change** shipped in this ticket; Figma row handled per product (hide/disabled/backlog).
|
||||
|
||||
**Files:** new `app/` routes and components, `app/api/rules/...` (or new segment handlers), [lib/create/api.ts](lib/create/api.ts) as needed, [prisma/schema.prisma](prisma/schema.prisma) only if account-delete policy requires schema tweaks, [messages/en/](messages/en/) for copy.
|
||||
|
||||
**Linear:** [CR-86](https://linear.app/community-rule/issue/CR-86/backend-profile-dashboard-account-figma-profile) (**Backlog**). **Blocked by** **CR-75** + **CR-77**. **Related:** [CR-81](https://linear.app/community-rule/issue/CR-81/backend-public-rule-detail-page-get-apirulesid-optional) (public rule detail for deep links from profile cards). **Not** part of the sequential **CR-72 → CR-83** chain—parallel after publish + session, similar to CR-84/CR-85.
|
||||
|
||||
---
|
||||
|
||||
## Summary order
|
||||
|
||||
| Order | Ticket | Short name |
|
||||
| ----: | ------ | -------------------------------- |
|
||||
| 1 | 1 | Refresh backend-roadmap |
|
||||
| 2 | 2 | CreateFlowState + API validation |
|
||||
| 3 | 3 | OTP sign-in UI |
|
||||
| 4 | 4 | Create flow session UI |
|
||||
| 5 | 5 | Draft sync hardening |
|
||||
| 6 | 6 | Publish wiring |
|
||||
| 7 | 7 | Template seed |
|
||||
| 8 | 8 | Templates in UI |
|
||||
| 9 | 9 | Web vitals persistence |
|
||||
| 10 | 10 | Public rule detail (optional) |
|
||||
| 11 | 11 | CI migrate smoke (optional) |
|
||||
| 12 | 12 | Ops runbook |
|
||||
| 13 | 13 | API errors + request-id logging |
|
||||
| 14 | 14 | Session lifecycle + cleanup |
|
||||
| Order | Ticket | Short name |
|
||||
| ----: | ------ | --------------------------------- |
|
||||
| 1 | 1 | Refresh backend-roadmap |
|
||||
| 2 | 2 | CreateFlowState + API validation |
|
||||
| 3 | 3 | Magic-link sign-in UI |
|
||||
| 4 | 4 | Create flow session UI |
|
||||
| 5 | 5 | Draft sync hardening |
|
||||
| 6 | 6 | Publish wiring |
|
||||
| 7 | 7 | Template seed |
|
||||
| 8 | 8 | Templates in UI |
|
||||
| 9 | 9 | Web vitals persistence |
|
||||
| 10 | 10 | Public rule detail (optional) |
|
||||
| 11 | 11 | CI migrate smoke (optional) |
|
||||
| 12 | 12 | Ops runbook |
|
||||
| 13 | 13 | API errors + request-id logging |
|
||||
| 14 | 14 | Session lifecycle + cleanup |
|
||||
| 15 | 15 | Profile + account (Figma profile) |
|
||||
|
||||
Tickets **10–11** can be deferred without blocking the core “auth + drafts + publish + templates” vertical slice. **Tickets 13–14** are parallel to that chain (blocked by **CR-73** and **CR-75** respectively), not sequential after CR-83.
|
||||
Tickets **10–11** can be deferred without blocking the core “auth + drafts + publish + templates” vertical slice. **Tickets 13–14** are parallel to that chain (blocked by **CR-73** and **CR-75** respectively), not sequential after CR-83. **Ticket 15** is also **parallel** (blocked by auth + session + publish—not by the ops runbook); Linear: **CR-86**.
|
||||
|
||||
---
|
||||
|
||||
## Linear (Community-rule team)
|
||||
|
||||
**Main chain:** **CR-72 → CR-83** (each blocks the next). **Parallel:** **CR-84** (blocked by CR-73), **CR-85** (blocked by CR-75).
|
||||
**Main chain:** **CR-72 → CR-83** (each blocks the next). **Parallel:** **CR-84** (blocked by CR-73), **CR-85** (blocked by CR-75), **CR-86** / Ticket 15 (blocked by CR-75 + CR-77, not in the CR-72–83 sequence).
|
||||
|
||||
| Doc ticket | Linear | Title (short) |
|
||||
| ---------: | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
|
||||
| 1 | [CR-72](https://linear.app/community-rule/issue/CR-72/backend-align-docsbackend-roadmapmd-with-current-codebase) | Align backend-roadmap |
|
||||
| 2 | [CR-73](https://linear.app/community-rule/issue/CR-73/backend-formalize-createflowstate-validate-draftpublish-api-payloads) | CreateFlowState + API validation |
|
||||
| 3 | [CR-74](https://linear.app/community-rule/issue/CR-74/backend-email-otp-sign-in-ui-existing-apis) | OTP sign-in UI |
|
||||
| 4 | [CR-75](https://linear.app/community-rule/issue/CR-75/backend-create-flow-session-ui-sign-out) | Create flow session UI |
|
||||
| 5 | [CR-76](https://linear.app/community-rule/issue/CR-76/backend-harden-server-draft-sync-createflowbackendsync) | Draft sync hardening |
|
||||
| 6 | [CR-77](https://linear.app/community-rule/issue/CR-77/backend-wire-publish-rule-from-create-flow-post-apirules) | Publish wiring |
|
||||
| 7 | [CR-78](https://linear.app/community-rule/issue/CR-78/backend-prisma-seed-ruletemplate-document) | Template seed |
|
||||
| 8 | [CR-79](https://linear.app/community-rule/issue/CR-79/backend-load-rule-templates-from-get-apitemplates-in-ui) | Templates in UI |
|
||||
| 9 | [CR-80](https://linear.app/community-rule/issue/CR-80/backend-persist-web-vitals-outside-next-db-or-external-rum) | Web vitals (prefer external) |
|
||||
| 10 | [CR-81](https://linear.app/community-rule/issue/CR-81/backend-public-rule-detail-page-get-apirulesid-optional) | Public rule detail (optional) |
|
||||
| 11 | [CR-82](https://linear.app/community-rule/issue/CR-82/backend-ci-postgres-migration-smoke-optional) | CI migrate smoke (optional) |
|
||||
| 12 | [CR-83](https://linear.app/community-rule/issue/CR-83/backend-stagingproduction-runbook-admin-handoff-docsops-backend) | Ops runbook / admin handoff |
|
||||
| 13 | [CR-84](https://linear.app/community-rule/issue/CR-84/backend-api-error-contract-request-id-logging) | API errors + request-id logging |
|
||||
| 14 | [CR-85](https://linear.app/community-rule/issue/CR-85/backend-custom-session-lifecycle-cleanup-invalidation-policy) | Session lifecycle + cleanup |
|
||||
| Doc ticket | Linear | Title (short) |
|
||||
| ---------: | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| 1 | [CR-72](https://linear.app/community-rule/issue/CR-72/backend-align-docsbackend-roadmapmd-with-current-codebase) | Align backend-roadmap |
|
||||
| 2 | [CR-73](https://linear.app/community-rule/issue/CR-73/backend-formalize-createflowstate-validate-draftpublish-api-payloads) | CreateFlowState + API validation |
|
||||
| 3 | [CR-74](https://linear.app/community-rule/issue/CR-74/backend-email-otp-sign-in-ui-existing-apis) | Magic-link sign-in UI + CR-75 prep |
|
||||
| 4 | [CR-75](https://linear.app/community-rule/issue/CR-75/backend-create-flow-session-ui-sign-out) | Create flow session UI |
|
||||
| 5 | [CR-76](https://linear.app/community-rule/issue/CR-76/backend-harden-server-draft-sync-createflowbackendsync) | Draft sync hardening |
|
||||
| 6 | [CR-77](https://linear.app/community-rule/issue/CR-77/backend-wire-publish-rule-from-create-flow-post-apirules) | Publish wiring |
|
||||
| 7 | [CR-78](https://linear.app/community-rule/issue/CR-78/backend-prisma-seed-ruletemplate-document) | Template seed |
|
||||
| 8 | [CR-79](https://linear.app/community-rule/issue/CR-79/backend-load-rule-templates-from-get-apitemplates-in-ui) | Templates in UI |
|
||||
| 9 | [CR-80](https://linear.app/community-rule/issue/CR-80/backend-persist-web-vitals-outside-next-db-or-external-rum) | Web vitals (prefer external) |
|
||||
| 10 | [CR-81](https://linear.app/community-rule/issue/CR-81/backend-public-rule-detail-page-get-apirulesid-optional) | Public rule detail (optional) |
|
||||
| 11 | [CR-82](https://linear.app/community-rule/issue/CR-82/backend-ci-postgres-migration-smoke-optional) | CI migrate smoke (optional) |
|
||||
| 12 | [CR-83](https://linear.app/community-rule/issue/CR-83/backend-stagingproduction-runbook-admin-handoff-docsops-backend) | Ops runbook / admin handoff |
|
||||
| 13 | [CR-84](https://linear.app/community-rule/issue/CR-84/backend-api-error-contract-request-id-logging) | API errors + request-id logging |
|
||||
| 14 | [CR-85](https://linear.app/community-rule/issue/CR-85/backend-custom-session-lifecycle-cleanup-invalidation-policy) | Session lifecycle + cleanup |
|
||||
| 15 | [CR-86](https://linear.app/community-rule/issue/CR-86/backend-profile-dashboard-account-figma-profile) | Profile + account (Figma 22143:900069) |
|
||||
|
||||
---
|
||||
|
||||
## Updating Linear issue CR-74 (manual)
|
||||
|
||||
Keep **[CR-74](https://linear.app/community-rule/issue/CR-74/backend-email-otp-sign-in-ui-existing-apis)** aligned with **Ticket 3** (Linear UI or MCP). If Linear still describes an old sign-in approach, update it so it matches **Ticket 3** above (magic link only):
|
||||
|
||||
- **Title (examples):** `Magic-link sign-in UI + APIs; prep for CR-75` or `Email magic-link sign-in (UI + routes) — residuals for create-flow auth`.
|
||||
- **Description — Shipped:** Magic link: `POST /api/auth/magic-link/request`, `GET /api/auth/magic-link/verify`, `MagicLinkToken`, `/login` + modal UI, `requestMagicLink`, session cookie.
|
||||
- **Description — Residual / before CR-75:** Use the checklist under **Residual / before CR-75** (Ticket 3 above). Mark **done** for items 1, 2, and 4 (repo docs). Keep **open** until verified: **(3)** staging/prod `Host` / link URLs on your real hosts.
|
||||
- **Comment (optional):** Start **CR-75** only after residuals are done **or** the team defers specific lines (e.g. CONTRIBUTING in a separate PR).
|
||||
|
||||
**Status:** CR-74 can stay **Done** with a **child issue** (e.g. “CR-74 follow-ups: auth docs + smoke”) if you prefer not to reopen the parent.
|
||||
|
||||
Reference in New Issue
Block a user