# Szpitale-graph — agent instructions

**TL;DR:** `cd szpitale-graph && ./mvnw -q compile` (wrapper, not `mvn`). Build lives in `szpitale-graph/`. Neo4j via `docker compose up -d` from same dir. CLAUDE.md has full TDD rules and PLAN.md has the execution backlog. This file covers what CLAUDE.md doesn't.

## Project location & structure

- Application root: `szpitale-graph/` (not the repo root).
- All Maven commands run from `szpitale-graph/` using `./mvnw`.
- Source: `src/main/java/com/developx/szpitale/`
- Tests: `src/test/java/com/developx/szpitale/` (mirror packages)

## Key commands

| Task | Command |
|---|---|
| Compile | `./mvnw -q compile` |
| Test single | `./mvnw -q test -Dtest=ClassName` |
| All tests | `./mvnw -q test` |
| Verify | `./mvnw -q verify` |
| Run CLI | `java -jar target/szpitale-graph.jar` |
| Neo4j up | `docker compose up -d` |
| Neo4j down | `docker compose down -v` |

## Architecture (two layers, JSON between them)

```
ingest (layer 1) ──canonical/*.json──→ load (layer 2 → Neo4j)
```

- **Ingest** = source parsing + normalisation + dedup. No Neo4j dependency.
- **Load** = canonical JSON → UNWIND/MERGE into Neo4j. No network dependency.
- Canonical files: `canonical/<voivodeship>.json` or `canonical/all.json`.

## Code layout (`src/main/java/com/developx/szpitale/`)

| Package | Purpose |
|---|---|
| `model/` | `CanonicalDataset`, `Hospital`, `Person`, `Affiliation`, `Role`, `Mandate`, `RawHospitalRecord` |
| `model/enums/` | `LegalForm`, `RoleType`, `MandateType`, `ConfidenceLevel`, `RoleStatus`, `AffiliationType`, `OrganType`, `SupervisoryBodyType` |
| `ingest/` | `IngestCommand`, `CanonicalWriter`, `IngestResults` |
| `ingest/source/` | `MarkdownRegistrySource` (parses `research-*.md`), `VoivodeshipSource` (interface) |
| `ingest/normalize/` | `NameNormalizer`, `PartyNormalizer`, `Deduplicator` |
| `load/` | `LoadCommand`, `CanonicalReader`, `GraphSchema`, `GraphLoader`, `GraphValidator` |
| `SzpitaleGraphApplication.java` | `@SpringBootApplication` entry point |

## Data format

Research files: `research-<voivodeship>.md` (e.g. `research-podlaskie.md`). Table header:

```
| Funkcja | Imię i nazwisko | Afiliacja partyjna | Źródło (URL) |
```

Every cell **must** have an `https://...` URL. No URL = `BRAK_DANYCH` or skip.

## Current state: build is broken (T1 blocker)

`Deduplicator.java:75` — `groups` is `Map<String, List<Person>>` but code puts `List<String>`. Fix needed before any test can run. See PLAN.md §11, task T1.

## Dependencies

- Spring Boot 3.4.4 (spring-shell, neo4j-starter, web)
- Jackson (databind + jsr310)
- Jsoup 1.18.3 (HTML/Mobile Markdown parsing)
- Commons Text 1.12.0 (Jaro-Winkler fuzzy match)
- Commons CSV 1.12.0 (reports)
- Lombok: **declared in pom.xml but has NO `<version>` — add one if you modify it**
- Spring Shell: **declared in pom.xml with empty line — needs `<version>` if you enable it**
- Testcontainers Neo4j 1.20.4 + JUnit Jupiter

## Test conventions

- Tests mirror main package structure.
- Class-name based: `./mvnw -q test -Dtest=NameNormalizerTest`
- Integration tests (`*IT`) use `@Testcontainers` + `Neo4jContainer`.
- Fixture files → `src/test/resources/fixtures/`

## Git / checkpoint protocol

PLAN.md mandates: one checkpoint commit per task (`-m "T<n>: descript [checkpoint]"`). The `local-agent-progress.json` file tracks task states. On conflicts, **git log is the source of truth** (PLAN.md §13.5).

## Getting a new voivodeship

1. Deep-research → produce `research-<voiv>.md` in same table format as `research-podlaskie.md`
2. Place file in `old/` or a `research/` directory
3. Run `ingest --voivodeship <voiv>` → generates canonical JSON
4. Run `load --voivodeship <voiv>` → pushes to Neo4j

No code changes needed to add a new region.
