Files
gh-greyhaven-ai-claude-code…/skills/code-style/REFERENCE.md
2025-11-29 18:29:15 +08:00

18 KiB

Technical Reference

Complete configuration files and detailed technical information for Grey Haven coding standards.

TypeScript/React Configuration Files

.prettierrc

Complete Prettier configuration from cvi-template:

{
  "tabWidth": 2,
  "semi": true,
  "printWidth": 90,
  "singleQuote": false,
  "endOfLine": "lf",
  "trailingComma": "all",
  "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-tailwindcss"]
}

Field Explanations:

  • tabWidth: 2 - Use 2 spaces for indentation (NOT 4)
  • semi: true - Always add semicolons at the end of statements
  • printWidth: 90 - Wrap lines at 90 characters (NOT 80 or 120)
  • singleQuote: false - Use double quotes for strings
  • endOfLine: "lf" - Use Unix-style line endings (\n)
  • trailingComma: "all" - Add trailing commas wherever possible
  • prettier-plugin-organize-imports - Auto-organize imports by type
  • prettier-plugin-tailwindcss - Auto-sort Tailwind CSS classes

.eslintrc

Complete ESLint configuration from cvi-template:

{
  "root": true,
  "env": { "browser": true, "es2020": true },
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react-hooks/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": ["react-refresh"],
  "rules": {
    "react-hooks/exhaustive-deps": "off",
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/no-unused-vars": "off",
    "no-unused-vars": "off",
    "react-refresh/only-export-components": "off"
  }
}

Rule Explanations:

  • react-hooks/exhaustive-deps: "off" - Don't enforce exhaustive deps in useEffect (manage manually)
  • @typescript-eslint/no-explicit-any: "off" - Allow any type for flexibility
  • @typescript-eslint/no-unused-vars: "off" - Don't error on unused variables (clean up manually)
  • no-unused-vars: "off" - Same as above for non-TypeScript files
  • react-refresh/only-export-components: "off" - Allow exporting non-components from module

Philosophy: Grey Haven takes a pragmatic approach over pedantic enforcement. The codebase values developer velocity and allows any types, unused variables, and manual dependency management when appropriate.

tsconfig.json

Complete TypeScript configuration from cvi-template:

{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "esModuleInterop": true,
    "isolatedModules": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "allowJs": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["./src/*"]
    },
    "noEmit": true,
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", ".wrangler", ".output"]
}

Key Settings:

  • strict: true - Enable all strict type checking options
  • target: "ES2022" - Compile to ES2022 JavaScript
  • module: "ESNext" - Use ESNext module syntax
  • moduleResolution: "Bundler" - Use bundler resolution for Vite/TanStack
  • jsx: "react-jsx" - Use React 17+ JSX transform
  • paths: { "~/*": ["./src/*"] } - Path alias for imports (e.g., import { foo } from "~/lib/utils")
  • noEmit: true - Don't emit compiled files (Vite handles this)

package.json Scripts

Standard scripts from cvi-template:

{
  "scripts": {
    "dev": "vinxi dev",
    "build": "vinxi build",
    "start": "vinxi start",
    "lint": "eslint .",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "db:generate": "drizzle-kit generate",
    "db:migrate": "drizzle-kit migrate",
    "db:push": "drizzle-kit push",
    "db:studio": "drizzle-kit studio",
    "prepare": "husky"
  }
}

Python/FastAPI Configuration Files

pyproject.toml (Ruff)

Complete Ruff configuration from cvi-backend-template:

[tool.ruff]
fix-only = true
show-fixes = true
indent-width = 4
line-length = 130  # NOT 80 or 88!

[tool.ruff.lint]
select = [
    "E",   # pycodestyle errors
    "W",   # pycodestyle warnings
    "F",   # pyflakes
    "I",   # isort
    "B",   # flake8-bugbear
    "C4",  # flake8-comprehensions
    "UP",  # pyupgrade
]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "lf"

[tool.ruff.lint.isort]
known-first-party = ["app"]

Field Explanations:

  • line-length = 130 - Wrap lines at 130 characters (CRITICAL: NOT 80 or 88!)
  • indent-width = 4 - Use 4 spaces for indentation
  • fix-only = true - Auto-fix issues without showing unfixable errors
  • show-fixes = true - Show what was fixed
  • select = [...] - Enable specific linter rules:
    • E, W - pycodestyle style enforcement
    • F - pyflakes error detection
    • I - isort import sorting
    • B - flake8-bugbear bug detection
    • C4 - flake8-comprehensions list/dict comprehension improvements
    • UP - pyupgrade automatic Python version upgrades

pyproject.toml (MyPy)

Complete MyPy configuration from cvi-backend-template:

