Gradeful
CoursesPricingAbout

How Gradeful connects

Raw markdown

Settings

Account settings modal over the workspace. Opened from the gear, account flyout Settings / Get help, or /dashboard?settings={tab} (also recognized on /my-courses?settings=). buildSettingsHref always points at /dashboard?settings=…. After open, the query is stripped. Legacy /settings, /settings/profile, /settings/security, /settings/notifications, /settings/billing, /settings/help, /settings/danger redirect here. /settings/appearance and /settings/language redirect to profile.

PAGE: /dashboard?settings={tab} Purpose: Every student account setting (identity, notifications, billing, security, delete, help). Access: logged-in + onboarded workspace. GET /api/workspace/settings returns 401 if anonymous. Entry points: Sidebar/header gear; flyout Settings; flyout Get help (help tab); security Manage account deletion →; marketing header gear → /dashboard?settings=profile.

SECTION: Modal chrome Copy: Dialog title (sr-only) Settings. Nav aria-label Settings sections. Load skeleton aria-label Loading settings. Error Could not load settings. Please try again. Billing placeholder Loading settings... Data shown: GET /api/workspace/settings → { settings, billing }

ELEMENT: Profile Action: toggle Destination: profile pane (settings=profile) Writes to: none Reads from: none

ELEMENT: Notifications Action: toggle Destination: notifications pane Writes to: none Reads from: none

ELEMENT: Plan & billing Action: toggle Destination: billing pane Writes to: none Reads from: none

ELEMENT: Security Action: toggle Destination: security pane Writes to: none Reads from: none

ELEMENT: Danger zone Action: toggle Destination: danger pane Writes to: none Reads from: none

ELEMENT: Help & contact Action: toggle Destination: help pane Writes to: none Reads from: none


SECTION: Profile Copy: Profile Correct name, university, and optional programs here. Paid access stays on the courses you bought — not these labels. Data shown: profiles.*, user_badges.*

Where you study

Copy: Where you study University matches AUB or LAU course offerings. Changing it does not change courses you already bought. Copy: Which university? AUB and LAU use different course codes. This picks the matching offering. Campus (optional, LAU only): Campus (optional) Beirut or Byblos does not change which Gradeful courses you can open.

ELEMENT: AUB / LAU Action: toggle Destination: none Writes to: profiles.university on Save changes Reads from: profiles.university

ELEMENT: Beirut / Byblos (optional) Action: toggle Destination: none Writes to: profiles.campus on Save changes Reads from: profiles.campus

Programs (optional)

Copy: Programs (optional) Major and minors are for later recommendations. They are not required to open a course. ELEMENT: Major / Second major / Minors (typeaheads, not required) Writes to: profiles.major, second_major, minors on Save changes

You

Copy: You How Gradeful greets you in the workspace. Labels Profile photo Full name Nickname {n}/20 Used in your workspace greeting. Letters, numbers, and underscores only. Account email This is your Gradeful login and receipts. It is not overwritten by an AUB or LAU address. Institution email Optional, and separate from login. Checkout may ask for your AUB or LAU address as a payment contact. Data shown: profiles.full_name, nickname, avatar_url; Auth email

ELEMENT: Change photo Action: open modal Destination: crop dialog Crop your photo Drag to reposition and use the slider to zoom. We save a square crop. Writes to: none until Save photo Reads from: profiles.avatar_url

ELEMENT: Zoom (range 1–3) Action: toggle Destination: none Writes to: none Reads from: none

ELEMENT: Cancel Action: toggle Destination: closes crop Writes to: none Reads from: none

ELEMENT: Save photo / Uploading... Action: submit Destination: none Writes to: Storage avatars/{userId}/avatar.jpg; profiles.avatar_url; profiles.updated_at Reads from: cropped blob Success: Profile photo updated Errors: Upload a JPG, PNG, or WebP image. Photo must be 5MB or smaller. You must be signed in to change your photo. Choose a photo to upload. Your photo could not be uploaded. Please try again. Your photo uploaded but could not be saved. Please try again.

