Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# TeamPlay Agent Notes

TeamPlay is a full-stack signal ORM built on top of ShareDB. The main user-facing API is the object-tree signal model: `$`, `$.collection[id]`, `sub()`, `useSub()`, and `Signal<SchemaType>`.

Before making nontrivial changes, read:

- [architecture.md](./architecture.md) for the monorepo layout and runtime architecture.
- [typing-architecture.md](./typing-architecture.md) for the TypeScript and generated type architecture.
- [tasks.md](./tasks.md) for the current backlog, known priorities, and verification guidance. Treat it as context unless the user explicitly asks you to work through backlog items.

Basic working rules:

- Preserve public runtime APIs and the object-tree UX unless the user explicitly asks for a product change.
- Prefer small, focused changes with nearby tests. Run focused tests while iterating and broader tests before commits.
- Keep runtime behavior and TypeScript behavior aligned; update the architecture docs when the direction changes.
- Do not invest in broad Compat rewrites. Compat is temporary; touch it only when needed to preserve behavior.
- Work only in this project. Neighboring folders mentioned in old notes are not available in this environment.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
553 changes: 553 additions & 0 deletions architecture.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs-theme/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export * from '@rspress/core/theme-original'

export function Layout () {
return (
<div className="project-layout">
<ProjectSidebar activeProject="teamplay" />
<div className="project-layout-content">
<div className='project-layout'>
<ProjectSidebar activeProject='teamplay' />
<div className='project-layout-content'>
<DefaultLayout />
</div>
</div>
Expand Down Expand Up @@ -58,16 +58,16 @@ interface ProjectSidebarProps {

function ProjectSidebar ({ activeProject }: ProjectSidebarProps) {
return (
<nav className="project-sidebar">
<nav className='project-sidebar'>
{PROJECTS.map((project) => (
<a
key={project.id}
href={project.url}
className={`project-sidebar-button project-sidebar-button--${project.id} ${project.id === activeProject ? 'active' : ''}`}
aria-label={project.name}
>
<span className="project-sidebar-button__text">{project.label}</span>
<span className="project-sidebar-button__tooltip">{project.name}</span>
<span className='project-sidebar-button__text'>{project.label}</span>
<span className='project-sidebar-button__tooltip'>{project.name}</span>
</a>
))}
</nav>
Expand Down
11 changes: 10 additions & 1 deletion docs/api/query-signals.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ A signal containing an array of IDs for the documents in the query result.
const userIds = $activeUsers.ids.get()
```

### extra

A signal containing extra query metadata returned by the server, such as count metadata.

```javascript
const extra = $activeUsers.extra.get()
```

### getIds()

Returns an array of ids for the query results.
Expand Down Expand Up @@ -64,4 +72,5 @@ for (const $user of $activeUsers) {

- Query signals are reactive. Changes to the underlying data or to the query result will automatically update components using the query signal.
- The documents within a query signal are themselves signals, allowing for nested reactivity.
- For public documents in query results, `_id` is available in `get()` results and matches the document id.
- For public documents in query results, `_id` is available in `get()` results and matches the document id.
- `ids` and `extra` are reserved metadata properties on query signals. Use the collection path, such as `$.users['ids']`, when you need a document whose id has one of those names.
41 changes: 24 additions & 17 deletions docs/guide/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ TeamPlay can run in three different modes. Pick the one that matches your needs

## Modes

- **In-memory (default)**: in-memory only, no server, no persistence across reloads.
- **In-memory Mode (default)**: in-memory only, no server, no persistence across reloads.
- **Offline Mode**: client-only with local persistence (browser or React Native), no server.
- **Server Sync**: real-time synchronization with a backend server.
- **Server Sync Mode**: real-time synchronization with a backend server.

## In-memory Mode

Expand All @@ -27,22 +27,17 @@ await connect()

See [Offline Mode](/guide/offline-mode) for details and React Native setup.

## Synchronization with Server
## Server Sync Mode

To enable synchronization with the server, follow these steps:

### Client Setup

Enable the connection on the client somewhere early in your client app:
To sync data with a server, connect from the client somewhere early in your app startup:

```js
import connect from 'teamplay/connect'

await connect()
```

### Server Setup

On the server, you need to create the TeamPlay backend and then create a connection handler for WebSockets:
On the server, create the TeamPlay backend and attach its WebSocket upgrade handler to your Node HTTP server:

```js
import { createBackend, initConnection } from 'teamplay/server'
Expand All @@ -52,17 +47,29 @@ const { upgrade } = initConnection(backend)
server.on('upgrade', upgrade) // Node's 'http' server instance
```

## Database Configuration
## Production Setup

For development, no extra database setup is needed. If `MONGO_URL` is not set, TeamPlay stores server data in an SQLite file named `local.db` in the root of your project.

You can still write MongoDB-style queries and aggregations in this local setup. TeamPlay emulates that query behavior with [`mingo`](https://github.com/kofrasa/mingo).

For production, configure the services your deployment needs:

- `MONGO_URL`: use [MongoDB](https://mongodb.com) instead of the local SQLite file.
- `REDIS_URL`: required when you run multiple server instances, so real-time updates can be coordinated through [Redis](https://redis.io).

:::note
TeamPlay's `createBackend()` is a wrapper around creating a [ShareDB backend](https://share.github.io/sharedb/api/backend). If you need lower-level control, you can create a ShareDB backend yourself and pass it to `initConnection()`. `ShareDB` is re-exported from `teamplay/server`, so you can import it as `import { ShareDB } from 'teamplay/server'`.
:::

By default no extra database setup is needed and the data is gonna be saved into an SQLite file `local.db` in the root of your project.
## Optional ORM Setup

You can still use the MongoDB query syntax with aggregations which is emulated using [`mingo`](https://github.com/kofrasa/mingo).
TeamPlay works without an ORM setup: you can use signals, subscriptions, and real-time sync directly. When your app starts to have named collections such as users, games, orders, or events, the ORM gives you a conventional place to define document schemas, model methods, access rules, and server aggregations.

- For production use, it's recommended to use [MongoDB](https://mongodb.com). It will be automatically used if you set the environment variable `MONGO_URL`.
- When deploying to a cluster with multiple instances, you also have to provide the environment variable `REDIS_URL` ([Redis](https://redis.io)).
To use the full ORM features, follow the [ORM Quick Start](/orm/index#quick-start). It shows the extra setup for the `models/` folder, the Babel plugin, and the shared `models.setup.ts` file used by both client and server.

:::note
TeamPlay's `createBackend()` is a wrapper around creating a [ShareDB's backend](https://share.github.io/sharedb/api/backend). You can instead manually create a ShareDB backend yourself and pass it to `initConnection()`. `ShareDB` is re-exported from `teamplay/server`, you can get it as `import { ShareDB } from 'teamplay/server'`.
StartupJS apps can skip the manual ORM setup. StartupJS configures model loading and initializes TeamPlay models automatically.
:::

Now that you have TeamPlay installed and configured, you're ready to start using it in your application!
Loading
Loading