Skip to content

feat: add friends and schedule linking#1511

Open
brelieu05 wants to merge 239 commits intomainfrom
911-suggestion-view-friends-schedules
Open

feat: add friends and schedule linking#1511
brelieu05 wants to merge 239 commits intomainfrom
911-suggestion-view-friends-schedules

Conversation

@brelieu05
Copy link
Copy Markdown
Contributor

@brelieu05 brelieu05 commented Feb 19, 2026

Summary

Builds off of the sharable schedule links system from #1357.

  • Adds a full friends system: send/accept/decline/remove friend requests by email, block/unblock users, and
    view a friend's shared schedule via a direct link.
  • Adds per-schedule sharing toggles so users can choose which of their schedules are visible to friends.
  • Refactors all friends mutations to verify identity via server-issued session tokens instead of
    client-supplied providerAccountId, closing an impersonation/spoofing vector.
image image image

Features

Friends system

  • Friend requests — send by email, accept or decline incoming requests, prevent duplicate requests in
    either direction
  • Unfriend / block / unblock — full relationship lifecycle with a blocked state that prevents
    re-requesting
  • View friend's schedule — navigate to a friend's shared schedule via direct link; non-friends are
    blocked from viewing
  • Friends menu — popover in the header with tabs for Friends, Requests, and Blocked. Skeleton loading
    state while data fetches.
  • Sign-in prompt — clicking Friends while logged out opens a sign-in dialog instead
  • Per-schedule sharing toggle — each schedule row gets a People/PeopleOutline icon to control
    whether friends can see it; defaults to visible for all existing schedules

DB changes

  • packages/db/src/schema/friendship.ts — new friendships table (requesterId, addresseeId, status: PENDING | ACCEPTED | BLOCKED, timestamps)
  • packages/db/src/schema/schedule/schedule.ts — added sharedWithFriends boolean NOT NULL DEFAULT true
  • packages/db/migrations/0008_old_misty_knight.sql — friendships table + self-friend constraint
  • packages/db/migrations/0009_friendships_no_self_friend.sql — check constraint preventing self-friendship
  • packages/db/migrations/0010_schedule_shared_with_friends.sql — new column on schedules

Test plan

  • Send a friend request by email — recipient sees it in the Requests tab
  • Accept the request — both users appear in each other's Friends tab
  • Decline a request — row removed, no ACCEPTED state
  • Block a user — removed from friends, blocked in both directions
  • Try to friend yourself — should return an error
  • Send a duplicate friend request — should show a contextual message, not crash
  • Toggle a schedule to hidden — friend visiting your link no longer sees that schedule
  • Hide all schedules — friend sees a warning banner instead of an error
  • Non-friend tries to visit your schedule link — blocked

Issues

Closes #

if (isSearchTab) {
return (
<Tooltip title="Add this schedule to your account before adding classes">
<span
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: i know MUI tooltips are tricky, but this is kinda ugly :(

not blocking tho

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will refer this to the design team next meeting, because i got no idea how to make this tooltip look better

brelieu05 and others added 16 commits May 1, 2026 16:39
@brelieu05
Copy link
Copy Markdown
Contributor Author

Screenshot 2026-04-29 at 7 26 36 PM The empty state on friends schedules should probably be amended to not be in the 1st person. Also, i have access to the import dialog panel here

Change I made:
image

@brelieu05
Copy link
Copy Markdown
Contributor Author

todo: i will fix the deployment db. db migrate command wasn't working a couple weeks ago, so I ran the sql commands manually into the scheduler, but now i gotta undo said commands and redeploy

@KevinWu098
Copy link
Copy Markdown
Member

todo: i will fix the deployment db. db migrate command wasn't working a couple weeks ago, so I ran the sql commands manually into the scheduler, but now i gotta undo said commands and redeploy

yeah the problem is annoying, but its actually very easy to fix — drizzle doesn't generate idiomatic migrations by default, but cursor will clean it up for you pretty easily

DO $$ BEGIN
 CREATE TYPE "public"."friendship_status" AS ENUM('PENDING', 'ACCEPTED', 'DECLINED', 'BLOCKED');
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "friendships" (
	"requester_id" text NOT NULL,
	"addressee_id" text NOT NULL,
	"status" "friendship_status" DEFAULT 'PENDING' NOT NULL,
	"created_at" timestamp with time zone DEFAULT now() NOT NULL,
	"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
	CONSTRAINT "friendships_requester_id_addressee_id_pk" PRIMARY KEY("requester_id","addressee_id"),
	CONSTRAINT "friendships_no_self_friend" CHECK ("friendships"."requester_id" <> "friendships"."addressee_id")
);
--> statement-breakpoint
ALTER TABLE "schedules" ADD COLUMN IF NOT EXISTS "shared_with_friends" boolean DEFAULT true NOT NULL;--> statement-breakpoint

@KevinWu098
Copy link
Copy Markdown
Member

todo: i will fix the deployment db. db migrate command wasn't working a couple weeks ago, so I ran the sql commands manually into the scheduler, but now i gotta undo said commands and redeploy

i would very very strongly recommend against executing commands against the DB directly, as that can really fuck with drizzle's state and the rest of the DB (in this case its staging so its whatever, but its a good rule of thumb to be really judicious in your usage)

Comment thread apps/antalmanac/src/backend/lib/rds.ts Outdated
Copy link
Copy Markdown
Member

@KevinWu098 KevinWu098 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more minor stuff. given that is past midnight already, im opting not to review the Friends- components. if we'd like to merge, im happy to approve in the morning. but otherwise, we can take an extra day to resolve this and maybe take a pass on styling

Comment thread apps/antalmanac/src/backend/routers/userData.ts Outdated
Comment thread apps/antalmanac/src/backend/lib/rds.ts Outdated
const session = useSessionStore.getState();
if (session.sessionIsValid) {
try {
await autoSaveSchedule({});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: why are we calling auto save schedule

throw new TRPCError({
code: 'BAD_REQUEST',
message: theyRequestedYou
? 'This user has already sent you a friend request. Check your Requests tab to accept.'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought (non-blocking): we could probably just "accept" the friend req at this point and success it

* @param input - An object containing the schedule ID.
* @returns The schedule data associated with the schedule ID, or throws NOT_FOUND if not found.
*/
getSharedSchedule: procedure.input(z.object({ scheduleId: z.string() })).query(async ({ input }) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: is this method not redundant? is there really no method for getting schedule by id on another router?

if it is not redundant, seems like this should... probably live on another router (?) with validation that the user is actually allowed to fetch this schedule?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggestion: View Friends' Schedules