Backend: - Prisma PushToken model + chat_push_enabled flag on profiles - Migration 20260530_add_push_tokens (push_tokens table + profile flag) - Service sendChatPush with expo-server-sdk (auto-disable invalid tokens) - Fire-and-forget push trigger in sendDirectMessage + createRoomMessage - API POST /users/me/push-token (upsert) + DELETE (soft-disable) Client (rebreak-native): - usePushTokenRegistration hook: permission, getExpoPushTokenAsync, Android channel 'chat', POST to backend; idempotent per session - Notification tap deep-link: dm -> /dm?userId, room -> /room?roomId Deploy: - run_quiet spinner for silent altool/xcodebuild/gradle phases - Release-notes pipeline (--notes flag / NEXT_RELEASE.md / interactive) archived to CHANGELOG.md, printed with ASC + Play Console links - Default version bump ON (--no-bump opt-out), build cleanup - NEXT_RELEASE.md with push-notification release note
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
/**
|
|
* POST /api/users/me/push-token
|
|
*
|
|
* Client (Expo) ruft das nach `getExpoPushTokenAsync()` auf, um seinen Token
|
|
* im Backend zu hinterlegen. Idempotent: bei existierendem Token wird nur
|
|
* lastUsedAt + enabled aktualisiert.
|
|
*
|
|
* Body: { token: string, platform: "ios" | "android", deviceId?: string }
|
|
*/
|
|
import { requireUser } from "../../../utils/auth";
|
|
import { usePrisma } from "../../../utils/prisma";
|
|
import { z } from "zod";
|
|
|
|
const Body = z.object({
|
|
token: z.string().min(10).max(200), // ExponentPushToken[xxx]
|
|
platform: z.enum(["ios", "android"]),
|
|
deviceId: z.string().max(120).optional(),
|
|
});
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const user = await requireUser(event);
|
|
const raw = await readBody(event).catch(() => ({}));
|
|
const parsed = Body.safeParse(raw);
|
|
if (!parsed.success) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
data: { error: "INVALID_BODY", detail: parsed.error.flatten() },
|
|
});
|
|
}
|
|
|
|
const { token, platform, deviceId } = parsed.data;
|
|
const db = usePrisma();
|
|
|
|
await db.pushToken.upsert({
|
|
where: { token },
|
|
create: {
|
|
userId: user.id,
|
|
token,
|
|
platform,
|
|
deviceId: deviceId ?? null,
|
|
enabled: true,
|
|
lastUsedAt: new Date(),
|
|
},
|
|
update: {
|
|
userId: user.id, // Token könnte das Device gewechselt haben
|
|
platform,
|
|
deviceId: deviceId ?? null,
|
|
enabled: true,
|
|
lastUsedAt: new Date(),
|
|
},
|
|
});
|
|
|
|
return { success: true, data: { ok: true } };
|
|
});
|