# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

`django-lumen` is a reusable Django app that renders an interactive ERD diagram of all project models in the browser. No external diagram library is used — the diagram is pure vanilla JS + SVG rendered at request time from the live Django model registry.

## Commands

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run a single test
pytest tests/test_inspector.py::test_name

# Build the package
hatch build
```

## Architecture

The app has three layers:

### 1. `lumen/inspector.py` — Data extraction

- `get_app_models()`: reads `django.apps.apps.get_models()`, excludes `auth`, `admin`, `sessions`, `contenttypes`.
- `get_diagram_data(models)`: converts model metadata into a JSON-serialisable dict. Each model gets a globally-unique `key` of the form `"app_label.ModelName"` (important: two apps can have classes with the same name, so bare `object_name` is never used as an identifier). Relation fields carry `{"to": "app_label.ModelName", "kind": "ForeignKey|OneToOneField|ManyToManyField"}`.

### 2. `lumen/views.py` — Single view

`DiagramView` is staff-only (`is_active and is_staff`). It calls the inspector and passes the JSON payload to the template.

### 3. `lumen/templates/lumen/diagram.html` — Self-contained frontend

The JSON payload is embedded in `<script type="application/json" id="diagram-data">` and read by inline JS (no CDN, no bundler). The JS handles:

- **Masonry layout** — models distributed across `√(n * 0.75)` columns
- **SVG line drawing** — orthogonal (right-angle) routing with three selectable notations: Arrow, Crow's Foot, UML. Marker definitions (`<defs>`) are built once; lines are redrawn on style change without re-layouting boxes.
- **Zoom / pan** — CSS `transform` on `#stage` inside `#viewport`; wheel zooms around cursor.
- **Focus mode** — clicking a model header dims unrelated models/lines using a pre-built adjacency set.
- **App filter** — sidebar chips filter to models belonging to selected apps plus their direct relations; triggers full `renderDiagram()` rebuild.

### Key invariant

`model.key` (`"app_label.ModelName"`) is the single source of truth for identity throughout both Python and JS. `model.name` is display-only.
