Skip to content

Conversation

@mtlaso
Copy link
Owner

@mtlaso mtlaso commented Dec 17, 2025

Summary by CodeRabbit

  • New Features

    • Server-side locale initialization and static locale params; new client auth helper for social sign‑in/out; React compiler and component caching enabled.
  • UI

    • Better mobile detection; improved login/logout flow with disabled buttons and redirect messaging; minor visual/responsive tweaks.
  • Bug Fixes

    • Grammar fix in copy; explicit decimal parsing to avoid number parsing issues.
  • Chores

    • Dependency and dev‑tool upgrades, packageManager metadata added, legacy experimental flags removed, dev script simplified.

@vercel
Copy link

vercel bot commented Dec 17, 2025

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
bocal Ignored Ignored Preview Feb 12, 2026 2:47am

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Centralizes many locale-scoped imports to @/lib, removes per-page experimental_ppr exports, replaces useMediaQuery with useIsMobile, migrates auth from NextAuth to better-auth (server + client), updates DB schema/migrations and snapshots, adds generateStaticParams, renames proxy export, and upgrades tooling/dependencies.

Changes

Cohort / File(s) Summary
Config & Tooling
biome.json, next.config.ts, tsconfig.json, .github/workflows/deploy-preview.yml, package.json
Bumped biome schema; reorganized Next.js config (new top-level flags, revised experimental keys); set JSX runtime to react-jsx; removed pnpm action pin; large dependency/version bumps and packageManager field; dev script removed --turbopack.
Auth Server & Client
src/auth.ts, src/auth-client.ts, src/old-auth.ts, src/app/api/auth/[...nextauth]/route.ts
Replaced NextAuth config with better-auth server config and auth export; added authClient for browser; preserved legacy NextAuth code commented in src/old-auth.ts; API route now uses toNextJsHandler(auth).
Auth UI & Actions
src/lib/actions.ts, src/app/[locale]/ui/auth/*
Removed legacy authenticate/logout helpers; UI now invokes authClient signIn/signOut inline; actions.ts trimmed of authenticate/logout.
Import Consolidation
src/app/[locale]/**, src/{sitemap.tsx,robots.tsx}, src/proxy.ts, src/lib/*
Many imports repointed from @/app/[locale]/lib/...@/lib/...; minor fixes (explicit parseInt radix, map→forEach, Tailwind class tweaks).
Pages & Locale Init
src/app/[locale]/**/page.tsx (landing, login, d/, legal/, newsletters, feeds, settings, etc.)
Pages now accept Page({ params }: PageProps<...>), call setRequestLocale(locale) (via use(params)), and remove export const experimental_ppr.
Layout & Routing
src/app/[locale]/layout.tsx
Added generateStaticParams() producing locale params; RootLayout signature updated to LayoutProps<"/[locale]">.
Hooks & Mobile Detection
src/app/[locale]/lib/hooks/use-media-query.tsx (deleted), useIsMobile usages
Deleted useMediaQuery; replaced desktop-detection with useIsMobile across UI components and adjusted render branches.
DAL / Feed Service / Stores
src/lib/dal.ts, src/lib/feed-service.ts, src/lib/stores/*
DAL switched to headers-based session retrieval via auth.api.getSession; feed-service and stores imports centralized; small iteration style changes.
Settings & Session Shape
src/app/[locale]/ui/settings/settings.tsx, related pages
Settings components now accept `sess: Promise<BocalUserSession
Proxy / Middleware
src/proxy.ts
Default export renamed from middlewareproxy; session cookie read refactored to getSessionCookie(req) and redirects use APP_ROUTES.login.
DB Schema & Migrations
src/db/schema.ts, auth-schema.ts, drizzle/*.sql, drizzle/meta/*, drizzle/meta/_journal.json
Drizzle schema and migrations updated: column renames, new timestamp/audit fields, PK/index reorganizations, snapshots added/updated and journal entries appended.
Small UI & Copy
src/components/ui/navigation-menu.tsx, assorted UI files, messages/en.json
Minor Tailwind utility normalizations, icon sizing tweaks, small text correction in messages.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser as Browser
  participant AuthClient as "authClient (browser)"
  participant NextAPI as "/api/auth (Next.js)"
  participant AuthServer as "better-auth (server)"
  participant DB as Database

  Browser->>AuthClient: user clicks provider sign-in
  AuthClient->>NextAPI: POST /api/auth (toNextJsHandler)
  NextAPI->>AuthServer: delegate request to better-auth
  AuthServer->>DB: read/write users/accounts/sessions
  DB-->>AuthServer: return records
  AuthServer-->>NextAPI: return response/redirect
  NextAPI-->>AuthClient: forward response
  AuthClient-->>Browser: follow redirect / update UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐇
I hopped imports from locale to lib with cheer,
swapped sessions and cookies so auth is clear,
pages learn their language, migrations took root,
mobile hops guide UI and components reboot,
tiny paws, bold code — a rabbit's bright cheer!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat!: mise à jour vers nextjs 16' clearly and concisely describes the main objective—upgrading to Next.js 16. The breaking change indicator (!) appropriately signals significant changes across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch next16-update

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/[locale]/ui/feeds/add-feed-form.tsx (1)

28-42: Potential hydration mismatch with useIsMobile.

The useIsMobile hook returns undefined during the initial render (before useEffect runs), which means !!isMobile evaluates to false, always rendering the desktop variant first. This can cause:

  1. Hydration mismatch warnings if SSR and client disagree
  2. Layout shift when the effect runs and switches to mobile variant
  3. Brief flash of desktop UI on mobile devices

Consider handling the undefined state explicitly:

 export function AddFeedForm(): React.JSX.Element {
 	const [isOpen, setIsOpen] = useState(false);
 	const isMobile = useIsMobile();
 
+	// Avoid rendering until mobile detection completes
+	if (isMobile === undefined) {
+		return null; // or a loading skeleton
+	}
+
 	return isMobile ? (
 		<AddFeedFormMobile
 			isOpen={isOpen}
 			onOpen={(status: boolean): void => setIsOpen(status)}
 		/>
 	) : (
 		<AddFeedFormDesktop
 			isOpen={isOpen}
 			onOpen={(status: boolean): void => setIsOpen(status)}
 		/>
 	);
 }

Alternatively, use CSS media queries for the initial render to match the client-side detection.

🧹 Nitpick comments (1)
src/app/[locale]/ui/landing/scroll-indicator.tsx (1)

24-34: Double visibility control may be redundant.

The component now has two layers of visibility control:

  1. The Activity component with mode={isMobile ? "hidden" : "visible"} (mobile vs desktop)
  2. The opacity-based transitions with the isVisible state (scroll-based)

If the Activity component's "hidden" mode removes the element from the render tree entirely, the opacity transitions will have no effect on mobile. If it only hides visually, this creates redundant visibility logic.

Please clarify the intended behavior and consider whether both mechanisms are necessary. If Activity "hidden" mode prevents rendering, the opacity classes are unnecessary on mobile.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 648d09c and 4f43759.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (52)
  • biome.json (3 hunks)
  • next.config.ts (1 hunks)
  • package.json (1 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx (1 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx (1 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/newsletters/page.tsx (1 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (1 hunks)
  • src/app/[locale]/(app)/d/(sidebar)/feeds/page.tsx (1 hunks)
  • src/app/[locale]/(app)/error.tsx (1 hunks)
  • src/app/[locale]/(landing)/page.tsx (3 hunks)
  • src/app/[locale]/(userfeeds)/userfeeds/[slug]/content/[feedContentEID]/route.tsx (1 hunks)
  • src/app/[locale]/(userfeeds)/userfeeds/[slug]/route.ts (1 hunks)
  • src/app/[locale]/layout.tsx (3 hunks)
  • src/app/[locale]/legal/privacy/page.tsx (0 hunks)
  • src/app/[locale]/legal/terms/page.tsx (0 hunks)
  • src/app/[locale]/lib/hooks/use-media-query.tsx (0 hunks)
  • src/app/[locale]/login/page.tsx (1 hunks)
  • src/app/[locale]/ui/app-navigation-menu.tsx (1 hunks)
  • src/app/[locale]/ui/auth/login-form.tsx (1 hunks)
  • src/app/[locale]/ui/auth/logout-form.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/add-feed-form.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/feed-context-menu.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/feeds-header-context-menu.tsx (2 hunks)
  • src/app/[locale]/ui/feeds/feeds-header.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/feeds-timeline.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-content.tsx (2 hunks)
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-folder.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-footer.tsx (2 hunks)
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-item-all.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-item.tsx (1 hunks)
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar.tsx (1 hunks)
  • src/app/[locale]/ui/landing/scroll-indicator.tsx (2 hunks)
  • src/app/[locale]/ui/links/add-link-form.tsx (2 hunks)
  • src/app/[locale]/ui/links/links-context-menu.tsx (1 hunks)
  • src/app/[locale]/ui/links/links.tsx (1 hunks)
  • src/app/[locale]/ui/links/search-links.tsx (1 hunks)
  • src/app/[locale]/ui/links/sort-links.tsx (1 hunks)
  • src/app/[locale]/ui/newsletters/add-newsletter-form.tsx (1 hunks)
  • src/app/[locale]/ui/newsletters/newsletter-item.tsx (2 hunks)
  • src/app/[locale]/ui/settings/view/view-section.tsx (2 hunks)
  • src/app/robots.tsx (1 hunks)
  • src/app/sitemap.tsx (1 hunks)
  • src/auth.ts (1 hunks)
  • src/components/ui/navigation-menu.tsx (3 hunks)
  • src/db/schema.ts (1 hunks)
  • src/i18n/request.ts (1 hunks)
  • src/lib/actions.ts (1 hunks)
  • src/lib/dal.ts (1 hunks)
  • src/lib/feed-service.ts (2 hunks)
  • src/lib/stores/search-params-states.ts (1 hunks)
  • src/proxy.ts (3 hunks)
  • tsconfig.json (2 hunks)
💤 Files with no reviewable changes (3)
  • src/app/[locale]/legal/privacy/page.tsx
  • src/app/[locale]/lib/hooks/use-media-query.tsx
  • src/app/[locale]/legal/terms/page.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-09T01:11:03.087Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 253
File: src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-content.tsx:31-39
Timestamp: 2025-08-09T01:11:03.087Z
Learning: In the bocal application, the `getUserFeedsGroupedByFolder()` function returns a `Map<string | null, FeedFolder>` where the key is either a string (representing the folder name) or null (representing uncategorized feeds). When rendering in `FeedsSidebarContent`, checking `if (key)` correctly distinguishes between named folders (truthy string) and uncategorized feeds (falsy null).

Applied to files:

  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-content.tsx
  • src/app/[locale]/ui/feeds/sidebar/feeds-sidebar.tsx
📚 Learning: 2025-04-08T06:37:10.493Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 98
File: src/app/[locale]/(app)/feed/page.tsx:54-54
Timestamp: 2025-04-08T06:37:10.493Z
Learning: React's `cache` function imported from 'react' can be used in Next.js server components without requiring "use client" directive. It's specifically designed to deduplicate data requests in server components.

Applied to files:

  • src/lib/dal.ts
  • src/lib/feed-service.ts
  • next.config.ts
📚 Learning: 2025-04-08T06:37:10.493Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 98
File: src/app/[locale]/(app)/feed/page.tsx:54-54
Timestamp: 2025-04-08T06:37:10.493Z
Learning: React's `cache()` function imported from 'react' is specifically designed for Server Components in Next.js and doesn't require the "use client" directive. It's used to deduplicate data fetching calls within a single request and can only be used in Server Components, not Client Components.

Applied to files:

  • src/lib/dal.ts
  • src/lib/feed-service.ts
  • next.config.ts
🧬 Code graph analysis (17)
src/app/[locale]/ui/auth/logout-form.tsx (1)
src/app/[locale]/lib/actions.ts (1)
  • logout (98-100)
src/app/[locale]/(app)/error.tsx (1)
src/app/[locale]/lib/logging.ts (2)
  • error (5-9)
  • info (15-19)
src/app/[locale]/ui/feeds/feed-context-menu.tsx (1)
src/app/[locale]/lib/actions.ts (1)
  • archiveFeedContent (777-827)
src/lib/actions.ts (1)
src/app/[locale]/lib/actions.ts (1)
  • moveFeedIntoFolder (1055-1111)
src/app/[locale]/ui/landing/scroll-indicator.tsx (2)
src/lib/hooks/use-mobile.ts (1)
  • useIsMobile (5-21)
src/lib/utils.ts (1)
  • cn (4-6)
src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-content.tsx (1)
src/app/[locale]/lib/actions.ts (2)
  • moveFeedIntoFolder (1055-1111)
  • addFeedFolder (974-1048)
src/app/[locale]/ui/settings/view/view-section.tsx (1)
src/app/[locale]/lib/actions.ts (1)
  • setFeedContentLimit (678-724)
src/app/[locale]/(userfeeds)/userfeeds/[slug]/content/[feedContentEID]/route.tsx (1)
src/app/[locale]/lib/feed-service.ts (1)
  • triggerBackgroundSync (257-349)
src/app/[locale]/ui/newsletters/newsletter-item.tsx (2)
src/app/[locale]/ui/newsletters/newsletters.tsx (1)
  • Newsletters (11-31)
src/app/[locale]/lib/actions.ts (1)
  • deleteNewsletter (918-968)
src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-footer.tsx (1)
src/app/[locale]/lib/actions.ts (1)
  • moveFeedIntoFolder (1055-1111)
src/app/[locale]/ui/feeds/add-feed-form.tsx (1)
src/lib/hooks/use-mobile.ts (2)
  • useIsMobile (5-21)
  • setIsMobile (12-14)
src/app/[locale]/ui/newsletters/add-newsletter-form.tsx (1)
src/lib/hooks/use-mobile.ts (2)
  • useIsMobile (5-21)
  • setIsMobile (12-14)
src/app/[locale]/layout.tsx (2)
src/i18n/routing.ts (1)
  • routing (6-11)
src/components/ui/base-layout.tsx (1)
  • BaseLayout (13-36)
src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx (2)
src/app/[locale]/lib/dal.ts (1)
  • Promise (182-288)
src/app/[locale]/lib/actions.ts (1)
  • archiveLink (212-262)
src/app/[locale]/ui/feeds/feeds-timeline.tsx (1)
src/app/[locale]/lib/actions.ts (2)
  • moveFeedIntoFolder (1055-1111)
  • archiveFeedContent (777-827)
src/proxy.ts (1)
src/lib/constants.ts (1)
  • APP_ROUTES (69-78)
src/app/[locale]/ui/links/add-link-form.tsx (1)
src/lib/hooks/use-mobile.ts (1)
  • useIsMobile (5-21)
🔇 Additional comments (63)
src/i18n/request.ts (1)

5-7: Clear documentation for request configuration.

The added comments effectively explain the purpose and scope of getRequestConfig, which improves code maintainability and helps developers understand the request-scoped configuration pattern for internationalization.

src/app/[locale]/ui/landing/scroll-indicator.tsx (1)

3-3: No issues identified. Next.js 16 is available as of October 2025, and the App Router in Next.js 16 uses React 19.2, which includes the Activity component that hides UI with display: none while maintaining state and cleaning up Effects. The Activity component import from React and the mode prop usage in the code are correct.

Likely an incorrect or invalid review comment.

src/app/[locale]/(landing)/page.tsx (1)

22-22: All APP_ROUTES imports have been consistently updated to the new centralized path.

The refactoring to centralize constants in @/lib/constants is complete across the codebase with no remaining old import paths. This change follows Next.js best practices for project organization.

src/components/ui/navigation-menu.tsx (3)

78-78: LGTM: Valid simplification to built-in utility.

The change from top-[1px] to top-px uses Tailwind's built-in utility class instead of arbitrary value syntax. Both produce identical CSS output (top: 1px), but the built-in class is more concise.


115-115: No changes needed — CSS variable syntax is valid in Tailwind CSS v4.

The parenthesized syntax for CSS variables like h-(--property) is documented and supported in Tailwind CSS v4 as shorthand notation. The syntax change from h-[var(--radix-navigation-menu-viewport-height)] to h-(--radix-navigation-menu-viewport-height) is valid and aligns with Tailwind CSS v4.0's CSS-first approach. The viewport will maintain its dynamic height and width correctly.


148-148: The z-1 utility class is valid in Tailwind CSS v4.

The change from z-[1] to z-1 is correct for this project. In Tailwind v4, any z-index is allowed and generated despite not being in a predefined scale, unlike Tailwind v3 where only predefined values (z-0, z-10, z-20, z-30, z-40, z-50) were available. Since this project uses @tailwindcss/postcss version 4.1.18, the z-1 class will generate a valid z-index: 1 CSS rule without issues.

Likely an incorrect or invalid review comment.

tsconfig.json (1)

14-14: LGTM! Modern JSX transform and enhanced type coverage.

The JSX runtime change to "react-jsx" uses the modern automatic JSX transform, which is appropriate for React 19. Adding .next/dev/types/**/*.ts to the include array ensures TypeScript picks up Next.js development-mode generated types.

