Building MyZubster World: The Metaverse Infrastructure We Have Implemented

Leader 1 2 41
calendar_today agoschedule9 min read

Building MyZubster World: The Metaverse Infrastructure We Have Implemented
MyZubster is evolving from a marketplace into a circular digital ecosystem connecting verified identities, virtual communities, knowledge sharing, real-world projects, and privacy-conscious services.
The virtual layer of this ecosystem is called MyZubster World.
It is still experimental. We are not presenting it as a finished metaverse, but we have already implemented the technical foundations for identity, rooms, access control, invitations, scheduling, moderation, stage permissions, communication, and persistent progress.
This article explains what currently works and what we want to build next.
Explore MyZubster
These links include readable UTM parameters that can be monitored through Vercel Analytics.
Enter MyZubster World:
https://www.myzubster.com/metaverse?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=enter_metaverse
Explore the marketplace:
https://www.myzubster.com/marketplace?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=explore_marketplace
Learn how MyZubster works:
https://www.myzubster.com/come-funziona?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=how_it_works
Explore the source code:
https://github.com/MyZubster-Ecosystem/myzubster?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=github_repository
The architecture
MyZubster World currently uses:
React frontend

Express API

Authentication and authorization

Metaverse services

MongoDB persistence

Vercel deployment and analytics
The frontend handles rendering, interaction, room controls, movement, forms, chat presentation, and user feedback.
The backend remains authoritative for:

  • Character identity
  • Room access
  • Session lifecycle
  • Private invitations
  • Capacity
  • Scheduling
  • Participant moderation
  • Stage permissions
  • Room chat
  • Message moderation
    The browser can request an operation, but only the server can approve it.
    Verified character identity
    A name stored in localStorage cannot be treated as a verified identity because it can be modified through browser developer tools.
    For authenticated users, the backend retrieves the canonical character from MongoDB:
    const character = await MetaverseCharacter.findOne({
    accountUserId: userId,
    worldId: WORLD.id,
    identityStatus: "account-linked"
    });
    The frontend replaces outdated local data with the server-provided identity.
    MyZubster distinguishes between:
    Guest character
    └── Temporary and unverified

