Skip to content

feat: unify personal and organization starter presets - #10

Merged
jacksonkasi1 merged 69 commits into
mainfrom
dev
Sep 7, 2026
Merged

jacksonkasi1 merged 69 commits into
mainfrom
dev

Conversation

@jacksonkasi1

@jacksonkasi1 jacksonkasi1 commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

What changes

FlowStack's personal and organization templates now share one maintained source. bun run setup asks only for the account model and frontend, installs the selected workspaces, and preserves existing environment files. --output ../my-app creates an independent starter copy without Git history or environment files. Both React Router and TanStack Start use the Hono API on Node.js.

Personal mode disables organization/onboarding backend plugins and UI while retaining the shared database schema. Organization mode includes onboarding and invitations. The change incorporates and extends the cache fix from #7 and the logging cleanup from #9, preserves Better Auth response payloads, refreshes cookies after onboarding/invitation mutations, and fixes fresh-database migrations and username columns.

Dependencies and the transitive lockfile are refreshed. Hono's Zod validator is exercised with Zod 4. TypeScript stays on 6.0.3 because the current ESLint integration rejects TypeScript 7; Node types follow Node 24. The only transitive security override is esbuild. Storage API access is now scoped to the authenticated user or a verified current organization membership.

Validation

  • All four clean generated presets passed install, frozen install, type checks, 12 tests / 82 assertions, production builds, and bun audit (no known vulnerabilities).
  • Root lint, diff whitespace checks, and Drizzle migration generation passed.
  • The interactive setup prompt was exercised in a terminal.
  • Both production frontends completed browser signup → organization creation → skip invitations → email verification without an onboarding loop. Duplicate TanStack notifications were removed.
  • A TanStack runtime check consumes the entire sign-in HTML response within five seconds; local completion was about half a second. CI runs this for both TanStack presets.
  • The production Node API started and handled unauthenticated session requests.
  • GitHub Actions repeats shared checks and the four-preset matrix on Linux.

Live OAuth, ZeptoMail, R2 operations, and Docker deployment were not exercised against external services. Auth integration tests use embedded PostgreSQL and stub outbound email.

Upgrade considerations

See docs/getting-started/template-setup.md, docs/advanced/unified-template-upgrade.md, and docs/advanced/template-verification.md. Existing storage objects need an explicit ownership/key migration; they are not automatically moved or deleted. Existing customized clones do not automatically receive template updates.

main and organization-v2 are unchanged. Their original tips are permanently preserved in backup/main-2026-09-06 and backup/organization-v2-2026-09-06. All implementation work is on dev. This PR is for review; do not merge or delete the backups automatically.

- Add centralized organization configuration (config/organization.ts)
- Configure AuthUIProvider with organization plugin in web and tanstack
- Create organization pages: settings, members, accept-invite
- Add OrganizationSwitcher to AppLayout in both apps
- Create tanstack organization routes
- Built-in roles: owner, admin, member (no custom roles)
- Organization logo upload/delete support

