Migration, with a receipt you can file.
Switching vendors is a data problem for about a weekend and a human problem for about six weeks. This page covers both honestly: what the importer does, what it deliberately does not do, and the timeline that makes a cutover survivable.
| File | Contents | What the importer does | Typical drops |
|---|---|---|---|
schools.csv | School and org identifiers | Becomes the org hierarchy that row-level security is enforced against | Rows with no id or no name |
students.csv | Student PII and language preference | Language names mapped to ISO codes; retention class set to student_pii at creation | Rows missing an id, first name or last name |
contacts.csv | Parents and guardians | Phones normalised to E.164, emails validated, contacts de-duplicated on email plus phone plus family name | Junk first names — mom, dad, parent, guardian, neighbor, grandma, unknown — and duplicate contact points |
student_contacts.csv | The many-to-many guardian associations | Referential integrity checked against the parsed students and contacts | Links pointing at a student or contact that is not in the export |
staff.csv | Teachers and administrators | Same phone and email normalisation; one person row can later carry both a staff role and a guardian role | Rows missing an id or names |
classes.csv | Sections | Bound to a school, and to a teacher where the teacher resolves | Unknown school; an unknown teacher drops the binding, not the class |
enrollments.csv | Student–class memberships | Validated against parsed classes and students | Unknown class or unknown student |
A missing file is not a silent failure: it is surfaced in the receipt's drops column. The unzip step caps the archive at 200 MB and carries a zip-slip guard, because "upload an archive from a third party" is a category of bug with a long history.
The importer, and exactly what it does
@kastr/importer-parentsquare is MIT-licensed and runs standalone. It takes a folder of CSVs or a ZIP in ParentSquare's documented seven-file export format, parses it, normalises it, and produces a receipt. It does not need a Kastr account and it does not phone home.
The one thing this tool will not do is pretend. Run it without IMPORTER_SIGNING_KEY set and it prints, in red, "no signing key configured" and leaves the signature field empty rather than emitting something that looks signed.
Migration receipt — ParentSquare export
| Record class | In source | Validated | Dropped |
|---|---|---|---|
| Schools | 14 | 14 | 0 |
| Students | 18,044 | 18,044 | 0 |
| Contacts (guardians) | 14,217 | 13,908 | 309 |
| Student–contact links | 31,205 | 30,974 | 231 |
| Staff | 1,089 | 1,089 | 0 |
| Classes | 1,412 | 1,412 | 0 |
| Enrolments | 64,880 | 64,880 | 0 |
Illustrative receipt, synthetic district. Being exact about what this tool does: it reads, validates and signs. It does not write rows into a live Kastr tenant — that step happens with us during onboarding.
What the receipt proves, and why procurement cares
Most migrations are documented by a screenshot of a success message. A receipt is a different class of artefact, and it is the thing that lets a business official sign off without taking anyone's word for it.
- A per-source-file SHA-256 manifest. Which exact file, at which exact byte content, was parsed. If the incumbent later sends a different export, the hashes will not match and you will know.
- An HMAC-SHA256 signature over the bundle hash, computed as
HMAC(key, "${generatedAt}:${bundleSha256}"), so the receipt cannot be quietly edited after the fact. - Counts in versus counts out, per record class. Not a total. Seven rows, each independently checkable against your own export.
- A drop ledger. Every single dropped record, with the reason: duplicate email or phone, junk first name, orphaned relationship, missing identifier.
- A timestamp and source manifest, so the document is dated evidence rather than an assertion.
As far as we can establish, no other vendor in K-12 family communication produces one. It is a weekend of work and it turns "we believe the migration went fine" into a document you can staple to a board agenda.
The honest limit: this validates, it does not load
Read this before you plan around it. The importer parses, validates, normalises and signs. It does not write a single row into a live Kastr database. It is a dry-run validator plus a procurement artefact. The step that loads validated records into your tenant is done with us during onboarding, not self-serve.
We could have described this as "one-click migration" and nobody would have caught it until implementation week. The reason to say it plainly instead is that the receipt's whole value is that it is verifiable, and a tool that overstates one thing has told you what to assume about the rest.
It also means you can run the importer today, against your current export, without any commercial relationship with us at all — and the drop ledger it produces is a genuine data-quality audit of your roster regardless of which vendor you end up choosing.
Six steps, four weeks, one person from your team
- Week 0 — request the export. Ask your incumbent for a full export before you sign anything with anyone. FERPA's portability provisions entitle the district to its data; most vendors return a bundle in two to five business days once a formal written request is on file. We will help draft the request language if that is useful.
- Week 1 — run the importer in validation mode. Get the PDF receipt. Read the drop ledger properly rather than skimming the totals; it is where the surprises are.
- Week 1 — spot-check ten families. Pick them yourself, at random, across schools and languages. Check names, language preference and contact points against what you know to be true. Ten families finds more problems than any automated summary.
- Week 2 — connect the roster feed. Classes and enrolments are better re-derived from a live roster sync than carried across a migration. Roster data is POSTed to
/api/v1/roster/sync; the diff engine classifies every record and the guardrail aborts a run that would withdraw more than half your active students. - Week 3 — train the front office. Two 45-minute sessions, one for office staff and one for principals. Office managers are the real users; they send twenty messages a week and they decide whether this succeeded.
- Week 4 — cut over, and over-communicate first. Announce the change on the old platform, repeatedly, before you turn it off. Families do not care that you changed vendors; they care that the thing which used to tell them about early dismissal has gone quiet.
Timing matters more than any of the six steps. Cut over in June or July: staff get the summer to learn the tool and family re-onboarding rides the back-to-school attention spike. A mid-year cutover asks families to re-enrol in an app when nothing has their attention, and it costs reach. If your renewal date forces the issue, a short bridging extension on the incumbent is a normal procurement conversation.
What does not come across, stated up front
Roster and contact data migrate cleanly. Several other things do not, and every one of them is better handled by planning than by discovering.
- Message history. Keep your export as the archive. It is a public-records and discovery asset and it should stay in the format the originating system produced.
- Form responses and signatures. Signed documents should stay with the system that captured the signature.
- Family app logins and notification preferences. Families re-onboard. This is the actual project. Budget three touches over three weeks, in every language your families read, and expect to chase the last few percent into September.
- Attachments. Kastr does not support file attachments at all today, so there is nothing on our side to migrate them into. That is a genuine gap and it belongs in your evaluation.
For a vendor-specific walkthrough, see switching from ParentSquare, which covers the same ground with a record-by-record table of what moves.
Questions people actually ask
What if our current vendor drags their feet on the export?
Put the request in writing and cite FERPA's portability provisions; districts are entitled to their data and a formal written request usually produces a bundle in two to five business days. Request it early rather than inside a notice period, and confirm which record classes are included, because message history and form responses are frequently handled separately from roster and contact data.
Does the importer actually load our data into Kastr?
No, and we would rather say so on the page than in implementation week. It parses, validates, normalises and signs a receipt. Loading validated records into a live tenant is done with us during onboarding. The tool is genuinely useful before that point — the drop ledger is a data-quality audit of your roster that you can run today, for free, without talking to us.
What exactly is in the signed migration receipt?
A per-source-file SHA-256 manifest, an HMAC-SHA256 signature over the bundle hash, counts in versus counts out for each of the seven record classes, a ledger of every dropped record with its reason, a timestamp, and the importer version. It renders as a PDF. Without a signing key configured it prints an explicit warning instead of a fabricated signature.
When is the best time to switch platforms?
June or July, without much competition. Staff learn the tool over the summer and family re-onboarding rides the back-to-school attention spike, when messages from school are already being opened. A mid-year cutover is survivable but costs reach, and reach is the entire product.
How long does the whole migration take?
The data is a weekend. Family re-onboarding is three to six weeks of communication and the long tail runs into September. Plan around the second number; every district that has done this badly did the data properly and the humans badly.
Switching is a weekend, and you get a receipt.
Our ParentSquare importer is MIT-licensed and runs without us. It validates your export, normalises phone numbers and languages, drops the junk guardian records, and emits a signed PDF receipt with a per-file SHA-256 manifest — a procurement artefact, not a developer log.