Cryptocurrency Tracker docs
v2.0.0
Live demoConsole demo Get help
● Set up · admin/

Operator console
run the app without code.

A small Node server you host yourself. It serves the MIKODES Admin Kit console at /admin, writes the app's settings to Firestore and gives you pages for revenue, users, alerts, sponsored slots, affiliate clicks, push campaigns, news and provider usage.

Node 22SQLite or PostgresDockerfile included

01What the console does

  • Settings → Firestore. The console is the only writer of the app's configuration. On every save, and once at start, it writes config/public (served to the app by the API's /v1/config) and config/private (read only by Cloud Functions: provider keys, feed URLs, AI key, RPC overrides, store verification and ad reporting keys). Each write bumps version and sets updatedAt.
  • Invalid lines are skipped, never guessed. A news source without a URL, a waterfall that names a network without that format, a sponsored slot that ends before it starts: each is left out and listed on the Status page.
  • Server-side access only. It uses the Firebase Admin SDK on the server. The browser never talks to Firestore.
  • Keys are write-only. Only the owner can set them. They are encrypted with ADMIN_SECRET_KEY, never shown again, never sent to the browser and written only to config/private. Each key has a Test button.
  • Money switches default to off: ads and every placement, Pro, in-app purchases, affiliates and sponsored slots. Every number has a hard minimum and maximum.
  • Every write is audited in the kit's append-only audit log.

What it never does: it never writes a backend field (proStore, alertsCount, stats, purchases and so on), never sends a push message itself, never deletes a user's alert, never shows a key it stored, and never estimates, converts or projects revenue (admin/README.md, test admin/test/writers.test.ts).

02Environment variables

Copy admin/.env.example to admin/.env (never commit it) or set these in your host's environment.

VariablePurposeWhere to get it
ADMIN_SECRET_KEY Required32 random bytes that encrypt the secrets the console stores (provider keys, AI key, store keys, RPC URLs).Generate: openssl rand -hex 32. Back it up. Without it the stored secrets cannot be read. If it is missing, the console generates data/.admin-secret-key and warns in the log; move it into your environment.
GOOGLE_APPLICATION_CREDENTIALSPath to a service-account key file of your Firebase project.Firebase console → Project settings → Service accounts → Generate new private key. Leave empty on Cloud Run or GCE to use the attached service account.
FIREBASE_PROJECT_IDOptional. Set it when the credentials do not name the project.Your project id.
FIRESTORE_EMULATOR_HOSTLocal development only: use the Firestore emulator, for example 127.0.0.1:8080, with no credentials. Project demo-cryptotracker unless FIREBASE_PROJECT_ID is set.—
ADMIN_DATAsample = built-in sample data and no Firebase at all (public demo). Empty = Firestore.Leave empty on your install.
ADMIN_DEMO_PASSWORDOnly on a public demo host: makes the console a read-only demo (account demo@cryptotracker.demo, a viewer).Leave empty on your install.
PORTHTTP port.Default 8790.
DATABASE_URLOptional Postgres for the console's own data (team, sessions, settings, audit) instead of data/admin.sqlite.Neon, Supabase, Cloud SQL… Use a pooled URL with sslmode=require.
The service account bypasses security rules

Keep its key file on the console's server only. Never put it in the app, in git or in a support message. The Firestore indexes the console's queries need are in firebase/firestore.indexes.json and are deployed with the backend.

03Run it and create the owner

cd admin
npm ci
cp .env.example .env   # fill in ADMIN_SECRET_KEY and GOOGLE_APPLICATION_CREDENTIALS
npm start              # http://localhost:8790/admin
  1. Find the setup codeOn first start the log prints a one-time setup code. Each start before an owner exists prints a new one; any printed code works.
  2. Create the ownerOpen /admin, choose Create the owner, enter the code, your e-mail and a password of 12 or more characters.
  3. Add your teamUnder Team, add managers and viewers.
  4. Fill in the sections in this orderLegal (privacy and terms URLs), Data providers (a free CoinGecko Demo key lifts the rate limit), News sources, AI summaries (optional), then the money sections when you are ready. Status shows what is still missing.

Compiled build instead of tsx: npm run build && npm run start:dist.

04Roles and sign-in security

RoleCan
ViewerRead every page and setting (keys stay hidden).
ManagerAct on the product pages (users, alerts, sponsored, push, revenue entries) and change settings.
OwnerEverything, plus set secrets and store identifiers, and manage the team.

The kit adds two-factor sign-in codes, a lockout after 5 failed sign-ins within 15 minutes, settings history and export/import (vendored Admin Kit 0.4.0, admin/vendor/mikodes-admin/; do not edit those files, fixes arrive with product updates).

05Deploy options

WhereHow
Any Node 22 host (VPS, Render, Railway, Fly)npm ci && npm start. Data lives in data/admin.sqlite: put data/ on a persistent disk, back it up together with ADMIN_SECRET_KEY, and run one instance.
DockerSee below. The volume keeps /app/data.
Serverless or several instances (Cloud Run with autoscaling)Set DATABASE_URL to Postgres; tables are named mk_cryptotracker_*. Give the service an account with the Cloud Datastore User role and leave GOOGLE_APPLICATION_CREDENTIALS empty. The console uses only Firestore (it never sends push itself).
cd admin
docker build -t cryptotracker-admin .
docker run -p 8790:8790 -v cryptotracker-admin-data:/app/data --env-file .env cryptotracker-admin

Put HTTPS in front of it (a reverse proxy or the platform's TLS). The session cookie is marked Secure over HTTPS and the server honours x-forwarded-proto.

06Settings sections

SectionWhat you set
BrandApp name (default "Cryptocurrency Tracker"), accent colour (default #10B981), support e-mail. See Rebranding.
LegalTerms URL, privacy policy URL, the disclaimer shown under prices, the brief and every report, and the four labels: "AI-generated", "Automatic summary", "Sponsored", "Affiliate link". The labels cannot be empty.
FeaturesSwitch whole parts of the app on or off: portfolio, price alerts, news, wallet tracking (public addresses), converter, market brief and coin reports, home-screen widgets, cloud backup of the user's lists. All on by default.
Sign-in methodsWhich sign-in buttons the app shows: Google, Apple (iOS and web), e-mail and password. All on by default; keep a method on only after enabling that provider in Firebase Authentication. With all three off the app says sign-in is not offered (users stay anonymous).
MarketDefault currency, the fiat currencies offered (30 by default), coins per page (10–250), refresh interval (15–3600 s), category chips (CoinGecko category ids).
Data providersPrimary provider, failover, CoinGecko plan and key, CoinMarketCap key, per-minute and monthly budgets, cache times. See Data providers.
News sourcesRSS feeds, refresh interval, how long headlines are kept. See News sources.
AI summariesOn/off, brief, coin reports, provider, key, model, caps and per-user allowances. See AI summaries.
AdsMaster switch, one network or a waterfall per format, every placement. See Ads.
AdMob / AppLovin MAX / Unity Ads / ironSource LevelPlay idsApp ids, SDK keys and unit ids per network and platform.
Pro and purchasesPro on/off, free and Pro limits, home-screen widgets for Pro only, perks, store product ids, AI pack size, store-verification keys. See Purchases.
AffiliatesOn/off, the Buy button, the disclosure and the exchange links. See Affiliates.
SponsoredSponsored coins and sponsored news (easier on the Sponsored page). See Sponsored.
Wallet chainsWhich chains users can look up, and your own RPC URLs. See Wallets.
Ad revenue reportingOptional AdMob and AppLovin MAX reporting keys. See Revenue centre.
NotificationsThe kit's standard operator notifications: an e-mail address for console alerts, and an optional webhook URL with a signing secret. These are for you, not for app users (app push is under Push campaigns).

07Product pages

PageWhat it shows and does
OverviewReal counts only: users, active and new today, Pro users, active alerts, alerts triggered and AI calls today, CoinGecko calls and CoinMarketCap credits this month.
Revenue centreRealised revenue only. Record sponsor bookings, affiliate and ad payouts, pull ad reports. See Revenue centre.
UsersSearch by user id (users sign in anonymously). Grant Pro until a date or for life, revoke the console grant, add or remove AI credits, grant remove-ads, ban or unban. Every action needs a reason and is audited.
AlertsActive alerts by type and coin, triggers in the last 7 days, recent triggers. Disable switches an alert off; the console never edits or deletes a user's alert otherwise.
SponsoredSponsored coins and news with schedule, state, impressions and clicks; record a sponsor booking.
Affiliate clicksTaps per exchange link. Payouts are recorded in the revenue centre.
Push campaignsCreate a message to everyone, Pro or free users, with an optional coin deep link, at a time or Send now; cancel while scheduled. See Push campaigns.
NewsThe newest stored headlines and the last item seen per source.
Provider usageCalls, credits and errors per provider and month against your budgets.
StatusFirestore reachable, last config sync, CoinGecko with the configured plan, the CoinMarketCap key, the AI key (a passing test is reused for 6 hours so the page does not spend tokens on every visit), each enabled feed, each RPC override, ad ids for what is on, store verification, ad reporting, revenue events without an amount, legal URLs, and every skipped settings line.

08Public demo console

To show the console to others without Firebase, run a separate instance with ADMIN_DATA=sample and ADMIN_DEMO_PASSWORD=<a password you publish>. Visitors sign in as demo@cryptotracker.demo, a viewer. No owner exists and every write answers 403. Sample users, alerts and campaigns are labelled "Sample" (ids start with sample-). The sample has no revenue at all, no news headlines, no provider usage and no sponsored or affiliate numbers. Its settings produce exactly the demo app's configuration (firebase/functions/src/api/demo-config.ts, checked by admin/test/sample.test.ts). Never set these two variables on your real console.

09Tests

cd admin
npm test                # manifest, defaults = contract, config mapping, writers, checks, revenue, sample, page routes
npm run test:emulator   # real writes against the Firestore emulator (needs the Firebase CLI and Java)
npm run build           # TypeScript check + compile to dist/

When these docs were written, npm test reported 65 passing tests (9 emulator tests are skipped without the emulator), checked again at the 2.0.0 release commit.