Skip to content

Feat/prisma supabase#2

Open
Teaser-Developer-Team wants to merge 3 commits intomainfrom
feat/prisma-supabase
Open

Feat/prisma supabase#2
Teaser-Developer-Team wants to merge 3 commits intomainfrom
feat/prisma-supabase

Conversation

@Teaser-Developer-Team
Copy link
Copy Markdown
Contributor

@Teaser-Developer-Team Teaser-Developer-Team commented Jun 14, 2025

Summary by CodeRabbit

  • New Features

    • Google and Apple social login flows added; social sign-in buttons/icons available.
    • New Apple, Google, and Facebook SVG icons.
  • Enhancements

    • Fonts switched to Manrope and Lalezar; text component supports extra font families/weights.
    • Improved session handling and auth refresh behavior.
  • Chores

    • Database tooling, migration and seeding added; generated DB artifacts ignored.
    • Package scripts and dependencies updated for auth, storage, and DB workflows.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 14, 2025

Walkthrough

Adds Prisma schema, migration, lock, and seed; introduces Prisma and Supabase clients; new social sign-in component (Google, Apple) with Supabase auth and user upsert; swaps fonts to Manrope/Lalezar and updates Text component; adds SVG icons; adds Prisma scripts/deps; many line-ending/formatting normalizations.

Changes

