Commit Graph
54 Commits
Author SHA1 Message Date
admin 1f3de0d7ff Terminal 2026-08-07 20:42:58 +00:00
admin a54a988314 Modified by www.SourceFiles.app 2026-08-07 20:23:53 +00:00
admin b07777befd Modified by www.SourceFiles.app 2026-08-07 14:03:42 +00:00
admin e0128f540b Modified by www.SourceFiles.app 2026-08-07 13:45:29 +00:00
admin d158ef9700 Modified by www.SourceFiles.app 2026-08-07 13:29:31 +00:00
admin 640d8e9952 Modified by www.SourceFiles.app 2026-08-07 12:56:26 +00:00
admin c5eda38a97 Modified by www.SourceFiles.app 2026-08-07 12:56:26 +00:00
admin bc064d004d Modified by www.SourceFiles.app 2026-08-07 12:52:18 +00:00
admin 3a6828e964 Modified by www.SourceFiles.app 2026-08-07 12:51:19 +00:00
admin 14406536f5 Modified by www.SourceFiles.app 2026-08-07 04:48:28 +00:00
admin c4a800f793 Modified by www.SourceFiles.app 2026-08-07 04:48:20 +00:00
admin 5fbd9c92b6 Modified by www.SourceFiles.app 2026-08-07 04:47:07 +00:00
admin 4bd1793348 Modified by www.SourceFiles.app 2026-08-07 04:46:10 +00:00
admin 28fa74c3fa Modified by www.SourceFiles.app 2026-08-07 04:45:59 +00:00
admin 381dabe139 Modified by www.SourceFiles.app 2026-08-07 04:45:54 +00:00
admin ed2aa101ec Modified by www.SourceFiles.app 2026-08-07 04:45:06 +00:00
admin 1b1ad9355c Modified by www.SourceFiles.app 2026-08-07 04:44:10 +00:00
admin f888ca67b9 Modified by www.SourceFiles.app 2026-08-07 04:43:28 +00:00
admin a37dcde4fe Modified by www.SourceFiles.app 2026-08-07 04:42:29 +00:00
admin 04b9d1a475 Modified by www.SourceFiles.app 2026-08-07 04:39:50 +00:00
admin 8f1a998d27 Modified by www.SourceFiles.app 2026-08-07 04:37:44 +00:00
admin e860429383 Modified by www.SourceFiles.app 2026-08-07 04:36:35 +00:00
admin 7771f26e98 Modified by www.SourceFiles.app 2026-08-07 04:35:43 +00:00
admin 2ea64031fd Modified by www.SourceFiles.app 2026-08-07 04:35:39 +00:00
admin 8b6be4b20e Modified by www.SourceFiles.app 2026-08-07 04:33:50 +00:00
admin 4670d04a2d Modified by www.SourceFiles.app 2026-08-07 04:32:13 +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 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 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 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 57fff3171a Modified by www.SourceFiles.app 2026-08-07 04:12:29 +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 3cead1afbc Modified by www.SourceFiles.app 2026-08-07 04:12:13 +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 501026093c Modified by www.SourceFiles.app 2026-08-07 04:12:01 +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 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
adminandClaude Opus 5 9d7d18669d Add 504 / IEP plans with tiered confidentiality
Plans, accommodations, related services, annual goals with progress
monitoring, meetings/team, and signed documents — plus a compliance
list and dashboard alerts for annual-review and triennial re-evaluation
dates (overdue in red, due-within-30-days in amber).

Access is tiered because special-education records are need-to-know
under FERPA:

  FULL  admin, the plan's case manager, the student's parents
  IMPL  the above, plus any teacher of the student — accommodations
        and services only, never eligibility or meeting notes

RLS is row-level and every app role is the same Postgres role
(`authenticated`), so column grants cannot separate the tiers. The
split is therefore physical: confidential fields live in plan_details,
plan_goals, plan_meetings and plan_documents rather than as columns on
student_plans.

The UI asks the database which tier applies via the same predicates the
policies use (can_view_plan_full / can_edit_plan) instead of re-deriving
the rules client-side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:14:40 -04:00
adminandClaude Opus 4.8 90e3c2c188 Add admin-emailed one-time intake links
- intake_tokens table (server-only via service role)
- Server functions: createIntakeToken (admin), getIntakeToken (public validate),
  submitIntake (public write + mark used, 14-day one-time tokens)
- Public /intake/$token full intake form (no login) with valid/used/expired states
- Student profile (admin): generate link, copy, and email-to-parent (mailto)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 18:00:39 -04:00
adminandClaude Opus 4.8 8880d7a805 Lock student profile editing to admins only
Parents and teachers are now view-only on student data (profile, guardians,
pickups, curriculum logins). Writes restricted to admins in RLS and the UI;
read access unchanged. Portal logins for parents/students are view-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 17:32:45 -04:00