Firestore admin panel for ops, support, and content teams
Give your team one safe screen to browse, edit, and export Firebase data, with every change logged, announced in Slack, and confirmed before it saves.
I want an internal data console for our Firebase Firestore database that ops, support, and content people can open instead of the Firebase console. They need to look things up and fix records every day, and right now that means either giving them access to the real Firebase console, which is confusing and dangerous, or asking an engineer every single time. Build an app where a non-technical viewer can browse, filter, edit, and export Firestore data safely, with hard guardrails around anything destructive.
The left sidebar lists every collection in the database using List Firestore Collection IDs. Each collection is a card showing its name and a document count, and that count must come from Run Firestore Aggregation Query with a count aggregation, never from pulling every document. Cache the counts and refresh them when the viewer reloads a collection or after a write.
Picking a collection opens the main table. Load rows with List Firestore Documents for the plain view and Run Firestore Query when the viewer applies filters or sorting, paging with the next page token rather than loading the whole collection. Firestore wraps every field in a typed envelope such as {"fields":{"name":{"stringValue":"Ada"},"age":{"integerValue":"36"}}}, so the table has to flatten those into plain readable columns: strings as text, integerValue and doubleValue as numbers (integerValue arrives as a JSON string, so convert it), booleanValue as a checkbox, timestampValue as a formatted date, and maps and arrays as a collapsed summary the viewer can expand. Derive the column set from the fields actually present across the loaded page, let the viewer show and hide columns, and give every column a filter and a click-to-sort header. Document names come back as full resource paths like projects/{projectId}/databases/(default)/documents/{collection}/{docId}, so show only the document id in the table and keep the full path for writes.
Clicking a row opens a detail drawer showing every field with an input suited to its type, refreshed with Get Firestore Document so the viewer is always editing current data. Saving must use Update Firestore Document with updateMask.fieldPaths limited to exactly the fields the viewer changed, because a patch without a field mask replaces the entire document and would wipe everything else. Convert edited values back into the correct typed envelope on save, and if a value does not fit the field's existing type, show a clear error rather than silently changing the type.
A New record button opens the same drawer empty and writes with Create Firestore Document, prefilling the field names the rest of the collection already uses so people do not invent new ones by accident. Delete lives in the drawer behind a confirmation dialog where the viewer has to type the document id before the button enables, then calls Delete Firestore Document. Selecting multiple rows in the table reveals a bulk bar that can set one field to one value across the selection, applied with Batch Write Firestore Documents, with a preview of exactly how many documents will change before it runs.
Every write, single or bulk, also writes an audit document into a dedicated Firestore collection (something like console_edits) using Create Firestore Document. Each audit record holds the signed in viewer's name and email, the collection and document id, the action (create, update, delete, bulk update), the before and after values of the affected fields, and a timestamp. A Recent changes tab reads that collection back with Run Firestore Query ordered by timestamp descending and renders a readable feed: who changed what, in which collection, from what value to what value. The audit collection itself must never be editable from inside the console.
After each successful write, post a one line change note to Slack with Slack Bot Send a Message, for example "Priya updated orders/AB12: status from pending to shipped". The destination channel is set in app config, chosen from a picker populated by List Channels. Bulk edits post a single summary line rather than one message per document.
An Export button takes the current filtered and sorted view and appends it to a tab in a Google Sheet with Google Sheets Append Values, headers first and then the flattened human readable values, plus a final row noting who exported it and when. The spreadsheet and tab are set in app config. The whole point is that people stop screenshotting and hand copying data out of the database.
Add a Check this collection button that kicks off a background agent. The agent samples the collection with Run Firestore Query (a few hundred documents, or all of them if the collection is smaller), works out the shape that the majority of documents follow, then compares every sampled document against that shape. It should flag documents missing fields that most others have, fields holding a different type than the majority (a number stored as a string, a date stored as free text), and referenceValue fields pointing at documents that no longer exist, verified with Batch Get Firestore Documents. It writes a findings report back into Firestore as a document in a reports collection with Create Firestore Document, containing the collection checked, the timestamp, how many documents were sampled, the inferred majority shape, and a list of findings where each one carries a document id, the problem, and a suggested fix.
A Data health tab reads the latest report for the selected collection and renders it as grouped findings with counts. Each finding gets a Fix button, but nothing is written until the viewer approves it: clicking Fix shows exactly what will change, and only then applies it with Update Firestore Document using a field mask, or with Batch Write Firestore Documents when the viewer approves a group of identical fixes at once. Approved fixes run through the same audit trail and Slack note as manual edits. Findings the viewer dismisses get marked dismissed on the report so they do not come back.
Bake the safety rules in everywhere, because the reason this app exists is that these people must never touch the real Firebase console. App config holds a list of collections marked read-only: they stay visible and browsable, but every edit, delete, bulk action, and health fix is disabled with a visible reason rather than hidden. Config can also hide collections from the sidebar entirely. Deletes always require the typed confirmation. Counts always come from the aggregation query, never from downloading documents. Show the signed in viewer's name in the header so it is obvious the app is acting as them, and stamp that name onto every audit record.
What does this prompt do?
- Browse every collection in your Firebase database from a sidebar, each with a live record count, then pick one to get a clean sortable table and a one-click export of whatever view you are looking at into a Google Sheet.
- Edit records in a side panel, add new ones, or delete one behind a confirmation you have to type out. Only the fields someone actually touched get saved, so nothing else in the record gets wiped.
- Every change lands in a history log with the person's name and the before and after values, shows up in a Recent changes tab, and posts a one line note to the Slack channel you choose.
- Hit Check this collection and an assistant reviews the data for records missing fields, values stored in the wrong format, and links pointing at records that no longer exist, then offers fixes your team approves one at a time.
What do I need to use this?
- A Firebase project with data in it, plus access to your project settings so you can download the file that connects it
- A Slack workspace and a channel where change notes should be posted
- A Google account and a spreadsheet you want exports to land in
- A short list of which collections should be read-only or hidden, so risky data never gets edited by mistake
How can I customize it?
- Mark any collection read-only so people can look but never edit or delete, or hide the truly sensitive ones from the sidebar entirely
- Choose which Slack channel gets change notes, and whether every edit gets announced or only deletes and bulk changes
- Pick which fields show as columns for each collection, and which spreadsheet tab exports land in
- Set how many records the health check samples before it decides what a normal record looks like
FAQs
Do my teammates need access to the Firebase console?
Can someone accidentally delete important data?
Will this slow down my database or run up costs?
Can I see who changed what?
Does it work with my existing data structure?
Related templates
Stop buying stale lists. Reps run a saved search, work the results like an inbox, and only the accounts they approve ever reach your CRM.
See how your brand's news coverage and sentiment stack up against four competitors, then let an assistant write the weekly report for you.
One screen showing every social post waiting on approval, sorted by deadline, so reviewers can approve or reject without leaving the page.
Every Monday, find the past champions and closed-won contacts who changed jobs, update Attio, and get the moves worth chasing in Slack.
Staff submit what happened, your social manager edits the copy, picks the accounts and puts it on the calendar without a single spreadsheet.
Drag creators through Sourced to Wrapped on a board grouped by campaign, with audience stats on every card and a one-click brief for each creator.
Stop handing out Firebase console access.
Give ops, support, and content one safe screen for the data they need, and keep the risky parts of your database off limits.