---
id: "business-updates-without-index-propagation"
type: "rule"
severity: "warning"
url: "https://localhost:3000/catalogue/rules/business-updates-without-index-propagation"
---

# Database updates not propagated to the search index

Application servers write a database and the design keeps a search index, but no change data capture leaves the database; index writes rely on dual writes.

| | |
|---|---|
| Severity | warning |
| Selects | every node of kind sql-database |
| Components in scope | 76 |

## Why

Application servers write this database and the design keeps a search index, but nothing captures the database's changes. The index then depends on the application writing to both places, and the two drift apart silently.

## What it checks

It looks at every node of kind sql-database, and fires when:

- all of these hold:
  - the node has at least one synchronous incoming edge from an app-server
  - the design contains a node of kind search-index
  - this does not hold:
    - the node has at least one outgoing edge to a change-data-capture

Message template:

```
Database '{{node.id}}' is written by application servers and the design has a search index, but no change-data-capture propagates its updates. Index writes rely on dual writes.
```

## Applies to

- [SQL database](https://localhost:3000/catalogue/kinds/sql-database.md) `sql-database`

76 catalogue components fall under it.

## Tripped by

Reference designs whose broken twin names this rule in its header:

- [airbnb-search](https://localhost:3000/d/zeema/airbnb-search)
- [booking-search](https://localhost:3000/d/zeema/booking-search)
- [etsy-search](https://localhost:3000/d/zeema/etsy-search)
- [facebook-tao](https://localhost:3000/d/zeema/facebook-tao)
- [gitlab-architecture](https://localhost:3000/d/zeema/gitlab-architecture)
- [lyft-envoy](https://localhost:3000/d/zeema/lyft-envoy)
- [notion-sharding](https://localhost:3000/d/zeema/notion-sharding)
- [proximity-service](https://localhost:3000/d/zeema/proximity-service)
- [stack-overflow](https://localhost:3000/d/zeema/stack-overflow)
- [twitch-live](https://localhost:3000/d/zeema/twitch-live)
- [twitter-timeline](https://localhost:3000/d/zeema/twitter-timeline)
- [uber-dispatch](https://localhost:3000/d/zeema/uber-dispatch)

## Source (`rule` YAML, verbatim)

```yaml
# yaml-language-server: $schema=../schema/rule.schema.json
# Application servers write this system of record and the design keeps a search index, but
# no change-data-capture leaves the database. Index updates then depend on dual writes from
# application code, which drift silently. Tripped by: designs/twitter-timeline.broken.yaml
schemaVersion: "1"
type: "rule"
id: "business-updates-without-index-propagation"
severity: "warning"
select:
  node:
    kind: "sql-database"
when:
  all:
    - hasEdge:
        direction: "in"
        mode: "sync"
        peerKind: "app-server"
    - hasNode:
        kind: "search-index"
    - not:
        hasEdge:
          direction: "out"
          peerKind: "change-data-capture"
message: "Database '{{node.id}}' is written by application servers and the design has a search index, but no change-data-capture propagates its updates. Index writes rely on dual writes."
```

Human page: https://localhost:3000/catalogue/rules/business-updates-without-index-propagation
