Ultimate AI-Native React/TypeScript Starter Pack implementing Alperen Keleş's "Test, Don't Verify" philosophy.
This starter pack shifts from a focus on implementation details to a focus on observable outcomes. For AI-assisted coding, this is the "Holy Grail." AI is terrible at maintaining complex internal state logic but excellent at writing code that passes a rigorous test suite. By providing a "Test, Don't Verify" foundation, you give the AI a feedback loop where it can fix its own mistakes without human intervention.
- Test Observable Outcomes: Don't test if a function was called; test if the user sees the expected result.
- Contract-First Development: Define Zod schemas before writing code. All data boundaries must be validated.
- AI Self-Correction: The AI can read test failures and fix code without human intervention.
- Type Safety: TypeScript strict mode + Zod schemas = AI-proof validation.
- Next.js 16 (App Router) - Unified server/client boundary
- TypeScript (Strict mode) - Type safety
- Prisma + SQLite - Database/ORM (SQLite is AI-readable)
- Zod - Runtime validation and TypeScript types
- Zustand + Immer - Lightweight state management
- next-safe-action - Type-safe Server Actions with Zod
- Better Auth - Authentication built on Prisma/Zod
- shadcn/ui - Copy-paste components (AI can read/modify source)
- React Hook Form + Zod resolver - Form handling
- TanStack Query - Server state synchronization
- Sonner - Toast notifications (observable outcomes)
- Lucide React - Predictable icon library
- Framer Motion - Declarative animations
- Playwright - E2E testing (observable outcomes)
- Vitest - Integration testing
- @axe-core/playwright - Accessibility testing
- Biome - Fast linting + formatting (replaces ESLint/Prettier)
- ts-reset - Improved TypeScript global types
- zod-to-json-schema - Export schemas for AI tool-calling
- Node.js 18+
- npm or pnpm
- Clone the repository:
git clone <your-repo-url>
cd contract-forge-starter- Install dependencies:
npm install- Set up the database:
# Copy the example env file and adjust as needed
cp .env.example .env
# Set DATABASE_URL in .env (or use default)
# DATABASE_URL="file:./dev.db"
# Generate Prisma client and run migrations
npm run db:generate
npm run db:migrate- Start the development server:
npm run dev├── .cursorrules # AI behavior guidelines
├── prisma/ # Prisma schema and migrations
├── src/
│ ├── app/ # Next.js App Router routes
│ │ └── api/ # API routes (including /dev/db-check)
│ ├── components/ # React components (shadcn/ui)
│ ├── hooks/ # Custom React hooks
│ ├── lib/
│ │ ├── actions/ # Server Actions with Zod validation
│ │ ├── schemas/ # Zod schemas (source of truth)
│ │ ├── queries/ # React Query key factory
│ │ ├── db.ts # Prisma client
│ │ └── auth.ts # Better Auth configuration
│ ├── stores/ # Zustand stores
│ └── __tests__/
│ ├── integration/ # Vitest integration tests
│ └── utils/ # Test utilities
└── tests/
└── e2e/ # Playwright E2E tests
- Define the Contract (Zod schema in
src/lib/schemas/) - Write a Failing Test (Playwright E2E test in
tests/e2e/) - Implement the Server Action (with Zod validation in
src/lib/actions/) - Create the UI Component (using shadcn/ui components)
- Run Quality Checks:
npm run ai:check - Fix Issues: Use the test feedback loop
The .cursorrules file instructs AI agents to:
- Always write tests before implementing features
- Use Zod for all validation
- Run
npm run ai:checkbefore completing tasks - Fix test failures automatically using the feedback loop
# Run all checks (Biome + TypeScript + Vitest + Playwright)
npm run ai:check
# Auto-fix formatting and linting
npm run ai:fix
# Type checking only
npm run type-check
# Run tests
npm test # Vitest
npm run test:e2e # PlaywrightTest what the user sees, not how it's implemented:
test("should create a task", async ({ page }) => {
await page.goto("/");
await page.fill('[data-testid="task-title-input"]', "My Task");
await page.click('[data-testid="task-submit-button"]');
// Test observable outcome: success toast appears
await expect(page.locator('text=Task created successfully')).toBeVisible();
});Test contracts (Zod schemas):
it("should validate task schema", () => {
const result = TaskSchema.safeParse({ title: "ab" }); // Too short
expect(result.success).toBe(false);
});In development, you can inspect the database state via:
GET /api/dev/db-check
This allows AI agents to verify data was saved correctly during test runs.
npm run dev- Start development servernpm run build- Build for productionnpm run lint- Run Biome checksnpm run format- Format code with Biomenpm run type-check- TypeScript type checkingnpm test- Run Vitest testsnpm run test:e2e- Run Playwright E2E testsnpm run ai:check- Run all quality checks (Biome + TypeScript + Vitest + Playwright)npm run ai:fix- Auto-fix formatting/lintingnpm run db:migrate- Run Prisma migrationsnpm run db:studio- Open Prisma Studio
Playwright uses PLAYWRIGHT_DATABASE_URL (defaults to file:./prisma/test.db) and applies migrations during global setup.
To reuse an already running dev server, set PLAYWRIGHT_START_WEB_SERVER=false and PLAYWRIGHT_BASE_URL to the server URL.
See CONTRIBUTING.md for development workflow guidelines.
MIT