Skip to content

Add spreadsheet UI, frontend and backend with monorepo setup#11

Merged
hackerwins merged 11 commits into
mainfrom
backend
May 3, 2025
Merged

Add spreadsheet UI, frontend and backend with monorepo setup#11
hackerwins merged 11 commits into
mainfrom
backend

Conversation

@hackerwins

@hackerwins hackerwins commented Apr 13, 2025

Copy link
Copy Markdown
Collaborator

What this PR does / why we need it?

Add spreadsheet UI, frontend and backend with monorepo setup

Established monorepo with pnpm workspace, configured
ESLint/Prettier/NestJS for backend, and Vite/TypeScript for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with in-memory storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.

Any background context you want to provide?

What are the relevant tickets?

Fixes #

Checklist

  • Added relevant tests or not required
  • Didn't break anything

Summary by CodeRabbit

  • New Features

    • Added backend document management with full CRUD API secured by JWT authentication.
    • Implemented GitHub OAuth and JWT-based user authentication with session cookies.
    • Developed frontend document listing, detail view, and spreadsheet editing with real-time collaboration.
    • Introduced reusable UI components including sidebar, tables, sheets, dropdowns, tooltips, and theme switcher.
    • Added theming support with light/dark modes and responsive layouts.
    • Provided comprehensive TypeScript types for users, documents, navigation items, and worksheet data.
    • Integrated a custom store backed by Yorkie for collaborative spreadsheet state management.
    • Added new spreadsheet theming, event handling improvements, and explicit render/cleanup methods.
    • Enhanced document list with interactive table including sorting, filtering, selection, and actions.
    • Added authentication-related frontend API functions and route guards for public/private access.
    • Introduced a new spreadsheet package with modular exports and build configuration.
  • Bug Fixes

    • Enhanced spreadsheet event handling and theming for improved stability and UX.
    • Improved formula token extraction to correctly handle uncovered formula segments.
  • Chores

    • Established monorepo workspace with pnpm, configured build scripts and CI workflows.
    • Added configuration files for TypeScript, ESLint, Prettier, NestJS, and Vite.
    • Updated dependencies and cleaned up package configurations across backend, frontend, and sheet packages.
    • Added comprehensive .gitignore files for project directories.
  • Documentation

    • Added README files for backend and frontend modules.
    • Included detailed comments and structured configuration files.
  • Tests

    • Added tests for formula parsing and spreadsheet calculation logic.

@hackerwins
hackerwins marked this pull request as draft April 13, 2025 05:43
@coderabbitai

coderabbitai Bot commented Apr 13, 2025

Copy link
Copy Markdown

Walkthrough

This change introduces the foundational structure for a full-stack monorepo application named "Wafflebase", organized with a pnpm workspace and modularized into backend, frontend, and sheet (spreadsheet) packages. The backend is implemented using NestJS and Prisma ORM, providing authentication (including GitHub OAuth), user management, and document CRUD APIs with corresponding database schema and migrations. The frontend is a React app built with Vite and Tailwind CSS, featuring a modular UI component library, authentication flows, document management pages, and integration with the sheet package for spreadsheet functionality. The sheet package offers a customizable spreadsheet engine with theming, tokenization, and memory store, now exported as a library. Extensive configuration files, build scripts, and type definitions are included for all packages.

Changes

Files/Paths Change Summary
.github/workflows/ci.yml Updated CI workflow: renamed, Node.js version bump, upgraded actions, switched to pnpm, added pnpm caching, split build steps, and revised test step.
.github/workflows/docker-publish.yml, .github/workflows/publish-ghpage.yml Added Docker publish workflow; updated GitHub Pages publish workflow with caching, pnpm setup, and deployment improvements.
.gitignore, packages/backend/.gitignore, packages/frontend/.gitignore Added comprehensive .gitignore files for root, backend, and frontend to ignore logs, build artifacts, dependencies, OS/editor files, and environment configs.
pnpm-workspace.yaml Added workspace configuration including all packages under packages/*.
package.json, packages/backend/package.json, packages/frontend/package.json, packages/sheet/package.json Added/updated package manifests for root and all packages; defined scripts, dependencies, and metadata.
Dockerfile Added Dockerfile for containerizing backend with Node 20 Alpine and pnpm.
packages/backend/... (multiple files: NestJS modules, controllers, services, configs, Prisma schema & migrations) Introduced backend structure with authentication (JWT, GitHub OAuth), user and document modules/services/controllers, Prisma ORM integration, database schema, and migrations.
packages/backend/src/database/prisma.service.ts Added PrismaService for managing database connection lifecycle in NestJS.
packages/backend/src/auth/... Implemented authentication logic: JWT, GitHub OAuth, guards, strategies, controller, and types.
packages/backend/src/document/... Implemented document controller and service for CRUD operations, with access control.
packages/backend/src/user/... Implemented user service and module for user management.
packages/frontend/... (multiple files: React components, pages, UI library, hooks, types, configs) Introduced frontend React app with routing, authentication, document management, custom UI component library, theming, hooks, and type definitions.
packages/frontend/src/api/auth.ts, src/api/documents.ts Added API utility functions for authentication and document CRUD operations with error handling and toast notifications.
packages/frontend/src/app/... (Layout, documents, login, settings, spreadsheet) Added main app layout, routing with public/private routes, document list/detail pages, login page, settings page with theme toggle, and spreadsheet view component integrating Yorkie store.
packages/frontend/src/components/... (UI components and hooks) Added extensive UI components including sidebar, navigation, loader, login form, theme provider, avatar, badge, breadcrumb, button, card, chart, checkbox, drawer, dropdown menu, input, label, select, separator, sheet, skeleton, switch, table, tabs, toggle, tooltip, and hooks like useIsMobile.
packages/frontend/src/lib/utils.ts Added utility function cn for merging Tailwind CSS class names.
packages/frontend/src/types/... Added type definitions for User, Document, NavItem, Worksheet, and other domain types.
packages/frontend/index.html, index.css, vite.config.ts, tsconfig.* Added frontend HTML entry point, global CSS with theming, Vite configuration with plugins and path aliases, and TypeScript configurations.
packages/sheet/... (spreadsheet engine, store, formula, worksheet, index, main, types, build config, tests) Refactored spreadsheet logic for theming, improved event handling and cleanup, updated token extraction, changed Sheet API (constructor requires store, added setActiveCell), removed DuckDB store, and updated tests and build scripts. Exported spreadsheet engine as a library with improved initialization and options.
frontend/src/store/duckdb/duckdb.ts Removed DuckDB store implementation for spreadsheet data management.
packages/backend/prisma/migrations/... Added initial and follow-up database migrations for user and document tables.
packages/backend/prisma/schema.prisma Defined Prisma schema for User and Document models, SQLite datasource, and client generator.
packages/sheet/src/formula/formula.ts Enhanced extractTokens to insert STRING tokens for gaps between recognized tokens.
packages/sheet/test/... Updated tests to instantiate Sheet with MemStore; added tests for token extraction.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend (React)
    participant Backend (NestJS)
    participant Database (Prisma/SQLite)

    User->>Frontend (React): Visit /login
    Frontend (React)->>Backend (NestJS): GET /auth/me (check session)
    Backend (NestJS)-->>Frontend (React): 401 Unauthorized
    Frontend (React)->>User: Show login form

    User->>Frontend (React): Click "Login with GitHub"
    Frontend (React)->>Backend (NestJS): GET /auth/github
    Backend (NestJS)->>GitHub: OAuth redirect
    GitHub->>Backend (NestJS): OAuth callback
    Backend (NestJS)->>Database (Prisma/SQLite): Find or create user
    Database (Prisma/SQLite)-->>Backend (NestJS): User record
    Backend (NestJS)->>Frontend (React): Set session cookie, redirect to dashboard

    User->>Frontend (React): View documents
    Frontend (React)->>Backend (NestJS): GET /documents/
    Backend (NestJS)->>Database (Prisma/SQLite): Query documents by user
    Database (Prisma/SQLite)-->>Backend (NestJS): Documents list
    Backend (NestJS)-->>Frontend (React): Documents data
    Frontend (React)->>User: Render document list

    User->>Frontend (React): Open document
    Frontend (React)->>Backend (NestJS): GET /documents/:id
    Backend (NestJS)->>Database (Prisma/SQLite): Fetch document, check ownership
    Database (Prisma/SQLite)-->>Backend (NestJS): Document data
    Backend (NestJS)-->>Frontend (React): Document data
    Frontend (React)->>Sheet (Spreadsheet): initialize(container, { theme })
    Sheet (Spreadsheet)->>Frontend (React): Spreadsheet instance
    Frontend (React)->>User: Render spreadsheet UI
Loading

Possibly related PRs

  • Initialize backend folder #10: Modifies the GitHub Actions workflow for frontend CI with npm caching and directory changes, related by workflow configuration updates.

Poem

🐇
In burrows deep, the code does grow,
A monorepo garden, neat in row.
Backend, frontend, sheet unite—
Auth and docs now work just right.
With themes that shift from dark to light,
And spreadsheets gleaming, pure delight!
Wafflebase is ready—hip, hip, hooray!
Let’s hop through features, code at play!

✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hackerwins
hackerwins force-pushed the backend branch 4 times, most recently from 8ec029b to b6f057b Compare April 13, 2025 05:50
@hackerwins
hackerwins marked this pull request as ready for review April 13, 2025 11:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 26

🧹 Nitpick comments (55)
packages/frontend/README.md (1)

1-2: Clear and Consistent Frontend README
This README provides a concise header that clearly identifies the frontend package. As the project evolves, consider expanding this file with additional details (e.g., setup instructions, usage, dependencies) to further enhance clarity for new developers.

packages/backend/README.md (1)

1-2: Straightforward Backend README
The backend README is minimal yet effective in stating the package title. Similar to the frontend README, you might eventually want to include further documentation (e.g., build instructions, API details) to assist with onboarding or maintenance.

packages/frontend/src/types/users.ts (1)

1-6: User type definition looks good, but consider adding JSDoc documentation.

The User type definition is clear and includes all the necessary basic fields for user representation. However, adding JSDoc documentation would improve developer experience by providing context and field descriptions.

Consider adding documentation like this:

+/**
+ * Represents a user in the system.
+ */
 export type User = {
+  /** Authentication provider (e.g., 'github', 'google') */
   authProvider: string;
+  /** User's display name */
   username: string;
+  /** User's email address */
   email: string;
+  /** URL to the user's profile image */
   avatar: string;
 };
packages/backend/src/auth/jwt-auth.guard.ts (1)

4-9: Remove unnecessary constructor.

The constructor doesn't add any functionality beyond calling the parent constructor, making it redundant.

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
-  constructor() {
-    super();
-  }
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 6-8: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

packages/frontend/components.json (1)

1-21: Component configuration file is clear and descriptive.
The JSON file properly defines schema validation, UI styling preferences, Tailwind configuration, and convenient alias mappings for components, utilities, and hooks. One minor note: if a specific Tailwind configuration file is available, consider updating the "config" field instead of leaving it as an empty string. This is an optional enhancement.

packages/backend/src/auth/github-auth.guard.ts (1)

6-15: Add error handling in the canActivate method.

There's no error handling for potential issues when accessing the request or session. If the session middleware isn't properly configured, this could cause runtime errors.

async canActivate(context: ExecutionContext): Promise<boolean> {
  const request = context.switchToHttp().getRequest();

+  try {
    const returnTo = request.query.returnTo;
    if (returnTo) {
      request.session.returnTo = returnTo;
    }

    return (await super.canActivate(context)) as boolean;
+  } catch (error) {
+    console.error('Error in GitHubAuthGuard:', error);
+    throw error;
+  }
}
packages/backend/src/auth/auth.module.ts (1)

11-11: Consider removing redundant ConfigModule.forRoot() call.

The ConfigModule.forRoot() call may be redundant if it's already called in the root AppModule, which is the typical pattern in NestJS applications.

