Claude-skill-registry Feature Structure

How to organize features in LivestockAI

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/feature-structure" ~/.claude/skills/majiayu000-claude-skill-registry-feature-structure && rm -rf "$T"
manifest: skills/data/feature-structure/SKILL.md
source content

Feature Structure

Each major feature in LivestockAI has its own directory in

app/features/
.

Directory Layout

app/features/batches/
├── server.ts        # Server functions (createServerFn)
├── service.ts       # Pure business logic
├── repository.ts    # Database operations
├── types.ts         # TypeScript interfaces
├── constants.ts     # Feature constants
└── index.ts         # Public exports

File Purposes

server.ts

Server functions that handle auth, validation, and orchestration:

export const createBatchFn = createServerFn({ method: 'POST' })
  .inputValidator(schema)
  .handler(async ({ data }) => {
    const session = await requireAuth()
    const error = validateBatchData(data)
    if (error) throw new AppError('VALIDATION_ERROR')
    return insertBatch(db, data)
  })

service.ts

Pure business logic functions (no side effects):

export function calculateFCR(
  feedKg: number,
  weightGain: number,
): number | null {
  if (feedKg <= 0 || weightGain <= 0) return null
  return Math.round((feedKg / weightGain) * 100) / 100
}

export function validateBatchData(data: CreateBatchData): string | null {
  if (data.initialQuantity <= 0) return 'Quantity must be positive'
  return null
}

repository.ts

Database operations only:

export async function insertBatch(
  db: Kysely<Database>,
  data: BatchInsert,
): Promise<string> {
  const result = await db
    .insertInto('batches')
    .values(data)
    .returning('id')
    .executeTakeFirstOrThrow()
  return result.id
}

types.ts

TypeScript interfaces:

export interface CreateBatchData {
  farmId: string
  species: string
  initialQuantity: number
  costPerUnit: number
}

export interface BatchStats {
  mortality: { rate: number; total: number }
  feed: { totalKg: number; fcr: number | null }
  sales: { totalRevenue: number }
}

index.ts

Public exports:

export { createBatchFn, getBatchesFn } from './server'
export { calculateFCR, validateBatchData } from './service'
export type { CreateBatchData, BatchStats } from './types'

Component Organization

UI components go in

app/components/
:

app/components/
├── ui/              # Base components (shadcn/ui)
├── dialogs/         # Create/edit modal dialogs
├── layout/          # Layout components
└── batches/         # Feature-specific components
    ├── batch-columns.tsx
    ├── batch-filters.tsx
    └── batches-skeleton.tsx

Route Organization

Routes go in

app/routes/
:

app/routes/
├── _auth/           # Protected routes
│   ├── batches/
│   │   ├── index.tsx
│   │   └── $batchId.tsx
│   └── dashboard.tsx
└── index.tsx        # Public landing

Related Skills

  • three-layer-architecture
    - Layer responsibilities
  • tanstack-router
    - Route organization
  • tanstack-start
    - Server function patterns