Skip to content

Finalsite to Focus Import

How student enrollment data moves from Finalsite (admissions / enrollment) into Focus (the SIS) for KIPP Miami, the decisions behind it, and the limitations the enrollment team should know about.

This page is written for the enrollment / registrar team. It describes behavior, not code — the technical implementation lives in the rpt_focus__* dbt models and is validated by automated tests.

What the pipeline does

Each midday run builds four files from current Finalsite data and delivers them to Focus over SFTP at 12:45 p.m. ET, matching Focus's import templates:

File Focus template Status
Demographics DEMOGRAPHICS Active
Student Enrollment STUDENT_ENROLLMENT Active
Addresses ADDRESS Active
Contacts CONTACTS Active

The 2 p.m. commitment and the two manual steps

The midday timing exists to support one promise: a student entered in Finalsite by 12:00 p.m. ET is usable in Focus by 2:00 p.m. ET. The promise covers new students only — a correction made in Finalsite to a student Focus already has never flows, at any hour (see Where to make corrections below).

Two steps in that chain are done by hand, and the 2 p.m. promise depends on both:

  1. Push the Finalsite SFTP export at 12:00 p.m. Finalsite's own export runs overnight on a schedule that is not ours to change. Without a manual push, the 12:45 delivery carries Finalsite data as of roughly 2:50 a.m. — silently, with no error and nothing on screen to notice. Push it after the noon cutoff, every day. This is Miami only — no other region needs it.

The window is 12:00 to 12:15 — push at noon or just after, not before. An early push misses anything entered between it and the 12:00 cutoff, and those students then wait for tomorrow. The late bound is 12:15: past that, the file may not be ingested and rebuilt in time for the 12:45 delivery. From a 12:15 push the pipeline needs about 11 minutes to have everything rebuilt, so the delivery clears it with roughly 19 minutes to spare.

Nothing breaks if a push lands outside the window. A student whose record is only half-captured is skipped for that day, not half-imported — there is no way to send wrong or duplicate data to Focus by pushing at an odd time.

  1. Run the four Focus imports. The pipeline only delivers files to Focus's incoming/ folder; nothing imports them for you. The imports themselves are quick, so the 75 minutes between the 12:45 delivery and 2 p.m. is slack, not time you need — a student is usable in Focus within minutes of you running them, typically well before 1 p.m.

Do not re-run the delivery after you have imported — ask the data team first. The pipeline decides what Focus already has by reading a copy of Focus taken at 12:00 p.m., not live Focus. Re-run the delivery after you have imported and it sends every record a second time, duplicating it in Focus. A copy is taken again at 2:00 p.m., which normally clears it — but only if your import finished before that copy was taken. If you imported late, 2:00 p.m. is not enough, so check rather than assuming a time makes it safe.

The pipeline is import-once: each run sends only records that Focus does not already have. Once a record has been imported, the pipeline never re-sends or overwrites it. This keeps the imports small and — importantly — means the pipeline never clobbers an edit made in Focus.

Finalsite is the source of truth only for the first import. After a record lands in Focus, neither system automatically wins. The pipeline will not push later Finalsite changes over an existing Focus record, and it will not pull Focus changes back. Until a clearer process is defined, the enrollment team is expected to keep the two systems aligned by hand — a correction made after the initial import must be made in both Finalsite and Focus.

Key design decisions

Student ID — minted in Finalsite

Finalsite mints a new, auto-incrementing 6-digit student ID for every new contact. That ID is what identifies the student in Focus, and the pipeline reads it straight from the contact record.

A student needs a minted Finalsite ID to be sent. If Finalsite has not yet minted an ID for a contact, that student is not included in the import. Make sure the ID is assigned before expecting the student to flow to Focus.

Focus stores the ID with a fixed 8400 district prefix, so the 6-digit Finalsite ID becomes a 10-digit Focus student_id (e.g. 3031978400303197). The pipeline applies that prefix, and the prefixed value is what each record matches on in Focus.

Enrollment codes (entry)

The entry code is derived from grade level:

Grade Enrollment code
Kindergarten E05
All others E01