@Module({
  imports: [
-   ConfigModule.forRoot(),
    JwtModule.registerAsync({
      imports: [ConfigModule],
      // ...

Ensure this is only called once, typically in the AppModule.

packages/frontend/src/PublicRoute.tsx (3)

6-14: Add documentation for the PublicRoute component.

The component lacks documentation describing its purpose and behavior. Adding a JSDoc comment would improve maintainability.

+ /**
+  * PublicRoute component restricts authenticated users from accessing routes like login
+  * If user is authenticated, redirects to home page
+  * If loading, displays a loader
+  * If not authenticated, renders the child routes via Outlet
+  */
export const PublicRoute = (): ReactElement => {
  const { me, isLoading } = useMe();

9-11: Consider adding a timeout for loading state.

The loading state could potentially continue indefinitely if there's a network issue without raising an error. Consider adding a timeout.

You could enhance the useMe hook to include a timeout mechanism, or add a local timeout in this component:

export const PublicRoute = (): ReactElement => {
  const { me, isLoading } = useMe();
+  const [isTimedOut, setIsTimedOut] = useState(false);
+  
+  useEffect(() => {
+    const timer = setTimeout(() => {
+      if (isLoading) {
+        setIsTimedOut(true);
+      }
+    }, 10000); // 10 seconds timeout
+    
+    return () => clearTimeout(timer);
+  }, [isLoading]);
+  
+  if (isTimedOut) {
+    return <div>Failed to authenticate. Please try again later.</div>;
+  }

  if (isLoading) {
    return <Loader />;
  }

  return me ? <Navigate to="/" /> : <Outlet />;
};

13-13: Store the intended destination for redirecting after login.

Currently, if a user is redirected to login from a protected route, they always go to the home page after login. Consider storing and using the original destination.

- return me ? <Navigate to="/" /> : <Outlet />;
+ // Use location from react-router to capture the intended location
+ const location = useLocation();
+ // Store the location the user tried to visit for later redirect
+ const from = location.state?.from?.pathname || "/";
+ 
+ return me ? <Navigate to={from} /> : <Outlet />;

This would require updating the protected routes to pass the current location when redirecting to login.

packages/frontend/src/app/login/page.tsx (1)

10-15: Update placeholder logo link.

The logo link is currently set to "#", which doesn't navigate anywhere. Consider setting it to a valid route such as the home page.

-          <a href="#" className="flex items-center gap-2 font-medium">
+          <a href="/" className="flex items-center gap-2 font-medium">
packages/sheet/src/store/local.ts (1)

7-9: Consider adding documentation about storage behavior change.

The change from DuckDB to in-memory storage represents a significant behavioral change. Consider adding a comment documenting this change and its implications, especially regarding data persistence.

 export async function createStore(key: string): Promise<LocalStore> {
+  // Uses in-memory storage that doesn't persist across page reloads
   const store = new MemStore();
   return new LocalStore(store);
 }
packages/frontend/src/api/auth.ts (1)

3-20: Improve error handling and add return value

The logout function effectively handles the logout process and provides user feedback through toast notifications. Consider these improvements:

  1. Improve error message display by using error.message or String(error) instead of concatenating with the error object directly
  2. Return a boolean or status to inform callers whether the logout was successful
  3. Add a check for the environment variable's existence before using it
-export async function logout() {
+export async function logout(): Promise<boolean> {
  try {
+   const apiUrl = import.meta.env.VITE_BACKEND_API_URL;
+   if (!apiUrl) {
+     toast.error("Backend API URL is not configured");
+     return false;
+   }
    const response = await fetch(
-     `${import.meta.env.VITE_BACKEND_API_URL}/auth/logout`,
+     `${apiUrl}/auth/logout`,
      {
        method: "POST",
        credentials: "include",
      }
    );
    if (response.ok) {
      toast.success("Logged out successfully");
+     return true;
    } else {
      toast.error("Failed to log out");
+     return false;
    }
  } catch (error) {
-   toast.error("Error during logout:" + error);
+   toast.error(`Error during logout: ${error instanceof Error ? error.message : String(error)}`);
+   return false;
  }
}
packages/frontend/src/components/ui/card.tsx (1)

5-16: Consider adding appropriate ARIA roles for improved accessibility

The Card component looks well implemented using the composition pattern. For better accessibility, consider adding appropriate ARIA roles like role="region" or more specific roles depending on the card's purpose.

<div
  data-slot="card"
+ role="region"
+ aria-labelledby="card-title"
  className={cn(
    "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
    className
  )}
  {...props}
/>
packages/backend/src/auth/jwt.strategy.ts (1)

21-27: Add type definition for JWT payload and consider additional validation

The validation method could be improved with proper typing and additional checks:

-  async validate(payload: any) {
+  async validate(payload: { sub: string; username: string; email: string }) {
+    // You could add additional validation here, such as:
+    // - Check if the user still exists in the database
+    // - Verify user permissions/roles
+    // - Check if the user is not banned/suspended
    return {
      id: payload.sub,
      username: payload.username,
      email: payload.email,
    };
  }
packages/frontend/src/components/ui/separator.tsx (1)

14-14: Consider adding documentation for the data-slot attribute

The data-slot="separator-root" attribute is used for component targeting, but its purpose might not be immediately clear to other developers.

packages/backend/package.json (1)

69-85: Consider configuring Jest coverage thresholds

The Jest configuration correctly sets up testing for TypeScript files and collects coverage information. For stricter quality control, consider adding coverage thresholds.

  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
-    "testEnvironment": "node"
+    "testEnvironment": "node",
+    "coverageThreshold": {
+      "global": {
+        "statements": 80,
+        "branches": 70,
+        "functions": 80,
+        "lines": 80
+      }
+    }
  }
packages/frontend/tsconfig.node.json (2)

5-5: Consider being more specific with the lib array

While ["ES2023"] will work, you may want to explicitly include other libraries you'll need like "DOM" if your code will run in a browser environment.


23-23: Check if you need additional files in the include array

Currently, you're only including vite.config.ts. If you have other Node-specific TypeScript files that should use this configuration (like build scripts), you might want to include them here as well.

🧰 Tools
🪛 Biome (1.9.4)

[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-24: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

packages/frontend/src/components/ui/skeleton.tsx (2)

7-7: Consider extracting default styles to a variable

For better maintainability, you might want to extract the default class string to a constant.

+const defaultClasses = "bg-accent animate-pulse rounded-md"
 function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
   return (
     <div
       data-slot="skeleton"
-      className={cn("bg-accent animate-pulse rounded-md", className)}
+      className={cn(defaultClasses, className)}
       {...props}
     />
   )
 }

3-11: Consider adding aria attributes for better accessibility

For better accessibility, consider adding appropriate ARIA attributes to indicate this is a loading state.

 function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
   return (
     <div
       data-slot="skeleton"
+      aria-hidden="true"
+      role="status"
       className={cn("bg-accent animate-pulse rounded-md", className)}
       {...props}
     />
   )
 }
packages/frontend/src/components/loader.tsx (2)

3-13: Consider making the component more configurable

The component could be more flexible by accepting props to customize the text and size.

-export const Loader = () => {
+export const Loader = ({ 
+  text = "Loading...", 
+  size = "default",
+}: { 
+  text?: string;
+  size?: "small" | "default" | "large";
+}) => {
+  const sizeClasses = {
+    small: "h-4 w-4",
+    default: "h-8 w-8",
+    large: "h-12 w-12"
+  };
  return (
    <div
      className="flex flex-col items-center justify-center min-h-[300px]"
      aria-live="polite"
    >
-      <Loader2 className="h-8 w-8 animate-spin text-primary" />
-      <p className="mt-4 text-sm text-muted-foreground">Loading...</p>
+      <Loader2 className={`${sizeClasses[size]} animate-spin text-primary`} />
+      <p className="mt-4 text-sm text-muted-foreground">{text}</p>
    </div>
  );
};

6-6: Consider making the min-height configurable

The fixed min-h-[300px] might not be suitable for all contexts. Consider making this configurable.

-      className="flex flex-col items-center justify-center min-h-[300px]"
+      className={`flex flex-col items-center justify-center ${className || "min-h-[300px]"}`}
packages/backend/eslint.config.mjs (1)

20-20: Consider updating the ECMAScript version.

The ECMAScript version is set to 5, which is quite outdated compared to your TypeScript target of ES2023 in the project's tsconfig.json. This mismatch might lead to inconsistent linting behavior.

- ecmaVersion: 5,
+ ecmaVersion: 2023,
packages/frontend/src/components/login-form.tsx (3)

13-15: Fix incomplete text in the login description.

The text "Wafflebase with your GitHub account" appears to be incomplete and should probably read "Login to Wafflebase with your GitHub account" or similar.

- <p className="text-balance text-sm text-muted-foreground">
-   Wafflebase with your GitHub account.
- </p>
+ <p className="text-balance text-sm text-muted-foreground">
+   Login to Wafflebase with your GitHub account.
+ </p>

20-23: Consider making the return URL configurable.

The return URL after authentication is hardcoded to "/dashboard". Consider making this configurable to support different redirect paths depending on the context.

- <Link
-   to={`${
-     import.meta.env.VITE_BACKEND_API_URL
-   }/auth/github?returnTo=${encodeURIComponent("/dashboard")}`}
-   rel="noopener noreferrer"
- >
+ <Link
+   to={`${
+     import.meta.env.VITE_BACKEND_API_URL
+   }/auth/github?returnTo=${encodeURIComponent(props.returnTo || "/dashboard")}`}
+   rel="noopener noreferrer"
+ >

This would require updating the component props:

type LoginFormProps = React.ComponentPropsWithoutRef<"form"> & {
  returnTo?: string;
};

export function LoginForm({
  className,
  returnTo,
  ...props
}: LoginFormProps) {
  // ...
}

25-31: Add accessibility attributes to the GitHub icon.

The SVG icon for GitHub is missing accessibility attributes such as aria-label and role, which can impact screen reader users.

- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" role="img" className="mr-2 h-4 w-4">
packages/backend/tsconfig.json (1)

8-8: Consider adding esModuleInterop setting.

The configuration includes allowSyntheticDefaultImports, but commonly esModuleInterop is also enabled to ensure complete interoperability with CommonJS modules.

  "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
packages/frontend/src/components/ui/input.tsx (1)

5-19: Well-structured Input component with comprehensive styling

The Input component follows best practices for React components:

  • Props are properly typed using React.ComponentProps
  • Destructuring props and spreading remaining ones to the input element
  • Using the cn utility to merge classNames effectively
  • Comprehensive styling for various states (focus, invalid, disabled)

Consider adding ARIA attributes for improved accessibility, especially when dealing with validation states:

 <input
   type={type}
   data-slot="input"
+  aria-invalid={props['aria-invalid'] || undefined}
   className={cn(
     "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
     "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
     "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
     className
   )}
   {...props}
 />
packages/frontend/src/components/nav-secondary.tsx (2)

14-23: Well-typed props interface for navigation items

The props are properly typed, accepting an array of items with title, URL, and icon properties, as well as inheriting props from SidebarGroup.

Consider adding a unique identifier for each item to improve stability when mapping:

 items: {
+  id: string
   title: string
   url: string
   icon: Icon
 }[]

24-42: Structured navigation implementation with potential key improvement

The component has a clear structure with nested sidebar components and correctly maps over the items array to create navigation elements.

Using the title as a key might lead to issues if titles aren't unique. Consider updating the key usage if you implement the id property:

-<SidebarMenuItem key={item.title}>
+<SidebarMenuItem key={item.id || item.title}>

Also, for improved accessibility, consider adding an aria-label to the links:

-<a href={item.url}>
+<a href={item.url} aria-label={`Navigate to ${item.title}`}>
packages/backend/src/auth/auth.service.ts (1)

12-27: Token generation implementation looks solid but missing expiration settings

The AuthService implementation follows NestJS best practices with proper dependency injection and a clean method for token creation. The JWT payload contains essential information.

However, no token expiration is specified, which could lead to tokens that never expire. Consider adding expiration configuration to enhance security.

    return {
-     token: this.jwtService.sign(payload),
+     token: this.jwtService.sign(payload, { expiresIn: '1h' }),
    };
packages/backend/src/auth/github.strategy.ts (1)

8-15: Configuration looks good but non-null assertions could be risky

The strategy configuration is well-structured, but using non-null assertions (!) for configuration values assumes these environment variables will always be set, which might cause runtime errors if they're missing.

Consider adding validation or fallback handling for missing configuration values.

super({
-  clientID: configService.get('GITHUB_CLIENT_ID')!,
-  clientSecret: configService.get('GITHUB_CLIENT_SECRET')!,
-  callbackURL: configService.get('GITHUB_CALLBACK_URL')!,
+  clientID: configService.getOrThrow('GITHUB_CLIENT_ID'),
+  clientSecret: configService.getOrThrow('GITHUB_CLIENT_SECRET'),
+  callbackURL: configService.getOrThrow('GITHUB_CALLBACK_URL'),
  scope: ['user:email'],
});
packages/frontend/package.json (1)

6-11: Build script looks good but consider adding test script

The build script properly runs TypeScript compilation before Vite build. However, unlike the sheet package, there's no test script defined. Consider adding test scripts for consistency across packages.

  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
+   "test": "vitest --run",
+   "test:watch": "vitest --watch"
  },
package.json (1)

1-15: Consider enhancing the package.json configuration.

While the basic pnpm monorepo setup is good, the package.json would benefit from additional information and improved script definitions:

  1. The description field is empty - adding a meaningful description would improve documentation
  2. The scripts only define package targets but don't specify operations to perform on them
  3. Missing standard fields like repository, homepage, and potentially workspaces configuration

Consider enhancing the configuration with something like:

 {
   "name": "wafflebase",
   "version": "1.0.0",
-  "description": "",
+  "description": "WaffleBase - A spreadsheet-like application",
   "main": "index.js",
   "scripts": {
     "frontend": "pnpm --filter @wafflebase/frontend",
     "backend": "pnpm --filter @wafflebase/backend",
-    "sheet": "pnpm --filter @wafflebase/sheet"
+    "sheet": "pnpm --filter @wafflebase/sheet",
+    "dev": "pnpm -r run dev",
+    "build": "pnpm -r run build",
+    "test": "pnpm -r run test"
   },
   "keywords": [],
   "author": "",
   "license": "ISC",
-  "packageManager": "[email protected]"
+  "packageManager": "[email protected]",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/wafflebase/wafflebase.git"
+  }
 }
packages/frontend/src/app/dashboard/data.json (1)

1-614: Consider representing numeric values as numbers rather than strings.

The target and limit properties are represented as strings (e.g., "18", "5") throughout the JSON file. If these values are intended to be used in calculations or comparisons, they should be numeric types rather than strings to avoid type coercion issues.

  {
    "id": 1,
    "header": "Cover page",
    "type": "Cover page",
    "status": "In Process",
-   "target": "18",
-   "limit": "5",
+   "target": 18,
+   "limit": 5,
    "reviewer": "Eddie Lake"
  },
packages/frontend/src/components/nav-user.tsx (2)

33-33: Remove debug console.log statement

There's a console.log statement that should be removed before deploying to production.

- console.log("user", user);

44-53: Refactor duplicate user information display to reduce code repetition

The user information layout (avatar, username, email) is duplicated between the dropdown trigger button and the dropdown content. Consider extracting this into a reusable component to adhere to the DRY principle.

+ // Create a component at the top of the file or in a separate file
+ function UserInfo({ user }: { user: User }) {
+   return (
+     <div className="flex items-center gap-2">
+       <Avatar className="h-8 w-8 rounded-lg">
+         <AvatarImage src={user.avatar} alt={user.username} />
+         <AvatarFallback className="rounded-lg">
+           {user.username.slice(0, 2).toUpperCase()}
+         </AvatarFallback>
+       </Avatar>
+       <div className="grid flex-1 text-left text-sm leading-tight">
+         <span className="truncate font-medium">{user.username}</span>
+         <span className="text-muted-foreground truncate text-xs">
+           {user.email}
+         </span>
+       </div>
+     </div>
+   );
+ }

Then use this component in both places.

Also applies to: 65-74

packages/frontend/src/components/app-sidebar.tsx (2)

96-101: Consider showing a skeleton loader instead of null during loading.

Returning null during loading can cause UI flickering when the component mounts. A skeleton loader would provide a smoother user experience.

export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
  const { me, isLoading } = useMe();

  if (isLoading) {
-    return null;
+    return (
+      <Sidebar collapsible="offcanvas" {...props}>
+        <SidebarHeader>
+          {/* Header content */}
+        </SidebarHeader>
+        <SidebarContent>
+          {/* Loading skeleton */}
+        </SidebarContent>
+        <SidebarFooter>
+          {/* Loading skeleton */}
+        </SidebarFooter>
+      </Sidebar>
+    );
  }

26-94: Extract navigation data to a separate configuration file.

The navigation data is currently embedded in the component file. For better maintainability and separation of concerns, consider moving this data to a dedicated configuration file.

- const data = {
-   navMain: [
-     // ... data ...
-   ],
-   navClouds: [
-     // ... data ...
-   ],
-   navSecondary: [
-     // ... data ...
-   ],
- };

Create a new file src/config/navigation.ts:

import {
  IconCamera,
  IconFileAi,
  IconFileDescription,
  IconFolder,
  IconSettings,
  IconUsers,
} from "@tabler/icons-react";

export const navigationConfig = {
  navMain: [
    // ... same data ...
  ],
  navClouds: [
    // ... same data ...
  ],
  navSecondary: [
    // ... same data ...
  ],
};

Then import it in the component:

import { navigationConfig } from "@/config/navigation";

And use it:

<NavMain items={navigationConfig.navMain} />
packages/frontend/src/components/ui/tabs.tsx (1)

42-44: Refactor long className string using class-variance-authority.

The TabsTrigger component has a very long className string which makes it hard to read and maintain. Consider using class-variance-authority (cva) to organize these classes, similar to the pattern used in the Button component.

+ const tabsTriggerVariants = cva(
+   "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+   {
+     variants: {
+       // Add variants if needed
+     },
+     defaultVariants: {
+       // Default variants if needed
+     },
+   }
+ );

  function TabsTrigger({
    className,
    ...props
  }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
    return (
      <TabsPrimitive.Trigger
        data-slot="tabs-trigger"
-       className={cn(
-         "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
-         className
-       )}
+       className={cn(tabsTriggerVariants(), className)}
        {...props}
      />
    );
  }
packages/frontend/src/hooks/useMe.ts (2)

6-6: Remove Korean comments for consistency.

There are Korean comments throughout the code. For an open-source project, maintaining English-only comments ensures better collaboration across different contributors.

-  const [isLoading, setIsLoading] = useState(true); // 로딩 상태 추가
+  const [isLoading, setIsLoading] = useState(true); // Loading state

-      setIsLoading(true); // 로딩 시작
+      setIsLoading(true); // Start loading

-        setIsLoading(false); // 로딩 종료
+        setIsLoading(false); // End loading

-  return { me: user, isLoading }; // 로딩 상태와 사용자 정보 반환
+  return { me: user, isLoading }; // Return loading state and user information

Also applies to: 17-17, 35-35, 41-41


19-25: Add error handling for network failures and handle API rate limits.

The current implementation logs errors but doesn't provide a way to retry requests or handle specific error cases like rate limiting. Consider adding more robust error handling.

  try {
    const res = await fetch(
      `${import.meta.env.VITE_BACKEND_API_URL}/auth/me`,
      {
        method: "GET",
        credentials: "include",
+       // Add timeout to prevent infinite loading in case of network issues
+       signal: AbortSignal.timeout(10000), // 10 second timeout
      }
    );
    if (res.ok) {
      setUser(await res.json());
+   } else if (res.status === 429) {
+     // Handle rate limiting
+     console.warn("Rate limited. Retrying in 5 seconds...");
+     setTimeout(fetchUser, 5000);
    } else {
+     console.error(`Failed to fetch user: ${res.status} ${res.statusText}`);
      setUser(null);
    }
packages/frontend/src/components/ui/toggle-group.tsx (1)

41-69: ToggleGroupItem handles context correctly

The component properly consumes context values with fallbacks to its own props, which is a good pattern.

One minor improvement: consider destructuring variant and size from context in one step for cleaner code.

-  const context = React.useContext(ToggleGroupContext)
+  const { variant: contextVariant, size: contextSize } = React.useContext(ToggleGroupContext)
   
   return (
     <ToggleGroupPrimitive.Item
       data-slot="toggle-group-item"
-      data-variant={context.variant || variant}
-      data-size={context.size || size}
+      data-variant={contextVariant || variant}
+      data-size={contextSize || size}
       className={cn(
         toggleVariants({
-          variant: context.variant || variant,
-          size: context.size || size,
+          variant: contextVariant || variant,
+          size: contextSize || size,
         }),
         "min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
         className
       )}
       {...props}
     >
       {children}
     </ToggleGroupPrimitive.Item>
   )
packages/frontend/src/components/ui/tooltip.tsx (2)

6-17: Consider increasing default delay duration

A delay duration of 0 means tooltips appear immediately, which can lead to tooltip flicker when users move their cursor across the UI. Consider increasing the default delay to a small value like 300ms.

function TooltipProvider({
-  delayDuration = 0,
+  delayDuration = 300,
  ...props
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
  return (
    <TooltipPrimitive.Provider
      data-slot="tooltip-provider"
      delayDuration={delayDuration}
      {...props}
    />
  )
}

35-57: TooltipContent has comprehensive animations

The component includes a rich set of animations for different states and positions using Tailwind's animation utilities.

One suggestion: consider making the sideOffset slightly larger to give more space between the trigger and the tooltip content:

function TooltipContent({
  className,
-  sideOffset = 0,
+  sideOffset = 4,
  children,
  ...props
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
packages/frontend/src/components/theme-provider.tsx (2)

33-49: Handle system theme changes dynamically.
Currently, the code checks the system preference on mount but does not react to future OS theme changes.

You could attach a matchMedia listener to reapply the "dark"/"light" class if the user’s system theme changes.


59-63: Avoid spreading extra props into the Provider unless necessary.
{...props} can lead to unintentional overrides or confusion.

Inline usage of the required props can be more predictable if no additional props are expected.

packages/frontend/src/components/data-table.tsx (1)

201-245: Form submissions do not update table data.
onSubmit triggers a toast but does not reflect the new target/limit values in your local state, leading to potential discrepancies.

You may want to store submitted values in the local state or pass them to an API, ensuring the table re-renders with the updated data.

packages/frontend/src/components/ui/table.tsx (1)

68-79: Optional: consider adding scope for TableHead cells.

While your <th> elements are styled correctly, you might consider using scope="col" or scope="row" for improved accessibility, particularly for assistive technologies.

packages/frontend/src/components/ui/chart.tsx (1)

35-68: ChartContainer is well-designed.

Providing a unique chartId for each chart ensures styles and references are properly scoped. The heavy inline class usage is acceptable, though you could consider factoring out some styles if it grows too large.

packages/frontend/src/components/ui/sidebar.tsx (4)

28-29: Consider storing UI preferences in localStorage or similar.
While using cookies to store the open/closed state can be convenient, localStorage might be simpler and less risky from a security perspective. If you decide to stick with cookies, consider attributes like SameSite or HttpOnly if needed for your application.


91-110: Prevent potential collisions with global keyboard shortcuts.
Using meta/ctrl+b might conflict with popular shortcuts (e.g., bold text in some contexts). Ensure that this shortcut does not interfere with user text editing or other features. You could allow customization or create a user setting for advanced users.


256-280: Enhance accessibility with labeling.
The SidebarTrigger includes a visually hidden label, which is great. Also consider aria-expanded or aria-controls to inform screen readers about sidebar state.


282-305: Improve resize handle discoverability.
The SidebarRail uses a hover-based approach to show a drag handle. Consider providing a more explicit visual indicator or a persistent affordance for better discoverability, especially on touch devices.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 65dabc9 and d040701.

⛔ Files ignored due to path filters (4)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • packages/frontend/public/vite.svg is excluded by !**/*.svg
  • packages/sheet/public/maltese.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (82)
  • .github/workflows/ci.yml (1 hunks)
  • .gitignore (1 hunks)
  • frontend/src/store/duckdb/duckdb.ts (0 hunks)
  • package.json (1 hunks)
  • packages/backend/.gitignore (1 hunks)
  • packages/backend/.prettierrc (1 hunks)
  • packages/backend/README.md (1 hunks)
  • packages/backend/eslint.config.mjs (1 hunks)
  • packages/backend/nest-cli.json (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/app.module.ts (1 hunks)
  • packages/backend/src/auth/auth.controller.ts (1 hunks)
  • packages/backend/src/auth/auth.module.ts (1 hunks)
  • packages/backend/src/auth/auth.service.ts (1 hunks)
  • packages/backend/src/auth/github-auth.guard.ts (1 hunks)
  • packages/backend/src/auth/github.strategy.ts (1 hunks)
  • packages/backend/src/auth/jwt-auth.guard.ts (1 hunks)
  • packages/backend/src/auth/jwt.strategy.ts (1 hunks)
  • packages/backend/src/main.ts (1 hunks)
  • packages/backend/test/app.e2e-spec.ts (1 hunks)
  • packages/backend/test/jest-e2e.json (1 hunks)
  • packages/backend/tsconfig.build.json (1 hunks)
  • packages/backend/tsconfig.json (1 hunks)
  • packages/frontend/.gitignore (1 hunks)
  • packages/frontend/README.md (1 hunks)
  • packages/frontend/components.json (1 hunks)
  • packages/frontend/eslint.config.js (1 hunks)
  • packages/frontend/index.html (1 hunks)
  • packages/frontend/package.json (1 hunks)
  • packages/frontend/src/App.tsx (1 hunks)
  • packages/frontend/src/PrivateRoute.tsx (1 hunks)
  • packages/frontend/src/PublicRoute.tsx (1 hunks)
  • packages/frontend/src/api/auth.ts (1 hunks)
  • packages/frontend/src/app/dashboard/data.json (1 hunks)
  • packages/frontend/src/app/dashboard/page.tsx (1 hunks)
  • packages/frontend/src/app/login/page.tsx (1 hunks)
  • packages/frontend/src/components/app-sidebar.tsx (1 hunks)
  • packages/frontend/src/components/data-table.tsx (1 hunks)
  • packages/frontend/src/components/loader.tsx (1 hunks)
  • packages/frontend/src/components/login-form.tsx (1 hunks)
  • packages/frontend/src/components/nav-documents.tsx (1 hunks)
  • packages/frontend/src/components/nav-main.tsx (1 hunks)
  • packages/frontend/src/components/nav-secondary.tsx (1 hunks)
  • packages/frontend/src/components/nav-user.tsx (1 hunks)
  • packages/frontend/src/components/site-header.tsx (1 hunks)
  • packages/frontend/src/components/theme-provider.tsx (1 hunks)
  • packages/frontend/src/components/ui/avatar.tsx (1 hunks)
  • packages/frontend/src/components/ui/badge.tsx (1 hunks)
  • packages/frontend/src/components/ui/breadcrumb.tsx (1 hunks)
  • packages/frontend/src/components/ui/button.tsx (1 hunks)
  • packages/frontend/src/components/ui/card.tsx (1 hunks)
  • packages/frontend/src/components/ui/chart.tsx (1 hunks)
  • packages/frontend/src/components/ui/checkbox.tsx (1 hunks)
  • packages/frontend/src/components/ui/drawer.tsx (1 hunks)
  • packages/frontend/src/components/ui/dropdown-menu.tsx (1 hunks)
  • packages/frontend/src/components/ui/input.tsx (1 hunks)
  • packages/frontend/src/components/ui/label.tsx (1 hunks)
  • packages/frontend/src/components/ui/select.tsx (1 hunks)
  • packages/frontend/src/components/ui/separator.tsx (1 hunks)
  • packages/frontend/src/components/ui/sheet.tsx (1 hunks)
  • packages/frontend/src/components/ui/sidebar.tsx (1 hunks)
  • packages/frontend/src/components/ui/skeleton.tsx (1 hunks)
  • packages/frontend/src/components/ui/sonner.tsx (1 hunks)
  • packages/frontend/src/components/ui/table.tsx (1 hunks)
  • packages/frontend/src/components/ui/tabs.tsx (1 hunks)
  • packages/frontend/src/components/ui/toggle-group.tsx (1 hunks)
  • packages/frontend/src/components/ui/toggle.tsx (1 hunks)
  • packages/frontend/src/components/ui/tooltip.tsx (1 hunks)
  • packages/frontend/src/hooks/use-mobile.ts (1 hunks)
  • packages/frontend/src/hooks/useMe.ts (1 hunks)
  • packages/frontend/src/index.css (1 hunks)
  • packages/frontend/src/lib/utils.ts (1 hunks)
  • packages/frontend/src/main.tsx (1 hunks)
  • packages/frontend/src/types/users.ts (1 hunks)
  • packages/frontend/tsconfig.app.json (1 hunks)
  • packages/frontend/tsconfig.json (1 hunks)
  • packages/frontend/tsconfig.node.json (1 hunks)
  • packages/frontend/vite.config.ts (1 hunks)
  • packages/sheet/package.json (1 hunks)
  • packages/sheet/src/store/local.ts (1 hunks)
  • packages/sheet/src/vite-env.d.ts (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/store/duckdb/duckdb.ts
🧰 Additional context used
🧬 Code Graph Analysis (33)
packages/frontend/src/PublicRoute.tsx (2)
packages/frontend/src/hooks/useMe.ts (1)
  • useMe (4-42)
packages/frontend/src/components/loader.tsx (1)
  • Loader (3-13)
packages/frontend/src/app/login/page.tsx (1)
packages/frontend/src/components/login-form.tsx (1)
  • LoginForm (5-37)
packages/frontend/src/components/ui/label.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/App.tsx (3)
packages/frontend/src/components/theme-provider.tsx (1)
  • ThemeProvider (23-64)
packages/frontend/src/PublicRoute.tsx (1)
  • PublicRoute (6-14)
packages/frontend/src/PrivateRoute.tsx (1)
  • PrivateRoute (6-14)
packages/frontend/src/components/ui/sonner.tsx (1)
packages/frontend/src/components/theme-provider.tsx (1)
  • useTheme (66-73)
packages/frontend/src/PrivateRoute.tsx (2)
packages/frontend/src/hooks/useMe.ts (1)
  • useMe (4-42)
packages/frontend/src/components/loader.tsx (1)
  • Loader (3-13)
packages/frontend/src/app/dashboard/page.tsx (4)
packages/frontend/src/components/ui/sidebar.tsx (2)
  • SidebarProvider (721-721)
  • SidebarInset (711-711)
packages/frontend/src/components/app-sidebar.tsx (1)
  • AppSidebar (96-129)
packages/frontend/src/components/site-header.tsx (1)
  • SiteHeader (4-17)
packages/frontend/src/components/data-table.tsx (1)
  • DataTable (332-621)
packages/frontend/src/components/ui/button.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/avatar.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/nav-user.tsx (3)
packages/frontend/src/components/ui/sidebar.tsx (4)
  • useSidebar (725-725)
  • SidebarMenu (712-712)
  • SidebarMenuItem (716-716)
  • SidebarMenuButton (715-715)
packages/frontend/src/components/ui/dropdown-menu.tsx (7)
  • DropdownMenu (242-242)
  • DropdownMenuTrigger (244-244)
  • DropdownMenuContent (245-245)
  • DropdownMenuLabel (247-247)
  • DropdownMenuSeparator (252-252)
  • DropdownMenuGroup (246-246)
  • DropdownMenuItem (248-248)
packages/frontend/src/components/ui/avatar.tsx (3)
  • Avatar (53-53)
  • AvatarImage (53-53)
  • AvatarFallback (53-53)
packages/frontend/src/components/ui/checkbox.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/toggle.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/badge.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/toggle-group.tsx (2)
packages/frontend/src/components/ui/toggle.tsx (1)
  • toggleVariants (47-47)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/nav-secondary.tsx (1)
packages/frontend/src/components/ui/sidebar.tsx (5)
  • SidebarGroup (705-705)
  • SidebarGroupContent (707-707)
  • SidebarMenu (712-712)
  • SidebarMenuItem (716-716)
  • SidebarMenuButton (715-715)
packages/frontend/src/components/nav-main.tsx (1)
packages/frontend/src/components/ui/sidebar.tsx (5)
  • SidebarGroup (705-705)
  • SidebarGroupContent (707-707)
  • SidebarMenu (712-712)
  • SidebarMenuItem (716-716)
  • SidebarMenuButton (715-715)
packages/frontend/src/components/ui/tooltip.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/app-sidebar.tsx (5)
packages/frontend/src/components/ui/sidebar.tsx (7)
  • Sidebar (702-702)
  • SidebarHeader (709-709)
  • SidebarMenu (712-712)
  • SidebarMenuItem (716-716)
  • SidebarMenuButton (715-715)
  • SidebarContent (703-703)
  • SidebarFooter (704-704)
packages/frontend/src/hooks/useMe.ts (1)
  • useMe (4-42)
packages/frontend/src/components/nav-main.tsx (1)
  • NavMain (11-47)
packages/frontend/src/components/nav-secondary.tsx (1)
  • NavSecondary (14-42)
packages/frontend/src/components/nav-user.tsx (1)
  • NavUser (26-94)
packages/frontend/src/components/ui/skeleton.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/breadcrumb.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/card.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/separator.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/data-table.tsx (13)
packages/frontend/src/components/ui/button.tsx (1)
  • Button (62-62)
packages/frontend/src/components/ui/checkbox.tsx (1)
  • Checkbox (30-30)
packages/frontend/src/components/ui/badge.tsx (1)
  • Badge (46-46)
packages/frontend/src/components/ui/label.tsx (1)
  • Label (24-24)
packages/frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
packages/frontend/src/components/ui/select.tsx (5)
  • Select (175-175)
  • SelectTrigger (183-183)
  • SelectValue (184-184)
  • SelectContent (176-176)
  • SelectItem (178-178)
packages/frontend/src/components/ui/dropdown-menu.tsx (6)
  • DropdownMenu (242-242)
  • DropdownMenuTrigger (244-244)
  • DropdownMenuContent (245-245)
  • DropdownMenuItem (248-248)
  • DropdownMenuSeparator (252-252)
  • DropdownMenuCheckboxItem (249-249)
packages/frontend/src/components/ui/table.tsx (6)
  • TableRow (113-113)
  • TableCell (114-114)
  • Table (108-108)
  • TableHeader (109-109)
  • TableHead (112-112)
  • TableBody (110-110)
packages/frontend/src/components/ui/tabs.tsx (4)
  • Tabs (64-64)
  • TabsList (64-64)
  • TabsTrigger (64-64)
  • TabsContent (64-64)
packages/frontend/src/components/ui/chart.tsx (4)
  • ChartConfig (9-17)
  • ChartContainer (345-345)
  • ChartTooltip (346-346)
  • ChartTooltipContent (347-347)
packages/frontend/src/hooks/use-mobile.ts (1)
  • useIsMobile (5-19)
packages/frontend/src/components/ui/drawer.tsx (8)
  • Drawer (120-120)
  • DrawerTrigger (123-123)
  • DrawerContent (125-125)
  • DrawerHeader (126-126)
  • DrawerTitle (128-128)
  • DrawerDescription (129-129)
  • DrawerFooter (127-127)
  • DrawerClose (124-124)
packages/frontend/src/components/ui/separator.tsx (1)
  • Separator (26-26)
packages/sheet/src/store/local.ts (1)
packages/sheet/src/store/memory/memory.ts (1)
  • MemStore (14-122)
packages/frontend/src/components/ui/chart.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/tabs.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/input.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/select.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/drawer.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/nav-documents.tsx (2)
packages/frontend/src/components/ui/sidebar.tsx (7)
  • useSidebar (725-725)
  • SidebarGroup (705-705)
  • SidebarGroupLabel (708-708)
  • SidebarMenu (712-712)
  • SidebarMenuItem (716-716)
  • SidebarMenuButton (715-715)
  • SidebarMenuAction (713-713)
packages/frontend/src/components/ui/dropdown-menu.tsx (5)
  • DropdownMenu (242-242)
  • DropdownMenuTrigger (244-244)
  • DropdownMenuContent (245-245)
  • DropdownMenuItem (248-248)
  • DropdownMenuSeparator (252-252)
packages/frontend/src/components/ui/sheet.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/sidebar.tsx (8)
packages/frontend/src/hooks/use-mobile.ts (1)
  • useIsMobile (5-19)
packages/frontend/src/components/ui/tooltip.tsx (4)
  • TooltipProvider (59-59)
  • TooltipContent (59-59)
  • Tooltip (59-59)
  • TooltipTrigger (59-59)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
packages/frontend/src/components/ui/sheet.tsx (4)
  • SheetContent (134-134)
  • SheetHeader (135-135)
  • SheetTitle (137-137)
  • SheetDescription (138-138)
packages/frontend/src/components/ui/button.tsx (1)
  • Button (62-62)
packages/frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
packages/frontend/src/components/ui/separator.tsx (1)
  • Separator (26-26)
packages/frontend/src/components/ui/skeleton.tsx (1)
  • Skeleton (13-13)
packages/frontend/src/components/ui/table.tsx (1)
packages/frontend/src/lib/utils.ts (1)
  • cn (4-6)
🪛 Biome (1.9.4)
packages/frontend/tsconfig.node.json

[error] 9-9: JSON standard does not allow comments.

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: JSON standard does not allow comments.

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-24: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

packages/backend/src/auth/jwt-auth.guard.ts

[error] 6-8: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

packages/backend/src/auth/github.strategy.ts

[error] 23-23: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/frontend/tsconfig.app.json

[error] 10-10: JSON standard does not allow comments.

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: JSON standard does not allow comments.

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-25: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 25-25: JSON standard does not allow comments.

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 27-27: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 27-27: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 27-29: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 30-30: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-31: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-31: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-31: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-32: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

packages/frontend/src/components/ui/chart.tsx

[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (136)
.gitignore (1)

1-145: Comprehensive and Well-Organized Gitignore File
The file is well structured and covers a wide range of Node.js–specific artifacts including logs, caches, build outputs, and directories used by various tools (e.g., ESLint, Stylelint, Parcel, and frameworks like Next.js, Nuxt.js, Gatsby). The header comments from toptal’s generator add clarity on its origin.

packages/frontend/eslint.config.js (1)

1-29: Solid ESLint Configuration for Frontend
The ESLint configuration effectively integrates recommended settings from both the JavaScript and TypeScript ESLint plugins, and it also properly incorporates rules from react-hooks and react-refresh. The use of tseslint.config (assuming it is a valid helper from the typescript-eslint package or a project-specific abstraction) streamlines the setup. Just ensure that the parser and other environment nuances are appropriately managed by this configuration.

packages/sheet/src/vite-env.d.ts (1)

1-2: Correct Vite Type Reference Inclusion
The file correctly includes the reference to Vite’s client types, ensuring appropriate type-checking and autocompletion for Vite-related features in the project. This is essential for a smooth development experience with Vite.

packages/backend/.prettierrc (1)

1-4: Prettier configuration follows standard practices.

The configuration uses common best practices with single quotes and trailing commas. The minimal configuration keeps things simple while enforcing consistent formatting.

pnpm-workspace.yaml (1)

1-2: PNPM workspace configuration is correctly structured.

The workspace configuration properly specifies all packages under the packages/ directory to be included in the monorepo setup, which aligns with the PR objective of adding PNPM configuration to manage packages.

packages/backend/nest-cli.json (1)

1-8: NestJS configuration follows recommended project structure.

The configuration provides appropriate settings for a NestJS application with proper schema reference, source directory configuration, and compiler options. Setting deleteOutDir to true is a good practice to ensure clean builds.

packages/backend/src/app.module.ts (1)

1-15: LGTM! Standard NestJS module setup.

The AppModule is correctly structured according to NestJS conventions with proper imports and configuration. Making the ConfigModule global is a good practice to ensure configuration is accessible throughout the application.

packages/frontend/src/lib/utils.ts (1)

1-6: LGTM! Great utility function for Tailwind CSS class management.

The cn function is a common and useful pattern for React projects using Tailwind CSS. It correctly leverages clsx and tailwind-merge to handle class name combinations and resolve potential conflicts when classes are conditionally applied.

packages/backend/test/jest-e2e.json (1)

1-9: LGTM! Standard Jest E2E test configuration.

The configuration correctly sets up the test environment for end-to-end testing with TypeScript support. It follows Jest and NestJS testing conventions with appropriate test file pattern matching.

packages/frontend/src/main.tsx (1)

1-10: Overall, the React entry point is well-structured.
The file correctly imports required modules and uses createRoot to bootstrap the application wrapped in StrictMode, which is a best practice in React 18. The use of the non-null assertion (!) on the DOM element is common in TypeScript React projects, assuming that the element with id "root" is guaranteed to exist.

packages/frontend/tsconfig.json (1)

1-13: TypeScript configuration looks good.
The configuration leverages project references by pointing to tsconfig.app.json and tsconfig.node.json, and the alias mapping using "@/*" for ./src/* is clear and useful for module resolution. Just ensure that the referenced files exist and are maintained consistently.

packages/backend/tsconfig.build.json (1)

1-4: Backend build configuration is appropriately streamlined.
The file extends from the main tsconfig.json and correctly excludes directories and patterns (like test files, node_modules, and dist) to optimize the build process.

packages/frontend/vite.config.ts (1)

1-14: Vite configuration is well-formed and optimizes the development environment.
The configuration imports essential plugins, sets up a path alias for cleaner imports, and integrates both React and Tailwind CSS via the respective plugins. Ensure that the Tailwind plugin imported from "@tailwindcss/vite" is the correct (and intended) package for your setup.

packages/backend/src/auth/auth.module.ts (1)

14-17: Review JWT token expiration time for your application needs.

The JWT token is set to expire after 1 hour. Consider whether this duration is appropriate for your application's security requirements and user experience. Shorter durations enhance security but may frustrate users with frequent re-authentication.

For applications with sensitive data, you might want to:

  1. Use a shorter expiration (15-30 minutes)
  2. Implement a refresh token mechanism
  3. Add token invalidation on user logout
packages/frontend/.gitignore (1)

1-24: Standard .gitignore configuration for frontend development.

This is a well-structured .gitignore file that follows best practices for frontend development:

  • Covers logs from various package managers (npm, yarn, pnpm, lerna)
  • Excludes build artifacts (node_modules, dist, dist-ssr)
  • Ignores local configuration files
  • Excludes editor-specific files and OS-specific files

The configuration appears to be adapted from a standard Vite template.

packages/frontend/src/components/ui/sonner.tsx (2)

4-21: Good implementation of themed toast component.

The Toaster component effectively wraps the Sonner component with theme support and custom styling. The implementation:

  • Properly forwards props to the underlying component
  • Sets appropriate CSS custom properties for styling
  • Handles theme detection with fallback to "system"

5-5:

Details

✅ Verification successful

Verify theme context compatibility.

The destructured theme property assumes the theme context has a particular structure. Ensure this is compatible with the actual theme context being used, especially if you switch to the local theme implementation.


🏁 Script executed:

#!/bin/bash
# Check if the local useTheme hook returns a compatible interface

# Find the ThemeProviderContext definition to understand its structure
rg -A 10 "ThemeProviderContext" packages/frontend/src/components

Length of output: 2033


Theme Context Compatibility Verified

I confirmed that the useTheme hook (defined in packages/frontend/src/components/theme-provider.tsx) returns a context object that includes the theme property. The fallback value ("system") aligns with the default used in the ThemeProvider. No changes are required at this moment, but please ensure that any local theme implementation maintains this structure.

packages/frontend/src/app/login/page.tsx (1)

7-22: Well-structured responsive login layout.

The login page uses a responsive grid layout that adapts well to different screen sizes. The component:

  • Provides a clean, centered login form on smaller screens
  • Adds a background image on larger screens
  • Includes proper spacing and alignment
packages/sheet/src/store/local.ts (1)

4-4:

Details

❓ Verification inconclusive

Transition from DuckDB to in-memory storage.

The code has been modified to use MemStore instead of a DuckDB-based storage solution. While this simplifies the implementation, be aware of the following implications:

  1. Data persistence: In-memory stores don't persist data across page reloads
  2. Memory usage: Large datasets might consume significant memory
  3. Data migration: No clear path for migrating existing user data

Also applies to: 8-8


🏁 Script executed:

#!/bin/bash
# Check for any code that might depend on the persistent nature of DuckDB

# Look for code that might be affected by the change to in-memory storage
rg -A 3 -B 3 "createStore|LocalStore" --glob "!packages/sheet/src/store/local.ts" packages/

Length of output: 3450


Updated Transition Note: Verify In-Memory Store Trade-offs

The storage in packages/sheet/src/store/local.ts has been updated to import and use MemStore (see lines 4 and 8), replacing the old DuckDB-based implementation. This change has been confirmed by our tests—e.g., in the spreadsheet initialization and store tests—which now create stores via createStore that instantiate MemStore.

Please note the following implications of this transition:

  • Data Persistence: In-memory storage does not persist data across page reloads.
  • Memory Usage: Handling large datasets may increase memory consumption.
  • Data Migration: There isn’t a defined mechanism for migrating data from the previous DuckDB storage.

Review these trade-offs to ensure they align with your project’s requirements.

packages/frontend/src/PrivateRoute.tsx (1)

1-14: Well-implemented authentication route protection

The PrivateRoute component correctly implements a protected route pattern by checking authentication status with the useMe hook. It properly handles the loading state and redirects unauthenticated users to the login page. The implementation is clean, concise, and follows React best practices.

packages/frontend/src/components/ui/label.tsx (1)

1-24: Well-implemented accessible label component

The Label component is well-structured and follows best practices:

  1. Uses Radix UI primitives for accessibility
  2. Handles proper styling for different states (disabled, etc.)
  3. Correctly implements class name merging with the cn utility
  4. Maintains proper TypeScript typing with appropriate props forwarding

The component effectively handles the accessibility concerns through proper labeling and state management, which is crucial for form elements.

packages/frontend/src/components/site-header.tsx (2)

4-17: Simple and focused header component

The SiteHeader component is well-structured, using semantic HTML and proper component composition with the SidebarTrigger and Separator components. The layout follows a good pattern for application headers with proper spacing and organization.


6-6:

Details

❓ Verification inconclusive

Verify custom CSS syntax in class name

The class name contains unusual syntax that isn't standard Tailwind CSS:

h-(--header-height)

And complex selectors:

group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)

Consider:

  1. Confirming that this custom syntax is properly configured in your Tailwind setup
  2. Extracting complex class combinations into more readable utility classes or variables

🏁 Script executed:

#!/bin/bash
# Check if there's a tailwind config that might explain this custom syntax
fd -e js -e ts "tailwind.config" -x cat {}

Length of output: 44


Action Required: Verify Custom Tailwind CSS Configuration

The class names in question use non-standard syntax such as h-(--header-height) and the complex selector group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height). Our initial automated search for a Tailwind configuration file (which might explain this custom setup) didn’t return any results. Please double-check whether a custom configuration exists elsewhere (or if it might be configured in a non-conventional file) to support this syntax. If not, consider extracting these custom combinations into named utility classes or standard Tailwind utilities to improve clarity and maintainability.

  • File: packages/frontend/src/components/site-header.tsx, Line: 6
packages/backend/.gitignore (1)

1-56: Well-structured .gitignore file with comprehensive coverage

This is a well-organized .gitignore file that properly excludes all standard files and directories that shouldn't be tracked in a Node.js/NestJS project. The inclusion of pnpm-specific log files (line 10) aligns with the PR's objective of adding pnpm configuration.

packages/frontend/src/components/ui/card.tsx (2)

18-82: Well-implemented component composition pattern

The Card subcomponents (CardHeader, CardTitle, etc.) follow a consistent pattern and create a flexible, reusable card system. The use of data-slot attributes provides good styling hooks, and the className merging with the cn utility preserves custom styling capabilities.


84-92: Named exports provide good developer experience

Exporting all components individually rather than as a default export makes importing specific components easier and enables tree-shaking.

packages/frontend/src/app/dashboard/page.tsx (1)

1-22: Good implementation of the dashboard page component!

This component correctly implements a dashboard layout using sidebar, header, and data table components. The structure follows React best practices with clean JSX hierarchy and proper component composition.

packages/frontend/src/components/ui/separator.tsx (1)

6-24: Well-implemented primitive component with good defaults

The Separator component is properly constructed using the Radix UI primitive. Good use of destructuring props, default parameters, and conditional class name application with the cn utility.

packages/frontend/src/App.tsx (2)

9-25: Good routing implementation with authentication protection

The App component correctly sets up the application's routing structure with proper authentication checks through PublicRoute and PrivateRoute components. The use of ThemeProvider ensures consistent theming across the application.


12-12:

Details

✅ Verification successful

Verify that the VITE_SYNCUP_BASENAME environment variable is properly set

The router's basename is dynamically set from an environment variable. Ensure this variable is defined in all environments where the application will run.


🏁 Script executed:

#!/bin/bash
# Check if the VITE_SYNCUP_BASENAME environment variable is defined in .env files

echo "Checking for VITE_SYNCUP_BASENAME in environment files..."
fd "\.env.*" packages/frontend -x grep -l "VITE_SYNCUP_BASENAME" {} \;

# If not found, suggest adding it
if [ $? -ne 0 ]; then
  echo "Warning: VITE_SYNCUP_BASENAME not found in any .env files."
  echo "Consider adding it to ensure proper routing in different environments."
fi

Length of output: 216


Environment variable verified: No changes required
The review comment has been validated. The VITE_SYNCUP_BASENAME variable is present in the relevant .env files, so its usage in the <Router basename={import.meta.env.VITE_SYNCUP_BASENAME}> line is already properly integrated. Please ensure that this variable is also defined in all deployment configurations to maintain consistent routing behavior across environments.

packages/backend/package.json (2)

8-21: LGTM: Comprehensive set of NestJS scripts

The scripts section provides all the necessary commands for development, testing, and production, following NestJS best practices.


22-38:

Details

✅ Verification successful

Verify dependency versions for security and compatibility

The package includes several key dependencies for authentication and API functionality. Some packages have specific version requirements to ensure proper functioning.


🏁 Script executed:

#!/bin/bash
# Check for any known vulnerabilities in dependencies

echo "Checking for potential dependency issues..."
# Check for passport-github2 vulnerabilities (it's quite old)
echo "Checking passport-github2 (version 0.1.12)..."
curl -s "https://registry.npmjs.org/passport-github2" | jq '.time.modified, .homepage, .repository.url'

# Check if there are newer NestJS versions available
echo "Latest NestJS core version:"
curl -s "https://registry.npmjs.org/@nestjs/core" | jq '.["dist-tags"].latest'

Length of output: 591


Dependency Versions Verified

  • Verified that passport-github2 (version 0.1.12) shows a last modified timestamp from 2022 without any flagged vulnerabilities. However, its older update history may warrant a brief review to confirm ongoing maintenance.
  • Checked that @nestjs/core, specified as ^11.0.1, is compatible with the latest registry version (11.0.16), ensuring that the caret range will capture relevant patch updates as expected.
  • All other dependencies appear compliant with security and compatibility requirements.

No further modifications are needed at this time.

packages/frontend/tsconfig.node.json (3)

1-24: TypeScript configuration looks well structured

This is a good TypeScript configuration for a Node environment, particularly for use with Vite. The configuration appropriately:

  • Targets modern JavaScript (ES2022)
  • Enables strict type checking
  • Configures bundler mode
  • Sets up proper linting rules for code quality

The build info file is correctly placed in the node_modules/.tmp directory to avoid cluttering your source code.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-9: JSON standard does not allow comments.

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: JSON standard does not allow comments.

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-24: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


9-14: Good bundler configuration for Vite

The bundler mode configuration is appropriately set up for Vite with TypeScript, enabling features like importing TypeScript files with their extensions and ensuring proper module isolation.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-9: JSON standard does not allow comments.

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 10-10: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


16-21: Strong linting settings enabled

Excellent job enabling strict type checking and additional linting rules like:

  • noUnusedLocals and noUnusedParameters to catch unused code
  • noFallthroughCasesInSwitch to prevent logic errors
  • noUncheckedSideEffectImports for better tree-shaking

These will help maintain code quality as the project grows.

🧰 Tools
🪛 Biome (1.9.4)

[error] 16-16: JSON standard does not allow comments.

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 17-17: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

packages/frontend/src/components/ui/skeleton.tsx (2)

1-13: Well-implemented skeleton loading component

The Skeleton component is cleanly implemented with good use of:

  • Props spreading for flexibility
  • Class name composition using the cn utility
  • Appropriate default styling for a loading placeholder
  • Semantic data-slot attribute for component identification

This will work well as a loading placeholder throughout the application.


6-6: Good use of data attributes for component identification

Using data-slot="skeleton" provides a good semantic identifier for this component, which can be useful for both styling and testing purposes.

packages/frontend/index.html (1)

1-13: Standard Vite React TypeScript entry point

This is a well-structured HTML entry point for a Vite React TypeScript application with all the necessary elements:

  • Proper DOCTYPE declaration
  • Appropriate meta tags
  • Root div for React mounting
  • Module script pointing to the main entry point
packages/frontend/src/components/loader.tsx (2)

1-13: Well-implemented loading component with good accessibility

The Loader component is well structured with:

  • Proper use of aria-live for accessibility
  • Clear visual loading indicator
  • Helpful loading text
  • Good use of Tailwind classes for styling

This will provide a good user experience during loading states.


7-7: Good use of aria-live for accessibility

The aria-live="polite" attribute is a good accessibility practice, as it will notify screen readers of the loading state without interrupting their current task.

packages/backend/eslint.config.mjs (1)

29-33: LGTM! Sensible rule customizations.

The rule customizations are appropriate:

  • Disabling no-explicit-any provides flexibility when needed
  • Warning for floating promises and unsafe arguments helps catch common issues while still allowing the code to pass linting
packages/backend/tsconfig.json (1)

1-21: Solid TypeScript configuration for NestJS.

The configuration is well-structured for a NestJS application with appropriate strict type checking and modern JavaScript features enabled.

packages/frontend/src/components/ui/input.tsx (2)

1-4: Clean import pattern with well-organized dependencies

The import structure follows React best practices by importing React and the utility function needed for class name management.


21-22: Appropriate export pattern

Named export is used correctly, allowing for clean imports elsewhere in the codebase.

packages/frontend/src/components/ui/avatar.tsx (5)

1-7: Appropriate usage of Next.js directive and imports

The "use client" directive ensures this component works correctly with Next.js RSC. The imports are clean and follow best practices, specifically importing from Radix UI's Avatar primitives.


8-22: Well-structured Avatar component with proper composition

The Avatar component is implemented following best practices:

  • Uses Radix UI primitives as the foundation
  • Props are correctly typed using React.ComponentProps
  • Styling is applied using the cn utility
  • Data attributes provide hooks for testing or styling

24-35: Clean implementation of AvatarImage component

The AvatarImage component correctly extends the Radix UI primitive with appropriate styling. The aspect-square class ensures the image maintains its aspect ratio.


37-51: Comprehensive AvatarFallback implementation

The AvatarFallback component provides a well-styled fallback for when images aren't available. The styling ensures appropriate contrast and visual consistency.


53-53: Appropriate export pattern for component composition

The named exports for all three components facilitate the composition pattern, allowing users to import and use them together as needed.

packages/frontend/src/index.css (5)

1-4: Proper CSS framework imports and custom variant definition

The imports for Tailwind CSS and tw-animate-css are correctly specified. The custom variant for dark mode is well-defined using modern CSS selector syntax.


6-42: Comprehensive theme variable structure

The theme definition establishes a robust system of CSS variables for consistent styling across the application, including variables for radius, colors, and component-specific styling.


44-77: Well-structured light theme color definitions

The root variables define a comprehensive set of OKLCH color values for the light theme, providing a modern and perceptually uniform color system across the application.


79-111: Comprehensive dark theme implementation

The dark theme overrides maintain consistent variable names while providing appropriate contrast ratios. The color choices ensure readability and accessibility in dark mode.


113-120: Clean base layer styling

The base layer applies consistent border and outline styles globally and sets appropriate background and text colors for the body element, ensuring a solid foundation for the UI.

packages/frontend/src/components/nav-secondary.tsx (1)

1-13: Appropriate directive and imports for navigation component

The "use client" directive ensures compatibility with Next.js RSC. The imports are clean and appropriately structured, importing only the necessary components from the sidebar UI library.

packages/backend/src/auth/auth.service.ts (1)

4-10: User interface looks good, but consider validating critical fields

The User interface is well-structured with clear type definitions. The authProvider is properly restricted to 'github' which matches the strategy being implemented in the system.

Consider adding validation for the critical fields to ensure data integrity when creating tokens.

packages/sheet/package.json (2)

2-5: Package name and description updates align well with monorepo structure

The change from "wafflebase" to "@wafflebase/sheet" follows the standard scoped package naming convention, which is ideal for a monorepo setup with pnpm. The added description provides clarity about the package's purpose.


1-30:

Details

❓ Verification inconclusive

DuckDB dependencies have been removed

The removal of DuckDB and Apache Arrow dependencies suggests a shift in the data storage strategy, which aligns with the PR description about enhancing package management. Make sure the DuckDB functionality has been properly migrated or replaced in the codebase.


🏁 Script executed:

#!/bin/bash
# Check for any remaining DuckDB references in the codebase
echo "Checking for remaining DuckDB references:"
rg -i "duckdb" --type ts --stats packages/sheet/

Length of output: 300


Verified the removal of DuckDB references in packages/sheet

The DuckDB dependency has been successfully removed from the package (no duckdb matches were found in the TypeScript files in packages/sheet and the package.json snippet confirms its absence). Please ensure that any functionality previously reliant on DuckDB (and Apache Arrow) has been fully migrated or replaced elsewhere in the codebase.

  • No remaining duckdb references were found in the TS files within packages/sheet.
  • Confirm that all features formerly dependent on DuckDB now work with the new data management strategy.
packages/frontend/package.json (2)

12-46: Comprehensive UI component library choices

The dependency list includes a well-rounded set of modern UI libraries (Radix UI, DND Kit, TanStack, etc.) which should provide a solid foundation for building interactive interfaces. The structured approach using packages like class-variance-authority and tailwind-merge suggests a thoughtful, maintainable UI architecture.


36-38:

Details

❓ Verification inconclusive

Using very recent React version

The package is using React 19.0.0 which is a very recent version. Ensure compatibility with other dependencies as some third-party libraries might not have been updated to support React 19 yet.


🌐 Web query:

When was React 19 released and what are the major breaking changes?

💡 Result:

React 19 was officially released as stable on December 5, 2024 [4][7]. Prior to this, a beta version was available starting April 25, 2024 [1][6], with Release Candidates (RC) circulating earlier in the year.

Major Breaking Changes in React 19

1. New JSX Transform Requirement
React 19 mandates the new JSX transform, which automatically imports React and optimizes output. The legacy React.createElement syntax is no longer supported[5][8][9].

2. Legacy API Removals

  • ReactDOM.render replaced by ReactDOM.createRoot[5][8]
  • ReactDOM.hydrate replaced by ReactDOM.hydrateRoot[5]
  • react-test-renderer deprecated in favor of React Testing Library[8][9]

3. Error Handling Changes
New error reporting methods introduced:

  • onCaughtError for Error Boundary-caught errors
  • onUncaughtError for unhandled errors
  • onRecoverableError for auto-recovered errors[7][9]

4. Ref Handling

  • Function components now accept ref as a direct prop, eliminating forwardRef[6][9][10]
  • Legacy element.ref access deprecated in favor of element.props.ref[8]

5. Strict Mode Updates

  • Double-rendering in development now preserves useMemo/useCallback results between renders[8]
  • Improved simulation of Suspense behavior during mounting[8]

6. Dependency Requirements

  • TypeScript types now require @types/react@^19.0.0[8]
  • Third-party libraries must update React peer dependencies[6][8]

7. Suspense Hydration
New algorithm skips third-party script injections during hydration mismatches while preserving styles[7][9].

These changes aim to improve performance and developer experience but require careful testing during migration. The React team provides codemods and detailed upgrade guidance in their official documentation[7][8].

Citations:


React 19 Usage: Verify Dependency Compatibility

The package now uses React 19.0.0 (stable since December 5, 2024), which introduces several breaking changes (new JSX transform, deprecation of legacy APIs like ReactDOM.render/hydrate, updated error handling, etc.). Please ensure that all third-party libraries—especially those dependent on React internals—are compatible with these changes.

  • Location: packages/frontend/package.json (Lines 36-38)
  • Snippet:
        "react": "^19.0.0",
        "react-dom": "^19.0.0",
        "react-router-dom": "^7.5.0",
  • Action: Double-check that dependent libraries have updated their peer dependencies and support for React 19’s breaking changes.
packages/frontend/src/components/ui/badge.tsx (1)

1-46: Well-structured Badge component following best practices.

This Badge component is well-implemented, using the class-variance-authority package for managing style variants and Radix UI's Slot for component composition. The component has:

  • Proper TypeScript typing
  • Consistent accessibility attributes with data-slot
  • Good variant handling with default options
  • Flexible rendering with the asChild pattern

The implementation provides an elegant, reusable UI component that can be used throughout the application.

packages/frontend/src/components/ui/checkbox.tsx (1)

1-30: Well-implemented Checkbox component with accessibility features.

This Checkbox component correctly implements:

  • Radix UI primitives for accessibility
  • Comprehensive styling for various states (checked, unchecked, disabled)
  • Proper TypeScript typing
  • Consistent use of data-slot attributes for styling hooks
  • Clean indicator implementation with appropriate icon sizing

The implementation follows the same pattern as other UI components, maintaining consistency across the design system.

packages/frontend/src/components/ui/toggle.tsx (1)

1-47: Well-structured Toggle component with variant support.

Aside from the className issue, this Toggle component is well-implemented with:

  • Clean separation of concerns using Radix UI primitives
  • Comprehensive variant and size options
  • Proper TypeScript typing with VariantProps
  • Consistent accessibility with data-slot attributes
  • "use client" directive for client-side rendering compatibility

The toggleVariants implementation provides good flexibility for different visual styles and sizes.

packages/frontend/tsconfig.app.json (1)

1-32: TypeScript configuration looks appropriate for a modern React application.

The configuration provides a solid foundation with:

  • ES2020 target for modern browser compatibility
  • Strict type checking enabled for better code quality
  • Path aliases using the @/ prefix for cleaner imports
  • Bundler mode configuration suitable for tools like Vite
  • Comprehensive linting options to prevent common issues

The setup is well-structured and follows TypeScript best practices.

🧰 Tools
🪛 Biome (1.9.4)

[error] 10-10: JSON standard does not allow comments.

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 12-12: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 13-13: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 15-15: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-16: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 16-18: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 18-18: JSON standard does not allow comments.

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 19-19: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 20-20: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 21-21: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 22-22: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-23: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 23-25: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 25-25: JSON standard does not allow comments.

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 26-26: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 27-27: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 27-27: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 27-29: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 30-30: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-31: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-31: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-31: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 31-32: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

.github/workflows/ci.yml (3)

18-18: Successfully upgraded Node.js to version 22.x

The upgrade to Node.js version 22.x aligns with the PR objective of improving package management capabilities.


22-40: Good implementation of pnpm setup with efficient caching

The configuration correctly:

  1. Sets up pnpm with the latest action version
  2. Configures Node.js to use pnpm for caching
  3. Implements a dedicated cache for the pnpm store with proper key generation
  4. Uses conditional installation to avoid unnecessary work when cache is hit

This follows best practices for pnpm in GitHub Actions workflows.


41-54: Successfully migrated build commands to use pnpm

The build commands have been properly updated to use pnpm's workspace functionality for building frontend, backend, and sheet packages.

packages/frontend/src/components/nav-user.tsx (1)

79-82: Add onClick handler to Account menu item

The Account menu item doesn't have an onClick handler, making it non-functional. Either implement navigation to the account page or remove this menu item if it's not ready yet.

- <DropdownMenuItem>
+ <DropdownMenuItem onClick={() => window.location.href = "/account"}>

Is there an account page implementation that this should navigate to? If not, consider either implementing one or adding a TODO comment explaining future plans.

packages/frontend/src/components/ui/tabs.tsx (3)

6-17: LGTM! Well-structured tabs root component.

The Tabs component is well-structured and correctly implements the Radix UI primitive with good styling and organization.


19-33: LGTM! Well-structured tabs list component.

The TabsList component correctly implements the Radix UI primitive with appropriate styling and data attributes.


51-62: LGTM! Well-structured tabs content component.

The TabsContent component appropriately implements the Radix UI primitive with good styling.

packages/frontend/src/components/ui/button.tsx (2)

7-36: LGTM! Well-structured button variants.

The buttonVariants implementation using class-variance-authority is well organized with comprehensive styling options for different variants and sizes.


38-60: LGTM! Well-implemented Button component.

The Button component implementation is solid with good TypeScript types, proper handling of the asChild prop, and correct application of variants.

packages/frontend/src/hooks/useMe.ts (1)

20-20:

Details

❓ Verification inconclusive

Verify environment variable availability.

The hook directly accesses import.meta.env.VITE_BACKEND_API_URL, which might not be available at runtime if not properly configured in the build process.


🏁 Script executed:

#!/bin/bash
# Check if the VITE_BACKEND_API_URL environment variable is defined in .env files

# Check for .env files
echo "Checking for environment variable configurations:"
fd "\.env" --type f --exec grep -l "VITE_BACKEND_API_URL" {} \;

# Check Vite configuration for environment variable definitions
echo -e "\nChecking Vite configuration for environment variables:"
fd "vite\.config\.(js|ts)" --type f --exec grep -l "env" {} \;

Length of output: 366


Attention: Verify Environment Variable Configuration

The hook in packages/frontend/src/hooks/useMe.ts accesses import.meta.env.VITE_BACKEND_API_URL without any clear indication that this variable is defined at build time. Our initial search for its definition in standard .env files and Vite configuration files returned no results, so please manually confirm that the VITE_BACKEND_API_URL variable is provided (whether via a local .env, .env.local, or similar configuration file or through Vite’s configuration). This verification is crucial to prevent potential runtime issues if the variable isn’t properly set.

packages/frontend/src/components/nav-main.tsx (1)

11-19: Component props defined correctly with TypeScript

The component's props are well-defined with proper TypeScript typing, making it clear what data structure is expected.

packages/frontend/src/components/ui/toggle-group.tsx (2)

8-13: Context setup is appropriate

The context is properly set up with default values for the toggle variants.


15-39: Well-structured ToggleGroup component

The component correctly extends Radix UI's toggle group and provides context to its children.

packages/frontend/src/components/nav-documents.tsx (3)

28-38: Responsive design with useSidebar hook

Good use of the useSidebar hook to determine if the view is mobile and adjust the UI accordingly.


39-42: Group has conditional visibility

The group-data-[collapsible=icon]:hidden class suggests this group will be hidden when a parent element has the data-collapsible="icon" attribute. Make sure this behavior is properly documented and tested.


43-81: Document items with dropdown menus are implemented well

The component maps through items array to create menu entries with associated dropdown menus that adjust positioning based on mobile view. Good implementation of the dropdown menu with proper separation of actions.

packages/frontend/src/components/ui/tooltip.tsx (1)

19-33: Tooltip and TooltipTrigger are well-implemented

Both components correctly wrap the Radix UI primitives and add data attributes for styling and accessibility.

packages/frontend/src/components/theme-provider.tsx (1)

29-31: Consider handling unavailable or restricted localStorage scenarios.
If this component renders in an environment without localStorage (SSR, private mode, etc.), it may throw an error.

Would you like to conditionally check for window.localStorage availability before attempting to read or write?

packages/frontend/src/components/data-table.tsx (3)

264-264: Verify custom class syntax.
className="w-38 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate" looks like a custom or experimental selector.

Confirm that these selectors are recognized by your styling engine or tailwind configuration.


508-511: Check row uniqueness for DnD keys.
Your data is mapped by row.id. If multiple rows share an identical id, the table could have unstable keys.

Ensure all id fields are unique to avoid drag-and-drop collisions.


643-799: LGTM!
The drawer-based detail view with a chart is well-structured and uses responsive logic via useIsMobile.

packages/backend/src/auth/auth.controller.ts (1)

21-31: Consider adding domain/path configuration for cookies if needed.
Your logout endpoint clears the session cookie but defaults to sameSite: 'lax'. This may be sufficient, but some deployments require a specific domain or path.

Would you like a domain/path configuration for cross-subdomain usage or out-of-scope?

packages/frontend/src/components/ui/table.tsx (8)

7-20: Well-structured Table component.

The use of a wrapping <div> for horizontal scrolling is a good approach for large, overflowing tables. No issues found regarding logic or accessibility at this time.


22-30: Solid structure for TableHeader.

The component succinctly wraps <thead> with a data attribute for potential testing or styling. Implementation looks good.


32-40: TableBody component is clear.

Clean usage of React.ComponentProps<"tbody"> ensuring a valid, flexible container for table rows.


42-53: TableFooter styling is fine.

Background and border classes appear consistent with a typical table footer layout. No further comments.


55-66: TableRow transitions are well done.

Hover effects and row transitions are properly incorporated. No issues found.


81-92: TableCell component looks solid.

The approach is consistent with your other components. No logical or performance concerns.


94-105: Adequate design for TableCaption.

Applying a distinct style to the table caption is clear and consistent. Looks good.


107-116: Exports are well-defined.

All components are exported together, promoting easy consumption across the codebase.

packages/frontend/src/components/ui/breadcrumb.tsx (8)

7-9: Breadcrumb component is accessible.

Using aria-label="breadcrumb" on the <nav> helps screen readers identify the breadcrumb section. Good implementation.


11-22: BreadcrumbList structure is sound.

The usage of <ol> is semantically correct for breadcrumbs, and the added classes ensure proper styling.


24-32: BreadcrumbItem is straightforward.

Inline styling with data attributes is a nice pattern for consistent styling or testing.


34-50: BreadcrumbLink effectively manages anchor vs. Slot usage.

The asChild property provides good flexibility. This pattern can help integrate with other components or routing solutions.


52-63: BreadcrumbPage logic is appropriate.

Ensuring aria-current="page" helps assistive technology identify the current page. This is an accessibility best practice.


65-81: BreadcrumbSeparator clearly sets the separator.

Conditionally using <ChevronRight /> when children are absent is a neat fallback. No issues found.


83-99: BreadcrumbEllipsis is well-implemented.

Using MoreHorizontal along with screen-reader text meets accessibility guidelines for hidden elements.


101-109: Exports appear consistent.

All components are neatly exported for external usage.

packages/frontend/src/components/ui/chart.tsx (3)

105-247: ChartTooltipContent logic is robust.

A well-organized approach that cleanly handles multiple data series, custom labels, icons, and formatting. Looks good for typical Recharts usage.


305-342: getPayloadConfigFromPayload is well-structured.

The function safely checks and retrieves extra label or icon config from your chart configuration. No issues discovered.


80-101:

Details

✅ Verification successful

Potential XSS concern with dangerouslySetInnerHTML.

Even though you are generating CSS here, please ensure that no untrusted or user-supplied content flows into dangerouslySetInnerHTML. If there's any remote possibility of unsafe input, sanitize it or consider a different approach to injecting dynamic style rules.

To confirm whether any user-supplied content might flow into this prop, run the script below:


🏁 Script executed:

#!/bin/bash
# Search for references to ChartStyle and checks if user input merges in.
rg "ChartStyle"
rg "dangerouslySetInnerHTML"

Length of output: 405


Action Required: Confirm Safe Usage of dangerouslySetInnerHTML

The analysis shows that the generated CSS in <ChartStyle> originates from predefined constants (THEMES and colorConfig) and does not appear to incorporate any user-supplied input. However, please ensure that the id and any parts of the configuration remain exclusively controlled by trusted sources. Future changes should maintain this safeguard to avoid potential XSS risks.

  • Verify that the id and other configuration values come only from safe, validated sources.
  • Continue to monitor for any refactoring that might inadvertently merge untrusted input into these dynamic style rules.
🧰 Tools
🪛 Biome (1.9.4)

[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

packages/frontend/src/components/ui/drawer.tsx (5)

1-11: Well-structured wrapper components for Drawer.

Good implementation of the root Drawer component using the vaul library. The data-slot attribute provides a good way to target these elements in CSS and testing.


12-44: Clean implementation of Drawer primitive components.

These wrapper components (DrawerTrigger, DrawerPortal, DrawerClose, DrawerOverlay) follow a consistent pattern, passing through all props and adding appropriate data attributes. The DrawerOverlay especially has good animation handling with conditional classes.


46-71: Comprehensive DrawerContent implementation with directional support.

Great job implementing different positioning logic for the drawer (top, bottom, right, left) with appropriate styling for each direction. The use of data-vaul-drawer-direction attribute to conditionally apply styles is a smart approach.


73-117: Semantic drawer structure components properly implemented.

The header, footer, title and description components provide good semantic structure and styling options through className props. This allows for flexible customization while maintaining consistent default styling.


119-130: Complete export of drawer component API.

All component exports are organized clearly, making the API easy to use by consumers of this module.

packages/frontend/src/components/ui/select.tsx (7)

1-8: Client-side component setup with proper imports.

Good use of the "use client" directive and appropriate imports from Radix UI and Lucide React for icons.


9-26: Clean base Select component wrappers.

These primitive wrappers (Select, SelectGroup, SelectValue) follow a consistent pattern with appropriate data attributes for styling and targeting.


27-51: Well-designed SelectTrigger with size variants.

Good implementation of the SelectTrigger component with size variants ('sm' and 'default'). The comprehensive className string handles various states and styling needs efficiently.


53-86: Properly structured SelectContent with portal and viewport.

The SelectContent component correctly uses a portal for rendering and includes scroll buttons. The conditional styling based on the position is well implemented.


88-136: Clean implementation of select item components.

The SelectLabel, SelectItem, and SelectSeparator components follow consistent patterns with good accessibility considerations through data attributes.


138-172: Functional scroll button components.

Both scroll button implementations provide good user experience for navigating long select lists with appropriate icons and styling.


174-185: Complete and organized component exports.

All components are properly exported, providing a clean API for consumers of this module.

packages/frontend/src/components/ui/sheet.tsx (6)

1-8: Client-side component with proper imports.

Good use of the "use client" directive indicating client-side rendering, with appropriate imports from Radix UI Dialog primitives and Lucide React for icons.


9-29: Clean base Sheet component wrappers.

These primitive wrappers (Sheet, SheetTrigger, SheetClose, SheetPortal) follow a consistent pattern with appropriate data attributes for styling and targeting.


31-45: Well-implemented SheetOverlay with animations.

Good implementation of overlay with fade animations for open/close states. The fixed positioning and z-index ensure proper stacking and visual effects.


47-82: Flexible SheetContent with directional variants.

Excellent implementation of the content component with support for different sides (top, right, bottom, left) and appropriate animations for each direction. The close button is well positioned and includes screen reader text for accessibility.


84-128: Semantic structure components with consistent styling.

The header, footer, title and description components provide a consistent structure and styling options, following the same pattern as other UI components in the system.


130-139: Complete component exports.

All components are properly exported, providing a clean API for consumers of this module.

packages/frontend/src/components/ui/dropdown-menu.tsx (8)

1-13: Client-side component with proper imports.

Good use of the "use client" directive and appropriate imports for Radix UI dropdown menu primitives and icons.


15-52: Well-structured portal and content components.

The DropdownMenuPortal, DropdownMenuTrigger, and DropdownMenuContent components are implemented correctly, with the content component handling animations and positioning appropriately.


54-83: Flexible DropdownMenuItem with variant support.

Good implementation of the menu item with support for different variants (default, destructive) and an inset option. This provides flexibility for different use cases within the same component.


85-144: Well-implemented checkbox and radio components.

The checkbox and radio items include proper indicators and state handling. The positioning of the indicators is consistent and provides good visual feedback.


146-177: Consistent support components.

The label and separator components follow the same pattern as other components, providing consistent styling and behavior.


179-193: Useful shortcut component for keyboard commands.

The DropdownMenuShortcut component provides a nice way to display keyboard shortcuts within menu items, enhancing the usability of the dropdown menu.


195-239: Comprehensive submenu implementation.

The submenu components (Sub, SubTrigger, SubContent) provide a complete solution for nested menus, with appropriate styling and indicators.


241-257: Complete component exports.

All components are properly exported, providing a clean and comprehensive API for dropdown menu functionality.

packages/frontend/src/components/ui/sidebar.tsx (5)

45-54: Validate correct usage of throw statement in custom hook.
The useSidebar hook throws an error if not used within the SidebarProvider. This is fine, but be aware that any code referencing useSidebar outside of the provider will cause a runtime crash. Ensure you wrap any usage with <SidebarProvider>.


96-110: Ensure cleanup of event listeners.
You have correctly removed the "keydown" listener on component unmount, which is good. This ensures no memory leaks.


154-206: Thorough responsive logic.
Your approach to gracefully switch between a Sheet on mobile and a persistent sidebar on desktop demonstrates solid responsiveness. This improves mobile UX while preserving a full sidebar on bigger screens.


476-496: Review class-variance-authority usage.
Your sidebarMenuButtonVariants usage is comprehensive. Just ensure that any new variant or size you add is consistent with the existing styling pattern to prevent class bloat.


602-638: Confirm the skeleton loading pattern meets design expectations.
Generating random widths for Skeleton placeholders adds visual variety, which is often beneficial. Make sure your designers are aware of and approve this effect for a consistent loading state experience.

Comment thread packages/backend/src/auth/github-auth.guard.ts Outdated
Comment thread packages/backend/test/app.e2e-spec.ts Outdated
Comment thread packages/backend/test/app.e2e-spec.ts Outdated
Comment thread packages/backend/test/app.e2e-spec.ts Outdated
Comment thread packages/backend/test/app.e2e-spec.ts Outdated
Comment thread packages/frontend/src/hooks/useMe.ts Outdated
Comment thread packages/frontend/src/components/nav-main.tsx Outdated
Comment thread packages/frontend/src/components/nav-main.tsx
Comment thread packages/frontend/src/components/nav-documents.tsx Outdated
Comment thread packages/backend/src/auth/auth.controller.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (5)
packages/frontend/src/components/app-sidebar.tsx (1)

57-57: ⚠️ Potential issue

Avoid using non-null assertion with potential null values.

Using the non-null assertion operator (!) with me assumes it will never be null, which could lead to runtime errors if the API call fails but isLoading becomes false.

-        <NavUser user={me!} />
+        {me ? <NavUser user={me} /> : <div>No user data available</div>}
packages/frontend/src/hooks/useMe.ts (1)

5-26: 🛠️ Refactor suggestion

Implement a caching or revalidation strategy.

The current implementation fetches user data on every mount without any caching. For components that use this hook multiple times, this could lead to unnecessary API calls.

Consider using a data fetching library like SWR or React Query to handle caching, revalidation, and stale data. This would improve performance and reduce API calls.

What are the benefits of using SWR or React Query compared to custom fetch hooks?
packages/frontend/src/components/nav-main.tsx (1)

23-43: Add ARIA attributes for better accessibility.

The navigation implementation uses Link components correctly with proper URL handling. This addresses a previous issue where navigation items weren't linking to their URLs. Consider enhancing accessibility with ARIA attributes.

<SidebarMenuButton
  tooltip={item.title}
  isActive={isActive(item.url)}
>
-  <Link to={item.url} className="flex items-center gap-2">
+  <Link 
+    to={item.url} 
+    className="flex items-center gap-2"
+    aria-current={isActive(item.url) ? "page" : undefined}
+  >
    {item.icon && <item.icon />}
    <span>{item.title}</span>
  </Link>
</SidebarMenuButton>
packages/backend/src/auth/github.strategy.ts (1)

23-24: Use optional chaining for safer property access.

The current implementation could cause runtime errors if the emails or photos arrays are undefined or empty.

Replace the conditional operators with optional chaining:

return {
  githubId: id,
  username,
-  email: emails && emails[0].value,
-  photo: photos && photos[0].value,
+  email: emails?.[0]?.value,
+  photo: photos?.[0]?.value,
  accessToken,
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 23-23: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 24-24: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/backend/src/auth/auth.controller.ts (1)

33-55: Handle authentication errors.

Currently, there is no error-handling path if GitHub auth fails or the user denies access.

Add a catch-all route or exception handler to avoid redirect loops or silent failures.

🧹 Nitpick comments (5)
packages/frontend/src/components/nav-main.tsx (1)

12-44: Consider handling empty navigation items.

The component doesn't handle the case when the items array is empty. Consider adding a fallback UI or message when there are no navigation items to display.

export function NavMain({ items }: { items: Array<NavItem> }) {
  const location = useLocation();

  const isActive = useCallback(
    (url: string) => {
      const pathname = location.pathname;
      return pathname === url || pathname.startsWith(url + "/");
    },
    [location.pathname]
  );

  return (
    <SidebarGroup>
      <SidebarGroupContent className="flex flex-col gap-2">
        <SidebarMenu>
+         {items.length === 0 ? (
+           <div className="px-4 py-2 text-sm text-muted-foreground">
+             No navigation items available
+           </div>
+         ) : (
            {items.map((item) => (
              <SidebarMenuItem key={item.title}>
                <SidebarMenuButton
                  tooltip={item.title}
                  isActive={isActive(item.url)}
                >
                  <Link to={item.url} className="flex items-center gap-2">
                    {item.icon && <item.icon />}
                    <span>{item.title}</span>
                  </Link>
                </SidebarMenuButton>
              </SidebarMenuItem>
            ))}
+         )}
        </SidebarMenu>
      </SidebarGroupContent>
    </SidebarGroup>
  );
}
packages/backend/src/auth/auth.controller.ts (4)

24-28: Consider extracting cookie options to a common configuration.

Cookie options are duplicated between the logout and githubAuthCallback methods. This could lead to inconsistencies if one location is updated but not the other.

Extract the common cookie options to a private method or class property:

+private getCookieOptions() {
+  return {
+    httpOnly: true,
+    secure: process.env.NODE_ENV === 'production',
+    sameSite: 'lax',
+  };
+}

async logout(@Res() res: Response) {
-  res.clearCookie('wafflebase_session', {
-    httpOnly: true,
-    secure: process.env.NODE_ENV === 'production',
-    sameSite: 'lax',
-  });
+  res.clearCookie('wafflebase_session', this.getCookieOptions());

  return res.sendStatus(200);
}

And in the callback method:

res.cookie('wafflebase_session', token, {
-  httpOnly: true,
-  secure: process.env.NODE_ENV === 'production',
-  sameSite: 'lax',
+  ...this.getCookieOptions(),
   maxAge: 3600000,
});

35-37: Empty method implementation for GitHub authentication.

The githubAuth method has a comment but no implementation. While the AuthGuard will handle the redirect, it's better to be explicit about the expected behavior.

@Get('github')
@UseGuards(AuthGuard('github'))
-async githubAuth() {
-  // NOTE(hackerwins): Redirect to GitHub for authentication.
-}
+async githubAuth(@Req() req: Request, @Res() res: Response) {
+  // This method won't be executed as the AuthGuard redirects to GitHub
+  // This implementation handles edge cases where the guard somehow doesn't redirect
+  return res.status(500).json({ error: 'Authentication failed. Please try again.' });
+}

51-51: Consider making session duration configurable.

The session cookie maxAge is hardcoded to 1 hour (3600000 ms). This should ideally be configurable via environment variables.

+// In your ConfigService initialization or module
+// SESSION_DURATION=3600000

res.cookie('wafflebase_session', token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'lax',
-  maxAge: 3600000,
+  maxAge: parseInt(this.configService.get('SESSION_DURATION') || '3600000'),
});

15-19: Consider returning a consistent data structure.

The getMe endpoint directly returns the user object from the request. For API consistency, consider standardizing the response format across all endpoints.

@Get('me')
@UseGuards(JwtAuthGuard)
async getMe(@Req() req: Request & { user: User }) {
-  return req.user;
+  return {
+    success: true,
+    data: req.user,
+  };
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d040701 and 7b77aed.

📒 Files selected for processing (19)
  • packages/backend/src/auth/auth.controller.ts (1 hunks)
  • packages/backend/src/auth/auth.service.ts (1 hunks)
  • packages/backend/src/auth/github.strategy.ts (1 hunks)
  • packages/backend/src/auth/jwt.strategy.ts (1 hunks)
  • packages/frontend/src/App.tsx (1 hunks)
  • packages/frontend/src/api/auth.ts (1 hunks)
  • packages/frontend/src/app/Layout.tsx (1 hunks)
  • packages/frontend/src/app/documents/page.tsx (1 hunks)
  • packages/frontend/src/app/members/page.tsx (1 hunks)
  • packages/frontend/src/app/settings/page.tsx (1 hunks)
  • packages/frontend/src/components/app-sidebar.tsx (1 hunks)
  • packages/frontend/src/components/login-form.tsx (1 hunks)
  • packages/frontend/src/components/nav-main.tsx (1 hunks)
  • packages/frontend/src/components/nav-secondary.tsx (1 hunks)
  • packages/frontend/src/components/nav-user.tsx (1 hunks)
  • packages/frontend/src/components/site-header.tsx (1 hunks)
  • packages/frontend/src/hooks/useMe.ts (1 hunks)
  • packages/frontend/src/types/nav-items.ts (1 hunks)
  • packages/frontend/src/types/users.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/frontend/src/app/documents/page.tsx
  • packages/frontend/src/app/members/page.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/frontend/src/components/site-header.tsx
  • packages/backend/src/auth/jwt.strategy.ts
  • packages/frontend/src/components/nav-secondary.tsx
  • packages/frontend/src/components/nav-user.tsx
  • packages/backend/src/auth/auth.service.ts
  • packages/frontend/src/components/login-form.tsx
🧰 Additional context used
🧬 Code Graph Analysis (7)
packages/frontend/src/types/users.ts (1)
packages/backend/src/auth/auth.service.ts (1)
  • User (4-10)
packages/frontend/src/api/auth.ts (3)
packages/backend/src/auth/auth.controller.ts (1)
  • logout (23-31)
packages/backend/src/auth/auth.service.ts (1)
  • User (4-10)
packages/frontend/src/types/users.ts (1)
  • User (1-6)
packages/frontend/src/components/app-sidebar.tsx (5)
packages/frontend/src/types/nav-items.ts (1)
  • NavItem (1-5)
packages/frontend/src/hooks/useMe.ts (1)
  • useMe (5-26)
packages/frontend/src/components/nav-main.tsx (1)
  • NavMain (12-44)
packages/frontend/src/components/nav-secondary.tsx (1)
  • NavSecondary (13-37)
packages/frontend/src/components/nav-user.tsx (1)
  • NavUser (26-92)
packages/frontend/src/App.tsx (5)
packages/frontend/src/components/theme-provider.tsx (1)
  • ThemeProvider (23-64)
packages/frontend/src/PublicRoute.tsx (1)
  • PublicRoute (6-14)
packages/frontend/src/PrivateRoute.tsx (1)
  • PrivateRoute (6-14)
packages/frontend/src/app/Layout.tsx (1)
  • Layout (29-51)
packages/frontend/src/app/settings/page.tsx (1)
  • Settings (1-3)
packages/frontend/src/components/nav-main.tsx (2)
packages/frontend/src/types/nav-items.ts (1)
  • NavItem (1-5)
packages/frontend/src/components/ui/sidebar.tsx (5)
  • SidebarGroup (705-705)
  • SidebarGroupContent (707-707)
  • SidebarMenu (712-712)
  • SidebarMenuItem (716-716)
  • SidebarMenuButton (715-715)
packages/backend/src/auth/auth.controller.ts (2)
packages/backend/src/auth/auth.service.ts (1)
  • User (4-10)
packages/frontend/src/types/users.ts (1)
  • User (1-6)
packages/frontend/src/app/Layout.tsx (3)
packages/frontend/src/components/ui/sidebar.tsx (2)
  • SidebarProvider (721-721)
  • SidebarInset (711-711)
packages/frontend/src/components/app-sidebar.tsx (1)
  • AppSidebar (20-61)
packages/frontend/src/components/site-header.tsx (1)
  • SiteHeader (4-17)
🪛 Biome (1.9.4)
packages/backend/src/auth/github.strategy.ts

[error] 23-23: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 24-24: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (10)
packages/frontend/src/app/settings/page.tsx (1)

1-3: Simple, focused component implementation.

This is a straightforward implementation of a Settings page component. The component follows React's functional component pattern and serves as a placeholder for future Settings functionality.

packages/frontend/src/types/users.ts (1)

1-6: Consider aligning with backend User interface

The backend User interface in packages/backend/src/auth/auth.service.ts includes an id property and restricts authProvider to 'github', while this implementation has a more generic type without the id field.

Consider updating the User type to match the backend interface:

export type User = {
-  authProvider: string;
+  authProvider: 'github';
+  id: string;
  username: string;
  email: string;
  photo: string;
};
packages/frontend/src/types/nav-items.ts (1)

1-5: Well-structured type definition for nav items

This type definition for navigation items is clear and provides good type safety for components that use it.

packages/frontend/src/app/Layout.tsx (3)

7-27: Structured navigation items with clear organization

The navigation items are well-organized into main and secondary categories, each with appropriate properties. The structure aligns well with the NavItem type defined in the nav-items.ts file.


29-35: Effective title determination based on current route

The code correctly determines the page title by matching the current pathname against navigation items. The fallback to an empty string ensures there are no undefined values when no match is found.


36-51: Well-structured layout implementation

The layout implementation provides a good structure with sidebar and content areas. It uses context providers appropriately and passes the necessary props to child components.

packages/frontend/src/App.tsx (1)

1-35: Well-structured routing setup with proper access control.

The App component is well-organized with clear separation between public and private routes. The implementation of PublicRoute and PrivateRoute wrappers provides good authentication control, while the nested route structure with the Layout component ensures consistent UI across protected routes.

The use of environment variables for the router's basename is a good practice for flexibility across different deployment environments.

packages/frontend/src/api/auth.ts (1)

4-21: Good implementation of logout functionality with proper error handling.

The logout function correctly handles both server errors and network exceptions with appropriate user feedback via toast notifications.

packages/frontend/src/components/nav-main.tsx (2)

1-11: Appropriate imports and component dependencies.

The component correctly imports React Router's navigation elements and the required UI components from the sidebar library. The imports are well-organized and the component dependencies are properly structured.


12-22: Well-implemented active state detection.

The isActive function is correctly implemented using useCallback with the proper dependency array. The logic accurately determines if a navigation item is active by checking if the current path matches exactly or is a child route.

Comment thread packages/frontend/src/api/auth.ts Outdated
Comment thread packages/frontend/src/hooks/useMe.ts Outdated
Comment thread packages/backend/src/auth/github.strategy.ts
Comment thread packages/backend/src/auth/github.strategy.ts
Comment thread packages/backend/src/auth/github.strategy.ts
Comment thread packages/backend/src/auth/auth.controller.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
packages/frontend/src/api/auth.ts (1)

24-39: Improve error handling in fetchMe function

While the function handles basic error cases, there are opportunities to improve the error handling:

  1. The error message provides minimal information about what went wrong
  2. There's no specific handling for different HTTP status codes
export async function fetchMe(): Promise<User> {
  const res = await fetch(`${import.meta.env.VITE_BACKEND_API_URL}/auth/me`, {
    method: "GET",
    credentials: "include",
  });

  if (!res.ok) {
-    throw new Error("Failed to fetch user");
+    const errorText = await res.text();
+    throw new Error(`Failed to fetch user: ${res.status} ${errorText}`);
  }

  return res.json();
}
🧹 Nitpick comments (16)
package.json (2)

12-14: Populate project metadata fields.
The "keywords", "author", and other fields such as "repository" or "bugs" are empty or missing. Filling these improves discoverability and integrates better with tooling (e.g., CI, GitHub).


15-15: Review pnpm version pinning.
You’ve locked "packageManager": "[email protected]". Confirm that all contributors use exactly this version, or consider allowing patch updates (e.g., ^10.5.2) to ease maintenance.

packages/frontend/src/app/documents/page.tsx (1)

51-72: Consider adding loading state for document creation

The component displays the document list and creation button, but doesn't show any loading indicator while a new document is being created. This might lead to user confusion if the creation takes time.

<Button
  onClick={handleCreateDocument}
  className="flex items-center gap-2"
+ disabled={createDocumentMutation.isPending}
>
  <Plus className="w-4 h-4" />
- New Document
+ {createDocumentMutation.isPending ? "Creating..." : "New Document"}
</Button>
packages/frontend/src/api/documents.ts (2)

3-20: Consider enhancing the createDocument function

The function only accepts a title field in the payload, but the Document type includes other fields like description. Consider expanding the payload to match the expected document structure.

export async function createDocument(payload: {
  title: string;
+  description?: string;
}): Promise<Document> {
  const response = await fetch(
    `${import.meta.env.VITE_BACKEND_API_URL}/documents`,
    {
      method: "POST",
      headers: { 
        "Content-Type": "application/json",
+       // Add auth headers if needed
+       // "Authorization": `Bearer ${getToken()}`
      },
      body: JSON.stringify(payload),
    }
  );

  if (!response.ok) {
-    throw new Error("Failed to create document");
+    const errorText = await response.text();
+    throw new Error(`Failed to create document: ${response.status} ${errorText}`);
  }

-  return response.json();
+  return await response.json();
}

22-30: Enhance fetchDocuments with better error handling

The error handling in this function could be improved to include response details for debugging purposes.

export async function fetchDocuments(): Promise<Array<Document>> {
  const response = await fetch(
    `${import.meta.env.VITE_BACKEND_API_URL}/documents`,
+   {
+     headers: {
+       // Add auth headers if needed
+       // "Authorization": `Bearer ${getToken()}`
+     }
+   }
  );
  if (!response.ok) {
-    throw new Error("Failed to fetch documents");
+    const errorText = await response.text();
+    throw new Error(`Failed to fetch documents: ${response.status} ${errorText}`);
  }
  return await response.json();
}
packages/backend/src/documents/document.controller.ts (3)

9-18: Remove unused ConfigService

The ConfigService is injected in the constructor but not used anywhere in the controller. Consider removing it if it's not needed.

-import { ConfigService } from '@nestjs/config';

@Controller('documents')
export class DocumentController {
  constructor(
    private readonly documentService: DocumentService,
-   private readonly configService: ConfigService,
  ) {}

20-29: Improve error handling for ID conversion

The current implementation assumes IDs are always numeric. If the ID format changes in the future (e.g., to UUID), this would break. Consider adding error handling for the ID conversion.

@Get('/:id')
async getDocumentById(
  @Param('id') id: string,
): Promise<DocumentModel | null> {
+  let numericId: number;
+  try {
+    numericId = Number(id);
+    if (isNaN(numericId)) {
+      throw new Error('Invalid ID format');
+    }
+  } catch (error) {
+    throw new NotFoundException(`Invalid document ID format: ${id}`);
+  }
-  const doc = await this.documentService.document({ id: Number(id) });
+  const doc = await this.documentService.document({ id: numericId });
  if (!doc) {
    throw new NotFoundException(`document not found with id ${id}`);
  }
  return doc;
}

31-34: Add pagination to document listing

The current implementation fetches all documents without pagination, which could lead to performance issues as the collection grows. Consider adding pagination parameters.

+import { Query } from '@nestjs/common';

@Get('/')
async getDocuments(
+  @Query('skip') skip?: string,
+  @Query('take') take?: string,
): Promise<DocumentModel[]> {
-  return this.documentService.documents({});
+  const skipNum = skip ? parseInt(skip, 10) : undefined;
+  const takeNum = take ? parseInt(take, 10) : undefined;
+  
+  return this.documentService.documents({
+    skip: skipNum,
+    take: takeNum || 10, // Default limit to avoid large result sets
+  });
}
packages/backend/src/users/user.service.ts (4)

1-3: Fix the import path for PrismaService

Importing from 'src/database/prisma.service' uses an absolute path, which might cause issues in some build configurations. Use a relative path or configure path aliases.

import { Injectable } from '@nestjs/common';
import { User, Prisma } from '@prisma/client';
-import { PrismaService } from 'src/database/prisma.service';
+import { PrismaService } from '../database/prisma.service';

5-8: Add documentation to the service class

Adding JSDoc comments to the class and methods would improve code readability and help other developers understand how to use this service.

+/**
+ * Service for managing user entities in the database.
+ * Provides methods for CRUD operations on users.
+ */
@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

34-38: Make createUser method signature consistent with updateUser

For consistency with the update method, consider using a params object with a separate data field for the createUser method.

-async createUser(data: Prisma.UserCreateInput): Promise<User> {
+async createUser(params: {
+  data: Prisma.UserCreateInput;
+}): Promise<User> {
+  const { data } = params;
  return this.prisma.user.create({
    data,
  });
}

51-55: Add existence check before deletion

The current implementation doesn't check if the user exists before deletion, which could lead to cryptic errors. Add a check to provide a clearer error message.

async deleteUser(where: Prisma.UserWhereUniqueInput): Promise<User> {
+  // Check if user exists
+  const user = await this.prisma.user.findUnique({
+    where,
+  });
+  
+  if (!user) {
+    throw new Error(`User not found for deletion`);
+  }
+  
  return this.prisma.user.delete({
    where,
  });
}
packages/backend/src/documents/document.service.ts (4)

9-11: Parameter name should be documentWhereUniqueInput for consistency.

The parameter name postWhereUniqueInput appears to be a copy-paste error from a Post service. Rename it to documentWhereUniqueInput to maintain consistency with the Document entity being operated on.

 async document(
-  postWhereUniqueInput: Prisma.DocumentWhereUniqueInput,
+  documentWhereUniqueInput: Prisma.DocumentWhereUniqueInput,
 ): Promise<Document | null> {

12-14: Update variable reference to match renamed parameter.

After renaming the parameter, update the reference in the where clause to maintain consistency.

 return this.prisma.document.findUnique({
-  where: postWhereUniqueInput,
+  where: documentWhereUniqueInput,
 });

38-38: Remove console.log statement before deploying to production.

Console logging should be removed from production code. Consider using a proper logging service if you need to track document creation events.

-    console.log('doc', doc);

5-60: Consider implementing pagination metadata for the documents method.

The documents method returns an array of Document objects but doesn't provide pagination metadata (total count, page information, etc.). This information is often useful for frontend UI components like data tables.

Consider modifying the return type to include pagination metadata:

async documents(params: {
  skip?: number;
  take?: number;
  cursor?: Prisma.DocumentWhereUniqueInput;
  where?: Prisma.DocumentWhereInput;
  orderBy?: Prisma.DocumentOrderByWithRelationInput;
}): Promise<{ data: Document[]; count: number; }> {
  const { skip, take, cursor, where, orderBy } = params;
  
  const [data, count] = await Promise.all([
    this.prisma.document.findMany({
      skip,
      take,
      cursor,
      where,
      orderBy,
    }),
    this.prisma.document.count({ where }),
  ]);
  
  return { data, count };
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7b77aed and 3dd5ca7.

⛔ Files ignored due to path filters (2)
  • packages/backend/prisma/dev.db is excluded by !**/*.db
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (25)
  • package.json (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/prisma/migrations/20250419011142_init/migration.sql (1 hunks)
  • packages/backend/prisma/migrations/20250419025308_init/migration.sql (1 hunks)
  • packages/backend/prisma/migrations/migration_lock.toml (1 hunks)
  • packages/backend/prisma/schema.prisma (1 hunks)
  • packages/backend/src/app.module.ts (1 hunks)
  • packages/backend/src/database/prisma.service.ts (1 hunks)
  • packages/backend/src/documents/document.controller.ts (1 hunks)
  • packages/backend/src/documents/document.module.ts (1 hunks)
  • packages/backend/src/documents/document.service.ts (1 hunks)
  • packages/backend/src/users/user.service.ts (1 hunks)
  • packages/frontend/package.json (1 hunks)
  • packages/frontend/src/App.tsx (1 hunks)
  • packages/frontend/src/PrivateRoute.tsx (1 hunks)
  • packages/frontend/src/PublicRoute.tsx (1 hunks)
  • packages/frontend/src/api/auth.ts (1 hunks)
  • packages/frontend/src/api/documents.ts (1 hunks)
  • packages/frontend/src/app/Layout.tsx (1 hunks)
  • packages/frontend/src/app/documents/page.tsx (1 hunks)
  • packages/frontend/src/components/app-sidebar.tsx (1 hunks)
  • packages/frontend/src/components/data-table.tsx (1 hunks)
  • packages/frontend/src/components/nav-user.tsx (1 hunks)
  • packages/frontend/src/index.css (1 hunks)
  • packages/frontend/src/types/documents.ts (1 hunks)
✅ Files skipped from review due to trivial changes (7)
  • packages/frontend/src/types/documents.ts
  • packages/backend/prisma/migrations/migration_lock.toml
  • packages/backend/prisma/migrations/20250419011142_init/migration.sql
  • packages/backend/src/documents/document.module.ts
  • packages/frontend/src/index.css
  • packages/frontend/src/app/Layout.tsx
  • packages/backend/prisma/schema.prisma
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/backend/src/app.module.ts
  • packages/frontend/src/components/nav-user.tsx
  • packages/frontend/src/PublicRoute.tsx
  • packages/frontend/package.json
  • packages/backend/package.json
  • packages/frontend/src/components/app-sidebar.tsx
  • packages/frontend/src/App.tsx
  • packages/frontend/src/components/data-table.tsx
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/backend/src/documents/document.service.ts (3)
packages/backend/src/database/prisma.service.ts (1)
  • Injectable (4-16)
packages/backend/src/users/user.service.ts (1)
  • Injectable (5-56)
packages/frontend/src/types/documents.ts (1)
  • Document (1-7)
packages/frontend/src/api/auth.ts (2)
packages/backend/src/auth/auth.controller.ts (1)
  • logout (23-31)
packages/frontend/src/types/users.ts (1)
  • User (1-6)
packages/frontend/src/PrivateRoute.tsx (2)
packages/frontend/src/api/auth.ts (1)
  • fetchMe (28-39)
packages/frontend/src/components/loader.tsx (1)
  • Loader (3-13)
packages/frontend/src/app/documents/page.tsx (3)
packages/frontend/src/types/documents.ts (1)
  • Document (1-7)
packages/frontend/src/api/documents.ts (2)
  • fetchDocuments (22-30)
  • createDocument (3-20)
packages/frontend/src/components/data-table.tsx (1)
  • DataTable (102-244)
packages/frontend/src/api/documents.ts (3)
packages/backend/src/documents/document.controller.ts (1)
  • createDocument (37-41)
packages/backend/src/documents/document.service.ts (1)
  • createDocument (34-40)
packages/frontend/src/types/documents.ts (1)
  • Document (1-7)
packages/backend/src/users/user.service.ts (2)
packages/backend/src/documents/document.service.ts (1)
  • Injectable (5-60)
packages/backend/src/database/prisma.service.ts (1)
  • Injectable (4-16)
🔇 Additional comments (8)
package.json (1)

16-18: Dev dependency looks good.
Adding concurrently is appropriate for orchestrating parallel processes in the dev script.

packages/backend/src/database/prisma.service.ts (1)

1-16: Well-structured Prisma service implementation

This is a well-implemented service class that properly integrates Prisma with the NestJS lifecycle. The class correctly:

  • Extends PrismaClient for database operations
  • Implements OnModuleInit and OnModuleDestroy interfaces
  • Connects to the database when the module initializes
  • Disconnects when the module is destroyed

This implementation ensures proper resource management and follows NestJS best practices for database integration.

packages/frontend/src/PrivateRoute.tsx (1)

7-19: Robust authentication route guard implementation

The PrivateRoute component correctly implements route protection based on authentication status. It:

  • Uses React Query to fetch the current user data
  • Shows a loading state while authentication is being verified
  • Renders child routes only for authenticated users
  • Redirects unauthenticated users to the login page
  • Disables automatic retries with retry: false which is appropriate for auth checks

This implementation follows React best practices for protected routes and properly handles the authentication flow.

packages/frontend/src/api/auth.ts (1)

4-22: Well-documented logout function

The logout implementation is clear and properly documented with JSDoc comments. It correctly:

  • Makes a POST request to the logout endpoint
  • Includes credentials to ensure cookies are sent
  • Throws an error on failure
  • Shows a success notification on successful logout

This follows best practices for API interactions.

packages/frontend/src/app/documents/page.tsx (2)

8-33: Well-structured document management implementation

This component correctly implements document fetching and creation using React Query. The code:

  • Uses appropriate hooks for querying and mutations
  • Properly invalidates the query cache after creating a document
  • Handles the document creation flow efficiently
  • Provides good separation of concerns between data fetching and UI rendering

This follows modern React and data fetching best practices.


34-49: Good user feedback for loading and error states

The component provides clear visual feedback to users when documents are loading or when an error occurs. The centered messages with appropriate styling improve the user experience.

packages/backend/prisma/migrations/20250419025308_init/migration.sql (1)

1-21: Migration script looks good

The migration script correctly removes the published column from the Document table using the SQLite approach of creating a new table, copying data, dropping the old table, and renaming. Foreign key constraints are properly managed with temporary disabling and re-enabling.

packages/backend/src/documents/document.service.ts (1)

1-60: The implementation follows NestJS and Prisma best practices.

The service is well-structured with appropriate dependency injection and follows a consistent pattern for CRUD operations. The code structure is similar to the UserService implementation, which promotes consistency throughout the application.

Comment thread package.json
Comment thread package.json Outdated
Comment thread packages/backend/src/documents/document.controller.ts Outdated
Comment thread packages/backend/src/documents/document.service.ts
- Introduced a new type `Document` in `documents.ts` with fields: id, title, description, createdAt, and updatedAt.
- Updated `pnpm-lock.yaml` to include new dependencies and versions:
  - Added `@prisma/client` and `@tanstack/react-query` with specified versions.
  - Updated `lucide-react` to version 0.501.0.
  - Updated `globals` and `typescript` to versions 16.0.0 and 5.8.3 respectively.
  - Added `concurrently` version 9.1.2 and `esbuild-register` version 3.6.0.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (5)
packages/frontend/src/app/documents/document-list.tsx (2)

43-115: Wrap columns in useMemo to prevent table‑state resets on every render

columns is re‑created on each component render, which causes a new table instance to be built every time. This can reset pagination, sorting, and selection state, and it allocates unnecessary memory.

-  const columns: Array<ColumnDef<Document>> = [
+  const columns: Array<ColumnDef<Document>> = React.useMemo(
+    () => [
       /* … column defs … */
-  ];
+    ],
+    [deleteDocumentMutation], // memo deps
+  );

117-126: Add loading/disabled states for document mutations

While a mutation is in‑flight users can click buttons multiple times, potentially spamming the backend with identical requests. Disable actions while isLoading is true and surface errors from onError.

 const createDocumentMutation = useMutation({
   mutationFn: async (data: { title: string }) => await createDocument(data),
-  onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
+  onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
+  onError: (e: unknown) => toast.error(`${e}`),
 });

And for the button:

-        <Button
-          onClick={() => {
-            createDocumentMutation.mutate({ title: "New Document" });
-          }}
-          className="flex items-center gap-2"
-        >
+        <Button
+          onClick={() => createDocumentMutation.mutate({ title: "New Document" })}
+          className="flex items-center gap-2"
+          disabled={createDocumentMutation.isLoading}
+        >
packages/sheet/src/store/local.ts (1)

7-10: createStore no longer needs to be async

After dropping the DuckDB path the function is fully synchronous. Keeping async unnecessarily wraps the return value in Promise.resolve, adds micro‑task overhead, and may mislead future maintainers.

-export async function createStore(): Promise<LocalStore> {
-  const store = new MemStore();
-  return new LocalStore(store);
-}
+export function createStore(): LocalStore {
+  const store = new MemStore();
+  return new LocalStore(store);
+}
packages/sheet/src/worksheet/sheet.ts (1)

24-27: Document the reduced row limit (now 700 000) and make it configurable

Changing Dimensions.rows from ~2 billion to 700 000 is a breaking behavioural change for consumers relying on the prior limit. Capture the motivation in code comments and consider surfacing it as a configurable value rather than a constant to maximise flexibility.

packages/sheet/src/spreadsheet/worksheet.ts (1)

861-868: Minor style optimisation

Repeated calls to getThemeColor during every paint tick could allocate strings unnecessarily.
Cache the resolved colors at construction time:

private colors = (this.theme === 'light' ? LightTheme : DarkTheme) as const;
...
ctx.fillStyle = selected ? this.colors.headerActiveBGColor : this.colors.headerBGColor;

This is purely a micro‑optimisation but keeps the hot rendering path lean.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3dd5ca7 and 21a9994.

⛔ Files ignored due to path filters (2)
  • packages/backend/prisma/dev.db is excluded by !**/*.db
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (36)
  • package.json (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/prisma/migrations/20250419011142_init/migration.sql (1 hunks)
  • packages/backend/prisma/migrations/20250419025308_init/migration.sql (1 hunks)
  • packages/backend/prisma/migrations/migration_lock.toml (1 hunks)
  • packages/backend/prisma/schema.prisma (1 hunks)
  • packages/backend/src/app.module.ts (1 hunks)
  • packages/backend/src/database/prisma.service.ts (1 hunks)
  • packages/backend/src/documents/document.controller.ts (1 hunks)
  • packages/backend/src/documents/document.module.ts (1 hunks)
  • packages/backend/src/documents/document.service.ts (1 hunks)
  • packages/backend/src/users/user.service.ts (1 hunks)
  • packages/frontend/package.json (1 hunks)
  • packages/frontend/src/App.tsx (1 hunks)
  • packages/frontend/src/PrivateRoute.tsx (1 hunks)
  • packages/frontend/src/PublicRoute.tsx (1 hunks)
  • packages/frontend/src/api/auth.ts (1 hunks)
  • packages/frontend/src/api/documents.ts (1 hunks)
  • packages/frontend/src/app/Layout.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-detail.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-list.tsx (1 hunks)
  • packages/frontend/src/app/documents/page.tsx (1 hunks)
  • packages/frontend/src/components/app-sidebar.tsx (1 hunks)
  • packages/frontend/src/components/nav-user.tsx (1 hunks)
  • packages/frontend/src/index.css (1 hunks)
  • packages/frontend/src/types/documents.ts (1 hunks)
  • packages/frontend/vite.config.ts (1 hunks)
  • packages/sheet/package.json (1 hunks)
  • packages/sheet/src/index.ts (1 hunks)
  • packages/sheet/src/main.ts (1 hunks)
  • packages/sheet/src/spreadsheet/spreadsheet.ts (2 hunks)
  • packages/sheet/src/spreadsheet/worksheet.ts (10 hunks)
  • packages/sheet/src/store/local.ts (1 hunks)
  • packages/sheet/src/worksheet/sheet.ts (2 hunks)
  • packages/sheet/src/worksheet/types.ts (0 hunks)
  • packages/sheet/vite.build.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/sheet/src/worksheet/types.ts
✅ Files skipped from review due to trivial changes (5)
  • packages/sheet/src/main.ts
  • packages/sheet/vite.build.ts
  • packages/sheet/src/index.ts
  • packages/frontend/src/index.css
  • packages/backend/package.json
🚧 Files skipped from review as they are similar to previous changes (23)
  • packages/backend/prisma/migrations/migration_lock.toml
  • packages/backend/src/app.module.ts
  • packages/backend/src/documents/document.module.ts
  • packages/frontend/src/PublicRoute.tsx
  • packages/frontend/src/app/documents/page.tsx
  • packages/backend/src/database/prisma.service.ts
  • packages/frontend/vite.config.ts
  • packages/frontend/src/api/auth.ts
  • packages/frontend/src/PrivateRoute.tsx
  • packages/frontend/src/app/Layout.tsx
  • packages/frontend/src/components/app-sidebar.tsx
  • packages/frontend/src/api/documents.ts
  • package.json
  • packages/backend/src/users/user.service.ts
  • packages/backend/src/documents/document.controller.ts
  • packages/backend/prisma/schema.prisma
  • packages/frontend/src/App.tsx
  • packages/frontend/src/types/documents.ts
  • packages/frontend/src/components/nav-user.tsx
  • packages/backend/prisma/migrations/20250419025308_init/migration.sql
  • packages/backend/prisma/migrations/20250419011142_init/migration.sql
  • packages/frontend/package.json
  • packages/backend/src/documents/document.service.ts
🧰 Additional context used
🧬 Code Graph Analysis (4)
packages/sheet/src/store/local.ts (1)
packages/sheet/src/store/memory/memory.ts (1)
  • MemStore (14-122)
packages/sheet/src/worksheet/sheet.ts (1)
packages/sheet/src/worksheet/types.ts (1)
  • Ref (26-29)
packages/frontend/src/app/documents/document-list.tsx (9)
packages/frontend/src/types/documents.ts (1)
  • Document (1-7)
packages/frontend/src/components/ui/checkbox.tsx (1)
  • Checkbox (30-30)
packages/frontend/src/components/ui/dropdown-menu.tsx (4)
  • DropdownMenu (242-242)
  • DropdownMenuTrigger (244-244)
  • DropdownMenuContent (245-245)
  • DropdownMenuLabel (247-247)
packages/frontend/src/components/ui/button.tsx (1)
  • Button (62-62)
packages/backend/src/documents/document.controller.ts (2)
  • createDocument (38-42)
  • deleteDocument (45-51)
packages/backend/src/documents/document.service.ts (2)
  • createDocument (34-40)
  • deleteDocument (53-59)
packages/frontend/src/api/documents.ts (2)
  • createDocument (4-21)
  • deleteDocument (33-47)
packages/frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
packages/frontend/src/components/ui/table.tsx (6)
  • Table (108-108)
  • TableHeader (109-109)
  • TableRow (113-113)
  • TableHead (112-112)
  • TableBody (110-110)
  • TableCell (114-114)
packages/sheet/src/spreadsheet/worksheet.ts (2)
packages/sheet/src/spreadsheet/spreadsheet.ts (1)
  • Theme (7-7)
packages/sheet/src/worksheet/sheet.ts (1)
  • Sheet (31-439)
🪛 GitHub Actions: Frontend CI
packages/frontend/src/app/documents/document-detail.tsx

[error] 6-6: TypeScript error TS6133: 'id' is declared but its value is never read.

🔇 Additional comments (8)
packages/frontend/src/app/documents/document-detail.tsx (1)

11-38: Simplify mounting logic & ensure cleanup on route changes

The extra didMount state adds another render cycle and the effect will not rerun if the document ID changes.
You can rely on useEffect with the container ref and (optionally) id as dependencies:

-  const [didMount, setDidMount] = useState(false);
...
-  useEffect(() => {
-    setDidMount(true);
-  }, []);
-
-  useEffect(() => {
-    if (!containerRef.current) {
-      return;
-    }
-    async function setupSpreadsheet() {
-      if (!didMount) {
-        return;
-      }
-      const cleanup = await setup(containerRef.current!, { theme: 'dark' });
-      cleanupRef.current = cleanup;
-    }
-    setupSpreadsheet();
-    return () => {
-      if (cleanupRef.current) {
-        cleanupRef.current();
-        cleanupRef.current = null;
-      }
-    };
-  }, [didMount, containerRef]);
+  useEffect(() => {
+    if (!containerRef.current) return;
+
+    (async () => {
+      cleanupRef.current = await setup(containerRef.current, { theme: 'dark' });
+    })();
+
+    return () => {
+      cleanupRef.current?.();
+      cleanupRef.current = null;
+    };
+  }, [containerRef, _id]);  // rerun when navigating to a different document

Benefits: one render shorter, easier to reason about, and spreadsheet re‑initialises when navigating between document IDs without unmounting the component.
[ suggest_essential_refactor ]

packages/sheet/src/spreadsheet/spreadsheet.ts (1)

19-24: Return type & unnecessary await

createStore() is described as synchronous; awaiting a sync function is harmless but misleading and forces the surrounding setup to stay async.
Consider:

-export async function setup(container: HTMLDivElement, options?: SetupOptions) {
-  const spreadsheet = new Spreadsheet(container, options);
-  const store = await createStore();
+export function setup(container: HTMLDivElement, options?: SetupOptions): Promise<() => void> | (() => void) {
+  const spreadsheet = new Spreadsheet(container, options);
+  const store = createStore();

If createStore is indeed synchronous you can remove the async/await pair and return the cleanup function directly; otherwise keep the current form but add an explicit return type (Promise<() => void>).
[ suggest_optional_refactor ]

packages/sheet/src/spreadsheet/worksheet.ts (1)

212-218: Type‐safety for theme keys

getThemeColor(key: string) allows any string and may return undefined, which later gets assigned to style.* or canvas colors.
Define a shared ThemeColorKey instead:

-  public getThemeColor(key: string) {
+  type ThemeColorKey = keyof typeof LightTheme;
+
+  public getThemeColor(key: ThemeColorKey) {

This guarantees compile‑time safety when adding new theme colors or refactoring existing ones.
[ suggest_optional_refactor ]

packages/sheet/package.json (5)

2-2: Verify scoped package naming across workspaces.

You’ve renamed the package to @wafflebase/sheet. Ensure this matches the entries in your root pnpm-workspace.yaml (or equivalent), and update any import/require paths in consuming packages to use the new scope.


5-5: Great addition of description.

Adding "description": "Frontend for Wafflebase" improves clarity for consumers and on registry listings.


17-17: Build script switched to custom Vite config.

Using vite --config vite.build.ts build reflects the new library build setup. This is correct and aligns with the added vite.build.ts file.


20-20: Prettier format script added.

Including "format": "prettier --write ." is a good move to keep styling consistent across the package.


28-28: Dev dependency version bumps.

You’ve upgraded prettier, vite, vite-plugin-node-polyfills, and vitest to recent majors. These versions look reasonable, but be sure to run full CI to catch any compatibility issues with your existing codebase.

Also applies to: 30-32

Comment thread packages/frontend/src/app/documents/document-list.tsx
Comment thread packages/sheet/src/worksheet/sheet.ts
Comment thread packages/frontend/src/app/documents/document-detail.tsx Outdated
Comment thread packages/sheet/src/spreadsheet/worksheet.ts
Comment thread packages/sheet/src/spreadsheet/worksheet.ts Outdated
Comment thread packages/sheet/package.json
Comment thread packages/sheet/package.json Outdated
Comment thread packages/sheet/package.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/sheet/src/spreadsheet/worksheet.ts (2)

91-97: Event‐listener registry is solid but could use stricter typing

Storing { element, type, handler } enables deterministic cleanup – nice!
If you want to tighten the API, consider generics so handler’s parameter type is derived from type (similar to your K extends keyof … trick below).


537-541: Frequent render() calls may pile up unresolved async work

render() invokes the async paintSheet() but doesn’t await it.
With rapid scroll or resize events, you can spawn overlapping paintSheet() executions, risking race conditions and unnecessary DOM/canvas work.

Consider debouncing with requestAnimationFrame or tracking a single in‑flight promise:

private renderPending?: Promise<void>;

private render = () => {
  if (this.renderPending) { return; }
  this.renderPending = (async () => {
    this.paintFormulaBar();
    await this.paintSheet();     // now awaited
    this.paintOverlay();
  })().finally(() => { this.renderPending = undefined; });
};

This keeps UI responsive while preventing uncontrolled concurrency.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8e55869 and 30f21d2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • packages/frontend/src/app/Layout.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-detail.tsx (1 hunks)
  • packages/sheet/package.json (1 hunks)
  • packages/sheet/src/index.ts (1 hunks)
  • packages/sheet/src/spreadsheet/spreadsheet.ts (2 hunks)
  • packages/sheet/src/spreadsheet/worksheet.ts (12 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/sheet/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/frontend/src/app/Layout.tsx
  • packages/frontend/src/app/documents/document-detail.tsx
  • packages/sheet/package.json
  • packages/sheet/src/spreadsheet/spreadsheet.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)
packages/sheet/src/spreadsheet/spreadsheet.ts (1)
  • Theme (7-7)
🔇 Additional comments (3)
packages/sheet/src/spreadsheet/worksheet.ts (3)

190-199: 👍 Bound handlers solve the previous leak

Great job binding the handlers once and storing them as fields – this directly addresses memory‑leak reports from the earlier review.


214-229: Wrapper adds/removes listeners safely

The private addEventListener helper and removeAllEventListeners guarantee balanced add/remove pairs and simplify cleanup(). Well done.


851-865: Nice theme integration in overlay drawing

Using getThemeColor for active‑cell and selection visuals centralises styling and simplifies future theme tweaks.

Comment thread packages/sheet/src/spreadsheet/worksheet.ts
Comment thread packages/sheet/src/spreadsheet/worksheet.ts
Comment thread packages/sheet/src/spreadsheet/worksheet.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)

368-379: ⚠️ Potential issue

One remaining event listener leak risk during drag operations.

The mousemove and mouseup listeners are still added directly to the document without using your centralized registry system. If cleanup() is called during a drag operation, these listeners won't be removed.

-    document.addEventListener('mousemove', onMove);
-    document.addEventListener('mouseup', onUp);
+    this.addEventListener(document, 'mousemove', onMove);
+    this.addEventListener(document, 'mouseup', onUp);

This was pointed out in a previous review but wasn't fully addressed in this file.

🧹 Nitpick comments (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)

15-33: Consider moving theme definitions to a separate file.

The theme objects are well-structured, but as the application grows, moving these to a dedicated themes file would improve modularity and make it easier to extend with additional themes.

Consider creating a themes.ts file that exports these theme objects and related types/utilities for better organization.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 30f21d2 and 7d3a1a0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • package.json (1 hunks)
  • packages/backend/src/auth/github.strategy.ts (1 hunks)
  • packages/frontend/package.json (1 hunks)
  • packages/frontend/src/app/Layout.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-detail.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-list.tsx (1 hunks)
  • packages/frontend/src/components/nav-user.tsx (1 hunks)
  • packages/frontend/src/components/ui/toggle.tsx (1 hunks)
  • packages/sheet/package.json (1 hunks)
  • packages/sheet/src/index.ts (1 hunks)
  • packages/sheet/src/spreadsheet/spreadsheet.ts (2 hunks)
  • packages/sheet/src/spreadsheet/worksheet.ts (12 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/sheet/src/index.ts
  • packages/frontend/src/components/ui/toggle.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/backend/src/auth/github.strategy.ts
  • packages/frontend/src/components/nav-user.tsx
  • packages/frontend/src/app/Layout.tsx
  • packages/frontend/src/app/documents/document-list.tsx
  • packages/sheet/src/spreadsheet/spreadsheet.ts
  • packages/frontend/package.json
  • packages/frontend/src/app/documents/document-detail.tsx
  • package.json
  • packages/sheet/package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)
packages/sheet/src/spreadsheet/spreadsheet.ts (1)
  • Theme (7-7)
🔇 Additional comments (9)
packages/sheet/src/spreadsheet/worksheet.ts (9)

7-7: Great implementation of theming support.

The addition of theme support with proper typing and constructor parameter is well-implemented. This aligns with the PR's broader goal of enhancing the structure of the codebase.

Also applies to: 77-77, 107-109


15-33: Good implementation of theme objects.

The separation into LightTheme and DarkTheme objects is clean and maintainable. Each theme consistently provides all necessary color values required by the worksheet.


91-95: Well-designed event listener tracking.

This listener tracking array is a clean solution for managing event listeners, making cleanup more reliable and preventing memory leaks.


97-106: Fixed event handler binding issue.

You've properly addressed the previous review comments by binding all event handlers once in the constructor and storing them as class properties, ensuring the same references are used for both adding and removing listeners.

Also applies to: 190-199


208-213: Comprehensive cleanup implementation.

The cleanup method properly removes all event listeners and clears the container, effectively preventing memory leaks when the component unmounts.


214-229: Well-implemented event listener management system.

This centralized approach to tracking and removing event listeners is excellent and ensures no listeners are left behind when the component is destroyed.


282-298: Correctly using the listener tracking system.

You're now consistently using the addEventListener method to register all event listeners, which ensures they can be properly cleaned up later.


526-539: Excellent implementation of system theme detection.

Your implementation of the getThemeColor method properly handles the 'system' theme by checking the user's OS preferences via media query. This addresses the previous review comment perfectly.


858-872: Consistent application of theme colors.

You've systematically updated all color references to use the getThemeColor method, ensuring consistent theming throughout the component's rendering.

Also applies to: 889-895, 907-915

@hackerwins
hackerwins force-pushed the backend branch 4 times, most recently from a01840e to 36fb4de Compare April 19, 2025 10:56
@hackerwins
hackerwins force-pushed the backend branch 2 times, most recently from 8b3a5a1 to e4202cc Compare April 19, 2025 16:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/sheet/src/spreadsheet/worksheet.ts (2)

307-379: ⚠️ Potential issue

Potential event listener leak during drag operations.

When handling mouse down events, you're attaching document-level event listeners for 'mousemove' and 'mouseup' directly rather than through your central registry.

If cleanup() is called while a drag operation is in progress (e.g., during component unmount), these listeners won't be removed because they're not tracked in your listener registry.

-      document.addEventListener('mousemove', onMove);
-      document.addEventListener('mouseup', onUp);
+      this.addEventListener(document, 'mousemove', onMove);
+      this.addEventListener(document, 'mouseup', onUp);

You can then remove the explicit removeEventListener calls in onUp, or keep them as an extra safety measure.


526-532: ⚠️ Potential issue

The getThemeColor method doesn't handle the 'system' theme.

The union type Theme = 'light' | 'dark' | 'system' (defined in the spreadsheet file) implies three distinct modes, but 'system' is not properly handled in this method.

This issue was previously flagged in a review comment but hasn't been addressed. Consider implementing OS preference detection when 'system' is specified:

  public getThemeColor(key: keyof typeof LightTheme): string {
    if (this.theme === 'light') {
      return LightTheme[key];
    }

+   if (this.theme === 'system') {
+     const prefersDark = window.matchMedia?.('(prefers-color-scheme: dark)').matches;
+     return (prefersDark ? DarkTheme : LightTheme)[key];
+   }

    return DarkTheme[key];
  }
🧹 Nitpick comments (1)
packages/sheet/src/formula/formula.ts (1)

74-97: Enhanced token coverage with string gap filling.

The addition of STRING tokens to fill gaps between recognized tokens ensures complete coverage of the formula string, which is crucial for accurate syntax highlighting in the UI.

However, the text extraction logic could benefit from a clarifying comment:

        text: formula.slice(currToken.stop + 2, token.start + 1),
+        // +2 accounts for the '=' prefix and 0-based indexing

Similarly for line 95:

        text: formula.slice(currToken.stop + 2),
+        // +2 accounts for the '=' prefix and 0-based indexing
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 378ae9a and 8b3a5a1.

⛔ Files ignored due to path filters (1)
  • packages/frontend/public/icon.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • packages/backend/src/documents/document.service.ts (1 hunks)
  • packages/frontend/index.html (1 hunks)
  • packages/frontend/src/app/documents/document-detail.tsx (1 hunks)
  • packages/frontend/src/app/login/page.tsx (1 hunks)
  • packages/frontend/src/components/app-sidebar.tsx (1 hunks)
  • packages/frontend/src/components/nav-user.tsx (1 hunks)
  • packages/frontend/src/components/theme-provider.tsx (1 hunks)
  • packages/sheet/src/formula/formula.ts (1 hunks)
  • packages/sheet/src/spreadsheet/spreadsheet.ts (2 hunks)
  • packages/sheet/src/spreadsheet/worksheet.ts (14 hunks)
  • packages/sheet/src/store/memory/cache.ts (0 hunks)
  • packages/sheet/test/formula/formula.test.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/sheet/src/store/memory/cache.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/frontend/src/app/login/page.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/frontend/index.html
  • packages/frontend/src/components/nav-user.tsx
  • packages/backend/src/documents/document.service.ts
  • packages/frontend/src/app/documents/document-detail.tsx
  • packages/frontend/src/components/theme-provider.tsx
  • packages/frontend/src/components/app-sidebar.tsx
  • packages/sheet/src/spreadsheet/spreadsheet.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/sheet/src/formula/formula.ts (2)
packages/sheet/antlr/FormulaLexer.ts (1)
  • FormulaLexer (16-212)
packages/sheet/antlr/FormulaParser.ts (1)
  • formula (123-166)
packages/sheet/test/formula/formula.test.ts (1)
packages/sheet/src/formula/formula.ts (1)
  • extractTokens (53-100)
🔇 Additional comments (11)
packages/sheet/test/formula/formula.test.ts (2)

2-6: Good addition of imports for extensive token testing.

The new import for extractTokens aligns well with the existing pattern of testing formula functions comprehensively. This ensures that all formula-related functionality is properly tested.


67-107: Comprehensive test coverage for token extraction.

The test cases for extractTokens cover a wide range of formula types including arithmetic operations, function calls, cell references, boolean values, and partial formula inputs. These tests ensure that each token is correctly identified with the appropriate type, position, and text content.

packages/sheet/src/formula/formula.ts (2)

62-64: Good optimization by filtering EOF tokens early.

Early filtering of EOF tokens simplifies the downstream processing of tokens and makes the code more efficient.


67-67: Robust token type handling with fallback.

Using the vocabulary to get the symbolic name with a fallback to 'STRING' for unrecognized token types is a good defensive programming practice that ensures all tokens have a valid type.

packages/sheet/src/spreadsheet/worksheet.ts (7)

2-2: Updated import for enhanced formula token extraction.

Adding the extractTokens import supports the improved token handling for formula syntax highlighting throughout the worksheet.


22-44: Well-structured theme objects with consistent color mapping.

The theme objects are well-organized with clear semantic naming for UI elements. The token coloring is properly included in the theme, allowing for consistent syntax highlighting across themes.


91-106: Robust event listener management system.

The centralized event listener registry is an excellent practice that enables proper cleanup and prevents memory leaks. This approach is much more maintainable than scattered event attachment and removal.


190-200: Properly bound event handlers prevent context issues.

Pre-binding event handlers in the constructor ensures that this references remain correct within handler methods, avoiding common issues with handler context.


208-212: Clean and thorough cleanup mechanism.

The cleanup method properly removes all event listeners and clears the container, which is essential for preventing memory leaks when the component is unmounted.


214-229: Well-designed event listener management methods.

These helper methods properly register and clean up event listeners, making the code more maintainable and less prone to leaks.


920-931: Simpler token processing for syntax highlighting.

The token handling for syntax highlighting is now more straightforward, directly leveraging the enhanced extractTokens function to obtain accurate token information. The code properly applies theme-based colors to the tokens, creating a consistent visual experience.

@hackerwins hackerwins changed the title Add pnpm configuration to manage packages Add auth, document management, and spreadsheet UI with monorepo setup Apr 19, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🧹 Nitpick comments (3)
.github/workflows/publish-ghpage.yml (3)

1-1: Workflow name consistency
The workflow is now named "GitHub Page Publish". Consider aligning this with other workflows or naming conventions (e.g., "Publish GitHub Pages") for consistency across the repo.


14-15: Upgrade checkout action
Switching to actions/checkout@v4 is a good update. Optionally, you could add fetch-depth: 0 to ensure the full Git history is available (useful for some deployment actions).


29-30: Install and build commands
You may want to enforce lockfile consistency during CI by using pnpm install --frozen-lockfile. Example:

- pnpm i
+ pnpm install --frozen-lockfile

This prevents unintended updates to pnpm-lock.yaml.

🛑 Comments failed to post (1)
.github/workflows/publish-ghpage.yml (1)

36-37: ⚠️ Potential issue

Invalid publish directory path
publish_dir is set to frontend/dist, but the monorepo layout uses packages/frontend/dist. The current path will fail to locate the build output.

Please apply:

- publish_dir: frontend/dist
+ publish_dir: packages/frontend/dist
📝 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.

          publish_dir: packages/frontend/dist
          enable_jekyll: false

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/frontend/package.json (1)

7-12: Add a type-check script
Since this is a TypeScript project, consider adding a "type-check": "tsc --noEmit" script to catch type errors in CI or pre-commit hooks.

 "scripts": {
     "dev": "vite",
     "build": "vite build",
     "lint": "eslint .",
+    "type-check": "tsc --noEmit",
     "preview": "vite preview"
 },
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2a2f363 and b081c40.

📒 Files selected for processing (10)
  • .github/workflows/docker-publish.yml (1 hunks)
  • .github/workflows/publish-ghpage.yml (1 hunks)
  • Dockerfile (1 hunks)
  • package.json (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/frontend/.env (1 hunks)
  • packages/frontend/.env.production (1 hunks)
  • packages/frontend/package.json (1 hunks)
  • packages/frontend/src/App.tsx (1 hunks)
  • packages/sheet/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/frontend/.env.production
  • packages/frontend/.env
  • Dockerfile
  • .github/workflows/docker-publish.yml
  • packages/backend/package.json
  • .github/workflows/publish-ghpage.yml
  • packages/frontend/src/App.tsx
  • packages/sheet/package.json
🔇 Additional comments (3)
packages/frontend/package.json (3)

1-6: Validate package metadata
Top-level fields (name, private, version, type, license) are correctly configured for a private monorepo package.


13-52: Dependencies look solid
The declared runtime dependencies (@dnd-kit, @radix-ui, React 19, Tailwind, etc.) align with the project's UI and state-management needs. The workspace:* reference for @wafflebase/sheet is correct.


53-62: DevDependencies are appropriate
ESLint, TypeScript types, Vite plugin, and related tooling are properly declared for development tasks.

Comment on lines +63 to +64
"typescript": "~5.8.3",
"typescript-eslint": "^8.24.1",

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

Incorrect ESLint TypeScript package
The "typescript-eslint" entry is not a valid package. Replace it with the official parser and plugin to enable proper TypeScript linting:

- "typescript-eslint": "^8.24.1",
+ "@typescript-eslint/parser": "^8.24.1",
+ "@typescript-eslint/eslint-plugin": "^8.24.1",
📝 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
"typescript": "~5.8.3",
"typescript-eslint": "^8.24.1",
"typescript": "~5.8.3",
- "typescript-eslint": "^8.24.1",
+ "@typescript-eslint/parser": "^8.24.1",
+ "@typescript-eslint/eslint-plugin": "^8.24.1",

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
packages/frontend/src/app/documents/page.tsx (1)

33-37: Consider adding an empty state handler

While the component renders the DocumentList correctly, it might be worth adding specific handling for when documents array is empty (beyond the default empty array).

  return (
    <div className="p-4">
+     {documents.length === 0 ? (
+       <div className="flex flex-col items-center justify-center h-64">
+         <p className="text-gray-500 text-lg">No documents found.</p>
+         <p className="text-gray-400">Create a new document to get started.</p>
+       </div>
+     ) : (
      <DocumentList data={documents} />
+     )}
    </div>
  );
packages/frontend/src/app/documents/document-list.tsx (3)

167-169: Enhance document creation with title input

Currently, new documents are created with a hardcoded title "New Document". Consider providing a way for users to specify a title during creation.

You could either:

  1. Use a modal/dialog to prompt for the title before creation
  2. Create with default title but immediately put the user in "edit mode"
  3. Implement inline creation in the table itself

For example, a simple prompt approach:

onClick={() => {
-  createDocumentMutation.mutate({ title: "New Document" });
+  const title = prompt("Enter document title:", "New Document");
+  if (title) {
+    createDocumentMutation.mutate({ title });
+  }
}}

203-208: Improve click handler robustness

The current approach to prevent navigation when clicking inputs or buttons uses a DOM traversal method that might be fragile if the component structure changes.

Consider a more robust approach using event targets and roles:

onClick={(e: MouseEvent<HTMLElement>) => {
-  if ((e.target as HTMLElement).closest("input, button")) {
+  const target = e.target as HTMLElement;
+  // Check for common interactive elements or their parents
+  if (
+    target.tagName === "INPUT" || 
+    target.tagName === "BUTTON" ||
+    target.getAttribute("role") === "button" ||
+    target.getAttribute("aria-role") === "button" ||
+    target.closest("[role='button'], [aria-role='button']")
+  ) {
    return;
  }
  navigate(`/${row.getValue("id")}`);
}}

74-76: Consider proper title case formatting

The capitalize class only capitalizes the first letter of the entire string. For proper title case with multiple words, consider a JavaScript function.

cell: ({ row }) => (
-  <div className="capitalize">{row.getValue("title")}</div>
+  <div>
+    {String(row.getValue("title"))
+      .split(' ')
+      .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
+      .join(' ')}
+  </div>
)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b081c40 and 142ee28.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • package.json (1 hunks)
  • packages/frontend/package.json (1 hunks)
  • packages/frontend/src/App.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-detail.tsx (1 hunks)
  • packages/frontend/src/app/documents/document-list.tsx (1 hunks)
  • packages/frontend/src/app/documents/page.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/frontend/src/app/documents/document-detail.tsx
  • packages/frontend/src/App.tsx
  • package.json
  • packages/frontend/package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/frontend/src/app/documents/document-list.tsx (7)
packages/frontend/src/types/documents.ts (1)
  • Document (1-7)
packages/frontend/src/components/ui/checkbox.tsx (1)
  • Checkbox (30-30)
packages/frontend/src/components/ui/dropdown-menu.tsx (4)
  • DropdownMenu (242-242)
  • DropdownMenuTrigger (244-244)
  • DropdownMenuContent (245-245)
  • DropdownMenuLabel (247-247)
packages/frontend/src/components/ui/button.tsx (1)
  • Button (62-62)
packages/frontend/src/api/documents.ts (2)
  • createDocument (5-22)
  • deleteDocument (48-62)
packages/frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
packages/frontend/src/components/ui/table.tsx (6)
  • Table (108-108)
  • TableHeader (109-109)
  • TableRow (113-113)
  • TableHead (112-112)
  • TableBody (110-110)
  • TableCell (114-114)
🔇 Additional comments (5)
packages/frontend/src/app/documents/page.tsx (2)

1-14: Data fetching implementation looks good

The React Query setup for fetching documents is well implemented with appropriate query key and function. The component properly handles the query state with type safety.


16-31: Loading and error states are well handled

Good user experience with clear loading and error states. The Tailwind classes create a well-centered and visually appropriate UI for these states.

packages/frontend/src/app/documents/document-list.tsx (3)

43-117: Well-structured table columns with appropriate formatting

The column definitions are well organized with appropriate accessors, headers, and cell renderers. The date formatting using formatDistanceToNow provides a good user experience with relative timestamps.


136-153: Excellent table configuration with complete state management

The table setup with sorting, filtering, pagination, and row selection is well implemented. All necessary models and state bindings are properly configured.


155-256: Comprehensive UI with good user experience features

The UI implementation includes a search filter, action buttons, clear table structure, and pagination controls with row selection status. These elements combine to create an excellent user experience.

Comment on lines +119 to +127
const createDocumentMutation = useMutation({
mutationFn: async (data: { title: string }) => await createDocument(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
});

const deleteDocumentMutation = useMutation({
mutationFn: async (id: string) => await deleteDocument(id),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
});

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 error handling to mutations

Both create and delete mutations lack explicit error handling, which could lead to silent failures from the user's perspective.

Add error callbacks to handle failures gracefully:

const createDocumentMutation = useMutation({
  mutationFn: async (data: { title: string }) => await createDocument(data),
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
+ onError: (error) => {
+   console.error("Failed to create document:", error);
+   // Consider adding a toast notification here
+ },
});

const deleteDocumentMutation = useMutation({
  mutationFn: async (id: string) => await deleteDocument(id),
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
+ onError: (error) => {
+   console.error("Failed to delete document:", error);
+   // Consider adding a toast notification here
+ },
});
📝 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 createDocumentMutation = useMutation({
mutationFn: async (data: { title: string }) => await createDocument(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
});
const deleteDocumentMutation = useMutation({
mutationFn: async (id: string) => await deleteDocument(id),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
});
const createDocumentMutation = useMutation({
mutationFn: async (data: { title: string }) => await createDocument(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
onError: (error) => {
console.error("Failed to create document:", error);
// Consider adding a toast notification here
},
});
const deleteDocumentMutation = useMutation({
mutationFn: async (id: string) => await deleteDocument(id),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
onError: (error) => {
console.error("Failed to delete document:", error);
// Consider adding a toast notification here
},
});

Comment on lines +104 to +108
className="cursor-pointer text-red-500"
onClick={(e: MouseEvent<HTMLElement>) => {
e.stopPropagation();
deleteDocumentMutation.mutate(String(row.getValue("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.

🛠️ Refactor suggestion

Add confirmation before deleting documents

Currently, documents are deleted immediately upon clicking the "Delete" option without any confirmation. This could lead to accidental data loss.

Consider adding a confirmation dialog before proceeding with deletion:

<DropdownMenuLabel
  className="cursor-pointer text-red-500"
  onClick={(e: MouseEvent<HTMLElement>) => {
    e.stopPropagation();
-   deleteDocumentMutation.mutate(String(row.getValue("id")));
+   if (window.confirm("Are you sure you want to delete this document?")) {
+     deleteDocumentMutation.mutate(String(row.getValue("id")));
+   }
  }}
>
📝 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
className="cursor-pointer text-red-500"
onClick={(e: MouseEvent<HTMLElement>) => {
e.stopPropagation();
deleteDocumentMutation.mutate(String(row.getValue("id")));
}}
<DropdownMenuLabel
className="cursor-pointer text-red-500"
onClick={(e: MouseEvent<HTMLElement>) => {
e.stopPropagation();
if (window.confirm("Are you sure you want to delete this document?")) {
deleteDocumentMutation.mutate(String(row.getValue("id")));
}
}}
>
Delete
</DropdownMenuLabel>

@hackerwins
hackerwins merged commit b54a7ca into main May 3, 2025
@hackerwins
hackerwins deleted the backend branch May 3, 2025 02:30
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

Refined formula parsing logic.
hackerwins added a commit that referenced this pull request May 3, 2025
Established monorepo with pnpm workspace, configured
NestJS for backend, and ShadCN/React for frontend.

Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.

Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.

Replaced DuckDB with Yorkie storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant