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 statementsprintWidth: 90- Wrap lines at 90 characters (NOT 80 or 120)singleQuote: false- Use double quotes for stringsendOfLine: "lf"- Use Unix-style line endings (\n)trailingComma: "all"- Add trailing commas wherever possibleprettier-plugin-organize-imports- Auto-organize imports by typeprettier-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"- Allowanytype 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 filesreact-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 optionstarget: "ES2022"- Compile to ES2022 JavaScriptmodule: "ESNext"- Use ESNext module syntaxmoduleResolution: "Bundler"- Use bundler resolution for Vite/TanStackjsx: "react-jsx"- Use React 17+ JSX transformpaths: { "~/*": ["./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 indentationfix-only = true- Auto-fix issues without showing unfixable errorsshow-fixes = true- Show what was fixedselect = [...]- Enable specific linter rules:E,W- pycodestyle style enforcementF- pyflakes error detectionI- isort import sortingB- flake8-bugbear bug detectionC4- flake8-comprehensions list/dict comprehension improvementsUP- 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 definitionspython_version = "3.11"- Target Python 3.11+ (projects use 3.12+)strict_optional: true- Strict checking of Optional typeswarn_return_any: true- Warn when returning Any from typed functionswarn_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:
- Every table includes a
tenant_idoraccount_idfield - Every query filters by tenant ID
- Row Level Security (RLS) policies enforce tenant boundaries
- 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
- Frontend Template: cvi-template - TanStack Start + React 19 + Drizzle
- Backend Template: cvi-backend-template - FastAPI + SQLModel + PostgreSQL
- Prettier Docs: https://prettier.io/docs/en/configuration.html
- ESLint Docs: https://eslint.org/docs/latest/use/configure/
- Ruff Docs: https://docs.astral.sh/ruff/
- Drizzle ORM: https://orm.drizzle.team/docs/overview
- TanStack Start: https://tanstack.com/router/latest/docs/framework/react/start/overview