[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
check_untyped_defs = true
ignore_missing_imports = false
strict_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true

Key Settings:

  • disallow_untyped_defs: true - CRITICAL: Require type hints on all function definitions
  • python_version = "3.11" - Target Python 3.11+ (projects use 3.12+)
  • strict_optional: true - Strict checking of Optional types
  • warn_return_any: true - Warn when returning Any from typed functions
  • warn_unused_configs: true - Warn about unused mypy config

Philosophy: Type hints are required in Grey Haven Python projects. Unlike TypeScript's relaxed rules, Python enforces strict typing.

pyproject.toml (Pytest)

Complete pytest configuration from cvi-backend-template:

[tool.pytest.ini_options]
pythonpath = ["."]
asyncio_mode = "auto"
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
    "unit: Unit tests (fast, isolated, mocked)",
    "integration: Integration tests (database, external services)",
    "e2e: End-to-end tests (full system)",
    "benchmark: Performance benchmark tests",
    "slow: Tests that take > 1 second",
]
addopts = [
    "-ra",  # Show summary of all test outcomes
    "--strict-markers",  # Require markers to be registered
    "--strict-config",  # Raise on config warnings
    "--tb=short",  # Shorter traceback format
]

[tool.coverage.run]
source = ["app"]
omit = ["tests/*", "*/migrations/*"]

