afp-backend / docs /references.md
cdupland
feat: enhance article import functionality with reference management
96d8d92
# Article reference numbers
## Rule
If a `reference_number` starts with a single lowercase **`a`**, that character is removed before storage and lookup. Examples:
| Input | Stored / matched |
|-------|------------------|
| `a12345` | `12345` |
| `aA12` | `A12` |
| `A12` | `A12` (unchanged) |
| `aa12` | `a12` (only the first `a`) |
Source of truth: Postgres function `public.normalize_reference_number(text)` (immutable). Python code uses the mirror helper `normalize_reference()` in [`app/domain/reference_normalization.py`](../app/domain/reference_normalization.py).
## Writes
Any insert or update on `public.article_references.reference_number` is normalized by the trigger `article_references_normalize_ref` (`BEFORE INSERT OR UPDATE OF reference_number`).
- FastAPI imports: Pydantic validators on `ArticleImportRow` and `PriceImportRow` call `normalize_reference()` before bulk upsert or resolution.
- Article catalogue imports may also write **alias** references (`main = false`) via `reference_old`, and **rename** an article via `reference_new` (see [imports.md](imports.md)).
- Front-end / Supabase client: you may send `aXXX` or `XXX`; the stored value is always normalized.
- SQL scripts: prefer `public.upsert_article_by_main_ref(...)`, which normalizes its `p_reference_number` argument.
- Frontend article creation flow is documented in [frontend-catalog-create.md](frontend-catalog-create.md).
## Reads / search
Do **not** filter with `.eq('reference_number', userInput)` on the client. Use the RPC:
```ts
const { data, error } = await supabase.rpc('find_article_references_by_ref', {
p_ref: userInput,
});
```
The RPC normalizes `p_ref` the same way as the trigger.
FastAPI repositories that query by reference should call `normalize_reference()` on the parameter before `WHERE reference_number = $1` (imports already do this via validators and `ArticleReferenceRepository.resolve_reference_numbers`).
## Data migration
Existing rows with a leading `a` are updated in migration `20260521100000_normalize_article_reference.sql`. Before applying on production, run the collision audit from that migration’s comment if both `a12345` and `12345` could exist as main references.
## Changing the rule
Update **both** `public.normalize_reference_number` and `normalize_reference()` in Python, then add tests in `tests/unit/test_reference_normalization.py` and integration tests under `tests/integration/test_reference_rpc.py`.