Repository navigation
Phase 1: identity — email-code sign-in, accounts, workspaces, roles, invites - #2
Merged
Merged
Conversation
WIP doc for Phase 1 (identity). Decision 017 records the owner's calls: Better Auth for identity only, GitHub link needed for GitHub tasks only, sign-up policy as an instance setting. Phase 0 docs now say CI passed on PR #1. Adds better-auth 1.7.8 to apps/web. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
authorize()/can() implement the spec's role matrix, the two Read Only switches, and the GitHub gate from decision 017 (GitHub tasks only). invitableRoles() and canManageMember() bound invites and role changes. 78 tests check every role x capability cell against a hand-written copy of the spec; flipping one cell turns the suite red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
Identity and domain schema (migration 0001) with CHECKs for roles and lowercase invite emails. New @gitwork/server package: Better Auth factory (email OTP, hashed codes, database rate limits, encrypted OAuth tokens, GitHub link-only), email adapters, and the sign-up rule from decision 017. Sign-in tests run through the HTTP handler on both drivers; weakening rate-limit storage or code hashing turns them red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
Services in @gitwork/server enforce the role matrix through packages/core. Invite acceptance guards the membership INSERT itself (INSERT ... SELECT ... WHERE pending) and takes the role from the invite row; dropping the guard fails the expired/revoked tests on both drivers. Role changes and removals are guarded on the checked role. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
A framework-free router in @gitwork/server serves /api/v1: me, accounts, workspaces, members, invites. Cookie-authenticated writes must be same-origin; bearer tokens (Mac app) are exempt. Tests cover 401, 403, 400, 404/405, cross-site writes, bearer auth, and the invite flow over HTTP on both drivers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
… link Pages for email-code sign-in (code or click-to-verify link), account onboarding, workspace members and invites, invite acceptance, and GitHub linking. /api/auth and /api/v1 mount Better Auth and the @gitwork/server router per request. E2E covers the owner-invites- client flow and the link verify; smoke now signs in inside the Worker bundle. Feature doc replaces the WIP doc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
- Per-IP limits trust only cf-connecting-ip (Workers) or an opt-in TRUSTED_IP_HEADER; otherwise off. A per-email limit (5/15 min) and a per-user invite cap (30/hour) use one atomic upsert in rate_limits. - listMyWorkspaces uses subqueries: D1 caps a query at 100 bound parameters; the old IN-list failed on D1 at 101 workspaces. - safeRedirectPath() resolves ?next= like a browser (/\evil.com). - BETTER_AUTH_URL is required in production. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
CI's clean install failed on URL in redirect.ts. Locally, URL resolved only through types that vitest pulls in transitively. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Phase 1 from
docs/spec.md. Feature doc:docs/features/identity.md. Decision 017 records the owner's calls (GitHub link needed for GitHub tasks only; sign-up policy is an instance setting).packages/core(authorize,can,invitableRoles,canManageMember,GITHUB_CAPABILITIES).packages/server, with SQL guards inside each write (D1 has no transactions)./api/v1framework-free router: cookie writes must be same-origin; bearer tokens for the Mac app.Verification
pnpm smoke: a full email-code sign-in inside the Worker bundle (D1 + localsend_email).Not covered yet
The GitHub OAuth callback needs a real GitHub App (Phase 2).
🤖 Generated with Claude Code
https://claude.ai/code/session_01GnDXTQ6MVbAXETYsq6fvqg