Skip to content
s9terpsync-release-bot edited this page Aug 6, 2026 · 3 revisions

S9TerpSync Wiki

S9TerpSync keeps Slate CRM and your Ellucian ERP in sync as a single, file-state Node.js service — no Docker, no database, and no external ETL platform to license or run. It's built to drop onto a RHEL/systemd box and stay there. Version 1 moves data from Slate into Banner through Ethos APIs; Slate-to-Colleague support is planned.

This project is aimed at institutions that don't have an ETL platform in place, or can't justify buying one just for this. If your institution already has Ellucian Ethos Data Connect, use that instead — it's the better-supported path. Boomi, MuleSoft, and Jitterbit equivalents of this same sync are coming as separate open-source pipelines.

How it works

Every trigger — manual CLI run, scheduler tick, or service boot — converges on the same safety path.

flowchart TB
  cli["CLI run<br/>manual, dry-run or live"]
  cron["Scheduler tick<br/>cron, non-overlapping"]
  boot["Service boot<br/>startup run assessment"]

  preflight["Preflight gates<br/>config, reference data, crosswalks"]
  coordinator["Run coordinator<br/>run lock, RUNNING manifest"]
  discover["Discover and claim<br/>SFTP or Slate API source"]
  acquire["Two-pass acquire<br/>checksum, duplicate skip"]
  decode["Decode and map<br/>canonical applicant per row"]
  match["Crosswalk and person match<br/>resolve codes, find person"]
  plan["Plan target commands<br/>nine ordered stages"]
  gateway["Target command gateway<br/>DRY_RUN plans, LIVE mutates"]
  evidence["Institution evidence gate<br/>fixture-only evidence is non-live"]
  ethos["Ellucian Ethos APIs"]
  banner["Banner ERP<br/>implemented v1 target"]
  colleague["Colleague ERP<br/>future target family"]
  finish["Complete and finish<br/>report, archive, mark processed"]
  state["File-based state<br/>locks, run audit, idempotency, reports"]

  cli --> preflight
  cron --> preflight
  boot --> preflight
  preflight --> coordinator
  coordinator --> discover
  discover --> acquire
  acquire --> decode
  decode --> match
  match --> plan
  plan --> gateway
  gateway --> evidence
  evidence -->|only when verified for school LIVE| ethos
  ethos --> banner
  ethos -. future .-> colleague
  gateway --> finish
  coordinator --> state
  acquire --> state
  gateway --> state
  finish --> state

  classDef pipeline fill:#EEEDFE,stroke:#534AB7,color:#26215C
  classDef mutation fill:#FAECE7,stroke:#993C1D,color:#4A1B0C
  classDef failure fill:#FAEEDA,stroke:#854F0B,color:#412402
  classDef readonly fill:#E1F5EE,stroke:#0F6E56,color:#04342C
  classDef neutral fill:#F1EFE8,stroke:#5F5E5A,color:#2C2C2A
  class preflight,coordinator,discover,acquire,decode,match,plan,finish pipeline
  class gateway,evidence,ethos,banner mutation
  class state readonly
  class cli,cron,boot,colleague neutral
Loading

How data moves from Slate to Banner

Every applicant record starts as a Slate export and ends as a set of Banner writes made through Ethos. A Banner person record is always matched or created first; everything else depends on it (and admission decision, student attribute, and student cohort also depend on the admission application existing first). This is the real dependency order the stage engine enforces — src/stages/stage-registry.ts is the single source of truth for it.

flowchart TB
  slate["Slate CRM export<br/>SFTP file or API"]
  canonical["Decode, crosswalk,<br/>match to a Banner person"]

  subgraph entities["Nine target entities, in dependency order"]
    person["Person"]
    permanentAddress["Permanent address"]
    priorSchool["Prior school"]
    familyAddress["Family address"]
    familyRelationship["Family relationship"]
    admissionApplication["Admission application"]
    admissionDecision["Admission decision"]
    studentAttribute["Student attribute"]
    studentCohort["Student cohort"]

    person --> permanentAddress
    person --> priorSchool
    person --> familyAddress
    person --> familyRelationship
    person --> admissionApplication
    person --> admissionDecision
    admissionApplication --> admissionDecision
    person --> studentAttribute
    admissionApplication --> studentAttribute
    person --> studentCohort
    admissionApplication --> studentCohort
  end

  ethos["Ellucian Ethos APIs"]
  banner["Banner ERP"]

  slate --> canonical --> person
  entities --> ethos --> banner

  classDef pipeline fill:#EEEDFE,stroke:#534AB7,color:#26215C
  classDef mutation fill:#FAECE7,stroke:#993C1D,color:#4A1B0C
  classDef failure fill:#FAEEDA,stroke:#854F0B,color:#412402
  classDef readonly fill:#E1F5EE,stroke:#0F6E56,color:#04342C
  classDef neutral fill:#F1EFE8,stroke:#5F5E5A,color:#2C2C2A
  class canonical pipeline
  class person,permanentAddress,priorSchool,familyAddress,familyRelationship,admissionApplication,admissionDecision,studentAttribute,studentCohort,ethos,banner mutation
  class slate neutral
Loading

Core entities

Entity What it carries Ethos resource
Person Match an existing Banner person (by Banner ID or Slate ID) or create one persons v12
Permanent address The applicant's Banner address persons v12
Prior school High school code, graduation date, GPA high-school-information-high-school-details v1
Family address Parent/guardian address general-person-identification-address v1
Family relationship Parent/guardian record and relationship type guardian-information v1
Admission application Application header, curricula, term/level/campus/program admissions-application-curricula v1
Admission decision Admit / deny / waitlist code and date admissions-decision-processing v1
Student attribute Attribute records tied to the application admissions-application-contacts-cohorts-attributes v1
Student cohort Cohort records tied to the application admissions-application-contacts-cohorts-attributes v1

See Ethos & Banner Prerequisites for exactly what to grant for each of these, and Configuration Reference for how source data maps into them.

Find your page

  • Installation & Requirements — for whoever installs the software: supported platforms, npm vs. source installs, and what the two shipped binaries do.
  • Ethos & Banner Prerequisites — for whoever administers your Banner/Ethos environment, before you touch the CLI at all: the integration user, the Ethos application/proxy, and exactly which resources need to be granted.
  • Configuration Reference — for whoever writes s9terpsync.yaml: every field, section by section, and how secrets are referenced without ever landing in plain YAML.
  • Running S9TerpSync — for the operator doing a manual run: run, run resume, and run recover-lock, and how dry-run and live modes differ.
  • Service & Systemd Operation — for whoever stands this up as a long-lived service: the systemd install plan, the service-level lock, and where state, logs, and secrets live on disk.
  • Retention, Replay & Recovery — for whoever cleans up after an interrupted or partially-failed run: retention policy, replaying incomplete records, and retry manifests.
  • Diagnostics & Troubleshooting — for whoever gets paged when a run fails: local diagnostics, Ethos contract status, and what each exit code means.
  • Architecture Overview — for contributors: the module boundaries and design constraints behind the codebase, not a how-to-contribute guide.

Clone this wiki locally