Skip to content

Local Development Workflow ​

This tutorial teaches you how to navigate, develop, and debug within the LenserFight Nx monorepo. By the end, you will have a productive local development environment and understand the codebase architecture.

Prerequisites ​


Project architecture ​

LenserFight is an Nx monorepo with a layered architecture:

lenserfight/
├── apps/                    # Deployable applications
│   ├── web/                 # Main web app (React + Vite, port 3000)
│   ├── arena/               # Public battle arena (port 3001)
│   ├── docs/                # VitePress documentation (port 3002)
│   ├── auth/                # Authentication flows (port 3004)
│   ├── mobile/              # Expo mobile app
│   ├── cli/                 # lf CLI (citty)
│   ├── gateway/             # Trust Gateway service
│   └── worker/              # Background worker (scheduled jobs, async tasks)
├── libs/                    # Shared libraries (layered)
│   ├── features/            # Vertical feature slices (UI + logic)
│   ├── domain/              # Business logic and domain types
│   ├── data/                # Supabase repositories and caching
│   ├── api/                 # API clients
│   ├── ui/                  # Shared UI components
│   ├── shared/              # Cross-cutting utilities
│   ├── types/               # TypeScript type definitions
│   ├── infra/               # Infrastructure adapters
│   ├── adapters/            # Provider adapters
│   ├── providers/           # AI provider integrations
│   ├── plugins/             # Plugin system
│   └── utils/               # Pure utility functions
├── supabase/                # Database schema and migrations
│   ├── migrations/          # Ordered SQL migrations
│   ├── seed.sql             # Seed data
│   └── config.toml          # Supabase local config
├── docs/                    # Documentation source (VitePress srcDir)
├── scripts/                 # Build and maintenance scripts
└── tools/                   # Nx plugins and generators

Layer rules ​

LayerImports fromNever imports from
apps/*libs/*Other apps/*
libs/features/*domain, data, api, ui, shared, typesOther features/*
libs/domain/*types, shareddata, api, features
libs/data/*domain, types, sharedfeatures, api
libs/ui/*types, shareddomain, data, features

Daily development loop ​

1. Start the development server ​

bash
# Web app only (most common)
pnpm nx run web:serve

# Multiple apps in parallel
pnpm nx run-many -t serve -p web,auth,docs

2. Make changes ​

Edit files in libs/ or apps/. Vite HMR picks up changes instantly — no manual restart needed.

3. Run affected checks ​

bash
# Lint only changed projects
pnpm nx affected -t lint

# Test only changed projects
pnpm nx affected -t test

# Build only changed projects
pnpm nx affected -t build

4. Commit with conventional commits ​

bash
git commit -m "feat(agents): add memory persistence toggle"
git commit -m "fix(workflows): resolve edge deletion crash"

Hot reload workflow ​

Vite provides instant HMR for all React components. Changes to .tsx, .ts, .css, and .json files are reflected immediately.

When HMR does not work ​

ScenarioAction
Changed vite.config.tsRestart the dev server
Changed tsconfig.*.jsonRestart the dev server
Changed Supabase typesRun type generation, then restart
Changed .env.localRestart the dev server
Added a new libraryRun pnpm nx reset then restart

Debugging HMR issues ​

bash
# Clear Vite cache
rm -rf node_modules/.vite

# Clear Nx cache
pnpm nx reset

# Full clean restart
rm -rf node_modules/.vite && pnpm nx run web:serve

VS Code ​

Install these extensions:

ExtensionPurpose
Nx ConsoleProject graph, task runner, generator UI
ESLintInline linting
PrettierCode formatting
Tailwind CSS IntelliSenseClass autocomplete
TypeScript NightlyLatest TS features
Error LensInline error display

Recommended settings.json:

json
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "typescript.preferences.importModuleSpecifier": "non-relative",
  "typescript.tsdk": "node_modules/typescript/lib"
}

WebStorm ​

  1. Enable ESLint: Settings → Languages → JavaScript → Code Quality → ESLint → Automatic
  2. Enable Prettier: Settings → Languages → JavaScript → Prettier → On save
  3. Configure TypeScript: Point to the workspace tsconfig.base.json

TypeScript workflow ​

Path aliases ​

The monorepo uses TypeScript path aliases defined in tsconfig.base.json:

typescript
// Instead of relative imports:
import { LensCard } from '../../../libs/ui/src/lib/LensCard'

// Use path aliases:
import { LensCard } from '@lenserfight/ui'

Type checking ​

bash
# Check a specific project
pnpm nx run web:typecheck

# Check all projects
pnpm nx run-many -t typecheck

Generating types from Supabase ​

After changing database schema:

bash
pnpm supabase gen types typescript --local > libs/types/src/lib/database.types.ts

Linting and formatting ​

ESLint ​

bash
# Lint a specific project
pnpm nx run web:lint

# Lint all projects
pnpm nx run-many -t lint

# Auto-fix
pnpm nx run web:lint --fix

Prettier ​

bash
# Format all files
pnpm prettier --write .

# Check formatting
pnpm prettier --check .

Configuration files:

  • .prettierrc — Prettier rules
  • eslint.config.js — ESLint rules (flat config)
  • .prettierignore — Files to skip

Testing ​

bash
# Run tests for a project
pnpm nx run web:test

# Run tests in watch mode
pnpm nx run web:test --watch

# Run all tests
pnpm nx run-many -t test

# Run affected tests only
pnpm nx affected -t test

Test file conventions ​

PatternLocation
Unit tests*.spec.ts / *.spec.tsx next to source
Integration tests*.integration.spec.ts
E2E testsapps/web-e2e/

Debugging ​

Browser DevTools ​

  1. Open http://localhost:3000
  2. Open DevTools (F12)
  3. Use the React DevTools extension for component inspection
  4. Use the Network tab for API call debugging

VS Code debugger ​

Create .vscode/launch.json:

json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug Web App",
      "type": "chrome",
      "request": "launch",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}",
      "sourceMaps": true
    }
  ]
}

Node.js debugging (worker) ​

bash
node --inspect-brk dist/apps/worker/main.js

Then attach VS Code debugger to port 9229.


Nx project graph ​

Visualize dependencies between projects:

bash
pnpm nx graph

This opens an interactive graph in your browser showing how apps and libs depend on each other.


Common patterns ​

Creating a new feature ​

  1. Identify the correct libs/features/ slice (or create a new one)
  2. Add components in src/lib/components/
  3. Add domain logic in libs/domain/ if it is reusable
  4. Add data access in libs/data/ if it touches Supabase
  5. Export public API from the library's index.ts

Adding a new page to the web app ​

  1. Create the page component in the relevant feature library
  2. Add the route in apps/web/src/app/router/
  3. Add navigation link if needed

Adding a new database table ​

  1. Create a migration: pnpm supabase migration new <name>
  2. Write SQL in supabase/migrations/<timestamp>_<name>.sql
  3. Apply: pnpm supabase:db:reset
  4. Regenerate types: pnpm supabase gen types typescript --local
  5. Add repository in libs/data/

Next steps ​