Teacher Supreme — Security & Privacy Overview

Audience: District IT, privacy officers, procurement. Product: Teacher Supreme — a Progressive Web App that helps K-12 teachers log student interactions, attendance, and work samples. Vendor: Agentic Edge Ventures — contact: James Morris, james@agenticedgeventures.com. Document version: 1.1 — July 10, 2026 (added on-device photo redaction §4b and AI usage guardrails §4c). Last reviewed with each production deploy.

This page is the short answer to the question a district asks before piloting a new teacher tool: *what happens to student data, and how do we know?* It is written to be understood without reading the codebase. Every claim on this page is enforced in source control; the files listed in parentheses are the single source of truth and are reviewed on every pull request.

1. FERPA posture

Teacher Supreme treats all student records as education records subject to the Family Educational Rights and Privacy Act (FERPA, 20 U.S.C. § 1232g) and operates under the school-official exception. The district remains the data controller; Agentic Edge Ventures is the processor and will execute a Data Processing Addendum (DPA) on request, including the Student Data Privacy Consortium (SDPC) National Data Privacy Agreement (NDPA) where the district prefers that template.

The product never sells student data, never uses it to train advertising or third-party models, and never shares personally identifiable information (PII) with any party that is not contractually bound to the same FERPA posture. There is no ad network, no analytics SDK that receives student fields, and no third-party script that runs against the student-data views.

2. Per-teacher data isolation (Row-Level Security)

Teacher-to-teacher isolation is enforced in the database, not in the application. Every PII-bearing table (classes, students, attendance_logs, interactions, work_samples, audit_log) carries a teacher_id UUID NOT NULL column that references auth.users. Row-Level Security is enabled and FORCEd on each table, and every SELECT/INSERT/UPDATE/DELETE policy reduces to a single predicate: auth.uid() = teacher_id. Service-role credentials that can bypass RLS are held only in the Supabase project dashboard and the CI secrets store; they never ship to the PWA, never reach a client device, and are not accessible to the teacher-facing application server under normal operation.

The exact policy text lives in supabase/migrations/0002_rls.sql. A regression is not theoretical: every pull request runs a pen-test route (src/app/api/rls-test/route.ts) that creates two ephemeral teacher accounts, inserts a student under teacher A, then authenticates as teacher B and asserts four separate failure modes (cross-teacher SELECT, cross-teacher INSERT impersonation, cross-teacher UPDATE, cross-teacher audit-log read). The CI workflow (.github/workflows/ci.yml, job rls-test) fails the build if any of the six assertions fail, which means a deploy containing a weakened RLS policy is not reachable through our release process.

3. Append-only audit log

Every mutation of a FERPA-relevant row writes a row to audit_log via a SECURITY DEFINER trigger (supabase/migrations/0003_audit.sql). The log records the acting teacher's UUID, the operation (INSERT/UPDATE/DELETE), the table and row ID, before/after snapshots, the actor role claim from the JWT, a request correlation ID, and a UTC timestamp. Sensitive columns (full_name, preferred_name, parent_name, parent_phone, parent_email, notes, ai_summary, email) are redacted to the literal string [REDACTED] before the snapshot is stored, so the log proves *that* a change happened and *who* made it without itself becoming a second copy of the PII.

INSERT, UPDATE, and DELETE on audit_log are revoked from the authenticated, anon, and PUBLIC roles at the SQL level; only the definer-trigger path can write to it, and nothing in the application has the grants required to tamper with a prior entry. Teachers can read their own audit rows via the same auth.uid() = teacher_id RLS predicate; no teacher can read another teacher's history.

4. LLM boundary — no raw PII leaves the database

The product uses Google Gemini to draft narrative summaries and parent-conference notes from logged interactions. Before any text is sent to Gemini, the src/lib/ferpa-shield.ts anonymizer substitutes every student reference with a deterministic opaque token (STU-001, STU-002, …) scoped to the current conversation. Gemini receives tokens, not names. The model's response is re-hydrated with the real names only after it arrives back inside the authenticated teacher's browser session. No student name, parent name, email, or phone number is included in any LLM payload, by construction — the anonymizer is a single choke point, and its unit tests assert that each sensitive field is tokenized before the outbound call.

Google's Gemini API, per its published enterprise terms, does not use content submitted through the paid API to train its models. We do not use Gemini's free-tier or consumer endpoints.

4b. Photos are scrubbed on the teacher's device — before they exist anywhere else

A photographed worksheet often shows the student's name in their own handwriting. A text filter can't help with that — the name is part of the picture. So Teacher Supreme removes it *on the teacher's phone, before the photo is ever uploaded*:

  • When a teacher snaps a worksheet for Snap-Grade, the app reads the text in the photo on the device itself (using an OCR engine that runs inside the browser — the photo is not sent anywhere to do this).
  • It compares what it finds against the class roster already on that device, and also looks for the "Name:" line at the top of a worksheet.
  • Any match is blacked out by rewriting the image's pixels — not a sticker laid on top, but a permanent replacement. The name cannot be recovered from the file that leaves the phone.
  • Only that scrubbed image is sent for grading.

If the on-device scan cannot run for any reason, the app does not quietly upload the photo anyway. It stops, tells the teacher, and asks them to either retake the photo with the name out of frame or personally confirm that no name is visible. In plain terms: a student's name leaves the device as pixels only if a teacher has looked at the photo and said so.

Honest limits, stated plainly: text recognition on messy handwriting is very good but not perfect, which is exactly why the "Name:" line is also scrubbed even when the handwriting can't be read, and why the teacher stays in the loop as the final check. The scrubbing code is a single choke point (src/lib/photo-shield.ts) with unit tests asserting that a roster name found in a photo is always covered by a redaction box.

4c. Cost and abuse guardrails protect the service for everyone

Every AI feature has a per-teacher monthly allowance, a global pause switch the founder can flip instantly without a deploy, and an automatic report that flags any single account using far more than a typical teacher — so one misbehaving account or stuck device can't degrade the service (or the budget) for everyone else's classroom. These counters track *how many times* a feature was used, never the content of what was said or photographed.

5. Encryption

Data at rest in Supabase Postgres is encrypted with AES-256 (managed by Supabase/AWS KMS). Data in transit uses TLS 1.2 or higher between the PWA and Supabase, between the application and Gemini, and between the PWA and our CDN. The service worker's offline cache sits in the browser's IndexedDB sandbox on the teacher's device; it inherits the OS-level disk encryption of the device (FileVault on macOS / BitLocker on managed Windows / device-encryption on managed Chromebooks) and is wiped on sign-out.

6. Sign-out wipes local caches

When a teacher signs out, the application awaits a full clear of the IndexedDB stores (sync queue, cached server reads, any draft rows) *before* the sign-out promise resolves, and then sends a CLEAR_DATA_CACHES message to the service worker so the runtime Cache Storage buckets are dropped as well. This means a shared-device scenario (a teacher using a lab laptop) leaves no retrievable student record behind after sign-out completes.

7. Data retention, export, and deletion

Teachers can export all of their own data to CSV or PDF from the app at any time. Teachers can delete individual rows (soft-delete: the row is marked deleted_at and becomes invisible to the application, for a 30-day recovery window) or request hard-delete of their entire account, which cascades through the foreign-key chain from auth.users and removes every student, class, and audit row under that teacher.

Districts retain the right to request bulk export or bulk deletion of all rows associated with their teachers at any time under the DPA.

8. Third-party data flows

There are three external processors. Supabase (operated by Supabase Inc. on AWS us-east-1 by default, with a region-pinning option available at the district's request) stores the Postgres database, authentication users, and, in Phase 3, object storage for student work-sample photos; Supabase sees full student records and has a SOC 2 Type II report available on request. Google Gemini (Google LLC) sees anonymized text only, per Section 4 above. Vercel hosts the static PWA bundle and serves no student data from its edge; it sees only HTTP metadata (IP, user-agent, URL) for rendered pages. Stripe will be added in Phase 5 for teacher subscription billing; Stripe sees teacher billing contact information only and never touches the student tables.

There are no advertising networks, no session-replay tools, no analytics SDKs that ingest student fields, and no data brokers in the pipeline.

9. Authentication

Teachers sign in with email + password (minimum 8 characters, bcrypt-hashed at rest by Supabase Auth) or with a district-provided SSO connection (Google Workspace for Education or Microsoft Entra ID via SAML — available on districts pilots). JWTs are short-lived (1-hour access token, rotating refresh token). Sessions are stored in secure, HTTP-only, SameSite=Lax cookies managed by @supabase/ssr; there is no teacher-accessible bearer token in browser storage that could be exfiltrated via a cross-site script.

10. Incident response

If an issue is found in our RLS policies, our LLM boundary, or our audit log, the affected production is rolled back to the last green deploy immediately, a post-incident report is written within 72 hours, and the district point-of-contact is notified within 24 hours of confirmation of any suspected unauthorized access to student records — consistent with the breach-notification expectations in the SDPC NDPA. Security reports may be sent to james@agenticedgeventures.com; a public disclosure address will be published when the product moves from beta to general availability.

11. What this document is not

This is a plain-language overview for district decision-makers. It is not a SOC 2 report (we are targeting a SOC 2 Type I within 12 months of paid-pilot sign), a penetration-test attestation, or a FedRAMP package. Districts that require those artifacts before a production pilot should contact us; we can describe our current compliance roadmap and, where appropriate, accommodate a district-led pen test under a mutually executed scope.

*Files referenced on this page are part of every pull-request review:*

  • supabase/migrations/0001_init.sql — table definitions, foreign keys, soft-delete columns.
  • supabase/migrations/0002_rls.sql — RLS policies; the final DO block fails the migration if RLS is ever unset on an expected table.
  • supabase/migrations/0003_audit.sql — audit trigger, redaction function, and REVOKE hardening.
  • src/app/api/rls-test/route.ts — programmatic pen test, 6 assertions.
  • .github/workflows/ci.yml — the rls-test job that runs the pen test on every pull request and blocks merges on failure.
  • src/lib/ferpa-shield.ts — the single anonymization choke point for all outbound LLM text calls.
  • src/lib/photo-shield.ts — the single on-device photo-redaction choke point; unit-tested in tests/unit/photo-shield.test.ts.
  • src/lib/ai-budget.ts — per-teacher AI usage caps, global pause switch, and usage-outlier detection.
  • src/lib/ai-models.ts — the fixed model-routing map; every tier stays on Google Gemini so the processor list in Section 8 stays accurate.
  • src/lib/supabase-server.ts — server-side cookie-aware client; uses the anon key only, never the service-role key.