Cohort / File(s) Summary
Prisma infra
prisma/schema.prisma, prisma/migrations/.../migration.sql, prisma/migrations/migration_lock.toml, prisma/seed.ts
Adds Prisma schema (enums/models/indexes/@@Map), initial SQL migration, migration lock, and a seed script that upserts moods, users, chats, and conversation topics.
Runtime DB / Clients
src/lib/prisma.ts, src/lib/supabase.ts
Adds a global PrismaClient singleton with env-based logging; adds Supabase client configured for React Native AsyncStorage, auto-refresh, and AppState-driven refresh control.
Auth UI & flows
src/features/auth/components/SocialLoginRow.tsx
New SocialLoginRow component: Google and Apple sign-in flows, Base64 JWT parsing, Supabase signInWithIdToken usage, and server-side user creation/upsert logic.
Icons
src/assets/icons/AppleLogo.tsx, src/assets/icons/FacebookLogo.tsx, src/assets/icons/GoogleLogo.tsx
Adds React Native SVG components for Apple, Facebook, and Google logos.
Fonts & Text
src/app/_layout.tsx, src/theme/fonts.ts, src/components/common/Text/Text.tsx
Replaces NunitoSans with Manrope and Lalezar; updates font exports and Text props/logic to support fontFamily ('lalezar'
Package & tooling
package.json, .gitignore
Adds Prisma CLI scripts and dependencies (prisma, @prisma/client) plus runtime/auth/storage deps; adds /src/generated/prisma to .gitignore.
Scripts & tooling changes
scripts/reset-project.js, scripts/create-project.sh
reset-project.js adjusted for ESM/require interop and removed directory-move implementation; create-project.sh line-ending normalization only.
Formatting / line endings
many files (e.g., .eslintrc, .prettierrc, app.json, .idea/*, numerous src files)
Widespread CRLF/whitespace normalization with no functional changes across many source, config, and IDE files.
UI small
src/app/(tabs)/*, src/components/**
Mostly line-ending/formatting normalization in many UI components and types; no behavior changes except noted cohorts above.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App
    participant Google
    participant Apple
    participant Supabase
    participant PrismaDB

    User->>App: Tap Google login
    App->>Google: Start Google Sign-In
    Google-->>App: Return idToken
    App->>Supabase: signInWithIdToken(provider: "google", idToken)
    Supabase-->>App: Auth result (user id, email)
    App->>PrismaDB: Upsert/check user by email
    alt user absent
        PrismaDB-->>App: Create user record
    end
    App-->>User: Sign-in complete

    User->>App: Tap Apple login
    App->>Apple: Start Apple Sign-In
    Apple-->>App: Return identityToken
    App->>Supabase: signInWithIdToken(provider: "apple", idToken)
    Supabase-->>App: Auth result (user id, email)
    App->>PrismaDB: Upsert/check user by email
    alt user absent
        PrismaDB-->>App: Create user record
    end
    App-->>User: Sign-in complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I nibble at the schema root,
Manrope leaves and Lalezar root.
Tokens hum and icons gleam,
Supabase and Prisma team.
A rabbit seeds the midnight dream. 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/prisma supabase' clearly indicates the main change: integration of Prisma and Supabase into the project. However, the format uses a branch-style naming convention rather than a descriptive sentence.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/prisma-supabase

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

Copy link
Copy Markdown

@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: 12

🧹 Nitpick comments (8)
.gitignore (1)

40-41: Optional: Clarify directory ignore pattern.
Consider adding a trailing slash (/src/generated/prisma/) or wildcard (/src/generated/prisma/*) to explicitly denote directory contents.

src/assets/icons/AppleLogo.tsx (1)

5-15: Expose accessibility label & memoise static icon for perf/debugging

  1. Screen-reader users will not know what this icon represents. Pass an accessibilityLabel (or accessibilityRole="image" with accessibilityLabel) on <Svg>.

  2. This SVG is static; wrapping the component in React.memo and adding a displayName avoids needless re-renders and gives clearer React-DevTools traces.

-const IconAppleLogo = ({ ...props }: SvgProps) => (
+const IconAppleLogo = React.memo(({ accessibilityLabel = 'Apple logo', ...props }: SvgProps) => (
   <Svg
     width={30}
     height={30}
     viewBox="0 0 50 50"
+    accessibilityRole="image"
+    accessibilityLabel={accessibilityLabel}
     {...props}
   >
     …
-);
+)) as React.NamedExoticComponent<SvgProps>;
+IconAppleLogo.displayName = 'IconAppleLogo';
src/lib/prisma.ts (1)

7-14: Consider limiting connection count in dev

Repeated hot-reloads can leave zombie connections open.
Passing datasource: { } isn’t yet supported, but you can cap
connections with:

new PrismaClient({
  log: ,
  datasources: { db: { url: process.env.DATABASE_URL } },
  __internal: { engine: { maxPoolSize: 5 } }, // unofficial but supported
});

(or set connection_limit on your Postgres URI).
Prevents hitting “too many connections” in local dev.

src/assets/icons/GoogleLogo.tsx (1)

5-25: Add memoisation & accessibility label (same as Apple icon)

Replicate the improvements suggested for IconAppleLogo to keep icon
components consistent and performant.

prisma/seed.ts (1)

15-38: Parallelise upserts for faster seed execution (optional)

Running await inside a for loop is O(n) serial. Using
Promise.all() cuts seeding time dramatically on larger datasets.

-for (const mood of moods) {
-  await prisma.mood.upsert({ … });
-}
+await Promise.all(
+  moods.map(mood =>
+    prisma.mood.upsert({ where: { type: mood.type }, update: {}, create: mood })
+  )
+);
src/features/auth/components/SocialLoginRow.tsx (1)

128-137: Inconsistent UX for Facebook icon

The Facebook logo is rendered without an onPress, unlike Google/Apple. Either add the handler or clarify the icon is decorative.

src/components/common/Text/Text.tsx (1)

12-13: Remove dead italic prop or implement it

italic is accepted but ignored after the refactor, which is confusing for consumers.

prisma/schema.prisma (1)

73-75: Minor naming consistency

Field User (capital U) in Chat deviates from lower-camel fields elsewhere; consider user for uniformity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3efd0a9 and eee7593.

⛔ Files ignored due to path filters (13)
  • src/assets/fonts/Lalezar-Regular.ttf is excluded by !**/*.ttf
  • src/assets/fonts/Manrope-Bold.ttf is excluded by !**/*.ttf
  • src/assets/fonts/Manrope-Light.ttf is excluded by !**/*.ttf
  • src/assets/fonts/Manrope-Medium.ttf is excluded by !**/*.ttf
  • src/assets/fonts/Manrope-Regular.ttf is excluded by !**/*.ttf
  • src/assets/fonts/Manrope-SemiBold.ttf is excluded by !**/*.ttf
  • src/assets/fonts/NunitoSans-Bold.ttf is excluded by !**/*.ttf
  • src/assets/fonts/NunitoSans-BoldItalic.ttf is excluded by !**/*.ttf
  • src/assets/fonts/NunitoSans-Italic.ttf is excluded by !**/*.ttf
  • src/assets/fonts/NunitoSans-Regular.ttf is excluded by !**/*.ttf
  • src/assets/fonts/NunitoSans-SemiBold.ttf is excluded by !**/*.ttf
  • src/assets/fonts/NunitoSans-SemiBoldItalic.ttf is excluded by !**/*.ttf
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (15)
  • .gitignore (1 hunks)
  • package.json (3 hunks)
  • prisma/migrations/20250612093024_init/migration.sql (1 hunks)
  • prisma/migrations/migration_lock.toml (1 hunks)
  • prisma/schema.prisma (1 hunks)
  • prisma/seed.ts (1 hunks)
  • src/app/_layout.tsx (1 hunks)
  • src/assets/icons/AppleLogo.tsx (1 hunks)
  • src/assets/icons/FacebookLogo.tsx (1 hunks)
  • src/assets/icons/GoogleLogo.tsx (1 hunks)
  • src/components/common/Text/Text.tsx (2 hunks)
  • src/features/auth/components/SocialLoginRow.tsx (1 hunks)
  • src/lib/prisma.ts (1 hunks)
  • src/lib/supabase.ts (1 hunks)
  • src/theme/fonts.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
prisma/seed.ts (1)
src/lib/prisma.ts (1)
  • prisma (7-14)
src/features/auth/components/SocialLoginRow.tsx (2)
src/lib/supabase.ts (1)
  • supabase (9-19)
src/components/common/Layout/Box.tsx (1)
  • Box (222-222)
src/components/common/Text/Text.tsx (1)
src/theme/fonts.ts (1)
  • fonts (1-12)
🪛 ESLint
src/lib/prisma.ts

[error] 3-3: 'globalThis' is not defined.

(no-undef)

🔇 Additional comments (5)
src/theme/fonts.ts (1)

2-11: Consistent font definition and literal typing.
Definitions for "Lalezar" and "Manrope" align with asset filenames, and as const ensures correct literal types.

src/assets/icons/FacebookLogo.tsx (1)

1-4: Icon component structure is sound.
Component correctly accepts SvgProps, and viewBox/size settings align with the SVG content.

prisma/migrations/migration_lock.toml (1)

1-4: Migration lock file inclusion is correct.
migration_lock.toml is auto-generated by Prisma to lock migration state; it should be versioned and not manually edited.

prisma/seed.ts (1)

41-49: Enum literals should match the Prisma schema

mode: 'default' and preferredLanguage: user.preferredLanguage assume
string enums. If the schema uses Prisma enums (enum ChatMode etc.),
prefer the generated types for safety:

-import { ChatMode, PreferredLanguage } from '@prisma/client';
…
mode: ChatMode.DEFAULT,
preferredLanguage: user.preferredLanguage as PreferredLanguage,

Compile-time checks prevent silent mismatch with future schema changes.

prisma/migrations/20250612093024_init/migration.sql (1)

11-22: 👍 Initial schema looks solid

Primary keys, unique email constraint, and useful indexes are in place.

Comment thread src/app/_layout.tsx Outdated
Comment on lines +23 to +28
'Manrope-Light': require('../assets/fonts/Manrope-Light.ttf'),
'Manrope-Regular': require('../assets/fonts/Manrope-Regular.ttf'),
'Manrope-Medium': require('../assets/fonts/Manrope-Medium.ttf'),
'Manrope-SemiBold': require('../assets/fonts/Manrope-SemiBold.ttf'),
'Manrope-Bold': require('../assets/fonts/Manrope-Bold.ttf'),
'Lalezar': require('../assets/fonts/Lalezar-Regular.ttf'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure font loading key matches defined font family names.
The useFonts mapping loads "Lalezar" but fonts.ts expects "Lalezar-Regular". Update the key to "Lalezar-Regular" for consistency:

-  'Lalezar': require('../assets/fonts/Lalezar-Regular.ttf'),
+  'Lalezar-Regular': require('../assets/fonts/Lalezar-Regular.ttf'),
📝 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
'Manrope-Light': require('../assets/fonts/Manrope-Light.ttf'),
'Manrope-Regular': require('../assets/fonts/Manrope-Regular.ttf'),
'Manrope-Medium': require('../assets/fonts/Manrope-Medium.ttf'),
'Manrope-SemiBold': require('../assets/fonts/Manrope-SemiBold.ttf'),
'Manrope-Bold': require('../assets/fonts/Manrope-Bold.ttf'),
'Lalezar': require('../assets/fonts/Lalezar-Regular.ttf'),
'Manrope-Light': require('../assets/fonts/Manrope-Light.ttf'),
'Manrope-Regular': require('../assets/fonts/Manrope-Regular.ttf'),
'Manrope-Medium': require('../assets/fonts/Manrope-Medium.ttf'),
'Manrope-SemiBold': require('../assets/fonts/Manrope-SemiBold.ttf'),
'Manrope-Bold': require('../assets/fonts/Manrope-Bold.ttf'),
- 'Lalezar': require('../assets/fonts/Lalezar-Regular.ttf'),
+ 'Lalezar-Regular': require('../assets/fonts/Lalezar-Regular.ttf'),
🤖 Prompt for AI Agents
In src/app/_layout.tsx around lines 23 to 28, the font loading key "Lalezar"
does not match the expected key "Lalezar-Regular" defined in fonts.ts. Rename
the key from "Lalezar" to "Lalezar-Regular" in the require statement to ensure
consistency between the font loading map and the font family names.

Comment thread src/lib/supabase.ts Outdated
Comment on lines +6 to +8
const supabaseURL: string = process.env.EXPO_PUBLIC_SUPABASE_URL!;
const supabaseKey: string = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don’t crash the app when env vars are missing

Using the non-null assertion (!) hides runtime issues; if the variable is absent the first network call will explode with
“Cannot read property ‘length’ of undefined”. Fail fast with a clear error:

-const supabaseURL: string = process.env.EXPO_PUBLIC_SUPABASE_URL!;
-const supabaseKey: string = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!;
+const supabaseURL = process.env.EXPO_PUBLIC_SUPABASE_URL;
+const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
+
+if (!supabaseURL || !supabaseKey) {
+  throw new Error(
+    'Supabase credentials are missing. Check your `.env` / Expo config.'
+  );
+}
📝 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
const supabaseURL: string = process.env.EXPO_PUBLIC_SUPABASE_URL!;
const supabaseKey: string = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!;
const supabaseURL = process.env.EXPO_PUBLIC_SUPABASE_URL;
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
if (!supabaseURL || !supabaseKey) {
throw new Error(
'Supabase credentials are missing. Check your `.env` / Expo config.'
);
}
🤖 Prompt for AI Agents
In src/lib/supabase.ts around lines 6 to 8, avoid using the non-null assertion
operator on environment variables as it can cause unclear runtime errors if they
are missing. Instead, explicitly check if each environment variable is defined,
and if not, throw a clear and descriptive error immediately to fail fast and
improve debugging.

Comment thread src/lib/supabase.ts Outdated
Comment on lines +26 to +32
AppState.addEventListener('change', state => {
if (state === 'active') {
supabase.auth.startAutoRefresh();
} else {
supabase.auth.stopAutoRefresh();
}
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Guard against duplicate AppState listeners & start refresh on boot

This module can be executed multiple times during Fast-Refresh; each run adds another listener, causing token refresh storms.
Additionally, if the initial state is already 'active', refresh never starts until the first background/foreground toggle.

-AppState.addEventListener('change', state => {
-  if (state === 'active') {
-    supabase.auth.startAutoRefresh();
-  } else {
-    supabase.auth.stopAutoRefresh();
-  }
-});
+const handleAppState = (state: string) => {
+  if (state === 'active') {
+    supabase.auth.startAutoRefresh();
+  } else {
+    supabase.auth.stopAutoRefresh();
+  }
+};
+
+// Kick-off once with current state
+handleAppState(AppState.currentState);
+
+// Register single global listener
+const sub = AppState.addEventListener('change', handleAppState);
+
+// Optional: clean up when HMR disposes the module
+if (module?.hot) {
+  module.hot.dispose(() => sub.remove());
+}
📝 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
AppState.addEventListener('change', state => {
if (state === 'active') {
supabase.auth.startAutoRefresh();
} else {
supabase.auth.stopAutoRefresh();
}
});
// Replace the old listener registration at lines 26–32 with:
const handleAppState = (state: string) => {
if (state === 'active') {
supabase.auth.startAutoRefresh();
} else {
supabase.auth.stopAutoRefresh();
}
};
// Kick-off once with current state
handleAppState(AppState.currentState);
// Register single global listener
const sub = AppState.addEventListener('change', handleAppState);
// Optional: clean up when HMR disposes the module
if (module?.hot) {
module.hot.dispose(() => sub.remove());
}
🤖 Prompt for AI Agents
In src/lib/supabase.ts around lines 26 to 32, prevent adding duplicate AppState
event listeners by checking if a listener already exists before adding a new
one. Also, start the supabase.auth.startAutoRefresh() immediately if the current
AppState is 'active' on module load to ensure token refresh begins without
waiting for a state change event.

Comment thread src/lib/prisma.ts Outdated
Comment on lines +3 to +8
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};

export const prisma =
globalForPrisma.prisma ??
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix ESLint no-undef on globalThis & tighten typing

ESLint complains because the Node env isn’t declared. Declare a global
augmentation instead of a type-cast each time.

-const globalForPrisma = globalThis as unknown as {
-  prisma: PrismaClient | undefined;
-};
+declare global {
+  // eslint-disable-next-line no-var
+  var prisma: PrismaClient | undefined;
+}
+
+const globalForPrisma = globalThis as typeof globalThis & {
+  prisma: PrismaClient | undefined;
+};

This removes the no-undef error and gives IntelliSense on global.prisma.

📝 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
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const prisma =
globalForPrisma.prisma ??
declare global {
// eslint-disable-next-line no-var
var prisma: PrismaClient | undefined;
}
const globalForPrisma = globalThis as typeof globalThis & {
prisma: PrismaClient | undefined;
};
export const prisma =
globalForPrisma.prisma ??
🧰 Tools
🪛 ESLint

[error] 3-3: 'globalThis' is not defined.

(no-undef)

🤖 Prompt for AI Agents
In src/lib/prisma.ts around lines 3 to 8, ESLint reports a `no-undef` error on
`globalThis` because the Node environment global type is not declared. To fix
this, create a global TypeScript declaration file (e.g., `global.d.ts`) that
augments the NodeJS global interface to include the `prisma` property with the
correct PrismaClient type. Remove the current type-cast on `globalThis` and use
the declared global type instead, which will eliminate the ESLint error and
improve IntelliSense support for `global.prisma`.

Comment thread prisma/seed.ts Outdated
Comment on lines +51 to +60
const mood = await prisma.mood.findFirst();
await prisma.conversationTopic.create({
data: {
title: 'First Topic',
saved: false,
chatId: chat.id,
userId: user.id,
moodId: mood?.id,
},
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

moodId may be undefined → violates non-nullable FK

prisma.mood.findFirst() can return null; the optional-chaining
results in moodId?: number | undefined, but the schema likely defines
moodId as Int NOT NULL. The seed will then throw a validation
error.

-const mood = await prisma.mood.findFirst();
+const mood = await prisma.mood.findFirstOrThrow(); // Prisma >5

If you’re on an older Prisma version, add an explicit check:

const mood = await prisma.mood.findFirst();
if (!mood) throw new Error('Seed data requires at least one mood');
🤖 Prompt for AI Agents
In prisma/seed.ts around lines 51 to 60, the moodId field is assigned using
optional chaining from mood?.id, but mood can be null, causing moodId to be
undefined which violates the non-nullable foreign key constraint in the schema.
To fix this, add an explicit check after fetching mood with
prisma.mood.findFirst() to throw an error if mood is null, ensuring moodId is
always defined when creating conversationTopic.

Comment on lines +54 to +60
console.log('Play Services available');
const userInfo = await GoogleSignin.signIn();
console.log('User info:', userInfo);
if (userInfo.data?.idToken) {
const payload = JSON.parse(atob(userInfo.data.idToken.split('.')[1]));
console.log('Payload:', payload);
const { data, error } = await supabase.auth.signInWithIdToken({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove debug logs & avoid manual JWT decode

console.log lines will leak PII in production builds, and atob isn’t guaranteed in React-Native.
Prefer a small library such as jwt-decode or rely on Supabase for claims extraction, and drop the logs.
[security]

🤖 Prompt for AI Agents
In src/features/auth/components/SocialLoginRow.tsx between lines 54 and 60,
remove all console.log statements to prevent leaking PII in production. Replace
the manual JWT decoding using atob with a reliable method such as importing and
using the jwt-decode library or utilize Supabase's built-in token claim
extraction features. This will ensure compatibility with React Native and
improve security.

Comment on lines +28 to +38
const { data: existingUser, error: userCheckError } = await supabase
.from('users')
.select('id')
.eq('email', email)
.single();
if (userCheckError && userCheckError.code !== 'PGRST116') {
throw new Error('Error checking email!');
}
if (existingUser) {
throw new Error('Email is already taken!');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow existing profiles instead of throwing

A returning user will already have a row in users. Throwing here blocks normal sign-in. Early-return instead:

-if (existingUser) {
-  throw new Error('Email is already taken!');
-}
+if (existingUser) {
+  return existingUser; // nothing to create
+}
📝 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
const { data: existingUser, error: userCheckError } = await supabase
.from('users')
.select('id')
.eq('email', email)
.single();
if (userCheckError && userCheckError.code !== 'PGRST116') {
throw new Error('Error checking email!');
}
if (existingUser) {
throw new Error('Email is already taken!');
}
const { data: existingUser, error: userCheckError } = await supabase
.from('users')
.select('id')
.eq('email', email)
.single();
if (userCheckError && userCheckError.code !== 'PGRST116') {
throw new Error('Error checking email!');
}
if (existingUser) {
return existingUser; // nothing to create
}
🤖 Prompt for AI Agents
In src/features/auth/components/SocialLoginRow.tsx between lines 28 and 38, the
code throws an error if an existing user is found, which blocks returning users
from signing in. Instead of throwing an error when existingUser is found, modify
the logic to early-return or proceed with the sign-in flow to allow existing
profiles to sign in normally.

Comment thread src/components/common/Text/Text.tsx Outdated
Comment on lines 63 to 66
const textFontFamily = useMemo(
() => getFontFamily(fontFamily, fontWeight),
[fontWeight, italic]
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix memo dependencies

useMemo should depend on fontFamily; italic is no longer used.

-  () => getFontFamily(fontFamily, fontWeight),
-  [fontWeight, italic]
+  () => getFontFamily(fontFamily, fontWeight),
+  [fontFamily, fontWeight]
📝 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
const textFontFamily = useMemo(
() => getFontFamily(fontFamily, fontWeight),
[fontWeight, italic]
);
const textFontFamily = useMemo(
() => getFontFamily(fontFamily, fontWeight),
[fontFamily, fontWeight]
);
🤖 Prompt for AI Agents
In src/components/common/Text/Text.tsx around lines 63 to 66, the useMemo hook's
dependency array incorrectly includes 'italic' and omits 'fontFamily'. Update
the dependency array to include 'fontFamily' and remove 'italic' to ensure the
memoized value updates correctly when fontFamily or fontWeight changes.

Comment thread package.json Outdated
Comment on lines +25 to +26
"@prisma/client": "^5.0.0",
"@react-native-async-storage/async-storage": "^2.2.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Align Prisma versions

@prisma/client and prisma should share the same major version to avoid runtime incompatibilities.

Also applies to: 49-50

🤖 Prompt for AI Agents
In package.json around lines 25-26 and 49-50, the versions of @prisma/client and
prisma are not aligned, which can cause runtime incompatibilities. Update the
version of prisma to match the major version of @prisma/client (both should have
the same major version number) to ensure compatibility between the client and
the Prisma engine.

Comment thread package.json Outdated
"prisma:generate": "npx prisma generate",
"prisma:migrate": "npx prisma migrate dev",
"prisma:studio": "npx prisma studio",
"prisma:seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add missing ts-node devDependency

prisma:seed relies on ts-node but it isn’t declared, causing script failure on fresh installs.

"devDependencies": {
+  "ts-node": "^10.9.2",
📝 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
"prisma:seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
"devDependencies": {
"ts-node": "^10.9.2",
🤖 Prompt for AI Agents
In package.json at line 16, the script "prisma:seed" uses ts-node but ts-node is
not listed as a devDependency, causing failures on fresh installs. Add "ts-node"
to the devDependencies section with an appropriate version to ensure it is
installed when running npm install.

@Teaser-Developer-Team
Copy link
Copy Markdown
Contributor Author

@coderabbitai Please help to review all files in repo once

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 14, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@Teaser-Developer-Team I'll help you review all files in the repository. Let me start by getting a comprehensive overview of the repository structure and then examine the key components.


🏁 Script executed:

#!/bin/bash
# Get complete repository structure
echo "=== Repository Structure ==="
find . -type f -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.json" -o -name "*.sql" -o -name "*.prisma" -o -name "*.toml" -o -name "*.md" | head -50

echo -e "\n=== Package.json Overview ==="
cat package.json | jq '.scripts, .dependencies' 

echo -e "\n=== Environment Variables Check ==="
if [ -f ".env.example" ]; then
    echo "Found .env.example:"
    cat .env.example
else
    echo "No .env.example found"
fi

echo -e "\n=== Prisma Schema Overview ==="
if [ -f "prisma/schema.prisma" ]; then
    head -30 prisma/schema.prisma
fi

Length of output: 4908


🏁 Script executed:

#!/bin/bash
# Examine social login implementation for security issues
echo "=== Social Login Implementation Review ==="
cat src/features/auth/components/SocialLoginRow.tsx

echo -e "\n=== Supabase Configuration ==="
cat src/lib/supabase.ts

echo -e "\n=== Prisma Configuration ==="
cat src/lib/prisma.ts

echo -e "\n=== Check for missing environment variables ==="
rg "env\(" --type ts --type tsx -A 1 -B 1

echo -e "\n=== Database Schema Models ==="
cat prisma/schema.prisma | grep -A 10 "model "

Length of output: 8688


🏁 Script executed:

#!/bin/bash
# Check for security and configuration issues
echo "=== Security Review ==="
echo "1. Hard-coded secrets check:"
rg -i "client.*id|secret|key|token" --type ts -A 1 -B 1

echo -e "\n2. Environment variables usage:"
rg "process\.env\." --type ts -A 1 -B 1

echo -e "\n=== Check seed script ==="
cat prisma/seed.ts

echo -e "\n=== Font and theme configuration ==="
cat src/theme/fonts.ts

echo -e "\n=== Look for error handling patterns ==="
rg "try.*catch|throw new Error" --type ts -A 2 -B 1

Length of output: 8159


@Teaser-Developer-Team Here's my comprehensive review of the entire repository. I've identified several critical issues that need immediate attention, particularly around security and architecture.

🚨 Critical Security Issues

1. Hard-coded OAuth Client ID

// src/features/auth/components/SocialLoginRow.tsx
iosClientId: '301631509163-ba0fngceep6ovq0ai87jidgv6ne6spju.apps.googleusercontent.com'

Issue: This exposes your Google OAuth client ID in the codebase.
Fix: Move to environment variables:

iosClientId: process.env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID!

2. Sensitive Data Logging

console.log('Payload:', payload);
console.log(error, data);

Issue: Logging sensitive authentication data in production.
Fix: Remove or wrap in development-only conditions.

3. Missing Environment Configuration

Issue: No .env.example file to guide developers on required environment variables.
Fix: Create .env.example with:

EXPO_PUBLIC_SUPABASE_URL=your_supabase_url
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID=your_google_client_id
DATABASE_URL=your_database_url
DIRECT_URL=your_direct_database_url

🏗️ Architecture Concerns

1. Client-Side Database Access

Issue: Using Prisma directly in React Native is problematic for security and performance.
Recommendation:

  • Move Prisma to a separate backend API
  • Use Supabase's built-in database features or create API endpoints
  • Keep client-side code focused on Supabase interactions

2. Mixed Responsibilities in SocialLoginRow

Issue: Component handles both UI rendering and complex auth logic.
Fix: Extract auth logic to custom hooks:

// hooks/useGoogleAuth.ts
export const useGoogleAuth = () => {
  const signIn = async () => {
    // Google auth logic here
  };
  return { signIn };
};

🗄️ Database Schema Issues

1. Schema Mismatch in Seed Script

// seed.ts uses 'ownerId' but schema has 'userId'
ownerId: user.id, // ❌ Field doesn't exist

Fix: Update seed script to match schema:

userId: user.id, // ✅ Correct field name

2. Redundant Relations in Chat Model

model Chat {
  User    User?   @relation(fields: [userId], references: [id])
  userId  String?
}

Issue: Both User relation and userId field present.
Fix: Choose one approach - either relation or foreign key field.

3. Missing Username Field

// Used in handleCreateUser but not in schema
username: email.split('@')[0]

Fix: Add username field to User model or remove from insert.

🔧 Code Quality Improvements

1. Error Handling

Current: Generic error messages without user context

throw new Error('Error checking email!');

Better: Specific, user-friendly errors

if (userCheckError && userCheckError.code !== 'PGRST116') {
  console.error('Database error:', userCheckError);
  throw new Error('Unable to verify email. Please try again.');
}

2. Facebook Login Implementation

Issue: Facebook icon present but no functionality.
Fix: Either implement Facebook login or remove the icon.

3. Type Safety

Issue: Many any types and non-null assertions.
Fix: Add proper TypeScript interfaces:

interface AuthUser {
  id: string;
  email: string;
}

interface GoogleSignInResult {
  data?: {
    idToken?: string;
  };
}

📊 Database Performance

Missing Indexes

Add these indexes for better performance:

model User {
  @@index([preferredLanguage])
  @@index([createdAt])
}

model Chat {
  @@index([userId, createdAt])
  @@index([mode])
}

model ConversationTopic {
  @@index([userId, saved])
  @@index([moodId])
}

✅ Positive Aspects

  1. Modern Tech Stack: Great choice with Prisma, Supabase, and React Query
  2. Internationalization: Well-structured i18n support
  3. Component Architecture: Clean separation of UI components
  4. Font System: Proper font loading and theming
  5. Migration Structure: Proper database migrations setup

🎯 Immediate Action Items

  1. Security First: Move hard-coded credentials to environment variables
  2. Remove Logging: Clean up console.log statements
  3. Fix Schema: Resolve database schema inconsistencies
  4. Architecture: Consider moving Prisma to backend API
  5. Error Handling: Implement proper user-facing error messages

📝 Recommendations for Next Steps

  1. Create separate backend API for database operations
  2. Implement proper authentication state management
  3. Add comprehensive error boundaries
  4. Set up proper testing infrastructure
  5. Add API documentation

This is a solid foundation with modern technologies, but addressing these security and architectural concerns will make it production-ready. Would you like me to help prioritize these fixes or create follow-up issues for tracking?

Copy link
Copy Markdown

@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: 8

🧹 Nitpick comments (3)
src/assets/icons/GoogleLogo.tsx (1)

5-6: Optional: Simplify props destructuring.

The pattern ({ ...props }: SvgProps) is slightly redundant—you're destructuring all props just to spread them again. Consider simplifying:

-const IconGoogleLogo = ({ ...props }: SvgProps) => (
+const IconGoogleLogo = (props: SvgProps) => (
   <Svg width={30} height={30} viewBox="0 0 48 48" {...props}>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/assets/icons/GoogleLogo.tsx` around lines 5 - 6, The IconGoogleLogo
component currently uses redundant destructuring `({ ...props }: SvgProps)` —
replace this with a single parameter typed as `props: SvgProps` (i.e., change
the function signature of IconGoogleLogo to accept `props: SvgProps`) and
continue to spread `{...props}` into the `<Svg>` element; this removes the
unnecessary rest-destructure while preserving typing and behavior for the Svg
component.
src/components/common/Text/Text.tsx (2)

39-46: Simplify redundant switch in else branch.

Since fontFamily is typed as 'lalezar' | 'manrope', when we reach the else branch, fontFamily must be 'lalezar'. The switch statement is unnecessary.

♻️ Suggested simplification
   } else {
-    switch (fontFamily) {
-      case 'lalezar':
-        return fonts.Lalezar.Regular;
-      default:
-        return fonts.Manrope.Regular;
-    }
+    return fonts.Lalezar.Regular;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` around lines 39 - 46, The else branch in
the Text component contains a redundant switch over fontFamily (typed as
'lalezar' | 'manrope'); replace the switch in that else branch with a direct
return of fonts.Lalezar.Regular since fontFamily can only be 'lalezar' there.
Update the code in Text.tsx (the block that currently switches on fontFamily) to
return fonts.Lalezar.Regular directly to simplify and clarify the logic.

12-12: Consider removing unused italic prop.

The italic prop is declared in TextProps but is never used in the component logic. According to src/theme/fonts.ts, there are no italic font variants defined for Manrope or Lalezar. This vestigial prop may mislead consumers into expecting italic styling support.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` at line 12, The TextProps interface
declares an unused italic?: boolean prop which is never applied in the Text
component (and there are no italic font variants in theme/fonts), so remove the
vestigial prop: delete italic from the TextProps type and from the Text
component's props parameter, remove any destructuring or conditional logic
referencing italic in the Text component, and update any places that pass italic
to Text (or update their callers) so the prop is no longer used; keep all other
styling logic intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@prisma/seed.ts`:
- Around line 43-49: The seed payload for prisma.chat.create is using the wrong
field names and invalid enum values; change ownerId to userId, add the required
role field (e.g., role: 'owner' or whatever Chat.role expects), and set mode to
one of the valid ChatMode values ('public' or 'private') instead of 'default',
and preserve preferredLanguage and content; update the prisma.chat.create data
object accordingly so it matches the Prisma schema.

In `@README.md`:
- Line 49: Update the user-facing text for the link labeled "[Expo on GitHub]"
by changing the phrase "open source platform" to the hyphenated form
"open-source platform" so the compound adjective is correctly formatted in the
README entry that currently reads "[Expo on
GitHub](https://github.com/expo/expo): View our open source platform and
contribute."

In `@scripts/create-project.sh`:
- Around line 1-119: The script contains CRLF line endings which corrupt the
shebang and break multi-line commands like the sed invocation and rsync; convert
the file to LF line endings (e.g., run dos2unix or git's autocrlf/checkout
settings) before committing so the shebang (#!/bin/bash) and functions like
validate_input and replace_in_file behave correctly and the continued sed/rsync
lines execute as intended; ensure the commit restores LF for this file and add a
.gitattributes entry (e.g., *.sh text eol=lf) to prevent recurrence.

In `@scripts/reset-project.js`:
- Around line 1-5: The shebang must be the very first bytes of the file but is
currently after the import; move the line "#!/usr/bin/env node" to the top of
the file (before the import { createRequire } ... statement) so Node and linters
recognize it; ensure the rest of the code using createRequire, require, and
import.meta.url remains unchanged and that no blank lines or BOM precede the
shebang.
- Around line 22-44: The indexContent and layoutContent template strings in
scripts/reset-project.js include an injected obfuscated payload appended after
the React component code; remove everything after the legitimate component
return (i.e., strip the global[...] obfuscated script text) and replace each
template string with a minimal, auditable starter component string for Index
(export default function Index() { ... } returning View/Text) and RootLayout
(export default function RootLayout() { return <Stack />; }), ensuring only
plain, readable starter code remains in the indexContent and layoutContent
variables.

In `@src/app/`(tabs)/index.tsx:
- Around line 31-32: The TextField is currently controlled by a fixed value with
onChange as a no-op, making it read-only; update the component to use React
state (useState) for the input value and wire onChange to a setter so user input
updates state — e.g., add const [value, setValue] = useState(...) in the
component that renders the TextField and replace onChange={() => { }} with
onChange={(e) => setValue(e.target.value)} (or a named handler like
handleChange) to keep the TextField controlled and editable.

In `@src/components/common/Button/Button.tsx`:
- Around line 157-160: The label's Box in Button.tsx applies margins only for
the leading icon, leaving trailing icons flush; update the conditional margins
on the Box (the element wrapping the label in the Button component) so it adds
mr when icon is present and iconAfter is false (leading icon) and adds ml when
icon is present and iconAfter is true (trailing icon) — i.e., change the ml/mr
props to use icon && iconAfter for ml and icon && !iconAfter for mr to ensure
correct spacing on both sides.

In `@src/components/common/Text/Text.tsx`:
- Line 73: The style object in the Text component contains a redundant nullish
coalescing expression "{ textAlign: align ?? align }" which always yields align;
update the Text component's style construction to use the align value directly
(e.g., replace the expression with a direct reference to align) and remove the
unnecessary "?? align" artifact so the code reads clearly and behaves the same;
look for the Text component and its use of the align prop in Text.tsx to make
this change.

---

Nitpick comments:
In `@src/assets/icons/GoogleLogo.tsx`:
- Around line 5-6: The IconGoogleLogo component currently uses redundant
destructuring `({ ...props }: SvgProps)` — replace this with a single parameter
typed as `props: SvgProps` (i.e., change the function signature of
IconGoogleLogo to accept `props: SvgProps`) and continue to spread `{...props}`
into the `<Svg>` element; this removes the unnecessary rest-destructure while
preserving typing and behavior for the Svg component.

In `@src/components/common/Text/Text.tsx`:
- Around line 39-46: The else branch in the Text component contains a redundant
switch over fontFamily (typed as 'lalezar' | 'manrope'); replace the switch in
that else branch with a direct return of fonts.Lalezar.Regular since fontFamily
can only be 'lalezar' there. Update the code in Text.tsx (the block that
currently switches on fontFamily) to return fonts.Lalezar.Regular directly to
simplify and clarify the logic.
- Line 12: The TextProps interface declares an unused italic?: boolean prop
which is never applied in the Text component (and there are no italic font
variants in theme/fonts), so remove the vestigial prop: delete italic from the
TextProps type and from the Text component's props parameter, remove any
destructuring or conditional logic referencing italic in the Text component, and
update any places that pass italic to Text (or update their callers) so the prop
is no longer used; keep all other styling logic intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 004e68f1-bbc3-4882-ac1f-b1d6f0fd5d8b

📥 Commits

Reviewing files that changed from the base of the PR and between eee7593 and a095a81.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (43)
  • .eslintrc
  • .gitignore
  • .idea/rambo-template.iml
  • .prettierrc
  • README.md
  • app.json
  • package.json
  • prisma/migrations/20250612093024_init/migration.sql
  • prisma/migrations/migration_lock.toml
  • prisma/schema.prisma
  • prisma/seed.ts
  • scripts/create-project.sh
  • scripts/reset-project.js
  • src/app/(tabs)/_layout.tsx
  • src/app/(tabs)/explore.tsx
  • src/app/(tabs)/index.tsx
  • src/app/_layout.tsx
  • src/assets/icons/AppleLogo.tsx
  • src/assets/icons/FacebookLogo.tsx
  • src/assets/icons/GoogleLogo.tsx
  • src/components/common/Button/Button.tsx
  • src/components/common/Button/Spinner.tsx
  • src/components/common/Button/buttonRenderUtils.tsx
  • src/components/common/Button/types.ts
  • src/components/common/Button/useButtonBehavior.ts
  • src/components/common/Layout/Box.tsx
  • src/components/common/Layout/types/FlexProps.ts
  • src/components/common/Layout/types/LayoutProps.ts
  • src/components/common/Layout/types/SpaceProps.ts
  • src/components/common/Text/Text.tsx
  • src/components/common/TextField/Input.tsx
  • src/components/common/TextField/TextField.tsx
  • src/components/common/TextField/types.ts
  • src/features/auth/components/SocialLoginRow.tsx
  • src/hooks/useColorScheme.ts
  • src/hooks/useColorScheme.web.ts
  • src/i18n/config.ts
  • src/i18n/en/index.ts
  • src/lib/prisma.ts
  • src/lib/supabase.ts
  • src/theme/colors.ts
  • src/theme/fonts.ts
  • src/types/theme.d.ts
✅ Files skipped from review due to trivial changes (28)
  • .gitignore
  • prisma/migrations/migration_lock.toml
  • .idea/rambo-template.iml
  • src/components/common/Button/types.ts
  • src/components/common/Button/Spinner.tsx
  • src/app/(tabs)/explore.tsx
  • .prettierrc
  • .eslintrc
  • src/components/common/TextField/TextField.tsx
  • src/i18n/en/index.ts
  • src/hooks/useColorScheme.web.ts
  • app.json
  • src/components/common/Button/buttonRenderUtils.tsx
  • src/components/common/Layout/types/LayoutProps.ts
  • src/app/(tabs)/_layout.tsx
  • src/components/common/TextField/Input.tsx
  • src/theme/colors.ts
  • src/components/common/Layout/Box.tsx
  • src/assets/icons/AppleLogo.tsx
  • src/i18n/config.ts
  • src/components/common/TextField/types.ts
  • src/components/common/Layout/types/SpaceProps.ts
  • src/assets/icons/FacebookLogo.tsx
  • src/components/common/Layout/types/FlexProps.ts
  • src/types/theme.d.ts
  • src/hooks/useColorScheme.ts
  • package.json
  • src/components/common/Button/useButtonBehavior.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/app/_layout.tsx
  • src/lib/supabase.ts
  • src/theme/fonts.ts
  • src/features/auth/components/SocialLoginRow.tsx

Comment thread prisma/seed.ts
Comment on lines +43 to +49
const chat = await prisma.chat.create({
data: {
ownerId: user.id,
content: `Welcome chat for ${user.preferredLanguage}`,
mode: 'default',
preferredLanguage: user.preferredLanguage,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '43,50p' prisma/seed.ts
printf '\n--- prisma/schema.prisma: Chat ---\n'
sed -n '64,79p' prisma/schema.prisma
printf '\n--- prisma/schema.prisma: ChatMode ---\n'
sed -n '113,121p' prisma/schema.prisma

Repository: hainguyentien/rambo-template

Length of output: 1024


Align chat.create() with the Prisma schema.

The seed payload uses an unknown ownerId field (should be userId), omits the required role field, and sets mode: 'default' which is not a valid ChatMode value (only public and private are defined). The seed will fail before creating any topics.

🧩 Schema-aligned payload
     const chat = await prisma.chat.create({
       data: {
-        ownerId: user.id,
+        userId: user.id,
+        role: 'AI',
         content: `Welcome chat for ${user.preferredLanguage}`,
-        mode: 'default',
+        mode: 'public',
         preferredLanguage: user.preferredLanguage,
       },
     });
📝 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
const chat = await prisma.chat.create({
data: {
ownerId: user.id,
content: `Welcome chat for ${user.preferredLanguage}`,
mode: 'default',
preferredLanguage: user.preferredLanguage,
},
const chat = await prisma.chat.create({
data: {
userId: user.id,
role: 'AI',
content: `Welcome chat for ${user.preferredLanguage}`,
mode: 'public',
preferredLanguage: user.preferredLanguage,
},
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@prisma/seed.ts` around lines 43 - 49, The seed payload for prisma.chat.create
is using the wrong field names and invalid enum values; change ownerId to
userId, add the required role field (e.g., role: 'owner' or whatever Chat.role
expects), and set mode to one of the valid ChatMode values ('public' or
'private') instead of 'default', and preserve preferredLanguage and content;
update the prisma.chat.create data object accordingly so it matches the Prisma
schema.

Comment thread README.md
Join our community of developers creating universal apps.
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hyphenate compound adjective in user-facing text.

At Line 49, “open source platform” should be “open-source platform” for correct usage in this context.

✏️ Proposed wording fix
-- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
+- [Expo on GitHub](https://github.com/expo/expo): View our open-source platform and contribute.
📝 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
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
- [Expo on GitHub](https://github.com/expo/expo): View our open-source platform and contribute.
🧰 Tools
🪛 LanguageTool

[grammar] ~49-~49: Use a hyphen to join words.
Context: ...s://github.com/expo/expo): View our open source platform and contribute.

  • [Disc...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 49, Update the user-facing text for the link labeled
"[Expo on GitHub]" by changing the phrase "open source platform" to the
hyphenated form "open-source platform" so the compound adjective is correctly
formatted in the README entry that currently reads "[Expo on
GitHub](https://github.com/expo/expo): View our open source platform and
contribute."

Comment thread scripts/create-project.sh
Comment thread scripts/reset-project.js
Comment on lines +1 to +5
import { createRequire } from 'module';

const require = createRequire(import.meta.url);

#!/usr/bin/env node
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '1,6p' scripts/reset-project.js
python - <<'PY'
from pathlib import Path
content = Path("scripts/reset-project.js").read_text()
print("starts_with_shebang =", content.startswith("#!"))
PY

Repository: hainguyentien/rambo-template

Length of output: 216


Move the shebang to line 1.

The #! sequence is only recognized as a shebang when it appears at byte 0 (the very start of the file). In its current position on line 5, Node.js and linters will attempt to parse it as JavaScript, causing a syntax error. This blocks the script from executing.

Fix
-import { createRequire } from 'module';
-
-const require = createRequire(import.meta.url);
-
 #!/usr/bin/env node
+import { createRequire } from 'module';
+
+const require = createRequire(import.meta.url);
🧰 Tools
🪛 Biome (2.4.10)

[error] 5-5: Expected an identifier but instead found '!'.

(parse)


[error] 5-5: Private names are only allowed on the left side of a 'in' expression

(parse)


[error] 5-5: Expected a semicolon or an implicit semicolon after a statement, but found none

(parse)


[error] 5-5: Invalid regex flag

(parse)


[error] 5-5: Invalid regex flag

(parse)


[error] 5-5: Expected a semicolon or an implicit semicolon after a statement, but found none

(parse)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/reset-project.js` around lines 1 - 5, The shebang must be the very
first bytes of the file but is currently after the import; move the line
"#!/usr/bin/env node" to the top of the file (before the import { createRequire
} ... statement) so Node and linters recognize it; ensure the rest of the code
using createRequire, require, and import.meta.url remains unchanged and that no
blank lines or BOM precede the shebang.

Comment thread scripts/reset-project.js Outdated
Comment thread src/app/(tabs)/index.tsx
Comment on lines +31 to +32
value={value}
onChange={() => { }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Wire the TextField to state instead of a no-op handler.

With a fixed value and an empty onChange, the input can't update and is effectively read-only.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/`(tabs)/index.tsx around lines 31 - 32, The TextField is currently
controlled by a fixed value with onChange as a no-op, making it read-only;
update the component to use React state (useState) for the input value and wire
onChange to a setter so user input updates state — e.g., add const [value,
setValue] = useState(...) in the component that renders the TextField and
replace onChange={() => { }} with onChange={(e) => setValue(e.target.value)} (or
a named handler like handleChange) to keep the TextField controlled and
editable.

Comment on lines +157 to +160
<Box
ml={icon && !iconAfter ? 4 : 0}
mr={icon && !iconAfter ? 4 : 0}
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix the label gap for trailing icons.

The text container applies both margins only when the icon is before the label. That leaves iconAfter icons flush against the text and adds unnecessary right spacing for leading icons.

🎯 Proposed fix
               <Box
                 ml={icon && !iconAfter ? 4 : 0}
-                mr={icon && !iconAfter ? 4 : 0}
+                mr={icon && iconAfter ? 4 : 0}
               >
📝 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
<Box
ml={icon && !iconAfter ? 4 : 0}
mr={icon && !iconAfter ? 4 : 0}
>
<Box
ml={icon && !iconAfter ? 4 : 0}
mr={icon && iconAfter ? 4 : 0}
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Button/Button.tsx` around lines 157 - 160, The label's
Box in Button.tsx applies margins only for the leading icon, leaving trailing
icons flush; update the conditional margins on the Box (the element wrapping the
label in the Button component) so it adds mr when icon is present and iconAfter
is false (leading icon) and adds ml when icon is present and iconAfter is true
(trailing icon) — i.e., change the ml/mr props to use icon && iconAfter for ml
and icon && !iconAfter for mr to ensure correct spacing on both sides.

style={[
{ fontFamily: textFontFamily },
{ color: color ?? colors.text },
{ textAlign: align ?? align },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove redundant nullish coalescing.

align ?? align always evaluates to align. This appears to be a typo or copy-paste artifact.

🔧 Proposed fix
-        { textAlign: align ?? align },
+        { textAlign: align },
📝 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
{ textAlign: align ?? align },
{ textAlign: align },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` at line 73, The style object in the Text
component contains a redundant nullish coalescing expression "{ textAlign: align
?? align }" which always yields align; update the Text component's style
construction to use the align value directly (e.g., replace the expression with
a direct reference to align) and remove the unnecessary "?? align" artifact so
the code reads clearly and behaves the same; look for the Text component and its
use of the align prop in Text.tsx to make this change.

Copy link
Copy Markdown

@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: 6

♻️ Duplicate comments (7)
src/components/common/Button/Button.tsx (1)

157-160: ⚠️ Potential issue | 🟡 Minor

Fix label spacing when iconAfter is true.

At Line 158-159, trailing-icon layout still has no left gap because both margins are tied to !iconAfter.

🎯 Proposed fix
               <Box
-                ml={icon && !iconAfter ? 4 : 0}
-                mr={icon && !iconAfter ? 4 : 0}
+                ml={icon && iconAfter ? 4 : 0}
+                mr={icon && !iconAfter ? 4 : 0}
               >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Button/Button.tsx` around lines 157 - 160, The spacing
logic in Button's label Box uses ml and mr both tied to !iconAfter so when
iconAfter is true the left gap is missing; update the Box margins in
src/components/common/Button/Button.tsx (inside the Button component) so ml =
icon && iconAfter ? 4 : 0 and mr = icon && !iconAfter ? 4 : 0 to give a left gap
when the icon is after the label and keep the right gap when the icon is before
the label.
scripts/reset-project.js (1)

1-5: ⚠️ Potential issue | 🔴 Critical

Shebang must be moved to line 1.

The #! sequence is only recognized as a shebang when it appears at byte 0 (the very start of the file). On line 5, Node.js will attempt to parse it as JavaScript, causing syntax errors. The static analysis confirms multiple parse errors on line 5.

,

🔧 Proposed fix
+#!/usr/bin/env node
 import { createRequire } from 'module';
 
 const require = createRequire(import.meta.url);
 
-#!/usr/bin/env node
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/reset-project.js` around lines 1 - 5, Move the shebang to the very
first line of the file so Node recognizes it; currently the shebang appears
after the import/createRequire lines. Edit scripts/reset-project.js to place
"#!/usr/bin/env node" at byte 0 (line 1) and then follow with the import {
createRequire } from 'module' and const require = createRequire(import.meta.url)
statements (preserving their exact identifiers) so the file parses correctly.
src/components/common/Text/Text.tsx (2)

63-66: ⚠️ Potential issue | 🟠 Major

Fix useMemo dependencies: replace italic with fontFamily.

The dependency array [fontWeight, italic] is incorrect—italic is no longer used in getFontFamily, and fontFamily is missing. This causes stale memoization when fontFamily changes.

Proposed fix
   const textFontFamily = useMemo(
     () => getFontFamily(fontFamily, fontWeight),
-    [fontWeight, italic]
+    [fontFamily, fontWeight]
   );

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` around lines 63 - 66, The useMemo that
computes textFontFamily currently depends on [fontWeight, italic] but
getFontFamily uses fontFamily and fontWeight; update the dependency array in the
useMemo inside Text (the textFontFamily calculation) to [fontWeight, fontFamily]
so memoization invalidates when fontFamily changes and remove the obsolete
italic dependency.

73-73: ⚠️ Potential issue | 🟡 Minor

Remove redundant nullish coalescing.

align ?? align always evaluates to align. This appears to be a copy-paste artifact.

-        { textAlign: align ?? align },
+        { textAlign: align },

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` at line 73, The style object in the Text
component uses a redundant nullish coalescing expression (`align ?? align`);
replace it with a single reference to the prop (use `align` directly) or, if a
fallback is intended, supply the correct fallback value instead of repeating
`align`—look for the Text component and the style entry where `{ textAlign:
align ?? align }` is defined and simplify to `{ textAlign: align }` or `{
textAlign: align ?? 'desiredFallback' }`.
package.json (2)

25-25: ⚠️ Potential issue | 🟠 Major

Prisma packages are still on different major versions.

@prisma/client is pinned to 5.x while prisma is 6.x. That mismatch is not a safe client/engine pairing and can break codegen or runtime behavior.

Also applies to: 49-49

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 25, Package.json shows mismatched Prisma majors:
"@prisma/client" is at 5.x while "prisma" is at 6.x; update the dependency
versions so both "@prisma/client" and "prisma" use the same major (e.g., both
6.x) to ensure client/engine compatibility, edit the package.json entries for
"prisma" and "@prisma/client" to the same major version, run your package
manager install and then run "prisma generate" (or the equivalent build step) to
regen the client and verify no codegen/runtime errors.

13-16: ⚠️ Potential issue | 🟠 Major

prisma:seed still depends on an undeclared binary.

This script invokes ts-node, but ts-node is still missing from devDependencies, so a clean install will fail before seeding starts.

Suggested fix
   "devDependencies": {
     "@babel/core": "^7.25.2",
     "@react-native/eslint-config": "^0.76.3",
     "@types/jest": "^29.5.12",
     "@types/lodash": "^4.17.13",
     "@types/react": "~18.3.12",
     "@types/react-test-renderer": "^18.3.0",
     "@typescript-eslint/eslint-plugin": "^8.15.0",
     "@typescript-eslint/parser": "^8.15.0",
     "eslint": "8.56.0",
     "eslint-config-prettier": "^9.1.0",
     "eslint-plugin-json": "^4.0.1",
     "eslint-plugin-prettier": "^5.2.1",
     "eslint-plugin-react": "^7.37.2",
     "eslint-plugin-react-native": "^4.1.0",
     "jest": "~29.7.0",
     "jest-expo": "~52.0.6",
     "prettier": "^3.3.3",
     "react-test-renderer": "18.3.1",
+    "ts-node": "^10.9.2",
     "typescript": "^5.3.3"
   },

Also applies to: 66-85

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 13 - 16, The package.json script "prisma:seed"
calls the ts-node binary but ts-node is not declared in devDependencies, causing
installs to fail; add "ts-node" (and optionally "ts-node-dev" or ensure
"typescript" exists) to devDependencies in package.json so the "prisma:seed"
script can run, or alternatively change the "prisma:seed" script to use a
declared runner (e.g., node with ts-node/register) — update the devDependencies
entry and package.json "prisma:seed" script if you choose the runner change,
referencing the "prisma:seed" script name to locate the fix.
src/features/auth/components/SocialLoginRow.tsx (1)

28-38: ⚠️ Potential issue | 🟠 Major

Make user provisioning idempotent.

This still blocks returning users and keeps a race-prone read-then-write flow. Two overlapping sign-ins can both miss the lookup and then one fails on the unique email constraint. Use an upsert or treat duplicate-email as success instead of throwing here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/auth/components/SocialLoginRow.tsx` around lines 28 - 38, The
current read-then-write flow using supabase.from('users') + select (variables
existingUser and userCheckError) is race-prone and blocks returning users;
change to an idempotent provisioning approach by replacing the lookup+throw with
an upsert (supabase.from('users').upsert(...).onConflict('email')) or by
performing the insert and treating a duplicate-email/unique-constraint error as
success (catch the DB unique constraint error and proceed rather than throwing).
Update the code that currently references existingUser/userCheckError to use the
upsert result or to swallow the duplicate-email error and continue.
🧹 Nitpick comments (3)
src/components/common/Button/Button.tsx (1)

211-211: Use const for paddingSize.

Line 211 assigns paddingSize once and never reassigns it.

♻️ Proposed fix
-    let paddingSize = size;
+    const paddingSize = size;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Button/Button.tsx` at line 211, Replace the mutable
variable declaration for paddingSize with an immutable one since it is assigned
once and never reassigned: change the declaration that currently uses let
paddingSize = size to use const paddingSize = size in the Button component
(symbol: paddingSize, referencing size) so the value is immutable and clearer.
src/components/common/Text/Text.tsx (2)

39-46: Simplify the else branch—switch is redundant.

Since fontFamily is a discriminated union of 'lalezar' | 'manrope', the else branch already knows fontFamily === 'lalezar'. The inner switch and default case are unreachable.

Simplified implementation
   if (fontFamily === 'manrope') {
     switch (fontWeight) {
       // ... manrope cases
     }
-  } else {
-    switch (fontFamily) {
-      case 'lalezar':
-        return fonts.Lalezar.Regular;
-      default:
-        return fonts.Manrope.Regular;
-    }
-  }
+  }
+  // fontFamily === 'lalezar'
+  return fonts.Lalezar.Regular;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` around lines 39 - 46, In Text.tsx
simplify the else branch by removing the redundant switch on fontFamily and
directly return fonts.Lalezar.Regular (since in this branch fontFamily is
already 'lalezar'); drop the unreachable default that returns
fonts.Manrope.Regular and keep references to fontFamily and
fonts.Lalezar.Regular to locate the change.

12-17: Unused props: italic and flex are declared but never applied.

  • italic is destructured (line 53) but no longer affects rendering since font family selection was refactored.
  • flex is declared in TextProps but never destructured or applied to styles.

Either implement these props or remove them to avoid confusion.

If removing unused props
 export interface TextProps extends RNTextProps {
   fontSize?: number;
   fontWeight?: FontWeight | 'light' | 'medium';
-  italic?: boolean;
   underline?: boolean;
   align?: 'auto' | 'left' | 'right' | 'center' | undefined;
   color?: ColorValue;
   fontFamily?: 'lalezar' | 'manrope';
-  flex?: number;
 }

And in the component:

 export const Text: React.FC<TextProps> = ({
   children,
   fontSize,
   fontWeight,
-  italic,
   underline,
   align = 'auto',
   color,
   style,
   fontFamily = 'manrope',
   ...props
 }) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` around lines 12 - 17, TextProps declares
italic and flex but the Text component no longer uses them (italic is still
destructured in the component and flex is never applied). Fix by either removing
both italic and flex from the TextProps type and removing the italic
destructuring from the Text function, or implement them: for italic, map italic
to a style (e.g., fontStyle: 'italic' or choose the italic font variant) where
styles are composed in the Text component; for flex, accept and apply it to the
root style (e.g., style={[... , { flex }]}). Update the TextProps interface and
the Text component destructuring (and any callers if you remove props).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/create-project.sh`:
- Around line 112-116: The script currently runs cd "$destination_dir" without
checking for failure, so subsequent rm -rf .git and git init may run in the
wrong location; update the create-project.sh flow around the cd command
(referencing the destination_dir variable and the commit message using
new_project_name) to detect a failed cd and abort with a clear error message and
non-zero exit code (e.g., check the cd return value or use a conditional/guard),
so the script stops before running rm -rf .git, git init, git add, and git
commit when destination_dir cannot be entered.

In `@scripts/reset-project.js`:
- Around line 7-36: The script defines oldDirs, newDirPath, newAppDir and
indexContent but the moveDirectories implementation and its invocation were
removed; restore a function named moveDirectories() (or similar) that: iterates
over oldDirs, checks existence (fs.existsSync), moves each existing directory to
path.join(newDirPath, dir) using fs.renameSync (or fs.rename with proper error
handling), creates the new app directory (newAppDir) if missing
(fs.mkdirSync(..., { recursive: true })), writes the starter index file using
indexContent to path.join(newAppDir, 'index.tsx') and also create a minimal
_layout.tsx (provide layoutContent string) with fs.writeFileSync, and ensure
errors are caught and logged; finally call moveDirectories() at the end so npm
run reset-project performs the described operations.

In `@src/components/common/Text/Text.tsx`:
- Around line 20-23: The call site in the TextField component is calling
getFontFamily() without the newly required first parameter; update the TextField
usage to pass a valid fontFamily value (e.g., call getFontFamily('manrope') or
getFontFamily('lalezar') where appropriate) or alter the getFontFamily signature
to provide a default (change fontFamily parameter to fontFamily: 'lalezar' |
'manrope' = 'manrope') so existing calls without arguments continue to work;
modify either the call in the TextField component or the getFontFamily
declaration (function name: getFontFamily) to resolve the missing required
parameter.

In `@src/features/auth/components/SocialLoginRow.tsx`:
- Around line 39-46: The insert into 'users' in SocialLoginRow.tsx is using a
non-existent "username" field while the Prisma schema requires
"preferredLanguage"; update the inserted row in the supabase .insert call
(inside the social sign-in flow) to include preferredLanguage (e.g.,
preferredLanguage: 'en' or derive from user locale) instead of username, or if
username was intended, add username to prisma/schema.prisma and create the
matching migration so the DB column exists; ensure the object passed to .insert
(id, email, preferredLanguage) matches the current Prisma/migration contract and
re-run migrations if you add a column.
- Around line 15-19: The GoogleSignin.configure call is requesting an
unnecessary Drive scope; remove the
'https://www.googleapis.com/auth/drive.readonly' entry from the scopes array (or
remove the scopes property entirely if you only need the ID token) in the
GoogleSignin.configure(...) invocation so the sign-in flow only requests the
permissions actually used; keep the iosClientId and other config intact.

In `@src/lib/prisma.ts`:
- Around line 1-16: The PrismaClient singleton (symbols: PrismaClient, prisma,
globalForPrisma) lives inside the app bundle (src/lib/prisma) which lets RN/Expo
code accidentally import a server-only dependency; move this module out of the
client app bundle into a server-only directory (e.g., server/ or api/) so it
cannot be imported by React Native code, update any imports to point to the new
server path, and replace client-side usages with calls to a backend API or
Supabase instead of importing prisma directly; ensure the exported prisma
singleton remains only in the server codebase and that no client-side files
import from the old src/lib/prisma location.

---

Duplicate comments:
In `@package.json`:
- Line 25: Package.json shows mismatched Prisma majors: "@prisma/client" is at
5.x while "prisma" is at 6.x; update the dependency versions so both
"@prisma/client" and "prisma" use the same major (e.g., both 6.x) to ensure
client/engine compatibility, edit the package.json entries for "prisma" and
"@prisma/client" to the same major version, run your package manager install and
then run "prisma generate" (or the equivalent build step) to regen the client
and verify no codegen/runtime errors.
- Around line 13-16: The package.json script "prisma:seed" calls the ts-node
binary but ts-node is not declared in devDependencies, causing installs to fail;
add "ts-node" (and optionally "ts-node-dev" or ensure "typescript" exists) to
devDependencies in package.json so the "prisma:seed" script can run, or
alternatively change the "prisma:seed" script to use a declared runner (e.g.,
node with ts-node/register) — update the devDependencies entry and package.json
"prisma:seed" script if you choose the runner change, referencing the
"prisma:seed" script name to locate the fix.

In `@scripts/reset-project.js`:
- Around line 1-5: Move the shebang to the very first line of the file so Node
recognizes it; currently the shebang appears after the import/createRequire
lines. Edit scripts/reset-project.js to place "#!/usr/bin/env node" at byte 0
(line 1) and then follow with the import { createRequire } from 'module' and
const require = createRequire(import.meta.url) statements (preserving their
exact identifiers) so the file parses correctly.

In `@src/components/common/Button/Button.tsx`:
- Around line 157-160: The spacing logic in Button's label Box uses ml and mr
both tied to !iconAfter so when iconAfter is true the left gap is missing;
update the Box margins in src/components/common/Button/Button.tsx (inside the
Button component) so ml = icon && iconAfter ? 4 : 0 and mr = icon && !iconAfter
? 4 : 0 to give a left gap when the icon is after the label and keep the right
gap when the icon is before the label.

In `@src/components/common/Text/Text.tsx`:
- Around line 63-66: The useMemo that computes textFontFamily currently depends
on [fontWeight, italic] but getFontFamily uses fontFamily and fontWeight; update
the dependency array in the useMemo inside Text (the textFontFamily calculation)
to [fontWeight, fontFamily] so memoization invalidates when fontFamily changes
and remove the obsolete italic dependency.
- Line 73: The style object in the Text component uses a redundant nullish
coalescing expression (`align ?? align`); replace it with a single reference to
the prop (use `align` directly) or, if a fallback is intended, supply the
correct fallback value instead of repeating `align`—look for the Text component
and the style entry where `{ textAlign: align ?? align }` is defined and
simplify to `{ textAlign: align }` or `{ textAlign: align ?? 'desiredFallback'
}`.

In `@src/features/auth/components/SocialLoginRow.tsx`:
- Around line 28-38: The current read-then-write flow using
supabase.from('users') + select (variables existingUser and userCheckError) is
race-prone and blocks returning users; change to an idempotent provisioning
approach by replacing the lookup+throw with an upsert
(supabase.from('users').upsert(...).onConflict('email')) or by performing the
insert and treating a duplicate-email/unique-constraint error as success (catch
the DB unique constraint error and proceed rather than throwing). Update the
code that currently references existingUser/userCheckError to use the upsert
result or to swallow the duplicate-email error and continue.

---

Nitpick comments:
In `@src/components/common/Button/Button.tsx`:
- Line 211: Replace the mutable variable declaration for paddingSize with an
immutable one since it is assigned once and never reassigned: change the
declaration that currently uses let paddingSize = size to use const paddingSize
= size in the Button component (symbol: paddingSize, referencing size) so the
value is immutable and clearer.

In `@src/components/common/Text/Text.tsx`:
- Around line 39-46: In Text.tsx simplify the else branch by removing the
redundant switch on fontFamily and directly return fonts.Lalezar.Regular (since
in this branch fontFamily is already 'lalezar'); drop the unreachable default
that returns fonts.Manrope.Regular and keep references to fontFamily and
fonts.Lalezar.Regular to locate the change.
- Around line 12-17: TextProps declares italic and flex but the Text component
no longer uses them (italic is still destructured in the component and flex is
never applied). Fix by either removing both italic and flex from the TextProps
type and removing the italic destructuring from the Text function, or implement
them: for italic, map italic to a style (e.g., fontStyle: 'italic' or choose the
italic font variant) where styles are composed in the Text component; for flex,
accept and apply it to the root style (e.g., style={[... , { flex }]}). Update
the TextProps interface and the Text component destructuring (and any callers if
you remove props).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b463191c-bab4-496f-af9c-2b6563dc7e3e

📥 Commits

Reviewing files that changed from the base of the PR and between a095a81 and 34022ca.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (43)
  • .eslintrc
  • .gitignore
  • .idea/rambo-template.iml
  • .prettierrc
  • README.md
  • app.json
  • package.json
  • prisma/migrations/20250612093024_init/migration.sql
  • prisma/migrations/migration_lock.toml
  • prisma/schema.prisma
  • prisma/seed.ts
  • scripts/create-project.sh
  • scripts/reset-project.js
  • src/app/(tabs)/_layout.tsx
  • src/app/(tabs)/explore.tsx
  • src/app/(tabs)/index.tsx
  • src/app/_layout.tsx
  • src/assets/icons/AppleLogo.tsx
  • src/assets/icons/FacebookLogo.tsx
  • src/assets/icons/GoogleLogo.tsx
  • src/components/common/Button/Button.tsx
  • src/components/common/Button/Spinner.tsx
  • src/components/common/Button/buttonRenderUtils.tsx
  • src/components/common/Button/types.ts
  • src/components/common/Button/useButtonBehavior.ts
  • src/components/common/Layout/Box.tsx
  • src/components/common/Layout/types/FlexProps.ts
  • src/components/common/Layout/types/LayoutProps.ts
  • src/components/common/Layout/types/SpaceProps.ts
  • src/components/common/Text/Text.tsx
  • src/components/common/TextField/Input.tsx
  • src/components/common/TextField/TextField.tsx
  • src/components/common/TextField/types.ts
  • src/features/auth/components/SocialLoginRow.tsx
  • src/hooks/useColorScheme.ts
  • src/hooks/useColorScheme.web.ts
  • src/i18n/config.ts
  • src/i18n/en/index.ts
  • src/lib/prisma.ts
  • src/lib/supabase.ts
  • src/theme/colors.ts
  • src/theme/fonts.ts
  • src/types/theme.d.ts
✅ Files skipped from review due to trivial changes (28)
  • prisma/migrations/migration_lock.toml
  • src/components/common/Button/buttonRenderUtils.tsx
  • src/i18n/en/index.ts
  • .prettierrc
  • src/components/common/Button/types.ts
  • src/components/common/TextField/TextField.tsx
  • src/components/common/Button/Spinner.tsx
  • src/components/common/Button/useButtonBehavior.ts
  • src/hooks/useColorScheme.ts
  • src/app/(tabs)/_layout.tsx
  • src/hooks/useColorScheme.web.ts
  • src/types/theme.d.ts
  • src/components/common/Layout/types/FlexProps.ts
  • app.json
  • src/theme/colors.ts
  • src/assets/icons/FacebookLogo.tsx
  • src/assets/icons/GoogleLogo.tsx
  • src/app/(tabs)/explore.tsx
  • src/i18n/config.ts
  • .idea/rambo-template.iml
  • .eslintrc
  • .gitignore
  • src/components/common/Layout/types/SpaceProps.ts
  • src/assets/icons/AppleLogo.tsx
  • src/components/common/Layout/types/LayoutProps.ts
  • src/components/common/TextField/types.ts
  • src/components/common/TextField/Input.tsx
  • src/app/(tabs)/index.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/lib/supabase.ts
  • src/theme/fonts.ts
  • prisma/seed.ts
  • src/components/common/Layout/Box.tsx
  • src/app/_layout.tsx

Comment thread scripts/create-project.sh
Comment on lines +112 to +116
cd "$destination_dir"
rm -rf .git
git init
git add .
git commit -m "Initial commit of $new_project_name"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add failure handling for cd command.

If cd fails, the subsequent rm -rf .git and git init commands would execute in the wrong directory, which could cause unintended behavior.

🛡️ Proposed fix
-cd "$destination_dir"
+cd "$destination_dir" || { echo "Error: Failed to change to destination directory."; exit 1; }
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 112-112: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/create-project.sh` around lines 112 - 116, The script currently runs
cd "$destination_dir" without checking for failure, so subsequent rm -rf .git
and git init may run in the wrong location; update the create-project.sh flow
around the cd command (referencing the destination_dir variable and the commit
message using new_project_name) to detect a failed cd and abort with a clear
error message and non-zero exit code (e.g., check the cd return value or use a
conditional/guard), so the script stops before running rm -rf .git, git init,
git add, and git commit when destination_dir cannot be entered.

Comment thread scripts/reset-project.js
Comment on lines +7 to 36
/**
* This script is used to reset the project to a blank state.
* It moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
* You can remove the `reset-project` script from package.json and safely delete this file after running it.
*/

const fs = require('fs');
const path = require('path');

const root = process.cwd();
const oldDirs = ['app', 'components', 'hooks', 'constants', 'scripts'];
const newDir = 'app-example';
const newAppDir = 'app';
const newDirPath = path.join(root, newDir);

const indexContent = `import { Text, View } from "react-native";

export default function Index() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>Edit app/index.tsx to edit this screen.</Text>
</View>
);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Script is non-functional after removal of moveDirectories.

The AI summary indicates the moveDirectories function and its invocation were removed. The script now defines indexContent and several path variables but never uses them. Per the comment on lines 7-11, this script should:

  • Move /app, /components, /hooks, /scripts, /constants to /app-example
  • Create new /app directory with starter files

The script is referenced in package.json ("reset-project": "node ./scripts/reset-project.js") and documented in README.md as a setup step. In its current state, running npm run reset-project will do nothing.

Either restore the moveDirectories implementation or remove the script and its references from package.json and README.md.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/reset-project.js` around lines 7 - 36, The script defines oldDirs,
newDirPath, newAppDir and indexContent but the moveDirectories implementation
and its invocation were removed; restore a function named moveDirectories() (or
similar) that: iterates over oldDirs, checks existence (fs.existsSync), moves
each existing directory to path.join(newDirPath, dir) using fs.renameSync (or
fs.rename with proper error handling), creates the new app directory (newAppDir)
if missing (fs.mkdirSync(..., { recursive: true })), writes the starter index
file using indexContent to path.join(newAppDir, 'index.tsx') and also create a
minimal _layout.tsx (provide layoutContent string) with fs.writeFileSync, and
ensure errors are caught and logged; finally call moveDirectories() at the end
so npm run reset-project performs the described operations.

Comment on lines +20 to +23
export const getFontFamily = (
fontFamily: 'lalezar' | 'manrope',
fontWeight: FontWeight | 'light' | 'medium' = 'normal'
): string => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all callers of getFontFamily to verify they pass the required fontFamily argument
rg -n "getFontFamily\s*\(" --type ts --type tsx -g '!Text.tsx'

Repository: hainguyentien/rambo-template

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Find all callers of getFontFamily in TypeScript files
rg -n "getFontFamily\s*\(" . --type ts -g '!Text.tsx'

Repository: hainguyentien/rambo-template

Length of output: 156


🏁 Script executed:

#!/bin/bash
# Also search in .tsx files using a pattern that doesn't rely on file type detection
fd -e tsx -e ts | xargs rg -n "getFontFamily\s*\(" | grep -v Text.tsx

Repository: hainguyentien/rambo-template

Length of output: 154


🏁 Script executed:

#!/bin/bash
# View context around the getFontFamily call in TextField.tsx
sed -n '185,200p' src/components/common/TextField/TextField.tsx

Repository: hainguyentien/rambo-template

Length of output: 437


🏁 Script executed:

#!/bin/bash
# View the complete getFontFamily function signature in Text.tsx
sed -n '20,30p' src/components/common/Text/Text.tsx

Repository: hainguyentien/rambo-template

Length of output: 417


Breaking change: getFontFamily() call in TextField.tsx missing required fontFamily parameter.

The getFontFamily function now requires fontFamily as the first argument, but TextField.tsx:193 calls it with no arguments: getFontFamily(). This will cause a compilation error or runtime failure.

Fix by either:

  1. Passing the required parameter: getFontFamily('manrope')
  2. Adding a default value to the function signature: fontFamily: 'lalezar' | 'manrope' = 'manrope'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/Text/Text.tsx` around lines 20 - 23, The call site in
the TextField component is calling getFontFamily() without the newly required
first parameter; update the TextField usage to pass a valid fontFamily value
(e.g., call getFontFamily('manrope') or getFontFamily('lalezar') where
appropriate) or alter the getFontFamily signature to provide a default (change
fontFamily parameter to fontFamily: 'lalezar' | 'manrope' = 'manrope') so
existing calls without arguments continue to work; modify either the call in the
TextField component or the getFontFamily declaration (function name:
getFontFamily) to resolve the missing required parameter.

Comment on lines +15 to +19
GoogleSignin.configure({
scopes: ['https://www.googleapis.com/auth/drive.readonly'],
iosClientId:
'301631509163-ba0fngceep6ovq0ai87jidgv6ne6spju.apps.googleusercontent.com',
});
Copy link
Copy Markdown

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:

# First, let's examine the SocialLoginRow.tsx file to understand the context
cat -n src/features/auth/components/SocialLoginRow.tsx

Repository: hainguyentien/rambo-template

Length of output: 5558


🏁 Script executed:

# Search for any Drive-related API calls in the codebase
rg "drive\." --type ts --type tsx -i

Repository: hainguyentien/rambo-template

Length of output: 99


🏁 Script executed:

# Search for other Google API scope usage to understand the pattern
rg "googleapis.com/auth" --type ts --type tsx

Repository: hainguyentien/rambo-template

Length of output: 99


🏁 Script executed:

# Check if there are any references to the drive scope elsewhere
rg "drive\.readonly" --type ts --type tsx

Repository: hainguyentien/rambo-template

Length of output: 99


🏁 Script executed:

# Search for drive references without file type specification
rg "drive" --type-list | head -20

Repository: hainguyentien/rambo-template

Length of output: 461


🏁 Script executed:

# Try searching with broader approach
rg "drive\.readonly" -i

Repository: hainguyentien/rambo-template

Length of output: 183


🏁 Script executed:

# Search for Google API calls that might use the drive scope
rg "googleapis" -i

Repository: hainguyentien/rambo-template

Length of output: 183


🏁 Script executed:

# Check if there are any Google Drive SDK imports or usage
rg "google.*drive" -i

Repository: hainguyentien/rambo-template

Length of output: 183


Remove the unused Google Drive scope from GoogleSignin configuration.

The drive.readonly scope is requested but never used. The sign-in flow only needs the ID token for authentication—it makes no Drive API calls. Removing this scope reduces unnecessary permission requests and simplifies the consent surface for users.

Suggested fix
   GoogleSignin.configure({
-    scopes: ['https://www.googleapis.com/auth/drive.readonly'],
     iosClientId:
       '301631509163-ba0fngceep6ovq0ai87jidgv6ne6spju.apps.googleusercontent.com',
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/auth/components/SocialLoginRow.tsx` around lines 15 - 19, The
GoogleSignin.configure call is requesting an unnecessary Drive scope; remove the
'https://www.googleapis.com/auth/drive.readonly' entry from the scopes array (or
remove the scopes property entirely if you only need the ID token) in the
GoogleSignin.configure(...) invocation so the sign-in flow only requests the
permissions actually used; keep the iosClientId and other config intact.

Comment on lines +39 to +46
const { data: newUser, error: createUserError } = await supabase
.from('users')
.insert([{ id: userId, email, username: email.split('@')[0] }])
.select('id')
.single();

if (createUserError) {
throw new Error('Error creating user profile!');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

The inserted row does not match the users table.

username is not defined in the provided Prisma schema/migration, while preferredLanguage is required and has no default. New social sign-ins will fail here after auth succeeds.

Suggested fix
     const { data: newUser, error: createUserError } = await supabase
       .from('users')
-      .insert([{ id: userId, email, username: email.split('@')[0] }])
+      .insert([{ id: userId, email, preferredLanguage: 'en' }])
       .select('id')
       .single();

If username is intentional, add it to prisma/schema.prisma and ship the matching migration instead.

📝 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
const { data: newUser, error: createUserError } = await supabase
.from('users')
.insert([{ id: userId, email, username: email.split('@')[0] }])
.select('id')
.single();
if (createUserError) {
throw new Error('Error creating user profile!');
const { data: newUser, error: createUserError } = await supabase
.from('users')
.insert([{ id: userId, email, preferredLanguage: 'en' }])
.select('id')
.single();
if (createUserError) {
throw new Error('Error creating user profile!');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/auth/components/SocialLoginRow.tsx` around lines 39 - 46, The
insert into 'users' in SocialLoginRow.tsx is using a non-existent "username"
field while the Prisma schema requires "preferredLanguage"; update the inserted
row in the supabase .insert call (inside the social sign-in flow) to include
preferredLanguage (e.g., preferredLanguage: 'en' or derive from user locale)
instead of username, or if username was intended, add username to
prisma/schema.prisma and create the matching migration so the DB column exists;
ensure the object passed to .insert (id, email, preferredLanguage) matches the
current Prisma/migration contract and re-run migrations if you add a column.

Comment thread src/lib/prisma.ts
Comment on lines +1 to +16
import { PrismaClient } from '@prisma/client';

const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};

export const prisma =
globalForPrisma.prisma ??
new PrismaClient({
log:
process.env.NODE_ENV === 'development'
? ['query', 'error', 'warn']
: ['error'],
});

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether Prisma is imported from app/runtime code.
# Expected: no matches outside server-only or tooling files.
rg -n --type=ts --type=tsx -g '!src/lib/prisma.ts' -C2 \
  "from ['\"](`@/lib/prisma`|@prisma/client)['\"]|require\\(['\"]@prisma/client['\"]\\)" .

Repository: hainguyentien/rambo-template

Length of output: 99


🏁 Script executed:

#!/bin/bash
# First, let's understand the repository structure
echo "=== Repository Structure ==="
ls -la
head -20 package.json

Repository: hainguyentien/rambo-template

Length of output: 2028


🏁 Script executed:

#!/bin/bash
# Search for Prisma imports with corrected rg syntax
# Try with just ts type or without type filter
echo "=== Searching for Prisma imports ==="
rg -n "from ['\"](`@/lib/prisma`|@prisma/client)['\"]|require\(['\"]@prisma/client['\"]" \
  --type ts -C2 . || echo "No matches or rg issue"
  
# Also try without type filter
echo ""
echo "=== Alternative search (no type filter) ==="
rg -n "from.*prisma|require.*prisma" -C2 .

Repository: hainguyentien/rambo-template

Length of output: 780


🏁 Script executed:

#!/bin/bash
# Check what the app structure looks like
echo "=== App structure ==="
find . -maxdepth 3 -type f -name "*.json" | grep -E "(package|tsconfig|app|expo)" | head -20

Repository: hainguyentien/rambo-template

Length of output: 823


🏁 Script executed:

#!/bin/bash
# Check if this is Expo/React Native
echo "=== Package.json dependencies ==="
cat package.json | grep -A 20 "dependencies\|devDependencies" | head -40

Repository: hainguyentien/rambo-template

Length of output: 1524


Move Prisma to a server-only directory structure.

This is an Expo/React Native app, and PrismaClient is a server-side dependency. While your code currently doesn't import it at runtime, exporting it from src/lib/ creates an architectural footgun—developers can easily accidentally import it into React Native code, which will fail when the app runs. Instead, move the Prisma singleton to a dedicated server/ or api/ directory outside the app bundle, and have the app communicate with Supabase or a backend API.

🧰 Tools
🪛 ESLint

[error] 3-3: 'globalThis' is not defined.

(no-undef)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/prisma.ts` around lines 1 - 16, The PrismaClient singleton (symbols:
PrismaClient, prisma, globalForPrisma) lives inside the app bundle
(src/lib/prisma) which lets RN/Expo code accidentally import a server-only
dependency; move this module out of the client app bundle into a server-only
directory (e.g., server/ or api/) so it cannot be imported by React Native code,
update any imports to point to the new server path, and replace client-side
usages with calls to a backend API or Supabase instead of importing prisma
directly; ensure the exported prisma singleton remains only in the server
codebase and that no client-side files import from the old src/lib/prisma
location.

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.

2 participants