Claude
Skills
Sign in
Back

fullstack-vite-convex

Included with Lifetime
$97 forever

Full-stack web development with Convex + Vite React. TDD-driven, strict TypeScript, fully autonomous. Covers scaffolding, schema design, backend functions, frontend components, testing, styling, and deployment. Use when building web apps, sites, or frontend tasks from scratch or adding features to Convex projects. Triggers on: 'build a web app', 'create a site', 'Convex app', 'React app', 'full-stack', 'frontend', 'build me an app', any request to create or modify a Convex + Vite React application.

Design

What this skill does


# Full-Stack Web Development — Convex + Vite React

Build production-quality Convex + Vite React applications with **test-driven development** and **strict TypeScript**. Handle the entire stack end-to-end: scaffolding, tests, database, backend, frontend, styling, starting servers, verifying the build, running tests, and delivering a running app.

## Core Principles

### 1. Autonomy Is Non-Negotiable

- **NEVER** tell the user to run commands. YOU run them.
- **NEVER** say "you can now run..." or "please execute...". Just do it.
- Scaffold the project, install deps, write all code, start all servers, seed data, run tests, verify the build — all yourself.
- The user should receive a **working, running, tested application** with a URL they can open.
- If something fails, fix it yourself. Don't report errors without attempting resolution.

### 2. TDD By Default

- **Write tests BEFORE implementation.** Always.
- Backend: write Convex function tests before writing the functions.
- Frontend: write component tests before writing the components.
- Every feature gets a test. No exceptions.
- Tests must pass before moving to the next phase. Run them yourself and fix failures.

### 3. Strict TypeScript — Zero Tolerance

- All code uses strict TypeScript. No `any`. No `as unknown as X` hacks. No `@ts-ignore`.
- Enable all strict flags in `tsconfig.json` — `strict: true`, `noUncheckedIndexedAccess: true`, `noImplicitReturns: true`, `noFallthroughCasesInSwitch: true`, `exactOptionalPropertyTypes: true`.
- Every function has explicit return types. Every variable has a type or is inferable.
- Use `Id<"tableName">` for Convex IDs, never `string`.
- Use discriminated unions with `as const` for status/kind fields.
- `npx tsc --noEmit` must produce **0 errors** before you deliver. Run it and fix every error.

## Documentation Lookup

Always use Context7 MCP tools (`resolve-library-id` then `query-docs`) when you need library, API, or framework documentation. Do NOT ask the user. Proactively use Context7 whenever the task involves a library, framework, or API you are not fully confident about. This includes Convex, React, Vite, Tailwind, Vitest, any npm package, or third-party API.

---

## Workflow

### Phase 1: Scaffold & Setup (Local by Default)

Scaffold the project yourself — no Convex account or cloud needed:

```bash
npm create convex@latest -- -t react-vite my-app && cd my-app && npm install
```

Install ALL deps in one shot — testing, styling, utilities:

```bash
npm install lucide-react && npm install -D tailwindcss @tailwindcss/vite vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom @types/node
```

Project structure:
```
my-app/
  convex/                # Backend
    _generated/          # Auto-generated (never edit)
    schema.ts
    tsconfig.json
  src/
    components/          # React components
    hooks/               # Custom hooks
    lib/                 # Utilities, types, constants
    __tests__/           # Frontend tests
    App.tsx
    main.tsx
  tests/                 # Backend/integration tests
  package.json
  tsconfig.json
  vite.config.ts
  vitest.config.ts
```

### Phase 2: Configure Strict TypeScript

Set up `tsconfig.json` with maximum strictness:

```json
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "isolatedModules": true,
    "resolveJsonModule": true,
    "allowImportingTsExtensions": true,
    "noEmit": true
  },
  "include": ["src/**/*", "tests/**/*", "vite.config.ts", "vitest.config.ts"],
  "exclude": ["convex"]
}
```

Set up `vitest.config.ts`:

```typescript
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  test: {
    environment: "jsdom",
    globals: true,
    setupFiles: ["./src/test-setup.ts"],
    include: ["src/**/*.test.{ts,tsx}", "tests/**/*.test.ts"],
    coverage: {
      provider: "v8",
      reporter: ["text", "lcov"],
    },
  },
});
```

Create `src/test-setup.ts`:

```typescript
import "@testing-library/jest-dom/vitest";
```

Add test scripts to `package.json`:

```json
{
  "scripts": {
    "test": "vitest run",
    "test:watch": "vitest",
    "test:coverage": "vitest run --coverage",
    "typecheck": "tsc --noEmit",
    "lint": "tsc --noEmit && vitest run"
  }
}
```

### Phase 3: Schema & Types

Define schema in `convex/schema.ts` and export shared types in `src/lib/types.ts`.

Define all data types, constants, and enums upfront. Use discriminated unions for status fields:

```typescript
// src/lib/types.ts
export const BOOKING_STATUS = {
  pending: "pending",
  confirmed: "confirmed",
  cancelled: "cancelled",
} as const;

export type BookingStatus = (typeof BOOKING_STATUS)[keyof typeof BOOKING_STATUS];
```

### Phase 4: Write Tests First (TDD)

**Backend tests** — test Convex function logic (validators, edge cases):

```typescript
// tests/services.test.ts
import { describe, it, expect } from "vitest";

describe("services", () => {
  it("should validate service has required fields", () => {
    const service = {
      name: "Consultation",
      description: "1-on-1 session",
      duration: 60,
      price: 150,
      category: "consulting",
      available: true,
      icon: "phone",
    };
    expect(service.name).toBeDefined();
    expect(service.price).toBeGreaterThan(0);
    expect(service.duration).toBeGreaterThan(0);
  });

  it("should reject invalid price", () => {
    expect(() => {
      if (-1 <= 0) throw new Error("Price must be positive");
    }).toThrow("Price must be positive");
  });
});
```

**Frontend component tests** — test rendering, user interactions:

```typescript
// src/__tests__/ServiceCard.test.tsx
import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import { ServiceCard } from "../components/ServiceCard";

describe("ServiceCard", () => {
  const mockService = {
    _id: "test-id" as any,
    _creationTime: Date.now(),
    name: "Consultation",
    description: "1-on-1 session",
    duration: 60,
    price: 150,
    category: "consulting",
    available: true,
    icon: "phone",
  };

  it("renders service name and price", () => {
    render(<ServiceCard service={mockService} onBook={() => {}} />);
    expect(screen.getByText("Consultation")).toBeInTheDocument();
    expect(screen.getByText(/\$150/)).toBeInTheDocument();
  });

  it("shows unavailable state when not available", () => {
    render(<ServiceCard service={{ ...mockService, available: false }} onBook={() => {}} />);
    expect(screen.getByText(/unavailable/i)).toBeInTheDocument();
  });
});
```

**Run tests — they should fail (red phase):**

```bash
npx vitest run
```

### Phase 5: Implement Code (Green Phase)

Now write the implementation to make tests pass:

1. **Backend functions** — queries, mutations, actions, seed data in `convex/`
2. **Frontend components** — each in its own file with typed props interfaces
3. **Hooks** — custom hooks for shared logic
4. **Pages** — route-level components composing smaller pieces

**Run tests again — they must pass (green phase):**

```bash
npx vitest run
```

Fix any failures before proceeding.

### Phase 6: Refactor

With passing tests as a safety net, refactor:
- Extract shared logic into hooks/utilities
- Remove duplication
- Improve component composition
- Tighten types

**Run tests after every refactor to ensure nothing broke.**

### Phase 7: Start Servers & Verify

Start the **local** Convex backend:

```bash
npx convex dev --local &
```

Start the Vite dev serv

Related in Design