---
title: "Architecture"
description: "Compose Playstack from portable domain contracts toward explicit framework and infrastructure edges."
tags: ["architecture","events","adapters"]
---

Playstack uses an inside-out package model. Portable contracts sit at the center; framework and infrastructure choices are attached at application-owned boundaries.

For example, your application can use the Storage package to save a file without putting S3-specific calls throughout its code. You choose and configure the storage provider in one place. A Nest adapter is only needed if you want that storage service supplied through Nest's dependency injection.

## Terms used in these guides

| Term | What it means |
| --- | --- |
| Domain package | The package that defines a capability, such as storage or accounts, without tying your application to a particular framework. |
| Adapter or provider | An implementation that connects a contract to a framework, database, or external service. |
| Composition root | The place in your application where you create services and connect their dependencies. |
| Operation context | Information about an operation, such as who initiated it and which request it belongs to. |
| Transactional event | An event whose handlers participate in the producing operation; failures can prevent that operation from completing. |
| Observational event | An event handled separately from the producing operation. Durable delivery requires explicit persistence and retry handling. |

You do not need every layer to get started. The [first storage example](/docs/getting-started) uses a domain package and an in-memory provider, with no framework or database setup.

## Dependency direction

```text
UI / HTTP / jobs
      |
framework adapters
      |
application composition
      |
domain packages + events
      |
database / queues / vendors
```

Dependencies point inward toward contracts. Runtime calls can flow outward through injected interfaces, but a domain package should not import the application, a framework adapter, or an infrastructure client.

## Event bridges

Event bridges are the standard seam for connecting domain activity to other capabilities. A bridge can publish to one or more sinks, transform an envelope for a broker, or remain in memory for tests. Events preserve operation context so downstream work can retain correlation and causation.

Keep the bridge in the application composition root. This makes fan-out, retries, observability, and delivery guarantees visible rather than implicit.

## Configuration

Adapters accept explicit configuration objects. Prefer an asynchronous module factory when configuration depends on application services or secrets. Pass schema names, client instances, table prefixes, queue names, and other deployment choices through those boundaries instead of relying on package globals.

## Testing

Test domain policy with in-memory ports. Test each adapter against its real boundary contract. Add a smaller number of application composition tests to prove that events, operation context, and configured clients cross package seams correctly.

This split keeps most tests fast while still exercising the places where packages meet.

## Composition references

- [Native and multi-account authentication](/docs/native-authentication): separate secure storage from device-wide refresh ownership and recovery.
- [Durable security decisions](/docs/durable-security-projections): commit revocation with audit intent, then repair downstream projections.
- [Data-only background sync hints](/docs/background-sync-hints): combine Devices and durable Delivery without an inbox or document payloads.

Each reference names what packages provide, what the host must own, and what its fixtures do not qualify.
