Commit Graph
100 Commits
Author SHA1 Message Date
admin 1cb86273f7 Modified by www.SourceFiles.app 2026-08-07 04:13:15 +00:00
admin a6e8f67a39 Modified by www.SourceFiles.app 2026-08-07 04:13:14 +00:00
admin ecdd9c69b6 Modified by www.SourceFiles.app 2026-08-07 04:13:14 +00:00
admin 33ddaeb90c Modified by www.SourceFiles.app 2026-08-07 04:13:13 +00:00
admin 604bf18d4a Modified by www.SourceFiles.app 2026-08-07 04:13:13 +00:00
admin d705da8d3a Modified by www.SourceFiles.app 2026-08-07 04:13:12 +00:00
admin ef71239759 Modified by www.SourceFiles.app 2026-08-07 04:13:12 +00:00
admin c4daba6b18 Modified by www.SourceFiles.app 2026-08-07 04:13:11 +00:00
admin a8586947b8 Modified by www.SourceFiles.app 2026-08-07 04:13:11 +00:00
admin 4226fc683b Modified by www.SourceFiles.app 2026-08-07 04:13:10 +00:00
admin a53c040cf3 Modified by www.SourceFiles.app 2026-08-07 04:13:10 +00:00
admin 35cb11b274 Modified by www.SourceFiles.app 2026-08-07 04:13:09 +00:00
admin 23e87485aa Modified by www.SourceFiles.app 2026-08-07 04:13:09 +00:00
admin c9d668f5c8 Modified by www.SourceFiles.app 2026-08-07 04:13:08 +00:00
admin a36c89817d Modified by www.SourceFiles.app 2026-08-07 04:13:08 +00:00
admin 1dc69aeb50 Modified by www.SourceFiles.app 2026-08-07 04:13:07 +00:00
admin 573e07777d Modified by www.SourceFiles.app 2026-08-07 04:13:07 +00:00
admin f9a64da58a Modified by www.SourceFiles.app 2026-08-07 04:13:06 +00:00
admin 068bfaaeaa Modified by www.SourceFiles.app 2026-08-07 04:13:06 +00:00
admin a6a8957f67 Modified by www.SourceFiles.app 2026-08-07 04:13:05 +00:00
admin f3395ceec2 Modified by www.SourceFiles.app 2026-08-07 04:13:05 +00:00
admin 89f3f18533 Modified by www.SourceFiles.app 2026-08-07 04:13:04 +00:00
admin 6fc382dc77 Modified by www.SourceFiles.app 2026-08-07 04:13:04 +00:00
admin 4041390ea7 Modified by www.SourceFiles.app 2026-08-07 04:13:03 +00:00
admin 318339be03 Modified by www.SourceFiles.app 2026-08-07 04:12:48 +00:00
admin 51704b05c8 Modified by www.SourceFiles.app 2026-08-07 04:12:47 +00:00
admin b4f82677e3 Modified by www.SourceFiles.app 2026-08-07 04:12:46 +00:00
admin 4fb5f7632d Modified by www.SourceFiles.app 2026-08-07 04:12:46 +00:00
admin b59cd0d240 Modified by www.SourceFiles.app 2026-08-07 04:12:45 +00:00
admin 22cf35c827 Modified by www.SourceFiles.app 2026-08-07 04:12:45 +00:00
admin cf4c78586f Modified by www.SourceFiles.app 2026-08-07 04:12:44 +00:00
admin 9d3c935501 Modified by www.SourceFiles.app 2026-08-07 04:12:44 +00:00
admin b84d6252b3 Modified by www.SourceFiles.app 2026-08-07 04:12:43 +00:00
admin 8797b32c51 Modified by www.SourceFiles.app 2026-08-07 04:12:42 +00:00
admin 637fb8d934 Modified by www.SourceFiles.app 2026-08-07 04:12:42 +00:00
admin c187e00f38 Modified by www.SourceFiles.app 2026-08-07 04:12:41 +00:00
admin 1ecba74f49 Modified by www.SourceFiles.app 2026-08-07 04:12:41 +00:00
admin 713c58b7f2 Modified by www.SourceFiles.app 2026-08-07 04:12:40 +00:00
admin 95c0961ea8 Modified by www.SourceFiles.app 2026-08-07 04:12:40 +00:00
admin c4ced91e16 Modified by www.SourceFiles.app 2026-08-07 04:12:39 +00:00
admin 023432011b Modified by www.SourceFiles.app 2026-08-07 04:12:38 +00:00
admin 56a5cbefb6 Modified by www.SourceFiles.app 2026-08-07 04:12:38 +00:00
admin afdbfa7b68 Modified by www.SourceFiles.app 2026-08-07 04:12:37 +00:00
admin 07532d61bb Modified by www.SourceFiles.app 2026-08-07 04:12:37 +00:00
admin 12db3dbde5 Modified by www.SourceFiles.app 2026-08-07 04:12:36 +00:00
admin 12fdb4f864 Modified by www.SourceFiles.app 2026-08-07 04:12:35 +00:00
admin 936e3c7aed Modified by www.SourceFiles.app 2026-08-07 04:12:35 +00:00
admin dae48fcb11 Modified by www.SourceFiles.app 2026-08-07 04:12:34 +00:00
admin 62e0e2a48c Modified by www.SourceFiles.app 2026-08-07 04:12:33 +00:00
admin 00b437e0d0 Modified by www.SourceFiles.app 2026-08-07 04:12:33 +00:00
admin 147a6f2b13 Modified by www.SourceFiles.app 2026-08-07 04:12:32 +00:00
admin 39ad1ae76a Modified by www.SourceFiles.app 2026-08-07 04:12:32 +00:00
admin 2d14990a1b Modified by www.SourceFiles.app 2026-08-07 04:12:31 +00:00
admin 359d73471a Modified by www.SourceFiles.app 2026-08-07 04:12:31 +00:00
admin aced914db5 Modified by www.SourceFiles.app 2026-08-07 04:12:30 +00:00
admin 3f3a4eaab7 Modified by www.SourceFiles.app 2026-08-07 04:12:29 +00:00
admin 57fff3171a Modified by www.SourceFiles.app 2026-08-07 04:12:29 +00:00
admin 9032ae3397 Modified by www.SourceFiles.app 2026-08-07 04:12:28 +00:00
admin 70fb824c28 Modified by www.SourceFiles.app 2026-08-07 04:12:27 +00:00
admin eb9f80cbe6 Modified by www.SourceFiles.app 2026-08-07 04:12:27 +00:00
admin 8e66e2fcf4 Modified by www.SourceFiles.app 2026-08-07 04:12:26 +00:00
admin 732799a8ad Modified by www.SourceFiles.app 2026-08-07 04:12:25 +00:00
admin 4198028ce1 Modified by www.SourceFiles.app 2026-08-07 04:12:25 +00:00
admin b21c4f6d18 Modified by www.SourceFiles.app 2026-08-07 04:12:22 +00:00
admin 696851d0c2 Modified by www.SourceFiles.app 2026-08-07 04:12:21 +00:00
admin 8b09c90832 Modified by www.SourceFiles.app 2026-08-07 04:12:21 +00:00
admin b0f4844ef9 Modified by www.SourceFiles.app 2026-08-07 04:12:20 +00:00
admin 1375981a9c Modified by www.SourceFiles.app 2026-08-07 04:12:19 +00:00
admin ffd94f8b64 Modified by www.SourceFiles.app 2026-08-07 04:12:18 +00:00
admin 534ef5c12d Modified by www.SourceFiles.app 2026-08-07 04:12:18 +00:00
admin 622e2b1bff Modified by www.SourceFiles.app 2026-08-07 04:12:17 +00:00
admin 2b58c9a4c6 Modified by www.SourceFiles.app 2026-08-07 04:12:16 +00:00
admin 83db1f9794 Modified by www.SourceFiles.app 2026-08-07 04:12:16 +00:00
admin 14772127f9 Modified by www.SourceFiles.app 2026-08-07 04:12:15 +00:00
admin be50ebdddb Modified by www.SourceFiles.app 2026-08-07 04:12:14 +00:00
admin bf71683be3 Modified by www.SourceFiles.app 2026-08-07 04:12:14 +00:00
admin 3cead1afbc Modified by www.SourceFiles.app 2026-08-07 04:12:13 +00:00
admin 23be17af07 Modified by www.SourceFiles.app 2026-08-07 04:12:13 +00:00
admin 086251b56b Modified by www.SourceFiles.app 2026-08-07 04:12:11 +00:00
admin e00aeed92d Modified by www.SourceFiles.app 2026-08-07 04:12:10 +00:00
admin b47054231e Modified by www.SourceFiles.app 2026-08-07 04:12:09 +00:00
admin 80e00adb98 Modified by www.SourceFiles.app 2026-08-07 04:12:08 +00:00
admin 371d5c00f7 Modified by www.SourceFiles.app 2026-08-07 04:12:08 +00:00
admin f7cb80cdb3 Modified by www.SourceFiles.app 2026-08-07 04:12:07 +00:00
admin b14a5c527a Modified by www.SourceFiles.app 2026-08-07 04:12:07 +00:00
admin ca0b1327ab Modified by www.SourceFiles.app 2026-08-07 04:12:06 +00:00
admin b004b3d46b Modified by www.SourceFiles.app 2026-08-07 04:12:05 +00:00
admin 60c6f16c31 Modified by www.SourceFiles.app 2026-08-07 04:12:04 +00:00
admin 9afcb77dad Modified by www.SourceFiles.app 2026-08-07 04:12:03 +00:00
admin 501026093c Modified by www.SourceFiles.app 2026-08-07 04:12:01 +00:00
admin a334cb5f8e Modified by www.SourceFiles.app 2026-08-07 04:11:58 +00:00
admin 956d75d39e Modified by www.SourceFiles.app 2026-08-07 04:11:57 +00:00
admin 4b77f3a978 Modified by www.SourceFiles.app 2026-08-07 04:11:56 +00:00
admin 475f98932b Modified by www.SourceFiles.app 2026-08-07 03:22:14 +00:00
admin 9ac1637043 Modified by www.SourceFiles.app 2026-08-07 03:14:02 +00:00
admin 933549e345 Modified by www.SourceFiles.app 2026-08-07 03:14:02 +00:00
adminandClaude Opus 5 d2d4e49fa6 Add embedded IMAP/SMTP mail for staff
Admins configure one mail server; each staff member gets their own mailbox
login. Read, reply and compose against real IMAP/SMTP.

