Fix Garmin token connection not persisting after save
All checks were successful
Deploy / deploy (push) Successful in 1m38s
All checks were successful
Deploy / deploy (push) Successful in 1m38s
Root cause: The setup-db script was missing user field definitions (garminConnected, tokens, etc.). Production PocketBase had no such fields, so updates silently failed to persist. Changes: - Add user custom fields to setup-db.ts (matches e2e harness) - Fix status route to use strict boolean check (=== true) - Add verification in tokens route with helpful error message - Add ENCRYPTION_KEY to playwright config for e2e tests - Add comprehensive e2e tests for Garmin connection flow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,8 @@ import { daysUntilExpiry, isTokenExpired } from "@/lib/garmin";
|
||||
export const GET = withAuth(async (_request, user, pb) => {
|
||||
// Fetch fresh user data from database (auth store cookie may be stale)
|
||||
const freshUser = await pb.collection("users").getOne(user.id);
|
||||
const connected = freshUser.garminConnected;
|
||||
// Use strict equality to handle undefined (field missing from schema)
|
||||
const connected = freshUser.garminConnected === true;
|
||||
|
||||
if (!connected) {
|
||||
return NextResponse.json({
|
||||
|
||||
@@ -12,10 +12,14 @@ let currentMockUser: User | null = null;
|
||||
// Track PocketBase update calls
|
||||
const mockPbUpdate = vi.fn().mockResolvedValue({});
|
||||
|
||||
// Track PocketBase getOne calls - returns user with garminConnected: true after update
|
||||
const mockPbGetOne = vi.fn().mockResolvedValue({ garminConnected: true });
|
||||
|
||||
// Create mock PocketBase client
|
||||
const mockPb = {
|
||||
collection: vi.fn(() => ({
|
||||
update: mockPbUpdate,
|
||||
getOne: mockPbGetOne,
|
||||
})),
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { NextResponse } from "next/server";
|
||||
import { withAuth } from "@/lib/auth-middleware";
|
||||
import { encrypt } from "@/lib/encryption";
|
||||
import { daysUntilExpiry } from "@/lib/garmin";
|
||||
import { logger } from "@/lib/logger";
|
||||
|
||||
export const POST = withAuth(async (request, user, pb) => {
|
||||
const body = await request.json();
|
||||
@@ -63,6 +64,26 @@ export const POST = withAuth(async (request, user, pb) => {
|
||||
garminConnected: true,
|
||||
});
|
||||
|
||||
// Verify the update persisted (catches schema issues where field doesn't exist)
|
||||
const updatedUser = await pb.collection("users").getOne(user.id);
|
||||
if (updatedUser.garminConnected !== true) {
|
||||
logger.error(
|
||||
{
|
||||
userId: user.id,
|
||||
expected: true,
|
||||
actual: updatedUser.garminConnected,
|
||||
},
|
||||
"garminConnected field not persisted - check PocketBase schema",
|
||||
);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error:
|
||||
"Failed to save connection status. The garminConnected field may be missing from the database schema. Run pnpm db:setup to fix.",
|
||||
},
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate days until expiry
|
||||
const expiryDays = daysUntilExpiry({
|
||||
oauth1: "",
|
||||
|
||||
Reference in New Issue
Block a user