Compliance · Guidance
Technical notes & open questions.
The short version of Cadenza's compliance posture is on the main compliance page. This page is the deeper one: technical detail for reviewers who want to know how the stack is built, plus the specific questions we're actively seeking input on from Canadian education-privacy counsel and experienced edtech founders.
Last reviewed April 22, 2026 · legal@studycadenza.com
Each topic below is collapsed by default. Expand the ones you want to go deeper on.
CodebaseTypeScript · Next.js 16+
Cadenza is written in TypeScript and built on Next.js 16 (App Router). The entire codebase is a single repo hosted on GitHub; there is no separate backend service. API routes live inside the same Next.js app as the UI pages.
We use pnpm for dependency management and Vitest for tests. Type-checking runs on every commit; every push to the main branch triggers a production deploy.
Why this matters for compliance: A single codebase with strict type-checking means the surface area for "what talks to student data" is narrow and auditable. Every read and write path is one of a small number of API routes, and each is statically typed against the database schema.
BackendNext.js API routes + Supabase+
The backend is a set of server-side API routes running on Vercel's serverless infrastructure. There's no long-running server, no persistent background worker, no daemon holding credentials. Each request spins up, does its work, and exits.
For data storage, we use Supabase, a managed Postgres provider. Supabase also provides authentication (email magic-link), row-level security, and a storage service for uploaded files (syllabus PDFs, when a user opts in).
The database schema is small, approximately 15 tables, and each user-scoped table has an access rule that restricts reads and writes to the authenticated user. A user can never see another user's rows, even by accident.
Why serverless + managed Postgres:It reduces the operational attack surface. We don't run our own server, so there's no long-running process that could be compromised and quietly mine data. The managed database handles encryption-at-rest, backups, and point-in-time recovery without us writing custom code for any of it.
Hosting, today and after migrationVercel, Supabase Oregon to Montréal+
Three layers, three providers:
- Web application. Hosted on Vercel. Vercel runs on AWS infrastructure in the US by default.
- Database.Hosted on Supabase, currently in AWS us-west-2 (Oregon, US). Migration to Supabase's ca-central-1 (Montréal, Canada) is planned before any UofT launch.
- AI inference. OpenAI's API, which runs in US data centers.
No data is replicated to European regions. Static assets (images, fonts) are served through Vercel's CDN, which has edge nodes globally but does not cache student-specific data.
Why the Montréal migration is a hard prerequisite: Ontario's public-sector privacy expectations (both FIPPA's written requirements and UofT's likely contractual expectations under a future data access agreement) favour Canadian residency for student data. The move is straightforward (Supabase offers one-click region switching for paid tiers), and we're doing it before, not after, institutional engagement.
DNS & routingCloudflare+
The studycadenza.com domain is registered with Cloudflare. Cloudflare handles DNS resolution, TLS termination at the edge, and some request caching (though never for authenticated API routes).
Requests to studycadenza.com resolve through Cloudflare, then forward to Vercel's servers where the Next.js application runs. The chain is: browser → Cloudflare edge → Vercel → Supabase (for database) or OpenAI (for inference).
Why Cloudflare:DDoS protection, fast DNS, edge TLS, and a sensible security baseline (bot filtering, WAF rules) that we'd otherwise have to build ourselves. Cloudflare does not see decrypted application data. TLS is re-established from Cloudflare to Vercel.
Canvas tokens, how we handle themPer-request, encrypted at rest+
The full lifecycle of a student's Canvas token:
- Student generates the token themselves inside Quercus settings. Cadenza never sees the UTORid password.
- Student pastes the token into a form on Cadenza.
- On the server, we immediately encrypt the token with a server-held key (industry-standard authenticated encryption). The key is stored as an environment variable on Vercel, never in source code or database rows.
- The encrypted token is written to the database.
- When Cadenza needs to call Canvas, the token is decrypted inside the memory of that specific HTTP request, used to make the Canvas call, and discarded when the request ends.
- The student can revoke the token at any moment from inside Quercus. When they do, our next attempted call gets a 401 and we surface an error in the UI prompting them to re-authorize.
Why this design:The decrypted token is never persisted, never cached, never sent to any other service. The shortest reasonable window of exposure. If an attacker obtained the raw database, they would get encrypted blobs they can't use without the key, which is elsewhere.
What we persist, in detailCourse structure only+
When Cadenza runs an AI Import for a course, the pipeline extracts and persists:
- Course code, title, and term dates.
- Week numbers and the Monday-start date of each week.
- Reading titles and due dates from the syllabus.
- Module and lecture titles (public-facing names, not slide contents).
- Announcement titles (not bodies, titles only).
- The study plan our AI generates from the above, including task titles and short "why this matters" explanations.
What the pipeline explicitly filters out before any write:
- Grades and grade distributions.
- Submission contents (the student's own work).
- Test or quiz questions that aren't publicly posted.
- Instructor-only materials (rubrics, answer keys).
- Any information about other students' enrollment, submissions, or performance.
- Private messages, discussion posts not explicitly public, calendar events containing PII.
Why the filter is in our code, not just in Canvas's permissions:Canvas's read-only API still exposes much more than a study planner needs. By filtering on our side we narrow the scope further, and we can prove exactly what is in scope by pointing at the filter code.
Telemetry & observabilityStage-level, no content+
Cadenza records one telemetry row per AI Import run. Each row lists the pipeline stages that ran, their durations, their success/error status, and the counts of rows produced at each stage (e.g., "parsed 14 weeks," "generated 16 tasks").
What telemetry rows do not contain: actual reading titles, actual task content, actual course names, or any identifiable student information. Counts only. Stage names only.
Why this separation:We need observability to debug pipeline failures. We don't need student course content to live in a diagnostic log where it could leak into stack traces or error alerts. The counts tell us when something's wrong; the real data stays in the user-scoped tables under normal access rules.
Secrets & environmentVercel-managed+
All secrets (the Canvas token encryption key, the Supabase service key, OpenAI API keys, Resend email keys) are stored in Vercel's environment variable manager. They are injected into the runtime at deploy time and are never present in source code, never written to the database, and never appear in logs.
The repository itself excludes any local .env file from version control. A developer running Cadenza locally needs their own .env file with the appropriate keys, which are communicated out-of-band.
Why this matters: The single biggest source of edtech data leaks historically is API keys committed to public repos. Our design makes that structurally difficult. A key cannot be in source because the build never expects it there.
If any of these are within your expertise and you'd be open to a short introductory call, write to legal@studycadenza.com. We're happy to prepare specific materials in advance.
On the regulatory frame+
- Which statute governs third-party access to student Canvas data at UofT: FIPPA, PIPEDA, or both simultaneously?
- Does UofT treat Canvas course metadata (titles, dates, module structure) as personal information under FIPPA, or only once it's linked to a named student?
- What's the prevailing interpretation of a student-generated Canvas API token as a consent basis under FIPPA?
On the Phase 1 path+
- What is UofT's process for issuing a Canvas developer key to a third-party tool operating under student consent?
- Are there UofT-recognized precedents for student-consent-operated apps we can learn from?
- Would a time-limited pilot (10 to 20 consenting UofT students, 60 days) under a light MOU be workable while longer conversations run?
On data residency and cross-border processing+
- Is Canadian data residency a hard requirement during Phase 1, or only at Phase 2 institutional scale?
- Where does UofT stand on AI processing that happens in US-based cloud infrastructure, over course content? Does de-identification change the answer?
On Phase 2 readiness+
- What level of demonstrated adoption (consenting students, duration of clean operation) would UofT consider sufficient to begin the Phase 2 conversation?
- What artifacts would UofT expect at Phase 2: third-party security audit, SOC 2 Type I, penetration test, user testimonials?
On liability and incorporation+
- What insurance coverage is typical for a third-party processor working under a UofT agreement: E&O, cyber liability, professional indemnity? Minimum coverage levels?
- Is Canadian incorporation a prerequisite for Phase 2 eligibility, or can a pilot proceed before incorporation?
On edge cases+
- Are there categories of student data that, even with explicit consent, cannot be shared with a third-party tool? (Accommodation records, health-intersecting data, disciplinary records.)
- If Cadenza receives accommodation information incidentally through a student's Canvas profile, what's the expected handling?
Looking for the short version? The main compliance page is the summary a UofT Legal reader can scan in three minutes.
Cadenza is an independent project, not affiliated with or endorsed by the University of Toronto or Instructure, Inc.