-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: admin dashboard #2988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: admin dashboard #2988
Changes from 23 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
e5213b4
add admin plan
Kitenite 38e4658
add admin plan
Kitenite 80ca857
hello world
Kitenite 76dfb66
admin projects view
Kitenite 1bb908f
fix typecheck
Kitenite 512cc7e
project list
Kitenite 594d79a
add preview
Kitenite 2d8582c
add search
Kitenite 4207f46
add search
Kitenite ab7a0f7
allow adding user
Kitenite e24570f
allow user detail
Kitenite ff524a3
allow add credit
Kitenite 24104b9
fix some type imports in ui package
Kitenite b908a03
add subscription view
Kitenite 8002f3d
disable auth for admin dashboard
Kitenite e3e5b12
price user count
Kitenite 3148cc2
open stripe urls
Kitenite 03e4ef8
deployments
Kitenite 1493aa0
show deployments
Kitenite af29250
show deployments
Kitenite 908ee8b
domain view
Kitenite ab3dc67
done
Kitenite 3d82a0c
product view
Kitenite 6861c71
add subscription view
Kitenite 05c9405
add subscription to user
Kitenite 10d7e3c
update subscription count
Kitenite 4945724
mark rate limit inactive
Kitenite 5626352
rate limit display
Kitenite e985436
Move admin dashboard to private submodule
Kitenite 4d14eb4
docs: Add admin dashboard documentation to README
Kitenite e008e36
docs: Add admin dashboard self-hosting documentation
Kitenite 4e7a416
add admin dashboard
Kitenite File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # ------------- Required Keys ------------- | ||
| # Supabase - Database and authentication | ||
| NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321 | ||
| NEXT_PUBLIC_SUPABASE_ANON_KEY="<Fill in from content after running supabase start>" | ||
| SUPABASE_DATABASE_URL=postgresql://postgres:[email protected]:54322/postgres | ||
| SUPABASE_SERVICE_ROLE_KEY="<Your Supabase service role key - REQUIRED for admin operations>" |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
|
||
| # dependencies | ||
| /node_modules | ||
| /.pnp | ||
| .pnp.js | ||
|
|
||
| # testing | ||
| /coverage | ||
|
|
||
| # database | ||
| /prisma/db.sqlite | ||
| /prisma/db.sqlite-journal | ||
| db.sqlite | ||
|
|
||
| # next.js | ||
| /.next/ | ||
| /out/ | ||
| next-env.d.ts | ||
|
|
||
| # production | ||
| /build | ||
|
|
||
| # misc | ||
| .DS_Store | ||
| *.pem | ||
|
|
||
| # debug | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
| .pnpm-debug.log* | ||
|
|
||
| # local env files | ||
| # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables | ||
| .env | ||
| .env*.local | ||
|
|
||
| # vercel | ||
| .vercel | ||
|
|
||
| # typescript | ||
| *.tsbuildinfo | ||
|
|
||
| # idea files | ||
| .idea |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| # Onlook Admin App | ||
|
|
||
| A lightweight admin dashboard for Onlook, built with the same architecture as the main web client. | ||
|
|
||
| ## Architecture | ||
|
|
||
| - **Next.js 15** (App Router) | ||
| - **tRPC** for type-safe API routes | ||
| - **Drizzle ORM** via shared `@onlook/db` package | ||
| - **Supabase Auth** for authentication | ||
| - **TailwindCSS** for styling | ||
| - **Bun** as package manager | ||
|
|
||
| ## Planned Directory Structure | ||
|
|
||
| ``` | ||
| apps/admin/ | ||
| ├── src/ | ||
| │ ├── app/ | ||
| │ │ ├── layout.tsx # Root layout with providers | ||
| │ │ ├── page.tsx # Homepage/Dashboard | ||
| │ │ └── api/ | ||
| │ │ └── trpc/ | ||
| │ │ └── [trpc]/ | ||
| │ │ └── route.ts # tRPC API handler | ||
| │ ├── server/ | ||
| │ │ └── api/ | ||
| │ │ ├── root.ts # Main tRPC router | ||
| │ │ ├── trpc.ts # tRPC context & procedures | ||
| │ │ └── routers/ # Feature-specific routers | ||
| │ │ └── admin.ts # Admin-specific endpoints | ||
| │ ├── trpc/ | ||
| │ │ ├── react.tsx # Client-side tRPC provider | ||
| │ │ ├── helpers.ts # tRPC configuration helpers | ||
| │ │ └── query-client.ts # React Query client setup | ||
| │ ├── utils/ | ||
| │ │ └── supabase/ | ||
| │ │ ├── server.ts # Server-side Supabase client | ||
| │ │ └── client/ | ||
| │ │ └── index.ts # Browser Supabase client | ||
| │ ├── components/ # Admin UI components | ||
| │ ├── env.ts # Environment validation (via @t3-oss/env-nextjs) | ||
| │ └── styles/ | ||
| │ └── globals.css # Global styles + Tailwind imports | ||
| ├── public/ # Static assets | ||
| ├── package.json # Dependencies & scripts | ||
| ├── tsconfig.json # TypeScript config | ||
| ├── next.config.ts # Next.js configuration | ||
| ├── tailwind.config.ts # Tailwind configuration | ||
| ├── postcss.config.js # PostCSS configuration | ||
| └── .env.local # Local environment variables (gitignored) | ||
| ``` | ||
|
|
||
| ## Shared Packages | ||
|
|
||
| This app reuses existing monorepo packages: | ||
|
|
||
| - `@onlook/db` - Drizzle schema & database client | ||
| - `@onlook/ui` - Shared UI components | ||
| - `@onlook/utility` - Shared utilities | ||
| - `@onlook/constants` - Shared constants | ||
| - `@onlook/typescript` - Shared TypeScript config | ||
| - `@onlook/eslint` - Shared ESLint config | ||
|
|
||
| ## Key Features | ||
|
|
||
| ### tRPC Setup | ||
|
|
||
| Following the same pattern as `apps/web/client`: | ||
|
|
||
| - **Context**: Database connection, Supabase auth, user session | ||
| - **Procedures**: | ||
| - `publicProcedure` - No authentication required | ||
| - `protectedProcedure` - Requires authenticated user | ||
| - `adminProcedure` - Requires admin privileges (uses Supabase service role) | ||
| - **Validation**: Zod schemas for all inputs | ||
| - **Serialization**: SuperJSON for handling dates, etc. | ||
|
|
||
| ### Environment Variables | ||
|
|
||
| Required environment variables (configure in `.env.local`): | ||
|
|
||
| #### Server-side | ||
| ```env | ||
| # Database | ||
| SUPABASE_DATABASE_URL=postgresql://... | ||
| SUPABASE_SERVICE_ROLE_KEY=... | ||
| ``` | ||
|
|
||
| #### Client-side (NEXT_PUBLIC_*) | ||
| ```env | ||
| NEXT_PUBLIC_SITE_URL=http://localhost:3001 | ||
| NEXT_PUBLIC_SUPABASE_URL=... | ||
| NEXT_PUBLIC_SUPABASE_ANON_KEY=... | ||
| ``` | ||
|
|
||
| ### TypeScript Path Aliases | ||
|
|
||
| - `@/*` → `src/*` | ||
| - `~/*` → `src/*` | ||
|
|
||
| ## Scripts | ||
|
|
||
| ```bash | ||
| # Development | ||
| bun dev # Start dev server (default: localhost:3001) | ||
|
|
||
| # Production | ||
| bun build # Build for production | ||
| bun start # Start production server | ||
|
|
||
| # Type checking & linting | ||
| bun typecheck # Run TypeScript type checking | ||
| bun lint # Run ESLint | ||
| bun format # Format code with ESLint --fix | ||
| ``` | ||
|
|
||
| ## Development Workflow | ||
|
|
||
| 1. **Install dependencies**: `bun install` (from repo root) | ||
| 2. **Set up environment**: Copy `.env.local.example` to `.env.local` and fill in values | ||
| 3. **Run dev server**: `bun --filter @onlook/admin dev` | ||
| 4. **Access**: http://localhost:3001 | ||
|
|
||
| ## Authentication | ||
|
|
||
| - Uses Supabase Auth (same setup as main web client) | ||
| - Server-side auth: `createClient()` from `@/utils/supabase/server` | ||
| - Client-side auth: `createClient()` from `@/utils/supabase/client` | ||
| - Admin routes should use `adminProcedure` for service role access | ||
|
|
||
| ## Deployment Considerations | ||
|
|
||
| ### As Git Submodule (Separate Private Repo) | ||
|
|
||
| This admin app is designed to be extracted into a separate private repository and included as a git submodule: | ||
|
|
||
| ```bash | ||
| # In a new private repo | ||
| git init | ||
| git remote add origin <private-repo-url> | ||
|
|
||
| # Copy apps/admin/* to the new repo | ||
| # Commit and push | ||
|
|
||
| # Back in main repo, add as submodule | ||
| git submodule add <private-repo-url> apps/admin | ||
| git commit -m "Add admin app as submodule" | ||
| ``` | ||
|
|
||
| ### Environment Variables | ||
|
|
||
| - Use Vercel/deployment platform environment variables | ||
| - Ensure `SUPABASE_SERVICE_ROLE_KEY` is set (required for admin operations) | ||
| - Set `NEXT_PUBLIC_SITE_URL` to production URL | ||
|
|
||
| ### Database Access | ||
|
|
||
| - Reuses the same Supabase database as main app via `@onlook/db` | ||
| - Admin routes have elevated permissions via service role key | ||
| - Consider implementing additional RBAC checks in tRPC procedures | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| - **Admin procedures**: Always verify user permissions before granting admin access | ||
| - **Service role key**: Never expose to client, only use in `adminProcedure` | ||
| - **RLS policies**: Admin client bypasses RLS, so implement checks in application layer | ||
| - **CORS**: Configure appropriately if admin is on separate domain | ||
|
|
||
| ## Next Steps | ||
|
|
||
| 1. ✅ Create directory structure | ||
| 2. ✅ Add README with plan | ||
| 3. ⬜ Set up package.json with dependencies | ||
| 4. ⬜ Configure Next.js & TypeScript | ||
| 5. ⬜ Set up tRPC router structure | ||
| 6. ⬜ Create environment configuration | ||
| 7. ⬜ Build basic layout & auth flow | ||
| 8. ⬜ Add admin-specific routes/features | ||
| 9. ⬜ Extract to separate private repo | ||
| 10. ⬜ Configure as git submodule | ||
|
|
||
| ## Contributing | ||
|
|
||
| This is an internal admin tool. Follow the same code standards as the main web client: | ||
|
|
||
| - Use Server Components by default | ||
| - Add `use client` only when needed (events, state, browser APIs) | ||
| - Validate all inputs with Zod | ||
| - Export new tRPC routers in `src/server/api/root.ts` | ||
| - Use path aliases (`@/*` or `~/*`) | ||
|
|
||
| ## Questions? | ||
|
|
||
| Refer to the main web client (`apps/web/client`) for examples of: | ||
| - tRPC router patterns | ||
| - Supabase auth setup | ||
| - Next.js App Router usage | ||
| - Component patterns |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import baseConfig from "@onlook/eslint/base"; | ||
| import nextjsConfig, { restrictEnvAccess } from "@onlook/eslint/nextjs"; | ||
| import reactConfig from "@onlook/eslint/react"; | ||
|
|
||
| /** @type {import('typescript-eslint').Config} */ | ||
| export default [ | ||
| { | ||
| ignores: [".next/**"], | ||
| }, | ||
| ...baseConfig, | ||
| ...reactConfig, | ||
| ...nextjsConfig, | ||
| ...restrictEnvAccess, | ||
| ]; |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { NextConfig } from 'next'; | ||
| import path from 'node:path'; | ||
| import './src/env'; | ||
|
|
||
| const nextConfig: NextConfig = { | ||
| devIndicators: false, | ||
| eslint: { | ||
| ignoreDuringBuilds: true, | ||
| }, | ||
| }; | ||
|
|
||
| if (process.env.NODE_ENV === 'development') { | ||
| nextConfig.outputFileTracingRoot = path.join(__dirname, '../../..'); | ||
| } | ||
|
|
||
| export default nextConfig; |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| { | ||
| "name": "@onlook/admin", | ||
| "version": "0.1.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "next dev --port 3001", | ||
| "build": "next build", | ||
| "start": "next start --port 3001", | ||
| "typecheck": "tsc --noEmit --project tsconfig.json 2>&1 | grep -v 'web/client' || exit 0", | ||
| "lint": "eslint . --max-warnings 0", | ||
| "format": "eslint --fix ." | ||
| }, | ||
| "dependencies": { | ||
| "@onlook/db": "*", | ||
| "@onlook/ui": "*", | ||
| "@onlook/utility": "*", | ||
| "@supabase/ssr": "^0.6.1", | ||
| "@supabase/supabase-js": "^2.45.4", | ||
| "@t3-oss/env-nextjs": "^0.12.0", | ||
| "@tanstack/react-query": "^5.69.0", | ||
| "@trpc/client": "^11.0.0", | ||
| "@trpc/react-query": "^11.0.0", | ||
| "@trpc/server": "^11.0.0", | ||
| "next": ">=15.5.3", | ||
| "react": "^19.0.0", | ||
| "react-dom": "^19.0.0", | ||
| "server-only": "^0.0.1", | ||
| "superjson": "^2.2.1", | ||
| "zod": "^4.1.3" | ||
| }, | ||
| "devDependencies": { | ||
| "@onlook/eslint": "*", | ||
| "@onlook/typescript": "*", | ||
| "@tailwindcss/postcss": "^4.0.15", | ||
| "@types/node": "^20.14.10", | ||
| "@types/react": "^19.0.0", | ||
| "@types/react-dom": "^19.0.0", | ||
| "eslint": "^9.0.0", | ||
| "postcss": "^8.5.3", | ||
| "tailwindcss": "^4.0.15", | ||
| "typescript": "^5.5.4" | ||
| } | ||
| } | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export default { | ||
| plugins: { | ||
| '@tailwindcss/postcss': {}, | ||
| }, | ||
| }; |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { fetchRequestHandler } from '@trpc/server/adapters/fetch'; | ||
| import { type NextRequest } from 'next/server'; | ||
| import { env } from '~/env'; | ||
| import { appRouter } from '~/server/api/root'; | ||
| import { createTRPCContext } from '~/server/api/trpc'; | ||
|
|
||
| /** | ||
| * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when | ||
| * handling a HTTP request (e.g. when you make requests from Client Components). | ||
| */ | ||
| const createContext = async (req: NextRequest) => { | ||
| return createTRPCContext({ | ||
| headers: req.headers, | ||
| }); | ||
| }; | ||
|
|
||
| const handler = (req: NextRequest) => | ||
| fetchRequestHandler({ | ||
| endpoint: '/api/trpc', | ||
| req, | ||
| router: appRouter, | ||
| createContext: () => createContext(req), | ||
| onError: | ||
| env.NODE_ENV === 'development' | ||
| ? ({ path, error }) => { | ||
| console.error(`❌ tRPC failed on ${path ?? '<no-path>'}: ${error.message}`); | ||
| } | ||
| : undefined, | ||
| }); | ||
|
|
||
| export { handler as GET, handler as POST }; |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { DeploymentsList } from '@/components/deployments/deployments-list'; | ||
|
|
||
| export default function DeploymentsPage() { | ||
| return ( | ||
| <div className="bg-background"> | ||
| <div className="container mx-auto px-4 py-8 space-y-8"> | ||
| <div> | ||
| <h1 className="text-4xl font-bold tracking-tight"> | ||
| Deployments | ||
| </h1> | ||
| <p className="mt-2 text-muted-foreground"> | ||
| View and manage all project deployments | ||
| </p> | ||
| </div> | ||
| <DeploymentsList /> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the typecheck script filter.
The typecheck script filters out errors containing
'web/client', which appears to be copied from another package and doesn't apply to the admin app. This could inadvertently hide legitimate TypeScript errors.Apply this diff to remove the incorrect filter:
📝 Committable suggestion
🤖 Prompt for AI Agents