Insta-style Online-Status mit Following-Filter + User-opt-out: - Profile.lastSeenAt + Profile.presenceVisible (default true) - GET /api/presence/last-seen?userIds=... batch, server-side filter durch Follow-Relation + presenceVisible - GET /api/me/following → User-IDs für client-side Channel-Filter (Supabase Realtime Presence hat keine server-side Filter) - POST /api/me/presence-visibility Toggle - POST /api/me/last-seen Heartbeat (Phase-1-Fallback bis Edge-Function) - /api/auth/me extended um presenceVisible für Settings-Initial-State DB-Layer nutzt raw SQL bis Migration auf staging gelaufen ist (Prisma-Client refresh erst nach CI generate). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
import { getProfile } from "../../db/profile";
|
|
import { getPlanLimits } from "../../utils/plan-features";
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const user = await requireUser(event);
|
|
const dbProfile = await getProfile(user.id);
|
|
|
|
const plan = (dbProfile?.plan === "premium"
|
|
? "legend"
|
|
: dbProfile?.plan === "standard"
|
|
? "pro"
|
|
: dbProfile?.plan ?? "free") as "free" | "pro" | "legend";
|
|
|
|
const limits = getPlanLimits(plan);
|
|
|
|
return {
|
|
id: user.id,
|
|
email: user.email,
|
|
username: dbProfile?.username ?? "",
|
|
nickname: dbProfile?.nickname ?? null,
|
|
avatar: dbProfile?.avatar ?? null,
|
|
plan,
|
|
foundingMember: dbProfile?.foundingMember ?? false,
|
|
streak: dbProfile?.streak ?? 0,
|
|
lyraVoiceId: dbProfile?.lyraVoiceId ?? null,
|
|
onboardingStep: dbProfile?.onboardingStep ?? "welcome",
|
|
created_at: dbProfile?.createdAt?.toISOString() ?? user.created_at,
|
|
// Für useUserPlan im Frontend — Key-Subset der PlanLimits
|
|
planLimits: {
|
|
customDomains: limits.customDomains, // { web: number, mail: number }
|
|
domainRefill: limits.domainRefill,
|
|
mailAgents: limits.mailAgents === Infinity ? null : limits.mailAgents,
|
|
globalBlocklist: limits.globalBlocklist,
|
|
maxAppDevices: limits.maxAppDevices,
|
|
maxProtectedDevices: limits.maxProtectedDevices,
|
|
canCreateGroup: limits.canCreateGroup,
|
|
canAddToBlocklist: limits.canAddToBlocklist,
|
|
},
|
|
globalBlocklistGraceUntil:
|
|
dbProfile?.globalBlocklistGraceUntil?.toISOString() ?? null,
|
|
presenceVisible: dbProfile?.presenceVisible ?? true,
|
|
};
|
|
});
|