Also applies to: 25-31

src/lib/stores/search-params-states.ts (1)

2-2: LGTM! Centralized import path.

The import path for SortOptions has been correctly updated to reference the centralized constants module, consistent with the broader refactor in this PR.

src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-item-all.tsx (1)

11-11: LGTM! Centralized import path.

The import path for searchParamsState has been correctly updated to reference the centralized stores module.

src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-item.tsx (1)

13-15: LGTM! Centralized imports and mobile detection hook.

The import paths have been correctly updated to reference centralized modules, and the useIsMobile hook is appropriately used for mobile detection logic (Line 78).

src/app/[locale]/ui/feeds/feeds-header.tsx (1)

8-8: LGTM! Centralized import path.

The import path for FeedStatusType and FeedWithContentsCount has been correctly updated to reference the centralized constants module.

src/app/[locale]/ui/feeds/feeds-header-context-menu.tsx (2)

14-17: LGTM! Centralized imports.

All import paths have been correctly updated to reference centralized modules, consistent with the broader refactor in this PR.


76-76: Good practice: Explicit radix in parseInt.

Adding the explicit radix 10 to parseInt ensures consistent decimal parsing and avoids potential issues with strings that might be interpreted as octal.

src/app/[locale]/ui/feeds/add-feed-form.tsx (1)

24-25: LGTM! Centralized imports.

Import paths have been correctly updated to reference centralized modules.

src/app/robots.tsx (1)

2-2: Import path verified successfully.

The getAppBaseURL function is correctly exported from the centralized location at src/lib/get-app-base-url.ts.

biome.json (2)

2-2: LGTM: Schema version aligned with package update.

The schema URL update to 2.3.9 correctly matches the Biome package version bump in package.json.


39-39: No action required. The useUniqueElementIds rule is part of Biome's correctness group and remains active. It is configured via the correctness domain, not the nursery, so its absence from nursery rules in biome.json is expected behavior, not a removal requiring verification.

src/app/[locale]/ui/settings/view/view-section.tsx (2)

15-16: LGTM: Import paths centralized.

The import paths have been correctly updated to use centralized library locations, aligning with the project-wide refactoring effort.


58-60: LGTM: Explicit radix prevents potential parsing ambiguities.

Adding the radix parameter (10) to Number.parseInt is a best practice that ensures consistent decimal parsing and prevents potential issues with strings that could be misinterpreted as octal or hexadecimal.

src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-folder.tsx (1)

25-31: LGTM: Import paths centralized.

The import paths have been correctly updated to reference centralized library locations, maintaining consistency with the project-wide refactoring effort.

package.json (2)

101-102: LGTM: Package manager version pinning improves reproducibility.

Adding the packageManager field with a specific pnpm version ensures consistent behavior across different development environments and CI/CD pipelines.


6-6: No action needed. Starting with Next.js 16, Turbopack is stable and used by default with next dev and next build, so the --turbopack flag is no longer necessary and can be removed from your package.json scripts. The dev script change correctly reflects this default behavior.

src/db/schema.ts (1)

23-23: LGTM: Import path centralized.

The import path has been correctly updated to reference the centralized constants location, consistent with the project-wide refactoring effort.

src/app/[locale]/ui/auth/logout-form.tsx (1)

6-6: LGTM: Import path centralized.

The import path has been correctly updated to use the centralized library location with an absolute import alias, improving maintainability.

src/app/[locale]/(userfeeds)/userfeeds/[slug]/route.ts (1)

2-2: LGTM: Import path centralized.

The import path has been correctly updated to reference the centralized feed service location, maintaining consistency with the project-wide refactoring effort.

next.config.ts (1)

16-28: All configuration options are valid for Next.js 16.

reactCompiler: true is now stable (promoted from experimental). cacheComponents: true enables Cache Components functionality. experimental.turbopackFileSystemCacheForDev is enabled by default starting with Next.js 16. The removal of experimental.ppr reflects Next.js 16's deprecation of the PPR flag in favor of Cache Components. The clientSegmentCache and devtoolSegmentExplorer were experimental canary features in Next.js 15.x and are not part of the stable Next.js 16 configuration.

src/app/[locale]/(userfeeds)/userfeeds/[slug]/content/[feedContentEID]/route.tsx (1)

2-3: LGTM! Import paths correctly centralized.

The refactor from locale-scoped to centralized library paths improves code organization and maintainability.

src/app/[locale]/ui/app-navigation-menu.tsx (1)

25-25: LGTM! Consistent with centralization refactor.

