491f495c66
- Updated `tibi-project-setup` skill to clarify project initialization goals and steps. - Improved `tibi-ssr-caching` skill to detail SSR architecture, responsibilities, and caching mechanisms. - Introduced `website-solution-architecture` skill for translating website requirements into coherent solutions. - Refined `AGENTS.md` to provide a structured roadmap for project development phases. - Added `ADMIN_ASSET_VERSION` to `api/config.yml.env` for asset versioning. - Updated SSR request flow and cache invalidation logic in `api/hooks/ssr/AGENTS.md`. - Removed obsolete `esbuild.config.admin.js` and integrated asset versioning into the main `esbuild.config.js`. - Adjusted `api/collections/content.yml` to utilize asset versioning for admin scripts.
214 lines
5.9 KiB
Markdown
214 lines
5.9 KiB
Markdown
---
|
|
name: realtime-and-live-workflows
|
|
description: Use tibi-server SSE channels for live website and admin workflows. Covers channel design, subscription hooks, replay/TTL/buffer behavior, permission boundaries, and when realtime fits a website project.
|
|
---
|
|
|
|
# realtime-and-live-workflows
|
|
|
|
## When to use this skill
|
|
|
|
Use this skill when:
|
|
|
|
- A website or admin feature needs live updates
|
|
- You want SSE-based notifications, preview refreshes, status feeds, or dashboards
|
|
- Hooks or jobs should push messages to connected clients
|
|
- You need to decide whether realtime is actually appropriate for the feature
|
|
|
|
## Goal
|
|
|
|
The goal is to model realtime as a deliberate workflow, not as a random event stream.
|
|
|
|
On this stack, realtime means:
|
|
|
|
- SSE transport
|
|
- in-memory per-project channels
|
|
- server-side send from hooks/jobs
|
|
- subscription endpoints implemented in hooks
|
|
|
|
## Source of truth
|
|
|
|
Use these sources when implementing or reviewing realtime behavior:
|
|
|
|
- `tibi-server/docs/07-realtime.md`
|
|
- `tibi-server/docs/11-jobs.md`
|
|
- the relevant hook files under `api/hooks/`
|
|
|
|
## Core architecture
|
|
|
|
tibi-server realtime is based on per-project in-memory pub/sub channels.
|
|
|
|
Important characteristics:
|
|
|
|
- channels are created on demand
|
|
- channels are isolated per project
|
|
- the transport is SSE, not WebSockets
|
|
- messages are not durable across restarts
|
|
- hooks subscribe, hooks or jobs send
|
|
|
|
This makes realtime useful for live UX, but not for durable messaging.
|
|
|
|
## Good use cases for website projects
|
|
|
|
Good fits:
|
|
|
|
- live status or progress streams
|
|
- lightweight admin notifications
|
|
- system messages pushed from jobs
|
|
- preview or refresh signals after mutations
|
|
- dashboards with current in-memory activity
|
|
|
|
Weak fits:
|
|
|
|
- business-critical guaranteed delivery
|
|
- cross-instance distributed eventing
|
|
- durable queue semantics
|
|
- workflows that require replay beyond a bounded in-memory buffer
|
|
|
|
## Subscription design
|
|
|
|
Realtime subscriptions should be exposed intentionally through dedicated read hooks that hold the SSE connection open.
|
|
|
|
Design the endpoint around:
|
|
|
|
- who may subscribe
|
|
- which channel names exist
|
|
- what event shape clients receive
|
|
- how replay and freshness should work
|
|
|
|
Do not expose a generic raw event hose unless the project truly needs that.
|
|
|
|
## Channel options that matter
|
|
|
|
When modeling realtime behavior, decide these explicitly:
|
|
|
|
- `bufferSize`
|
|
- `onFull`
|
|
- `messageTTL`
|
|
- `lastN`
|
|
- `maxAge`
|
|
|
|
These are product decisions, not low-level afterthoughts.
|
|
|
|
### Buffer size
|
|
|
|
Use a larger buffer only when reconnecting clients should receive some recent history. Do not overestimate it as persistence.
|
|
|
|
### On-full behavior
|
|
|
|
- `drop-oldest` favors receiving the newest state, even if some history is lost
|
|
- `drop-newest` preserves older pending messages for the subscriber and skips the new one
|
|
|
|
For most live UI use cases, `drop-oldest` is the more natural choice.
|
|
|
|
### Replay and freshness
|
|
|
|
Use `lastN` or `maxAge` only when reconnecting clients genuinely benefit from recent context.
|
|
|
|
For notification-like channels, some replay can help.
|
|
For pure live status indicators, it may be better to show only new events.
|
|
|
|
## Permission boundaries
|
|
|
|
Channels do not carry independent auth rules. Access is controlled by the hook/collection permission layer that exposes the SSE endpoint.
|
|
|
|
That means:
|
|
|
|
- secure the subscription endpoint, not just the client code
|
|
- do not assume channel names themselves protect access
|
|
- be explicit about who may connect and what data is safe to send
|
|
|
|
## Event design
|
|
|
|
Prefer small, explicit event shapes.
|
|
|
|
Good event payloads usually include:
|
|
|
|
- event `type`
|
|
- relevant identifier
|
|
- minimal status or message fields
|
|
- timestamp when useful
|
|
|
|
Avoid pushing whole documents unless the live client truly needs them.
|
|
|
|
## Hooks vs. jobs
|
|
|
|
Use hooks to send events when changes happen immediately in response to requests.
|
|
|
|
Use jobs to send events when the trigger is scheduled or background-driven.
|
|
|
|
Typical patterns:
|
|
|
|
- hook sends `content-updated`
|
|
- job sends `maintenance-warning`
|
|
- hook sends `import-finished`
|
|
- job sends `daily-report-ready`
|
|
|
|
## Operational limits
|
|
|
|
This realtime system is intentionally lightweight.
|
|
|
|
Important limits:
|
|
|
|
- messages are lost on server restart
|
|
- no cross-server synchronization
|
|
- no durable backlog
|
|
- slow subscribers can miss messages due to ring-buffer behavior
|
|
|
|
If the feature cannot tolerate these limits, this realtime system is the wrong abstraction.
|
|
|
|
## Recommended modeling patterns
|
|
|
|
### Live admin notifications
|
|
|
|
Recommended shape:
|
|
|
|
- authenticated SSE endpoint
|
|
- narrow event schema
|
|
- optional short replay via `lastN`
|
|
|
|
### Preview refresh signal
|
|
|
|
Recommended shape:
|
|
|
|
- hook emits lightweight invalidation or refresh event
|
|
- client decides whether to refetch
|
|
- do not stream full content when a simple signal is enough
|
|
|
|
### Scheduled status feed
|
|
|
|
Recommended shape:
|
|
|
|
- job emits events to a system channel
|
|
- UI listens and renders current status
|
|
- TTL keeps stale messages from resurfacing after reconnect
|
|
|
|
## Anti-patterns
|
|
|
|
- Using realtime as a replacement for persistence
|
|
- Publishing sensitive data because “the UI needs it quickly”
|
|
- Creating one generic catch-all channel for unrelated features
|
|
- Ignoring replay/TTL/buffer behavior and assuming delivery guarantees
|
|
|
|
## Verification checklist
|
|
|
|
After adding realtime behavior, verify all of these:
|
|
|
|
1. The subscription endpoint is permissioned correctly.
|
|
2. The event shape is explicit and minimal.
|
|
3. Replay/TTL/buffer settings match the intended UX.
|
|
4. Disconnect/reconnect behavior is acceptable.
|
|
5. The feature still behaves sensibly after a server restart.
|
|
6. `yarn validate` stays clean.
|
|
|
|
## What an LLM should inspect first
|
|
|
|
When asked to add realtime to this starter, inspect in this order:
|
|
|
|
1. `tibi-server/docs/07-realtime.md`
|
|
2. the hook that should expose or emit the events
|
|
3. whether a job is also part of the workflow
|
|
4. the permission boundary of the SSE endpoint
|
|
5. the exact event contract the client needs
|
|
|
|
This prevents building live features with unclear delivery or security assumptions.
|