-
Notifications
You must be signed in to change notification settings - Fork 42
migration presence storage
Public APIs: Stable. Presence helpers, filters, actions, REST/Heartbeat payloads and epoch-millisecond units keep their existing shapes. Integrations should call the helpers rather than read or write the old option directly.
The current site's openstation_presence table replaces the shared
_desktop_mode_presence option. Existing keys, tables and timestamp formats in
other features are unchanged. The table has one primary-keyed row per user, an
index on last_seen_ms, and an internal away-intent timestamp so delayed activity
cannot undo a later explicit "set away" request.
Creation and import use a site/database-scoped connection lock on MySQL/MariaDB.
SQLite provides a compatibility no-op; the import remains idempotent. Imports
merge timestamps without lowering newer destination values. The non-autoloaded
openstation_presence_storage option records ready, completed_at_ms and legacy_digest only
after verification succeeds. Failed creation, reads, imports or verification
leave migration pending and retryable on the next request. Setup failures are
memoized for the current request; lock attempts do not wait. If installation is unavailable, helpers
retain the legacy read/write path; that temporary fallback retains the original
shared-row contention until setup succeeds. Pruning skips work while setup fails.
An established table's write failure returns failure rather than dual-writing.
For five minutes after cutover, admin, Heartbeat and presence REST requests import legacy records whose heartbeat is newer than the cutover timestamp. This bridges requests that started on the old code. A digest skips unchanged legacy maps. Initial import preserves away state, but late legacy zero-activity records never override newer activity: an old idle heartbeat cannot be distinguished from an explicit away request. Deployments must finish replacing old workers within this interval; a worker running older code beyond it can have a presence update ignored until the user's next current heartbeat. New code never dual-writes after successful migration.
The legacy option remains untouched for recovery. Once the bridge closes it is no longer consulted. Retained data can include old user timestamps; it is not a live presence feed. Daily pruning applies to the new table only.
Back up the database before upgrading and test the upgrade on a populated clone. Rolling back code reads the retained legacy option again. Presence may look stale or offline until fresh heartbeats arrive; uploaded files, desktop content and other settings are unaffected. Do not drop the new table merely to roll back.
After a rollback that lasted beyond the five-minute bridge, before upgrading
again, delete only the openstation_presence_storage checkpoint for each affected
site using the WordPress Options API. This reruns the idempotent import against the
retained table and starts a new bridge. Do not reset the general migration version
or rename _desktop_mode_presence.
Multisite migrates each site's records separately as it is accessed. Removing a subsite includes its presence table in the existing Core table-cleanup integration. No uninstall policy is changed by this migration.
Schema changes require a versioned schema migration before changing the ready-check
or required columns. The current checkpoint describes only this initial table shape;
CREATE TABLE IF NOT EXISTS is not an alteration mechanism.
This wiki is generated from the docs/ directory — edits made here are overwritten by the next sync.
To change a page, open a pull request against docs/.
Guides
- Development guide
- Releasing openstation
- Agents security model
- API Index
- The App Framework — a window in one PHP file
- Architecture
- Bridge protocol — wiring overview
- <os-*> component reference
- Data model — where OpenStation keeps its data
- Native Desktop Host — Experimental
- Desktop themes
- Dock customization — two registries, one mental model
- The event-driven framework
- Files on the Desktop
- Folder sharing
- Getting Started
- Hooks Reference
- Icons
- JavaScript Reference
- The Living Tree — algorithm definition
- Window-scoped MIO
- Mio
- Mobile — the phone layer
- Multisite
- Native Windows & Framework Interop
- OpenStation Network
- Plugin compatibility layer
- Progressive Web App (PWA)
- Station Home
- Using openstation from your own plugin
- Workspaces
Migration notes
- Migration: built-in activity channels move to the os/ namespace
- Migration — Code Blue becomes an App Framework app
- Migration — AI comment scoring leaves core
- Migration: window, wallpaper and widget bundles load on demand
- Migration — Posts, Pages, Users, User Edit, Plugins and Comments become App Framework apps
- Migration — the navigation model
- Migration — OpenStation Preferences becomes an App Framework app
- Performance settings move to Extended options
- Presence storage migration
- Migration — the Recycle Bin becomes an App Framework app
- Migration — the shell boots from its own screen
- Migration — Station Home becomes an App Framework app
- Migration: a native window's tabs move to the window chrome
- Migration — WP Explorer becomes the my-wordpress app
- Migration — WordPress package globals are no longer ambient
More
All examples
- AI Agents — extend and invoke from a plugin
- wp.os.ai.ask() — programmatic AI Copilot
- Tune the AI model config
- App layout recipes
- Custom arrange-menu action
- Open a child window its owner can't cover
- Style a specific admin page inside the iframe
- Code Blue — register your plugin's log file
- Open a file in the Code editor (deep-link from any window)
- Connect to a window — title-bar button + iframe pub/sub
- Content changes — live-refresh every window listing your type
- Custom window chrome (Experimental)
- Register a custom unfocused-window effect
- Example: render a data table
- Real file storage — react to uploads, gate policy, share from PHP
- React to a window being set free onto the real desktop
- Cross-window devtools — instrumentation primitives
- Add a dock item with a badge
- Decorate the dock without forking the renderer
- Replace the dock rail entirely
- Retune the Drafts widget's AI writing assistant
- Gate OpenStation by role
- Iframe-initiated window opens
- Build a feed reader without the bookkeeping
- Inject data into openStationConfig
- Render a list without losing clicks — renderKeyedList()
- Example: layout primitives (body → panel → row → col)
- Use <os-*> components from a plugin that ships as a zip
- Restyle and drive Mio
- Repairable form edits with MIO
- Register a window companion
- Pin your app to the phone tab bar, and react to the mode
- Add an action that works on a whole selection
- WP Explorer — custom post types and their folder
- WP Explorer — add a column to the list view
- Add an action button to a WP Explorer preview pane
- Example: native Posts window
- Example: native window with tabs
- Native windows
- Customize note → post conversion
- Send a notification
- OAuth relay — connect to an external service
- Ship a window as an .os.php app
- OS-file drop
- <os-flyout> — window-scoped sliding card
- Plugins window — extras
- Track who's around — wp.os.presence
- Example: progress bar
- PWA install — surface your own button
- React to window events
- Example: extend the Trash
- Register a slash-command
- Register a desktop theme from a plugin
- Register a game
- Example: register a desktop icon (Jorvy)
- Register a wallpaper
- Register a widget
- Related entities — extend the title bar's "Related" menu
- The native-window render ctx
- Revisions in their own window — extend or redirect "View revisions"
- Programmatic folder sharing
- Share state across multi-bundle plugins — wp.os.createSharedStore()
- Example: loading spinner
- Add an opt-in card to Station Home
- Observe stored-file cleanup failures
- Accept drops on your desktop icon
- Give a tile two icons, one per state
- Add a row to a window's ⋯ menu
- Example: window activity & the status ring
- Window controls
- Subscribe to window lifecycle events
- Window links — relate windows and restyle the ties (Experimental)
- Window loading state — spinner overlay & ready signal
- Show a banner at the top of a window
- Pulse a window's icon — Window.requestAttention()
- Register a custom window reveal
- Window slots
- Window themes
- Native window with bundle-bound config
- Place something where the user can reach it — wp.os.workArea
- Ship a workspace template