The APP_ROUTES import path update aligns with the broader refactoring effort to centralize shared constants.

src/app/[locale]/ui/links/sort-links.tsx (1)

25-26: LGTM! Import paths correctly updated.

The centralized import paths for SortOptions and searchParamsState are consistent with the refactoring pattern.

src/app/[locale]/ui/feeds/feeds-timeline.tsx (1)

12-16: LGTM! Import consolidation complete.

All action and utility imports have been correctly updated to centralized library paths. The optimistic UI logic remains intact.

src/app/[locale]/ui/feeds/feed-context-menu.tsx (1)

15-15: LGTM! Import path correctly updated.

The archiveFeedContent import has been properly centralized, consistent with the refactoring pattern.

src/app/[locale]/ui/links/search-links.tsx (1)

10-10: LGTM! Import path correctly updated.

The searchParamsState import has been properly centralized, maintaining consistency with the refactoring effort.

src/app/[locale]/(app)/error.tsx (1)

6-6: LGTM! Import path correctly updated.

The logger import has been properly centralized. The error logging functionality remains unchanged.

src/lib/actions.ts (1)

30-39: LGTM! Comprehensive import consolidation for server actions.

All utility imports have been correctly updated to use centralized library paths. Verification confirms no residual references to old locale-scoped paths remain in the codebase, and the new import pattern is consistently applied across the application.

src/app/[locale]/ui/links/links.tsx (1)

16-18: LGTM—Import centralization.

The migration from locale-scoped paths to centralized library imports is clean and consistent with the broader refactoring across the PR.

src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-footer.tsx (2)

36-37: LGTM—Import centralization.

The migration to centralized library paths is consistent with the PR-wide refactoring pattern.


160-160: The h-4.5 class works correctly in Tailwind CSS v4 without requiring custom configuration. Tailwind v4 allows spacing utilities to accept any value out of the box, dynamically derived from a single spacing scale variable, so h-4.5 resolves to calc(0.25rem * 4.5) = 1.125rem (18px) by default. No extension to the @theme block is needed.

src/lib/dal.ts (1)

17-25: LGTM—Import centralization and auth import addition.

The migration to centralized library paths and the addition of the auth import are clean. The cache() usage from React (line 16) is appropriate for Server Components, as confirmed by learnings.

Based on learnings, React's cache() is specifically designed for Server Components and doesn't require the "use client" directive.

src/app/[locale]/login/page.tsx (2)

2-2: LGTM—Import path update.

The migration to an absolute alias path is consistent with the broader refactoring.


1-12: This removal is correct for Next.js 16.

In Next.js 16, the experimental experimental.ppr flag and configuration options have been removed in favor of the Cache Components configuration. The login page appropriately does not include the experimental_ppr export since Partial Prerendering is the default behavior with Cache Components when enabled via the cacheComponents option in next.config.ts. This is not a regression but rather the evolution of PPR from experimental to stable in Next.js 16.

src/app/[locale]/ui/links/links-context-menu.tsx (1)

16-17: LGTM—Import centralization.

The migration to centralized library imports is consistent and straightforward.

src/app/[locale]/(app)/d/(sidebar)/feeds/page.tsx (1)

14-14: LGTM—Import centralization.

The migration of the dal import to a centralized path is consistent with the broader refactoring.

src/app/[locale]/ui/auth/login-form.tsx (1)

7-9: LGTM—Import path updates.

The migration of authenticate to the centralized library while keeping SPACING in the locale-scoped UI path is appropriate, as UI utilities remain localized while cross-cutting actions are centralized.

src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx (1)

15-15: LGTM—Import centralization.

The migration of the dal import to a centralized path is consistent with the refactoring pattern throughout the PR.

src/auth.ts (1)

6-7: LGTM! Import path centralization.

The import paths for constants and logging have been updated to use centralized root paths. This aligns with the broader refactor pattern across the codebase.

src/app/[locale]/(app)/d/(no-sidebar)/newsletters/page.tsx (1)

10-10: LGTM! Consistent import path centralization.

The dal import follows the same centralization pattern applied across the codebase.

src/app/[locale]/ui/feeds/sidebar/feeds-sidebar.tsx (1)

7-7: LGTM! Import centralization.

The dal import path has been updated to the centralized location.

src/lib/feed-service.ts (2)

9-11: LGTM! Import path centralization.

The imports for constants, logging, and parsing utilities have been moved to centralized root paths, consistent with the broader refactor.


174-182: Good refactor: mapforEach for side effects.

The change from map to forEach is more semantically correct since the operation mutates the atom object via side effects rather than building a new array. The original map created an unused array, making forEach the more appropriate choice here.

src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (1)

9-10: LGTM! Import centralization.

The imports for APP_ROUTES and dal have been updated to use centralized root paths.

src/app/[locale]/ui/newsletters/add-newsletter-form.tsx (2)

24-26: LGTM! Centralized imports and new mobile detection hook.

The imports have been updated to use centralized paths, and the new useIsMobile hook provides a cleaner abstraction for mobile detection.


31-43: Good improvement: More intuitive conditional logic.

The conditional isMobile ? Mobile : Desktop is more intuitive than previous patterns. The useIsMobile hook uses window.matchMedia for efficiency and automatically updates when the screen size changes, providing cleaner mobile detection across the application.

src/app/[locale]/ui/newsletters/newsletter-item.tsx (2)

30-31: LGTM! Import centralization.

The imports for deleteNewsletter and userfeedsfuncs have been updated to centralized paths.


48-48: LGTM! Minor formatting cleanup.

The className has been collapsed to a single line without any semantic changes.

src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx (2)

14-14: Centralized import path verified and working correctly.

The dal import from @/lib/dal resolves properly to the module at src/lib/dal.ts. The import is actively used in the file and no old locale-scoped imports remain in the codebase.


14-66: PPR has been intentionally disabled project-wide.

The removal of experimental_ppr from this page is part of a comprehensive decision to not use Partial Prerendering. Since no ppr: 'incremental' configuration exists in next.config.ts and no pages export experimental_ppr, the feature is completely disabled. The Suspense boundaries in this route will continue to work for streaming, just without PPR prerendering.

src/app/[locale]/ui/feeds/sidebar/feeds-sidebar-content.tsx (2)

18-23: LGTM! Import path centralization.

The import paths have been successfully updated to use centralized lib locations. This aligns with the PR's objective to consolidate module structure.


77-77: Type error with RestrictToVerticalAxis modifier is legitimate. The change from @ts-ignore to @ts-expect-error is the appropriate best practice approach. This TypeScript type incompatibility with @dnd-kit/abstract 0.1.21 and @dnd-kit/react 0.1.21 is a known issue where RestrictToVerticalAxis in DragDropProvider's modifiers prop results in a type mismatch error. Using @ts-expect-error correctly signals that this is an expected type error from the library that may be resolved in future versions.

src/app/[locale]/layout.tsx (1)

42-44: LGTM! Correct implementation of generateStaticParams.

The generateStaticParams function correctly generates static params for all locales defined in the routing configuration.

src/app/sitemap.tsx (1)

3-4: LGTM! Import path centralization.

The import paths have been correctly updated to use centralized lib locations, maintaining the same functionality.

src/app/[locale]/ui/links/add-link-form.tsx (2)

6-6: LGTM! Import path centralization and hook replacement.

The import paths have been correctly updated to centralized lib locations, and the replacement of useMediaQuery with the more semantic useIsMobile hook improves code readability.

Also applies to: 26-27


30-45: LGTM! Mobile detection logic correctly updated.

The conditional rendering logic has been correctly updated to use the new useIsMobile hook. The logic now renders the mobile form when isMobile is true, which maintains the intended behavior.

src/proxy.ts (1)

41-59: File naming and function naming follow the current Next.js convention.

Starting with Next.js 16, Middleware is now called Proxy to better reflect its purpose, with the functionality remaining the same. The renaming from middleware.ts to proxy.ts and the function from middleware to proxy (line 41) aligns with the current Next.js file convention. The proxy.ts file should be located at the same level as pages or app. No special middleware configuration in Next.js config files is required—the proxy function is automatically recognized when properly placed and exported.

@mtlaso mtlaso self-assigned this Dec 17, 2025
@github-actions
Copy link

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34d04ba and b7d45a5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/app/[locale]/layout.tsx (3 hunks)
  • src/lib/actions.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/actions.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/[locale]/layout.tsx (2)
src/i18n/routing.ts (1)
  • routing (6-11)
