Skip to content

Architecture

How config becomes a running API

Monorise uses a small build step to turn entity configs into runnable handlers.

monorise.config.ts + entity configs  →  monorise dev/build (CLI)  →  .monorise/config.ts + handle.ts  →  SST stack
  • monorise.config.ts points to your entity config directory and optional custom routes (Hono).
  • The CLI writes .monorise/handle.ts which exports Lambda handlers used by SST (API + processors + replication).

SST infrastructure

The MonoriseCore SST construct provisions the full runtime infrastructure on AWS:

Monorise SST Architecture

The architecture consists of:

  • API Gateway — routes HTTP requests to the Hono Lambda handler
  • DynamoDB single table — stores all entities, mutuals, tags, and unique fields
  • EventBridge bus — publishes entity lifecycle events (created, updated, mutual processed)
  • Processors — SQS-backed Lambda functions that react to events and maintain denormalized data
  • DynamoDB Stream — triggers the replication processor to keep denormalized copies in sync

QFunction (processor pattern)

Each processor (mutual, tag, prejoin) uses the QFunction pattern — an SQS queue paired with a Lambda function, a Dead Letter Queue for failed messages, and a CloudWatch alarm that notifies via Slack when messages land in the DLQ:

Monorise QFunction

The flow:

  1. Events arrive in the SQS queue from EventBridge
  2. Lambda processes the message (e.g., syncs mutual records, recalculates tags)
  3. If processing fails, the message moves to the DLQ after retry exhaustion
  4. A CloudWatch Alarm fires when the DLQ depth exceeds 0
  5. The alarm sends a notification to Slack (if slackWebhook is configured)

Failed messages can be redriven from the DLQ once the issue is resolved.

Key behaviors

  • Mutual processor: creates/updates/removes relationship items in both directions with conditional checks and locking.
  • Tag processor: calculates tag diffs and syncs tag items.
  • Prejoin processor: walks configured relationship paths and publishes derived mutual updates.
  • Replication processor: keeps denormalized copies aligned via stream updates (uses replication indexes).

API reference

The default Hono API exposes the following routes under /core. All entity routes are validated by entityTypeCheck middleware, and mutual routes by mutualTypeCheck middleware.

Entity endpoints

MethodRouteDescription
GET/entity/:entityTypeList entities (paginated, ?limit=20&query=...)
POST/entity/:entityTypeCreate entity
GET/entity/:entityType/unique/:field/:valueGet entity by unique field
GET/entity/:entityType/:entityIdGet entity by ID
PUT/entity/:entityType/:entityIdUpsert entity (full replacement)
PATCH/entity/:entityType/:entityIdUpdate entity (partial)
DELETE/entity/:entityType/:entityIdDelete entity

Mutual endpoints

MethodRouteDescription
GET/mutual/:byEntityType/:byEntityId/:entityTypeList mutuals (entities related to a given entity)
POST/mutual/:byEntityType/:byEntityId/:entityType/:entityIdCreate mutual relationship
GET/mutual/:byEntityType/:byEntityId/:entityType/:entityIdGet specific mutual
PATCH/mutual/:byEntityType/:byEntityId/:entityType/:entityIdUpdate mutual data
DELETE/mutual/:byEntityType/:byEntityId/:entityType/:entityIdDelete mutual relationship

Tag endpoints

MethodRouteDescription
GET/tag/:entityType/:tagNameQuery tagged entities (?group=...&start=...&end=...)

Custom routes can be mounted under /core/app/* via customRoutes in your monorise config.

Data layout cheat sheet

Access patternKey structure
Entity metadataPK = <entityType>#<entityId>, SK = #METADATA#
Entity listPK = LIST#<entityType>, SK = <entityType>#<entityId>
Mutual recordsMUTUAL#<id> item + two directional lookups
Tag recordsPK = TAG#<entityType>#<tagName>[#group], SK = <sortValue?>#<entityType>#<entityId>
Unique fieldsPK = UNIQUE#<field>#<value>, SK = <entityType>

The replication indexes (R1PK/R2PK) support fast updates of denormalized items when entity data changes.

Released under the MIT License.