Skip to content

Single app vs composition

Default: single app. Codenames, Chess, Tic-Tac-Toe, polls, whiteboards — all single apps. One synced-store schema with the right visibility tiers handles role-specific or hidden state without splitting.

Compose into multiple apps only when at least one holds:

  1. Sub-experiences must be private to a subset of the parent's users (e.g. a private Discord channel inside a server). Synced-store's per-user privacy is per-instance, so scoping the child as its own instance beats encoding per-channel ACLs in one giant schema.
  2. The sub-app is a reusable, independently-publishable piece (e.g. a "threaded chat" primitive multiple parents could embed).
  3. Lifecycles diverge sharply — parent persists across long timescales (server membership, tournament season) while children are created / used / archived independently (channels, individual matches). A March-Madness tournament parent that pairs players into independent chess matches is the canonical case: bracket / scheduling / leaderboard live in the parent, each match is its own <poe-app> instance reusing an existing single-app game unchanged.

Not enough reasons: "cleaner architecture", different screens / modes / roles of the same experience, splitting lobby + game. Routes inside one app are simpler than cross-app coordination.

How composition works: the manager (platform-owned root) renders any creator app via <poe-app type-id="..." instance-id="...">. Any creator app can also embed children via the same element (registerPoeAppElement from poe-apps-sdk/v1/client.js). Each child gets its own synced-store instance scoped to the chosen instance-id.

<poe-app> resolves children by type-id, which only exists once the child has been published. When composing: publish each child first, capture type-id from app-platform apps list, wire into parent as constants, then republish the parent.

If the prompt is ambiguous, briefly describe the single-app vs composed plan and confirm before scaffolding.