From f814fdb1d209ca8ca7c0dc70afd36bead5c3d366 Mon Sep 17 00:00:00 2001 From: "farming-labs-docs[bot]" <276457176+farming-labs-docs[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 00:12:13 +0000 Subject: [PATCH] docs(better-auth-studio): scaffold docs app Generated 26 docs files in one commit for a faster preview startup. Generated by Docs Cloud via https://docs.farming-labs.dev --- .docs/site/.gitignore | 6 + .docs/site/app/global.css | 2 + .docs/site/app/layout.tsx | 33 ++++ .docs/site/app/page.tsx | 38 +++++ .docs/site/docs.config.tsx | 54 +++++++ .docs/site/next-env.d.ts | 6 + .docs/site/next.config.ts | 12 ++ .docs/site/package.json | 30 ++++ .docs/site/postcss.config.mjs | 7 + .docs/site/scripts/sync-managed-content.mjs | 159 ++++++++++++++++++++ .docs/site/tsconfig.json | 42 ++++++ AGENTS.md | 28 ++++ docs.json | 26 ++++ docs/configuration.mdx | 13 ++ docs/configuration/database-adapters.mdx | 80 ++++++++++ docs/configuration/deployment.mdx | 40 +++++ docs/features.mdx | 70 +++++++++ docs/features/organization-management.mdx | 37 +++++ docs/guides.mdx | 59 ++++++++ docs/guides/watch-mode.mdx | 39 +++++ docs/index.mdx | 17 +++ docs/installation.mdx | 49 ++++++ docs/quickstart.mdx | 49 ++++++ docs/self-hosting.mdx | 29 ++++ docs/self-hosting/overview.mdx | 63 ++++++++ pnpm-workspace.yaml | 1 + 26 files changed, 989 insertions(+) create mode 100644 .docs/site/.gitignore create mode 100644 .docs/site/app/global.css create mode 100644 .docs/site/app/layout.tsx create mode 100644 .docs/site/app/page.tsx create mode 100644 .docs/site/docs.config.tsx create mode 100644 .docs/site/next-env.d.ts create mode 100644 .docs/site/next.config.ts create mode 100644 .docs/site/package.json create mode 100644 .docs/site/postcss.config.mjs create mode 100644 .docs/site/scripts/sync-managed-content.mjs create mode 100644 .docs/site/tsconfig.json create mode 100644 AGENTS.md create mode 100644 docs.json create mode 100644 docs/configuration.mdx create mode 100644 docs/configuration/database-adapters.mdx create mode 100644 docs/configuration/deployment.mdx create mode 100644 docs/features.mdx create mode 100644 docs/features/organization-management.mdx create mode 100644 docs/guides.mdx create mode 100644 docs/guides/watch-mode.mdx create mode 100644 docs/index.mdx create mode 100644 docs/installation.mdx create mode 100644 docs/quickstart.mdx create mode 100644 docs/self-hosting.mdx create mode 100644 docs/self-hosting/overview.mdx diff --git a/.docs/site/.gitignore b/.docs/site/.gitignore new file mode 100644 index 00000000..7ab6091b --- /dev/null +++ b/.docs/site/.gitignore @@ -0,0 +1,6 @@ +node_modules +.env* +!.env.example +.next +.vercel +app/docs diff --git a/.docs/site/app/global.css b/.docs/site/app/global.css new file mode 100644 index 00000000..3c489baa --- /dev/null +++ b/.docs/site/app/global.css @@ -0,0 +1,2 @@ +@import "tailwindcss"; +@import "@farming-labs/theme/colorful/css"; diff --git a/.docs/site/app/layout.tsx b/.docs/site/app/layout.tsx new file mode 100644 index 00000000..8a31ca5c --- /dev/null +++ b/.docs/site/app/layout.tsx @@ -0,0 +1,33 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import { RootProvider } from "@farming-labs/theme"; +import docsConfig from "../docs.config"; +import "./global.css"; + +const geistSans = Geist({ + variable: "--fd-font-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--fd-font-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: { + default: "Docs", + template: docsConfig.metadata?.titleTemplate ?? "%s", + }, + description: docsConfig.metadata?.description, +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + ); +} diff --git a/.docs/site/app/page.tsx b/.docs/site/app/page.tsx new file mode 100644 index 00000000..bf468bb2 --- /dev/null +++ b/.docs/site/app/page.tsx @@ -0,0 +1,38 @@ +import Link from "next/link"; + +const title = "Better Auth Studio"; +const description = "An admin studio for Better Auth — inspect users, manage organizations, and monitor your auth system from a polished UI."; + +export default function HomePage() { + return ( +
+
+
+

+ Documentation +

+

{title}

+

{description}

+

+ Author markdown in{" "} + + docs/ + + . Everything under{" "} + /docs is synced from that folder. +

+
+ + Open documentation + +
+
+
+ ); +} diff --git a/.docs/site/docs.config.tsx b/.docs/site/docs.config.tsx new file mode 100644 index 00000000..a8452c08 --- /dev/null +++ b/.docs/site/docs.config.tsx @@ -0,0 +1,54 @@ +import { defineDocs } from "@farming-labs/docs"; +import { colorful } from "@farming-labs/theme/colorful"; + +export default defineDocs({ + entry: "docs", + theme: colorful(), + ordering: [ + { + "slug": "quickstart" + }, + { + "slug": "installation" + }, + { + "slug": "features", + "children": [ + { + "slug": "organization-management" + } + ] + }, + { + "slug": "configuration", + "children": [ + { + "slug": "database-adapters" + }, + { + "slug": "deployment" + } + ] + }, + { + "slug": "guides", + "children": [ + { + "slug": "watch-mode" + } + ] + }, + { + "slug": "self-hosting", + "children": [ + { + "slug": "overview" + } + ] + } + ], + metadata: { + titleTemplate: "%s – Docs", + description: "Managed by @farming-labs/docs Cloud", + }, +}); diff --git a/.docs/site/next-env.d.ts b/.docs/site/next-env.d.ts new file mode 100644 index 00000000..9edff1c7 --- /dev/null +++ b/.docs/site/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/.docs/site/next.config.ts b/.docs/site/next.config.ts new file mode 100644 index 00000000..948bed40 --- /dev/null +++ b/.docs/site/next.config.ts @@ -0,0 +1,12 @@ +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { withDocs } from "@farming-labs/next/config"; + +const appDir = dirname(fileURLToPath(import.meta.url)); +const root = join(appDir, "../.."); + +export default withDocs({ + turbopack: { + root, + }, +}); diff --git a/.docs/site/package.json b/.docs/site/package.json new file mode 100644 index 00000000..a3012c46 --- /dev/null +++ b/.docs/site/package.json @@ -0,0 +1,30 @@ +{ + "name": "docs-cloud-managed-runtime", + "private": true, + "packageManager": "pnpm@10.9.0", + "scripts": { + "sync:content": "node ./scripts/sync-managed-content.mjs", + "dev": "node ./scripts/sync-managed-content.mjs && next dev --turbopack", + "build": "node ./scripts/sync-managed-content.mjs && next build --turbopack", + "start": "node ./scripts/sync-managed-content.mjs && next start" + }, + "dependencies": { + "@farming-labs/docs": "latest", + "@farming-labs/next": "latest", + "@farming-labs/theme": "latest", + "next": "16.2.3", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "zod": "^4.1.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.1.18", + "@types/mdx": "^2.0.13", + "@types/node": "^22.10.0", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", + "typescript": "^5.9.3" + } +} diff --git a/.docs/site/postcss.config.mjs b/.docs/site/postcss.config.mjs new file mode 100644 index 00000000..61e36849 --- /dev/null +++ b/.docs/site/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/.docs/site/scripts/sync-managed-content.mjs b/.docs/site/scripts/sync-managed-content.mjs new file mode 100644 index 00000000..bd8e35b9 --- /dev/null +++ b/.docs/site/scripts/sync-managed-content.mjs @@ -0,0 +1,159 @@ +import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises"; +import { basename, dirname, extname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const runtimeRoot = resolve(fileURLToPath(new URL("..", import.meta.url))); +const repoRoot = resolve(runtimeRoot, "../.."); +const authoredRoots = [ + { source: resolve(repoRoot, "docs"), target: resolve(runtimeRoot, "app/docs") }, + { source: resolve(repoRoot, "api-reference"), target: resolve(runtimeRoot, "app/docs/api") }, +]; +const ignoredDirectoryNames = new Set([ + "node_modules", + ".next", + ".turbo", + ".vercel", + "dist", + "build", + "coverage", +]); +const ignoredFileNames = new Set([ + "bun.lock", + "jsconfig.json", + "package-lock.json", + "package.json", + "pnpm-lock.yaml", + "tsconfig.json", + "yarn.lock", +]); +const staticAssetExtensions = new Set([ + ".avif", + ".bmp", + ".csv", + ".gif", + ".ico", + ".jpeg", + ".jpg", + ".json", + ".mp4", + ".pdf", + ".png", + ".svg", + ".txt", + ".webm", + ".webp", + ".zip", +]); +const codeFenceLanguageAliases = new Map([ + ["dotenv", "bash"], + ["env", "bash"], + ["shell", "bash"], +]); + +function isMarkdownFile(path) { + return [".md", ".mdx"].includes(extname(path).toLowerCase()); +} + +function isStaticAssetFile(path) { + return staticAssetExtensions.has(extname(path).toLowerCase()); +} + +function shouldSkipDirectory(name) { + return name.startsWith(".") || ignoredDirectoryNames.has(name); +} + +function shouldSkipFile(name) { + return name.startsWith(".") || ignoredFileNames.has(name); +} + +function normalizeMarkdownContent(content) { + const fenceMarker = String.fromCharCode(96); + const codeFencePattern = new RegExp( + "(^|\\n)(" + fenceMarker + "{3,})([A-Za-z0-9_+.-]+)([^\\n" + fenceMarker + "]*)", + "g", + ); + + return content.replace(codeFencePattern, (match, prefix, fence, language, rest = "") => { + const normalizedLanguage = codeFenceLanguageAliases.get(language.toLowerCase()); + + if (!normalizedLanguage) { + return match; + } + + return prefix + fence + normalizedLanguage + rest; + }); +} + +function targetPagePath(targetRoot, relativePath) { + const withoutExtension = relativePath.replace(/\.mdx?$/i, ""); + const routeFileName = basename(withoutExtension).toLowerCase(); + const isIndexPage = routeFileName === "index" || routeFileName === "page"; + const targetDirectory = isIndexPage ? dirname(withoutExtension) : withoutExtension; + return join(targetRoot, targetDirectory === "." ? "" : targetDirectory, "page.mdx"); +} + +async function fileExists(path) { + try { + await readdir(path); + return true; + } catch { + try { + await readFile(path, "utf8"); + return true; + } catch { + return false; + } + } +} + +async function syncAuthoredRoot(sourceRoot, targetRoot) { + if (!(await fileExists(sourceRoot))) { + return; + } + + const visit = async (currentSourceDirectory, relativeDirectory = "") => { + const entries = await readdir(currentSourceDirectory, { withFileTypes: true }); + + for (const entry of entries) { + if (entry.name.startsWith(".")) { + continue; + } + + const sourcePath = join(currentSourceDirectory, entry.name); + const relativePath = relativeDirectory ? join(relativeDirectory, entry.name) : entry.name; + + if (entry.isDirectory()) { + if (shouldSkipDirectory(entry.name)) { + continue; + } + + await visit(sourcePath, relativePath); + continue; + } + + if (!isMarkdownFile(entry.name)) { + if (shouldSkipFile(entry.name) || !isStaticAssetFile(entry.name)) { + continue; + } + + const targetPath = join(targetRoot, relativePath); + await mkdir(dirname(targetPath), { recursive: true }); + await cp(sourcePath, targetPath, { force: true }); + continue; + } + + const targetPath = targetPagePath(targetRoot, relativePath); + await mkdir(dirname(targetPath), { recursive: true }); + await writeFile(targetPath, normalizeMarkdownContent(await readFile(sourcePath, "utf8")), "utf8"); + } + }; + + await visit(sourceRoot); +} + +await rm(resolve(runtimeRoot, "app/docs"), { recursive: true, force: true }); +await mkdir(resolve(runtimeRoot, "app/docs"), { recursive: true }); + +for (const authoredRoot of authoredRoots) { + await syncAuthoredRoot(authoredRoot.source, authoredRoot.target); +} diff --git a/.docs/site/tsconfig.json b/.docs/site/tsconfig.json new file mode 100644 index 00000000..247f602d --- /dev/null +++ b/.docs/site/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "baseUrl": ".", + "paths": { + "@/*": [ + "./*" + ] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..bbbc4870 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# Docs Maintenance Guide +Use this file as the handoff checklist for future edits to this documentation PR. +## Source Layout +- The docs source lives in `docs/`. +- `docs.json` is the Docs Cloud configuration for publishing, previews, and content roots. +- The managed runtime lives in `.docs/site`; edit authored markdown at the repo root instead of generated runtime pages under `.docs/site/app/docs`. +- Keep every page grounded in README content, package metadata, source exports, CLI help, environment examples, or existing docs. +## Docs Routes +- /docs - Introduction +- /docs/installation - Installation +- /docs/quickstart - Quickstart +- /docs/configuration - Configuration +- /docs/configuration/database-adapters - Database Adapters +- /docs/configuration/deployment - Deployment +- /docs/guides - Guides +- /docs/guides/watch-mode - Watch Mode +- /docs/self-hosting - Self-Hosting +- /docs/self-hosting/overview - Self-Hosting Overview +- /docs/features - Features +- /docs/features/organization-management - Organization Management +## Editing Guidelines +- Prefer reader-facing setup, usage, and troubleshooting notes over source inventories. +- Do not add commands, flags, environment variables, routes, imports, or framework names unless they are present in the repository. +- If you add or rename a page, keep its frontmatter title and description accurate and make sure the navigation ordering still includes it. +- Avoid analyzer language such as generated from, source evidence, implementation map, source surface, or detected in files. +## Verification +- Build the docs site with `cd .docs/site && pnpm install && pnpm build` before handing off a docs PR. +- Open `/docs` and at least one generated leaf page to confirm the sidebar and page content match the PR. diff --git a/docs.json b/docs.json new file mode 100644 index 00000000..a738484d --- /dev/null +++ b/docs.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://docs.farming-labs.dev/schema/docs.json", + "version": 1, + "docs": { + "mode": "frameworkless", + "runtime": "nextjs", + "root": ".docs/site" + }, + "content": { + "docsRoot": "docs", + "apiReferenceRoot": "api-reference", + "openapi": [] + }, + "cloud": { + "apiKey": { + "env": "DOCS_CLOUD_API_KEY" + }, + "preview": { + "enabled": true + }, + "publish": { + "mode": "draft-pr", + "baseBranch": "master" + } + } +} diff --git a/docs/configuration.mdx b/docs/configuration.mdx new file mode 100644 index 00000000..252709a6 --- /dev/null +++ b/docs/configuration.mdx @@ -0,0 +1,13 @@ +--- +title: "Configuration" +description: "Environment, database, and framework settings required to run Better Auth Studio." +order: 0 +--- + +# Configuration + +Better Auth Studio picks up its configuration from two sources: the CLI flags you pass to `better-auth-studio start`, and the `studio.config.ts` file you create in your project root when embedding the studio inside a framework app. + +For standalone use (running the CLI against your project), no config file is required — the CLI reads your existing `auth.ts` directly. For embedded use, you create a `studio.config.ts` that exports a `defineStudioConfig` call so your framework route handler knows how to wire everything together. + +The sub-pages in this section cover the two areas most likely to need explicit configuration: [Database Adapters](/docs/configuration/database-adapters) describes how the studio detects and connects to your persistence layer, and [Deployment](/docs/configuration/deployment) covers running the studio in Docker or on a cloud platform. diff --git a/docs/configuration/database-adapters.mdx b/docs/configuration/database-adapters.mdx new file mode 100644 index 00000000..590fd6a5 --- /dev/null +++ b/docs/configuration/database-adapters.mdx @@ -0,0 +1,80 @@ +--- +title: "Database Adapters" +description: "How Better Auth Studio connects to Prisma, Drizzle, and SQLite databases." +order: 1 +--- + +# Database Adapters + +Better Auth Studio reads and writes your auth database through the same adapter you already configured in `auth.ts`. It auto-detects which adapter is in use when the CLI starts, so in most cases you don't need to do anything extra. + +## Supported adapters + +The studio works with: + +- **Prisma** (`prismaAdapter`) — PostgreSQL, MySQL, and SQLite providers +- **Drizzle** (`drizzleAdapter`) — `pg`, `mysql`, and `sqlite` providers +- **better-sqlite3** (`new Database(...)`) — direct SQLite without an ORM + +## Prisma + +If your project already uses Prisma, your `auth.ts` likely looks like this: + +```typescript +import { betterAuth } from "better-auth"; +import { prismaAdapter } from "better-auth/adapters/prisma"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +export const auth = betterAuth({ + database: prismaAdapter(prisma, { + provider: "postgresql", // or "mysql" or "sqlite" + }), +}); +``` + +The studio picks this up automatically. No additional configuration is needed. + +## Drizzle + +For Drizzle, the setup looks like: + +```typescript +import { betterAuth } from "better-auth"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; +import { db } from "./database"; + +export const auth = betterAuth({ + database: drizzleAdapter(db, { + provider: "pg", // or "mysql" or "sqlite" + }), +}); +``` + +## SQLite + +For projects using `better-sqlite3` directly: + +```typescript +import { betterAuth } from "better-auth"; +import Database from "better-sqlite3"; + +export const auth = betterAuth({ + database: new Database("./better-auth.db"), +}); +``` + +## Migrations and schema + +Some studio features — such as `lastSeenAt` tracking on user records — add columns to your database schema. After enabling those features, run your migrations before restarting the studio: + +```bash +# Prisma +npx prisma migrate dev + +# Drizzle +npx drizzle-kit push +``` + +The studio will warn you in the UI if a required column is missing. diff --git a/docs/configuration/deployment.mdx b/docs/configuration/deployment.mdx new file mode 100644 index 00000000..507a0628 --- /dev/null +++ b/docs/configuration/deployment.mdx @@ -0,0 +1,40 @@ +--- +title: "Deployment" +description: "Run Better Auth Studio in Docker or on a cloud platform." +order: 2 +--- + +# Deployment + +Better Auth Studio ships with a Dockerfile and Docker Compose configuration you can use to run the standalone studio in any containerized environment. This is the recommended approach when you want a persistent admin UI that's not tied to a single developer's machine. + +## Docker Compose (recommended) + +The repository includes `docker/compose.yml`. The minimum required environment variable is `HOST_PROJECT_PATH` — the path on your host machine to your Better Auth project directory: + +```bash +HOST_PROJECT_PATH=/path/to/your/project docker compose -f docker/compose.yml up +``` + +The container mounts your project directory at `/workspace`, installs dependencies automatically, and starts the studio on port `3002`. + +## Environment variables + +The Docker setup reads the following variables: + +| Variable | Default | Description | +|---|---|---| +| `HOST_PROJECT_PATH` | *(required)* | Absolute path to your Better Auth project on the host | +| `PORT` | `3002` | Port the studio listens on | +| `CONFIG_PATH` | `./auth.ts` | Relative path to your auth config inside the workspace | +| `WATCH` | `false` | Set to `true` to enable watch mode | +| `AUTO_INSTALL` | `true` | Automatically run `pnpm install` on startup | +| `GEO_DB_PATH` | *(empty)* | Optional path to a GeoLite2 database file | + +## Container image + +The multi-stage Dockerfile builds from `node:20-bookworm-slim`. The builder stage compiles TypeScript and the frontend, packs the result into a tarball, and the runtime stage installs it globally so `better-auth-studio` is available on `PATH`. The container exposes port `3002`. + +## Vercel + +The docs site deploys to Vercel via `vercel.json` at the repository root. If you're deploying your own Next.js or other framework app that embeds the studio, standard platform deployment applies — set the required environment variables (`BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, and your database URL) in your platform dashboard. diff --git a/docs/features.mdx b/docs/features.mdx new file mode 100644 index 00000000..32748363 --- /dev/null +++ b/docs/features.mdx @@ -0,0 +1,70 @@ +--- +title: "Features" +description: "The main admin workflows available inside Better Auth Studio." +order: 0 +--- + +# Features + +Better Auth Studio gives you a full admin UI on top of your Better Auth database. This section documents the major workflows available inside the studio. + +**Dashboard** — The landing screen shows aggregate counts for users, teams, and organizations, so you can understand the state of your system at a glance. + +**User Management** — Create, edit, delete, and search users. You can update email verification status, view linked accounts, and bulk-seed test users for development. When event tracking is enabled, the studio also surfaces a `lastSeenAt` timestamp for each user. + +**[Organization Management](/docs/features/organization-management)** — Manage the multi-tenant layer of your auth system. Create organizations with custom slugs, manage teams inside those organizations, control membership, handle invitations, and bulk-seed test data. + +**Settings** — Inspect which Better Auth plugins are active, review your database adapter configuration, and check the status of OAuth social providers and email settings. + +## Examples + +Use these examples as concrete starting points for this workflow: + +### Setup +```typescript +import type { StudioConfig } from "better-auth-studio"; +import { auth } from "./lib/auth"; + +const config: StudioConfig = { + auth, + basePath: "/api/studio", + metadata: { + title: "Admin Dashboard", + theme: "dark", + }, + access: { + roles: ["admin"], + allowEmails: ["admin@example.com"], + allowIpAddresses: ["127.0.0.1", "::1", "192.168.*"], + blockIpAddresses: ["203.0.113.45"], + }, +}; + +export default config; +``` + +### Basic Usage +```bash +pnpm better-auth-studio start +``` + +### Start Studio +```bash +# Start on custom port (if installed as dev dependency) +pnpm better-auth-studio start --port 3001 + +# Or with pnpx +pnpx better-auth-studio start --port 3001 + +# Start without opening browser +pnpm better-auth-studio start --no-open + +# Use custom config file +pnpm better-auth-studio start --config ./custom-auth.ts + +# Enable watch mode for auto-reload on config changes +pnpm better-auth-studio start --watch + +# Combine multiple options +pnpx better-auth-studio start --port 3001 --watch --config ./src/auth.ts +``` diff --git a/docs/features/organization-management.mdx b/docs/features/organization-management.mdx new file mode 100644 index 00000000..0de53ca0 --- /dev/null +++ b/docs/features/organization-management.mdx @@ -0,0 +1,37 @@ +--- +title: "Organization Management" +description: "Create and manage organizations, teams, and memberships in Better Auth Studio." +order: 1 +--- + +# Organization Management + +Organization management is the multi-tenant administrative surface inside Better Auth Studio. It lets you inspect and modify the organizations, teams, and memberships that structure access inside your application — without writing SQL or building a custom admin UI. + +## Organizations + +From the Organizations screen you can: + +- Browse all organizations in a paginated list +- Create new organizations with a name and a custom slug +- Edit organization details after creation +- Delete organizations when they're no longer needed +- Bulk-seed test organizations for development and staging environments + +## Teams + +Each organization can contain one or more teams. The studio lets you create and manage teams within an organization, rename them, and remove them when the structure changes. + +## Members + +You can add users to a team or remove them from one directly in the studio. Membership changes take effect immediately against your database — there's no separate sync step. + +## Invitations + +The studio surfaces pending invitations so you can review who has been invited to an organization and cancel invitations that are no longer valid. + +## Bulk seeding + +The bulk seed feature generates multiple test organizations and teams in a single action. This is useful for populating a development or staging database before testing multi-tenant workflows in your application. + +> **Note:** Organization management features require the Better Auth organizations plugin to be enabled in your `auth.ts`. The Settings screen inside the studio shows which plugins are currently active. diff --git a/docs/guides.mdx b/docs/guides.mdx new file mode 100644 index 00000000..9d797846 --- /dev/null +++ b/docs/guides.mdx @@ -0,0 +1,59 @@ +--- +title: "Guides" +description: "Practical runbooks for common Better Auth Studio development and maintenance tasks." +order: 0 +--- + +# Guides + +The guides in this section cover specific tasks you'll run into after the initial setup. Each guide focuses on a single goal and takes you from start to a verified outcome. + +**[Watch Mode](/docs/guides/watch-mode)** — Keep the studio in sync with your `auth.ts` during active development. The server restarts automatically when you save changes, and the browser updates via WebSocket without a manual refresh. + +More guides will be added as the project grows. If you run into a workflow that isn't documented here, [open an issue](https://github.com) on the GitHub repository. + +## Examples + +Use these examples as concrete starting points for this workflow: + +### Running From Source +```bash +# Clone the repository +git clone https://github.com/Kinfe123/better-auth-studio.git +cd better-auth-studio + +# Install dependencies +pnpm install + +# Build the project +pnpm build + +# Start development server +pnpm dev +``` + +### Basic Usage +```bash +pnpm better-auth-studio start +``` + +### Start Studio +```bash +# Start on custom port (if installed as dev dependency) +pnpm better-auth-studio start --port 3001 + +# Or with pnpx +pnpx better-auth-studio start --port 3001 + +# Start without opening browser +pnpm better-auth-studio start --no-open + +# Use custom config file +pnpm better-auth-studio start --config ./custom-auth.ts + +# Enable watch mode for auto-reload on config changes +pnpm better-auth-studio start --watch + +# Combine multiple options +pnpx better-auth-studio start --port 3001 --watch --config ./src/auth.ts +``` diff --git a/docs/guides/watch-mode.mdx b/docs/guides/watch-mode.mdx new file mode 100644 index 00000000..1f26b1ec --- /dev/null +++ b/docs/guides/watch-mode.mdx @@ -0,0 +1,39 @@ +--- +title: "Watch Mode" +description: "Automatically reload the studio when your auth config changes during development." +order: 1 +--- + +# Watch Mode + +Watch mode keeps the studio server in sync with your `auth.ts` while you're actively developing. Instead of stopping and restarting the CLI every time you change your auth configuration, the server detects the file change, restarts automatically, and pushes an update to the browser over WebSocket — no manual refresh needed. + +## Enabling watch mode + +Pass `--watch` to the `start` command: + +```bash +pnpm better-auth-studio start --watch +``` + +Or combine it with other flags: + +```bash +pnpm better-auth-studio start --watch --port 4000 --config ./src/lib/auth.ts +``` + +With `pnpx`: + +```bash +pnpx better-auth-studio start --watch +``` + +## What gets watched + +The CLI monitors the auth config file resolved at startup — either the auto-detected path or the path you passed via `--config`. Changes to that file trigger a server restart. Other files in your project are not watched. + +## When to use it + +Watch mode is designed for local development. It's especially useful when you're iterating on plugin configuration, adding social providers, or changing database adapter settings and you want to see the studio reflect those changes immediately. + +> **Note:** Avoid enabling watch mode in production or inside a Docker container where the config file is unlikely to change. Use it as a development-time convenience only. diff --git a/docs/index.mdx b/docs/index.mdx new file mode 100644 index 00000000..ae4b992d --- /dev/null +++ b/docs/index.mdx @@ -0,0 +1,17 @@ +--- +title: "Introduction" +description: "An admin studio for Better Auth — inspect users, manage organizations, and monitor your auth system from a polished UI." +order: 0 +--- + +# Introduction + +Better Auth Studio is an admin interface for [Better Auth](https://better-auth.com) projects. It gives you a real-time view into your authentication database — users, sessions, organizations, teams, and settings — without writing a single query. You run it from the CLI, point it at your existing `auth.ts` config, and open the dashboard in your browser. + +> **Note:** Better Auth Studio is currently in beta. You may encounter bugs or incomplete features. Report issues on the GitHub repository — your feedback shapes the roadmap. + +The studio ships in two modes. In **standalone mode**, you run it as a CLI tool (`better-auth-studio start`) alongside your application — zero framework coupling required. In **embedded mode**, you mount it directly inside your Next.js, SvelteKit, Astro, Nuxt, Remix, SolidStart, Elysia, Express, Hono, or TanStack Start app using the framework-specific handler. + +A [live demo](https://bt-nextjs.vercel.app/admin) is available if you want to explore the UI before installing. Login with `admin@user.com` / `admin@user.com`. + +Head to [Installation](/docs/installation) to add the package to your project, or jump straight to [Quickstart](/docs/quickstart) to run it in under two minutes. If you want to embed the studio inside your framework app rather than run it standalone, see [Self-Hosting](/docs/self-hosting). diff --git a/docs/installation.mdx b/docs/installation.mdx new file mode 100644 index 00000000..2453ad97 --- /dev/null +++ b/docs/installation.mdx @@ -0,0 +1,49 @@ +--- +title: "Installation" +description: "Install and configure Better Auth Studio." +order: 10 +--- + +# Installation + +Better Auth Studio runs against your existing Better Auth project. Before you install it, make sure you have: + +- **Node.js v18 or higher** +- **A Better Auth project** with a valid `auth.ts` configuration file +- **A supported database adapter** — Prisma, Drizzle, or `better-sqlite3` + +## Install the package + +The recommended approach is installing as a dev dependency so each project pins its own version: + +```bash +pnpm add -D better-auth-studio +``` + +You can also install it globally if you want one shared installation across projects: + +```bash +pnpm add -g better-auth-studio +``` + +Or run it on demand without installing at all: + +```bash +pnpx better-auth-studio start +``` + +## Verify the installation + +Run the following from your project root to confirm the binary is available: + +```bash +pnpm better-auth-studio --help +``` + +You should see the available commands and flags printed to the terminal. If the command is not found after a local install, make sure your shell resolves `node_modules/.bin` (pnpm does this automatically when you prefix commands with `pnpm`). + +## Auto-detection + +## Next steps + +Once the package is installed, follow the [Quickstart](/docs/quickstart) to launch the studio for the first time. To embed the studio inside your framework app instead of running it standalone, start with [Self-Hosting](/docs/self-hosting). diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx new file mode 100644 index 00000000..b432f6af --- /dev/null +++ b/docs/quickstart.mdx @@ -0,0 +1,49 @@ +--- +title: "Quickstart" +description: "Run Better Auth Studio for the first time." +order: 20 +--- + +# Quickstart + +This guide takes you from a fresh install to a running studio dashboard. You need an existing Better Auth project with a configured `auth.ts` and a working database connection. + +## 1. Navigate to your project + +```bash +cd your-better-auth-project +``` + +## 2. Install Better Auth Studio + +```bash +pnpm add -D better-auth-studio +``` + +## 3. Start the studio + +```bash +pnpm better-auth-studio start +``` + +The CLI auto-detects your `auth.ts` file and starts the studio server on port `3002` by default. Your browser opens automatically at `http://localhost:3002`. + +> **Note:** Port `3002` is chosen to avoid colliding with apps already running on `3000`. You can override it with `--port`. + +## Custom port or config path + +```bash +pnpm better-auth-studio start --port 4000 --config ./src/lib/auth.ts +``` + +## 4. Explore the dashboard + +Once the browser opens you'll see the dashboard with an overview of your users, sessions, organizations, and plugin status. From here you can create or edit users, manage organizations and teams, and inspect your database adapter settings. + +## Using pnpx (no install) + +If you prefer not to add the package to your project, run it directly: + +```bash +pnpx better-auth-studio start +``` diff --git a/docs/self-hosting.mdx b/docs/self-hosting.mdx new file mode 100644 index 00000000..508d24a9 --- /dev/null +++ b/docs/self-hosting.mdx @@ -0,0 +1,29 @@ +--- +title: "Self-Hosting" +description: "Embed Better Auth Studio inside your own framework application." +order: 0 +--- + +# Self-Hosting + +Better Auth Studio supports two deployment models. The **standalone CLI** runs as a separate process alongside your app — useful during development and for teams who want an isolated admin tool. The **embedded** model mounts the studio directly inside your application as a set of API routes, so the studio lives at a path like `/api/studio` in your own domain. + +This section covers the embedded model. If you just want to run the CLI, the [Quickstart](/docs/quickstart) is all you need. + +## Supported frameworks + +The studio ships framework-specific handlers for: + +- Next.js + +## General setup + +Regardless of framework, the steps are the same: + +1. Install `better-auth-studio` as a dependency (not just dev dependency, since it runs at request time). +2. Run `better-auth-studio init` to scaffold `studio.config.ts` and the route file. +3. Fill in the `auth` and `basePath` options in `studio.config.ts`. +4. Set the required environment variables: `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, and `STUDIO_SECRET`. +5. Start your application and navigate to the `basePath` you configured. + +See [Self-Hosting Overview](/docs/self-hosting/overview) for a detailed walkthrough including Docker-based deployment. diff --git a/docs/self-hosting/overview.mdx b/docs/self-hosting/overview.mdx new file mode 100644 index 00000000..3ee9d072 --- /dev/null +++ b/docs/self-hosting/overview.mdx @@ -0,0 +1,63 @@ +--- +title: "Self-Hosting Overview" +description: "Run Better Auth Studio in infrastructure you control — embedded or Docker-based." +order: 1 +--- + +# Self-Hosting Overview + +This page walks through both self-hosting approaches: embedding the studio in a framework app, and running it as a standalone Docker container. + +## Embedded in a framework app + +The quickest way to embed the studio is with the `init` command: + +```bash +pnpm better-auth-studio init +``` + +This creates `studio.config.ts` in your project root and the appropriate route file for your framework. For Next.js, that file lands at `app/api/studio/[[...path]]/route.ts`. + +Open `studio.config.ts` and configure it: + +```typescript +import { defineStudioConfig } from 'better-auth-studio'; +import { auth } from './src/lib/auth'; + +export default defineStudioConfig({ + auth, + basePath: '/api/studio', + access: { + allowEmails: ['admin@yourcompany.com'], + }, +}); +``` + +Then set the required environment variables: + +```bash +BETTER_AUTH_SECRET=your-secret +BETTER_AUTH_URL=https://yourapp.com +STUDIO_SECRET=a-separate-studio-secret +``` + +Start your app and open `https://yourapp.com/api/studio` in the browser. + +## Docker standalone + +The repository includes a `Dockerfile` and `docker/compose.yml` for running the studio as a standalone container pointed at any Better Auth project on your host. + +```bash +HOST_PROJECT_PATH=/path/to/your/project \ + docker compose -f docker/compose.yml up +``` + +The container exposes port `3002` by default. Set `PORT` in your environment to change it. + +See [Deployment](/docs/configuration/deployment) for the full list of Docker environment variables and configuration options. + +## Access control + +When the studio is embedded at a public URL, use `access.allowEmails` in `studio.config.ts` to restrict access to a specific list of email addresses. Without this, any authenticated user in your Better Auth system can reach the admin UI. + +> **Note:** Self-hosting is in beta. The access control model may evolve in future releases. diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b75a0187..feef55e5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,3 +2,4 @@ packages: - "frontend/**" - "docs/**" - "src/**" + - ".docs/site"