MongoDB Atlas App Services configuration (functions + triggers) for the
custom-home-sec project, managed as code instead of being copy-pasted into the
Atlas web editor.
App Services app: Triggers (Client App ID triggers-jzeek, project 64667e5a73876c614f15afb7).
Two pieces of logic live here:
Trigger (app/triggers) |
Type | Function (app/functions) |
What it does |
|---|---|---|---|
lead_history |
Database (INSERT, UPDATE on leads.leads) |
Atlas_Triggers_lead_history_1756228609 |
Appends each change to the leads.history event log. |
visit_history |
Scheduled (*/30 * * * *) |
Atlas_Triggers_visit_history_1718045998 |
Rolls up status-change events from leads.history into the per-lead leads.visit_history summary (used by the API's leads_table enrichment). |
The function names are the auto-generated identifiers from the Atlas Triggers UI. Renaming them in this repo would create new functions and orphan the live ones, so leave them as-is unless you intend to recreate the triggers.
This directory is a verbatim appservices pull of the live app, so it can be pushed
back without drift.
app/
root_config.json # App metadata (name "Triggers", region, deployment model)
data_sources/
custom-home-sec/config.json # Linked Atlas cluster ("custom-home-sec" data source)
environments/ # Per-environment values (currently empty)
functions/
config.json # Function manifest (name, private)
Atlas_Triggers_lead_history_1756228609.js
Atlas_Triggers_visit_history_1718045998.js
triggers/
lead_history.json
visit_history.json
.mdb/ # CLI local state (gitignored)
scripts/
sync.sh # Wrapper around the `appservices` CLI
.env.example # API keys + APP_ID template
-
Install the App Services CLI
npm install -g atlas-app-services-cli # provides the `appservices` binary -
Atlas API key with App Services access (Project > Access Manager > API Keys). Copy
.env.exampleto.envand fill in:cp .env.example .env # set MONGODB_ATLAS_PUBLIC_API_KEY, MONGODB_ATLAS_PRIVATE_API_KEY, APP_ID.envis gitignored.scripts/sync.shauto-sources it. -
Unique index on
visit_history.lead_id— already exists in production (the$merge ... on: "lead_id"stage has relied on it for years). Only relevant if you ever rebuild the collection in a fresh environment, in which case recreate it with:db.visit_history.createIndex({ lead_id: 1 }, { unique: true })
The data source already points at the real custom-home-sec cluster (captured from
the live app), so no placeholders need editing.
The app/ directory is a pull of the live triggers-jzeek app and is currently
in sync (./scripts/sync.sh diff reports no changes). Day-to-day:
# 0. Check tooling + auth
./scripts/sync.sh doctor
# 1. Authenticate (reads keys from .env)
./scripts/sync.sh login
# 2. Edit files under app/, then preview the change
./scripts/sync.sh diff # appservices push --remote $APP_ID --dry-run
# 3. Deploy
./scripts/sync.sh push # appservices push --remote $APP_IDCommit each change with a conventional-commit message and open a small MR.
To re-import live state (e.g. if someone edits in the Atlas UI), run
./scripts/sync.sh pull — note this overwrites local files, so review the git diff.
push/diff always target $APP_ID, so they can never create a duplicate app.
./scripts/sync.sh logs tails recent function/trigger execution logs.
- Look-back vs schedule: the
visit_historyfunction looks back 1 hour; the trigger runs every 30 minutes (*/30 * * * *). Overlap is intentional and safe — the$mergede-duplicates identical{status, timestamp}entries with$setUnion. Keep the schedule interval shorter than the 1-hour look-back so no events are dropped. - Unbounded array:
visit_history.updatesgrows over a lead's lifetime. The API only consumescount, so consider capping/trimmingupdatesif very active leads approach the 16 MB document limit. - Service name: the data source is named
custom-home-secand the functions reference it viacontext.services.get("custom-home-sec"). Keep these in sync.