src/components/ui/base-layout.tsx (1)
  • BaseLayout (13-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Create Neon Branch
🔇 Additional comments (7)
src/app/[locale]/layout.tsx (2)

6-9: LGTM!

Import changes align with the PR objectives: Suspense added for the new rendering pattern, and getAppBaseURL moved to the centralized @/lib path consistent with other files in this refactor.


42-44: LGTM!

Standard Next.js pattern for static parameter generation. This correctly derives locale params from routing.locales to enable static generation for both "en" and "fr" locales.

package.json (5)

99-99: Good addition: Enforces consistent package manager version.

The packageManager field ensures all contributors use the same pnpm version (10.25.0) via Corepack. This prevents "works on my machine" issues caused by package manager version differences and is a best practice for monorepos and collaborative projects.


51-59: All Next.js 16 and React 19.2 migrations have been successfully completed. Verification confirms:

  • No synchronous dynamic API calls found (cookies, headers, draftMode properly use await)
  • Middleware properly renamed to proxy.ts
  • No deprecated React forwardRef usage found

No further action needed.


14-67: Test authentication flows thoroughly with next-auth beta update.

next-auth v5 is a major rewrite, though with as few breaking changes as possible. The dependency update to 5.0.0-beta.30 involves significant API changes from v4, including import restructuring and OAuth 1.0 support deprecation and a minimum Next.js version requirement of 14.0. While most other dependency updates (Radix UI patches, Drizzle ORM, next-intl) are conservative and compatible, verify the next-auth migration guide and test all authentication flows after the upgrade, particularly session management and OAuth provider integrations.


72-73: The codebase is already using Tailwind CSS v4 syntax. The globals.css file demonstrates proper v4 CSS-first configuration with @import 'tailwindcss', @plugin directives, and @theme definitions. Code inspection found no v3 breaking patterns (old important modifiers, removed opacity utilities, or old CSS variable syntax), and CSS variables are correctly using the v4 parentheses syntax throughout. No migration action is needed.

Likely an incorrect or invalid review comment.


6-6: Turbopack is now the default bundler in Next.js 16.

The removal of the --turbo flag is expected and correct. Turbopack is now the default bundler in Next.js and no configuration is needed to use it. Development will automatically use Turbopack. The optional filesystem cache configuration in your next.config.ts will continue to work as expected.

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7d45a5 and c0d0f35.

📒 Files selected for processing (1)
  • src/lib/actions.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 297
File: src/app/[locale]/layout.tsx:61-65
Timestamp: 2025-12-17T07:26:49.098Z
Learning: In Next.js 16 with cacheComponents: true enabled, next-intl requires wrapping components that access request-scoped data (like locale from params or call setRequestLocale) in Suspense boundaries. This includes wrapping BaseLayout in Suspense in the root layout at src/app/[locale]/layout.tsx when using next-intl with cacheComponents, even though it renders the root <html> and <body> structure.
🔇 Additional comments (1)
src/lib/actions.ts (1)

29-38: LGTM! Import path centralization.

The refactor from locale-scoped paths (@/app/[locale]/lib/*) to centralized top-level paths (@/lib/*) improves code organization and aligns with the PR's objective to consolidate module locations.

@mtlaso
Copy link
Owner Author

mtlaso commented Dec 19, 2025

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/app/[locale]/(landing)/page.tsx (1)

163-163: Replace wrap-break-word with break-words.

As noted in the previous review, wrap-break-word is not a standard Tailwind utility. Use break-words instead:

-				"hover:shadow-md transition-all duration-200 wrap-break-word",
+				"hover:shadow-md transition-all duration-200 break-words",
🧹 Nitpick comments (1)
src/app/[locale]/(landing)/page.tsx (1)

121-145: Consider refactoring async sections to proper React components.

The current pattern works but is unconventional: async functions return Promises that are rendered directly in JSX. A more idiomatic Next.js 15+/React 19 pattern would be to define these as async component functions and render them as JSX elements:

🔎 Proposed refactor to async components
-const HeroSection = async (locale: Locale): Promise<React.JSX.Element> => {
+async function HeroSection({ locale }: { locale: Locale }): Promise<React.JSX.Element> {
 	const t = await getTranslations({ locale, namespace: "metadata" });
 	return (
 		// ... existing JSX
 	);
-};
+}

Then update the elements array:

 const elements: {
-	el: () => Promise<React.JSX.Element> | React.JSX.Element;
+	el: React.JSX.Element | Promise<React.JSX.Element>;
 	index: number;
 }[] = [
 	{
-		el: () => HeroSection(locale as Locale),
+		el: <HeroSection locale={locale as Locale} />,
 		index: 0,
 	},
 	// ... similar for other sections
 ];

And rendering:

 {elements.map((el) => (
 	<BlurFade key={el.index} delay={0.25 + el.index * 0.05}>
-		{el.el()}
+		{el.el}
 	</BlurFade>
 ))}

Also applies to: 147-199, 201-222

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0d0f35 and 4182387.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • messages/en.json (1 hunks)
  • package.json (1 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx (3 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx (3 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/newsletters/page.tsx (2 hunks)
  • src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (3 hunks)
  • src/app/[locale]/(app)/d/(sidebar)/feeds/page.tsx (3 hunks)
  • src/app/[locale]/(landing)/page.tsx (6 hunks)
  • src/app/[locale]/layout.tsx (2 hunks)
  • src/app/[locale]/legal/privacy/page.tsx (2 hunks)
  • src/app/[locale]/legal/terms/page.tsx (2 hunks)
  • src/app/[locale]/login/page.tsx (1 hunks)
  • src/app/[locale]/ui/settings/settings.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • messages/en.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/app/[locale]/(app)/d/(sidebar)/feeds/page.tsx
  • src/app/[locale]/(app)/d/(no-sidebar)/newsletters/page.tsx
  • src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx
  • src/app/[locale]/legal/privacy/page.tsx
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 297
File: src/app/[locale]/layout.tsx:61-65
Timestamp: 2025-12-17T07:26:49.098Z
Learning: In Next.js 16 with cacheComponents: true enabled, next-intl requires wrapping components that access request-scoped data (like locale from params or call setRequestLocale) in Suspense boundaries. This includes wrapping BaseLayout in Suspense in the root layout at src/app/[locale]/layout.tsx when using next-intl with cacheComponents, even though it renders the root <html> and <body> structure.
📚 Learning: 2025-12-17T07:26:49.098Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 297
File: src/app/[locale]/layout.tsx:61-65
Timestamp: 2025-12-17T07:26:49.098Z
Learning: In Next.js 16 with cacheComponents: true enabled, next-intl requires wrapping components that access request-scoped data (like locale from params or call setRequestLocale) in Suspense boundaries. This includes wrapping BaseLayout in Suspense in the root layout at src/app/[locale]/layout.tsx when using next-intl with cacheComponents, even though it renders the root <html> and <body> structure.

Applied to files:

  • src/app/[locale]/ui/settings/settings.tsx
  • src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx
  • src/app/[locale]/login/page.tsx
  • src/app/[locale]/legal/terms/page.tsx
  • src/app/[locale]/(landing)/page.tsx
  • src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx
  • package.json
  • src/app/[locale]/layout.tsx
📚 Learning: 2025-04-08T06:37:10.493Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 98
File: src/app/[locale]/(app)/feed/page.tsx:54-54
Timestamp: 2025-04-08T06:37:10.493Z
Learning: React's `cache` function imported from 'react' can be used in Next.js server components without requiring "use client" directive. It's specifically designed to deduplicate data requests in server components.

Applied to files:

  • src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx
  • src/app/[locale]/layout.tsx
📚 Learning: 2025-04-08T06:37:10.493Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 98
File: src/app/[locale]/(app)/feed/page.tsx:54-54
Timestamp: 2025-04-08T06:37:10.493Z
Learning: React's `cache()` function imported from 'react' is specifically designed for Server Components in Next.js and doesn't require the "use client" directive. It's used to deduplicate data fetching calls within a single request and can only be used in Server Components, not Client Components.

Applied to files:

  • src/app/[locale]/layout.tsx
🧬 Code graph analysis (7)
src/app/[locale]/ui/settings/settings.tsx (3)
src/auth.ts (2)
  • session (45-60)
  • Session (25-30)
src/lib/constants.ts (1)
  • APP_ROUTES (69-78)
src/app/[locale]/ui/settings/view/view-section.tsx (1)
  • ViewSection (23-40)
src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (4)
src/app/[locale]/login/page.tsx (1)
  • Page (6-18)
src/i18n/routing.ts (1)
  • Locale (4-4)
src/lib/dal.ts (1)
  • dal (330-337)
src/app/[locale]/ui/settings/settings.tsx (1)
  • Settings (18-34)
src/app/[locale]/login/page.tsx (6)
src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx (1)
  • Page (33-64)
src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx (1)
  • Page (34-66)
src/app/[locale]/(app)/d/(no-sidebar)/newsletters/page.tsx (1)
  • Page (28-54)
src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (1)
  • Page (27-48)
src/app/[locale]/(app)/d/(sidebar)/feeds/page.tsx (1)
  • Page (33-62)
src/i18n/routing.ts (1)
  • Locale (4-4)
src/app/[locale]/legal/terms/page.tsx (1)
src/i18n/routing.ts (1)
  • Locale (4-4)
src/app/[locale]/(landing)/page.tsx (2)
src/i18n/routing.ts (1)
  • Locale (4-4)
src/components/ui/navigation-menu.tsx (1)
  • NavigationMenu (159-159)
src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx (4)
src/app/[locale]/(app)/d/(no-sidebar)/archive/page.tsx (1)
  • Page (33-64)
src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (1)
  • Page (27-48)
src/app/[locale]/login/page.tsx (1)
  • Page (6-18)
src/i18n/routing.ts (1)
  • Locale (4-4)
src/app/[locale]/layout.tsx (2)
src/i18n/routing.ts (1)
  • routing (6-11)
src/app/layout.tsx (1)
  • RootLayout (3-9)
🔇 Additional comments (14)
package.json (2)

6-6: Verify removal of --turbopack flag is intentional.

The --turbopack flag was removed from the dev script. Next.js 15+ supports stable Turbopack development mode, which typically offers faster refresh times. Was this removal intentional, or should Turbopack remain enabled for development?


99-99: LGTM! Package manager version pinning added.

The packageManager field correctly pins pnpm to version 10.25.0 with integrity hash. This ensures consistent package manager behavior across all environments and contributors.

src/app/[locale]/login/page.tsx (1)

1-10: LGTM! Locale handling follows the established Next.js 16 pattern.

The implementation correctly:

  • Extracts locale from async params using React's use hook
  • Calls setRequestLocale to configure server-side translations
  • Uses the consistent PageProps type pattern seen across other pages in this PR
src/app/[locale]/ui/settings/settings.tsx (2)

14-22: Clean Promise-based session handling with React 19's use hook.

The refactor correctly:

  • Accepts a Promise<Session | null> prop for streamed session data
  • Resolves it with use(sess) which works in Server Components
  • Redirects to login when session is missing

This pattern aligns well with the parent component passing dal.verifySession() (as seen in src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx).


25-29: Safe null-coalescing for user properties.

The fallback to empty strings (?? "") handles cases where name or email might be undefined on the session user object.

src/app/[locale]/(app)/d/(no-sidebar)/links/page.tsx (2)

34-38: Locale handling follows the established Next.js 16 pattern.

Consistent with other pages: extracts locale via use(params) and configures server-side translations with setRequestLocale.


15-15: Good refactor: Centralized dal import path.

Moving from @/app/[locale]/lib/dal to @/lib/dal aligns with the PR's goal of centralizing imports.

src/app/[locale]/legal/terms/page.tsx (1)

23-28: Correct async pattern with await params.

This async Server Component correctly uses await params (vs. use(params) in sync components) and properly initializes the locale with setRequestLocale before the dynamic MDX import.

src/app/[locale]/layout.tsx (3)

41-43: Essential addition: generateStaticParams for static locale routes.

This function enables Next.js to statically generate pages for each locale (["en", "fr"] from routing.locales), which is important for Next.js 16's static generation behavior.


45-55: Layout correctly implements Next.js 16 locale handling.

The implementation:

  • Uses LayoutProps type consistent with other files
  • Validates locale against allowed values before proceeding
  • Calls setRequestLocale for server-side i18n setup

Based on learnings, the Suspense boundary requirement for cacheComponents: true is handled appropriately in the component hierarchy.


8-8: Consistent import centralization.

Moving getAppBaseURL to @/lib/get-app-base-url aligns with the broader PR effort to centralize utility imports.

src/app/[locale]/(app)/d/(no-sidebar)/settings/page.tsx (1)

27-44: LGTM! Correct Next.js 16 + next-intl integration pattern.

The implementation correctly follows Next.js 16 patterns:

  • Locale extracted via use(params) and initialized with setRequestLocale
  • dal.verifySession() returns a Promise passed to Settings
  • Settings is wrapped in Suspense, where it uses use(sess) to unwrap the Promise
  • Import path centralized to @/lib/dal

Based on learnings, this pattern aligns with Next.js 16 requirements for request-scoped data access.

src/app/[locale]/(landing)/page.tsx (2)

27-50: LGTM! Correct Next.js 16 locale integration.

The implementation correctly:

  • Extracts locale via use(params) and initializes with setRequestLocale
  • Passes locale to async section functions
  • Handles both sync and async element rendering

Based on learnings, this pattern aligns with Next.js 16 requirements.


55-55: Good catch on the typo fix!

Correcting justif-around to justify-around fixes the flexbox layout.

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
package.json (3)

52-52: Verify next-auth@5.0.0-beta.29 compatibility with Next.js 16.1.0.

A previous review flagged next-auth@5.0.0-beta.30 as having peer dependency issues with Next.js 16. The current version (beta.29) may be pinned to avoid those issues, but verify that:

  1. beta.29 has no peer dependency conflicts with Next.js 16.1.0
  2. Authentication flows (login/logout/session) work correctly with React 19.2.0
  3. Consider upgrading to a stable next-auth v5 release once available
#!/bin/bash
# Check for newer next-auth versions and peer dependency requirements
echo "=== Checking next-auth peer dependencies ==="
npm info next-auth@5.0.0-beta.29 peerDependencies 2>/dev/null || echo "Failed to fetch peer dependencies"

echo ""
echo "=== Checking for latest next-auth v5 versions ==="
npm view next-auth versions --json 2>/dev/null | jq '.[] | select(startswith("5."))' | tail -5 || echo "Failed to fetch versions"

51-51: Verify Next.js 16.1.0 breaking changes have been addressed.

The upgrade to Next.js 16.1.0 includes several breaking changes. While the AI summary indicates some migrations were completed (proxy middleware rename), verify that all async API changes have been applied throughout the codebase:

  • params, searchParams now require await
  • cookies(), headers(), draftMode() now return Promises
  • Route handler caching defaults changed
  • Variant order now reads left → right
#!/bin/bash
# Search for potentially un-migrated synchronous usage of async APIs
echo "=== Checking for synchronous usage of async Next.js 16 APIs ==="

# Check for direct property access on params/searchParams without await
rg -n "params\.[a-zA-Z]|searchParams\.[a-zA-Z]" --type ts --type tsx -g '!*.test.*' -g '!*.spec.*' 2>/dev/null || true

echo ""
echo "=== Checking for cookies/headers/draftMode without await ==="
rg -n "cookies\(\)|headers\(\)|draftMode\(\)" --type ts --type tsx -A2 -g '!*.test.*' 2>/dev/null | rg -v "await|useActionState" || true

58-59: Critical: Upgrade React to 19.2.1 for security patches.

React 19.2.0 has known critical security vulnerabilities (CVSS 10.0) in the React Server Components protocol. React 19.2.1 addresses these issues and was released in December 2025.

🔎 Apply security update
-		"react": "19.2.0",
-		"react-dom": "19.2.0",
+		"react": "19.2.1",
+		"react-dom": "19.2.1",
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4182387 and ed7783c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • package.json (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 297
File: src/app/[locale]/layout.tsx:61-65
Timestamp: 2025-12-17T07:26:49.098Z
Learning: In Next.js 16 with cacheComponents: true enabled, next-intl requires wrapping components that access request-scoped data (like locale from params or call setRequestLocale) in Suspense boundaries. This includes wrapping BaseLayout in Suspense in the root layout at src/app/[locale]/layout.tsx when using next-intl with cacheComponents, even though it renders the root <html> and <body> structure.
📚 Learning: 2025-12-17T07:26:49.098Z
Learnt from: mtlaso
Repo: mtlaso/bocal PR: 297
File: src/app/[locale]/layout.tsx:61-65
Timestamp: 2025-12-17T07:26:49.098Z
Learning: In Next.js 16 with cacheComponents: true enabled, next-intl requires wrapping components that access request-scoped data (like locale from params or call setRequestLocale) in Suspense boundaries. This includes wrapping BaseLayout in Suspense in the root layout at src/app/[locale]/layout.tsx when using next-intl with cacheComponents, even though it renders the root <html> and <body> structure.

Applied to files:

  • package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Create Neon Branch
🔇 Additional comments (2)
package.json (2)

84-99: Good: Package manager and overrides configured correctly.

The explicit packageManager field and pnpm overrides are well-configured for project consistency. Note that @types/react and @types/react-dom overrides (19.2.2) are slightly ahead of the runtime versions (19.2.0). Once React is upgraded to 19.2.1 per the security fix, verify type compatibility remains sound.


6-6: No concerns with the dev script change. Turbopack is now the default bundler in Next.js, so removing the flag in Next.js 16.1.0 is the correct approach.

@github-actions
Copy link

@github-actions
Copy link

Neon logo Neon Schema Diff summary

Schema diff between the compare branch (preview/pr-297-next16-update) and the base branch (main).

Index: neondb-schema.sql
===================================================================
--- neondb-schema.sql	Branch main
+++ neondb-schema.sql	Branch preview/pr-297-next16-update
@@ -130,18 +130,21 @@
 --
 
 CREATE TABLE public.accounts (
     "userId" text NOT NULL,
-    type text NOT NULL,
-    provider text NOT NULL,
-    "providerAccountId" text NOT NULL,
-    refresh_token text,
-    access_token text,
-    expires_at integer,
-    token_type text,
+    "providerId" text NOT NULL,
+    "refreshToken" text,
+    "accessToken" text,
+    "expiresAt" integer,
+    "idToken" text,
     scope text,
-    id_token text,
-    session_state text
+    "accountId" text,
+    "accessTokenExpiresAt" timestamp without time zone,
+    "refreshTokenExpiresAt" timestamp without time zone,
+    password text,
+    created_at timestamp without time zone DEFAULT now() NOT NULL,
+    updated_at timestamp without time zone DEFAULT now() NOT NULL,
+    id text NOT NULL
 );
 
 
 ALTER TABLE public.accounts OWNER TO neondb_owner;
@@ -266,11 +269,16 @@
 -- Name: sessions; Type: TABLE; Schema: public; Owner: neondb_owner
 --
 
 CREATE TABLE public.sessions (
-    "sessionToken" text NOT NULL,
+    token text NOT NULL,
     "userId" text NOT NULL,
-    expires timestamp without time zone NOT NULL
+    expires_at timestamp without time zone NOT NULL,
+    ip_address text,
+    user_agent text,
+    created_at timestamp without time zone DEFAULT now() NOT NULL,
+    updated_at timestamp without time zone DEFAULT now() NOT NULL,
+    id text NOT NULL
 );
 
 
 ALTER TABLE public.sessions OWNER TO neondb_owner;
@@ -280,12 +288,14 @@
 --
 
 CREATE TABLE public.users (
     id text NOT NULL,
-    name text,
+    name text NOT NULL,
     email text,
-    "emailVerified" timestamp without time zone,
-    image text
+    "emailVerified" boolean NOT NULL,
+    image text,
+    created_at timestamp without time zone DEFAULT now() NOT NULL,
+    updated_at timestamp without time zone DEFAULT now() NOT NULL
 );
 
 
 ALTER TABLE public.users OWNER TO neondb_owner;
@@ -357,19 +367,22 @@
 
 ALTER TABLE public.users_preferences OWNER TO neondb_owner;
 
 --
--- Name: verification_tokens; Type: TABLE; Schema: public; Owner: neondb_owner
+-- Name: verifications; Type: TABLE; Schema: public; Owner: neondb_owner
 --
 
-CREATE TABLE public.verification_tokens (
+CREATE TABLE public.verifications (
     identifier text NOT NULL,
-    token text NOT NULL,
-    expires timestamp without time zone NOT NULL
+    value text NOT NULL,
+    "expiresAt" timestamp without time zone NOT NULL,
+    id text NOT NULL,
+    created_at timestamp without time zone DEFAULT now() NOT NULL,
+    updated_at timestamp without time zone DEFAULT now() NOT NULL
 );
 
 
-ALTER TABLE public.verification_tokens OWNER TO neondb_owner;
+ALTER TABLE public.verifications OWNER TO neondb_owner;
 
 --
 -- Name: __drizzle_migrations id; Type: DEFAULT; Schema: drizzle; Owner: neondb_owner
 --
@@ -393,13 +406,13 @@
     ADD CONSTRAINT users_sync_pkey PRIMARY KEY (id);
 
 
 --
--- Name: accounts accounts_provider_providerAccountId_pk; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
+-- Name: accounts accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
 --
 
 ALTER TABLE ONLY public.accounts
-    ADD CONSTRAINT "accounts_provider_providerAccountId_pk" PRIMARY KEY (provider, "providerAccountId");
+    ADD CONSTRAINT accounts_pkey PRIMARY KEY (id);
 
 
 --
 -- Name: authenticators authenticators_credentialID_unique; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
@@ -453,12 +466,20 @@
 -- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
 --
 
 ALTER TABLE ONLY public.sessions
-    ADD CONSTRAINT sessions_pkey PRIMARY KEY ("sessionToken");
+    ADD CONSTRAINT sessions_pkey PRIMARY KEY (id);
 
 
 --
+-- Name: sessions sessions_token_unique; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
+--
+
+ALTER TABLE ONLY public.sessions
+    ADD CONSTRAINT sessions_token_unique UNIQUE (token);
+
+
+--
 -- Name: users users_email_unique; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
 --
 
 ALTER TABLE ONLY public.users
@@ -489,8 +510,16 @@
     ADD CONSTRAINT "users_feeds_userId_feedId_pk" PRIMARY KEY ("userId", "feedId");
 
 
 --
+-- Name: users users_name_unique; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
+--
+
+ALTER TABLE ONLY public.users
+    ADD CONSTRAINT users_name_unique UNIQUE (name);
+
+
+--
 -- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
 --
 
 ALTER TABLE ONLY public.users
@@ -505,13 +534,13 @@
     ADD CONSTRAINT users_preferences_pkey PRIMARY KEY ("userId");
 
 
 --
--- Name: verification_tokens verification_tokens_identifier_token_pk; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
+-- Name: verifications verification_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: neondb_owner
 --
 
-ALTER TABLE ONLY public.verification_tokens
-    ADD CONSTRAINT verification_tokens_identifier_token_pk PRIMARY KEY (identifier, token);
+ALTER TABLE ONLY public.verifications
+    ADD CONSTRAINT verification_tokens_pkey PRIMARY KEY (id);
 
 
 --
 -- Name: users_sync_deleted_at_idx; Type: INDEX; Schema: neon_auth; Owner: neondb_owner
@@ -520,8 +549,15 @@
 CREATE INDEX users_sync_deleted_at_idx ON neon_auth.users_sync USING btree (deleted_at);
 
 
 --
+-- Name: accounts_userId_idx; Type: INDEX; Schema: public; Owner: neondb_owner
+--
+
+CREATE INDEX "accounts_userId_idx" ON public.accounts USING btree ("userId");
+
+
+--
 -- Name: feeds_content_eid_index; Type: INDEX; Schema: public; Owner: neondb_owner
 --
 
 CREATE UNIQUE INDEX feeds_content_eid_index ON public.feeds_content USING btree (eid);
@@ -555,8 +591,15 @@
 CREATE UNIQUE INDEX "users_feeds_folders_userId_name_index" ON public.users_feeds_folders USING btree ("userId", name);
 
 
 --
+-- Name: verification_identifier_idx; Type: INDEX; Schema: public; Owner: neondb_owner
+--
+
+CREATE INDEX verification_identifier_idx ON public.verifications USING btree (identifier);
+
+
+--
 -- Name: accounts accounts_userId_users_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: neondb_owner
 --
 
 ALTER TABLE ONLY public.accounts

This comment was last updated at Thu, 29 Jan 2026 03:03:01 GMT

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

🤖 Fix all issues with AI agents
In `@auth-schema.ts`:
- Around line 61-63: The accounts table column definition for updatedAt (the
timestamp builder named updatedAt in auth-schema.ts) is marked .notNull() but
lacks a default, causing INSERTs to fail; fix by adding .defaultNow() to the
updatedAt column definition (the same pattern used for createdAt/defaultNow) so
that updatedAt has a default value on INSERT and still uses .$onUpdate(() => new
Date()) for updates.
- Around line 32-34: The sessions.updatedAt timestamp is marked .notNull() but
lacks a default causing INSERT failures; update the timestamp("updated_at")
definition for updatedAt (the same pattern used by createdAt) to include
.defaultNow() (i.e.,
timestamp("updated_at").defaultNow().$onUpdate(...).notNull()) so new session
rows can be inserted without explicitly providing updatedAt.
- Around line 11-23: The users table definition in auth-schema.ts must match
src/db/schema.ts: remove .notNull() from the email column (make email nullable),
add .unique() to the name column, and remove the inline preferences
jsonb("preferences") column so preferences are modeled via the separate
users_preferences table (which uses a prefs column); update the users export
accordingly (refer to the users constant and its id, name, email, preferences
symbols) to match the DB schema.

In `@drizzle/0020_daffy_nekra.sql`:
- Line 5: The migration is renaming accounts.token_type to accounts.idToken
which mixes semantics; instead decide whether to preserve token_type values or
create a separate idToken column: if the old token_type must be preserved, add a
new column idToken (ALTER TABLE "accounts" ADD COLUMN "idToken" TEXT),
migrate/copy relevant values from "token_type" into "idToken" with an UPDATE,
and only then DROP COLUMN "token_type" if appropriate; if token_type should be
discarded, simply DROP COLUMN "token_type" and ADD "idToken" separately; update
the migration SQL to use ADD COLUMN, UPDATE (data copy) and DROP COLUMN
statements rather than a direct RENAME so token semantics remain correct.
- Line 15: The migration adds accounts.accountId as nullable but your schema
requires notNull: true; update the migration to (1) keep the ADD COLUMN
"accountId" text as a nullable step, (2) add a backfill step that populates
"accountId" for all existing rows (e.g., copy from an existing identifier or
generate UUIDs) and commit, then (3) add an ALTER TABLE "accounts" ALTER COLUMN
"accountId" SET NOT NULL step to enforce the constraint; reference the
"accounts" table and "accountId" column in the migration so the sequence is add
-> backfill -> set NOT NULL.
- Line 27: The migration adds a new NOT NULL primary key column "id" to table
"verification_tokens" which will fail on tables with existing rows; change the
migration to a safe multi-step approach: first add "id" as nullable (ALTER TABLE
"verification_tokens" ADD COLUMN "id" text), populate it for existing rows
(e.g., update rows with gen_random_uuid() or another unique generator), then
alter the column to be NOT NULL and add the PRIMARY KEY constraint (or create
the PK separately), or alternatively add the column with a DEFAULT
gen_random_uuid() so existing rows are assigned values, or guard the statement
to run only when the table is empty—target the "verification_tokens" table and
the "id" column in your fixes.

In `@drizzle/0024_famous_nico_minoru.sql`:
- Around line 1-2: The migration currently adds "id" as NOT NULL PRIMARY KEY
immediately which will fail on non-empty "sessions"; instead: drop
"sessions_pkey" as you already do, ADD COLUMN "id" text NULL (no NOT NULL/PK),
run an UPDATE to backfill "id" for every row (preferably copying the existing
primary key column if one exists, otherwise generate stable unique values e.g.
uuid functions), then ALTER TABLE "sessions" ALTER COLUMN "id" SET NOT NULL and
finally ADD CONSTRAINT "sessions_pkey" PRIMARY KEY ("id"); ensure the backfill
uses a deterministic function available in your DB (uuid_generate_v4() or
gen_random_uuid()) or copies the existing key to preserve identity.

In `@package.json`:
- Around line 52-53: Remove the stale next-auth dependency from package.json and
update any remaining type/import references: delete the "next-auth" entry and
replace the type import in src/app/[locale]/ui/settings/settings.tsx with the
equivalent type from better-auth (or use a local session type), and
remove/ignore src/old-auth.ts if it's truly legacy; verify usage across
src/auth.ts, src/auth-client.ts, and src/proxy.ts to ensure nothing still
imports next-auth before committing.

In `@src/app/`[locale]/ui/auth/logout-form.tsx:
- Around line 14-23: Wrap the authClient.signOut call in error handling: perform
the existing toast.info(t("loggingOut")) then await authClient.signOut(...)
inside a try block (keeping the fetchOptions.onSuccess that calls
router.push("/")), and add a catch block that calls toast.error(...) with a
localized failure message (e.g. t("logoutFailed")), logs the error
(console.error or a logger), and prevents navigation so the user gets feedback;
ensure you reference authClient.signOut, toast, router.push and the existing
fetchOptions.onSuccess when making this change.

In `@src/auth-client.ts`:
- Around line 1-3: The client is initialized with an empty config; update the
createAuthClient call used to export authClient so it sets baseURL to the public
frontend env var (e.g., use process.env.NEXT_PUBLIC_BETTER_AUTH_URL) to match
server-side baseURL and production domain routing; ensure the
NEXT_PUBLIC_BETTER_AUTH_URL environment variable is exposed to the frontend so
the authClient uses the correct endpoint.

In `@src/auth.ts`:
- Around line 101-102: The code is using unsafe type assertions
(clientId/clientSecret) for environment variables (AUTH_GITHUB_ID,
AUTH_GITHUB_SECRET and the other pair at lines 108-109); replace these with a
small runtime validation helper (e.g., getRequiredEnv or assertEnv) and call it
when constructing the auth provider config so the app fails fast with a clear
error if a variable is missing, then use the validated value in the provider
configuration (replace direct uses of clientId/clientSecret with the returned
non-null string).
- Around line 104-107: The inline comment in the google config object is
malformed—split the concatenated URL/comment and the config option into two
parts: add a proper comment line with the URL
("https://www.better-auth.com/docs/authentication/google#always-get-refresh-token")
above or beside the google config, and restore the accessType option inside the
google object as accessType: "offline" (ensuring it's a separate property
alongside prompt). Update the google config (the google object and its
properties prompt and accessType) to remove the broken comment and include
accessType correctly.
- Around line 22-32: The preferences additional field is required but has no
defaultValue; import the DEFAULT_USERS_PREFERENCES constant and set defaultValue
for user.additionalFields.preferences to that constant (uncomment and assign
DEFAULT_USERS_PREFERENCES) so new users get the expected defaults; ensure the
import is added near other imports and that the symbol name
(DEFAULT_USERS_PREFERENCES) matches the exported identifier used elsewhere.

In `@src/db/schema.ts`:
- Around line 253-265: The sessions pgTable definition is missing an index on
the userId column; update the sessions table (pgTable named "sessions") to
create an index on the userId field so lookups by userId are efficient (mirror
the index that exists in auth-schema.ts). Add the index declaration alongside
the sessions definition (using your project's index helper/DSL so it becomes
part of the table schema) and ensure it references the sessions.userId column
and uses a sensible name (e.g., sessions_user_id_idx) and non-unique
configuration.

In `@src/old-auth.ts`:
- Around line 1-80: Delete this legacy NextAuth configuration file (old-auth.ts)
since it is dead code; remove the file entirely and update any imports that
might reference its exported symbols (handlers, signIn, signOut, auth) to use
the new auth implementation (e.g., auth.ts). Ensure there are no remaining
usages of config, createUser event handler, or the DrizzleAdapter setup in the
repo before committing the deletion.
🧹 Nitpick comments (12)
src/app/[locale]/ui/auth/logout-form.tsx (1)

24-24: Remove unnecessary type="submit" attribute.

This Button is not inside a <form> element and uses an onClick handler, so type="submit" has no effect and could be misleading.

🧹 Proposed fix
-			type="submit"
+			type="button"
src/lib/dal.ts (3)

17-18: Remove duplicate commented import.

Line 18 contains a commented-out duplicate of the import on line 17. This appears to be leftover from the migration and should be removed.

🧹 Proposed fix
 import { auth } from "@/auth";
-// import { auth } from "@/auth";

39-44: Remove commented-out legacy code.

This commented block is the old NextAuth-based implementation. If the migration to better-auth is complete, this dead code should be removed to avoid confusion.

🧹 Proposed fix
-// /**
-//  * verifySession returns the current session (logged in user).
-//  */
-// const verifySession = cache(async (): Promise<Session | null> => {
-// 	return await auth();
-// });
-

33-37: Add explicit return type for better type clarity and IDE support.

The function lacks type annotation, which reduces clarity and IDE support despite strict TypeScript configuration. Use the proper better-auth type inference: Promise<typeof auth.$Infer.Session | null> or create a named type alias for cleaner code.

src/lib/actions.ts (1)

8-8: Remove commented-out import.

The signIn and signOut imports are commented out and no longer used in this file since the authentication functions were removed during the migration to better-auth.

🧹 Proposed fix
-// import { signIn, signOut } from "@/auth";
src/old-auth.ts (1)

45-60: Consider caching user preferences lookup in session callback.

The session callback queries the database for user preferences on every session access. This could impact performance for authenticated requests.

Consider using React's cache() or a similar memoization strategy to deduplicate preference lookups within a single request, or explore better-auth's built-in session data mechanisms.

src/db/schema.ts (1)

224-251: Clean up commented-out code in accounts table.

The accounts table has extensive commented-out code (lines 233-234, 238, 241, 248-250) that appears to be remnants of the old next-auth schema. Consider removing these comments to improve readability, or add a brief explanatory comment if they're intentionally kept for reference.

package.json (1)

6-6: Turbopack flag removed from dev script.

The --turbopack flag was removed from the dev script. In Next.js 15, Turbopack Dev was stable and production-ready. If this was intentional (e.g., due to compatibility issues with Next.js 16), this is fine. Otherwise, consider re-enabling it for faster development builds:

"dev": "next dev --turbopack"
src/app/api/auth/[...nextauth]/route.ts (1)

1-6: Remove commented-out code and consider renaming the route path.

The commented-out next-auth code (lines 1-2) should be removed since the migration to better-auth is complete.

Additionally, the route path [...nextauth] is misleading since better-auth is now being used. Better-auth typically uses [...all] as the catch-all route name. Consider renaming the directory to avoid confusion, though this would require updating BETTER_AUTH_URL accordingly.

♻️ Proposed cleanup
-// import { handlers } from "@/auth";
-// export const { GET, POST } = handlers;
-
 import { toNextJsHandler } from "better-auth/next-js";
 import { auth } from "@/auth";
+
 export const { POST, GET } = toNextJsHandler(auth);
src/auth.ts (1)

34-94: Remove or document the extensive commented-out code.

Lines 34-94 contain a large block of commented-out hooks and database hooks. If this code is for future reference or planned implementation, consider:

  1. Moving it to a separate documentation file or README
  2. Creating a GitHub issue to track the implementation
  3. Removing it entirely if it's no longer needed

Leaving large blocks of commented code makes the file harder to maintain.

drizzle/0022_worried_mac_gargan.sql (1)

6-16: Ensure accounts.id has a generation strategy for future inserts.

After Line 9-14, id is NOT NULL/PK but no DEFAULT is set; inserts will fail unless the app always supplies id. If the DB should generate it, add a default.

✅ Optional default for `id`
 ALTER TABLE "accounts" ADD COLUMN "id" text;
+ALTER TABLE "accounts" ALTER COLUMN "id" SET DEFAULT gen_random_uuid()::text;
 UPDATE "accounts" SET "id" = gen_random_uuid()::text WHERE "id" IS NULL;
drizzle/meta/0021_snapshot.json (1)

559-637: Consider adding a primary key to the sessions table.

The sessions table relies solely on a unique constraint on token without an explicit primary key. While PostgreSQL permits this, having a primary key is generally recommended for:

  • Better ORM compatibility
  • Clearer intent for the table's identity
  • Potential performance benefits with clustered indexes

If token is intended as the identifier, consider making it the primary key instead of just a unique constraint.

Comment on lines +11 to +23
export const users = pgTable("users", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").default(false).notNull(),
image: text("image"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
.defaultNow()
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
preferences: jsonb("preferences").notNull(),
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find SQL migrations touching the users table
fd -e sql . drizzle/ | xargs rg -l "users" | head -5

# Inspect users schema in src/db/schema.ts
rg -nA20 "export const users = pgTable" src/db/schema.ts

Repository: mtlaso/bocal

Length of output: 769


🏁 Script executed:

#!/bin/bash
# Check for DEFAULT_USERS_PREFERENCES usage
rg -n "DEFAULT_USERS_PREFERENCES" .

# Inspect migrations for preferences column
rg -n "preferences" drizzle/

Repository: mtlaso/bocal

Length of output: 6553


Align auth-schema.ts with src/db/schema.ts

  • email: auth-schema sets .notNull(), but DB defines email as nullable.
  • name: auth-schema omits .unique(), while DB enforces unique names.
  • preferences: auth-schema introduces an inline preferences column, but the DB uses a separate users_preferences table with a prefs column.
🤖 Prompt for AI Agents
In `@auth-schema.ts` around lines 11 - 23, The users table definition in
auth-schema.ts must match src/db/schema.ts: remove .notNull() from the email
column (make email nullable), add .unique() to the name column, and remove the
inline preferences jsonb("preferences") column so preferences are modeled via
the separate users_preferences table (which uses a prefs column); update the
users export accordingly (refer to the users constant and its id, name, email,
preferences symbols) to match the DB schema.

Comment on lines +32 to +34
updatedAt: timestamp("updated_at")
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing defaultNow() on updatedAt will cause INSERT failures.

The sessions.updatedAt column is marked as .notNull() but lacks .defaultNow(), unlike createdAt. This will cause database errors when inserting new sessions without explicitly providing updatedAt.

🐛 Proposed fix
 		updatedAt: timestamp("updated_at")
+			.defaultNow()
 			.$onUpdate(() => /* `@__PURE__` */ new Date())
 			.notNull(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
updatedAt: timestamp("updated_at")
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
updatedAt: timestamp("updated_at")
.defaultNow()
.$onUpdate(() => /* `@__PURE__` */ new Date())
.notNull(),
🤖 Prompt for AI Agents
In `@auth-schema.ts` around lines 32 - 34, The sessions.updatedAt timestamp is
marked .notNull() but lacks a default causing INSERT failures; update the
timestamp("updated_at") definition for updatedAt (the same pattern used by
createdAt) to include .defaultNow() (i.e.,
timestamp("updated_at").defaultNow().$onUpdate(...).notNull()) so new session
rows can be inserted without explicitly providing updatedAt.

Comment on lines +61 to +63
updatedAt: timestamp("updated_at")
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing defaultNow() on updatedAt will cause INSERT failures.

Same issue as with sessions table - the accounts.updatedAt column is .notNull() without a default value.

🐛 Proposed fix
 		updatedAt: timestamp("updated_at")
+			.defaultNow()
 			.$onUpdate(() => /* `@__PURE__` */ new Date())
 			.notNull(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
updatedAt: timestamp("updated_at")
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
updatedAt: timestamp("updated_at")
.defaultNow()
.$onUpdate(() => /* `@__PURE__` */ new Date())
.notNull(),
🤖 Prompt for AI Agents
In `@auth-schema.ts` around lines 61 - 63, The accounts table column definition
for updatedAt (the timestamp builder named updatedAt in auth-schema.ts) is
marked .notNull() but lacks a default, causing INSERTs to fail; fix by adding
.defaultNow() to the updatedAt column definition (the same pattern used for
createdAt/defaultNow) so that updatedAt has a default value on INSERT and still
uses .$onUpdate(() => new Date()) for updates.

ALTER TABLE "accounts" RENAME COLUMN "refresh_token" TO "refreshToken";--> statement-breakpoint
ALTER TABLE "accounts" RENAME COLUMN "access_token" TO "accessToken";--> statement-breakpoint
ALTER TABLE "accounts" RENAME COLUMN "expires_at" TO "expiresAt";--> statement-breakpoint
ALTER TABLE "accounts" RENAME COLUMN "token_type" TO "idToken";--> statement-breakpoint
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Semantic mismatch: token_type renamed to idToken.

The column token_type typically stores the token type (e.g., "Bearer"), while idToken represents the actual ID token value from OIDC. This rename appears to repurpose the column with different semantics.

If migrating from NextAuth to better-auth, verify:

  1. Whether existing token_type data should be preserved elsewhere
  2. If this column should be dropped instead of renamed
  3. If a new idToken column should be added separately
🤖 Prompt for AI Agents
In `@drizzle/0020_daffy_nekra.sql` at line 5, The migration is renaming
accounts.token_type to accounts.idToken which mixes semantics; instead decide
whether to preserve token_type values or create a separate idToken column: if
the old token_type must be preserved, add a new column idToken (ALTER TABLE
"accounts" ADD COLUMN "idToken" TEXT), migrate/copy relevant values from
"token_type" into "idToken" with an UPDATE, and only then DROP COLUMN
"token_type" if appropriate; if token_type should be discarded, simply DROP
COLUMN "token_type" and ADD "idToken" separately; update the migration SQL to
use ADD COLUMN, UPDATE (data copy) and DROP COLUMN statements rather than a
direct RENAME so token semantics remain correct.

ALTER TABLE "users" ALTER COLUMN "emailVerified" SET DATA TYPE boolean USING ("emailVerified" IS NOT NULL);--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "emailVerified" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "accounts" ADD CONSTRAINT "accounts_providerId_providerAccountId_pk" PRIMARY KEY("providerId","providerAccountId");--> statement-breakpoint
ALTER TABLE "accounts" ADD COLUMN "accountId" text;--> statement-breakpoint
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

accountId column is added as nullable but schema expects NOT NULL.

The column is added without NOT NULL, but the schema snapshot shows notNull: true. A subsequent migration or manual step is needed to:

  1. Populate existing rows with values
  2. Add the NOT NULL constraint

Verify the migration sequence handles this correctly, or add the constraint after data population.

🤖 Prompt for AI Agents
In `@drizzle/0020_daffy_nekra.sql` at line 15, The migration adds
accounts.accountId as nullable but your schema requires notNull: true; update
the migration to (1) keep the ADD COLUMN "accountId" text as a nullable step,
(2) add a backfill step that populates "accountId" for all existing rows (e.g.,
copy from an existing identifier or generate UUIDs) and commit, then (3) add an
ALTER TABLE "accounts" ALTER COLUMN "accountId" SET NOT NULL step to enforce the
constraint; reference the "accounts" table and "accountId" column in the
migration so the sequence is add -> backfill -> set NOT NULL.

Comment on lines +101 to +102
clientId: process.env.AUTH_GITHUB_ID as string,
clientSecret: process.env.AUTH_GITHUB_SECRET as string,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Environment variable assertions may fail silently at runtime.

The as string type assertions on environment variables (lines 101-102, 108-109) will mask undefined values and could cause cryptic runtime errors. Consider validating these at startup or using a more defensive pattern.

🛡️ Proposed fix with runtime validation
+const getRequiredEnv = (name: string): string => {
+	const value = process.env[name];
+	if (!value) {
+		throw new Error(`Missing required environment variable: ${name}`);
+	}
+	return value;
+};
+
 export const auth = betterAuth({
 	// ...
 	socialProviders: {
 		github: {
 			scopes: ["read:user", "user:email"],
-			clientId: process.env.AUTH_GITHUB_ID as string,
-			clientSecret: process.env.AUTH_GITHUB_SECRET as string,
+			clientId: getRequiredEnv("AUTH_GITHUB_ID"),
+			clientSecret: getRequiredEnv("AUTH_GITHUB_SECRET"),
 		},
 		google: {
 			prompt: "select_account consent",
-			clientId: process.env.AUTH_GOOGLE_ID as string,
-			clientSecret: process.env.AUTH_GOOGLE_SECRET as string,
+			clientId: getRequiredEnv("AUTH_GOOGLE_ID"),
+			clientSecret: getRequiredEnv("AUTH_GOOGLE_SECRET"),
 		},
 	},

Also applies to: 108-109

🤖 Prompt for AI Agents
In `@src/auth.ts` around lines 101 - 102, The code is using unsafe type assertions
(clientId/clientSecret) for environment variables (AUTH_GITHUB_ID,
AUTH_GITHUB_SECRET and the other pair at lines 108-109); replace these with a
small runtime validation helper (e.g., getRequiredEnv or assertEnv) and call it
when constructing the auth provider config so the app fails fast with a clear
error if a variable is missing, then use the validated value in the provider
configuration (replace direct uses of clientId/clientSecret with the returned
non-null string).

Comment on lines +104 to +107
google: {
// https://www.better-auth.com/docs/authentication/google#always-get-refresh-tokenaccessType: "offline",
// // Always get refresh token
prompt: "select_account consent",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix malformed comment on line 105.

The comment on line 105 has a URL concatenated with a config option, making it unreadable:

// https://www.better-auth.com/docs/authentication/google#always-get-refresh-tokenaccessType: "offline",

This should be split into a proper comment and potentially the accessType option:

🔧 Proposed fix
 		google: {
-			// https://www.better-auth.com/docs/authentication/google#always-get-refresh-tokenaccessType: "offline",
-			// // Always get refresh token
+			// https://www.better-auth.com/docs/authentication/google#always-get-refresh-token
+			// accessType: "offline", // Always get refresh token
 			prompt: "select_account consent",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
google: {
// https://www.better-auth.com/docs/authentication/google#always-get-refresh-tokenaccessType: "offline",
// // Always get refresh token
prompt: "select_account consent",
google: {
// https://www.better-auth.com/docs/authentication/google#always-get-refresh-token
// accessType: "offline", // Always get refresh token
prompt: "select_account consent",
🤖 Prompt for AI Agents
In `@src/auth.ts` around lines 104 - 107, The inline comment in the google config
object is malformed—split the concatenated URL/comment and the config option
into two parts: add a proper comment line with the URL
("https://www.better-auth.com/docs/authentication/google#always-get-refresh-token")
above or beside the google config, and restore the accessType option inside the
google object as accessType: "offline" (ensuring it's a separate property
alongside prompt). Update the google config (the google object and its
properties prompt and accessType) to remove the broken comment and include
accessType correctly.

Comment on lines 253 to 265
export const sessions = pgTable("sessions", {
sessionToken: text().primaryKey(),
// sessionToken: text().primaryKey(),
id: text("id").primaryKey(),
token: text("token").notNull().unique(),
userId: text()
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
expires: timestamp({ mode: "date" }).notNull(),
// expires: timestamp({ mode: "date" }).notNull(),
expiresAt: timestamp("expires_at").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
...timestampFields,
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add missing index on userId for sessions table.

The sessions table is missing an index on userId that exists in the reference auth-schema.ts (lines 24-41). This index is important for efficient session lookups by user.

🔧 Proposed fix to add the missing index
-export const sessions = pgTable("sessions", {
+export const sessions = pgTable(
+	"sessions",
+	{
 	// sessionToken: text().primaryKey(),
 	id: text("id").primaryKey(),
 	token: text("token").notNull().unique(),
 	userId: text()
 		.notNull()
 		.references(() => users.id, { onDelete: "cascade" }),
 	// expires: timestamp({ mode: "date" }).notNull(),
 	expiresAt: timestamp("expires_at").notNull(),
 	ipAddress: text("ip_address"),
 	userAgent: text("user_agent"),
 	...timestampFields,
-});
+	},
+	(table) => [index("sessions_userId_idx").on(table.userId)],
+);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const sessions = pgTable("sessions", {
sessionToken: text().primaryKey(),
// sessionToken: text().primaryKey(),
id: text("id").primaryKey(),
token: text("token").notNull().unique(),
userId: text()
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
expires: timestamp({ mode: "date" }).notNull(),
// expires: timestamp({ mode: "date" }).notNull(),
expiresAt: timestamp("expires_at").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
...timestampFields,
});
export const sessions = pgTable(
"sessions",
{
// sessionToken: text().primaryKey(),
id: text("id").primaryKey(),
token: text("token").notNull().unique(),
userId: text()
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
// expires: timestamp({ mode: "date" }).notNull(),
expiresAt: timestamp("expires_at").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
...timestampFields,
},
(table) => [index("sessions_userId_idx").on(table.userId)],
);
🤖 Prompt for AI Agents
In `@src/db/schema.ts` around lines 253 - 265, The sessions pgTable definition is
missing an index on the userId column; update the sessions table (pgTable named
"sessions") to create an index on the userId field so lookups by userId are
efficient (mirror the index that exists in auth-schema.ts). Add the index
declaration alongside the sessions definition (using your project's index
helper/DSL so it becomes part of the table schema) and ensure it references the
sessions.userId column and uses a sensible name (e.g., sessions_user_id_idx) and
non-unique configuration.

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/app/`[locale]/(app)/d/(sidebar)/feeds/page.tsx:
- Around line 77-79: The fallback "Not logged in" string is hardcoded when sess
is falsy; replace it with a translated string by using the project's i18n
utilities: either call useTranslations (or getTranslations in this async
component) and return t('yourNamespace.notLoggedIn') instead of the literal, or
pass a translation function/prop into FeedsWrapper so it renders the translated
text; update the locale files with the notLoggedIn key accordingly. Reference:
sess check, FeedsWrapper, useTranslations, getTranslations.

In `@src/app/`[locale]/ui/settings/settings.tsx:
- Around line 14-23: The Settings component currently expects a sess Promise
(Props with sess and calling use(sess)) but the parent passes user={sess.user};
fix by changing Settings to accept the resolved user prop (rename Props from
sess to user), update the function signature to Settings({ user }: Props),
remove the use(sess) call, and replace checks that reference session.user with
the passed user (or redirect to APP_ROUTES.login when user is falsy); reference
the Props type, Settings function, sess/use(sess) usage, and the parent usage
user={sess.user} when making these edits.
🧹 Nitpick comments (2)
src/app/[locale]/(app)/d/(sidebar)/feeds/page.tsx (1)

86-88: Track the @ts-expect-error technical debt.

The suppressed type error with TODO ("corriger quand Preferences fonctionnera dans auth.ts") indicates a known issue with the auth migration affecting sess.user.preferences typing. Consider creating an issue to track this fix once the Preferences type is properly integrated in auth.ts.

Would you like me to open a GitHub issue to track resolving this type suppression after the auth/preferences work is complete?

src/app/[locale]/ui/settings/settings.tsx (1)

30-32: Avoid @ts-ignore; address the type mismatch properly.

The Session interface in auth.ts already types preferences as typeof DEFAULT_USERS_PREFERENCES. If there's a mismatch with ViewSection's expected type, consider:

  1. Exporting and reusing DEFAULT_USERS_PREFERENCES type in ViewSection.
  2. Using @ts-expect-error with a specific explanation if this is a temporary workaround (it will error when the underlying issue is fixed, unlike @ts-ignore).

Leaving @ts-ignore risks silently masking future type regressions.

Comment on lines +77 to +79
if (!sess) {
return <div>Not logged in</div>;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hardcoded string is not internationalized.

The fallback "Not logged in" text is hardcoded in English while the rest of the page uses the useTranslations hook for i18n. This creates an inconsistent user experience for non-English locales.

🌐 Proposed fix using translations

Pass the translations to FeedsWrapper or use getTranslations within the async component:

 async function FeedsWrapper(): Promise<React.JSX.Element> {
+	const t = await getTranslations("rssFeed");
 	const [timeline, sess] = await Promise.all([
 		dal.getUserFeedsTimeline(),
 		dal.verifySession(),
 	]);

 	if (!sess) {
-		return <div>Not logged in</div>;
+		return <div>{t("notLoggedIn")}</div>;
 	}

Then add the corresponding translation key to your locale files.

🤖 Prompt for AI Agents
In `@src/app/`[locale]/(app)/d/(sidebar)/feeds/page.tsx around lines 77 - 79, The
fallback "Not logged in" string is hardcoded when sess is falsy; replace it with
a translated string by using the project's i18n utilities: either call
useTranslations (or getTranslations in this async component) and return
t('yourNamespace.notLoggedIn') instead of the literal, or pass a translation
function/prop into FeedsWrapper so it renders the translated text; update the
locale files with the notLoggedIn key accordingly. Reference: sess check,
FeedsWrapper, useTranslations, getTranslations.

@github-actions
Copy link

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/auth.ts`:
- Around line 14-17: The trustedOrigins array in src/auth.ts contains a
duplicate reference to process.env.BETTER_AUTH_URL; update the second entry to
the intended preview/alternate origin (e.g., process.env.VERCEL_URL or a preview
pattern based on VERCEL_URL) so trustedOrigins contains the primary
BETTER_AUTH_URL and the preview/alternate URL; edit the trustedOrigins array
definition to replace the redundant BETTER_AUTH_URL reference with the correct
environment variable or pattern (referencing the trustedOrigins symbol in the
file).

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/auth.ts`:
- Around line 14-17: The trustedOrigins array is using process.env.VERCEL_URL
which is just a hostname; update the trustedOrigins construction (the
trustedOrigins variable/array in src auth module) to prepend "https://" to
process.env.VERCEL_URL when present (e.g., const vercelOrigin =
process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : undefined),
include only defined values (filter out undefined), and keep
process.env.BETTER_AUTH_URL as-is so origin validation receives a full URL for
VERCEL.

@github-actions
Copy link

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/app/`[locale]/(landing)/page.tsx:
- Around line 121-124: The HeroSection server component is currently dumping the
entire environment via console.log(JSON.stringify(process.env)), which risks
leaking secrets and noisy per-request logs; remove that console.log call from
the HeroSection function (the async HeroSection(locale: Locale) surrounding the
getTranslations(...) call) and, if you need to inspect a value during
development, replace it with a targeted, non-sensitive log (e.g., log a single
safe variable or a debug flag) or use secure server-side debugging tools—ensure
no other occurrences of JSON.stringify(process.env) remain in the module.
- Around line 27-33: The Home component calls request-scoped APIs (use(params)
and setRequestLocale) while cacheComponents: true is enabled; convert export
default function Home to an async component or wrap the parts that access
request-scoped data in a React.Suspense boundary (matching other pages) so
request state doesn’t leak across cached instances — ensure any async child that
reads use(params) is suspended; also remove the console.log(process.env) call
(or replace it with logging of explicit, non-sensitive vars) to avoid exposing
secrets.

In `@src/auth.ts`:
- Around line 46-60: The current after hooks (after: async (user, _ctx) in the
user create handler and after: async (account) in the account.create handler)
log full user/account objects via logger.info which may contain PII or tokens;
change those logger calls to only log non-sensitive identifiers (e.g., user.id
and account.id) or explicitly redact sensitive fields before logging (e.g.,
construct a minimal object { id: user.id, email: user.email? } or a redacted
copy) and replace the two logger.info("User created", { user }) and
logger.info("Account created", { account }) calls accordingly.

@github-actions
Copy link

@github-actions
Copy link

@mtlaso mtlaso merged commit f0c2b3f into master Feb 12, 2026
6 checks passed
mtlaso added a commit that referenced this pull request Feb 12, 2026
Merge pull request #297 from mtlaso/next16-update
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant