Add refresh shelf capability

This commit is contained in:
Rob Walsh
2026-03-05 22:24:42 -07:00
parent 01b59fae9d
commit a564fefd7c
11 changed files with 206 additions and 29 deletions
@@ -17,6 +17,7 @@ const logger = RMABLogger.create('API.HardcoverShelves');
const UpdateHardcoverSchema = z.object({
listId: z.string().min(1, 'List ID is required').optional(),
apiToken: z.string().optional(),
forceSync: z.boolean().optional(),
});
/**
@@ -89,10 +90,10 @@ export async function PATCH(
}
const body = await request.json();
const { listId, apiToken } = UpdateHardcoverSchema.parse(body);
const { listId, apiToken, forceSync } = UpdateHardcoverSchema.parse(body);
const updateData: { listId?: string; apiToken?: string; lastSyncAt?: null; bookCount?: null; coverUrls?: null } = {};
let needsResync = false;
let needsResync = !!forceSync;
let cleanedToken: string | undefined;
if (apiToken && apiToken.trim() !== '') {
+63
View File
@@ -0,0 +1,63 @@
/**
* Component: Manual Shelf Sync API Route
* Documentation: documentation/backend/services/goodreads-sync.md
*/
import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, AuthenticatedRequest } from '@/lib/middleware/auth';
import { getJobQueueService } from '@/lib/services/job-queue.service';
import { RMABLogger } from '@/lib/utils/logger';
import { z } from 'zod';
const logger = RMABLogger.create('API.ShelvesSync');
const SyncSchema = z.object({
shelfId: z.string().optional(),
shelfType: z.enum(['goodreads', 'hardcover']).optional(),
});
/**
* POST /api/user/shelves/sync
* Trigger a manual sync for all or a specific shelf belonging to the user.
*/
export async function POST(request: NextRequest) {
return requireAuth(request, async (req: AuthenticatedRequest) => {
try {
if (!req.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await request.json().catch(() => ({}));
const { shelfId, shelfType } = SyncSchema.parse(body);
const jobQueue = getJobQueueService();
// Trigger sync job with userId filter
await jobQueue.addSyncShelvesJob(
undefined,
shelfId,
shelfType,
0, // unlimited lookups for manual trigger
req.user.id
);
logger.info(`Manual sync triggered for user ${req.user.id}${shelfId ? ` (shelf: ${shelfId})` : ' (all shelves)'}`);
return NextResponse.json({
success: true,
message: shelfId ? 'Shelf sync triggered' : 'All shelves sync triggered'
});
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json({ error: 'ValidationError', details: error.errors }, { status: 400 });
}
logger.error('Failed to trigger manual sync', {
error: error instanceof Error ? error.message : String(error),
});
return NextResponse.json(
{ error: 'Failed to trigger manual sync' },
{ status: 500 },
);
}
});
}