The Problem
Jaanify's login/auth UI is fully integrated — the /login page renders, the middleware guards routes, the navbar shows session state — but clicking "Continue with Google" leads to a dead end. The OAuth callback route doesn't exist, the auth service functions are TODO stubs, and the session hydration endpoint (/users/me) returns 404.
Three P1 gaps from Cycle 14 gap analysis block the login flow:
L-31: Google OAuth Callback Route Missing
The login page generates a valid Google OAuth URL and redirects users to Google's consent screen. But when Google redirects back to /login/callback, there's no handler — users hit a 404.
What's needed:
- Frontend callback page at
apps/web/src/app/login/callback/page.tsx that reads the code query param and sends it to the API
- Backend
googleAuth() implementation that exchanges the authorization code for an ID token, verifies it, upserts the user in Prisma, and returns a token pair
The frontend route prefix /login/ is already marked as public in the middleware. The backend route /v1/auth/google exists but calls a stub function.
L-32: Auth Service Stubs Still TODO
apps/api/src/routes/auth/auth.service.ts has 4 stub functions that the route handlers call:
googleAuth() — needs to exchange Google auth code → verify ID token → upsert user → generateTokenPair()
refreshToken() — needs to call verifyRefreshToken() → check user exists → generateTokenPair()
register() — needs to create user from anonymous session → generateTokenPair()
logout() — needs to invalidate refresh token in DB
The building blocks are already there: auth-tokens.ts has generateTokenPair(), verifyAccessToken(), verifyRefreshToken(). The Prisma User and RefreshToken models exist. The route handlers already call setAuthCookies(reply, tokens) with the return value. The service layer just needs to compose these pieces.
L-33: /users/me Endpoint Missing
The Zustand auth store calls apiClient.get("/users/me") on page load to check if the session is valid and populate user info for the navbar. But no /users/me route exists — the request fails and the navbar always shows "Sign In" even for authenticated users.
What's needed:
- A
GET /v1/users/me route that reads request.userId (set by the auth plugin) and returns the user profile from Prisma
- This is a thin endpoint — the auth plugin already handles token verification and sets
request.userId
What We Already Have
Jaanify has invested 14 co-evolution cycles using jaan-to skills to build:
- 80+ deliverables across 20 categories
- 21 API endpoints defined in OpenAPI 3.1
- 8 Prisma models including User and RefreshToken
auth-tokens.ts with generateTokenPair(), verifyAccessToken(), verifyRefreshToken() using jose HS256
secure-cookies.ts with setAuthCookies(), clearAuthCookies() for HttpOnly Secure SameSite cookies
- Auth plugin with dual-mode token extraction (Authorization header + cookie)
- Cookie helpers with
getRefreshToken() for reading refresh tokens from cookies
- Build passes: both
tsc --noEmit and turbo build succeed
The inputs are all there. The auth route handlers exist, the cookie management exists, the token generation exists, the Prisma models exist. What's missing is the service layer glue that composes these pieces into working auth flows.
The Ask
The backend-service-implement skill (scored 4.7/5 in Jaanify testing) should be able to generate the auth service implementations from the existing specs, schemas, and scaffold code. Specifically:
- Implement
googleAuth() — Google code exchange → user upsert → token pair
- Implement
refreshToken() — verify → rotate → new token pair
- Implement
register() — anonymous → registered user flow
- Implement
logout() — invalidate refresh token
- Add
GET /v1/users/me route — return authenticated user profile
- Add
/login/callback frontend page — handle OAuth redirect
Context
- jaan-to version: v7.2.0-1-g3c10276
- Full gap report:
gap-reports/14-cycle/14-launch-gaps.md
- Tech stack: Fastify v5, Next.js 15, Prisma v6, jose, pnpm monorepo
- Critical path: L-32 → L-31 → L-33 → Working Login → Revenue
The Problem
Jaanify's login/auth UI is fully integrated — the
/loginpage renders, the middleware guards routes, the navbar shows session state — but clicking "Continue with Google" leads to a dead end. The OAuth callback route doesn't exist, the auth service functions are TODO stubs, and the session hydration endpoint (/users/me) returns 404.Three P1 gaps from Cycle 14 gap analysis block the login flow:
L-31: Google OAuth Callback Route Missing
The login page generates a valid Google OAuth URL and redirects users to Google's consent screen. But when Google redirects back to
/login/callback, there's no handler — users hit a 404.What's needed:
apps/web/src/app/login/callback/page.tsxthat reads thecodequery param and sends it to the APIgoogleAuth()implementation that exchanges the authorization code for an ID token, verifies it, upserts the user in Prisma, and returns a token pairThe frontend route prefix
/login/is already marked as public in the middleware. The backend route/v1/auth/googleexists but calls a stub function.L-32: Auth Service Stubs Still TODO
apps/api/src/routes/auth/auth.service.tshas 4 stub functions that the route handlers call:googleAuth()— needs to exchange Google auth code → verify ID token → upsert user →generateTokenPair()refreshToken()— needs to callverifyRefreshToken()→ check user exists →generateTokenPair()register()— needs to create user from anonymous session →generateTokenPair()logout()— needs to invalidate refresh token in DBThe building blocks are already there:
auth-tokens.tshasgenerateTokenPair(),verifyAccessToken(),verifyRefreshToken(). The PrismaUserandRefreshTokenmodels exist. The route handlers already callsetAuthCookies(reply, tokens)with the return value. The service layer just needs to compose these pieces.L-33: /users/me Endpoint Missing
The Zustand auth store calls
apiClient.get("/users/me")on page load to check if the session is valid and populate user info for the navbar. But no/users/meroute exists — the request fails and the navbar always shows "Sign In" even for authenticated users.What's needed:
GET /v1/users/meroute that readsrequest.userId(set by the auth plugin) and returns the user profile from Prismarequest.userIdWhat We Already Have
Jaanify has invested 14 co-evolution cycles using jaan-to skills to build:
auth-tokens.tswithgenerateTokenPair(),verifyAccessToken(),verifyRefreshToken()using jose HS256secure-cookies.tswithsetAuthCookies(),clearAuthCookies()for HttpOnly Secure SameSite cookiesgetRefreshToken()for reading refresh tokens from cookiestsc --noEmitandturbo buildsucceedThe inputs are all there. The auth route handlers exist, the cookie management exists, the token generation exists, the Prisma models exist. What's missing is the service layer glue that composes these pieces into working auth flows.
The Ask
The
backend-service-implementskill (scored 4.7/5 in Jaanify testing) should be able to generate the auth service implementations from the existing specs, schemas, and scaffold code. Specifically:googleAuth()— Google code exchange → user upsert → token pairrefreshToken()— verify → rotate → new token pairregister()— anonymous → registered user flowlogout()— invalidate refresh tokenGET /v1/users/meroute — return authenticated user profile/login/callbackfrontend page — handle OAuth redirectContext
gap-reports/14-cycle/14-launch-gaps.md