Project Structure
Understanding the Unstack Pro codebase organization
Project Structure
Understand the codebase so you can build your product on top. Auth, organizations, and admin are already organized and working.
You don't need to modify the auth system. Focus on the /app directory where you'll build your product features.
Root Structure
convex-better-auth/
├── app/ # Next.js App Router pages
├── actions/ # Server actions
├── components/ # Reusable React components
├── config/ # Configuration files
├── emails/ # Email templates (React Email)
├── lib/ # Utilities and core logic
├── schemas/ # Validation schemas (Zod)
├── scripts/ # Build and utility scripts
├── styles/ # Global styles
├── types/ # TypeScript type definitions
├── video/ # Remotion demo-video project (own deps)
└── ... config filesApp Directory (/app)
Next.js 16 App Router structure with all routes.
Authentication Routes
app/auth/
├── layout.tsx # Auth pages layout
├── page.tsx # Auth redirect/landing
├── login/
│ ├── page.tsx
│ ├── loading.tsx
│ ├── 2fa/
│ │ ├── page.tsx
│ │ ├── loading.tsx
│ │ └── _components/
│ │ ├── backup-code-verify-form.tsx
│ │ ├── totp-verify-form.tsx
│ │ └── two-factor-form.tsx
│ └── _components/
│ ├── login-form.tsx
│ ├── otp-request-form.tsx
│ ├── passkey-login-button.tsx
│ └── password-login-form.tsx
├── register/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ ├── register-card.tsx
│ └── register-form.tsx
└── forgot-password/
├── page.tsx
├── loading.tsx
└── _components/
├── email-request-form.tsx
├── forgot-password-form.tsx
└── reset-password-form.tsxAccount Routes
app/account/
├── layout.tsx # Account layout with sidebar
├── page.tsx # Account dashboard
├── loading.tsx
├── settings/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ └── settings-client.tsx
├── security/
│ ├── page.tsx # Security overview
│ ├── sessions/
│ │ ├── page.tsx
│ │ ├── loading.tsx
│ │ └── _components/
│ │ ├── revoke-all-sessions-button.tsx
│ │ ├── revoke-other-sessions-button.tsx
│ │ ├── revoke-session-button.tsx
│ │ ├── session-card.tsx
│ │ └── sessions-client.tsx
│ ├── two-factor/
│ │ ├── page.tsx
│ │ ├── loading.tsx
│ │ └── _components/
│ │ ├── backup-codes-step.tsx
│ │ ├── disable-two-factor.tsx
│ │ ├── enable-two-factor-form.tsx
│ │ ├── otp-verify-step.tsx
│ │ ├── qr-code-step.tsx
│ │ ├── regenerate-backup-codes.tsx
│ │ ├── two-factor-configure-form.tsx
│ │ ├── two-factor-status-card.tsx
│ │ └── view-backup-codes.tsx
│ ├── passkeys/
│ │ ├── page.tsx
│ │ ├── loading.tsx
│ │ └── _components/
│ │ ├── delete-passkey-dialog.tsx
│ │ ├── edit-passkey-name-dialog.tsx
│ │ ├── empty-state.tsx
│ │ ├── passkey-card.tsx
│ │ ├── passkeys-client-list.tsx
│ │ └── register-passkey-button.tsx
│ ├── audit/
│ │ ├── page.tsx
│ │ ├── loading.tsx
│ │ └── _components/
│ │ ├── audit-card.tsx
│ │ └── audit-client.tsx
│ └── _components/
│ ├── delete-account-dialog.tsx
│ ├── delete-confirmation-form.tsx
│ └── security-settings-client.tsx
├── connections/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ ├── connection-card.tsx
│ ├── connections-client.tsx
│ ├── empty-state.tsx
│ └── unlink-account-button.tsx
├── invitations/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ ├── invitation-highlighter.tsx
│ └── invitations-client.tsx
└── delete/
├── page.tsx
├── loading.tsx
└── _components/
└── delete-account-form.tsxOrganization Routes
app/organizations/
├── layout.tsx # Org layout
├── page.tsx # Org list
├── loading.tsx
└── [organizationSlug]/
├── page.tsx # Org dashboard
├── loading.tsx
├── members/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ └── members-table.tsx
├── invitations/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ ├── accept-invitation-button.tsx
│ ├── cancel-invitation-button.tsx
│ ├── invitation-card.tsx
│ ├── invitations-list.tsx
│ └── reject-invitation-button.tsx
├── teams/
│ ├── page.tsx
│ ├── loading.tsx
│ ├── [teamId]/
│ │ ├── page.tsx
│ │ └── loading.tsx
│ └── _components/
│ └── teams-list.tsx
├── roles/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ ├── create-role-dialog.tsx
│ ├── edit-role-dialog.tsx
│ ├── roles-manager.tsx
│ └── roles-table.tsx
├── settings/
│ ├── page.tsx
│ ├── loading.tsx
│ └── _components/
│ ├── delete-organization-dialog.tsx
│ ├── edit-organization-name.tsx
│ ├── organization-image-uploader.tsx
│ └── settings-client.tsx
└── billing/
├── page.tsx
├── loading.tsx
└── _components/
├── manage-billing.tsx
├── orders-table.tsx
├── plan-hero-card.tsx
└── upgrade-plan-button.tsxAdmin Routes
app/admin/
├── page.tsx # Admin dashboard
├── loading.tsx # Loading state
└── _components/
├── admin-stats.tsx
├── ban-user-dialog.tsx
├── banned-users-table.tsx
├── change-password-dialog.tsx
├── create-user-dialog.tsx
├── revoke-sessions-dialog.tsx
├── set-role-dialog.tsx
├── users-manager.tsx
├── users-table.tsx
└── verify-email-dialog.tsxAPI Routes
app/api/
└── auth/
└── [...all]/
└── route.ts # Better Auth API handlerOther Routes
app/
├── layout.tsx # Root layout
├── page.tsx # Home page
├── providers.tsx # App providers
├── global-error.tsx # Global error boundary
├── (legal)/ # Terms & Privacy scaffolding
│ ├── layout.tsx # Shared legal layout
│ ├── terms/page.tsx # Terms of Service (starter copy)
│ └── privacy/page.tsx # Privacy Policy (starter copy)
├── goodbye/
│ ├── page.tsx # Account deleted confirmation
│ └── loading.tsx
└── success/
├── page.tsx # Success page
└── loading.tsxThe app/(legal)/terms and app/(legal)/privacy pages ship with starter copy
parameterized via config/site.ts (appName, supportEmail). Replace and review
this copy before production — see the Customization guide.
Actions Directory (/actions)
Server actions for server-side operations.
actions/
└── update-profile-picture.tsServer actions provide type-safe server-side functions callable from client components.
Components Directory (/components)
Reusable React components organized by category.
Auth Components
components/auth/
├── authenticated-client.tsx
├── change-password-form.tsx
├── controlled-email-input.tsx
├── controlled-input.tsx
├── controlled-otp-input.tsx
├── controlled-password-input.tsx
├── editable-email-input.tsx
├── editable-name-input.tsx
├── form-submit-button.tsx
├── logout-button.tsx
├── otp-input.tsx
├── otp-verify-form.tsx
├── password-confirmation-form.tsx
├── password-input.tsx
├── profile-picture-uploader.tsx
├── profile-sidebar.tsx
├── resend-control.tsx
└── verify-email-dialog.tsxOrganization Components
components/organization/
├── active-org-syncer.tsx
├── add-member-card.tsx
├── add-member-form.tsx
├── add-member-to-team-dialog.tsx
├── create-organization-dialog.tsx
├── create-team-dialog.tsx
├── invite-member-dialog.tsx
├── leave-organization-button.tsx
├── member-card.tsx
├── my-information-card.tsx
├── organization-selector.tsx
├── organization-sidebar.tsx
├── role-multiselect.tsx
├── team-card.tsx
├── team-members-empty-state.tsx
└── teams-empty-state.tsxUI Components
components/ui/
├── avatar.tsx
├── badge.tsx
├── button.tsx
├── card.tsx
├── checkbox.tsx
├── command.tsx
├── data-table.tsx
├── dialog.tsx
├── dropdown-menu.tsx
├── empty-state.tsx
├── field.tsx
├── form.tsx
├── input.tsx
├── label.tsx
├── multi-select.tsx
├── popover.tsx
├── select.tsx
├── separator.tsx
├── sheet.tsx
├── sidebar.tsx
├── skeleton.tsx
├── spinner.tsx
├── table.tsx
├── textarea.tsx
├── toaster.tsx
├── tooltip.tsx
└── visually-hidden.tsxLanding Components
components/landing/
├── landing-nav.tsx # Landing page navigation
└── reveal.tsx # Scroll reveal animationOther Components
components/
├── danger-zone.tsx
├── faq.tsx
├── json-ld.tsx
├── page-header.tsx
├── react-scan.tsx
├── theme-toggle.tsx
└── user-dropdown.tsxConfig Directory (/config)
Application configuration files.
config/
├── fonts.ts # Font configuration
└── site.ts # Site metadata and constantsEmails Directory (/emails)
React Email templates for transactional emails.
emails/
├── delete-account-verification.tsx
├── email-change-verification.tsx
├── index.ts # Template registry
├── organization-invitation-email.tsx
├── reset-password-email.tsx
├── signin-otp-email.tsx
└── verification-email.tsxReact Email lets you write email templates in React with great previews.
Lib Directory (/lib)
Core application logic and utilities.
Authentication
lib/
├── audit-log.ts # Audit log helpers
├── auth-client.ts # Better Auth client config
├── auth-helpers.ts # Auth utility functions
├── auth-server.ts # Better Auth server config
├── autumn-server.ts # SDK-free Autumn REST client (safe for Convex)
├── autumn.ts # Autumn SDK integration (Node/Next.js only)
├── http-polyfills.ts # HTTP polyfills
├── permissions.ts # RBAC permissions
├── session.ts # Session management
├── use-preloaded-auth-query.ts # Preloaded authenticated query hook
└── utils.ts # General utilitiesConvex
lib/convex/
├── convex-provider.tsx # Convex React provider
└── query-client.tsx # Query client setupPlugins
lib/plugin/
├── overrides/ # Custom auth overrides
│ ├── client.ts
│ ├── index.ts
│ └── server.ts
└── reverify/ # Re-verification plugin
├── client.ts
├── index.ts
└── server.tsAudit logging comes from the better-auth-audit package, with helpers in lib/audit-log.ts.
Hooks
lib/hooks/
├── use-debounced-save.ts # Debounced autosave
├── use-loading-callback.ts # Loading state management
└── use-mobile.ts # Mobile detectionUtilities
lib/utils/
├── admin.ts # Admin-related utilities
├── currency.ts # Currency formatting
├── date.ts # Date formatting
├── download.ts # File download utilities
├── organization.ts # Org management utilities
├── passkey-provider.ts # Passkey provider metadata
├── roles.ts # Role helpers
├── string.ts # String utilities
├── toast.ts # Toast notifications
└── user-agent.ts # User agent parsingSchemas Directory (/schemas)
Zod validation schemas.
schemas/
└── auth.ts # Auth form validation schemasScripts Directory (/scripts)
Build and utility scripts.
scripts/
├── capture-demo.ts # Playwright demo capture (bun run demo:capture)
├── compile-all-pages.ts # Page compilation script
├── debug-resend.ts # Resend delivery debugging (needs RESEND_DEPLOY_KEY)
├── line-count.ts # Line counting utility
├── record-demo.ts # Demo recording script
├── run-demo-node.ts # Node runner for demo scripts
├── sync-template.ts # Template update sync script
└── view-file-tree.ts # File tree visualizationscripts/sync-template.ts powers template updates (see
Template Updates); .template-version records the last
synced commit. The video/ project + demo:* scripts render a demo video —
see Customization.
Styles Directory (/styles)
Global CSS and Tailwind styles.
styles/
└── globals.css # Global styles and TailwindTypes Directory (/types)
TypeScript type definitions.
types/
└── organization.ts # Organization-related typesConfiguration Files
Root Config Files
├── .env # Environment variables
├── .env.example # Example environment template
├── .env.local # Local environment overrides
├── .env.sentry-build-plugin # Sentry build configuration
├── .gitignore # Git ignore rules
├── .template-version # Last synced template commit
├── autumn.config.ts # Autumn configuration
├── biome.json # Biome linting/formatting
├── components.json # Shadcn/ui configuration
├── instrumentation-client.ts # Client-side instrumentation
├── instrumentation.ts # Server instrumentation
├── next-env.d.ts # Next.js TypeScript env
├── next.config.js # Next.js configuration
├── package.json # Dependencies and scripts
├── postcss.config.js # PostCSS configuration
├── sentry.edge.config.ts # Sentry Edge Runtime config
├── sentry.server.config.ts # Sentry server config
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
└── tsconfig.tsbuildinfo # TypeScript build infonext.config.js
Next.js configuration with Sentry integration.
instrumentation.ts & instrumentation-client.ts
Sentry instrumentation for error tracking.
sentry.edge.config.ts
Sentry configuration for Edge Runtime functions.
sentry.server.config.ts
Sentry configuration for server-side error tracking.
tailwind.config.js
Tailwind CSS configuration with custom theme.
tsconfig.json
TypeScript configuration with path aliases.
Important aliases:
{
"@/*": "./*" # Root import alias
}biome.json
Biome configuration for linting and formatting.
package.json
Dependencies and scripts:
{
"scripts": {
"dev": "next dev --turbopack",
"build": "tsgo --noEmit && next build --turbopack",
"lint": "biome lint .",
"format": "biome format --write .",
"demo:capture": "…", // Playwright capture
"demo:video": "…", // Remotion render
"demo:render": "…" // capture + render
}
}File Conventions
Loading States
loading.tsx files provide loading UI:
// app/admin/loading.tsx
export default function Loading() {
return <Skeleton />
}Error Boundaries
error.tsx and global-error.tsx files handle errors:
// app/global-error.tsx
export default function GlobalError({ error, reset }) {
return <ErrorUI error={error} retry={reset} />
}Layouts
layout.tsx files wrap route segments:
// app/account/layout.tsx
export default function AccountLayout({ children }) {
return (
<div>
<Sidebar />
{children}
</div>
)
}Component Organization
Pattern: _components folders for route-specific components:
app/admin/
├── page.tsx
└── _components/ # Admin-only components
├── users-table.tsx
└── admin-stats.tsxUnderscore prefixed folders are not treated as routes by Next.js.
Key Technologies
Frontend
- Next.js 16: App Router, Server Components
- React 19: Latest React features
- Tailwind CSS: Utility-first styling
- Shadcn/ui: Component library
- React Hook Form: Form handling
- Zod: Schema validation
Backend
- Better Auth: Authentication framework (via better-convex)
- Convex: Realtime database
- Resend: Email service
- React Email: Email templates
Development
- TypeScript: Type safety
- Biome: Fast linting/formatting
- Sentry: Error tracking (optional)
Adding New Features
New Route
- Create folder in
/app - Add
page.tsx - Add
layout.tsxif needed - Create
_componentsfor route-specific components
New Component
- Add to appropriate
/componentssubfolder - Export from component file
- Import where needed
- Keep reusable, not route-specific
New Action
- Create file in
/actions - Mark with
'use server' - Export async function
- Use from components
New Email Template
- Create in
/emails - Use React Email components
- Add to email sending logic
- Test in development
Best Practices
- Co-location: Keep related code together
- Separation: Separate UI from logic
- Reusability: Extract reusable components
- Type Safety: Use TypeScript everywhere
- Server Components: Default to server, client when needed
- Actions: Use server actions for mutations
- Validation: Validate all inputs with Zod
- Error Handling: Handle errors gracefully
Development Tips
- Use
_componentsfor route-specific components - Keep
components/for truly reusable components - Server Components are default, add
'use client'when needed - Use path alias
@/for clean imports - Follow existing patterns for consistency