Chapter 01 · Graph Database Foundations, Neo4j Editions, Deployment Choices, and Lab Setup
Build a Reproducible Graph Lab with Sample Data, Administrative Accounts, Metrics, and Safe Reset Procedures
Freeze Chapter 01 into a reusable course contract: deterministic graph state, account semantics, observable baselines, reversible failures, and explicit reset blast radii.
Learning outcomes
Chapter 01 ends by converting the ad-hoc experiments into a lab contract that future chapters can reuse. AtlasMart needs deterministic sample identities, a known database/user, persistent but disposable volumes, simple resource evidence, safe failure tests, and two reset levels: remove only course graph data, or destroy the entire course DBMS state. A lab without a reset path eventually becomes an unknown environment and stops teaching cause and effect.
Create a repeatable AtlasMart graph fixture with explicit identities, constraints, relationship types, and deterministic verification queries.
Inspect the default administrative user and demonstrate Community user-management semantics without pretending Community provides Enterprise RBAC.
Collect lightweight process, container, query, storage and log evidence that establishes a baseline without inventing benchmark claims.
Inject reversible authentication/endpoint/process failures, record expected signals, and prove recovery.
Perform graph-only and full-environment resets with an explicit blast radius and verification checklist.
Server 2026.07.1 Community; Cypher examples
prefixed with CYPHER 25; local database
neo4j; local admin user neo4j; host
endpoints 127.0.0.1:7474 and
127.0.0.1:7687; named volumes
atlasmart-neo4j-data and
atlasmart-neo4j-logs; optional Python driver
6.3.0. No APOC, GDS, TLS, cluster, CDC, vector,
or Enterprise feature is required in Chapter 01.
Every destructive command in this lesson targets the names
above. Before copying it, verify the container and volume
names with docker ps -a and
docker volume ls. Never substitute a production
container, a shared Docker volume, an Aura database, or an
unrelated local Neo4j home.
Start from known infrastructure state
Use the existing Chapter 01 container if it is healthy. If you intentionally want a clean environment, perform the full reset at the end of this lesson and recreate it. The acceptance criteria below make “healthy” concrete:
docker ps --filter name=atlasmart-neo4j --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"docker volume inspect atlasmart-neo4j-datadocker volume inspect atlasmart-neo4j-logsdocker exec atlasmart-neo4j cypher-shell -a neo4j://localhost:7687 -u neo4j -p atlasmart-course-2026 "CALL dbms.components() YIELD versions, edition RETURN versions, edition;"docker exec atlasmart-neo4j cypher-shell -a neo4j://localhost:7687 -u neo4j -p atlasmart-course-2026 "SHOW SETTINGS 'db.query.default_language' YIELD value RETURN value;"
Do not use container uptime as the only success criterion. A valid baseline proves the image tag, persistent mounts, responding Bolt endpoint, server/edition identity, and Cypher default.
Build a deterministic AtlasMart fixture
The fixture is intentionally small enough to understand by
inspection but connected enough to support future Cypher
lessons. Stable business identifiers are properties such as
customerId and productId; do not teach
Neo4j internal element IDs as durable business identifiers. We
add uniqueness constraints before using MERGE so
concurrent or repeated setup has a clear identity rule.
CYPHER 25 CREATE CONSTRAINT customer_id IF NOT EXISTS FOR (c:Customer) REQUIRE c.customerId IS UNIQUE;CYPHER 25 CREATE CONSTRAINT product_id IF NOT EXISTS FOR (p:Product) REQUIRE p.productId IS UNIQUE;CYPHER 25 CREATE CONSTRAINT order_id IF NOT EXISTS FOR (o:Order) REQUIRE o.orderId IS UNIQUE;CYPHER 25 CREATE CONSTRAINT device_id IF NOT EXISTS FOR (d:Device) REQUIRE d.deviceId IS UNIQUE;
CYPHER 25MERGE (c1:Customer {customerId:'C-1001'}) SET c1.name='Mina Rahimi', c1.region='west'MERGE (c2:Customer {customerId:'C-1002'}) SET c2.name='Omid Karimi', c2.region='west'MERGE (d1:Device {deviceId:'D-9001'}) SET d1.kind='mobile'MERGE (p1:Product {productId:'P-1001'}) SET p1.name='Trail Camera', p1.category='Cameras', p1.price=129.90MERGE (p2:Product {productId:'P-2001'}) SET p2.name='Smart Shelf Sensor', p2.category='Store IoT', p2.price=79.50MERGE (o1:Order {orderId:'O-5001'}) SET o1.orderedAt=datetime('2026-09-08T16:30:00Z'), o1.status='PAID'MERGE (c1)-[:USED_DEVICE]->(d1)MERGE (c2)-[:USED_DEVICE]->(d1)MERGE (c1)-[:PLACED]->(o1)MERGE (o1)-[:CONTAINS {quantity:1}]->(p1)MERGE (c1)-[:VIEWED {at:datetime('2026-09-09T08:00:00Z')}]->(p2);
MERGE here is repeatable because the entity
patterns are anchored by constrained business IDs and the
relationships have unambiguous endpoints/types in this fixture.
That does not make MERGE a universal upsert
primitive. Later chapters show partial-pattern matching,
relationship uniqueness, concurrent creation, and when separate
MATCH/CREATE logic is clearer.
Verify graph state from independent queries
CYPHER 25 MATCH (n) RETURN labels(n) AS labels, count(*) AS count ORDER BY labels;CYPHER 25 MATCH ()-[r]->() RETURN type(r) AS relationshipType, count(*) AS count ORDER BY relationshipType;CYPHER 25 MATCH (seed:Customer {customerId:'C-1001'})-[:USED_DEVICE]->(:Device)<-[:USED_DEVICE]-(peer:Customer) RETURN peer.customerId, peer.name;CYPHER 25 MATCH (:Customer {customerId:'C-1001'})-[:PLACED]->(o:Order)-[:CONTAINS]->(p:Product) RETURN o.orderId, p.productId, p.name;
The fixture should converge to the same graph when rerun. Verification queries should return stable identities rather than relying on row display order or internal IDs.
Administrative accounts: authenticate clearly, do not fake least privilege
Every fresh Neo4j DBMS has the native neo4j user.
The Docker environment set its disposable initial password so
Browser, Cypher Shell, and the driver can authenticate without
an interactive first-login password change. Inspect the current
identity:
SHOW CURRENT USER;SHOW USERS;
Community supports multiple users, but current Neo4j documentation states that Community has no roles and all users have implied administrator privileges. Therefore a second Community user can demonstrate authentication/account lifecycle but cannot demonstrate least-privilege application authorization.
CREATE USER atlasmart_lab IF NOT EXISTS SET PASSWORD 'atlasmart-lab-user-2026' CHANGE NOT REQUIRED;SHOW USERS;DROP USER atlasmart_lab IF EXISTS;
The account is deliberately deleted in the same exercise. For a
production application that needs
reader/publisher/custom privileges,
use Enterprise/Aura tiers that provide the required
authorization features and design grants/denies explicitly. Do
not label Community’s extra user as a “read-only user.”
Collect a lightweight observable baseline
This is not a benchmark chapter. We collect enough evidence to
recognize a later change. A single
docker stats sample is a point-in-time observation,
not a latency distribution or capacity model. Likewise, graph
counts prove fixture size, not production scale.
docker stats --no-stream atlasmart-neo4jdocker inspect atlasmart-neo4j --format 'Image={{.Config.Image}} Started={{.State.StartedAt}} Status={{.State.Status}}'docker exec atlasmart-neo4j sh -lc 'du -sh /data /logs 2>/dev/null'docker logs --tail 80 atlasmart-neo4j
CYPHER 25 MATCH (n) RETURN count(n) AS nodeCount;CYPHER 25 MATCH ()-[r]->() RETURN count(r) AS relationshipCount;SHOW INDEXES YIELD name, type, entityType, state, populationPercent RETURN name, type, entityType, state, populationPercent ORDER BY name;SHOW CONSTRAINTS YIELD name, type, entityType RETURN name, type, entityType ORDER BY name;
Record the server image, DBMS version/edition, graph counts, index/constraint state, data/log footprint, and logs after a clean setup. Later chapters can compare query plans, indexes, transaction behavior, imports, plugins, or memory without guessing what changed.
Controlled failure test: authentication
Blast radius: one deliberately invalid client login. It does not change graph data or server configuration. Expected signal: authentication failure from Cypher Shell. Reset: none; immediately retry with the known-good disposable credential.
docker exec atlasmart-neo4j cypher-shell -a neo4j://localhost:7687 -u neo4j -p wrong-password "RETURN 1;"docker exec atlasmart-neo4j cypher-shell -a neo4j://localhost:7687 -u neo4j -p atlasmart-course-2026 "RETURN 1 AS recovered;"
A timeout and an authentication rejection are operationally different. Preserve the error category rather than reducing every client failure to “Neo4j is down.”
Controlled failure test: process stop and recovery
Blast radius: only the container
atlasmart-neo4j; named data/log volumes remain.
Expected signal: Bolt queries fail while the
container is stopped. Reset: restart the same
container and verify fixture state. This demonstrates process
availability and persistence—not cluster failover.
docker stop atlasmart-neo4jdocker ps -a --filter name=atlasmart-neo4jdocker start atlasmart-neo4jdocker logs --tail 80 atlasmart-neo4jdocker exec atlasmart-neo4j cypher-shell -a neo4j://localhost:7687 -u neo4j -p atlasmart-course-2026 "CYPHER 25 MATCH (c:Customer) RETURN count(c) AS customers;"
If the query is attempted before the restarted DBMS is ready, it can fail transiently; wait for readiness and retry. The fact that data survives a container restart comes from the mounted named volume. It does not constitute a backup because the volume remains in the same local failure domain.
Graph-only reset versus full environment reset
A graph-only reset preserves DBMS configuration, users, system state, and volumes while deleting user-database data and schema objects. It is useful when beginning a modeling/query lab again. A full reset destroys the course container and named volumes and is appropriate when configuration/storage state itself must return to zero.
Graph-only reset
The following command is intentionally destructive and should
run only against the disposable neo4j database in
this course container. Do not paste it into an unknown
Browser/Aura session.
CYPHER 25 MATCH (n) DETACH DELETE n;DROP CONSTRAINT customer_id IF EXISTS;DROP CONSTRAINT product_id IF EXISTS;DROP CONSTRAINT order_id IF EXISTS;DROP CONSTRAINT device_id IF EXISTS;CYPHER 25 MATCH (n) RETURN count(n) AS remainingNodes;
Afterward, rerun the fixture script to recreate exactly the expected state.
Full environment reset
Stop here if you want to continue Chapter 02 with the existing fixture. The commands below permanently remove only the explicitly named course container and volumes.
docker rm -f atlasmart-neo4jdocker volume rm atlasmart-neo4j-datadocker volume rm atlasmart-neo4j-logsdocker ps -a --filter name=atlasmart-neo4jdocker volume ls --filter name=atlasmart-neo4j
Recreate with the pinned setup commands from Lesson 3. A trustworthy course reset is one whose absence can also be verified.
Chapter 01 verification checklist
-
Version:
CALL dbms.components()reports the intended2026.07.1Community server line. -
Cypher: runtime/default evidence is recorded,
and examples explicitly use
CYPHER 25where version intent matters. - JVM: the actual compatible image JVM is recorded rather than assumed.
- Network: local HTTP/Bolt host mappings are loopback-only; production exposure/TLS is not inferred from this lab.
- Auth: only disposable course credentials appear in commands; Community’s lack of RBAC is understood.
- Data: business IDs are explicit; rerunning fixture commands produces the same intended graph.
-
Schema: identity constraints exist and are
online before relying on
MERGEuniqueness. -
Persistence: a stop/start retains data
because
/datais a named volume. - Recovery: this persistence is not called a backup; backup/restore arrives in dedicated operations chapters.
- Reset: graph-only and full reset procedures have explicit blast radii and postconditions.
Production judgment: make the lab assumptions visible before scaling them
The course environment is intentionally unlike a production deployment in several ways: one Community instance, local loopback networking, no TLS, a synthetic tiny graph, one machine/failure domain, no online backup, no RBAC, no APOC/GDS, no cluster, no CDC, no vector/full-text workload, and no representative concurrency. That honesty is a strength: later chapters can introduce one mechanism at a time and measure the result.
For production, AtlasMart must quantify node/relationship cardinalities, high-degree distributions, write/read concurrency, transaction conflicts, index/selectivity needs, page-cache/heap/query memory, CPU/storage/network, driver pools/timeouts/retries/idempotency, security/tenancy, backup/restore RPO/RTO, observability, patch/upgrade policy, and deployment/edition/tier constraints. No universal “X GB heap per Y million nodes” rule can replace workload measurements.
Check your understanding
- Why do uniqueness constraints precede the fixture’s MERGE statements?
- Why is a second Community user not a least-privilege application account?
- What does the stop/start exercise prove, and what does it explicitly not prove?
- When should you prefer graph-only reset over deleting Docker volumes?
- Name four Chapter 01 assumptions that must not silently carry into production.
Review the answers
1. They establish explicit business identity and make repeated/concurrent match-or-create behavior safer and more understandable. MERGE alone is not an identity constraint.
2. Community has user management but no Enterprise role/privilege model; its users have implied administrator-level access.
3. It proves the single DBMS process can stop/restart and that named-volume persistence retains data. It does not prove high availability, failover, backup, or disaster recovery.
4. When you want to keep the same DBMS/config/user/storage environment but restore only the synthetic graph/schema to a known state. Full volume removal is for resetting infrastructure/storage state too.
5. Examples include single instance, loopback-only networking, no TLS, no RBAC, tiny synthetic data, one failure domain, no online backup, no plugins, no cluster, and non-representative concurrency.
Summary and bridge to Chapter 02
Chapter 01 now has a reproducible contract: a pinned Community DBMS, explicit Cypher/JVM/driver evidence, stable AtlasMart identities, deterministic graph setup, observable storage/log/container state, reversible failure tests, and safe reset procedures. The course can build on this state without relying on mystery local history.
Chapter 02 moves from deployment boundaries into the property graph model itself: nodes, relationships, labels, properties, data types, identity, cardinality, schema discipline, and modeling decisions.
Authoritative references
- Current Neo4j versions — Official current-release and LTS patch snapshot.
- Neo4j Operations Manual — Authoritative self-managed operational documentation for the current release.
- Neo4j system requirements — Supported operating systems and JVM requirements.
- Cypher Manual — Current Cypher 25 reference and language semantics.
- Configure the Cypher default version — Cypher 5 versus Cypher 25 default and override behavior.
- Neo4j in Docker — Official image tags, ports, editions, and Docker starting point.
- Manage users — Current Community/Enterprise user behavior and CREATE/SHOW USER syntax.
- Cypher and Neo4j editions — Community versus Enterprise database/security/schema boundaries.
- Docker volumes — Persistence/mount-point behavior for the official image.
- Neo4j indexes — Current index concepts and SHOW INDEXES context.
- Neo4j constraints — Current constraint semantics and commands.
- Neo4j Python Driver installation — Driver compatibility and Python requirements.