Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
99d8dac
feat (graphdb) Neo4j backend skeleton (PR 1)
hourdays Jun 9, 2026
df303b5
feat (graphdb) Neo4j settings UI — left menu + dropdown + config form
hourdays Jun 9, 2026
05adc4e
feat (graphdb) Neo4j named-query Cypher implementations
hourdays Jun 9, 2026
1bc8d7d
feat (reasoning) SWRLFlatCypherTranslator scaffold + wire Neo4jStore
hourdays Jun 9, 2026
80df9ca
chore (graphdb) Neo4j plumbing — pyproject + tests + changelog
hourdays Jun 9, 2026
409f499
feat (graphdb) settings.js wiring for the Neo4j engine config
hourdays Jun 9, 2026
a026aa7
docs (graphdb) Neo4j manual smoke-test runbook
hourdays Jun 9, 2026
732f6f9
fix (graphdb) Neo4j label schema — single-label, not :Triple:<store>
hourdays Jun 9, 2026
5205010
feat (graphdb) engine-aware Build page label
hourdays Jun 9, 2026
aa42cae
fix (graphdb) install neo4j driver in deployed app
hourdays Jun 9, 2026
cc679b9
fix (graphdb) Build label falls back to global engine when dt empty
hourdays Jun 12, 2026
fe23f8c
fix (graphdb) drop the lakebase coercion in triplestore_page_context
hourdays Jun 12, 2026
a72c56f
fix (graphdb) JS reconciles label against /settings/graph-engine
hourdays Jun 12, 2026
0ba4ca6
fix (graphdb) JS always reconciles label against global engine
hourdays Jun 12, 2026
0feddf8
fix (graphdb) keep Graph DB card visible on Neo4j; hide Sync card only
hourdays Jun 12, 2026
80a49a5
feat (graphdb) 3-card Build arch on Neo4j with a Bolt writer card
hourdays Jun 12, 2026
34164b0
feat (graphdb) 3-card Cockpit arch with engine-aware Bolt card
hourdays Jun 12, 2026
6b9e6ec
docs (v0.6) Neo4j demo deck + screenshots + PDF
hourdays Jun 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions app.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@
# (defined in `pyproject.toml`'s optional `[project.optional-dependencies]
# lakebase = [...]`) so the Lakebase Postgres backend works in the
# deployed app even when the `database` resource is not yet bound.
# This is what powers the runtime backend toggle in
# **Settings → Registry Location**: the admin can switch
# Volume ↔ Lakebase without redeploying. On a Volume-only deployment
# the extra costs ~10MB of unused wheels but the app continues to
# run normally — the Lakebase code paths are guarded by
# `LakebaseAuth.is_available` and never reached.
#
# `--extra neo4j` installs the official `neo4j` Python driver
# (Bolt / Cypher) so the Neo4j graph DB engine works when an admin
# selects it in **Settings → Triple store → Global**. Same rationale
# as Lakebase: the extra costs ~5MB of unused wheels on
# Volume/Lakebase-only deployments but Neo4j code paths are guarded
# by `NEO4J_AVAILABLE` and never reached.
#
# Both extras together power the runtime backend toggle:
# the admin can switch Volume / Lakebase / Neo4j without redeploying.
#
# Databricks Apps sets DATABRICKS_APP_PORT automatically.
# MCP endpoint is exposed at /mcp (Streamable HTTP transport).
Expand All @@ -33,6 +37,8 @@ command:
- "run"
- "--extra"
- "lakebase"
- "--extra"
- "neo4j"
- "python"
- "run.py"

Expand Down
59 changes: 59 additions & 0 deletions changelogs/v0.5.0/hourdays_2026-06-09.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 2026-06-09 — Neo4j graph DB engine

**Author:** Hugues Journeau (@hourdays)
**Branch:** `feature/neo4j-graphdb-skeleton` → PR #47 (target: `develop`)
**Version:** v0.5.0

## Context

