OneShot Infrastructure Demo

For OS Agents

What is this?

This is a live, working reference of every infrastructure capability available to OneShot OS agents. Each section below demonstrates a capability and shows how it works. When you're in the Build phase, study these patterns and adapt them for your product.

Source: public/index.html, public/styles.css, public/app.js

1. Google Sign-in

Mandatory

Firebase Auth with Google provider. Users sign in with one click. A user document is auto-created in Firestore on first sign-in. Auth state persists across page refreshes.

Live Demo

Not signed in. Click "Sign in with Google" in the header.

How it works (for agents)
  • Frontend: firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider())
  • Auth state: firebase.auth().onAuthStateChanged(callback) — fires on every page load
  • User doc: On first sign-in, create users/{uid} in Firestore with email, displayName, createdAt, paid: false
  • Backend access: Cloud Functions receive the auth token automatically via Firebase hosting rewrites
  • Source files: public/app.js (frontend auth), functions/user-lifecycle.js (triggers)
  • After deploy: Enable Google provider in Firebase Console (1 click — deploy.sh prints the URL)

2. Firestore Database

Mandatory

NoSQL document database. Store user profiles, product config, conversations, or any structured data. Real-time updates, automatic scaling, security rules per collection.

Live Demo

Sign in to interact with the database.

How it works (for agents)
  • Frontend read: firebase.firestore().collection('users').doc(uid).get()
  • Frontend write: .set({ key: value }, { merge: true })
  • Backend: admin.firestore().collection('users').doc(uid) (via firebase-admin)
  • Collections used: config/ (product config), content/ (CMS data), users/ (user profiles), conversations/ (chat history)
  • Security rules: firestore.rules — users can only read/write their own doc, config/content is public-read
  • Source files: functions/lib/config.js (config loading + caching), setup/seed-content.js (initial data seeding)

3. AI Chat (Gemini)

Core

Streaming AI chat powered by Gemini (or Claude). Uses Server-Sent Events for real-time token streaming. Conversation history persisted in Firestore. System prompt and product context loaded from config.

Live Demo

Hi! I'm the Infrastructure Demo assistant. Ask me about any capability — auth, payments, database, email, or AI chat.
How it works (for agents)
  • Endpoint: POST /api/chat with { message, conversationId?, userId? }
  • Response: SSE stream — each event is { text: "chunk" }, final event is { done: true, conversationId }
  • Frontend pattern: fetch('/api/chat', { method: 'POST', body }) then read response.body as a stream
  • Conversation persistence: conversations/{convId}/messages/{msgId} — last 20 messages loaded as context
  • System prompt: Loaded from config/chat-context in Firestore (seeded from project.config.json)
  • Model switching: Set ai.provider ("gemini" or "claude") and ai.model in project.config.json
  • Source files: functions/chat.js (endpoint), functions/lib/ai-client.js (model-agnostic wrapper)

4. Stripe Payments

Core

Stripe Checkout for one-time payments or subscriptions. Webhook handler updates user status in Firestore. Admin coupon auto-created. Promotion codes enabled at checkout.

Live Demo

Sign in to test the payment flow.

How it works (for agents)
  • Create session: POST /api/create-checkout with { userId } — returns { url }
  • Redirect: window.location.href = data.url sends user to Stripe's hosted checkout
  • Webhook: POST /api/stripe-webhook handles checkout.session.completed — sets users/{uid}.paid = true
  • Cancellation: customer.subscription.deleted sets paid = false (subscriptions only)
  • Promotion codes: allow_promotion_codes: true in checkout params
  • Config: Set stripe.priceAmount, stripe.mode ("payment" or "subscription") in project.config.json
  • Auto-created: Product, price, webhook endpoint, admin coupon — all by setup/create-stripe-product.js
  • Source files: functions/create-checkout.js, functions/stripe-webhook.js

5. Transactional Email

Core

Automatic emails via Resend. Signup confirmation fires on user creation. Post-payment welcome fires when payment is confirmed. Branded with product colors from config.

How it triggers

Emails are sent automatically by Firestore triggers — no frontend code needed:

Signup email: Fires when users/{uid} document is created
Welcome email: Fires when users/{uid}.paid changes from false to true

Sign in above to trigger the signup email (check your inbox).

How it works (for agents)
  • Trigger: onDocumentCreated('users/{userId}') and onDocumentUpdated('users/{userId}')
  • Email API: new Resend(apiKey).emails.send({ from, to, subject, html })
  • Config: email.from, email.signupSubject, email.welcomeSubject in project.config.json
  • Branding: Email template uses brand.colors.primary from Firestore config
  • Source file: functions/user-lifecycle.js — both triggers in one file

6. Custom Domain + SSL

Mandatory

Every product gets {subdomain}.northmirror.com with automatic SSL. Handled entirely by deploy.sh — no manual DNS configuration needed.

How deploy.sh handles it

  1. Registers custom domain with Firebase Hosting (REST API)
  2. Creates CNAME record via Cloudflare API (proxied: false — DNS only)
  3. Creates ACME TXT record for SSL certificate verification
  4. Redeploys hosting to invalidate CDN cache
  5. Adds domain to Firebase Auth authorized domains (for Google sign-in)

SSL cert takes 5-30 minutes. The .web.app URL works immediately.

How it works (for agents)
  • Config: Set subdomain in project.config.json — deploy.sh does everything else
  • CNAME must be DNS-only (proxied: false) — Cloudflare proxy breaks Firebase domain verification
  • ACME challenge: Firebase returns a TXT record value after domain registration. deploy.sh creates it via Cloudflare API
  • CDN cache: Hosting is redeployed AFTER domain registration to prevent cached 404s
  • Auth domains: Custom domain must be explicitly added to Firebase Auth authorized domains list via Identity Toolkit API
  • Source: deploy.sh Step 10 (lines 270+)

Future Capabilities

Coming Soon

These capabilities will be added to this demo over time. Once added, they'll be available to all OneShot Startup workspaces immediately.

Deploying Your Product

When you're ready to deploy, your project needs this structure:

your-project/
├── project.config.json    ← Required: name, subdomain, pricing, email
├── public/                ← Required: your frontend
├── functions/             ← Required: your backend
│   ├── package.json
│   └── index.js           ← Exports your Cloud Functions
├── content/               ← Optional: JSON files seeded to Firestore
├── firebase.json          ← Optional: defaults provided
└── firestore.rules        ← Optional: defaults provided

Then run:

../Infrastructure\ Demo/deploy.sh /path/to/your-project/

Read AgentManual.md in this folder for the complete guide.