Files
seastem-electronjs/AGENTS.md

5.6 KiB

AGENTS.md - AI Coding Agent Guidelines

Project Overview

TanStack Start fullstack app with Tauri desktop shell.

Layer Tech
Framework TanStack Start (React SSR, file-based routing)
Runtime Bun
Language TypeScript (strict mode)
Styling Tailwind CSS v4
Database PostgreSQL + Drizzle ORM
RPC ORPC (contract-first, type-safe)
Build Vite + Turbo
Linting Biome
Desktop Tauri v2 (optional, see src-tauri/AGENTS.md)

Commands

# Development
bun dev              # Start Tauri + Vite via Turbo
bun dev:vite         # Vite only (localhost:3000)
bun db:studio        # Drizzle Studio

# Build
bun build            # Full build (Vite → compile → Tauri)
bun build:vite       # Vite only (outputs to .output/)

# Code Quality
bun typecheck        # TypeScript check (tsc -b)
bun fix              # Biome auto-fix (format + lint)

# Database
bun db:generate      # Generate migrations from schema
bun db:migrate       # Run migrations
bun db:push          # Push schema changes (dev only)

# Testing (not configured yet)
# When adding tests, use Vitest or Bun test runner:
# bun test path/to/test.ts        # Single file
# bun test -t "pattern"           # By test name

Code Style

Formatting (Biome enforced)

  • Indent: 2 spaces
  • Line endings: LF
  • Quotes: Single 'string'
  • Semicolons: As needed (ASI)
  • Arrow parens: Always (x) => x

Imports

Biome auto-organizes. Order: external → internal (@/*) → type-only imports.

import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'
import { db } from '@/db'
import type { ReactNode } from 'react'

TypeScript

Strict mode with extra checks:

  • noUncheckedIndexedAccess: true - array/object index returns T | undefined
  • noImplicitOverride: true
  • verbatimModuleSyntax: true

Path alias: @/*src/*

Naming

Entity Convention Example
Files (utils) kebab-case utils.ts, db-provider.ts
Files (components) PascalCase NotFound.tsx
Routes TanStack conventions routes/index.tsx, routes/__root.tsx
Components PascalCase arrow functions const MyComponent = () => {}
Functions camelCase handleSubmit
Constants UPPER_SNAKE_CASE MAX_RETRIES
Types/Interfaces PascalCase TodoItem, RouterContext

React Patterns

// Components: arrow functions (Biome enforces)
const MyComponent = ({ title }: { title: string }) => {
  return <div>{title}</div>
}

// Routes: createFileRoute
export const Route = createFileRoute('/')({
  component: Home,
  loader: async ({ context }) => {
    await context.queryClient.ensureQueryData(orpc.todo.list.queryOptions())
  },
})

// Data fetching: TanStack Query
const query = useSuspenseQuery(orpc.todo.list.queryOptions())
const mutation = useMutation(orpc.todo.create.mutationOptions())

ORPC Pattern (Contract-First RPC)

  1. Define contract (src/orpc/contracts/my-feature.ts):
import { oc } from '@orpc/contract'
import { z } from 'zod'

export const get = oc.input(z.object({ id: z.uuid() })).output(schema)
export const create = oc.input(insertSchema).output(schema)
  1. Implement handler (src/orpc/handlers/my-feature.ts):
import { os } from '@/orpc/server'
import { dbProvider } from '@/orpc/middlewares'

export const get = os.myFeature.get
  .use(dbProvider)
  .handler(async ({ context, input }) => {
    return await context.db.query.myTable.findFirst(...)
  })
  1. Register in contract.ts and router.ts
  2. Use in components via orpc.myFeature.get.queryOptions()

Drizzle Schema

import { sql } from 'drizzle-orm'
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'

export const myTable = pgTable('my_table', {
  id: uuid('id').primaryKey().default(sql`uuidv7()`),
  name: text('name').notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow().$onUpdateFn(() => new Date()),
})

Environment Variables

  • Server: no prefix (e.g., DATABASE_URL)
  • Client: VITE_ prefix required
  • Validated via @t3-oss/env-core in src/env.ts

Directory Structure

src/
├── components/          # Reusable React components
├── db/
│   ├── schema/         # Drizzle schema definitions
│   └── index.ts        # Database instance
├── integrations/       # TanStack Query/Router setup
├── lib/                # Utility functions
├── orpc/
│   ├── contracts/      # Input/output schemas
│   ├── handlers/       # Server procedure implementations
│   ├── middlewares/    # Middleware (e.g., dbProvider)
│   ├── contract.ts     # Contract aggregation
│   ├── router.ts       # Router composition
│   └── client.ts       # Isomorphic client
├── routes/             # File-based routes
│   ├── __root.tsx      # Root layout
│   └── api/rpc.$.ts    # ORPC HTTP endpoint
└── env.ts              # Environment validation

Critical Rules

  • DO NOT edit src/routeTree.gen.ts (auto-generated)
  • DO NOT commit .env files
  • MUST run bun fix before commits
  • MUST use @/* path alias (not relative imports)
  • MUST use React Compiler (no manual memoization needed)
  • MUST use Readonly<T> for immutable props

Git Workflow

  1. Make changes following style guide
  2. Run bun fix (format + lint)
  3. Run bun typecheck (type safety)
  4. Test with bun dev
  5. Commit with descriptive message