Vol. II · Functory Quarterly№ 001 · Edition 2026
I
The atom

It all starts with an entity.

Configure, compose, and Functory delivers: APIs, persistence, events, search, observability.

Start with an entity. Use one of 100+ built-in primitives or define your own.

Four beats

01

Declare what it is

Pick a name and the fields you'll filter by, in the Console or as code. That's enough to get a typed REST API, a GraphQL schema, and DynamoDB persistence — no migrations, no DTOs, no handlers.

REST APIGraphQLDynamoDB
fig. i·a ExperienceConfig
val experienceConfig = EntityConfig(
  kind      = "experience",
  fragments = Seq("hostId", "category", "city"),
)
02

Decide who can touch it

One line decides the access model. OWNER means only the creator can read or write. GROUP, PUBLIC, and custom policies plug in the same way — and they're enforced at the API layer for you.

Access controlAudit trail
fig. i·b ExperienceConfig
val experienceConfig = EntityConfig(
  kind       = "experience",
  accessMode = EntityAccessMode.OWNER,
  fragments  = Seq("hostId", "category", "city"),
)
03

Define what happens when it changes

Hook into create, update, and state changes declaratively. Run lifecycle hooks, fire webhooks, or auto-enrich content with sentiment, key phrases, OCR, and image labels. Every change is event-sourced and replayable.

Lifecycle hooksEvent sourcingSentiment & key phrasesOCR & image labels
fig. i·c ExperienceConfig
val experienceLifecycle = LifecycleConfig(
  initial = "Draft",
  transitions = Seq(
    Transition("Draft", "Published",
      guards = Set("hasPhotos"),
      hooks  = Set("notifyFollowers")),
  ),
)

val experienceConfig = EntityConfig(
  kind            = "experience",
  accessMode      = EntityAccessMode.OWNER,
  fragments       = Seq("hostId", "category", "city"),
  lifecycleConfig = Some(experienceLifecycle),
)
.withContentAnalysis(
  fields   = Seq("title", "description"),
  analyses = Set(KeyPhrases, Sentiment),
)
.withMediaAnalysis(MediaAnalysisConfig(
  analyses       = Set(IMAGE_LABELS, IMAGE_TEXT),
  analyzeOnReady = true,
))
04

Query it however you need

Every entity is mirrored to the right database for the question you're asking — full-text search, geospatial, graph traversal — kept in sync via CDC with sub-second lag. You write one config; you query four engines.

Full-text searchGeospatialGraph
fig. i·d GET /api/v1/experiences
# Key lookup → DynamoDB
GET /api/v1/experiences/exp_a8f2c1

# Faceted full-text → OpenSearch
GET /api/v1/experiences/search?q=cozy+loft&filter[city]=SF

# Geospatial → PostgreSQL/PostGIS
GET /api/v1/experiences/search?near=37.77,-122.42&withinKm=5

# Graph traversal → Neo4j/Neptune
GET /api/v1/users/user_42/relationships/FAVORITED
The payoff

One entity, four query engines.

Every entity is mirrored to the right database for the question you’re asking, kept in sync with sub-second lag.

DynamoDB

Source of truth

experiences.get(id)
OpenSearch

Full-text search

"cozy loft downtown"
PostgreSQL

Geospatial · Aggregations · Ad-hoc

within 5km of me
Neo4j · Neptune

Graph traversal

friends-of-friends
II
The deploy

Then the infrastructure provisions itself.

Your config drives the deploy.

Data, compute, and 100+ pre-wired services come up together: auth, payments, search, scheduling, and more. The same codebase deploys as SaaS, multi-tenant, or single-tenant.

fig. ii·a14 services

Infrastructure, provisioned meticulously.

DynamoDBOpenSearchPostgreSQLEvent logNeo4jNeptuneEventBridgeSNSLambdaS3API GatewayIAMVPCKMS
Provisioned automatically when you deploy. Tenant-isolated, encrypted, with observability wired in.
fig. ii·b100+ primitives

Services, pre-wired cohesively.

AuthAdmin ConsolePaymentsReservationsSearchSchedulingFilesMessagingGamificationNotificationsMarketplaceSubscriptionsObservability
100+ primitives ship with the platform. REST and GraphQL APIs come for free.
III
Listen

Then you extend by listening.

When config isn’t enough, the platform meets you with events.

Subscribe to domain events, react to CDC streams, plug in webhook handlers — all without forking the codebase.

fig. iii·a01 / 03

Domain events

Every lifecycle transition emits an event: created, approved, expired. Subscribe via EventBridge to react in real time, audit, or feed downstream pipelines.

functory.entities-lifecycle-events
fig. iii·b02 / 03

CDC streams

Every entity change ships to a managed event log and an EventBridge rule. Build projections, aggregates, and your own analytics without polling.

functory.entities · .commands · .auth
fig. iii·c03 / 03

Webhooks

Fire HTTP endpoints on lifecycle transitions or fragment writes. Configure per entity, in code or in the Console.

.withHooks("notifyCRM")

Coda

See it run in your own AWS.

Request a walkthrough, or read the docs first.

We’ll deploy a tenant into your account and walk through the platform end-to-end.