Skip to main content

Memory & Conversations

All MIA-owned data lives in Firebase Realtime Database (RTDB). Firestore is read-only from MIA and used only for integration plugin metadata.

Important framing: the AI's tools mostly don't touch RTDB directly. They HTTP-call internal Firebase Function endpoints (which write to RTDB through the standard module repository layer). The "Owner" column below names the module endpoint, not the tool. See Agent SDK for the architecture.

MIA-owned RTDB paths

PathSchema (key fields)Owner (endpoint)Read by
pivotAiAgentMemory/{cid}/companyProfiletypicalRevenue, laborBudget, peakDays, watchedEmployees, hasPatio, location, notes (keyed object), updatedAtPATCH /ai-memory/company-profile (ai-memory module)System prompt builder, fetchCompanyMemoryActivity, update_company_memory tool
pivotAiAgentRules/{cid}/userRules/{ruleId}id, rule (text), enabled, createdAt, updatedAtPOST/PATCH/DELETE /ai-memory/user-rules*System prompt builder, fetchUserRulesActivity, set_user_rule / list_user_rules / delete_user_rule tools
pivotAiAgentCrons/{cid}/{taskId}See MIA Task Lifecycle/ai-memory/cron-tasks*ai-memory list endpoint, Temporal Scheduler (read at fire time), set_cron_task tool
AIZackboardSessions/{cid}/{uid}/{sessionId}messages, widgets, widgetLayouts, suggestions, title, createdAt, updatedAt, tokenUsage, pendingJobId?saveSession (end of pipeline, in functions/pivotAiAgent/session.ts); frontend also writes widgetLayouts directly on drag/resizeFrontend (session list + resume)
AiTipsRules/{cid}/{ruleId}See MIA Tips/companies/:id/ai-tips-rules* (companies module)Tip-distribution engine, MIA Tips UI, save_ai_tips_rule family of tools
AiUsageLogs/{cid}/{day}/{rowId}ts, provider, model, flow, userId, inputTokens, outputTokens, cacheReadTokens, cacheCreateTokens, totalTokens, costUsdWritten at end of every LLM call by the AI service/companies/:id/ai-usage admin endpoint
AiUsageLogs/_onboarding/{day}/{rowId}Same shape as aboveOnboarding-flow LLM calls (before companyId is known)/ai-usage/onboarding admin endpoint
Companies/{cid}/aiConfig{ provider, model, updatedAt }PATCH /companies/:id/ai-config (admin only)callLlm provider resolution
GlobalAiConfig{ provider, model, updatedAt }PATCH /ai-config/global (admin only)callLlm fallback when no per-company override
pivotAiAgentUploads/{uploadId}uploadId, filename, type (csv/image/sheet), mediaType, createdAt, base64 (images)POST /upload (Cloud Run)Tool calls referencing uploadId
AIOnboardingSessions/{userId}progress checklist, current step, captured configAdmin SDK only (no public endpoint) — written by onboarding toolsget_onboarding_status, complete_onboarding, onboarding pipeline state
ImportStagingArea/{userId}/*staged employee imports from CSV / Agendrix / 7shiftsAdmin SDK only — written by import_competitor_csv, scrape_*onboarding pipeline

Note on direct-RTDB writers: create_shift writes WeeklySchedule/{cid}/{date} directly via Firebase REST (legacy, has TODO to migrate). The onboarding-state paths above (AIOnboardingSessions/, ImportStagingArea/) are intentionally not exposed via the public API.

There is no Companies/{cid}/miaSettings path. Earlier docs referenced it; the codebase has no writers for that path. Per-company AI configuration lives at Companies/{cid}/aiConfig (see above).

Cross-cutting RTDB paths MIA reads (via tools / endpoints)

These are owned by other parts of Pivot but routinely accessed by MIA via the standard endpoints:

PathOwning moduleAccessed by tool
Companies/{cid}companiesget_company_info, get_company_settings, get_integration_status
Users/{uid}(auth context)get_current_user
Employees/{cid}/{eid}employeesget_employees, find_employee, employee CRUD
EmployeeRates/{cid}/{eid}employees (sub-resources)get_employee_rates
Attendance/{cid}/{date}attendanceget_attendance, get_payroll_issues
WeeklySchedule/{cid}/{date}scheduleget_schedule, shift CRUD

Firestore (read-only here)

IntegrationSettings/{docId}                   — read yes, write no
IntegrationPluginSyncs/{pluginSyncId}/... — read-only
PluginSyncJobs/{jobId} — read-only
PluginSyncSlices/{sliceId} — read-only
(everything else) — deny read, deny write

Rules source: firestore.rules.

PostgreSQL

Migration in progress for non-MIA data. The codebase has @google-cloud/cloud-sql-connector + kysely. Several Pub/Sub triggers (onPublishedSchedulePgSync, onCompanyWritePgSync, etc.) propagate RTDB writes to PG. No MIA-specific PG tables exist yet — usage logs, memory, rules, cron tasks all stay in RTDB.

Conversation history details

Note the collection name: AIZackboardSessions (typo that stuck in source — the backend's older ARCHITECTURE.md says AIDashboardSessions but the actual source-of-truth at functions/pivotAiAgent/session.ts and the frontend both use AIZackboardSessions).

A single session record holds:

{
messages: ChatMessage[], // conversation history
widgets: Widget[], // parsed widget config (see AI Dashboard)
widgetLayouts: PlacedWidget[], // per-widget position + size on the canvas
suggestions: string[], // last suggested follow-ups
title: string, // ~40 chars; derived from first user message
createdAt: number,
updatedAt: number,
tokenUsage: { ... }, // aggregate counters for this session
pendingJobId?: string // present while a pipeline run is still streaming
}

pendingJobId is removed when the run finishes. On session resume, the frontend re-subscribes if pendingJobId exists, so a long-running data-path query can survive a page reload.

Token usage is also rolled up to AiUsageLogs/ per-row for cross-session reporting (see Token & Cost Tracking).