Adds **Neo4j (Bolt / Cypher)** as a selectable graph DB engine alongside Lakebase Postgres, following `docs/graphdb-integration.md`. Cleanly opt-in: existing Lakebase deployments are unaffected; users activate Neo4j by selecting it from **Settings → Triple store → Global**.

This implementation realises the v0.6 roadmap slot ahead of the August 2026 target, building on Benoit's v0.5 `GraphDBBackend` abstraction and the `_starter_kit/` template.

## Changes

1. **`src/back/core/graphdb/neo4j/__init__.py`** — new package init with `NEO4J_AVAILABLE` guarded import.
2. **`src/back/core/graphdb/neo4j/Neo4jStore.py`** — full `GraphDBBackend` implementation:
- Capability flags: `supports_cypher=True`, `supports_graph_model=False` (flat triple model in v1), `query_dialect="cypher"`.
- Connection management: lazy `neo4j.GraphDatabase.driver(...)`, session-per-query via `_run`.
- Auth: `basic` (username/password) implemented; `databricks_secret` validated but resolution deferred to a follow-up PR.
- CRUD: `create_table` (SPO unique constraint), `drop_table` (constraint + nodes), `insert_triples` (`UNWIND` + `MERGE`, batched), `delete_triples`, `query_triples`, `count_triples`, `table_exists` (via `SHOW CONSTRAINTS`), `get_status`.
- `execute_query` raises `NotImplementedError` by design — no raw Cypher entry point. Preserves the C2 safeguard ("l'entrée se fait par l'ontologie", Benoit 20/05).
- All 16 named-query methods (`get_aggregate_stats`, `get_type_distribution`, `get_predicate_distribution`, `find_subjects_by_type`, `resolve_subject_by_id`, `get_entity_metadata`, `get_triples_for_subjects`, `get_predicates_for_type`, `paginated_triples`, `paginated_count`, `bfs_traversal`, `find_seed_subjects`, `find_subjects_by_patterns`, `expand_entity_neighbors`, `transitive_closure`, `symmetric_expand`, `shortest_path`, `delete_cohort_triples`) implemented in native Cypher with parameterised queries.
3. **`src/back/core/graphdb/GraphDBFactory.py`** — `_create_neo4j` dispatch + `NEO4J_AVAILABLE` guarded import + class-level availability flag.
4. **`src/back/objects/session/GlobalConfigService.py`** — `ALLOWED_GRAPH_ENGINES = ("lakebase", "neo4j")`.
5. **`src/back/core/reasoning/SWRLFlatCypherTranslator.py`** — new translator class scaffolded with the same public interface as `SWRLSQLTranslator`. **Methods return `None` and log a warning** — full SWRL → Cypher translation is its own follow-up PR. Reasoning on Neo4j therefore reports zero violations / inferences (graceful no-op) rather than crashing.
6. **`src/front/config/menu_config.json`** — new "Neo4j" item under TRIPLE STORE group.
7. **`src/front/templates/settings.html`**:
- `<option value="neo4j">Neo4j (Bolt)</option>` in `#graphEngineSelect`.
- New `#neo4j-section` with config form: URI, database, auth method, credentials, encrypted toggle.
8. **`pyproject.toml`** — `[project.optional-dependencies] neo4j = ["neo4j>=5.0"]`.
9. **`tests/units/graphdb/test_neo4j_store.py`** — new test module (driver-mocked) covering capability flags, construction validation, schema sanitisation, CRUD Cypher emission, factory dispatch, and reasoning translator wiring.

## Files modified / added

- `src/back/core/graphdb/neo4j/__init__.py` (new)
- `src/back/core/graphdb/neo4j/Neo4jStore.py` (new, ~580 lines)
- `src/back/core/graphdb/GraphDBFactory.py`
- `src/back/objects/session/GlobalConfigService.py`
- `src/back/core/reasoning/SWRLFlatCypherTranslator.py` (new)
- `src/front/config/menu_config.json`
- `src/front/templates/settings.html`
- `pyproject.toml`
- `tests/units/graphdb/__init__.py` (new)
- `tests/units/graphdb/test_neo4j_store.py` (new)