Configuration is now easily configurable via @/config/organization
…ation, auth hooks, and add `react-grab` dependency.
…d organization creation, including database schema updates and UI integration.
- Replace dedicated organizationName column with flexible metadata JSONB
- Add migration 0002_user_metadata.sql
- Update journal for new migration
- Add user-metadata.ts with USER_METADATA_FIELDS configuration
- Add organization.ts with ORGANIZATION_LOGO and ORGANIZATION_ROLES
- Add helper functions: getAuthUserFields(), getUIUserFields()
- Add package exports for new configs
- Add README.md documenting shared package
- Remove unused configs: navigation, routes, inviteSignup, signUpFields
- Import ORGANIZATION_LOGO from @repo/shared
- Remove customRoles (using default admin/member only)
- Reduce file size from ~170 lines to ~100 lines
- Both web and tanstack apps now use centralized config
- Add createdAt field required by better-auth organization plugin
- Create migration 0003_invitation_created_at.sql
- Fixes invitation error when inviting members to organization
- Better-auth additionalFields requires separate database columns, not JSON
- Organization name is handled via frontend and user.create.after hook
- Removed unused getAuthUserFields import
- Add hooks.before to capture signup fields and inject into metadata
- Update user.create.after to read org name from user.metadata
- Works without additionalFields (which requires real columns)
- Create signup-metadata-store.ts with Map for passing signup data
- hooks.before stores organizationName by email in Map
- databaseHooks.user.create.before injects metadata before DB insert
- Auto-cleanup of Map entries after 5 minutes
…neon-http` client for enhanced database performance.
- Add @better-auth-extended/onboarding package
- Configure onboarding plugin with createOrganization step
- Remove hooks.before and databaseHooks.user.create.before
- Delete signup-metadata-store.ts
- Organization now created during onboarding flow instead of signup
- Add type assertions for better-auth-extended compatibility
- Install @better-auth-extended/onboarding in web app
- Add onboarding client plugin to auth-client
- Create Onboarding.tsx page with org creation form
- Add /onboarding route
- Update shared config: remove organizationName from metadata
- Export auth type for client type inference

Note: Has type errors - needs UI component fixes
- Simplified Onboarding.tsx to use direct API call
- Removed onboarding client plugin (type incompatibility)
- Use HTML inputs with Tailwind instead of missing shadcn components
- All type checks passing

Working flow: Signup → /onboarding → Create org → Dashboard
- Fixed runtime error: auth is a type, not a value
- Export type { auth } instead of value export
- Upgraded better-auth from 1.4.12 to 1.4.15
- Re-added onboarding client plugin with 'as any' workaround
- Type checks passing
- Create onboarding.ts config (enable/disable, bypass routes)
- Add RequireOnboarding guard component with loading state
- Simplify ProtectedRoute (auth only, no onboarding)
- Update Dashboard to use both guards
- SaaS-style: forces onboarding before accessing app

Configuration:
- Set ONBOARDING_CONFIG.enabled = false to disable
- Customize bypass routes
- Easy to apply to any protected route
- Create rest-api/onboarding folder with API functions
  - check-status.ts: checkOnboardingStatus()
  - complete-step.ts: completeOnboardingStep()

- Update config/redirects.ts: add onboarding path

- Update onboarding.ts config: use AUTH_REDIRECTS

- Update RequireOnboarding: use rest-api function

- Update Onboarding.tsx: use rest-api and AUTH_REDIRECTS

- Update auth-client.ts: use APP_URLS.api config

No more hardcoded URLs or API calls in components
- check-status.ts: use authClient.onboarding.shouldOnboard()
- complete-step.ts: use authClient.onboarding.step.{stepName}()
- Fixes 403 error from direct REST API calls
- Uses 'as any' for type safety with dynamic methods
- Add should_onboard (boolean, default true)
- Add completed_onboarding_steps (text)

These fields are required by @better-auth-extended/onboarding plugin
to track user onboarding status and completed steps.
RequireOnboarding component handles redirect via React Router instead.
This prevents infinite reload loop caused by window.location.href.
Workaround for @daveyplate/better-auth-ui OrganizationRefetcher crash
when user has no organization (during onboarding).
- Update backend invitation link to use ?invitationId={id} format
- Change frontend route from /invitation/:id to /accept-invitation
- Ensures compatibility with AcceptInvitationCard component
- Rewrite AcceptInvite page with SignedIn/SignedOut logic
- Show signup/signin prompt for unauthenticated users
- Add redirectTo query param support in AuthPage
- Preserve invitation context through auth flow
- Create ORGANIZATION_CONFIG with requireOrganization flag
- Add backend config in packages/auth/src/config/organization.ts
- Add frontend config in apps/web/src/config/organization.ts
- Enables flexible control over organization enforcement
- Add organization membership check to RequireOnboarding
- Redirect to onboarding if user has no active org
- Use ORGANIZATION_CONFIG.requireOrganization flag for control
- Handle edge case where user is removed from all organizations
- Create @repo/onboarding package with multi-step wizard
- Add configurable steps with required/optional flags
- Support step completion, skipping, and validation
- Add step order and current step tracking
- Include roles configuration for organization creators
- Add shouldOnboard, currentOnboardingStep, completedOnboardingSteps fields
- Create migration 0005 for schema changes
- Update user metadata configuration
- Create reusable image upload/delete handlers
- Add ORGANIZATION_LOGO configuration constants
- Support both web and tanstack apps
jacksonkasi1 and others added 19 commits January 30, 2026 00:10
- Added  for centralized auth mode config
- Added comprehensive documentation in
- Updated docs README to include new auth mode guide
- Allows developers to easily switch between 'simple' and 'organization' auth modes via config
- Updated auth package to respect auth mode settings

- Updated web and tanstack apps to use centralized config

- Conditionally render routes in web app based on mode
- Ensure authentication routes are accessible without prior
  authentication.
- Consolidate onboarding and organization routes under a unified
  structure.
- Pass `authClient` to `RequireOnboarding` for proper authentication
  checks.
- Remove aggressive auto-clearing of `shouldOnboard` to allow for
  multi-step onboarding processes.
- Update Zod dependency to v4.3.5.
- Adjust `apps/tanstack` scripts to differentiate build/dev commands.
- Add `.vercel` to `apps/server/.gitignore`.
- Updated Zod version in multiple packages to v4.3.5.
- Renamed build and dev scripts in apps/tanstack for consistency.
- Added Zod dependency to the auth package.
…ache

Re-enable session.cookieCache (maxAge: 60s) and fix the root cause: when
onboarding step handlers wrote directly to DB (sessionTable.activeOrganizationId,
userTable.shouldOnboard), the signed cookie cache was never refreshed, so
RequireOnboarding guards read stale values and looped back to /onboarding.

Fix:
- hooks.after now intercepts /onboarding/step/* and /onboarding/skip-step/*
  paths. After the plugin has run adapter.updateOnboardingState (which sets
  shouldOnboard=false on the completion step), refreshSessionCookie() re-reads
  the fresh session from DB via internalAdapter.findSession and re-issues the
  signed cookie — so the very next guard check sees the updated values.
- The createOrganization step handler also calls refreshSessionCookie() inline
  after writing activeOrganizationId to the session row, giving the client an
  updated cookie mid-flow (before the completion step).
- Added packages/auth/src/utils/refresh-session-cookie.ts helper that wraps
  internalAdapter.findSession + setSessionCookie with error isolation.
…console noise

- Add `debug` level to @repo/logs logger
- Demote four verbose logger.info calls inside hooks.after /get-session
  middleware to logger.debug — fires on every session check and was
  spamming production logs
- Merge duplicate @repo/db imports in packages/auth/src/auth.ts into one
- Remove redundant console.error calls from axios response interceptors in
  web and tanstack apps (error already re-thrown to callers)
- Remove console.error from onboarding catch blocks in web and tanstack
  (user-facing toast already surfaces the error message)
- Remove unused sharedUtility export from packages/config/src/index.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @jacksonkasi1, your pull request is larger than the review limit of 150,000 diff characters

@coderabbitai

coderabbitai Bot commented Sep 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 190 files, which is 90 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: ba28b127-8bc1-425c-bd5c-cfaa96a0b084

📥 Commits

Reviewing files that changed from the base of the PR and between 0e46141 and 793db30.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (190)
  • .explorer/better-auth-extended
  • .github/workflows/verify.yml
  • .gitignore
  • README.md
  • apps/server/.env.example
  • apps/server/.gitignore
  • apps/server/Dockerfile
  • apps/server/package.json
  • apps/server/src/index.ts
  • apps/server/src/middleware/auth.ts
  • apps/server/src/routes/storage/delete.ts
  • apps/server/src/routes/storage/download.ts
  • apps/server/src/routes/storage/exists.ts
  • apps/server/src/routes/storage/list.ts
  • apps/server/src/routes/storage/upload.ts
  • apps/server/src/routes/storage/validation.ts
  • apps/server/tsconfig.json
  • apps/tanstack/.env.example
  • apps/tanstack/eslint.config.js
  • apps/tanstack/package.json
  • apps/tanstack/src/components/auth/ProtectedRoute.tsx
  • apps/tanstack/src/components/layout/AppLayout.tsx
  • apps/tanstack/src/components/ui/full-page-loading.tsx
  • apps/tanstack/src/config/axios.ts
  • apps/tanstack/src/config/email-verification.ts
  • apps/tanstack/src/config/organization.ts
  • apps/tanstack/src/lib/auth-client.ts
  • apps/tanstack/src/providers.tsx
  • apps/tanstack/src/rest-api/storage/delete-file.ts
  • apps/tanstack/src/routeTree.gen.ts
  • apps/tanstack/src/routes/__root.tsx
  • apps/tanstack/src/routes/accept-invitation.tsx
  • apps/tanstack/src/routes/account/settings.tsx
  • apps/tanstack/src/routes/account/verify-email.tsx
  • apps/tanstack/src/routes/dashboard.tsx
  • apps/tanstack/src/routes/invitation/$id.tsx
  • apps/tanstack/src/routes/onboarding/-onboarding-page.tsx
  • apps/tanstack/src/routes/onboarding/create-organization.tsx
  • apps/tanstack/src/routes/onboarding/index.tsx
  • apps/tanstack/src/routes/onboarding/invite-members.tsx
  • apps/tanstack/src/routes/organization/members.tsx
  • apps/tanstack/src/routes/organization/settings.tsx
  • apps/tanstack/src/styles.css
  • apps/tanstack/tsconfig.json
  • apps/web/.env.example
  • apps/web/eslint.config.js
  • apps/web/index.html
  • apps/web/package.json
  • apps/web/src/App.tsx
  • apps/web/src/components/auth/ProtectedRoute.tsx
  • apps/web/src/components/layout/AppLayout.tsx
  • apps/web/src/components/ui/alert.tsx
  • apps/web/src/components/ui/full-page-loading.tsx
  • apps/web/src/components/ui/input.tsx
  • apps/web/src/components/ui/label.tsx
  • apps/web/src/config/axios.ts
  • apps/web/src/config/email-verification.ts
  • apps/web/src/config/onboarding.ts
  • apps/web/src/config/organization.ts
  • apps/web/src/config/redirects.ts
  • apps/web/src/index.css
  • apps/web/src/lib/auth-client.ts
  • apps/web/src/pages/Dashboard.tsx
  • apps/web/src/pages/Onboarding.tsx
  • apps/web/src/pages/Settings.tsx
  • apps/web/src/pages/account/VerifyEmail.tsx
  • apps/web/src/pages/auth/AuthPage.tsx
  • apps/web/src/pages/organization/AcceptInvite.tsx
  • apps/web/src/pages/organization/Members.tsx
  • apps/web/src/pages/organization/Settings.tsx
  • apps/web/src/providers.tsx
  • apps/web/src/rest-api/storage/delete-file.ts
  • apps/web/tsconfig.json
  • apps/web/vite.config.ts
  • docs/README.md
  • docs/advanced/README.md
  • docs/advanced/template-verification.md
  • docs/advanced/unified-template-upgrade.md
  • docs/auth/README.md
  • docs/auth/adding-providers.md
  • docs/auth/auth-modes.md
  • docs/auth/configuration.md
  • docs/auth/cross-domain-auth.md
  • docs/auth/email-templates.md
  • docs/auth/email-verification-policy.md
  • docs/auth/invitation-policy.md
  • docs/auth/oauth-redirects.md
  • docs/auth/onboarding.md
  • docs/auth/organization-invitations.md
  • docs/auth/protected-routes.md
  • docs/auth/user-metadata.md
  • docs/concepts/README.md
  • docs/concepts/architecture.md
  • docs/concepts/authentication-flow.md
  • docs/examples/README.md
  • docs/examples/recipes/invite-flow.md
  • docs/examples/recipes/protected-dashboard.md
  • docs/getting-started/README.md
  • docs/getting-started/first-steps.md
  • docs/getting-started/prerequisites.md
  • docs/getting-started/quickstart.md
  • docs/getting-started/template-setup.md
  • docs/reference/README.md
  • docs/reference/cheatsheet.md
  • eslint.config.mjs
  • package.json
  • packages/auth-ui/package.json
  • packages/auth-ui/src/config/defaults.ts
  • packages/auth-ui/src/guards/decision.ts
  • packages/auth-ui/src/guards/react-router/EmailVerificationBanner.tsx
  • packages/auth-ui/src/guards/react-router/ProtectedRoute.tsx
  • packages/auth-ui/src/guards/react-router/RequireOnboarding.tsx
  • packages/auth-ui/src/guards/react-router/index.ts
  • packages/auth-ui/src/guards/react-router/useEmailVerificationStatus.ts
  • packages/auth-ui/src/guards/tanstack-router/EmailVerificationBanner.tsx
  • packages/auth-ui/src/guards/tanstack-router/ProtectedRoute.tsx
  • packages/auth-ui/src/guards/tanstack-router/RequireOnboarding.tsx
  • packages/auth-ui/src/guards/tanstack-router/index.ts
  • packages/auth-ui/src/guards/tanstack-router/useEmailVerificationStatus.ts
  • packages/auth-ui/src/guards/use-guard.tsx
  • packages/auth-ui/src/index.ts
  • packages/auth-ui/src/invitation-flow.tsx
  • packages/auth-ui/src/organization-menu.tsx
  • packages/auth-ui/src/types.ts
  • packages/auth-ui/tsconfig.json
  • packages/auth/package.json
  • packages/auth/src/auth.ts
  • packages/auth/src/client.ts
  • packages/auth/src/config/organization.ts
  • packages/auth/src/config/roles.ts
  • packages/auth/src/index.ts
  • packages/auth/src/invitation-policy.ts
  • packages/auth/src/types.ts
  • packages/auth/src/utils/refresh-session-cookie.ts
  • packages/config/README.md
  • packages/config/package.json
  • packages/config/src/config/auth-mode.ts
  • packages/config/src/config/invitations.ts
  • packages/config/src/config/organization.ts
  • packages/config/src/config/preset.ts
  • packages/config/src/config/settings.ts
  • packages/config/src/config/user-metadata.ts
  • packages/config/src/index.ts
  • packages/config/src/storage/handlers.ts
  • packages/config/src/storage/index.ts
  • packages/config/src/types/index.ts
  • packages/config/tsconfig.json
  • packages/db/drizzle/0001_sturdy_pyro.sql
  • packages/db/drizzle/0002_user_metadata.sql
  • packages/db/drizzle/0003_invitation_created_at.sql
  • packages/db/drizzle/0004_modern_scorpion.sql
  • packages/db/drizzle/0005_awesome_sentinel.sql
  • packages/db/drizzle/0006_chief_pepper_potts.sql
  • packages/db/drizzle/meta/0001_snapshot.json
  • packages/db/drizzle/meta/0004_snapshot.json
  • packages/db/drizzle/meta/0005_snapshot.json
  • packages/db/drizzle/meta/0006_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/package.json
  • packages/db/src/client.ts
  • packages/db/src/schema/auth.ts
  • packages/db/tsconfig.json
  • packages/email-templates/package.json
  • packages/email/package.json
  • packages/logs/package.json
  • packages/logs/src/index.ts
  • packages/onboarding/package.json
  • packages/onboarding/src/adapter.ts
  • packages/onboarding/src/client.ts
  • packages/onboarding/src/error-codes.ts
  • packages/onboarding/src/index.ts
  • packages/onboarding/src/schema.ts
  • packages/onboarding/src/types.ts
  • packages/onboarding/src/utils.ts
  • packages/onboarding/tsconfig.json
  • packages/shared/src/index.ts
  • packages/storage/package.json
  • packages/storage/src/types.ts
  • packages/storage/src/upload.ts
  • packages/storage/src/utils.ts
  • packages/typescript-config/base.json
  • patches/@daveyplate%2Fbetter-auth-ui@3.4.0.patch
  • scripts/setup.mjs
  • scripts/verify-presets.mjs
  • scripts/verify-tanstack-runtime.mjs
  • tests/auth.integration.test.ts
  • tests/browser-server.ts
  • tests/guards.test.ts
  • tests/setup.test.ts
  • tests/validation.test.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jacksonkasi1
jacksonkasi1 merged commit 449c4c8 into main Sep 7, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant