Technical details · estud.ia

How estud.ia is built.

Five views of the same system: its architecture, a request, an AI call, its security and its quality gates. Every diagram uses the real names from the code.

One platform: seven roles, four kinds of module.

What the system is made of, from the screens people use to the database underneath.

Architecture of estud.ia System architecture. Seven roles use the web app on Heroku: a gunicorn and gevent web dyno serving UI blueprints, an API, services and models, with a release phase that runs migrations, a Socket.IO live channel, an AI client, a daily retention job and field encryption. Models read and write PostgreSQL, where personal fields are encrypted and every row carries its school, one school being one tenant boundary. Files go to S3-compatible storage or Cloudinary. Services call one AI provider (Anthropic or OpenAI, with an offline fallback) through the AI client, and send consent invitations by email. Delivery runs in five steps: developer, pre-commit gates, GitHub, CI with pytest on Postgres 15, and a Heroku deploy that runs migrations first. Operations add a daily encrypted backup and optional error monitoring. Heroku Data · one school = one tenant boundary Outside services Delivery Operations Seven roles Admin · School adminPrincipal · TeacherPsychopedagogyStudent · Parent Web dyno gunicorn · gevent UI blueprints 23 blueprints API 40 modules Services 45 services Models 33 · tenant-stamped Release phase flask db upgrade Live channel Socket.IO notices Retention job daily cleanup script Field encryption Fernetper-field keys AI client One door for AIsafety, moderationand audit PostgreSQL Personal fieldsstored encrypted File storage S3-compatibleCloudinary AI provider Anthropic · OpenAIor offline fallback Email (SMTP) Consent invitations Developer AI-assisted 1 Pre-commit gates schema · service tests 2 GitHub main · develop 3 CI pytest · Postgres 15 4 Heroku deploy migrations run first 5 Daily backup GitHub Actionsencrypted with gpg Error monitoring Sentry (optional)

How the data is organized.

Users, profiles and schools at the root; every school-scoped table carries its school. Personal fields are encrypted and key records are immutable.

How the data is organized A user can hold several profiles, each with one of seven roles, in a school (the tenant root). A family link joins a parent profile to a student profile and carries the consent record. School-scoped tables hold lessons, tasks with three teacher-written help levels, submissions, wellbeing check-ins, journal entries, insight reports, the audit log and attachments. Every row carries its school. Personal fields are encrypted, and the audit log, journal and insight reports are immutable. School-scoped tables Parent and student every row carries its school One login, many profiles User Email (encrypted)Password hashSession token School (tenant root) Country and settingsAI and storage overridesContent safety level Profile Role: one of sevenSchool and sectionName and ID (encrypted)Active flag Family link Parent ↔ studentConsent status and expiryIP, user agent, terms hash Lesson Teacher, section, subjectObjective, activity type Task Three help levelslow · medium · highWritten by the teacher Submission Student answerAI help historyEncrypted prompt copy Wellbeing check-in Student and sectionSentiment, optional wordEncrypted, can anonymize Journal entry Teacher observationEncrypted noteImmutable Insight report AI-assisted draftTeacher’s final textEncrypted, immutable Audit log Who, what, when, whereImmutableKey events kept forever Attachment Task and lesson filesS3-compatible storageSigned, expiring URLs

Four checkpoints run before any page loads.

They run on every request, so a page cannot forget them. Checkpoints 3 and 4 protect minors.

  1. Checkpoint 1 · Session

    Who are you?

    One active session per person. Signing in elsewhere closes the first.

    set_tenant_context

  2. Checkpoint 2 · School

    Which school?

    Rows are stamped with their school and cannot be moved to another.

    TenantMixin

  3. Checkpoint 3 · Minors

    Did a parent consent?

    No valid consent, no access. The attempt is audited.

    enforce_parent_consent

  4. Checkpoint 4 · Launch

    Is the school live?

    Students wait until their school has gathered its parents’ consents.

    enforce_institution_launch_status

After the checkpoints: a role check (403 if not allowed), the service, encrypted columns, then the page.

Many callers, one door to the provider.

Chat and help calls pass through one client: safety rules go in, moderation and audit come out. Prompt text is never shown here, only the structure.

