# CLAUDE.md

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

## Project Overview

`xprofile` is a Python package that provides the `XProfile` model class, built on top of `xapian_model.base.BaseXapianModel`. It uses a src layout and is built with hatchling.

## Development Setup

The project uses direnv (`.envrc`) to auto-create and activate a `.venv`. To set up manually:

```
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```

## Architecture

- **src/xprofile/models.py** — Defines `XProfile(BaseXapianModel)` base class (INDEX_TEMPLATE must be defined by users)
- **src/xprofile/schemas.py** — Provides `get_profile_schema()` with profile field definitions (_foreign field must be configured by users)
- **src/xprofile/__init__.py** — Re-exports `XProfile` as the public API

The key dependency is `xapian_model>=0.4.0` (specifically `xapian_model.base.BaseXapianModel`), which provides a fully async API via `pyxapiand>=2.1.0` (httpx-based).

### Security Design

For security reasons, the following values are **NOT** included in the public package:
- `INDEX_TEMPLATE` in `XProfile` class
- `_schema._foreign` field value in the schema
- `PROFILE_ADMIN_API_ID` and related constants

These must be defined in each application that uses xprofile. See README.md for configuration examples.

## Key Conventions

- **Python:** 3.12+ only — use modern syntax (f-strings, PEP 695 type hints, `from __future__ import annotations`)
- **Line length:** 120 characters
- **Type hints:** strict — all public functions and methods must be annotated
- **Naming:** PascalCase for classes, snake_case for functions, UPPER_CASE for constants
- **Dependencies:** `xapian_model>=0.4.0` (async, httpx-based via `pyxapiand>=2.1.0`)
- **Docstrings:** all functions, classes, and methods must include Google-style docstrings
- **`__all__`** explicitly lists all public exports

## Testing

Integration tests run against a live Xapiand server on `localhost:8880`:

```
.venv/bin/pytest tests/test_integration.py -v
```

Key testing conventions:
- Use `cuuid.uuid4().encode()` for UUID values (Xapiand requires standard UUID format)
- Always pass explicit `id=` to `create()` (PUT without ID targets the index, not a document)
- Access document IDs via `._id` (Xapiand uses `_id`, not `id`)
- Use `NotFoundError` (not `TransportError`) for 404 responses
- Null fields are omitted from Xapiand responses; use `getattr(obj, field, None)`
- Set `client.commit = True` for tests that use search/filter (conftest handles this)
