CtrlK
BlogDocsLog inGet started
Tessl Logo

g14wxz/commerce-database-architect

Database architecture skills, docs, and rules for high-demand multi-tenant commerce platforms (PostgreSQL source of truth, Neo4j as derived GraphRAG projection, transactional outbox, RLS-based tenant isolation). Includes live schema introspection workflow via Postgres MCP.

97

Quality

97%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

database-non-negotiables.mdsteering/

Database Non-Negotiables

These rules are always on, applied to every interaction in this project, regardless of which command or skill is active. They are the minimum bar below which the agent never produces output.

If any rule conflicts with a user instruction, the rule wins and the agent explains why.


Architectural defaults

  1. The default architecture is modular monolith + PostgreSQL + RLS + transactional outbox + Neo4j as derived projection. Deviation requires an ADR.
  2. PostgreSQL is the source of truth. Neo4j, search indexes, caches, and analytics stores are derived. When they disagree, PostgreSQL wins.
  3. Microservices are not a default. Propose extraction only after measured evidence (write throughput, replication lag, deploy cadence conflict, regulatory boundary, team-size driver).

Multi-tenant isolation

  1. Every tenant-scoped table includes tenant_id BIGINT NOT NULL.
  2. Every tenant-scoped composite index is tenant-first: (tenant_id, ...).
  3. Every tenant-scoped unique constraint includes tenant_id: UNIQUE (tenant_id, sku), never UNIQUE (sku).
  4. Row Level Security is on for every table holding user-visible data. The policy uses current_setting('app.tenant_id').
  5. Frontend filtering is never sufficient. Tenant isolation lives at four layers: app authz, RLS, tenant-aware indexes, tenant-aware constraints.

Schema discipline

  1. No table exceeds ~40 columns. If you're approaching that, model it as sub-aggregates.
  2. Every table has created_at TIMESTAMPTZ and updated_at TIMESTAMPTZ, both NOT NULL DEFAULT now(). updated_at is trigger-maintained.
  3. All timestamps are TIMESTAMPTZ. Never TIMESTAMP. Never epoch integers. Never strings.
  4. Primary keys are BIGINT GENERATED ALWAYS AS IDENTITY for internal use. External IDs are UUID or ULID via a separate public_id column.
  5. Foreign keys are mandatory. Removing one for "performance" requires an ADR with measured evidence.

JSONB

  1. JSONB is for flexible, optional, non-critical metadata.
  2. JSONB is forbidden for: prices, stock balances, payment amounts, tenant ownership, order totals, tax-critical fields, or any field used in joins, constraints, or frequent queries.
  3. JSONB keys that become business-critical or frequently queried must be promoted to real columns and the JSONB key dropped.

Eventing

  1. Every domain event leaving PostgreSQL is written to outbox_messages in the same transaction as the state change. Never publish-after-commit.
  2. The outbox relay uses FOR UPDATE SKIP LOCKED.
  3. External API calls happen outside DB transactions. Pattern: short tx (write intent + outbox) → commit → external call → short tx (record result).
  4. Event consumers are idempotent. Exactly-once delivery is never assumed.

Inventory & financial integrity

  1. Inventory balance changes are backed by an append-only inventory_movements row written in the same transaction.
  2. Overselling prevention is mandatory: SELECT FOR UPDATE on the balance row, or inventory_reservations with a unique constraint, or optimistic concurrency with retry. Pick one per feature; document it.
  3. Order totals, payment amounts, and refund amounts use NUMERIC(p, s), never FLOAT or DOUBLE.

Migration safety

  1. Production migrations follow expand/contract: nullable add → batched backfill → cutover → enforce/drop.
  2. Indexes in production use CREATE INDEX CONCURRENTLY.
  3. No ALTER TABLE that rewrites the table without an ADR.
  4. Every migration has a documented rollback step.

Neo4j boundary

  1. Neo4j may store derived nodes, derived relationships, and stale-tolerant denormalized properties. It must not store transactional truth.
  2. Sync flow is one-way: PostgreSQL → outbox → projection worker → Neo4j.
  3. Before any commitment (checkout, reservation, payment, regulated-product sale), the system re-checks PostgreSQL truth.
  4. GraphRAG output is suggestion-quality. The user or an authorized service action confirms the actual transaction.

Compliance

  1. Pharmacy/regulated workflows default to the stricter interpretation when ambiguity exists.
  2. The system never assists in bypassing legal controls, prescription requirements, age restrictions, or compliance checks.

When in doubt

If a user request would force a violation, stop and explain, then propose the constitutional alternative. If the user wants to override, require an ADR via /speckit.adr.

tile.json