The entry code reflects how the student entered and does not change when a student withdraws — a withdrawal is expressed by the drop code and end date, not by clearing the entry code. It is written to Focus once; because it's derived from grade, the pipeline never resends it, so a wrong entry code must be corrected manually in Focus.

Withdraw / drop codes

A withdrawal is recognized from a single Finalsite signal: the last-attended date (withdrawal_last_attended_date). A student is treated as withdrawn only when that date is populated and falls on or after the enrollment's start date. When it is, the pipeline sends the end date together with the drop code.

The drop code itself comes from Finalsite's fl_state_withdraw_codes_ss field as the full FLDOE label — e.g. (W02) In District Transfer. Focus's import wants the short code (W02), not the label, so the pipeline looks the label up in Focus's own withdrawal-code list and sends the matching short code in the DROP_CODE column.

Like everything else, a withdrawal is a one-time push — and it only ever lands on an enrollment Focus still shows as open, meaning it has no end date yet. The pipeline fills in the end date and drop code only when that open enrollment doesn't already have a drop code of its own. If Focus has already closed the enrollment with an end date, or the open enrollment already carries a drop code, the pipeline leaves it alone and will not add or correct one — even a wrong or missing drop code has to be fixed in Focus directly.

Enrollment feed — current year, enrolled students only

A student appears in the Student Enrollment file only once Finalsite has an enrollment start date for them — that is, once they are actually enrolled — and that enrollment belongs to the current academic year. Students who are still accepted, in progress, or only assigned a school (with no start date yet) are held back and not sent until they enroll. A prior year's enrollment, or a next year's enrollment recorded before that year is underway, is held back too — the Student Enrollment file only ever carries the year that's currently active.

A student can be in Demographics, Address, and Contacts before they're in Student Enrollment. Those three files are sent as soon as Finalsite marks the student enrolled; the enrollment record additionally waits for a start date, an assigned school, and for the enrollment's year to become the current one. A student enrolled ahead of next year, for example, shows up in Demographics, Address, and Contacts now — their Student Enrollment record follows once that year begins.

Enrollment start date — aligned to the first day of school

Finalsite often records an enrollment's start date as the registration or contract date, which can fall weeks before school actually starts. Focus records enrollments as of the first day of school. To make the two line up, the pipeline raises any start date that falls before the first day up to the first day of school; a start date already on or after the first day is left unchanged (so a genuine mid-year enrollment keeps its real date).

The first day of school is read from Focus's own attendance calendar (the earliest instructional day of the year), so it always matches what Focus expects — for 2026-27 that is August 11, 2026. A school year with no calendar in Focus yet leaves its start dates unchanged.

This lines up what Focus receives for a brand-new enrollment — it is not how the pipeline recognizes one it already sent. Aligning the start date means a new entry lands in Focus on the date Focus expects. The pipeline does not rely on this date to know Focus already has the enrollment; see the next section.

How the pipeline knows Focus already has an enrollment

An enrollment counts as "already in Focus" when Focus has a record for the same student and academic year — those two values alone are the match; the enrollment's start date is not part of it. That's deliberate: once an enrollment lands in Focus, the registrar team may need to correct its start date there, and the pipeline should not mistake that corrected enrollment for a brand-new one. Matched student-years are not re-sent as a new entry (see the exception for withdrawals below).

School, grade, and entry code are not used to decide this either. Focus stores its own internal codes for them and translates the imported values on load, so they never match on a literal comparison even when they describe the same school and grade — comparing them would make every record look new.

The one thing that will still be sent for a matched student-year is a new withdrawal — and only onto that student-year's currently open Focus enrollment (the one Focus has not yet closed with an end date). If the extract now has an end date and drop code, and that open enrollment doesn't already have a drop code of its own, the exit is filled in against whatever start date Focus currently shows for it — so an ops correction to the Focus start date does not stop the withdrawal from landing. See Withdraw / drop codes above for what happens when Focus has already closed the enrollment or the open enrollment already has a drop code.

What gets sent

Every feed follows the same import-once rule — a record is sent only when Focus does not already have it, and nothing is ever overwritten:

  • Demographics — a student's demographics are sent only once Finalsite marks the student enrolled and the student is not yet in Focus. A student who is still accepted, in progress, or only assigned a school does not flow.
  • Student enrollment — an enrollment is sent when the student's (student, academic year) is new to Focus, the student is enrolled (has a start date), and that academic year is the current one; a prior-year or not-yet-current next-year enrollment is held back. A withdrawal (end date + drop code) is filled in once onto that student-year's open Focus enrollment when it has neither yet — never onto one Focus already shows as closed.
  • Addresses — sent only once the student is enrolled and Focus does not already have the address record for that student. The address itself comes from the households the student's Parent 1 is linked to, falling back to the student's own households when Parent 1 has none; when Finalsite points to several, the most complete one is sent rather than none. A household with no street line is not treated as an address at all; a partial address (missing city, state, or ZIP) is sent rather than held, so it can be spotted and corrected in Focus.
  • Contacts — sent only once the student is enrolled, Focus does not already have the record for that student, and the contact has a name. It is the student's enrolled status that gates the feed, not the guardian contact's own. A guardian's address does not gate whether the contact is sent: when Finalsite links the guardian to several addresses the most complete one is sent, and the address is left blank only when the guardian has no street address on file at all — either way the contact still goes out with the rest of their details.

Forward-moving enrollments are protected

A Finalsite contact is reused year to year (re-enrollment keeps the same Finalsite ID and moves the start date forward). The pipeline ensures a new enrollment never carries a previous year's drop code or end date — a last-attended date before the current enrollment's start is treated as belonging to the prior enrollment and is ignored.

Address and contact formatting

Household address values are cleaned before they go to Focus so the imports stay consistent:

  • A blank or space-only field (street, city, state, zip) is normalized to truly empty, not a stray space.
  • The state is upper-cased (e.g. fl becomes FL).

This is formatting only — what decides whether a record is sent at all is covered next.

Blank addresses and nameless contacts are held back

Because addresses and contacts are import-once, a record sent before Finalsite can resolve it would be locked in — a student imported with no address at all would keep that gap in Focus even after a real one is entered, because import-once never sends them again. To prevent that, the pipeline holds a student's address record back only when Finalsite has no usable address for them at all. A guardian's address works differently — see the Contacts bullet below.

  • Addresses — a student's address comes from the households their Parent 1 is linked to, falling back to the households the student is linked to when Parent 1 has none. When Finalsite points to several addresses, the pipeline sends the most complete one rather than sending nothing. A household with no street line is not treated as an address at all; a household that has a street but is missing its city, state, or ZIP is sent, so the gap is visible in Focus and can be fixed there. A student gets no address only when neither they nor their Parent 1 has a household carrying a street line, and flows the first run Finalsite gives either of them one.
  • Contacts — a contact is sent only once it has a name. A nameless contact is skipped and flows once the name is filled in. A guardian's address is resolved from the guardian's own households only, with no fallback: when Finalsite links them to several addresses the most complete one is sent, and the address is left blank only when none of their households carries a street line. The contact goes out with the rest of their details either way.

A guardian's blank address is not held back the way a student's is — it is permanent. A student's address record waits until Finalsite resolves it, then sends a real address the first run it can. A guardian's contact record does not wait: it imports as soon as it has a name, blank address and all, and once that student's contacts have imported, a later Finalsite fix — retiring the extra household, or adding a street where none existed — is never re-sent. A guardian's address gap has to be filled in Focus by hand.

A student can be enrolled in Focus with no address yet. That is expected when Finalsite holds no street address for them or for their Parent 1. Fix it in Finalsite — fill in the missing address, or retire the household the family no longer lives at — and it flows on the next run. (Demographics is not held back this way; a student's demographics import as soon as the student is enrolled in Finalsite and new to Focus.)

Emergency contacts

The Contacts file now carries the student's emergency contacts alongside their parents and guardians. They come from the four emergency-contact slots on the student's Finalsite record — not from the family relationships — and they are sent after the guardians, in the order the slots appear in Finalsite. Each one carries its name, relationship, email, and up to three phone numbers, and is flagged in Focus as an emergency contact. Emergency contacts have no household in Finalsite, so they arrive with no address; that is expected, not a gap.

The custody, pickup, and lives-with checkboxes are sent when Finalsite has them. KIPP Miami's emergency form does not currently collect them, so those three columns arrive blank today and will populate on their own if the form starts asking.

Emergency contacts only reach a student Focus does not already have. The import-once rule matches on the student, not the individual contact — once any contact for a student has been imported, none of that student's other contacts are ever sent, including emergency contacts added later. Add them in Focus directly for students already imported.

Where to make corrections

After the initial import, the pipeline never overwrites Focus — so any correction you make in Focus sticks. The trade-off is that the pipeline also won't carry a later Finalsite correction into Focus. Until a clearer sync process exists, treat the two systems as independent after the first import and harmonize them by hand:

Field After initial import
Demographics (all fields) Sent once. A Focus edit sticks; a later Finalsite change is not pushed.
Entry code (ENROLLMENT_CODE) Sent once (derived from grade). A wrong code must be fixed in Focus.
Withdraw code / end date Filled once onto Focus's open enrollment; once Focus closes it, a later change must be made in Focus.
Address, contacts Sent once. A Focus edit sticks.

Correct after the first import in both systems. Fix the record in Focus so Focus is right today, and update Finalsite too so the two stay aligned — the pipeline will not reconcile them for you.

Known limitations

Finalsite holds current enrollment only — not history. Finalsite tracks a student's current enrollment state, not a multi-year history. The pipeline can send the current enrollment (and a re-enrollment shows up as a new start date), but it cannot send or backfill a prior year's enrollment as a separate record. Focus retains prior years from earlier imports; Finalsite is not the system of record for enrollment history.

  • Home language is sent as the FLDOE language code (e.g. EN), matching what Focus stores.
  • A withdrawal depends on the last-attended date being set in Finalsite. If withdrawal_last_attended_date is blank, the student is treated as still enrolled and no end date or drop code is sent — even if other withdrawal notes exist in Finalsite. Make sure the last-attended date is recorded when a student withdraws.
  • No changes flow after the first import. Because every feed is import-once, a later Finalsite edit will not reach Focus and a Focus edit will not reach Finalsite. The two systems are kept aligned manually.

What the enrollment team should watch for

  • Mint the Finalsite student ID before expecting a student in Focus — records without one are skipped.
  • An enrollment needs a start date, in the current academic year. A student reaches Focus's Student Enrollment file only once Finalsite has an enrollment start date for the academic year that's currently active; accepted, in-progress, or not-yet-current-year students wait until then.
  • Demographics, Address, and Contacts wait for enrolled status too. All four feeds now require Finalsite to mark the student enrolled — a student who is only accepted, in progress, or assigned a school does not appear in any of them yet.
  • The pipeline sends the most complete address on file, not just a single unambiguous one. A student Finalsite links to more than one household no longer gets skipped — the pipeline picks the most complete address rather than withholding. A student with no street on file anywhere still gets no address; likewise a contact still needs a name before it is sent.
  • Duplicate households can still send the wrong address, just not a blank one. A family with two live household records in Finalsite — usually an old address and a current one — no longer blocks resolution, but the pipeline may pick whichever is more complete, not necessarily the current one. Retiring the stale household is still the fix to make sure the right address goes out.
  • A partial address now imports rather than waiting. An address missing its city, state, or ZIP is sent to Focus so you can see and fix it there, instead of the student silently having no address. A household with no street line at all is still not sent — that's the only case where a student gets no address.
  • A student without a Parent 1 designated still resolves an address. Parent 1's households are tried first, but a student missing a Parent 1 designation falls back to their own household instead of being skipped. A student still gets no address only when neither they nor their Parent 1 has a household with a street line.
  • Set the last-attended date in Finalsite when a student withdraws — it is what triggers the end date and drop code being sent.
  • Corrections after the first import are manual. A wrong entry code, drop code, or demographic field must be fixed in Focus, and the same fix made in Finalsite to keep the systems aligned — the pipeline won't resend it.

Questions or issues

For data questions or to report something that looks wrong in a Focus import, contact the Data Team. Technical design history is tracked in the project's pull requests and issues.