Skip to content

Territory map 2026-11-10: Central US and MCE to Bryant Cloud - #271

Closed
jj-mobilemark wants to merge 85 commits into
trycompai:mainfrom
jj-mobilemark:cursor/territory-map-2026-11-10
Closed

jj-mobilemark wants to merge 85 commits into
trycompai:mainfrom
jj-mobilemark:cursor/territory-map-2026-11-10

Conversation

@jj-mobilemark

Copy link
Copy Markdown

Updates to Ken's Territory Map 2026 (updated 11/10/2026 – KL) and the 2026 Sales Team by Region sheet (Rev A).

  • Nino Barker (NB) left. Central US (AR, IA, KS, LA, MN, MO, NE, ND, OK, SD, TX) and the MCE Connectronics distributor move to Bryant Cloud (BC, [email protected]). Jordan confirmed the code.
  • Ken's name and email ([email protected]) are filled in, and the "Syynex" spelling is added as an alias.
  • Every other state, province, international region and exception was checked line by line against the PDF and is unchanged.
  • Bryant has no Sage, Django or MM-CRM user ID yet. Those come later, as his accounts are set up.

The same map is updated in MM-CRM, MM-Doc-Scanner, MM-Doc-Scanner-Demo (Blue Folder) and MM-Analytics (branch cursor/territory-map-2026-11-10 in each).

Tests: bun test src/sales-territory.test.ts: 18 pass, including the new Central US → BC, MCE → BC and no-NB cases.

Effect: until Bryant has an MM-CRM user, Central US web leads land unassigned in the shared pool (before this change they went to Nino's user). The order-defaults rep_territory field returns BC.

Made with Cursor

jj-mobilemark and others added 30 commits August 2, 2026 09:33
…cker

Snapshot of local work before merging new upstream (trycompai/crm @288d41a):
- Phase 0: additive Outlook id columns + migration.
- Phase 1: Microsoft SSO via Better Auth; email/password fallback; optional
  MICROSOFT_* env; sign-in and grant-access UI.
- Phase 2: apps/api/src/microsoft/ mail + calendar sync, match, connection,
  router; timeline wiring; interim Microsoft settings panel.
- CompanyPicker replaces the plain company dropdown in create sheets.
- Docs/plans and .cursor project scaffolding.

Co-authored-by: Cursor <[email protected]>
Log the branch-first merge of upstream trycompai/crm @288d41a into
m365-expansion (zero conflicts) and the post-merge verification. Note the new
git layout: work on m365-expansion, main tracks pure upstream.

Co-authored-by: Cursor <[email protected]>
…-ups)

Phase 3 — targeted Graph backfill when a contact is added (EmailBackfill
model, contacts.service enqueue, outlook-mail-backfill.service worker).

Phase 4 — Screening Room for unmatched external correspondents
(PendingContact model, screening-harvest hooked into unmatched mail drop,
screening tRPC router, /screening approve/reject UI).

Phase 5 — per-rep Follow-ups panel (FollowUpSuggestion model, propose_followups
+ read_rep_followup_context agent tools on a daily per-rep AgentTask, followups
tRPC router + cron route, /follow-ups UI with suggestions, open tasks and
active deals).

check-types, lint and test all pass; server.ts regenerated (12 routers / 51
procedures). HANDOFF.md and the plan doc's Definition of Done sections are
updated for all three phases.

Co-authored-by: Cursor <[email protected]>
origin was trycompai/crm (read-only for this account); renamed it to
upstream, forked to jj-mobilemark/crm as the new origin, and fast-forwarded
main to m365-expansion's tip so main carries every phase done so far.

Co-authored-by: Cursor <[email protected]>
Per-rep float/lookback/scope settings filter the cockpit and bias the daily
sweep; HANDOFF records that eve dev needs a manual schedule dispatch and an
AI Gateway key before suggestions can appear.

Co-authored-by: Cursor <[email protected]>
Adds the additive schema (sage ids + Sage 100 customer key on Company,
sage id on Contact, RecordSource.SAGE, SageSyncState + SageRecordSnapshot;
migration add_sage_sync), the SAGE_SOAP_* config + capability helper, and the
apps/api/src/sage module: SOAP client (logon/query/logoff over eware.dll,
fast-xml-parser), field/owner mappings, and unit tests. Deal changes, the
import route, and the id-surfacing UI are deferred.

Also documents Phase 7 in docs/plans/sage-crm-sync.md (confirmed SOAP access,
field mappings, forecasting gap, and the resumable/throttled backfill +
incremental design for 27k+ records) and updates HANDOFF.md.

Co-authored-by: Cursor <[email protected]>
Import Mobile Mark companies/contacts via SOAP, fix nested person email/phone
parsing, and surface Sage CRM + Sage 100 IDs with one-click copy in tables and sheets.

