- 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.
5.9 KiB
name, description
| name | description |
|---|---|
| realtime-and-live-workflows | 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.mdtibi-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:
bufferSizeonFullmessageTTLlastNmaxAge
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-oldestfavors receiving the newest state, even if some history is lostdrop-newestpreserves 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:
- The subscription endpoint is permissioned correctly.
- The event shape is explicit and minimal.
- Replay/TTL/buffer settings match the intended UX.
- Disconnect/reconnect behavior is acceptable.
- The feature still behaves sensibly after a server restart.
yarn validatestays clean.
What an LLM should inspect first
When asked to add realtime to this starter, inspect in this order:
tibi-server/docs/07-realtime.md- the hook that should expose or emit the events
- whether a job is also part of the workflow
- the permission boundary of the SSE endpoint
- the exact event contract the client needs
This prevents building live features with unclear delivery or security assumptions.