Files
libnovel/ui/src/routes/api/progress/+server.ts
Admin 8edad54b10 feat(progress): associate progress with logged-in user for cross-device sync
Add optional user_id field to the progress collection. When a user is
authenticated, progress is keyed by user_id instead of session_id, making
it portable across devices and browsers. Anonymous reading still works via
session_id as before.

On login or registration, any progress accumulated under the anonymous
session is merged into the user's account (most-recent timestamp wins),
so chapters read before logging in are not lost.

- scripts/pb-init.sh: add user_id field to progress collection schema
- scraper/internal/storage/pocketbase.go: add user_id to EnsureCollections
- ui/src/lib/server/pocketbase.ts: Progress interface gains user_id;
  getProgress/allProgress/setProgress accept optional userId and query/write
  by user_id when present; add mergeSessionProgress() helper
- ui/src/routes/login/+page.server.ts: call mergeSessionProgress after
  successful login and registration (fire-and-forget, non-fatal)
- ui/src/routes/api/progress/+server.ts: pass locals.user?.id to setProgress
- ui/src/routes/books/+page.server.ts: pass locals.user?.id to allProgress
- ui/src/routes/books/[slug]/+page.server.ts: pass locals.user?.id to getProgress
2026-03-04 09:51:11 +05:00

28 lines
1008 B
TypeScript

import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { setProgress } from '$lib/server/pocketbase';
import { log } from '$lib/server/logger';
/**
* POST /api/progress
* Body: { slug: string, chapter: number }
* Records the user's reading position.
* When the user is logged in, progress is keyed by user_id so it syncs across devices.
* When anonymous, progress is keyed by the session cookie.
*/
export const POST: RequestHandler = async ({ request, locals }) => {
const body = await request.json().catch(() => null);
if (!body || typeof body.slug !== 'string' || typeof body.chapter !== 'number') {
error(400, 'Invalid body — expected { slug, chapter }');
}
try {
await setProgress(locals.sessionId, body.slug, body.chapter, locals.user?.id);
} catch (e) {
log.error('progress', 'setProgress failed', { slug: body.slug, chapter: body.chapter, err: String(e) });
error(500, 'Failed to save progress');
}
return json({ ok: true });
};