Case Law Explorer platform
A modular legal-research platform that joins court-data search, shared identity, scoped access, rate limits, APIs, and reproducible deployment.01
A guarded query across the legal-data estate.
The current system joins three corpus-specific ingestion paths to one schema and API. Identity, entitlement, product delivery, and operations remain separate boundaries.
Scroll through seven system boundaries.
citations-api, caselaw-access, caselaw-auth, and caselaw-coolify documentation. The retired /api/network route is deliberately absent; it now returns 410.Google Spain, from public work to queryable graph.
Case C-131/12 enters through CELEX 62012CJ0131. Seven maintained contracts turn it into multilingual text, a stored citation relation, and a guarded result in the research workspace.
- ECLI
- ECLI:EU:C:2014:317
- CELEX
- 62012CJ0131
- Procedure
- Preliminary ruling
- CELEX
- 62012CJ0131
- ECLI
- ECLI:EU:C:2014:317
- Case
- C-131/12
- Languages
- 23 recovered
- English
- 76,831 chars
- Source
- INFOCURIA_BLOB_HTML
- Metadata
- cases.parquet
- Text
- fulltexts.parquet
- Missing
- none reported
- From
- 62012CJ0131
- Relation
- cites
- To
- 62009CJ0509
- Identity
- cases.id
- Corpus
- cjeu_document.case_id
- Graph
- case_citation
- Route
- POST /api/cjeu
- Scope
- cjeu
- Depth
- 1 out · 1 in
- Proxy
- /api/[...path]
- Result
- CJEU profile
- Reader
- /api/cjeu/text
Resolve the work
Boundary 01 · cellar-extractor · get_cellar()The public CELLAR work binds the CELEX identifier to the court ECLI before any application row exists.
cdm:resource_legal_id_celex
"62012CJ0131"
→ ECLI:EU:C:2014:317CELEX becomes the stable join key for metadata, renditions, and citation relations.
Recover renditions
Boundary 02 · cellar-extractor · get_case_data_by_celex_id()Sector-6 retrieval prefers structured InfoCuria material, then fills missing language bodies from CELLAR items.
language EN
format html
source INFOCURIA_BLOB_HTMLEach rendition retains its language, format, and upstream provenance instead of becoming an anonymous text blob.
Normalize the record
Boundary 03 · cellar-extractor · fulltext_saving.pyMetadata and full text travel separately. The text sidecar carries CELEX, ECLI, provenance, format, language, and explicit missing reasons.
text_language EN
text_format html
missing_reasons ""The loader receives typed, inspectable fields; upstream absence remains data rather than disappearing as null.
Extract the edge
Boundary 04 · cellar-extractor · citations_adder.pyThe work_cites_work predicate yields a directed edge from Google Spain to eDate Advertising, not a visual inference from the judgment text.
62012CJ0131
└─ cites → 62009CJ0509
ECLI:EU:C:2011:685Outbound and inbound relations are preserved separately because their upstream coverage differs.
Load the shared model
Boundary 05 · cjeu-migration · 50_load_cjeu.pyA shared case owns corpus-specific metadata, language-specific text, and integer-keyed citation relations without flattening their source semantics.
cases
├─ cjeu_document
├─ case_text × language
└─ case_citation × relationNatural identifiers resolve the case once; satellite and graph rows use the resulting internal key.
Serve a bounded graph
Boundary 06 · citations-api · api/cjeuThe CJEU handler searches the unified schema, walks CELLAR edges, and exposes whether the returned graph is complete enough for statistics.
degreesSource 1
degreesTarget 1
statisticsSafe true | falseWhen enforcement is enabled, @protect("cjeu") resolves scope, cost, quota, and audit state before the handler runs.
Open it for research
Boundary 07 · citations · edgeApi.ts + citation-panel.svelteThe browser calls its own SvelteKit origin. The server adds the bearer credential, the result profile exposes CELEX-specific fields, and text loads by language on demand.
browser → SvelteKit proxy
→ guarded CJEU API
→ result + language readerThe research surface receives a typed case and a qualified graph; neither the database nor service credential reaches the browser.
Google Spain → eDate Advertising. Verify the source judgment in EUR-Lex, the cited case in EUR-Lex, or inspect the public CELLAR package.System boundary
Case Law Explorer is a legal-data platform, not only a search screen. Its deployed request path is browser → SvelteKit server proxy → citations-api → Postgres. Rechtspraak, HUDOC, and CELLAR enter through corpus-specific extraction paths before converging on the cle_v2 schema. Identity, entitlement, product delivery, and operations remain separate so that multiple research tools can share the corpus without sharing one application runtime.
Contribution
David’s work spans the Case Law Explorer search experience, shared interface packages, the account service, scoped API access, rate enforcement, modularization, Docker-based deployment, and server operations. It also includes work on the extraction and normalization path that supplies the research database.
Consequential decisions
One case relation, three corpus satellites. cases is the shared ECLI-keyed entry point. rs_document, echr_document, and cjeu_document retain corpus-specific fields; case_text stores language-specific full text; and integer-keyed case_citation records the cross-corpus graph. This avoids flattening source-specific semantics into one oversized case table.
Search and full text have different costs. The API exposes fifteen JSON routes across Rechtspraak, ECHR, CJEU, combined search and expansion, statistics, communities, summaries, and legal-link resolution. Full text has a dedicated route per corpus, and the old generic /api/network route returns 410. The interface therefore loads large judgment bodies only when the reader asks for them.
Identity is not entitlement. Keycloak establishes who the caller is. caselaw-access separately decides whether that principal may use an endpoint, how much the route costs, which minute and daily limits apply, and why the request was allowed or denied. A valid identity therefore never silently becomes universal API access.
Completeness travels with the graph. Cursor state, result caps, partialReasons, and statisticsSafe remain part of the API response. A truncated network cannot accidentally reach a centrality method while presenting itself as complete.
Optional services remain optional in code. The core database, API, and frontend run without shared sign-in or rate enforcement. Auth and access connect over explicit URLs and credentials; enabling one does not import it into every product runtime. Public search, guarded APIs, and research workspaces can therefore adopt different access postures without forking the corpus.
Public and authenticated products share versioned interface primitives across Vue and Svelte. The deployment contract keeps each service replaceable and lets the search surface, research APIs, and internal workspaces evolve at different rates.
Account export and erasure use subject-bound, expiring service tokens on /internal/users/{subject} routes outside the public API prefix. Coolify composes the API, frontend, migrator, database, backup, signed SQL runner, and Airflow services; Airflow’s bookkeeping remains in a different Postgres instance from the case-law data.
Ingestion
CELLAR extraction is one component of this pipeline. European legal material is distributed across CELLAR, EUR-Lex, InfoCuria, RDF records, and multiple document manifestations. The extractor retrieves base metadata, follows the public CELLAR SPARQL citation graph, and adds full text, summaries, keywords, provenance, and explicit missing-data states.
Separate paths cover CJEU-style case law, national case-law material, legislation, and consolidated versions. Outputs support both tabular research and graph-ready node and edge projections. Missing values are retained with their causes because source absence, format drift, and incomplete enrichment affect the validity of downstream research.
Evidence
- A live research interface at
app.caselawexplorer.tech. - Published JavaScript and Python packages for interface, ingestion, authentication, and access layers.
- Service-specific repositories for extraction, API, shared UI, authentication, access policy, and deployment.
- Reproducible Docker configurations and documented operational boundaries.
Reflection
Good research infrastructure makes limits visible. Authentication remains optional where open access is appropriate; scopes and quotas are explicit where scarce resources need protection; and every service documents what it owns.
Design and implementation
- Visual decision
- The estate overview names the owned boundaries; the second trace follows one real CJEU judgment through CELLAR resolution, multilingual recovery, normalization, citation extraction, cle_v2, the guarded API, and the SvelteKit reader.
- Access decision
- Every boundary remains in an ordered text sequence. The active readout can be changed by pointer, previous/next controls, or arrow keys; reduced-motion visitors receive the same state changes without the route animation.
- Delivery constraint
- The concrete judgment values were checked through the maintained extractor and public CELLAR graph, then frozen into static HTML. This example sends no query, database identifier, service credential, or private deployment state.