ELEMENT: Full name Action: toggle Destination: none Writes to: profiles.full_name on Save changes (max 100) Reads from: profiles.full_name

ELEMENT: Nickname Action: toggle Destination: none Writes to: profiles.nickname (2–20, [a-zA-Z0-9_]+) Reads from: profiles.nickname Errors: Enter a nickname. Use at least 2 characters. Use at most 20 characters. Use letters, numbers, and underscores only.

ELEMENT: Email (disabled) Action: none Destination: none Writes to: none Reads from: auth.users.email

ELEMENT: Contact support Action: external link Destination: https://wa.me/96179057533 Writes to: none Reads from: none

ELEMENT: Save changes / Saving... Action: submit Destination: toast + refresh Writes to: profiles.full_name, profiles.nickname, profiles.updated_at Reads from: form Success: Profile updated Error: Something went wrong

Showing up

Copy: Showing up Quiet milestones for coming back. Not trophies for never missing a day. Cards: One week Showed up seven days in a row; Two weeks A fortnight of showing up; One month A month of making this a habit; Two months Sixty days of quiet consistency; One hundred days A home you kept returning to. Earned subtitle formatted MMM D, YYYY. Data shown: user_badges.badge_type, user_badges.earned_at

ELEMENT: none (display only) Action: none Destination: none Writes to: none Reads from: user_badges


SECTION: Notifications Copy: Notifications Choose what you hear about from us. Study reminders stay quiet and optional. Data shown: profiles.notification_preferences JSON. Defaults: access_granted true, new_course true, announcements false, study_reminders true. Key reservation_updates exists in JSON (default true) with no toggle.

ELEMENT: Access granted emails Action: toggle Destination: none (saves immediately) Writes to: profiles.notification_preferences.access_granted, profiles.updated_at Reads from: same Description: Get an email when your course access is activated.

ELEMENT: New course available Action: toggle Destination: none Writes to: profiles.notification_preferences.new_course Reads from: same Description: Hear when a new course pack is added for your university.

ELEMENT: Platform announcements Action: toggle Destination: none Writes to: profiles.notification_preferences.announcements Reads from: same Description: Occasional updates about Gradeful features and changes.

ELEMENT: Study reminders Action: toggle Destination: none Writes to: profiles.notification_preferences.study_reminders Reads from: same Description: A gentle evening nudge if you haven't opened a pack yet. Never a guilt trip. Toasts: Preferences updated Something went wrong


SECTION: Plan & billing Copy: Plans & access Your active courses and payment history. Change plan anytime. Active access Payment history columns Date Plan Amount Status Data shown: Active cards from user_access (plan_type, course_ids, expires_at, statuses paid/confirmed/pending, not expired) joined to courses.code. History from Whish orders for the signed-in user (plan, amount, payment_status, created_at). Plan names Focus / Balance / Full Load / Crunch else Course access. Status from commercialOrderStatus(). Courses covered: {codes | Selected courses | No courses selected} Expires {date | Not set} badge Expiring soon if ≤14 days. Empty access No active access yet. Empty history No payment history yet. Amount uses orders.amount.

ELEMENT: Upgrade or change plan Action: navigate Destination: /pricing Writes to: none Reads from: none

ELEMENT: Browse plans → Action: navigate Destination: /pricing Writes to: none Reads from: visible when no active access


SECTION: Security Copy: Security Manage how you sign in to Gradeful loading Loading sign-in methods… Data shown: Supabase Auth identities and session (last_sign_in_at / updated_at as last active)

Change password (email identity only)

Copy: Change password labels Current password New password Confirm new password

ELEMENT: Update password / Updating... Action: submit Destination: none Writes to: auth.users password (signInWithPassword then updateUser) Reads from: email prop + form Toasts: New password must be at least 8 characters New passwords do not match Current password is incorrect Something went wrong Password updated

Phone sign-in (phone identity)

Copy: Phone sign-in You sign in with your phone number ending in ••••{lastFour}. Data shown: Auth phone identity ELEMENT: none (display)

Google

Copy: Google You sign in with Google. status Connected / Not connected check aria-label Connected

