Skip to content

Conversation

@github-actions
Copy link
Contributor

This is an automated pull request to merge mariano/make-portal-great-again into dev.
It was created by the [Auto Pull Request] action.

@vercel
Copy link

vercel bot commented Dec 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
portal Error Error Jan 6, 2026 5:33pm
1 Skipped Deployment
Project Deployment Review Updated (UTC)
app Skipped Skipped Jan 6, 2026 5:33pm

@cursor
Copy link

cursor bot commented Dec 18, 2025

PR Summary

Centralizes authentication and streamlines the employee portal against the API.

  • Better Auth (API): Adds canonical better-auth instance, mounts at /api/auth/*, introduces JwtAuthGuard, and a new MeController (GET /v1/me/organizations).
  • People endpoints: Adds /v1/people/me (member), /v1/people/me/training-videos and POST /v1/people/me/training-videos/:videoId/complete.
  • Policies: Extends policy model responses (displayFormat, pdfUrl) and adds acknowledgements (POST /v1/policies/:id/acknowledge, POST /v1/policies/acknowledge-bulk) plus signed PDF URL (GET /v1/policies/:id/pdf-url).
  • Portal refactor: Migrates UI to @trycompai/design-system, replaces server actions with API calls (SWR hooks), implements org selection via new memberships API, and rewires policies/training/device agent flows to new endpoints.
  • Config/clients: Requires NEXT_PUBLIC_API_URL; updates auth clients to point to API origin with credentials: 'include'; removes app-local auth routes; tweaks build/transpile settings and package deps.

Written by Cursor Bugbot for commit c0404e6. This will update automatically on new commits. Configure here.

@graphite-app graphite-app bot requested a review from Marfuen December 18, 2025 15:40
@graphite-app
Copy link

graphite-app bot commented Dec 18, 2025

Graphite Automations

"Auto-assign PRs to Author" took an action on this PR • (12/18/25)

1 reviewer was added to this PR based on Mariano Fuentes's automation.

return true;
} catch (error) {
throw new UnauthorizedException('Invalid or expired JWT token');
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JWT guard swallows specific auth error messages

The catch block at the end of handleJwtAuth catches all errors including the specific UnauthorizedException instances thrown within the try block (e.g., "BETTER_AUTH_URL not configured", "missing user information", "User does not have access to organization"). These informative error messages are discarded and replaced with a generic "Invalid or expired JWT token" message, making it very difficult to diagnose authentication failures in production or during development.

Fix in Cursor Fix in Web

@vercel vercel bot temporarily deployed to Preview – portal January 2, 2026 20:55 Inactive
@vercel vercel bot temporarily deployed to Preview – app January 2, 2026 20:55 Inactive
emailOTPClient(),
multiSessionClient(),
],
baseURL: env.NEXT_PUBLIC_API_URL,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OAuth login broken due to cross-domain session cookie

The authClient.baseURL was changed from NEXT_PUBLIC_BETTER_AUTH_URL to NEXT_PUBLIC_API_URL, and the portal's auth routes (/api/auth/[...all]) were removed. OAuth flows now complete on the API server, setting the session cookie on the API domain. However, the portal's server-side layout calls auth.api.getSession() which looks for session cookies on the portal's domain. Since the cookie is on a different domain, OAuth users always have a null session and get redirected to /auth in an infinite loop, preventing login via Google or Microsoft.

Additional Locations (1)

Fix in Cursor Fix in Web


if (error || data?.error) {
return null;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silent error handling returns empty dashboard view

When the useEmployeePortalOverview hook encounters errors (either from the hook's error property or data?.error), the component silently returns null instead of displaying an error message like NoAccessMessage. The previous implementation in OrganizationDashboard.tsx showed appropriate error states to users. With this change, users may see a blank screen without any indication of what went wrong, making it difficult to understand or report issues.

Fix in Cursor Fix in Web


return {
status: 200,
data: EmployeePortalDashboardSchema.parse(dashboardCandidate),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zod parse errors in SWR fetcher are unhandled

If the API returns data that doesn't match the expected Zod schemas (MemberSchema, PolicySchema, HostSchema, etc.), the parse() calls will throw ZodError exceptions. These errors are not caught within the fetcher, causing SWR to enter an error state with a potentially cryptic validation error message rather than a user-friendly one. While SWR handles the error, users would see unhelpful schema validation messages instead of clear feedback about what went wrong.

Fix in Cursor Fix in Web

@vercel vercel bot temporarily deployed to Preview – app January 6, 2026 17:30 Inactive
request.userId = userId;
request.userEmail = userEmail;
request.authType = 'jwt';
request.isApiKey = false;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JwtAuthGuard does not initialize required userRoles property

Medium Severity

The JwtAuthGuard sets userId, userEmail, authType, and isApiKey on the request but never sets userRoles. The AuthenticatedRequest interface defines userRoles as string[] | null (non-optional), but it remains undefined at runtime. This violates the type contract and could cause runtime errors if any code accesses request.userRoles expecting it to be an array or null. The HybridAuthGuard correctly sets userRoles to either the parsed roles or null, but JwtAuthGuard omits this initialization entirely.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants