Data Layer
Yugma is fully Firebase-native: Auth, Firestore, Realtime Database, Cloud Storage, and Cloud Functions.
Firebase Services
Authentication
| Method | Provider |
|---|---|
| Google OAuth | Firebase Auth |
Google OAuth is the only sign-in method. The onUserCreate trigger seeds a user profile in Firestore.
Firestore Collections
| Collection | Path | Purpose | Access |
|---|---|---|---|
projects | projects/{projectId} | Scene data + metadata | Owner read/write |
projects/*/assets | projects/{pid}/assets/{aid} | Per-project asset library | Authenticated |
shareLinks | shareLinks/{linkId} | Public share link metadata | Public read, auth write |
aiSessions | aiSessions/{uid}/sessions/{sid} | AI chat history (Firestore copy) | Owner only |
aiRateLimits | aiRateLimits/{uid} | Per-user rate limit counters | Owner only |
materialJobs | materialJobs/{jobId} | AI material gen jobs | Owner only |
sysconfig/admins | — | Admin UID list | Auth read, console write |
sysconfig/providers | — | LLM provider config (keys) | Admin only |
Planned (not live):
videoJobs/{jobId}(Phase 12 video reconstruction) andrenderJobs/{jobId}(Phase 16 render jobs) are planned collections — no shipped code writes them.
Realtime Database Paths
| Path | Purpose | Frequency |
|---|---|---|
collab/{sessionId}/presence/{uid} | User online status | On connect/disconnect |
collab/{sessionId}/cursors/{uid} | 3D cursor position | ~30 Hz |
collab/{sessionId}/deltas/{deltaId} | Scene change deltas | Per edit |
rooms/{roomCode} | Room code → session mapping | On create/join |
Planned (not live): the Phase 13
sensors/{sensorId}/...paths are planned for the digital-twins vertical. They were removed fromdatabase.rules.jsonin the 2026-07 cleanup and no shipped code writes them.
Cloud Storage
assets/{uid}/{timestamp}_{filename} — uploaded GLBs, textures
Access via signed upload/download URLs (Cloud Functions). The Phase 12 videos/{uid}/{jobId}/{filename} upload path is planned, not live.
AI Session Persistence
Sessions are stored in Firestore at aiSessions/{uid}/sessions/{sessionId}. Each document contains the full message array, auto-updated via setDoc with merge on each AI turn. On mount, loadLastSession queries the most recent session by updatedAt and hydrates the chat.
Client send message → AIPanel → saveAISession → Firestore (fire-and-forget)
Client mount → loadLastSession (Firestore query) → hydrateSession
Zustand Stores (17 total)
| Store | Key state |
|---|---|
useSceneStore | objects, objectOrder, selectedObjectId, environment, cameraTarget |
useAnimationStore | clips, currentFrame, isPlaying |
useProjectStore | projectMeta, isDirty |
useAuthStore | user, tier, isLoading |
useAIStore | messages, isStreaming, sessionId |
useUIStore | toasts, theme |
useCollabStore | remoteUsers, isConnected |
useRoomStore | roomCode, isHost |
useCommentStore | comments |
useGenerationStore | jobs (text-to-3D) |
useHistoryStore | undoStack, redoStack |
useUpgradeModalStore | paywall trigger, gate variant |
useVersionStore | version snapshots |
useUsageStore | current-period usage meters |
useYgmStore | catalog kinematics records |
useYgmPhysicsStore | per-object physics run flag |
useRosStore | ROS connection + topics |
Security Rules
All Firestore rules enforce owner-only access for user-scoped data. Pattern:
allow read: if request.auth != null && resource.data.userId == request.auth.uid;
allow create: if request.auth != null && request.resource.data.userId == request.auth.uid;