Co-authored-by: Cursor <[email protected]>
Add Deal Sage/forecast columns, mapOpportunity + stage mapping, pull the test
slice opportunities (with DealContact), and point the next agent at forecast UI.

Co-authored-by: Cursor <[email protected]>
7.4b full pull (docs/plans/sage-crm-sync.md §6): SagePullService.runBackfill
+ scripts/sage-backfill.ts import every non-deleted company (nested people)
then opportunity, inside one global Sage session (withSageSession advisory
lock), throttled query/next. GET /internal/sync/sage now runs runScheduled
(test slice while phase=backfill, incremental once flipped). Migration
add_sage_backfill_state extends SageSyncState (phase/backfillId/highWater) and
adds sageDeactivatedAt + push-echo markers. ensureSageUsers pre-creates the 11
reps.

Mapping corrections against live data:
- Company owner from Sage acctmgr (name match); contacts inherit company owner.
- amount <- forecast (Sage total is unused/empty); weightedAmount = amount x
  certainty (was storing the full value as weighted).
- Deal createdAt <- opened; closedAt <- closed -> targetclose -> opened
  (no more stamping "now").
- Sage 100 id shows the customer number only (drop the unused 00- division).

One-time backfill scripts recompute the already-imported rows from snapshots
(owners, deal dates, amount/weighted) with no Sage refetch.

Also includes overview date-range + dashboard forecast, deal edit-access, and
the auth admin allow-list from this work series. Docs (plan, project-overview,
HANDOFF) updated to match.

Co-authored-by: Cursor <[email protected]>
Ship the sequences panel with Outlook send, deal/task priority plus a Tasks page, and the Sage outbox push path so local CRM edits can sync back to Sage.

Co-authored-by: Cursor <[email protected]>
Railpack does not detect Bun, so the API and Next app build from oven/bun images with turbo filter commands.

Co-authored-by: Cursor <[email protected]>
@crm/db postinstall runs prisma generate, which requires DATABASE_URL even though no DB is contacted during the image build.

Co-authored-by: Cursor <[email protected]>
Chained start commands exited after migrate deploy; run migrations then Nest from one shell script.

Co-authored-by: Cursor <[email protected]>
Raw Nest TypeScript decorators crash under Bun in the container; use the built dist/main.js entrypoint after migrate deploy.

Co-authored-by: Cursor <[email protected]>
Track deal field changes from app edits and Sage pull, show a 7-day pulse on the overview, and add a Me/Everyone pipeline chat that reads the same pulse data.

Co-authored-by: Cursor <[email protected]>
Railway Dockerfile builds only see service vars when they are ARG/ENV; without that Next inlined localhost and Microsoft sign-in CORS-failed.

Co-authored-by: Cursor <[email protected]>
Geocode via Nominatim into stored lat/lng, filter by owner and Sage link, and open the company record sheet from the split list/map view.

Co-authored-by: Cursor <[email protected]>
Keep reps on the map while they filter by view, focus a pin, and open the shared company sheet without navigating to /companies.

Co-authored-by: Cursor <[email protected]>
Prefer deal amount for closes this month so Sage forecast-only deals still count without treating noisy certainty as the headline.

Co-authored-by: Cursor <[email protected]>
Replace Comp AI copy in the UI and ship the signal favicon/app icons plus wordmark on the auth panel so the product reads as Mobile Mark end to end.

Co-authored-by: Cursor <[email protected]>
Server-side app→API calls via the public hostname return Cloudflare HTML
Error 1000; route them over Railway private networking instead.

Co-authored-by: Cursor <[email protected]>
Keep prior mapList rows during filter changes, reset stale Leaflet bounds, and treat empty Sage ids as unlinked so Has Sage ID no longer looks like zero results.

Co-authored-by: Cursor <[email protected]>
Reps care about ERP customer numbers; every Sage-pulled company already has a CRM id, so the old filter was a no-op.

Co-authored-by: Cursor <[email protected]>
Drop the create-account UI and disable email/OAuth signup server-side so new users cannot register against prod CRM data.

Co-authored-by: Cursor <[email protected]>
GitHub builds need Dockerfile.agent on main; eve/just-bash cannot run under Bun or npx in this monorepo.

Co-authored-by: Cursor <[email protected]>
Update sageStage/sageStatus on setStage so the deal sheet matches what we push, and add a read-only SOAP check script for opportunity verification.

Co-authored-by: Cursor <[email protected]>
Managers can ask about closing months and open-by-stage from real deal data instead of inventing totals beyond the 7-day pulse.

Co-authored-by: Cursor <[email protected]>
jj-mobilemark and others added 25 commits August 5, 2026 13:12
Entra mailbox policy + WEBFORM_MAILBOX are live; record cron-webform and ops status in project overview, HANDOFF, and Railway/webform plans.

