Building Realtime Infrastructure for the MyZubster Metaverse
he MyZubster Metaverse is evolving from a mostly synchronous web experience into a persistent shared environment where authenticated users can communicate, move between spaces, and see other participants in real time.
During our latest development cycle, we built and deployed the first production-oriented realtime foundation for this experience.
This article explains what we implemented, how we secured it, what we verified in the preview environment, and what comes next.
The goal
The Metaverse already had working REST endpoints for joining the world, moving characters, sending messages, and synchronizing state.
That approach was useful for the first version, but it depended on repeated polling.
For a more responsive multiplayer experience, we needed:
- persistent realtime connections;
- authenticated Socket.IO sessions;
- reconnect and resume support;
- presence management;
- private and shared channels;
- message persistence;
- operational metrics;
- database readiness checks;
- a deployment architecture compatible with Vercel;
- privacy-aware observability.
The result is the first version of the MyZubster realtime gateway.
The realtime transport
We added a Socket.IO server mounted on:
/realtime
It supports both WebSocket and HTTP polling transports.
The polling transport is useful as a compatibility fallback, while WebSocket provides the persistent connection required for realtime interaction.
The public health endpoint is available at:
GET /api/realtime/health
The preview deployment currently returns:
{
"success": true,
"status": "ok",
"transport": "socket.io",
"socketPath": "/realtime",
"presence": "local-fallback",
"privacy": "aggregate-only"
}
This confirms that:
- the application runtime is healthy;
- Socket.IO is attached correctly;
- the
/realtimetransport is available; - MongoDB is reachable;
- observability uses aggregate-only data;
- presence currently uses the local fallback store.
Secure socket authentication
Realtime connections are not trusted automatically.
Before connecting, an authenticated client requests a short-lived token from:
POST /api/realtime/token
The server signs a dedicated JWT containing only the data required by the realtime gateway.
The token includes:
- the user identifier;
- the user role;
- a realtime-specific purpose;
- an issuer and audience;
- a short expiration time;
- a correlation identifier for operational tracing.
The Socket.IO middleware verifies this token before accepting the connection.
Invalid, expired, or incorrectly scoped tokens are rejected.
Private keys are never accepted from clients, and application secrets are never included in frontend code.
Server-controlled authorization
Authentication identifies the user, but it does not automatically authorize access to every channel.
Every subscription and presence request passes through the server authorization layer.
For example:
const decision = await authorizeChannel({
channel: payload.channel,
userId: actor.userId,
role: actor.role
});
if (!decision.allowed) {
return ack({
ok: false,
error: decision.reason
});
}
This prevents the browser from deciding which private rooms or user channels it can access.
Each connected user is automatically assigned a private channel:
user:<userId>
Additional subscriptions are validated individually.
Presence and reconnect support
The gateway implements the main building blocks required for multiplayer presence:
presence.joinpresence.heartbeatpresence.leaverealtime.resume
When a connection is interrupted, the client can reconnect and ask the server to restore its authorized subscriptions.
The server validates every requested channel again before restoring it.
Presence entries also have a limited lifetime. If a client disappears without sending a clean disconnect event, stale entries can expire automatically instead of remaining visible forever.
Realtime messaging
The gateway also supports server-controlled message delivery.
Messages are:
- validated;
- authorized;
- persisted;
- checked for duplicate client identifiers;
- delivered to the permitted recipients;
- acknowledged to the sender.
A client message identifier makes retries safer. If the network fails after submission, the client can retry without necessarily creating duplicate messages.
We also introduced backpressure protection so that an overloaded realtime service can reject work cleanly instead of consuming unlimited resources.
Privacy-aware observability
Realtime systems need metrics, but observability must not become surveillance.
Our metrics are therefore aggregate-only.
We collect operational information such as:
- connection attempts;
- successful connections;
- rejected connections;
- active connection count;
- disconnects;
- message processing attempts;
- failures;
- duplicate messages;
- reconnect and resume activity;
- processing duration;
- Redis failures.
Sensitive identifiers are not written directly into operational logs. Where correlation is needed, identifiers are transformed into non-reversible references.
The metrics endpoint is also protected:
GET /api/realtime/metrics
It requires an authenticated administrator instead of being exposed publicly.
MongoDB preview isolation
The preview deployment received its own restricted MongoDB identity.
Instead of reusing a broad production credential, we created:
- a dedicated preview database user;
- a custom role;
- access limited to the preview database;
- permissions restricted to the required cluster;
- a branch-scoped Vercel secret.
The custom role inherits readWrite access only for:
myzubster_preview
This follows the principle of least privilege: a compromised preview deployment should not automatically gain access to unrelated databases.
The MongoDB URI and realtime signing secret were added as encrypted Vercel environment variables only for the development branch.
No credentials were committed to GitHub or exposed in frontend code.
Fail-closed database readiness
The realtime gateway waits for its required infrastructure before accepting authenticated socket connections.
If MongoDB is unavailable, the connection is rejected instead of continuing in an undefined state.
This is important because a realtime server that accepts users while its authorization or persistence layer is unavailable may create inconsistent data or bypass expected controls.
The health endpoint helped us confirm that the preview database connection is now operational.
Vercel preview deployment
The work was deployed to an isolated Vercel preview environment before merging it into the main branch.
This allowed us to verify:
- the application build;
- the Node runtime;
- the public health endpoint;
- MongoDB connectivity;
- environment-variable isolation;
- the Socket.IO transport path;
- privacy and fallback status.
The implementation is currently tracked in a dedicated pull request, keeping production unchanged until the remaining checks are completed.
What remains
The current health response reports:
presence: local-fallback
This means presence works inside a single running application instance, but it is not yet shared reliably across multiple instances.
The next infrastructure step is Redis.
Redis will provide:
- distributed presence state;
- coordination across application instances;
- cross-instance Socket.IO event delivery;
- more reliable horizontal scaling;
- better reconnect behavior during instance changes.
We also need to connect the Metaverse frontend directly to the new Socket.IO gateway. The current interface can continue using REST synchronization as a fallback while the realtime client is introduced progressively.
Next steps
Our immediate roadmap is:
- integrate the Socket.IO client into the Metaverse interface;
- preserve REST synchronization as a temporary fallback;
- add the Socket.IO Redis adapter;
- configure an isolated preview Redis instance;
- test two simultaneous clients;
- verify presence, chat, disconnect, and resume behavior;
- merge the pull request;
- run production smoke tests;
- monitor aggregate realtime metrics.
Final thoughts
Realtime infrastructure is more than opening a WebSocket.
A reliable implementation requires authentication, authorization, persistence, reconnect handling, presence expiration, backpressure, observability, secret management, and careful failure behavior.
With this release, MyZubster now has the server-side foundation required to turn its Metaverse into a genuinely shared environment.
The transport is online.
The database is connected.
The security boundaries are in place.
Now we can start connecting the world.
Follow the development of the MyZubster ecosystem:
- Website: https://www.myzubster.com
- GitHub: https://github.com/MyZubster-Ecosystem
Top comments (0)