ELEMENT: Connect / Working... Action: submit Destination: /auth/callback?next=/dashboard?settings=security Writes to: Auth identity (linkIdentity Google) Reads from: identities Toast: Google could not be connected

ELEMENT: Disconnect / Working... Action: submit Destination: none Writes to: Auth (unlinkIdentity) Reads from: blocked if only one identity Toasts: Google could not be disconnected Add another sign-in method before disconnecting Google Google disconnected

Add password backup (Google-only)

Copy: Add password backup Add a password so you can still sign in if Google is unavailable. ELEMENT: Password / Confirm password / Add backup / Saving... Action: submit Destination: none Writes to: Auth updateUser({ password }) Reads from: none Toasts: Password must be at least 8 characters Passwords do not match We could not add a password backup. Try again. Password backup added

Add email and password backup (phone-only)

Copy: Add email and password backup Add an email and password so you have another way back in. After send: We sent a confirmation link to {email}. Confirm it to finish adding your backup sign-in method. ELEMENT: Email / Password / Confirm password / Add backup / Saving... Action: submit Destination: none Writes to: Auth email+password Reads from: none Toasts: Enter a valid email address. We could not add email and password backup. Try again. Check your email to confirm the backup sign-in method. plus password match/length toasts above

This device

Copy: This device Last active {Just now | Recently | formatted datetime} ELEMENT: none (display) Reads from: Auth last_sign_in_at / updated_at

ELEMENT: Manage account deletion → Action: toggle Destination: Danger zone tab (fallback /dashboard?settings=danger) Writes to: none Reads from: none


SECTION: Danger zone Copy: Danger zone Account actions that cannot be undone

Sign out

Copy: Sign out End your session on this device.

ELEMENT: Sign out / Signing out... Action: submit Destination: / Writes to: clears Auth session Reads from: none

Delete your account

Copy: Delete your account This permanently removes your profile, access records, and account data. This cannot be undone. Dialog Delete your account? This action is permanent. Type DELETE below to confirm. Label Confirmation placeholder DELETE

ELEMENT: Delete account Action: open modal Destination: confirm dialog Writes to: none Reads from: none

ELEMENT: Cancel Action: toggle Destination: closes dialog Writes to: none Reads from: none

ELEMENT: Permanently delete / Deleting... Action: submit Destination: / on success; /login if unauthorized Writes to: deletes Auth user (auth.admin.deleteUser); related rows cascade Reads from: confirmation must equal DELETE Errors: You must be signed in to delete your account. We couldn't delete your account right now. Please contact support.


SECTION: Help & contact Copy: Help & contact Reach out or browse common answers Chat with us Usually responds within a day Request a missing course We prioritize by demand

ELEMENT: Open WhatsApp Action: external link Destination: https://wa.me/96179057533 Writes to: none Reads from: none

ELEMENT: Request a course Action: navigate Destination: /courses#course-request Writes to: none Reads from: none

ELEMENT: Privacy Policy Action: navigate Destination: /privacy Writes to: none Reads from: none

ELEMENT: Terms of Service Action: navigate Destination: /terms Writes to: none Reads from: none

ELEMENT: Refund Policy Action: navigate Destination: /refunds Writes to: none Reads from: none

ELEMENT: Academic Integrity Action: navigate Destination: /academic-integrity Writes to: none Reads from: none


Not in the modal (removed half-features)

Dark mode and extra languages are not shipped. The orphaned Appearance and Language panes were removed so settings only shows working tabs. /settings/appearance and /settings/language still redirect to profile. profiles.theme_preference and profiles.language_preference remain in the schema for a later full feature — do not expose “coming soon” UI until then.

Gradeful

Course-specific study packs for AUB and LAU students. Built for focused self-study.

Gradeful is an independent study-support service. Universities named on this site are listed only so you can match a Gradeful pack to the course you are taking. Those universities do not provide, sponsor, or endorse Gradeful, and Gradeful does not claim access to their official materials or assessments.

© 2026 Gradeful.

Platform

HomeCoursesPricing

Policies

Privacy PolicyTerms of ServiceRefund PolicyAcademic Integrity