Account-linked character
└── Persistent and verified
A client-submitted character name, GitHub username, or MYZ-ID is never considered proof of identity.
Expired-session recovery
We implemented recovery for expired JWT sessions:
if (error.status === 401) {
localStorage.removeItem("myzubster-token");
setAuthenticated(false);
setMessage(

"Session expired. Please sign in again."

);
}
The interface can now recover from an invalid authentication state instead of repeatedly sending an expired token.
The login system also preserves private-room invitation URLs, allowing users to authenticate and return to the original invitation.
Persistent exploration progress
Verified characters can discover landmarks inside MyZubster World.
Progress is recorded server-side:
await MetaverseCharacter.findOneAndUpdate(
{

accountUserId: userId,
worldId: WORLD.id,
identityStatus: "account-linked"

},
{

$addToSet: {
  "missionProgress.visitedLandmarks":
    landmarkId
}

}
);
Using $addToSet prevents duplicate landmark records.
Progress survives browser refreshes, local-storage deletion, new sessions, and device changes.
Shared presence
The current world supports:

  • Player entry and exit
  • Online-character discovery
  • Position synchronization
  • Temporary chat
  • Emotes
  • Reconnection states
  • Presence expiration
    The client retrieves shared state through an incremental synchronization request:
    const result = await syncMetaverse(
    sessionId,
    cursor
    );
    The cursor allows the server to return only data that appeared after the previous synchronization.
    Why polling is currently used
    MyZubster runs in a serverless environment.
    Long-lived in-memory connections can be unreliable when requests are distributed between stateless instances. A connection owned by one instance may not exist on another.
    The current model uses MongoDB as shared state:
    Client A ─┐
        ├── API instances ── MongoDB
    

    Client B ─┘
    This is a pragmatic solution for the current stage. A dedicated realtime infrastructure remains on our roadmap.
    Server-authoritative rooms
    MyZubster World supports persistent virtual rooms with a controlled lifecycle:
    Draft

    Published

    Scheduled

    Live

    Ended

    Archived
    Allowed transitions are defined on the server:
    const ROOM_TRANSITIONS = {
    draft: new Set(["published"]),
    published: new Set([ "scheduled", "live" ]),
    scheduled: new Set(["live"]),
    live: new Set(["ended"]),
    ended: new Set(["archive"]),
    archive: new Set()
    };
    A modified client cannot move a completed room back into a live state.
    Room access policies
    Rooms support three access policies:
    Public
    Authenticated
    Private
    Public rooms can be discovered without authentication.
    Authenticated rooms require a valid MyZubster account.
    Private rooms require explicit authorization and are excluded from public room discovery.
    Unauthorized requests receive a generic 404 response. This limits the amount of information revealed about private spaces.
    Host controls
    Room hosts can currently:

  • Create a room draft
  • Configure its access policy
  • Set capacity
  • Configure its stage policy
  • Select an optional session date
  • Publish the room
  • Create a session
  • Start the session
  • Cancel a scheduled session
  • End a live session
  • Generate and revoke private invitations
  • Remove or block participants
  • Restore blocked participants
  • Approve speaking requests
  • Revoke stage access
  • Delete room-chat messages
    Every operation is verified on the backend:
    function canManage(
    actorUserId,
    actorRole,
    hostUserId
    ) {
    return Boolean(
    actorUserId &&
    (
    actorRole === "admin" ||
    String(actorUserId) ===
      String(hostUserId)
    

    )
    );
    }
    Frontend button visibility is used for usability, not authorization.
    Capacity controls
    Hosts can configure a room capacity between 1 and 500 participants.
    The server rejects values outside this range.
    A new participant cannot enter a full room, while someone already registered in the session can reconnect without being counted again.
    Capacity and other structural settings become locked once the session has been scheduled.
    Secure private-room invitations
    Private-room links are generated using cryptographically secure randomness:
    const code = crypto
    .randomBytes(24)
    .toString("base64url");
    The raw code is shown to the host only when created. The database stores its SHA-256 hash:
    const hash = crypto
    .createHash("sha256")
    .update(code)
    .digest("hex");
    An invitation:

  • Expires after 24 hours
  • Can be redeemed once
  • Can be revoked immediately
  • Is replaced when a new invitation is created
  • Cannot override the blocklist
  • Survives the authentication redirect
  • Is never stored in plain text
    Atomic invitation redemption
    One-time invitations must remain one-time even when multiple requests arrive together.
    The invitation is consumed through one conditional MongoDB operation:
    const claimedRoom =
    await VirtualRoom.findOneAndUpdate(
    {
    roomId,
    accessPolicy: "private",
    inviteTokenHash: suppliedHash,
    inviteExpiresAt: {
      $gt: new Date()
    },
    blockedUserIds: {
      $ne: actorUserId
    }
    

    },
    {

    $addToSet: {
      allowedUserIds: actorUserId
    },
    $set: {
      inviteTokenHash: null,
      inviteExpiresAt: null
    }
    

    },
    {

    new: true
    

    }
    );
    The same atomic operation checks the code, verifies expiration, checks the blocklist, authorizes the account, and destroys the invitation.
    Only one concurrent request can succeed.
    Privacy-conscious participant moderation
    Hosts receive a participant list containing an opaque session reference, character name, and archetype:
    {
    "ref": "8af39a3d42b781b821003c14",
    "characterName": "ExampleCharacter",
    "archetype": "explorer"
    }
    Internal account IDs are not returned.
    The opaque reference is scoped to a specific session:
    function moderationParticipantRef(
    sessionId,
    userId
    ) {
    return sha256(
    ${sessionId}:${userId}
    ).slice(0, 24);
    }
    Hosts can remove participants or remove and block them.
    When a private-room participant is blocked, their authorization is also removed so they cannot immediately re-enter.
    Blocklist management
    Hosts can inspect blocked characters without receiving their internal account IDs.
    Blocklist references are scoped to the room:
    function blockedParticipantRef(
    roomId,
    userId
    ) {
    return sha256(
    blocklist:${roomId}:${userId}
    ).slice(0, 24);
    }
    The host can restore access for a selected character.
    Unblocking does not automatically add the user back to a private room. The user must receive another valid invitation.
    Moderated stage
    Rooms can use two stage policies:
    Host only
    Host-approved speakers
    In a host-approved room, a joined participant can request permission to speak.
    The full workflow is:
    Request access

    Host review

    Approve or reject

    Participant receives updated status
    Participants can:

  • Request permission to speak
  • Cancel a pending request
  • Leave the stage voluntarily
    Hosts can:
  • Inspect pending requests
  • Approve or reject requests
  • See current speakers
  • Revoke stage permission
    Account IDs remain hidden throughout the process.
    Session scheduling
    Hosts can configure an optional date and time.
    The browser converts the local date into an ISO timestamp:
    const scheduledFor =
    new Date(localValue).toISOString();
    The server rejects invalid or past dates.
    A session cannot start before the configured date, even if someone manually calls the API.
    Rooms without a date can start immediately.
    Safe cancellation
    A scheduled session can be cancelled before starting.
    Cancellation:
  • Archives the scheduled session
  • Returns the room to the published state
  • Restores access to its settings
  • Allows the host to correct and reschedule
  • Generates a lifecycle event
    Starting and cancelling use conditional database updates. If both commands arrive simultaneously, only one can claim the scheduled state.
    Automatic room synchronization
    Room pages retrieve authoritative state every five seconds.
    Without reloading, users can see:
  • Session start
  • Session cancellation
  • Participant-count changes
  • Their participation status
  • Session completion
  • Timeline updates
    Cancelled sessions are excluded from current-session results. The latest completed session remains visible for timeline inspection.
    Privacy-safe session history
    The operational timeline can contain events such as:
    session_created
    session_started
    participant_joined
    participant_left
    participant_removed
    participant_blocked
    stage_approved
    stage_rejected
    stage_left
    stage_revoked
    session_cancelled
    session_ended
    Public events contain aggregate data instead of participant IDs:
    {
    "type": "participant_joined",
    "participantCount": 4,
    "sequence": 12
    }
    Room-scoped chat
    Each virtual session now has an isolated chat.
    Chat access requires:
  • Authentication
  • Session membership or host capability
  • Absence from the room blocklist
    Messages can be sent only while the session is live.
    A public message contains:
    {
    "id": "message-id",
    "characterName": "H4x0r",
    "text": "Hello room",
    "createdAt":
    "2026-09-15T10:00:00.000Z"
    }
    Account, room, and internal session identifiers are omitted.
    Messages are:
  • Sanitized
  • Limited to 280 characters
  • Rate-controlled
  • Retrieved incrementally
  • Deduplicated by the client
  • Rendered as text
  • Automatically deleted after 24 hours
    Chat moderation
    Hosts and administrators can remove individual messages.
    Deletion is scoped to:
    Message ID
    • Session ID
    • Room namespace
      An ID from another room cannot be used to delete its message through the current session.
      The frontend does not need the sender’s account ID.
      Connecting the metaverse to the marketplace
      MyZubster World is not intended to remain an isolated virtual experiment.
      It will become a visual entry point into marketplace areas such as:
  • Underground and alternative cultures
  • Kefir communities
  • Plant cultivation and documentation
  • University assistance
  • Creative collaboration
  • Privacy-conscious technology
    The proposed ecosystem is circular:
    Discover

    Learn

    Collaborate

    Exchange

    Document

    Share

    Discover again
    A user could discover a community in the virtual world, enter its room, exchange knowledge, request help through the marketplace, and share the result with the same community.
    What we still need to build
    Dedicated realtime infrastructure
    The current system uses polling. Future development should evaluate:
  • WebSockets
  • Managed realtime channels
  • Room-scoped broadcasts
  • Regional routing
  • Horizontal scaling
  • Reliable reconnection
  • Abuse protection
    Immersive room scenes
    Room authorization and lifecycle management are implemented, but entering a room does not yet launch a complete dedicated immersive scene.
    The intended connection is:
    Authorized session

    Short-lived room token

    Realtime room channel

    Immersive scene
    Audio and video
    Stage permissions are stored and enforced as application state, but they do not yet activate a production WebRTC transport.
    This will require device permissions, speaker enforcement, network recovery, media infrastructure, and privacy documentation.
    Message reporting
    Hosts can delete messages, but participant reporting still needs:

  • Reason categories
  • Minimal evidence retention
  • Abuse prevention
  • Review procedures
  • Appeal policies
    Stronger distributed rate limiting
    The current chat uses a basic recent-message check.
    Production hardening should introduce atomic distributed limits so concurrent requests cannot bypass the interval.
    Marketplace destinations
    The virtual world should eventually contain destinations connected to real marketplace information:
    Neon Plaza
    ├── Underground Culture
    ├── Kefir and Cultivation
    ├── University Collaboration
    ├── Creators
    └── Privacy Technology
    Monero research
    We are evaluating Monero for appropriate marketplace transactions.
    A production integration still requires work on wallet architecture, payment verification, confirmations, refunds, exchange rates, accounting, security, and regulatory responsibilities.
    It remains a research and development objective rather than a completed payment feature.
    Monitoring this article with Vercel Analytics
    All public links in this article use:
    utm_source=coderlegion
    utm_medium=article
    utm_campaign=myzubster_metaverse_build
    Each link has a separate utm_content value so traffic from different calls to action can be distinguished.
    Authorized project members can inspect the results here:
    https://vercel.com/myzubster/my-zubster-app/analytics
    The Vercel dashboard is private. Readers should use the public MyZubster links.
    Follow the project
    Enter MyZubster World:
    https://www.myzubster.com/metaverse?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=final_metaverse_cta
    Explore the marketplace:
    https://www.myzubster.com/marketplace?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=final_marketplace_cta
    Learn how the ecosystem works:
    https://www.myzubster.com/come-funziona?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=final_how_it_works_cta
    View the source code:
    https://github.com/MyZubster-Ecosystem/myzubster?utm_source=coderlegion&utm_medium=article&utm_campaign=myzubster_metaverse_build&utm_content=final_github_cta
    MyZubster World remains experimental, but it is becoming a server-authoritative platform with real identity, privacy, lifecycle, moderation, scheduling, and communication systems.
    We are building it publicly, one verifiable layer at a time.
    What should we implement next: immersive rooms, realtime infrastructure, participant reporting, or marketplace destinations?
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

Building MyZubster World: The Architecture We Have Implemented and What Is Still Missing

Myzubster - Sep 14

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23

Sovereign Intelligence: The Complete 25,000 Word Blueprint (Download)

Pocket Portfolio - Apr 1

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

The MyZubster Metaverse has reached a new technical milestone.

Myzubster - Sep 8
chevron_left
2.1k Points44 Badges
Rimini
49Posts
3Comments
15Connections

Related Jobs

View all jobs →

Commenters (This Week)

2 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!