## Known limitations (deliberate)

- **Reasoning on Neo4j is a no-op** until the dedicated SWRLFlatCypherTranslator translation PR lands. UI surfaces zero violations / zero inferences cleanly.
- **`auth_method=databricks_secret`** is validated but unresolved — basic auth is the only live-tested path.
- **`paginated_triples` SQL conditions** are not translated to Cypher — the unfiltered page is returned and the call is logged. Filtered access should switch to `find_subjects_by_type` / `find_seed_subjects`.
- **`settings.js` save handlers** for the Neo4j section are not in this commit — `engine_config` can currently be persisted via API; UI wiring follows in the next commit on this branch.
- **Build page** (`_query_sync.html` / `_domain_validation.html`) — engine-aware "Graph DB (…)" labels for Neo4j follow in the next commit on this branch.

## Test result

- Static syntax check on all new files: OK.
- Unit tests pass when `neo4j>=5.0` is installed; skip cleanly when not.
- Live smoke test against the Ryan-provisioned Aura (`neo4j+s://b4810af7.databases.neo4j.io`) — pending after the next commit (settings.js wiring + Build page labels).
- `make test` — to be re-run before marking the PR ready-for-review.
69 changes: 69 additions & 0 deletions changelogs/v0.5.0/hourdays_2026-06-12.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# 2026-06-12 — Build page engine label: API fallback when dt.graph_engine is empty

**Author:** Hugues Journeau (@hourdays)
**Branch:** `feature/neo4j-graphdb-skeleton` → PR #47 (target: `develop`)
**Version:** v0.5.0

## Context

Follow-up to commit `5205010` (engine-aware Build page label). The previous
patch read `dt.graph_engine` from the `/dtwin/exist` payload, but that field
is only populated **after** a domain has been built. Pre-Build (status
"Never built"), `dt.graph_engine` is empty and the JS fallback
`dt.graph_engine || 'lakebase'` mislabels the card as "Graph DB (Lakebase)"
even when the global engine setting is Neo4j.

This patch fetches `/settings/graph-engine` asynchronously when
`dt.graph_engine` is empty and re-applies the title + Lakebase-details
visibility once the global engine is known.

## Changes

1. **`src/front/static/domain/js/domain-validation.js`** — in
`populateDtwinCard()` (Build page validation card), when
`dt.graph_engine` is falsy, kick off a `fetch('/settings/graph-engine')`
and re-apply `psDtGraphBackendTitle` / `psDtLakebaseDetails` from the
resolved global engine. Initial render keeps the existing
`'lakebase'` fallback so there is no visual flicker for users on
Lakebase.
2. **`src/front/static/query/js/query-sync.js`** — same pattern in
`_applyBuildGraphEngineUi()`, gated on both `dt.graph_engine` AND
`cfg.graph_engine` being absent (avoids redundant fetches when the
value is already cached on `window.__TRIPLESTORE_CONFIG`). On success,
caches the resolved engine onto `cfg.graph_engine` for subsequent
calls.

## Stronger JS reconciliation (2026-06-12 PM)

Server fix landed in `dependencies.py` but `dt.graph_engine` can still arrive
stale: it reflects the engine recorded on the domain at build-time, which
isn't necessarily the active global engine. Updated both JS files to
reconcile unconditionally against `/settings/graph-engine` on every render
(was: only when `dt.graph_engine` was empty). Global engine is now the
single source of truth for the Build/Validation Graph DB card title.

## Server-side companion fix

3. **`src/front/fastapi/dependencies.py`** — root-cause fix for
`triplestore_page_context`. The previous body was a tautology
(`graph_engine = _raw if _raw == "lakebase" else "lakebase"`) that
silently coerced any non-Lakebase engine to `"lakebase"` before it
reached the template, so the `__TRIPLESTORE_CONFIG.graph_engine`
variable in `domain.html` / `dtwin.html` was hard-stuck on Lakebase
even when Neo4j was the active global engine. Replaced with a direct
pass-through of `TripleStoreFactory._resolve_graph_engine(...)`. The
JS fetch fallback above remains in place as defence in depth.