[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false

Marker Explanations:

  • @pytest.mark.unit - Fast, isolated tests with mocked dependencies
  • @pytest.mark.integration - Tests with database or external services
  • @pytest.mark.e2e - Full system end-to-end tests
  • @pytest.mark.benchmark - Performance measurement tests
  • @pytest.mark.slow - Tests taking over 1 second

Coverage: Aim for >80% code coverage across the project.

Project Structure Details

TypeScript/React Structure (cvi-template)

cvi-template/
├── src/
│   ├── routes/                      # TanStack Router file-based routing
│   │   ├── __root.tsx               # Root layout
│   │   ├── index.tsx                # Homepage (/)
│   │   ├── _authenticated/          # Protected routes (requires auth)
│   │   │   └── dashboard.tsx        # /dashboard
│   │   └── settings/
│   │       ├── index.tsx            # /settings
│   │       └── profile.tsx          # /settings/profile
│   │
│   ├── lib/
│   │   ├── components/              # React components
│   │   │   ├── ui/                  # Shadcn UI components (button, card, etc.)
│   │   │   ├── auth/                # Authentication components
│   │   │   └── layout/              # Layout components (header, sidebar)
│   │   │
│   │   ├── server/                  # Server-side code
│   │   │   ├── schema/              # Drizzle database schemas (snake_case!)
│   │   │   ├── functions/           # TanStack Start server functions
│   │   │   ├── auth.ts              # Better-auth configuration
│   │   │   └── db.ts                # Database connection with RLS
│   │   │
│   │   ├── config/                  # Configuration files
│   │   │   └── env.ts               # Environment validation (@t3-oss/env-core)
│   │   │
│   │   ├── hooks/                   # Custom React hooks (use-* naming)
│   │   ├── utils/                   # Utility functions
│   │   └── types/                   # TypeScript type definitions
│   │
│   ├── clients/                     # API client code
│   ├── data/                        # Zod schemas for data validation
│   ├── middleware/                  # Route middleware and guards
│   ├── services/                    # Business logic services
│   ├── workers/                     # Cloudflare Workers code
│   ├── index.css                    # Global styles (Tailwind)
│   └── router.tsx                   # Router configuration
│
├── public/                          # Static assets
├── tests/                           # Test files
├── .prettierrc                      # Prettier config
├── .eslintrc                        # ESLint config
├── tsconfig.json                    # TypeScript config
├── drizzle.config.ts                # Drizzle ORM config
├── vite.config.ts                   # Vite bundler config
├── wrangler.jsonc                   # Cloudflare Workers config
└── package.json                     # Dependencies and scripts

Python/FastAPI Structure (cvi-backend-template)

cvi-backend-template/
├── app/
│   ├── config/                      # Application configuration
│   │   └── settings.py              # Pydantic settings with env vars
│   │
│   ├── db/                          # Database layer
│   │   ├── models/                  # SQLModel database models (snake_case!)
│   │   │   ├── account.py           # Account model
│   │   │   ├── tenant.py            # Tenant model (multi-tenant)
│   │   │   └── user.py              # User model
│   │   │
│   │   ├── repositories/            # Repository pattern (data access)
│   │   │   ├── base.py              # Base repository
│   │   │   ├── account_repository.py
│   │   │   ├── tenant_repository.py
│   │   │   └── user_repository.py
│   │   │
│   │   ├── db_types.py              # Custom database types (UTCDateTime)
│   │   └── session.py               # Database session management
│   │
│   ├── routers/                     # FastAPI routers (endpoints)
│   │   ├── accounts.py              # /accounts endpoints
│   │   ├── tenants.py               # /tenants endpoints
│   │   └── users.py                 # /users endpoints
│   │
│   ├── services/                    # Business logic layer
│   │   ├── auth_service.py          # Authentication service
│   │   └── billing_service.py       # Billing service
│   │
│   ├── schemas/                     # Pydantic schemas (API contracts)
│   │   ├── accounts.py              # Account request/response schemas
│   │   ├── tenants.py               # Tenant request/response schemas
│   │   └── users.py                 # User request/response schemas
│   │
│   ├── utils/                       # Utility functions
│   │   ├── logging.py               # Logging configuration
│   │   └── security.py              # Security utilities
│   │
│   ├── dependencies.py              # FastAPI dependencies
│   └── main.py                      # FastAPI app entry point
│
├── tests/                           # Test files
│   ├── unit/                        # Unit tests (@pytest.mark.unit)
│   ├── integration/                 # Integration tests (@pytest.mark.integration)
│   ├── e2e/                         # E2E tests (@pytest.mark.e2e)
│   ├── conftest.py                  # Pytest fixtures
│   └── __init__.py
│
├── alembic/                         # Database migrations (if using Alembic)
├── pyproject.toml                   # Python project config (Ruff, MyPy, pytest)
├── requirements.txt                 # Python dependencies
└── .env.example                     # Example environment variables

Database Naming Standards

Field Naming Rules

ALWAYS use snake_case for database columns:

✅ CORRECT          ❌ WRONG
created_at          createdAt
tenant_id           tenantId
email_address       emailAddress
is_active           isActive
first_name          firstName
last_name           lastName
phone_number        phoneNumber
billing_tier        billingTier
max_retries         maxRetries
api_key_hash        apiKeyHash

Table Naming Rules

Use lowercase plural names:

✅ CORRECT          ❌ WRONG
users               User, Users, user
accounts            Account, ACCOUNTS
tenants             Tenant, Tenants
organizations       Organization
subscriptions       Subscription

Index Naming Rules

Use descriptive index names:

Format: {table}_{column}_idx

✅ CORRECT                    ❌ WRONG
user_email_idx                idx_1, email_index
user_tenant_id_idx            tenant_idx
organization_slug_idx         slug

Foreign Key Naming Rules

Reference the parent table:

Format: {parent_table}_{singular}_id

✅ CORRECT          ❌ WRONG
tenant_id           tenant
account_id          acc_id, accountId
organization_id     org_id, orgId
user_id             userId, uid

Multi-Tenant Architecture

Tenant Isolation Levels

Grey Haven projects use row-level tenant isolation:

  1. Every table includes a tenant_id or account_id field
  2. Every query filters by tenant ID
  3. Row Level Security (RLS) policies enforce tenant boundaries
  4. Repository pattern centralizes tenant filtering

RLS Policy Pattern

Standard RLS policy structure:

// TypeScript/Drizzle RLS helper
export const inSameTenant = (tenantIdCol: AnyPgColumn, query: SQL): SQL =>
  sql`${isSameTenant(tenantIdCol)} and (${query})`;

// Apply to table
pgPolicy("table_name_select", {
  for: "select",
  to: "public",
  using: inSameTenant(table.tenantId, sql`true`),
});
-- SQL RLS Policy
CREATE POLICY tenant_isolation_policy ON users
  USING (tenant_id = current_setting('app.tenant_id')::text);

Repository Tenant Filtering

Every repository method filters by tenant:

# Python repository pattern
async def get_by_id(self, id: UUID, tenant_id: UUID) -> Optional[Model]:
    """Get record by ID with tenant isolation."""
    result = await self.session.execute(
        select(self.model)
        .where(self.model.id == id)
        .where(self.model.tenant_id == tenant_id)  # Tenant filter!
    )
    return result.scalar_one_or_none()

Import Organization

TypeScript Import Order

Auto-organized by prettier-plugin-organize-imports:

// 1. External libraries
import { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";

// 2. Internal modules (path alias)
import { Button } from "~/lib/components/ui/button";
import { useAuth } from "~/lib/hooks/use-auth";
import { env } from "~/lib/config/env";

// 3. Relative imports
import { helpers } from "./helpers";

Python Import Order

Auto-organized by Ruff isort:

# 1. Standard library imports
import os
from datetime import datetime
from typing import Optional

# 2. Third-party imports
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import select
from pydantic import BaseModel

# 3. Local imports (app.*)
from app.db.models.user import User
from app.db.repositories.user_repository import UserRepository
from app.schemas.user import UserCreate, UserResponse

Line Length Reasoning

TypeScript: 90 Characters

Why 90?

  • Comfortable reading width on modern displays
  • Allows two editor panes side-by-side
  • Balances readability with code density
  • TailwindCSS classes can be long - 90 gives room
  • Standard 80 is too restrictive for modern development

Python: 130 Characters

Why 130?

  • Type hints can be verbose: Annotated[AccountRepository, Depends(get_account_repository)]
  • Pydantic field definitions: Field(default=None, description="Long description here")
  • Allows descriptive variable names without constant wrapping
  • FastAPI decorators are long: @router.post("/endpoint", response_model=ResponseSchema)
  • PEP 8's 79 is outdated for modern development

Pre-commit Hooks

Both templates use pre-commit hooks for code quality:

TypeScript Pre-commit

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# Run linting
npm run lint

# Run formatting check
npm run format:check

# Run type checking
npx tsc --noEmit

Python Pre-commit

#!/usr/bin/env sh

# Activate virtual environment
source .venv/bin/activate

# Run Ruff formatter
ruff format .

# Run Ruff linter
ruff check --fix .

# Run MyPy type checking
mypy app/

# Run tests
pytest -m "not slow"

Additional Resources