IMAP and SMTP are raw TCP, so none of this can run in a browser — every
operation is a TanStack Start server function. mail.functions.ts ships to
the client bundle, so imapflow/nodemailer/mailparser and the crypto
helpers are imported inside handlers, never at the top level. Verified
that Nitro inlines all three into .output/server/_libs, since the Docker
runner stage copies only .output and has no node_modules.

Note this ties the app to the Node deployment: the default local build
targets Cloudflare Workers, which cannot open IMAP sockets.

Credential handling, since a mailbox password grants full read and send
access to someone's mail:

- user_mailboxes has RLS enabled, no policies, and SELECT revoked from
  anon and authenticated. Verified: teacher and admin both see zero rows
  and no ciphertext; only service_role can read it. The revoke is belt and
  braces — Supabase's default privileges had granted SELECT, leaving the
  table one stray policy away from leaking.
- Passwords are sealed with AES-256-GCM using MAIL_CRED_KEY from
  .env.secret, so a database dump alone opens nothing. GCM also makes
  tampering fail the auth tag instead of decrypting to garbage.
- Provisioning verifies credentials against the live IMAP server before
  storing them, so typos surface at setup rather than as a broken inbox.

Message bodies render as plain text; sender HTML is never injected, which
would execute sender-controlled markup and leak read receipts via
tracking pixels.

Mailboxes are limited to admins and teachers. Students are excluded
deliberately — external mail for minors carries archiving, monitoring and
consent obligations that should be chosen, not inherited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 10:46:47 -04:00
adminandClaude Opus 5 53ab6b92b5 Let admins edit, deactivate and delete forms
The database already permitted all three (forms admin manage is FOR ALL);
this was purely a missing UI. Create and edit now share one editor, since
the only differences are the initial values and insert vs update.

Three hazards in the existing data model shaped this rather than just
adding buttons:

- form_responses.form_id is ON DELETE CASCADE, so deleting a form
  permanently destroys its submissions. The confirmation names the
  response count and points to deactivating instead. Verified: deleting a
  form with two responses leaves zero.

- The list filtered active = true for everyone, so deactivating a form
  hid it from the only people who could reactivate it. Admins now see
  inactive forms with a badge; families still see only active ones.

- Responses key their answers by field *label* in data_json, so renaming
  a field strands existing answers under the old key. The editor warns
  when the form already has responses. Deliberately not migrating old
  answers — guessing which old label maps to which new one would risk
  silently rewriting submitted data.

Also strips fields with blank labels on save, shows a response count per
form, and gives the response list an empty state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 10:26:42 -04:00
adminandClaude Opus 5 9360bf3055 Add printable report cards, progress reports and invoices
Three documents, all print-styled rather than generated server-side: no
PDF dependency is added, and "Save as PDF" in the browser produces the
file. @media print in styles.css strips the app chrome (.no-print) and
breaks each student onto its own sheet (.print-page).

- Report card: weighted category breakdown, overall percent and letter
  from the existing gradebook config, plus an attendance summary.
- Academic progress report: the same, plus assignment-level detail —
  a mid-term report is only actionable with the underlying work listed.
- 504 / IEP progress report: each goal's baseline, target, status and
  progress entries within the period, for the quarterly report IDEA
  requires. RLS keeps it to the case manager, admins and parents.
- Invoice, reachable per student from the tuition ledger: opening
  balance carried forward, itemised activity, and balance due.

Grade maths is reused from lib/grades and the class grading config from
useEffectiveConfig, so report cards cannot drift from the gradebook.

The "Email to parents" button opens a prefilled mailto: draft — the same
mechanism the intake-link share already uses. It gathers addresses from
intake guardians and linked parent accounts. mailto cannot attach a file,
so the itemisation goes in the body as text; sending a real attachment
would need a transactional email provider and an API key.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:45:46 -04:00
adminandClaude Opus 5 85d87d1c62 Charge tuition automatically from attendance
Adds a per-student daily rate (students.daily_tuition_cents) and a trigger
that writes a tuition charge when a student is marked present or late.

Idempotency is the crux. The attendance UI upserts on (student_id, date)
and teachers toggle a status freely — present, absent, present again. A
naive "insert a charge on attendance" trigger bills the family once per
click. So each auto-charge is bound to the attendance row that caused it
via ledger_entries.attendance_id (UNIQUE), which turns the write into an
upsert, lets a change back to absent delete the charge, and cascades the
charge away if the attendance record is deleted.

Manual entries keep attendance_id NULL — Postgres allows unlimited NULLs
in a unique index — so hand-entered charges are untouched and the UI can
tell auto from manual.

A NULL rate (the default) means never auto-charge, so nothing begins
billing until a rate is deliberately set on a student. Existing
attendance is not backfilled: retroactively generating charges against
families' balances should be an explicit decision, not a side effect of
deploying a migration.

The trigger is SECURITY DEFINER because the writer is a teacher marking
attendance while ledger_entries is admin-write under RLS; teachers gain
no general ledger access, only this fixed attendance-derived write.

Verified against the live schema across all eight paths: charge on
present, reversal on absent, no duplicate on re-mark, late billable,
excused free, no rate means no charge, rate change on re-save, and
cascade on attendance delete.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:45:30 -04:00