Co-authored-by: Cursor <[email protected]>
Sage's next-based pagination is session-stateful, so a dropped session
("You are not logged on.") could not resume mid-walk. Detect the fault,
drop the cached session id, and restart the same changed-set walk
(upserts are idempotent) instead of failing the whole sync. Also make
/internal/sync/sage return 503 on a hard failure so Railway's curl -f
cron check goes red instead of showing a false green on a failed pull.

Already running in prod (deployed via Railway upload on 2026-08-06);
this just brings git up to date with it.

Co-authored-by: Cursor <[email protected]>
New read-only, external lookup so the doc-scanner / PO-processing app
can fill attention/phone/email/rep/is_distributor from this CRM's own
Sage pull instead of a separate replica:

- GET /company/:masCustomerNo/order-defaults, with a
  GET /company/order-defaults?name=&zip= fallback for callers with no
  MAS customer number yet. X-API-Key guard on a new CRM_API_KEY secret
  (separate scope from CRON_SECRET).
- Mechanical only: returns exactly what Sage sync already wrote
  locally (primary contact, company owner, territory-map rep,
  distributor name-list match), null-safe, with a fields_returned list
  so the caller can tell "not sourced yet" from "genuinely empty".
  tracking/ship_via/freight/terms_code stay out of v1 on purpose — no
  source for them.
- packages/db: new isDistributor() helper (independent of assignRep's
  rep resolution, since a distributor can still be an ambiguous-rep
  match) plus tests; @@index([sage100CustomerNo]) on Company for the
  lookup key.

Design notes in docs/plans/sage-crm-sync.md §7.

Co-authored-by: Cursor <[email protected]>
Sage company SOAP payloads already carry mas_termscode (~4.8k filled).
Read it from SageRecordSnapshot for the matched company so the sister
PO-processing app can stamp terms without a new Company column.

Co-authored-by: Cursor <[email protected]>
Sister intake often has letterhead + ship-to + email and no Bill-To.
Rank MAS-backed companies from labeled signals (MAS hint, email,
buyer/letterhead, bill-to, phone; ship-to candidates only), reject
vendor names, and auto-accept only at high confidence. Soft
order-defaults lookups (?name=, ?email_domain=, ?phone=) reuse the
same engine.

Co-authored-by: Cursor <[email protected]>
Mail/calendar were queuing identify and company-profile tasks continuously and burning the AI Gateway budget; Re-enrich/Research on the company sheet still works.

Co-authored-by: Cursor <[email protected]>
The 40s deadline and connect blips were killing the nightly incremental
pull. Also skip trycompai/crm v1.14.0 — too much overlap with this fork.

Co-authored-by: Cursor <[email protected]>
…zing deals.

Sage often leaves updateddate unchanged after a push, so a permanent echo skip left Won/Lost rows on open stages (opp 799). This month now includes deals dated later in the calendar month.

Co-authored-by: Cursor <[email protected]>
Everyone is the team pipeline, not a shared inbox — keep mailbox threads and calendar events on the signed-in user.

Co-authored-by: Cursor <[email protected]>
Nightly cron-sage was returning 503 on the first curl because Sage next wedged with List index out of bounds or Query failed; restart the changed-set walk in-process instead of waiting on curl retry.

Co-authored-by: Cursor <[email protected]>
Hide overdue tasks on Everyone so deals use the full row. Root
`bun run prisma generate` now forwards to packages/db.

Co-authored-by: Cursor <[email protected]>
…CRM-only.

Use blue for new pipeline on the won-vs-created chart so the two series separate.

Co-authored-by: Cursor <[email protected]>
Ken's Territory Map 2026 (updated 11/10/2026 - KL): Nino Barker left; Central US (AR, IA, KS, LA, MN, MO, NE, ND, OK, SD, TX) and MCE Connectronics move to Bryant Cloud (BC). Ken's name and email filled in. Everything else checked unchanged against the PDF.

Co-authored-by: Cursor <[email protected]>
@vercel

vercel Bot commented Nov 11, 2026

Copy link
Copy Markdown

@jj-mobilemark is attempting to deploy a commit to the Comp AI - PoC Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
github-actions Bot changed the base branch from release to main November 11, 2026 15:07
@github-actions

Copy link
Copy Markdown
Contributor

Retargeted this onto main.

release is the default branch so that a plain clone runs the last tagged release, but nothing merges into it — it is fast-forwarded onto the tag by the Release workflow and that is all. Changes go to main, and reach release when a release is cut.

Nothing is wrong with your branch. If the diff now shows commits that are already on main, rebase and force-push:

git fetch origin main
git rebase origin/main
git push --force-with-lease

@jj-mobilemark

Copy link
Copy Markdown
Author

Opened against the wrong repository by mistake; closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant