Changelog
What's new.
Everything that's shipped on tutor., in reverse chronological order. Expect this page to grow as we get closer to launch.
- shipped
Automatic refunds on paid cancellations
- Cancel a paid session 12+ hours before it starts and you get a full refund back to the original card — we fire a Stripe refund at the same moment the booking is cancelled.
- Shows up on the dashboard as a 'Refunded' badge. Usually lands on your statement in 5–10 business days.
- Cancel dialog now promises the refund explicitly. Terms updated to match.
- If the refund call fails for any reason, the cancel is rolled back so we never end up in the 'cancelled but not refunded' state silently.
- design
Confirmation dialogs + duration-grid slots + friendlier copy
- Booking now asks 'are you sure?' before submitting. Free sessions get a softer 'Lock in your free session?'; paid sessions get 'Ready to pay and book?' with the amount in the confirm button.
- Cancelling asks 'Cancel this session?' with the exact date/time and reminds you that the slot opens up and your free session resets.
- Calendar now snaps to the duration: pick 60 min → slots show at every hour, not every 15 min. Pick 30 → :00 and :30 only. A 60-min booking still blocks overlapping 30-min attempts via the DB exclusion constraint.
- Student-facing copy softened: dashboard greeting, empty-state headline, and supporting lines now read more like a friend than a form.
- fix
Cancellation window: 24h → 12h
- You can now cancel a booking up to 12 hours before the start time (down from 24). Dashboard, signup copy, terms, booking review, and confirmation email all updated.
- The Resend-hosted email template still needs a matching edit in the Resend UI (we can only change template copy there, not in code).
- shipped
Stripe payments + first session free
- Every account gets one free session to start. After that, sessions are paid: 30 min / 45 min / 60 min priced in CAD, configurable via env.
- Paid bookings now redirect through Stripe Checkout. The slot is locked when you click confirm (via the Postgres exclusion constraint), held for 30 min while you finish checkout, and released if you abandon.
- After payment, Stripe sends you back to /book/success which verifies the session with Stripe, marks the booking paid, and fires the confirmation email.
- Cancelling a booking — even a paid one — resets you to the free tier. Next booking is on the house again. Deliberate: we want you to actually show up, not get stuck.
- Dashboard now shows a payment status pill on every booking: Free, Paid, Payment pending.
- design
Brand mark lands on every page
- Replaced the plain ink squares in the nav, footer, and every page header with the actual tutor. brand mark — a lime T with a period, on an ink rounded-square background.
- Same mark is now the browser favicon and the iOS home-screen icon.
- shipped
Post-Google-signup profile step
- Google sign-in doesn't give us age (Google won't share it) — so after Google signup you land on /get-started to fill in age (5–18) and confirm your name.
- Returning users skip the page automatically; the route bounces straight to the dashboard if the profile is already complete.
- Trying to hit /book without a complete profile now redirects back to finish it. Age is required for picking the right material.
- shipped
Privacy policy + terms of service
- Added /privacy and /terms pages written in plain language — what we collect, how long we keep it, cancellation rules, contact.
- Covers K-12 specifics: parental guidance for under-13 accounts, account deletion on request.
- Linked from the footer. Firebase OAuth consent can now point at these URLs for the 'App privacy policy' and 'App terms' links.
- fix
Human-readable auth errors
- Raw Firebase errors like 'auth/popup-closed-by-user' are now translated into plain English on the signup and login pages.
- Cancelling the Google popup is silent (no red error splashed across the form). Wrong password, network errors, blocked popups, and similar all have friendly messages.
- infra
Auth swapped from better-auth to Firebase
- Email + password and Google sign-in both go through Firebase now.
- Firebase owns identity (password hashing, OAuth, email verification); our database keeps the app-specific bits — role, age, and booking relationships keyed by Firebase UID.
- Session is a signed httpOnly cookie created from a verified Firebase ID token. No more custom session table.
- Anyone who made a test account earlier will need to sign up again — the user table was reset during the migration.
- infra
Email design now lives in Resend
- Booking confirmation emails are now sent via a Resend-hosted template (alias: session-confirmation).
- Design edits happen in Resend's UI — no redeploy needed for copy or layout tweaks.
- Server sends only the eight variables the template expects: student_name, teacher_name, date_label, time_label, duration_minutes, address, cancel_url, site_url.
- shipped
Booking confirmation emails via Resend
- Every confirmed booking now fires a branded HTML email: session time, duration, where, and a link back to the dashboard.
- Lime-and-ink system carried over into the email so the brand stays consistent. Table-based layout with inline styles, renders everywhere from Gmail to Outlook.
- Fire-and-forget: if the email fails to send, the booking still succeeds. The DB is the source of truth, not the email.
- While the custom sending domain (mail.tutoring.aradrsk.com) verifies with DNS, we're sending from Resend's shared onboarding@resend.dev. Flip the EMAIL_FROM env once verification completes.
- Preview the template live at /dev/email/booking.
- shipped
Dashboard shows your real bookings
- The /account/bookings page now reads from the database instead of showing a placeholder.
- Upcoming sessions appear in a chunky card list with date, time, and duration. Past sessions collapse into a muted list below.
- Students can cancel upcoming sessions more than 24 hours out. Closer than that, the cancel button is hidden and a note explains why. Teachers can cancel any session (emergencies happen).
- Teachers see every confirmed booking with the student's name and email, not just their own.
- design
Booking step 2 is now a calendar
- The long vertical list of days in the booking wizard is gone.
- New month-calendar grid: green = open (shows how many start times), grey = no availability, red = blocked.
- Tap a date → open times appear in a panel below. Much faster than scrolling a list.
- Works across month boundaries with prev/next arrows when the 30-day horizon crosses a month.
- design
Teacher has a name: Theepa Jeyapalan
- The landing page 'Your teacher' card now reads Theepa Jeyapalan. Bio copy updated too.
- shipped
Booking flow is live
- The /book route is a three-step wizard: pick length (30/45/60), pick a start time, review & confirm.
- The server double-checks every booking against live availability before inserting, and catches the Postgres exclusion-violation cleanly when two people try to grab the same slot.
- Dashboard empty-state now points straight to /book.
- shipped
Teacher availability editor + public preview
- Teachers now have /dashboard/availability: add weekly windows, block specific dates, and a 14-day preview that overlays 30/45/60-minute valid start times.
- Landing page shows real availability for the next 15 days, with a green/grey/red legend. No more fake placeholder school logos.
- The whole slot-generation engine is shared across teacher preview, landing page, and booking — so all three stay in sync automatically.
- design
Full UX rehaul + /updates page
- Introduced a shared Nav + Footer across every page — logged-in users now see a Dashboard link, logged-out users see Log in + Book a session.
- Redesigned /signup and /login in the lime + ink system: chunky card, inline hints, proper error states, a value-prop list on signup.
- Dashboard at /account/bookings got stat cards, an empty-state with clear next steps, and an account-details card that reads live from the session.
- This /updates page is new. You're reading it.
- shipped
Live at tutoring.aradrsk.com
- Deployed to Vercel production with a custom domain.
- Cloudflare DNS A record → Vercel edge. SSL auto-provisioned.
- Environment variables moved out of local dev; production now reads DATABASE_URL, BETTER_AUTH_SECRET, and the site URLs from Vercel.
- infra
Migrated to Neon Postgres
- Swapped local SQLite for Neon serverless Postgres so the app works on Vercel's ephemeral filesystem.
- Schema ported to pg-core with real enums (user_role, booking_status), timestamptz, checks, and proper indexes.
- Bookings overlap exclusion constraint restored via btree_gist + a trigger-maintained end_at column — prevents a 30-min booking at 4:30 pm from colliding with a 60-min booking at 4 pm at the DB layer.
- design
Landing page redesign
- New visual system: lime #B9FF66 + ink #191A23 on white.
- Chunky rounded cards with offset drop-shadows, section headers in lime pills, inline SVG illustrations for sessions and the hero.
- Added a 4-card sessions grid (30 / 45 / 60 / free trial), 3-step how-it-works, a teacher profile card, and a dark pricing panel.
- shipped
Auth + schema for signup / login / verify flow
- Users can create accounts with name, age, email, and password.
- Session cookies via better-auth. Dashboard redirects unauthenticated visitors to /login.
- Email verification is currently off in dev; it comes back on when Resend is wired in TU-9.
- infra
Project scaffold
- Next.js 16 (App Router, Turbopack) on React 19, TypeScript 5, Tailwind 4, ESLint 9.
- drizzle-orm + drizzle-kit for schema and migrations.
- better-auth with a drizzle adapter. Pushed to github.com/aradrsk/tutoring.
- shipped
PRD v1 locked
- Resolved the five open product questions: public landing as home, teacher's home as fixed session location, configurable 30 / 45 / 60 min sessions, 24-hour cancellation window, and Vercel subdomain for v1 (later upgraded to tutoring.aradrsk.com).
- Everything else in the PRD is downstream of those five decisions.
What's next
The remaining MVP backlog. Each row is a tracked issue; order is the critical path to launch.
- Next up
TU-6
Teacher sets weekly availability + date blocks
- Planned
TU-7
Public landing page with visible availability
- Planned
TU-8
Users can book a session with slot locking
- Planned
TU-9
Email confirmations via Resend
- Planned
TU-10
Teacher dashboard
- Planned
TU-11
User dashboard with cancel
- Partial (prod live)
TU-12
Deploy to prod + onboard teacher