## Files modified / added

- `src/front/static/domain/js/domain-validation.js`
- `src/front/static/query/js/query-sync.js`
- `src/front/fastapi/dependencies.py`

## Test result

- Static syntax check on both files: OK.
- Live behaviour to be verified in the Chrome MCP screenshot capture
pass (task #54 in the PR plan) — the Build page should now display
"Graph DB (Neo4j)" pre-Build when the global engine is Neo4j on the
fevm-mjolnir deployment.
Binary file added docs/v0.6-neo4j-demo/OntoBricks-PR47-Neo4j.pdf
Binary file not shown.
61 changes: 61 additions & 0 deletions docs/v0.6-neo4j-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# v0.6 Neo4j integration — end-to-end demo artefacts

This folder collects the proof artefacts for **PR #47 — Neo4j as a selectable
graph DB engine**. The demo was run on the `fevm-mjolnir` Databricks workspace
on 2026-06-12 using a real PFAS research-paper ontology.

## Files

- **`OntoBricks-PR47-Neo4j.pdf`** (4.9 MB, 21 slides) — full deck walking through
the end-to-end flow: Settings → Documents → Generate Ontology →
Data Source → Auto-Map → Build → Neo4j Browser → Inference → Cockpit →
GraphQL Playground → GraphQL→Cypher behind-the-scenes → SHACL Data Quality.
- **`deck.html`** — same content as a single-file HTML deck (keyboard
← / → / `P` to print; click left/right halves to navigate).
- **`screenshots/`** — the 13 source PNGs referenced by the deck.

## Demo numbers

| | |
|---|---|
| AI-generated classes | **32** |
| AI-generated relations | **13** |
| Entities mapped via Auto-Map | **25 / 25** |
| Relations mapped via Auto-Map | **12 / 12** |
| Triples written to Neo4j | **303** |
| Build duration (cold) | **10.3 s** |
| Build duration (cached) | **5.3 s** |
| Inferred triples (T-Box OWL 2 RL) | **99** in 0.102 s |
| SHACL Consistency rules auto-generated | **13** |
| SHACL Graph-mode pass rate against Neo4j | **92.3 %** |
| Total nodes in Neo4j after cleanup | **0** (label dropped) |

## What was tested live

- ✅ Settings → Triple store → Global engine swap to Neo4j
- ✅ Settings → Neo4j config form (URI / database / basic-auth / encrypted)
- ✅ Domain → Documents PDF upload → Ontology → Generate (AI)
- ✅ Ontology Designer (with auto-generated icons)
- ✅ Domain → Data Sources (UC table import)
- ✅ Mapping → Auto-Map (batch + per-entity)
- ✅ Mapping → Diagnostics (0 errors after exclude pass)
- ✅ Domain → Build (writes triples to Neo4j over Bolt)
- ✅ Domain → Cockpit (3-card arch shows Bolt + Graph DB Neo4j)
- ✅ Digital Twin → Knowledge Graph header (engine-aware)
- ✅ Digital Twin → GraphQL Playground (real query against Neo4j)
- ✅ Digital Twin → Inference (OWL 2 RL produced 99 inferred)
- ✅ Digital Twin → Data Quality → Graph mode (SHACL against Neo4j)
- ✅ Neo4j Browser external verification (303 nodes, single label)

## How to reproduce on your own Neo4j endpoint

```bash
export NEO4J_URI=neo4j+s://<your-endpoint>
export NEO4J_USER=neo4j
export NEO4J_PASS=<password>
make deploy # to a fevm-* workspace with --extra neo4j
# then in the deployed app:
# Settings → Triple Store → Global → Neo4j (Bolt) → fill creds → Save
# Domain → Build (writes triples via Bolt)
# Verify: tests/integration/neo4j_e2e_smoke.py — 9 / 9 assertions
```
Loading