your-ai-workflow-firebase-os
v2.0.3
Published
Your AI Firebase — a complete Firebase-powered admin app in one React component.
Readme
🔥 Your AI Firebase
A complete, production-ready Firebase app — packaged as a single React component.
Authentication, user management, role-based access control, file storage, pages your AI assistant builds, a form builder, a theme engine and an inbox — all behind one import.
import { FirebaseOS } from 'your-ai-workflow-firebase-os';
import 'your-ai-workflow-firebase-os/styles.css';
export default function App() {
return <FirebaseOS />;
}That's it. One component. Zero configuration files.
The component, the package and the
.firebase-osCSS scope keep their original names — renaming them would break every existing install. The product is called Your AI Firebase.
✨ What you get
| Feature | Details |
|:--------|:--------|
| 🔐 Authentication | Email/password, email verification, password reset |
| 👥 User Management | Admin panel, three access levels (Free · Internal · Admin), inactive user blocking |
| 🗂️ Pages | Add a page on /pages — for anyone, signed-in users, your team or admins only — in sections, each box showing a real example before you type: the page itself (its name, its web address, what is on it), its pictures, its form, its booking (a schedule picked from the Schedule screen), the pages it links to (one you have, or a new one made right there with the same sections) and, once switched on, its emails and its payments. Copy the sentence and the assistant builds it, deciding whatever was skipped. Once copied the row opens on one box — what should change — with the same sections under it; the change sentence carries your words plus only the sections you changed since, copying blanks the box again, and a rename or a move is a Name: or Address: line. Home, the dashboard, Contact and Support open on the same sections. Reorder, hide and delete live on the row |
| 📋 Templates | Board (Kanban), Calendar, Table, Drive, Inline Form, Popup Form, Confirmation |
| 🎨 Theme Engine | Light and dark modes, every colour and corner in one file your assistant designs from the sentence the /theme screen hands the owner |
| 📁 File Storage | An admin-only Assets screen for public images, plus a drive preset any page can be built on |
| 📬 Forms | Created with their pages on /pages — say in one box what a form should ask and what happens after (or name one you already have) and the AI builds it with the page; see and hand-edit every form afterwards on /forms. Questions can ask for a file — a CV, a photo, a receipt — and the upload works signed out |
| 📥 Inbox | Every form entry in one list at /inbox, filtered "From anyone" or "From signed-in users"; an attached file opens from the entry by its own name |
| 💳 Payments | Stripe checkout in one line — a Take payments switch at the top of /payments pauses every Pay button and checkout at once (read by the server, so a built page stops too), then the owner configures what they sell under What you sell on /payments (things paid for once — each a name and a price, grouped under one entry — or plans and their Stripe ids), answers How your payments work in one box per payment (start to finish; whatever is skipped, the AI decides), then adds payments to a page from that page's own Payments section on /pages — offered first, a Dynamic payment only that page has, whose amount the page works out (one <BuyButton amount={total}>, or a whole basket as <Basket> — the bag, who is paying and the Pay button in one drawer, with <CheckoutReturn> for the way back); then one they already have, a one-time payment made right there (it lands on /payments too), or a subscription (a page with none sends the owner to /payments with a subscription already chosen, and back with it added) — and the page's sentence carries the exact <BuyButton> tags and the owner's words — public and signed-in pages sell with <BuyButton>, <Basket> and <Plans> (each asks who is paying itself, then goes on to Stripe), internal and admin pages show the team the sales through useSales(), and before-paying questions go through the app's own forms. Connection says Test mode connected and nothing about webhooks while the owner practises; the Go live switch under it is always there and, once flipped, walks the test→live change — the live secret key, live price ids only when a subscription is sold (test ids kept, and the id-swap prompt for the assistant generated), and last the webhook, locked until step 3 of /publish is ticked because Stripe needs the published address, which it then hands over with a copy button — buyers get a built-in /billing page that appears after their first purchase, and every cancel/switch/invoice screen is Stripe's own billing portal |
| 🧾 Transactions | The ledger, /transactions: every charge and subscription made through the app, live from Stripe (anything else in the same Stripe account is left out), each row opening on everything the page collected — the buyer's details (their account, asked for by <BuyButton> / <Basket> before the money moves; they ride the payment's metadata) and the order a shop's <Basket> saved before the payment started, joined to it by the entry id the payment carried — plus who paid, how, where it goes and the receipt; an order started and never paid for stays listed as No payment. A payment's forms carry transaction: true, so their entries land here and never in the Inbox |
| 📅 Schedule | Calendly-style booking, built in — on /schedule the owner keeps SCHEDULES: a week of hours per team member, in that person's own time zone, with the days they are away marked on it. Under them, BOOKING LINKS: one meeting each, booked in a chosen set of hours — its name, its length, how far ahead, how much notice, what it asks the visitor beyond their name and email, and a one-time payment taken first when they want one. Every link has a shipped booking page at /book/{id} to send to anyone: the app's theme and name, a full calendar in the visitor's own time zone, and Stripe checkout before the time is confirmed when a payment is attached. One set of hours carries as many links as you like, and they share one availability, so a time taken under any of them is gone from all; Your booking pages makes one address that offers several. The calendar at the top of /schedule shows everything booked on a month grid — Paid beside the paid ones, Cancel to free the time — read by an admin as the whole team or as any one person, and whoever booked reads the same calendar under My bookings. On /pages a page can be built on somebody's hours (Schedules on that page: a rota, or a page people book time on — the hours are read live, so changing the week changes the page) or carry a plain link to a booking link or page already made (Booking links), and any form can ask a Pick-a-time question. The assistant never builds a calendar, a time picker or a bookings collection |
| 🔗 Payment links | Every one-time payment has a shipped page at /pay/{id} in the app's theme and name — under Payment links on /payments the owner adds one from a name, a line about it and a price, copies the link and sends it to anyone; Customise this page makes a real page on /pages and hands over the sentence that builds it, and the link goes there once it is built |
| ✉️ Email | Resend in one line — a Send email switch at the top of /email stops every send at once (the server reads it before each one); while it is on, every page can send email once it is connected: emailOwner() tells the owner what happened, emailPerson() confirms to the person a record names, emailAnyone() lets a team page write to any address (a signed-in admin or team member only), receipts and sale alerts send themselves off a Pay button's settings, and /email says what the app can do with email and where owner mail goes |
| 🚀 Publish App | The admin's last tab, /publish: going live one step at a time — each step appears only once the one before it is ticked, and a finished step folds under its checkmark and reopens on a click. 1 publish in AI Studio and save the app name; 2 map your own domain in Google Cloud Run (Search Console TXT record, the four A records) and save the domain; 3 add both addresses as Firebase authorised domains and verify the email sender, with both addresses handed back to copy; 4 — only while Stripe is still on a test key or has no live webhook — finish Go live on /payments, whose webhook step unlocks on step 3. Email and WhatsApp buttons at the top reach support |
| 📊 Dashboard | Personalised user dashboard |
Ordering, visibility, renaming and deleting all live on the Pages screen — there is no separate settings screen, no Submissions screen and no Requests screen.
📦 Installation
Peer dependencies (install these in your project)
npm install firebase react react-dom react-router-domInstall the library
From npm:
npm install your-ai-workflow-firebase-osFrom a local build (development):
npm pack # in this repo
npm install /path/to/your-ai-workflow-firebase-os-1.0.0.tgz # in your appInstalling runs a postinstall step that patches the consumer project: it clears Vite's default CSS, writes src/main.tsx and src/App.tsx (both are owned by the library — see below), adds yourAiFirebase() from your-ai-workflow-firebase-os/vite and Tailwind to vite.config.ts, and creates src/your-ai-workflow-firebase-os/ with the editable theme and configs. It writes no GEMINI.md / AGENTS.md: AI Studio reserves those filenames for the developer's own instructions, and a package writing them reads as prompt injection.
Starting from nothing (Claude Code, Codex, Antigravity)
In Google AI Studio the project, the server.ts and the Secrets tab all exist before the owner
arrives. On your own machine none of it does — so the first move is one block of text handed to
the assistant, not a list of commands for a person:
- Create a Vite + React + TypeScript app in the folder and delete the starter demo.
npm install your-ai-workflow-firebase-os, thennpm installonce more (the install step adds Tailwind).- Write
.envin the project root — every value empty:
# Firebase Configuration
VITE_FIREBASE_API_KEY=""
VITE_FIREBASE_AUTH_DOMAIN=""
VITE_FIREBASE_PROJECT_ID=""
VITE_FIREBASE_STORAGE_BUCKET=""
VITE_FIREBASE_MESSAGING_SENDER_ID=""
VITE_FIREBASE_APP_ID=""
STRIPE_SECRET_KEY=""
STRIPE_WEBHOOK_SECRET=""
RESEND_API_KEY=""
APP_NAME=""
VITE_ADMIN_EMAILS=""
EMAIL_FROM=""npm install express dotenv stripeandnpm install -D tsx @types/express, copynode_modules/your-ai-workflow-firebase-os/server.template.tstoserver.tsunchanged, and set the dev script totsx server.ts. Nothing is ever added to that file: every route lives in the package.npm run dev, then open the app — it lands on its Setup screen.
The Setup screen carries the same block behind a copy button. The switch at the top of /setup
("I'm building with…") is what decides whether the whole walkthrough talks about the Secrets tab
and Apply, or about .env and restarting; the choice is remembered and the Payments and Email
screens read it too.
What the build enforces
The package ships a Vite plugin, yourAiFirebase(), that puts the project's structure out of the assistant's reach. src/App.tsx and src/main.tsx are owned files: the plugin serves its own canonical source for both and rewrites them on disk whenever they differ, so an edit there has no effect. Pages, forms and content files are discovered from src/your-ai-workflow-firebase-os/configs/ and microcomponents/ through a virtual module, so a deleted registry import can no longer make a page vanish. And every discovered file is validated before the build: a config file with the wrong name, a route that is not one string starting with /, an address used twice, a *Tab.config.ts without a valid pageType, a missing *Config export, a systemName that does not match the file, or a content file with no default export fails the build with one sentence that names the fix. A bare <img> in a content file fails it too: pictures go through <Picture>, which holds its space before the picture lands, fetches the light copy written beside every upload, and crosses over when its src changes rather than blanking — the thing that made a product page's colour swatches flash. A hand-written <form> in a content file only warns — its entries would never reach the Inbox.
Manual-first recipe: the owner adds the page — and its form, if it needs one — on /pages and then asks the assistant for the content, which is a single microcomponents/<PascalCaseName>Content.tsx file — no config file, no second address.
🚀 Quick Start
Option A — Zero config (recommended)
On first load the app opens its Setup screen, which walks through connecting a Firebase project. Nothing is stored on any server — keys are saved in the browser's localStorage.
// App.tsx
import { FirebaseOS } from 'your-ai-workflow-firebase-os';
import 'your-ai-workflow-firebase-os/styles.css';
export default function App() {
return <FirebaseOS />;
}Option B — Pre-configured (CI/CD, teams)
Skip the setup screen entirely by passing the Firebase config as props:
import { FirebaseOS } from 'your-ai-workflow-firebase-os';
import 'your-ai-workflow-firebase-os/styles.css';
export default function App() {
return (
<FirebaseOS
firebaseConfig={{
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
}}
/>
);
}🎛️ Props API
interface FirebaseOSProps {
/**
* Pass Firebase config directly to skip the Setup screen.
* If omitted, setup runs on first load and saves config to localStorage.
*/
firebaseConfig?: {
apiKey: string;
authDomain: string;
projectId: string;
storageBucket: string;
messagingSenderId: string;
appId: string;
};
/** Theme defaults from your own theme.config.ts. */
themeConfig?: any;
/** Auto-discovered page content files, keyed by page id. */
microcomponents?: Record<string, React.ComponentType<any>>;
/** Local overrides for built-in components — `{ Home }` is the usual one. */
components?: { Home?: React.ComponentType<any> };
/** Default form configs shipped with your project. */
defaultConfigs?: { contactForm?: any; supportForm?: any };
/** Custom router basename (e.g. "/app" if your app lives at a subdirectory). */
basename?: string;
/** Callback fired whenever the Firebase auth state changes. */
onAuthChange?: (user: any) => void;
}The postinstall step writes an App.tsx that already passes themeConfig, microcomponents, components and defaultConfigs for you.
🪝 Advanced: Hooks
For advanced integrations, two hooks are exported from the library:
import { useAuth, useTheme } from 'your-ai-workflow-firebase-os';
// Access auth state anywhere inside <FirebaseOS />
function MyWidget() {
const { user, userRole, signOut } = useAuth();
const { theme, toggleTheme, activeConfig } = useTheme();
// ...
}Note: These hooks only work when rendered inside the
<FirebaseOS />component tree.
🔥 Getting your Firebase config
- Go to Firebase Console
- Create or select a project
- Go to Project Settings → Your apps → Web app
- Copy the
firebaseConfigobject - Enable Authentication (Email/Password), Firestore, and Storage in your project
The Setup screen in the app walks through all of this and generates the security rules to paste, so nobody has to work it out from here.
🎨 Theming
The theme is one file, src/your-ai-workflow-firebase-os/configs/theme.config.ts, which the owner's assistant writes from the sentence the /theme screen hands them. There is no hand editor: the file is the whole theme.
All CSS is scoped to .firebase-os — the library's styles do not leak into your own application's CSS.
🤖 Working with the AI
Your AI Firebase is built to be driven from an AI chat (Google AI Studio, Cursor, Claude Code…). The contract says what the assistant may build, which words to use with the owner, and what it must never touch.
That contract lives in src/contract/aiRules.ts, and it is the only copy. Read it there, and change it there. Nothing writes it into the consumer project and no screen hands it over: an assistant that should have it is given it by the owner, in whatever file that assistant reads. This README deliberately does not restate it, so the two can never disagree.
The short version for a person evaluating the library: you ask for a page or a form in plain language, the assistant writes it, and it appears on the /pages screen where the basics — name, web address, icon, order, visibility — are yours to edit. A form is created with its page there, and once built it also shows up on /forms, where you edit its title, questions and button text yourself. Everything else is the assistant's job; ask it in chat.
📐 CSS Isolation
The library uses a .firebase-os container div for all its CSS variable scope. This means:
- ✅ Library's theme variables stay inside
.firebase-os - ✅ Your own
:rootvariables are untouched - ✅
data-themeattribute is set on the container, not<html> - ✅ No Tailwind class pollution on your global styles
🔒 How data is stored
- Firebase credentials —
localStorage(your browser only, never any server) - User data — your own Firebase Firestore
- Files — your own Firebase Storage
- Theme / page config — your own Firestore (
sys_configscollection)
You own all your data. Your AI Firebase is just the UI layer.
📁 Project structure (for contributors)
src/
├── index.ts ← Public API (only exports FirebaseOS + hooks)
├── FirebaseOS.tsx ← The library component wrapper
├── App.tsx ← Router + route guards (internal)
├── lib/
│ ├── firebase.ts ← Dynamic Firebase init (env OR props)
│ ├── AuthContext ← Auth lifecycle (internal)
│ ├── ThemeContext ← CSS variable injection (internal)
│ └── ConfigContext ← Library props → internal bridge
├── pages/ ← Page components (internal)
├── templates/ ← Template components (internal)
├── components/ ← Shared UI, incl. components/fields (internal)
├── configs/ ← Default configurations (internal)
└── contract/ ← The assistant's contract, and the tests pinning itScripts
npm run dev # Run standalone app (for development)
npm run test # Run the test suite
npm run build:lib # Build the distributable library
npm pack # Create .tgz for local testing📄 License
MIT
