Portal backend: Facebook OAuth, social features, portal comments

- Facebook Login OAuth (meta-web auth service + routes)
- Account linking (merge Quest metaId + Facebook facebookId)
- User profile updates (bio, isPublic, displayName)
- Social endpoints: follow/unfollow, feed (trending/following/recent), likes
- Portal comments via WebSocket (subscribe_portal, send_portal_comment)
- Prisma migration: Follow, Like models, facebookId/bio/isPublic on User
- Provider OAuth source=web redirect support for portal callbacks
- Docker compose portal service, CORS multi-origin support
This commit is contained in:
2026-03-02 12:32:39 +01:00
parent 6931670a1f
commit 7ce1c2a8bc
17 changed files with 1060 additions and 26 deletions

View File

@@ -20,6 +20,31 @@ export interface UserProfileResponse {
displayName: string;
email: string | null;
avatarUrl: string | null;
bio: string;
isPublic: boolean;
hasQuestLink: boolean;
hasFacebookLink: boolean;
}
export interface UpdateProfileBody {
displayName?: string;
bio?: string;
isPublic?: boolean;
}
export interface MetaWebCallbackBody {
code: string;
state: string;
}
export interface LinkQuestBody {
metaId: string;
nonce?: string;
}
export interface LinkFacebookBody {
code: string;
state: string;
}
// ── Providers ────────────────────────────────────────────
@@ -113,3 +138,36 @@ export interface PreparedDestination {
streamKey: string;
broadcastId: string;
}
// ── Social ──────────────────────────────────────────────
export interface PublicUserResponse {
id: string;
displayName: string;
avatarUrl: string | null;
bio: string;
followerCount: number;
followingCount: number;
isFollowing: boolean;
}
export interface FeedItemResponse {
plan: StreamPlanResponse & { user: { id: string; displayName: string; avatarUrl: string | null } };
likeCount: number;
commentCount: number;
isLiked: boolean;
}
export interface FeedResponse {
items: FeedItemResponse[];
nextCursor: string | null;
}
export interface LikeStatusResponse {
count: number;
isLiked: boolean;
}
export interface FollowListResponse {
users: PublicUserResponse[];
nextCursor: string | null;
}