Architecture
who talks to whom.
One picture of the three parts you deploy (the app, the Firebase backend and the operator console) and the outside services they call. You do not need to understand code to read it. Most setup problems are one broken arrow in this picture, so read it once before you start.
01The diagram
Boxes with a solid border are parts of this package. Boxes with a dashed border are outside services you open accounts for. Arrows point in the direction of the request.
02The parts in plain words
- Mobile app (
app/). Knows one address: your API (API_BASE_URL, set when you build). It never talks to an AI provider directly and carries no secret. It keeps the user's chats on the phone and edits videos on the phone itself. - Backend (
firebase/). TheapiCloud Function answers every request of the app. It reads your settings from Firestore, checks the user's plan and allowance, runs moderation, forwards the request to the provider with your key, streams the answer back and counts usage. Three scheduled functions send push campaigns (every 5 minutes), fetch the Discover feeds (every 10 minutes, only while Discover is on) and clean up old data (daily at 03:30 UTC). - Operator console (
admin/). A small Node server you host. You set everything there; on every save it writes two Firestore documents:config/public(what the app may see, served byGET /v1/config) andconfig/private(keys, feed addresses and caps, read only by the backend). - Outside services (dashed boxes). Each one is an account you open and pay yourself: AI providers, Firebase, the stores, ad networks. The Discover feeds come from the publishers whose RSS / Atom feeds you enable.
03config/public and config/private
config/public | config/private | |
|---|---|---|
| Contains | Brand, legal texts, features, sign-in methods, chat settings, model, image, voice, video, image-edit and caption-style catalogs, styles, assistants, prompts, plans, paywall, limits, Discover categories, store product ids, ad settings and ad unit ids, push topic | AI, image, voice and video keys, compatible endpoints, daily caps, Discover feed addresses, image tool model ids, moderation settings, store verification credentials, ad reporting tokens, AdMob SSV switch |
| Written by | The console only | The console only |
| Read by | The backend, which serves it to the app as GET /v1/config (cached 60 s), without your prices, provider model ids and unusable models | The backend only |
| App or browser access | Never directly (Firestore rules deny it) | Never |
Until the console has saved once, the backend uses the built-in defaults: every model disabled, every paid module off, ads, plans and purchases off.
04What happens when a user sends a message
- The app sendsthe last messages of the chat (at most Messages sent as context, default 30) to
POST /v1/chatwith the user's Firebase ID token. - The backend checksthat the model is enabled, that the user's plan rank reaches the model's tier, that attachments fit the model, and that the user has allowance, credits or a rewarded unlock. Failing checks answer with a plain error before anything is charged.
- Moderationruns on the server: your blocked words, then the optional moderation endpoint. A blocked prompt is never sent to the provider and its text is not stored.
- The provider answersand the backend streams the text back as Server-Sent Events. The allowance or credit is charged when the stream starts; if the provider fails before the first word, it is refunded.
- Counting, not storingThe backend adds the token counts the provider reported to the daily statistics. It stores no message text. The app saves the conversation on the device.
Images, image edits, AI video, natural voices and transcription follow the same pattern: check, moderate where it applies, charge, call the provider, refund on failure. AI video runs as a job: the app polls it until the provider has finished, and the finished file is copied into your Storage.
05The public demo
The same API code also runs without Firebase, with an in-memory store and the sample configuration: that is npm run dev:api on your computer and the public web demo. In this mode it uses no key unless the host sets DEMO_AI_* environment variables, and labels every demo reply and sample: sample picture, "Sample headline — demo", "Sample clip — demo", "Sample captions — demo", "Sample transcript — demo". Natural voices are not available there; the app reads aloud with the device voice.