Technical specs · TeamCentral
How TeamCentral is built: one AI workspace, server-first
The stack, the request path, where data is stored and how it's reached, how each layer is secured, and where AI does the work: retrieval, routing between models through OpenRouter, and an MCP connector that brings it all into Claude and ChatGPT. Written for engineers and technical evaluators.
01 · ArchitectureHow it fits together
TeamCentral is a single SvelteKit application rendered server-side on Netlify. Every request (from the web app, an AI assistant over MCP, a public share page, a webhook or a scheduled job) passes through one ordered set of server hooks before it reaches a route. Routes are the only code that touches data: the browser signs in and nothing more. Firestore is the system of record, Pinecone holds the search vectors, and model calls go out through OpenRouter.
Swipe sideways to see the whole diagram →
02 · StackWhat it's built with
A deliberately small set of managed services: one framework, one database, one vector store, one model gateway. There are no servers to run; the app ships as one serverless function plus static assets.
| Layer | Technology | How it's used |
|---|---|---|
| Front end | ||
| Framework | SvelteKit, TypeScript, Svelte runes | Server-rendered pages with form actions; client code holds UI state only. |
| UI | Tailwind CSS + DaisyUI | Two app themes (light default, dark), one signature blue-to-teal gradient, Lucide icons. |
| Content | Marked, DOMPurify, Turndown | Markdown in and out of AI answers, sanitized before it renders. |
| Server & hosting | ||
| Hosting | Netlify | CDN for static assets; the whole app runs as one server-side rendering function. |
| Auth | Firebase Authentication | Client SDK signs in, then trades its ID token for an httpOnly session cookie. |
| Scheduling | External cron callers | Token-protected endpoints for news scans, digests, the email queue and clean-up. |
| Data | ||
| Database | Cloud Firestore (Admin SDK) | System of record for users, orgs, meetings, prompts, billing state, logs and analytics. |
| Vector search | Pinecone + Pinecone Inference | Meeting transcript chunks and contact profiles; embedding and reranking in the same service. |
| Media | Cloudinary | Avatars, org logos, social images, design-system files and oversized share pages. |
| AI | ||
| Language models | OpenRouter (OpenAI SDK) | One API for every chat, routing and summarization call; models swap by setting, not code. |
| Assistant access | Model Context Protocol | A built-in MCP server so Claude and ChatGPT can use TeamCentral's tools directly. |
| Integrations | ||
| Calendar & video | Google Calendar API, Zoom | Free/busy heatmaps, booking, and meeting links. |
| Transcripts | Fathom webhook, email in, upload | Meetings arrive automatically or by hand and are indexed for search. |
| Billing | Stripe | Checkout, three plans plus seat add-ons, monthly and yearly. |
| Resend + Handlebars | Templated mail sent from a Firestore-backed queue with retries. | |
| Web data | RSS, scraping, Apify | News Scanner feeds and LinkedIn post scans. |
| Quality | ||
| Checks | Vitest, svelte-check, ESLint, Prettier | Tests live next to the code they cover; type, lint and format checks before each release. |
The codebase at a glance
178 server endpoints, 162 of them under the API.
53 pages, 45 with server-side loaders or actions.
106 server-only library modules, never shipped to the browser.
03 · DataHow data is stored and reached
Firestore holds the truth, including full meeting transcripts. Pinecone holds only vectors pointing back to Firestore records, so the search index can be rebuilt at any time. No browser code reads the database: every query runs in a server route with the Admin SDK, after the hooks have established who is asking.
Firestore
About 60 collections. Server loaders map every document field by field into typed objects and convert timestamps before anything reaches a page, so the client never sees raw database shapes.
Pinecone
Each meeting gets one "topic anchor" vector (title, summary, metadata) plus overlapping transcript chunks. Each user gets one contact-profile vector, re-indexed when the profile is saved.
Cloudinary
Images and binaries. Small text files stay in Firestore; large design-system bundles and oversized share pages are offloaded to the CDN.
Local storage only
Model preference and a meetings cache for speed. Nothing authoritative lives in the browser.
What lives in Firestore
| Domain | What it stores |
|---|---|
| Identity & orgs | Profiles, organizations, connections between users and orgs, sign-up codes, app settings, system prompts. |
| Meetings | Transcripts with AI-generated summaries, decisions and action items; pending meetings; recent chats. |
| BrandBot & Contacts | Conversations and messages, contact requests, design-system files. |
| Prompts & News | Prompt library with folders and version history; RSS feeds, articles and scan caches. |
| Scheduling | Encrypted calendar and Zoom connections, 15-minute availability blocks (start and end times only), share tokens. |
| MCP & sharing | Hashed access tokens, OAuth clients and codes, audit log, chat and article snapshots, hosted share pages. |
| Operations | Billing customers, webhook idempotency records, email queue, query analytics, daily metrics, error logs, health and locks. |
Short-lived records (webhook receipts, MCP audit entries, chat snapshots) carry expiry dates and are cleaned up automatically.
Who can see what
Ownership checked on the server
Every record carries its owner (a user ID or org). Server routes filter on it in every query, and vector search results are re-loaded from Firestore under the caller's ownership before any text reaches a model. A search hit the caller doesn't own is dropped, never summarized.
Roles, plans and orgs
Four roles (user, org member, org admin, admin) decide which screens exist; the subscription plan and the active organization decide which tools and data a request can reach. Contact search only ever looks across the caller's own connections.
04 · SecurityDefense in layers
Each layer assumes the one outside it might fail. The rules are enforced in code review too: secrets come only from the platform's private environment, writes happen only in server code, and nothing sensitive is written to logs.
Edge filtersEvery request
Cross-site form posts are rejected by an origin check; known vulnerability probes are answered with a 404 before any app code runs.
IdentitySession
Firebase session cookies (httpOnly, Secure, SameSite=Lax) with an admin-set lifetime, verified on every request with revocation checks. Disabled accounts are signed out on their next request.
AuthorizationRole · plan · org
An auth guard resolves the user's role, subscription status and active organization before a route runs; tools the plan doesn't include simply aren't reachable.
Secrets at restTokens
Calendar and Zoom OAuth tokens are encrypted with AES-256-GCM. MCP tokens are stored only as SHA-256 hashes and shown once. Email links (unsubscribe, digest settings) are HMAC-signed and compared in constant time.
Inbound callsWebhooks · cron
Stripe and Resend webhooks are signature-verified, and Stripe events are de-duplicated. Scheduled-job endpoints require a secret token compared in constant time.
Abuse limitsRate limits
Per-route limits on sign-in, password reset, contact forms, AI chat (30 a minute per user) and MCP (per IP and per token). Sign-up and reset flows answer the same way whether or not an email exists.
Browser hardeningHeaders · sandbox
A Content Security Policy with an allowlist, HSTS with preload, no-sniff and a strict referrer policy. User-generated share pages render in a sandboxed, null-origin frame so their HTML can never reach the app.
05 · AIHow AI is used to make it work
AI shows up in two ways: as the product (chat over your meetings, brand-aware writing, news summaries) and as plumbing (deciding how to answer a question, naming and summarizing meetings). Every model call goes through one OpenRouter client, every task has a primary and a fallback model, and every call is logged with its cost.
Why OpenRouter
One OpenAI-compatible API reaches Google, OpenAI, Anthropic, xAI, Qwen and DeepSeek models. Swapping or adding a model is a settings change, not a new SDK, and an outage at one provider falls through to another.
Admins choose the default model and the list users may pick from; the server refuses any model not on that list.
AI accounting
Each call records its token usage. Prices come from OpenRouter's live model list (cached for a day, with a built-in fallback table, plus OpenRouter's fee), rolled up per user, per tool and per day, so cost per tool is visible to users and admins.
Which model does what
| Task | Primary | Fallback | Why this pairing |
|---|---|---|---|
| Chat default | Gemini 2.5 Flash | user's pick | Fast, long context, low cost; users switch per conversation within the admin's allowed list. |
| Query routing | Claude Sonnet 4.5 | GPT-5.2 | Strict JSON and careful date handling matter more than speed. |
| News summaries | Gemini 2.5 Flash | GPT-4o-mini | High volume, structured output, lowest cost per article. |
| Fast tasks | Gemini 3 Flash | Grok 4.1 Fast | Short, latency-sensitive calls. |
| Meeting metadata | Gemini 3 Flash | Claude Sonnet 4.5 | Summary, decisions, action items, red flags and sentiment from a transcript. |
| Meeting titles | Grok 4.1 Fast | Gemini 2.5 Flash | One short, cheap call per meeting. |
User-selectable chat models today: Gemini 2.5 Flash, Gemini 3 Flash, Grok 4.1 Fast, GPT-5 Mini, Qwen3 Next 80B and DeepSeek V3.2. The list changes as models improve.
Meeting Assistant: retrieval-augmented answers
- Ingest
Transcripts arrive from Fathom, email or upload. An LLM writes the title, summary, decisions, action items and sentiment.
- Index
One anchor vector per meeting plus 1,500-character chunks with 20% overlap, embedded in batches and stored with owner and date metadata.
- RouteLLM
A router model reads the question and returns JSON: which data path (exact lookup, metadata, totals, semantic, anchors only, or hybrid), plus dates in the user's time zone, people and intent.
- Retrieve & rerank
Vector search pulls up to 150 candidates; a reranker keeps the best 25, with a boost for recent meetings and meeting-level anchors.
- AnswerLLM
Full records load from Firestore under the user's ownership, then the answer streams back with inline citations like
[[Weekly sync, 2026-10-02]].
Retrieval funnel, per question
Questions like "how many meetings with Acme last quarter?" skip vectors entirely: the router sends them to an exact Firestore query, which is cheaper and always correct.
AI in the other tools
BrandBot
Builds its system prompt from the active org's brand training (overview, audience, offerings, tone, guidelines) or the user's own, plus global writing rules. Long conversations are trimmed oldest-first to stay within the model's context, and it notices when a chat drifts off topic.
News Scanner
Reads RSS feeds, scrapes each article (CSS selectors first, an LLM extractor if that fails, then an archived copy), and summarizes it to structured JSON with the low-cost model, retrying on the fallback.
Contact Directory
Semantic search over the profiles of the people you're connected to, then an AI chat that answers questions about your network from those profiles.
Team Scheduler
Deterministic where it counts: free/busy data from Google is cached in 15-minute blocks and drawn as a team heatmap, so availability is always exact.
06 · MCP connectorTeamCentral inside Claude and ChatGPT
TeamCentral runs its own Model Context Protocol server, so an assistant can look up a contact, find a meeting time and book it, pull a meeting summary or load brand context without leaving the chat. The assistant brings its own model; TeamCentral supplies the tools and the data, under the same permission checks as the app.
- Discover
The assistant reads standard OAuth discovery documents and registers itself (Dynamic Client Registration).
- Consent
The user signs in to TeamCentral and approves. PKCE (S256) is required, redirect URLs must match exactly, and codes work once within five minutes.
- Call tools
Opaque, hashed access tokens (12 hours) bound to TeamCentral's MCP address; refresh tokens rotate safely. Every call is capped at 25 seconds and rate-limited.
- Audit
Each call is logged without its parameters, results or token, and with a hashed IP address. Tokens can be revoked at any time.
16 tools, gated by plan
list_my_organizationslist_team_membersfind_contactget_contact_detailssearch_contactssend_emailfind_meeting_timesbook_meetinglist_promptsget_promptcreate_share_link
get_brandbot_contextget_design_systemlist_recent_meetingsget_meetingget_news_digest
Long meeting transcripts are returned in pages, so an assistant can read a two-hour call in full.
07 · OperationsBackground work and design choices
With no servers of its own, TeamCentral runs background work as ordinary endpoints called on a schedule, each protected by a secret token. The news scan also takes a Firestore lock so two runs never overlap.
- every minuteEmail queueSends queued mail in priority order, spaced to the provider's rate limit, with retries and a dead-letter state.
- every 5 minKeep-warmKeeps the server function warm so the first click of the day is fast.
- mornings, 15 minNews scanScans feeds in small batches inside a time budget, so one slow site can't stall the run.
- dailyNews digestBuilds and emails each user's summarized digest.
- scheduledLinkedIn scan · reminders · clean-upPost scans, checkout reminders, and removal of expired snapshots and logs.
- on demandAvailability syncCalendar free/busy is fetched when a heatmap is opened, with a timeout, then cached.
Design choices worth knowing
- Server-first data access. No client database SDK, so access rules live in reviewed TypeScript rather than in a separate rules language.
- Firestore is the truth, vectors are an index. Losing the index loses speed, not data.
- One model gateway. Models are chosen per task and replaced as better or cheaper ones appear, with no code change.
- Routing before retrieval. An LLM decides whether a question needs vectors at all; counts and dates go to exact queries.
- One function, managed services. Simple to deploy and cheap at low volume; the trade-offs are cold starts (hence keep-warm) and platform response-size limits.
Interested in collaboration or a custom installation?
I design and build custom apps like TeamCentral, from the first sketch to running in production. Tell me what you have in mind and I'll reply by email.