Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

An organizer who opens their own signup's link can't get to its responses from there

オープン
#647 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
45/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
next.js, typescript

調査の方向性

Start with src/app/s/[slug]/page.tsx, src/auth/session.ts, and src/lib/policy.ts to trace how the public signup and organizer membership are loaded; review the linked discussion in #583 as well. Then inspect SignupView and the query budget and end to end specs named in the issue. Done means workspace members see the Responses and Build links on open and closed signups, visitors and nonmembers do not, and the listed budgets and checks pass.

索引モデルが issue の本文から書いたものです。

説明

enhancement pipeline:proposed pipeline:ux

Needs your OK: this changes what a signed-in organizer sees on their own signup's public page: a bar at the top with links to Responses and Build. Participants see no change. Swap pipeline:proposed for pipeline:ready to have it built.

What happens

An organizer opened their own open signup from the link they'd shared and asked where to see the responses. The page gave them no way to find out.

  • The public page never checks who's signed in. PublicSignupPage in src/app/s/[slug]/page.tsx reads only the returning-participant cookie (COMMIT_COOKIE_NAME). An organizer sees exactly what a participant sees: the title, the slots and the Sign up buttons. Nothing says it's their signup or where the responses are.
  • The only link off the page is the brand mark. It goes to /, the home page, which doesn't send a signed-in organizer on to their dashboard.
  • Organizers land here a lot. It's the link they copy and send: the share panel, the share message, and links.public from the AI connector tools and Magic Compose. Opening it again later is the natural way to check on a signup.
  • The cookie that's needed is already sent. The Auth.js session cookie (authjs.session-token) has path /, so it already reaches /s/[slug]. The returning-participant cookie is the wrong one for this. It only says this browser signed up for a slot, not who made the signup.

To see it: sign in, publish a signup, then open its public link in the same browser. Nothing on the page leads to Responses or Build.

Fix, in outline

  • Read the session once the signup has loaded. In PublicSignupPage, after loadPublicSignup succeeds (open or closed), call getOrganizerSession() from src/auth/session.ts. Run it alongside getOwnCommitmentsForSignup with Promise.all, so it adds no wait.
  • Check membership through the policy module. Use workspaceRole(toActor(session), sig.workspaceId) from src/lib/policy.ts. Any role counts. No session, no role, or a null workspaceId means no bar. This checks data the page already has, so open and closed signups need no new service read.
  • Show an organizer bar at the top of the page, above the signed-up bar and the title. It says this is their signup and has two links: "See responses" to /app/signups/[id]/responses and "Edit signup" to /app/signups/[id]/build. The wording is under "Choices this makes".
  • Render it on the server. SignupView is a server component. Give it an optional prop carrying the signup id, used in live mode only. The bar is plain links, so /s/[slug]'s first-load JavaScript shouldn't grow.
  • Reuse the signed-up bar's look. The signed-up bar in SignupViewBody is already a line of text with a link, on this page. Move its outer div into a small shared component and use it for both bars, rather than adding a third style (CLAUDE.md: reuse banners).

Watch for

  • This reverses one rule in #583. #583 says an open or closed signup's page "must not call auth()", and its "Done when" checks that "an open signup's page reads no session". Its reason is that this is the participants' hot path. Participants still pay nothing: with no session cookie, Auth.js returns before it touches the database (session() in @auth/core's lib/actions/session.js: if (!sessionToken) return response). Only a signed-in organizer pays, about 2 more statements (the session lookup and loadOrganizerSessionById). If #583 lands first, remove its "reads no session" check in this change. If this lands first, #583's draft branch can reuse the session read. Whichever lands second has the merge.
  • Query budget. GET /s/[slug] in budgets.json is 5 and must stay 5. src/app/query-budget.db.test.ts runs that case with no session cookie. Add a second case signed in as the signup's organizer, with its own budget entry, so the organizer's cost is pinned too.
  • Participants are not users. Nothing a participant does changes, and the organizer keeps the same Sign up buttons. An organizer who also signed up for a slot sees both bars.
  • Keep the id private. Render the bar and its links only for a member. Don't add the id or the membership check to getPublicSignup's result or to GET /api/public/signups/[slug]. toPublicSignup is an allow-list, and it should stay one.
  • Caching. The page already reads cookies and renders on every request. Check that pnpm build still lists /s/[slug] as dynamic (ƒ).
  • e2e specs that open the public page while signed in. loginAsSeededOrganizer (tests/e2e/helpers/auth.ts) signs in the whole browser context. Specs such as organizer.spec.ts, responses.spec.ts and a11y.spec.ts that open /s/[slug] in that context will now see the bar. Check their assertions still hold and the axe scan passes with the bar showing. The help walkthroughs open the public page in a fresh browser.newPage(), so their screenshots stay participant-only. Check that's still true.
  • Help. No article says how to get from the public link to the responses. create-and-publish-a-signup could mention it. Run the help-pages skill's affected-articles.mjs to check.
  • Legal pages. No new cookie, and nothing new is stored. The cookies page says the session cookie "keeps organizers signed in after they sign in", which is still true. The privacy and terms pages need no change.
  • CHANGELOG entry under Unreleased › Added.

Choices this makes

  • The words. "This is your signup. People who open the link see this page without this bar." Links: "See responses" and "Edit signup". Default: these words. They answer the organizer's question and make clear participants don't see the bar.
  • Two links, not one. Default: both. Responses is what the organizer asked for, and Build is where they change the signup. A single link to /app/signups/[id] would land on Build, one more step from the responses.
  • Who sees it: any member of the signup's workspace, viewers included. Default: any member, the same as #583. A viewer can open Responses.
  • Which statuses: open and closed, where the page already has the signup's row. Default: open and closed. Draft is #583's job. An archived signup keeps its message with no link: the page doesn't load an archived row, so it would need #583's kind of guarded read, and an archived signup isn't being shared any more.
  • Not signed in on this device: nothing shows. Default: no "Made this signup? Sign in" line for everyone, for the reason #583 gives: it puts organizer instructions in front of every participant.
  • Telemetry. recordPublicView still writes the organizer's own visit as a signup.viewed system row. Default: leave it. Skipping or tagging members' visits changes what the views query in docs/telemetry.md counts, so it can follow as its own issue.
  • Placement: at the top of the page, not fixed to the bottom. Default: the top. It's the first thing seen on a phone, and a fixed bar would cover the slots.

Done when

  • A signed-in member of the signup's workspace who opens an open or closed signup's public link sees the bar, and its links go to the Responses and Build tabs.
  • A signed-out visitor, and a signed-in organizer from another workspace, see the page exactly as today, with no bar.
  • GET /s/[slug]'s budget stays at 5 for a visitor with no session cookie, and a new budget case pins the count for a signed-in organizer.
  • Tests show the bar for a member and not for a non-member or a signed-out visitor: a SignupView component test, and an e2e check with and without loginAsSeededOrganizer.
  • pnpm build && pnpm budgets pass with /s/[slug]'s first-load JS budget unchanged.
  • pnpm lint && pnpm typecheck && pnpm knip && pnpm test and pnpm test:db pass.

From an organizer's question, passed on by the owner: on their live signup's page, they asked where to see the responses. Checked against the code on main at 7950b54, and against @auth/core 0.41.3's session action for what happens with no session cookie. https://claude.ai/code/session_013hhheErU4qtihAPTY6BjWA

主要言語
TypeScript
スター
19
フォーク
4
平均マージ
20時間 9分
マージ済み PR(30日)
156

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

richshaw/OpenSignup のほかの issue

richshaw/OpenSignup の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。