Backend building
Backend building that grafts tRPC + Drizzle ORM + Hono onto an existing webapp-building frontend. Supports incremental features (db, auth). Use when the user needs a backend, API, database, server, authentication, or wants to add tRPC/Drizzle to their webapp-building project. Requires webapp-building first.From its SKILL.md
npx -y skills add serejaris/kimi-skills --skill backend-buildingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
13.3 KB, ~3.3k tokens by cl100k_base, as published. Nobody here has run it
Backend Building
Stack: tRPC + Drizzle ORM + Hono + MySQL + OAuth 2.0
A backend-only skill that grafts onto an existing webapp-building project. It adds api/, contracts/ directories and optionally db/ — but never replaces or modifies existing frontend files.
Prerequisite: An existing project created by webapp-building.
Features
Features can be installed incrementally. Base infrastructure (Hono server, tRPC, contracts) is always installed automatically on first run.
| Feature | What it provides | Dependencies |
|---|---|---|
db | Drizzle ORM + MySQL — adds db/, api/queries/connection.ts, drizzle.config.ts | — |
auth | Kimi OAuth + user management — adds api/kimi/, Login page, useAuth, AuthLayout | requires db (auto-included) |
Default: init.sh "App" with no --features → defaults to auth (= db + auth), preserving backward compat.
Workflows
Frontend-first (recommended when UI is already built):
webapp-buildinginit → develop UI pages and componentsbackend-buildinggraft (this skill) — auto-wires tRPC providers and routes- Verify with
npm run check, then add tRPC routers, database tables, wire frontend to API
Full-stack from scratch (recommended when backend is needed immediately):
webapp-buildinginit → immediately graftbackend-building- Verify with
npm run check - Develop frontend and backend together
Incremental features (add capabilities over time):
- Start with
--features dbfor database only - Later add auth:
init.sh "App" --features auth
Quick Start
1. Initialize Frontend First (webapp-building)
bash /app/.agents/skills/webapp-building/scripts/init-webapp.sh "My App"
cd /mnt/agents/output/app
2. Graft Backend
# Full stack with auth (default, same as before):
bash /app/.agents/skills/backend-building/scripts/init.sh "My App"
# Database only (no auth):
bash /app/.agents/skills/backend-building/scripts/init.sh "My App" --features db
# Add auth later:
bash /app/.agents/skills/backend-building/scripts/init.sh "My App" --features auth
What this does (base, always on first run):
- Copies
api/,contracts/into the project - Patches
vite.config.tsin-place (adds@contractsalias,envDir,build.outDir) - Adds
tsconfig.server.jsonand merges@contracts/*path into existing tsconfigs - Merges
package.json(adds backend deps and scripts) - Generates
.envwith portal credentials - Runs
npm install
Additional per feature:
- db: Adds
db/directory,drizzle.config.ts, database connection,DATABASE_URLenv var, anddb/seed.ts(scaffold for seeding — run withnpx tsx db/seed.ts). Do not overwrite the generatedapi/queries/connection.ts,drizzle.config.ts, or.env— they are complete and correct. Only add your tables todb/schema.ts - auth: Adds
api/kimi/, auth router, client patches (Login, useAuth, AuthLayout, TRPCProvider), auto-wires Login/NotFound routes intoApp.tsx
3. Verify Auto-Wiring (see below)
4. Database Setup (if db or auth feature installed)
npm run db:push # sync schema to database (recommended for development)
5. Development
npm run dev
Start development server with HMR at http://localhost:3000
Post-Init Wiring
On first run, init.sh auto-wires TRPCProvider into src/main.tsx. When auth feature is installed, it also adds Login/NotFound routes to src/App.tsx. Check the init output:
- "Auto-wired" — no action needed, proceed to verification
- "Wiring required" — complete the listed steps manually (see Post-Init Wiring for details)
If manual wiring is needed, it typically means:
- Add
import { TRPCProvider } from "@/providers/trpc"tosrc/main.tsx - Wrap the content inside
<BrowserRouter>with<TRPCProvider> - Add Login and NotFound routes to
src/App.tsx
Verification
After init (and manual wiring if needed), verify everything works:
- Run
npm run check— must pass with zero type errors - Run
npm run dev— server should start at http://localhost:3000 - If any step fails, read the error and fix before proceeding
Common Commands
| Command | Description | Requires |
|---|---|---|
npm run dev | Start development server with HMR at http://localhost:3000 | base |
npm run build | Build for production (outputs to dist/) | base |
npm start | Start production server | base |
npm run check | Type-check all TypeScript files | base |
npm run format | Format code with Prettier | base |
npm run test | Run tests with Vitest | base |
npm run db:push | Sync schema to DB during development (recommended) | db |
npm run db:generate | Generate migration SQL for production deployment | db |
npm run db:migrate | Apply pending migration files to the database | db |
Stack Overview
Backend (added by this skill)
- Hono + tRPC 11.x
- End-to-end type safety
- Public query procedure (base); + authenticated/admin procedures (auth feature)
Database (db feature)
- Drizzle ORM with MySQL
- Lazy
getDb()connection, ready to use - Type-safe queries (Guide)
- Schema migrations
Authentication (auth feature)
- OAuth 2.0 (Details)
- JWT sessions, admin role support
Frontend (from webapp-building, untouched)
- React 19 + TypeScript + Vite (HMR)
- Tailwind CSS + shadcn/ui components
- Dark/light mode
Common Mistakes
- Don't hand-write TypeScript interfaces for DB entities — use
typeof table.$inferSelectfromdb/schema.tsto keep types aligned with superjson's Date serialization via tRPC. Hand-writtencreatedAt: stringwill conflict with the actualDateobjects delivered by superjson - Don't write raw SQL — always use Drizzle's type-safe query API (
getDb().query.*,getDb().select(),getDb().insert()) - Don't modify
api/lib/orapi/kimi/— these are framework internals (auth, static file serving). Build on top of them, not inside them - Don't import
api/from frontend code — use@contracts/for types/constants that cross the boundary. The only exception is the type import insrc/providers/trpc.tsx - Don't use
apias the tRPC client name — it'strpc(imported from@/providers/trpc) - Don't skip Zod validation on tRPC inputs — always use
.input(z.object({...}))for mutations and parameterized queries - Don't use
serial()for foreign key columns —serial()createsbigint unsigned auto_increment, and MySQL only allows one auto-increment column per table. FK columns must usebigint("col", { mode: "number", unsigned: true })to match the PK type - Don't use
int()for foreign keys referencingserial()PKs —intis signed 4-byte,serial()isbigint unsigned8-byte. MySQL rejects the type mismatch. Usebigint("col", { mode: "number", unsigned: true }) - NEVER drop tables to fix a failed migration — the database may contain user data. Fix
schema.tsand runnpm run db:pushto sync. See Troubleshooting below - NEVER use
db:push --force— it auto-accepts destructive changes (dropping columns/tables) which can destroy user data - NEVER modify
.envvalues —.envis generated byinit.shwith valid, working credentials. All values (API keys, OAuth URLs, secrets, database URL) are pre-configured and ready to use. Do not overwrite, regenerate, or placeholder-ify them - NEVER overwrite or replace init.sh-generated infrastructure files — files like
api/queries/connection.ts,api/middleware.ts,api/lib/,drizzle.config.ts,src/providers/trpc.tsx, and.envare generated byinit.shwith correct configuration. Read the init output to see what was created. Build on top of these files (e.g., add routers, schemas), but do not rewrite them - Don't change the default port (3000) — the server runs at
http://localhost:3000. Do not change this invite.config.ts,api/boot.ts, or anywhere else
AI Agent Instructions
Required reading before implementing features — read these docs (under docs/) for the features you're working with:
- db feature: Database.md (schema, migrations, connection), tRPC.md (router patterns, procedures, client usage)
- auth feature: Authentication.md (OAuth flow, session handling), tRPC.md
- All features: Development-Guide.md (dev workflow, scripts), Project-Structure.md (file layout)
When building features on this stack:
- Read existing frontend code in
src/to understand the app structure - Design tRPC routers that match the frontend's data needs
- Add DB tables in
db/schema.ts, then runnpm run db:push(requires db feature) - Create new routers in
api/and register them inapi/router.ts - Use type-safe queries via Drizzle ORM — never raw SQL (requires db feature)
- Frontend components go in
src/using the existing@/alias
When to use which features:
- If the user needs a database but no auth, use
--features db - If they need user login, use
--features auth(includes db automatically) - Default (no
--featuresflag) =auth, which is backward compatible
Key Paths
| Path | What to do |
|---|---|
src/main.tsx | TRPCProvider auto-wired here (verify after init) |
src/App.tsx | Login/NotFound routes auto-wired here (verify after init, auth feature only) |
src/pages/ | Route-level page components (one per route in App.tsx) |
src/sections/ | Visual sections within a page (Hero, Footer, etc.) — from webapp-building templates |
src/components/ | Create new UI components |
api/router.ts | Register new tRPC routers |
api/queries/ | Add query functions for new tables (db feature) |
db/schema.ts | Add new database tables (db feature) |
contracts/ | Shared types/constants (frontend + backend) |
api/lib/ | Framework internals — don't modify |
api/kimi/ | Kimi SDK modules — don't modify (auth feature) |
Full directory tree: Project Structure
Detailed Documentation
- Project Structure - Directory layout and where to put things
- Development Guide - Component development, API patterns, common workflows
- Authentication - OAuth 2.0 implementation details (optional)
- Database Guide - Drizzle ORM configuration, schema design, migrations
- tRPC Best Practices - Router patterns and type safety
Routing (react-router)
This template uses react-router v7.
// Navigation
import { useNavigate } from "react-router";
const navigate = useNavigate();
navigate("/dashboard");
// Current location
import { useLocation } from "react-router";
const location = useLocation();
console.log(location.pathname);
// Route params
import { useParams } from "react-router";
const { id } = useParams<{ id: string }>();
// Links
import { Link } from "react-router";
<Link to="/about">About</Link>
// Route definitions (in App.tsx)
import { Routes, Route } from "react-router";
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users/:id" element={<UserProfile />} />
<Route path="*" element={<NotFound />} />
</Routes>
// BrowserRouter wraps the app in main.tsx
import { BrowserRouter } from "react-router";
<BrowserRouter>
<App />
</BrowserRouter>
Troubleshooting
Port 3000 already in use — Another process is using the port. Kill it with lsof -ti:3000 | xargs kill.
Database connection refused — Check DATABASE_URL in .env is correct and MySQL is running. Run npm run db:push before npm run dev.
OAuth callback fails — The callback URL must be {origin}/api/oauth/callback. Verify VITE_KIMI_AUTH_URL and VITE_APP_ID in .env match the portal app config.
npm run db:migrate fails — NEVER drop tables to recover. MySQL doesn't support transactional DDL, so a failed migration can leave the DB in a partial state. To recover:
- Fix
schema.ts(e.g., correct FK types) - Run
npm run db:push— it introspects the actual DB state and syncs it to your corrected schema - Delete the broken migration file and its entry in
db/migrations/meta/_journal.json - Run
npm run db:generateto create a clean baseline migration
Type errors after adding a new router — Make sure you registered the router in api/router.ts inside appRouter. The AppRouter type is derived from there and propagates to the frontend automatically.
What ships with it: 65 files
116.0 KB alongside SKILL.md, 40 of them executable
docs/
- Authentication.md6.7 KB
- Database.md11.0 KB
- Development-Guide.md6.7 KB
- Post-Init-Wiring.md1.1 KB
- Project-Structure.md6.8 KB
- tRPC.md5.0 KB
scripts/
- init.shruns23.2 KB
- lib/merge-package-json.mjsruns1.1 KB
- lib/merge-schema.mjsruns3.2 KB
- lib/merge-tsconfig.mjsruns2.2 KB
- lib/patch-boot-auth.mjsruns1.5 KB
- lib/patch-env-ts.mjsruns1.2 KB
- lib/patch-router-auth.mjsruns1.4 KB
- lib/patch-vite-config.mjsruns2.9 KB
- lib/wire-app-tsx.mjsruns1.6 KB
- lib/wire-main-tsx.mjsruns1.9 KB
- .prepare-template.shruns217 B
- template/auth/api/auth-router.tsruns725 B
- template/auth/api/context.tsruns572 B
- template/auth/api/kimi/auth.tsruns3.8 KB
- template/auth/api/kimi/platform.tsruns712 B
- template/auth/api/kimi/session.tsruns1.1 KB
- template/auth/api/kimi/types.tsruns307 B
- template/auth/api/lib/cookies.tsruns462 B
- template/auth/api/middleware.tsruns1.1 KB
- template/auth/api/queries/users.tsruns858 B
- template/auth/client-patches/components/AuthLayoutSkeleton.tsx1.6 KB
- template/auth/client-patches/components/AuthLayout.tsx8.8 KB
- template/auth/client-patches/const.tsruns36 B
- template/auth/client-patches/hooks/useAuth.tsruns1.4 KB
- template/auth/client-patches/pages/Login.tsx1.2 KB
- template/auth/client-patches/pages/NotFound.tsx724 B
- template/auth/configs/package.json.feat213 B
- template/auth/contracts/constants.tsruns335 B
- template/auth/contracts/types.tsruns61 B
- template/auth/db/schema.users.tsruns771 B
- template/auth/.env.example816 B
- template/base/api/boot.tsruns1001 B
- template/base/api/context.tsruns311 B
- .gitignore66 B
25 more files not listed here. See all 65 in the repository.