Step 2
Project setup
25 min
Project setup
The base for an admin hub is a lean Next.js 16 + TypeScript strict + Tailwind 4. Admin is not a public site, so SEO and i18n are stripped.
1. Create the project
pnpm create next-app admin-platform \
--typescript --tailwind --app --turbopack \
--src-dir --import-alias "@/*"
cd admin-platform
2. Tighten TypeScript
tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true,
"exactOptionalPropertyTypes": true
}
}
noUncheckedIndexedAccess forces undefined into every index access and removes a lot of subtle bugs later.
3. Install shadcn/ui
pnpm dlx shadcn@latest init
pnpm dlx shadcn@latest add button input select table card dialog scroll-area
4. Directory layout
src/
├── app/
│ ├── admin/
│ │ ├── layout.tsx # AuthGuard
│ │ ├── dashboard/
│ │ └── blog/posts/
│ ├── api/
│ └── login/
├── shared/
│ ├── lib/
│ │ ├── db.ts
│ │ ├── auth/
│ │ └── audit.ts
│ ├── components/
│ │ ├── AdminResourceTable.tsx
│ │ ├── AuthGuard.tsx
│ │ └── Sidebar.tsx
│ └── constants/routes.ts
5. Environment variables
BLOG_DB_HOST=localhost
BLOG_DB_PORT=5435
BLOG_DB_NAME=blog
BLOG_DB_USER=postgres
BLOG_DB_PASSWORD=postgres
MARKET_DB_HOST=localhost
MARKET_DB_PORT=5433
# ...
KAKAO_CLIENT_ID=...
KAKAO_CLIENT_SECRET=...
JWT_SECRET_KEY=change-me-32-bytes
SESSION_EXPIRES_IN=86400
ADMIN_ALLOWED_EMAILS=admin@example.com
Domain-prefixed names make .env readable later.
6. Dev server
pnpm dev
Visit http://localhost:3000. We will replace the default page with /login and /admin/dashboard in the next steps.
Closing
Admin apps have more visual freedom than public sites. Staying with shadcn defaults or stacking on top of Radix primitives both work. What matters is "every page comes from the same component drawer" — the payoff lands around the third or fourth page.
Next
- 03-multiple-pg-pools