How an AI call is governed Two kinds of callers reach one client, AIClient.generate(): PromptService (a registry, a loader and a builder, used by parent chat and grading) and direct callers (student help and chat, lesson authoring, curriculum parsing). Inside the client: safety rules are prepended, the provider answers, the reply is moderated, and the call is audited. Unsafe replies become a safe message. PromptService Registry: role + question Loader: typed context Builder: composes prompt Parent chat · grading Direct callers Student help and chat Lesson authoring Curriculum parsing AIClient.generate() 1 Safety Rules for minorsare prepended tothe call, aheadof everything. 2 Provider Anthropic, OpenAIor an offlinefallback, set perschool. 3 Moderate The reply ischecked: providerAPI, or Spanishkeyword rules. 4 Audit Every call islogged. Unsafereplies become asafe message. Unsafe reply → safe message Audit log request · reply AI provider Anthropic · OpenAI offline fallback

How a prompt is built.

Four layers in a fixed order: two in the system message, two in the user message. Structure only, never the prompt text.

How a prompt is built Every AI call is a stack of four layers. Two go in the system message: the safety rules, always first, and a role frame. Two go in the user message: a task prompt that depends on the scenario, and a typed context holding only the data that call needs. The stack is wrapped in a provider envelope (Anthropic or OpenAI), sent to the provider, and the reply is moderated and audited; grading replies are parsed into a grade and an explanation. The four scenarios are student help, student chat, parent chat and grading. The diagram shows structure only, never prompt text. Prompt stack Safety rules System Absolute rules for minors. Always first. SAFETY_INSTRUCTION Role frame System Who the model acts as in this call. system message Task prompt User One per scenario: tutor, parent questions, grading. services/prompts/builders Typed context User Only the data this call needs, as structured fields. services/prompts/contexts Provider envelope Anthropic: one system field and one user message. OpenAI: system and user messages. Same prompt, either way. AI provider Anthropic · OpenAI Reply handling Checked by moderation and written to the audit log Unsafe: replaced by a safe message Grading: parsed to JSON { grade, explanation } Four scenarios, one stack Student help The teacher’s help text, plus grade, style, help level and detail mode Student chat Lesson and task material; falls back when there is no official material Parent chat One of nine questions, with progress, attendance and journal summaries Grading Academic principles, task, answer and scale → a proposed grade

AI call simulator · scripted, no network, synthetic data

Student · help level MEDIUM: trace

  1. The student asks for help on a task
  2. Context for this school is loaded
  3. Safety rules are prepended
  4. The provider answers
  5. The reply is moderated
  6. The call is audited

Prompt structure (redacted)

  1. Safety rules
  2. The teacher’s help text, level MEDIUM
  3. Learning style
  4. Task context

Parent · “How is my child doing?”: trace

  1. The registry routes (parent, question)
  2. The loader builds a typed context
  3. The builder composes the prompt
  4. Safety rules are prepended
  5. The reply is moderated
  6. The call is audited

Prompt structure (redacted)

  1. Safety rules
  2. Role instructions
  3. Typed context (synthetic here)

Teacher · propose a grade: trace

  1. The registry routes the grading request
  2. The loader reads the submission
  3. The builder adds the academic principles
  4. Safety rules are prepended
  5. The reply is moderated
  6. A proposal returns for the teacher to confirm

Prompt structure (redacted)

  1. Safety rules
  2. Academic principles: delegate, describe, discern, be diligent
  3. Submission (synthetic here)

Student · unsafe message: trace

  1. The student writes something harmful
  2. The safety rules tell the model to answer with care and point to a trusted adult
  3. The reply is moderated and flagged if unsafe
  4. A safe message replaces an unsafe reply
  5. A permanent audit event is written; critical cases are flagged for review

Prompt structure (redacted)

  1. Safety rules
  2. The student’s message

The safety rules steer the model toward a careful answer, and the reply is checked and flagged if unsafe.

Who could try what, and what stops them.

How security is layered, then a threat model in one table.

Security architecture The security architecture in layers, from the browser through the web layer (HTTPS, HSTS, CSRF, secure cookies, rate limits), four checkpoints (session, school, parental consent, school launch), a role check, the service and the database, where personal fields are encrypted. Blocked attempts and key events go to a permanent audit log. AI calls leave the service for the AI provider; student and parent calls get safety rules in, reply moderation and audit. Network Identity and consent Data Browser student · parentteacher Web layer HTTPS + HSTSCSRF · Secure cookiesRate limits Checkpoints 1 session · 2 school3 consent · 4 launch Role check Not allowed → 403 Service Business rulesQueries scoped tothe school Database Encrypted personalfields · write-onceaudit and records Audit log Blocked attempts · logins · AI calls Key events are kept permanently AI provider Anthropic · OpenAI offline fallback Student and parent calls: safety rules in, reply moderated, audited

Consent is a flow, not a checkbox.

A single-use link, a recorded acceptance with the terms’ hash, an activated profile and a permanent audit event. It can be revoked at any time.

How parental consent works The school admin sends an invitation. The platform sends the parent a single-use link valid for seven days. The parent opens it without logging in and accepts the terms. The platform checks the token and expiry, stores the time, IP address and a hash of the accepted terms, and clears the token. The student profile is activated and a permanent audit event is written. Consent can be revoked at any time: the student profile is deactivated, the token is cleared and the event is audited. School admin sends invitations Parent no login needed Platform checks and records Audit log permanent events Student profile Sends the invitation Single-use link, valid 7 days Opens the link, no login needed Accepts the terms Checks token and expiry Stores time, IP and terms hash Clears the token (single use) Student profile activated Event kept permanently Revoke any time: the student profile is deactivated, the token is cleared and the event is audited.

Every attack has a stopper.

Who Tries to Stopped by
Student Get unsafe content from the AI Safety rules in the call, reply moderation, audit; critical cases flagged for review
Student Enter without parental consent Consent and school-launch checkpoints on every request; the attempt is audited
Anyone Guess national IDs in parent onboarding Sliding-window limits on failed lookups, per user and per IP; names masked
Staff of another school Read another school’s data Rows stamped with their school and immutable; role checks; access-control tests; review for cross-school access
Stolen login Reuse a session elsewhere One active session per person; Secure and HttpOnly cookies; HSTS in production
Database leak Read personal data from a copy Field-level encryption with a key per field; encrypted backups

Threat explorer · pick an attack

Stopped at: Safety rules in the call, then reply moderation

The rules lead every call. An unsafe reply is replaced with a safe message and the event is audited.

Stopped at: Checkpoint 3 · Parental consent

Blocked and audited on every request.

Stopped at: Sliding-window limits per user and per IP

Names are also masked in the invite flow.

Stopped at: Checkpoint 2, role checks and access-control tests

Every row carries its school and cannot be moved to another.

Stopped at: Field-level encryption and encrypted backups

Each kind of field has its own key, and backups are encrypted.

A piece of data has a lifecycle.

Each stage has a rule, from the first write to the purge.

  1. 1 · Collect

    Consent first

    Parents consent before a student gets access.

  2. 2 · Store

    Encrypted

    Personal fields are encrypted on write, with a key per field.

  3. 3 · Use

    Scoped and audited

    Role and school are checked; sensitive reads leave a trace.

  4. 4 · Retain

    By type

    Security and consent events are kept; other logs 365 days; attachments 90.

  5. 5 · Purge

    AI prompts: 30 days

    A cleanup job removes the content of AI prompts.

No green checks, no commit.

Each gate must pass before a change moves on. If one fails, the change stops there and gets fixed.

  1. Gate 1 · On edit

    Still starts?

    The app must still import after each change.

    import check

  2. Gate 2 · Commit

    Still consistent?

    Schema and services must match the models, or the commit is blocked.

    pre-commit hook

  3. Gate 3 · Review

    Safe and green?

    Security review of the diff first, then the full test suite. A human confirms the commit.

    /pre-commit routine

  4. Gate 4 · CI

    Green anywhere?

    Tests repeat on a clean machine with PostgreSQL 15, on every push and pull request.

    GitHub Actions

  5. Release

    Data first

    Database migrations run before the new version starts.

    flask db upgrade

Also: data scripts carry a production guard, and a daily encrypted database backup runs on GitHub Actions.