GFS Platform
Runbook
Procedures, checklists, onboarding, secret rotation, incident response
Procedures
11
Incident playbooks
7
Checklists
7
Onboarding steps
9
NS nav entries
34
Quick links
- Onboarding a new admin
- Secret rotation
- Incident response playbooks
- Day-to-day procedures (Deploy, Sync Troubleshooting, D1 Ops, Secrets, Emergency Recovery)
- Cadenced checklists (Daily / Weekly / Monthly / Quarterly / Annual)
- NetSuite navigation map
- Admin SuiteQL queries — see data-model → SuiteQL library
Onboarding a new admin
End-to-end provisioning from "this person exists" to "they can run sync, query D1, and deploy the Worker". Update the Decisions log (ADR) with the new admin's name and starting scope.
Provisioning a new admin from scratch
- Confirm the new admin's identity and need-to-know scope. Decide whether they should have NS Administrator or a scoped custom role (Controller / Sales & Ops Mgr etc).
- In NetSuite: Setup → Users/Roles → Manage Roles. Pick or create the role. Assign permissions per least-privilege — never copy Administrator wholesale.
- In NetSuite: Setup → Users/Roles → Manage Users → New. Set name, email, password reset link. Assign roles. Set Subsidiary = GFS, Default Role = the one above.
- In Cloudflare: dash.cloudflare.com → Manage Account → Members → Invite. Send invite with the minimum role needed (Reader for view-only, otherwise narrower built-in roles).
- Local tools (only if the new admin will run sync): install wrangler (npm i -g wrangler), run wrangler login on their machine, confirm they appear in wrangler whoami.
- Chartstone Pro: hand off the localhost API key. Set CHARTSTONE_SECRET in their ~/.zshenv. Verify with curl http://127.0.0.1:56411/health on their machine.
- Bookmarks: send this admin guide URL, GAPS_TO_CLOSE, and the Cloudflare dashboard link. Tag them in the Decisions log (decisions.html) so they know where decisions are recorded.
- Knowledge handoff: 30-min walk-through of admin-dashboard, runbook (this page), and the daily/weekly checklists below. Confirm they can run a D1 query via wrangler.
- Update the Personnel section of this runbook with the new admin's name and scope. Record the date and starting permissions in the Decisions log (ADR).
Secret rotation
Cadenced rotation of every Bearer token and API key. Record each rotation in the Decisions log so an audit trail exists.
API_KEY (Worker) — rotate Quarterly + on suspected leak
- Generate new key: openssl rand -hex 32
- wrangler secret put API_KEY (paste new value)
- Update any consuming clients (admin-dashboard checks reload automatically)
- Test: curl -H 'Authorization: Bearer $NEW' https://api.ai-globalfoodsolutions.co/api/kpis
- Record rotation in Decisions log with date and operator
CHARTSTONE_SECRET (local) — rotate Quarterly + on machine change
- Generate in Chartstone Pro UI → API → New Token
- Edit ~/.zshenv: replace the CHARTSTONE_SECRET= line
- Reload shell: source ~/.zshenv
- Test: ~/Desktop/gfs-platform/sync.sh manual run; tail -20 sync.log
- Record rotation in Decisions log
NetSuite TBA tokens — rotate Annually + on integration removal
- In NS: Setup → Users/Roles → Manage Authentication Tokens
- Identify active tokens (SuiteAttach id 11, Analytics Warehouse id 2)
- Create new token under the SAME integration record
- Update the consuming system with the new TOKEN_ID + TOKEN_SECRET
- Test the integration
- Revoke old token only after the new one is confirmed working
- Record rotation in Decisions log
Cloudflare API token (if used) — rotate Quarterly
- dash.cloudflare.com → My Profile → API Tokens
- Create new token with minimum scope (zone:read, worker:edit, pages:edit, d1:edit, etc — narrow as possible)
- Update local ~/.cloudflare.toml or env
- Revoke old token
Incident response playbooks
"X is broken — do these steps." Each playbook is independent and short enough to execute under pressure.
Sync stopped (D1 stale)
- Check sync.log: tail -50 ~/Desktop/gfs-platform/sync.log
- If localhost connection refused: open Chartstone Pro and verify it's running
- If 'Operation not permitted': run xattr -d com.apple.provenance sync.sh; re-launch via launchd
- If Bearer rejected: rotate CHARTSTONE_SECRET (see secret rotation)
- If wrangler errors: wrangler login; wrangler whoami
- Manual catch-up: run sync.sh from terminal; observe stdout
- Verify in D1: wrangler d1 execute gfs-netsuite --remote --command 'SELECT MAX(lastmodifieddate) FROM transactions'
D1 quota or write errors
- Check D1 size: Cloudflare dashboard → Workers & Pages → D1 → gfs-netsuite → Metrics
- If over 10GB: identify largest tables — usually transactions or invoice_lines
- Archive: DELETE FROM transactions WHERE year < 2020 (after exporting to R2 via wrangler r2 object put)
- If write rate-limited: pause sync.sh temporarily (sudo launchctl unload ~/Library/LaunchAgents/gfs-sync.plist)
- Resume: sudo launchctl load ~/Library/LaunchAgents/gfs-sync.plist
API_KEY leaked or suspected leak
- Immediately rotate: wrangler secret put API_KEY (new value)
- wrangler tail — watch for requests with the old key (will start 401-ing)
- Audit access logs in Cloudflare dashboard → Workers → gfs-platform → Logs
- Notify anyone who legitimately had the old key with the new one
- Record incident in Decisions log with timeline
Cloudflare Pages site down
- Check status: https://www.cloudflarestatus.com
- If global Pages issue: wait, no action
- If specific to gfs-netsuite project: dash.cloudflare.com → Workers & Pages → gfs-netsuite → Deployments → Roll back to previous
- If build failed: check deploy logs, fix locally, re-run wrangler pages deploy
NetSuite unavailable
- Check status.netsuite.com
- If NS down: sync.sh will fail silently (Chartstone returns empty results). D1 keeps the last-known data.
- Admin dashboard data quality grades remain valid; live KPIs (when implemented) will show 'stale'
- No action until NS is restored. After restoration, sync.sh catches up on its next 15-min run.
Period close blocked
- Run the period-close SuiteQL admin query (see data-model → SuiteQL admin library → Period close)
- Identify unposted transactions in the period
- Either post them OR move them to a different period after verifying impact
- Re-run close from NS UI: Setup → Accounting → Manage Accounting Periods → Lock the period
Suitelet 500 error (public broker portal)
- Check the Suitelet's script execution log in NS: Customization → Scripting → Script Execution Log
- Identify the error — usually a query that timed out or a NULL where a value was expected
- If a downstream consumer broke (a broker missing data), notify the broker contact
- Fix in the Suitelet code (File Cabinet folder 717413), redeploy
- If urgent: take the Suitelet offline (uncheck isonline=T) until fixed
Day-to-day procedures
Recovered from the original ops dashboard. Each is a stepwise procedure for a recurring admin task.
Deploy Worker Changes
- Edit source:
- ~/Desktop/gfs-platform/src/index.ts
- Test locally:
- cd ~/Desktop/gfs-platform && npm run dev
- Opens local dev server at localhost:8787. Test endpoints.
- Deploy:
- npm run deploy
- Runs
- wrangler deploy
- . Deploys to gfs-platform.mikelevine.workers.dev
- Verify:
- Hit /api/health and one auth endpoint to confirm
Deploy Dashboard to Pages
- Prepare deploy folder:
- rm -rf /tmp/gfs-deploy && mkdir -p /tmp/gfs-deploy/docs /tmp/gfs-deploy/diagrams
- Copy files:
- cp guide/*.html guide/*.css /tmp/gfs-deploy/ && cp guide/diagrams/*.html /tmp/gfs-deploy/diagrams/ && cp dashboard/index.html /tmp/gfs-deploy/command-center.html && cp docs/04-Power-Tools.html /tmp/gfs-deploy/docs/
- Deploy:
- wrangler pages deploy /tmp/gfs-deploy --project-name gfs-system-guide
- Verify:
- Check gfs-system-guide.pages.dev
Sync Troubleshooting
- Sync not running
- Check launchd:
- launchctl list | grep gfs
- Should show two entries (sync every 900s, report at 7pm).
- Check Chartstone:
- Open Chartstone Pro, verify it's running on port 56411
- curl -s http://127.0.0.1:56411/health
- — should return 200.
- Check Full Disk Access:
- System Settings → Privacy → Full Disk Access → Terminal.app
- macOS Sequoia blocks launchd scripts without this.
- Check wrangler auth:
- wrangler whoami
- Should show mikelevine@gfs account. Re-login:
- wrangler login
- Check sync log:
- tail -20 ~/Desktop/gfs-platform/sync.log
- Sync running but no data
- Check Chartstone secret:
- grep CHARTSTONE_SECRET ~/.zshenv
- Test query manually:
- Run the SuiteQL from sync.sh against Chartstone directly
- Check D1 write:
- wrangler d1 execute gfs-netsuite --remote --command="SELECT COUNT(*) FROM sync_log"
D1 Database Operations
- Query D1 directly
- wrangler d1 execute gfs-netsuite --remote --command="YOUR SQL HERE"
- Backup D1 (manual export)
- wrangler d1 execute gfs-netsuite --remote --command="SELECT * FROM customers" --json > backup_customers.json
- Repeat for each table. No native D1 full-export yet. Automate with a shell script.
- Reload a table from SQL loader
- wrangler d1 execute gfs-netsuite --remote --file=sql/01_customers.sql
- Loader files use INSERT OR REPLACE. Safe to re-run.
- Check database size
- Current:
- ~28.3 MB of 10 GB limit (0.3% used). At current growth, years of runway.
- Monitor quarterly. D1 limit is 10 GB per database.
Secrets & Credentials
- Worker API_KEY
- Set via: wrangler secret put API_KEY
- Chartstone secret
- In ~/.zshenv as CHARTSTONE_SECRET
- Wrangler auth
- OAuth token — wrangler login to refresh
- NS credentials
- In Chartstone Pro config
- CF account
- mikelevine — dashboard.cloudflare.com
- NS account
- 4656898 — system.netsuite.com
- Rotation schedule
- API_KEY:
- Rotate quarterly. Update Worker secret + dashboard sessionStorage clears automatically.
- Chartstone:
- Rotate if laptop changes. Update ~/.zshenv.
- NS password:
- Per company policy. Update Chartstone config after change.
Emergency Recovery
- Worker down
- Check CF status:
- cloudflarestatus.com — verify no platform outage
- Check Worker logs:
- CF Dashboard → Workers → gfs-platform → Logs
- Redeploy:
- cd ~/Desktop/gfs-platform && npm run deploy
- D1 data corruption
- Reload from SQL loaders:
- Files in sql/ directory are the original full dataset
- Incremental data:
- entity backfill, GL accounts, vb_lines added post-load would need re-sync
- Laptop failure (total loss)
- Worker + D1 + KV + R2 are in Cloudflare
- — survive laptop loss
- Source code:
- once git pushed to remote, recoverable
- Until then: this is the single copy. git init + remote push is critical.
- Sync will stop
- — sync.sh runs on laptop. Server-side sync (Phase 3) eliminates this risk.
Cadenced checklists
Daily / weekly / monthly / quarterly / annual reviews. Recovered from the original ops dashboard.
Daily — Morning (7:00 – 9:00 AM) (20 items)
- Review KPIs on Command Center
- Open this dashboard → Dashboard tab. Check: Revenue YTD pace, Open AR total (flag if > $2.5M), Open SO count. Takes 2 min.
- Check sync health
- System tab → Sync Log. Verify last sync was
- 1 hour, check launchd:
- launchctl list | grep gfs
- Review new orders overnight
- NS → Transactions → Sales → Sales Order List. Filter: Date = Today, Status = Pending Fulfillment. Route to warehouse.
- Check overdue AR
- Collections tab → Aging table. Any new entries in 61-90 or 90+ columns = escalation needed. Flag for afternoon call.
- Process pending POs
- NS → Transactions → Purchases → Purchase Order List. Filter: Status = Pending Receipt. Verify with warehouse on expected deliveries.
- Check email for vendor confirmations
- Match PO confirmations to open POs. Update expected receipt dates if changed.
Daily — End of Day (4:00 – 5:00 PM) (15 items)
- Confirm all shipments processed
- NS → Transactions → Sales → Item Fulfillment List. Filter: Date = Today. Verify tracking numbers entered.
- Invoice shipped orders
- NS → Transactions → Sales → Invoice List. Create invoices for all fulfilled SOs. Verify terms match customer record.
- Apply received payments
- NS → Transactions → Customers → Accept Payment. Match checks/ACH/wire to open invoices.
- Bank deposit if applicable
- NS → Transactions → Bank → Make Deposits. Group payments received today.
- Review daily report at 7pm
- Auto-generated by daily-report.sh (email delivery coming in Phase 3). Compare to morning KPIs.
Weekly — Monday (18 items)
- Full AR aging review
- Collections tab or NS → Reports → Financial → A/R Aging. Identify accounts for escalation. Send reminder emails for 30+ days. Owner: Amanda S.
- Vendor bill reconciliation
- NS → Reports → Payables → Open Vendor Bills. Match against POs and receipts. Flag discrepancies. Owner: Amanda S.
- Inventory spot check
- NS → Reports → Inventory → Inventory Valuation. Check negative items list. Review pending WOs (currently 0). Owner: Elena M.
- CME pricing review
- Check CME block/barrel prices. Update Bongards formula calc (trailing week avg + 35% moisture). Notify affected customers of changes. Owner: Michael L.
- Sales pipeline review
- Revenue tab → Customer Ranking. Compare to prior week. Review open SOs > $10K. Update forecast. Owner: Sales team.
- Open PO follow-up
- NS → Transactions → Purchases → PO List. Filter: overdue POs. Contact vendors for ETA. Owner: Buyer.
Weekly — Friday (9 items)
- Week-end revenue snapshot
- Dashboard → Revenue YTD. Compare to last week's number. Calculate weekly run rate vs $29M annual pace.
- Prepare next week's ship schedule
- NS → Sales Order List. Filter: Ship Date = next week. Ensure warehouse capacity. Flag large orders.
- Vendor payment run
- NS → Transactions → Payables → Pay Bills. Select bills due this week. Process payment batch.
Monthly Close — By 10th of Following Month (69 items)
- Phase 1: Days 1-3 — Transaction Cleanup
- Final invoicing
- — invoice ALL fulfilled SOs from prior month
- Run saved search: Fulfilled SOs with no invoice. Create invoices. Zero should remain.
- Apply all payments
- — zero unapplied payments
- NS → Customers → Unapplied Payments. Match to invoices or create on-account credit.
- Bank reconciliation
- — match NS to bank statement
- NS → Transactions → Bank → Reconcile. All cleared items should match. Investigate discrepancies.
- Credit card reconciliation
- — verify all charges posted
- Phase 2: Days 3-5 — Accruals & Adjustments
- AP accruals
- — accrue for received-not-billed items
- Create JE: Debit expense, Credit accrued AP. Reverse in new period.
- Prepaid expense amortization
- — recognize monthly portions
- Inventory adjustments
- — resolve negative items, write-offs
- NS → Transactions → Inventory → Adjust Inventory. Document reason for each adjustment.
- Rebate accruals
- — estimate earned rebates by customer
- Calculate based on volume tiers. JE: Debit rebate expense, Credit accrued rebate liability.
- Phase 3: Days 5-7 — Revenue & Review
- Revenue recognition review
- — verify all revenue properly recorded
- Match invoice totals to revenue GL accounts. Investigate variances.
- Intercompany/related party entries
- — if applicable
- Review all journal entries
- — verify proper documentation
- NS → Reports → Financial → General Ledger. Filter: JE type, current period.
- Phase 4: Days 7-9 — Reports & Verification
- Trial balance review
- — all accounts balanced
- NS → Reports → Financial → Trial Balance. Compare to prior month. Investigate swings > 10%.
- P&L review
- — revenue, COGS, gross margin, operating expenses
- Compare to budget. Flag variances. Prepare management commentary.
- Balance sheet review
- — assets, liabilities, equity tie-out
- Cash flow statement
- — verify operating, investing, financing
- Phase 5: Day 10 — Close
- Close accounting period
- Setup → Accounting → Manage Accounting Periods → select month → Close All. Prevents further posting.
- Distribute management reports
- — P&L, Balance Sheet, AR Aging
- Update forecast
- — adjust annual projection based on actuals
Quarterly (16 items)
- Customer tier review
- — reclassify by volume
- Compare YTD volume to tier thresholds. Update pricing levels. Notify sales of changes.
- Vendor performance review
- — on-time delivery, quality, pricing
- Procurement tab → Vendor Spend. Compare to prior quarter. Flag underperformers.
- 1099 vendor review
- — verify eligibility and tax IDs
- NS → Lists → Relationships → Vendors. Filter: Is 1099 Eligible = Yes. Verify W-9 on file.
- Saved search cleanup
- — archive unused, consolidate duplicates
- 968 searches exist. ~300 are TAF/SII/Intrastat from unused bundles. ~20 are dead Zapier/Airtable.
Annual (16 items)
- 1099 filing
- — generate and file by January 31
- NS → Reports → Financial → 1099 Report. Verify all eligible vendors have tax ID.
- Customer contract renewal review
- Identify all contracts expiring in next 90 days. Schedule renewal discussions. Update pricing.
- NS role and access audit
- 97 roles, 116 employees. Verify terminated employees disabled. Review admin access (currently concentrated on 1 user).
- Budget preparation
- — build next year's budget in NS
- Use Revenue tab data + vendor spend analysis for informed projections.
- Data Quality Dashboard
- — Every entity type graded A through F based on field completeness. Each F-grade item has an assigned owner and remediation plan. Data quality directly impacts every workflow — bad data = broken processes.
Source
- data/runbook-source.json — procedures + checklists extracted from the original ops dashboard
- data/ns-navigation.json — NetSuite navigation map
- Onboarding, secret rotation, incident response playbooks authored in this build pass