Implement tab-scoped runs pagination state
This commit is contained in:
parent
dce67ea9e3
commit
c834c3c254
6 changed files with 444 additions and 62 deletions
15
AGENTS.md
15
AGENTS.md
|
|
@ -27,7 +27,7 @@ The views are pure functions data in -> html out.
|
|||
By only using data: mode morph and always targeting the main element of the document the API can be massively simplified. This avoids having the explosion of endpoints you get with HTMX and makes reasoning about your app much simpler.
|
||||
|
||||
- we only have a single render function per page
|
||||
By having a single render function per page you can simplify the reasoning about your app to view = f(state). You can then reason about your pushed updates as a continuous signal rather than discrete event stream. The benefit of this is you don't have to handle missed events, disconnects and reconnects. When the state changes on the server you push down the latest view, not the delta between views. On the client idiomorph can translate that into fine grained dom updates.
|
||||
By having a single render function per page you can simplify the reasoning about your app to view = f(state). In immediate-mode terms the server is re-running the whole page render against the latest state, like a game loop, rather than trying to patch the view incrementally by hand. You can then reason about your pushed updates as a continuous signal rather than discrete event stream. The benefit of this is you don't have to handle missed events, disconnects and reconnects. When the state changes on the server you push down the latest view, not the delta between views. On the client idiomorph can translate that into fine grained dom updates.
|
||||
|
||||
|
||||
- any database change -> re render all connected users with 200ms throttle
|
||||
|
|
@ -52,11 +52,18 @@ The views are pure functions data in -> html out.
|
|||
Actions should not update the view via patch elements. This is because the changes they make would get overwritten on the next render-fn that pushes a new view down the updates SSE connection. However, they can still be used to update signals as those won't be changed by elements patch. This allows you to do things like validation on the server.
|
||||
|
||||
- Stateless views
|
||||
The only way for actions to affect the view returned by the render-fn running in a connection is via the database. The ensures CQRS. This means there is no connection state that needs to be persisted or maintained (so missed events and shutdowns/deploys will not lead to lost state). Even when you are running in a single process there is no way for an action (command) to communicate with/affect a view render (query) without going through the database.
|
||||
The state passed to a render-fn should be thought of as `{persistent db state, ephemeral tab state}`. The database is the source of truth for durable application state. Ephemeral tab state is server-owned in-memory state keyed by tab id for non-persistent UI concerns like pagination, sort order, expanded panels, wizard step, etc.
|
||||
|
||||
This tab state is not a client signal and not a database row. It exists so that non-persistent actions can still participate in the same immediate-mode render model: an action mutates server-side tab state, then the render-fn re-runs with the new `{db state, tab state}` and sends the latest full page view.
|
||||
|
||||
Tab state must be scoped to a single tab/SSE connection, initialized when the long-lived page stream connects, cleaned up when that stream closes, and periodically reaped for stale entries so memory cannot grow without bound.
|
||||
|
||||
Nothing else should influence a render. Do not smuggle view state through ad hoc globals, connection-local mutable objects, or client-owned signals that the server "trusts". If state should survive reconnects, restarts, or be shared across users, it belongs in the database. If it is purely per-tab and ephemeral, it belongs in tab state.
|
||||
|
||||
- CQRS
|
||||
Actions modify the database and return a 204 or a 200 if they patch-signals.
|
||||
Render functions re-render when the database changes and send an update down the updates SSE connection.
|
||||
Persistent actions modify the database and return a 204 or a 200 if they patch-signals.
|
||||
Ephemeral actions modify tab state and return a 204 or a 200 if they patch-signals.
|
||||
Render functions re-render from the combined `{db state, tab state}` and send an update down the updates SSE connection.
|
||||
|
||||
- Work sharing (caching)
|
||||
Work sharing is the term I'm using for sharing renders between connected users. This can be useful when a lot of connected users share the same view. For example a leader board, game board, presence indicator etc. It ensures the work (eg: query and html generation) for that view is only done once regardless of the number of connected users. The simplest way to do this is to recalculate and cache values after after a batch has been run.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue