Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 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
da9cae9
feat(graphdb): source Neo4j password from Databricks Apps secret
hourdays Jun 22, 2026
e8b523c
feat(graphdb): log executed Cypher at INFO level (no secrets)
hourdays Jun 23, 2026
577b70f
chore(release): v0.7.0 inits
hourdays Jun 23, 2026
e63bfce
fix(front): render persisted graph engine server-side to avoid Settin…
hourdays Jun 23, 2026
7a9a625
refactor(graphdb): split Neo4jStore into Connection/Writes/Reads
hourdays Jun 24, 2026
820f607
feat(graphdb): wire Neo4j Test connection + bind secret resource via DAB
hourdays Jun 25, 2026
b13dda0
feat(graphdb): add RETURN 1 Cypher probe to Test connection + refresh…
hourdays Jun 25, 2026
a4281eb
chore(docs): rename v0.6-neo4j-demo/ → pr47-neo4j-demo/ (covers v0.6 …
hourdays Jun 25, 2026
6782d38
chore: untrack syncs/ folder (local working drafts only)
hourdays Jun 25, 2026
5b29dc3
docs(demo): full v0.7 E2E re-capture on ontobricks-070 + KG filter li…
hourdays Jun 25, 2026
65ccc73
fix(graphdb): release-ready hardening — GraphQL fallback, MCP retry, …
hourdays Jun 25, 2026
c70e55e
docs(demo): screenshot of GraphQL friendly fallback (live on ontobric…
hourdays Jun 25, 2026
5ea8f3d
docs(demo): redesign slide 4 architecture — 2 backend rows mirroring …
hourdays Jun 26, 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ tests/e2e/_e2e_server.log
.understand-anything/



# Local working drafts — should never be committed (per topic-folder convention)
syncs/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img src="src/front/static/global/img/ontobricks-icon.svg" alt="OntoBricks Logo" width="120" height="120">
</p>

<h1 align="center">OntoBricks 0.5.0</h1>
<h1 align="center">OntoBricks 0.7.0</h1>

<p align="center">
<strong>Digital Twin Builder for Databricks</strong>
Expand Down
33 changes: 27 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 Expand Up @@ -100,6 +106,17 @@ env:
# MLflow — ensure traces are persisted to the workspace tracking server.
- name: MLFLOW_TRACKING_URI
value: "${APP_MLFLOW_TRACKING_URI}"
# ── Neo4j (optional) ──────────────────────────────────────────
# Password sourced from a Databricks Apps secret resource (see
# `resources:` below). The `neo4j-password` resource is unbound by
# default; the admin binds it to a workspace secret (scope/key) in
# the Apps UI before selecting the Neo4j engine. When the resource
# is unbound, NEO4J_PASSWORD stays unset and the deployed app refuses
# to instantiate Neo4jStore with a clear instruction in the logs.
# Local dev keeps the legacy fallback to engine_config['password'].
# See docs/v0.6-neo4j-demo/secret-configuration.md.
- name: NEO4J_PASSWORD
valueFrom: neo4j-password

# User authorization scopes — declares which Databricks APIs the app is
# allowed to access on behalf of the logged-in user via the
Expand All @@ -126,3 +143,7 @@ resources:
description: "Unity Catalog Volume for the OntoBricks domain registry"
volume:
permission: CAN_READ_WRITE
- name: neo4j-password
description: "Databricks Apps secret holding the Neo4j Bolt password. Unbound by default; bind it to a workspace secret (scope/key) in the Apps UI before activating the Neo4j engine. See docs/v0.6-neo4j-demo/secret-configuration.md."
secret:
permission: READ
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.
Loading