Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: db changed #323

Merged
merged 4 commits into from
Feb 28, 2025
Merged

feat!: db changed #323

merged 4 commits into from
Feb 28, 2025

Conversation

hmbanan666
Copy link
Contributor

@hmbanan666 hmbanan666 commented Feb 27, 2025

Summary by CodeRabbit

  • New Features

    • Enabled Redis support via updated environment settings.
    • Improved dynamic product categorization for enhanced navigation.
  • Improvements

    • Refined checkout, search, and payment interactions for smoother user experience.
    • Enhanced form controls and button actions for more responsive submissions.
  • Refactor

    • Streamlined data handling and error management for increased reliability and performance.
    • Updated dependency configurations and runtime settings across the system.
    • Introduced new service functions for managing checkout, product, and menu operations, enhancing modularity.

Copy link

coderabbitai bot commented Feb 27, 2025

Walkthrough

This pull request makes extensive configuration and code changes across both the frontend and backend. On the frontend side, new SonarLint settings and environment variable updates were applied along with modifications to event handling, URL construction, and data flow in several Vue components and pages. On the backend, repository calls have been replaced with service functions across multiple API endpoints and stores, and new service modules and a Redis-based plugin have been added. Type definitions and workspace dependencies were also updated accordingly.

Changes

File(s) Change Summary
.vscode/settings.json Added new SonarLint configuration "sonarlint.connectedMode.project" with connectionId and projectKey.
apps/web-app/.env.example Removed NUXT_PUBLIC_LOCALE; added NUXT_REDIS_URL with value redis://localhost:6379.
apps/web-app/app/components/Cart/Line.vue
apps/web-app/app/components/Checkout/Line.vue
apps/web-app/app/pages/catalog/[categorySlug]/[productSlug]/index.vue
apps/web-app/app/components/CommandCenter/ProductCard.vue
Updated product URL construction to use a computed category from a service lookup instead of direct product properties; adjusted product variant retrieval methods.
apps/web-app/app/components/CategoryBlock.vue
apps/web-app/app/components/Form/UpdateWorkingDays.vue
apps/web-app/app/pages/catalog/[categorySlug]/index.vue
apps/web-app/app/pages/checkout/index.vue
apps/web-app/app/components/SearchBlock.vue
Refactored data extraction and iteration logic; moved filtering logic into script variables; changed DOM elements from <div> to <template> for conditional rendering; improved safe property access using optional chaining.
apps/web-app/app/components/Form/CreateChannelPaymentMethod.vue
apps/web-app/app/components/Form/DeleteChannelPaymentMethod.vue
apps/web-app/app/components/Form/DeleteProduct.vue
apps/web-app/app/components/Form/DeleteProductVariant.vue
apps/web-app/app/components/Modal/CreateChannelPaymentMethod.vue
Modified event handlers and added a new 'submitted' event emission to improve interactivity and update modal behavior.
apps/web-app/nuxt.config.ts
apps/web-app/package.json
Updated configuration (channelId changed from 'burger' to 'web-app' and locale removed) and added the "ioredis" dependency.
apps/web-app/stores/channel.ts
apps/web-app/stores/checkout.ts
apps/web-app/middleware/02.staff.ts
Replaced repository calls with service functions, added new product query methods, and enhanced error handling with simplified conditional checks.
packages/core/... (multiple API endpoints, plugins, and services files) Refactored backend logic by replacing repository access with dedicated service functions for channels, payment methods, products, users, warehouses, and working days; added new service modules and a Redis plugin; removed deprecated API endpoints; updated service functions to update channel status via setChannelAsUpdated.
packages/core/shared/services/workingDay.ts
packages/core/types/index.d.ts
pnpm-workspace.yaml
packages/core/package.json
Updated type definitions (including timestamp types and working day schema changes) and added new dependencies (e.g., @paralleldrive/cuid2 and ioredis) to the workspace.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant C as Cart Component
    participant Channel as Channel Store
    U->>C: Select product variant
    C->>Channel: getProductByProductVariant(variantId)
    Channel-->>C: Return product data
    C->>Channel: getMenuCategoryByProduct(productId)
    Channel-->>C: Return category data
    C->>U: Render productUrl as /catalog/{category.slug}/{product.slug}
Loading
sequenceDiagram
    participant Client as Client
    participant API as API Endpoint
    participant PMService as Payment Method Service
    participant ChannelService as Channel Service
    Client->>API: Request deletion of payment method (id)
    API->>PMService: deletePaymentMethod(id)
    PMService-->>API: Acknowledgement
    API->>ChannelService: setChannelAsUpdated(channelId)
    ChannelService-->>API: Channel updated
    API->>Client: Send success response
Loading

Poem

I'm a bunny with paws so light,
Hopping through code from day to night.
New configs and services, structured so neat,
With endpoints and plugins that simply can't be beat.
I nibble on changes, carrot code in bloom,
Celebrating each update that makes our system zoom!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.

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 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🔭 Outside diff range comments (1)
apps/web-app/app/components/Form/CreateChannelPaymentMethod.vue (1)

72-94: 💡 Verification agent

🧩 Analysis chain

Consider handling disconnection between modal and error states.

Since the modal will now close immediately upon submission (based on the AI summary), users might miss error notifications if the API call fails. Consider adding a mechanism to handle errors more visibly after the modal closes.


🏁 Script executed:

#!/bin/bash
# Check how errors are handled in the modal component
fd "CreateChannelPaymentMethod.vue" apps/web-app/app/components/Modal --type f | xargs cat

Length of output: 433


Revisit Modal Closing Behavior on Submission

The current flow immediately closes the modal on the submitted event—even before the API call completes. Our verification confirms that the modal component in apps/web-app/app/components/Modal/CreateChannelPaymentMethod.vue closes the modal on both @submitted and @success events. This means that if the API call fails (as handled in the form’s onSubmit function in apps/web-app/app/components/Form/CreateChannelPaymentMethod.vue), the error toast is shown only after the modal has already closed, which may cause users to miss the error notification.

Recommendations:

  • Delay Modal Closure: Remove or adjust the immediate modal.close() call from the @submitted event. Consider closing the modal only after a successful API call so that error notifications remain visible.
  • Error State Handling: Alternatively, if keeping the modal open on error isn’t feasible, introduce a mechanism (such as re-opening the modal or displaying persistent error messages) to ensure users acknowledge API call failures.
🧹 Nitpick comments (43)
apps/web-app/app/components/Form/DeleteProductVariant.vue (1)

8-8: Correct event binding for button element

The change from @submit to @click is appropriate since submit events are typically handled on form elements, while buttons should use click events. This change aligns with proper Vue event handling practices.

However, consider reviewing if type="submit" is still needed on line 3, as this attribute is meant for buttons within forms that should trigger form submission.

apps/web-app/app/components/Form/DeleteChannelPaymentMethod.vue (1)

8-8: Correct event binding for button element

The change from @submit to @click is appropriate since submit events are typically handled on form elements, while buttons should use click events. This change aligns with proper Vue event handling practices.

However, consider reviewing if type="submit" is still needed on line 3, as this attribute is meant for buttons within forms that should trigger form submission.

apps/web-app/app/components/Form/DeleteProduct.vue (1)

8-8: Correct event binding for button element

The change from @submit to @click is appropriate since submit events are typically handled on form elements, while buttons should use click events. This change aligns with proper Vue event handling practices.

However, consider reviewing if type="submit" is still needed on line 3, as this attribute is meant for buttons within forms that should trigger form submission.

apps/web-app/app/components/Form/CreateChannelPaymentMethod.vue (1)

73-74: Good implementation of the submitted event.

Emitting the 'submitted' event at the beginning of the submission process ensures that parent components can react immediately, before waiting for the async operations to complete.

However, consider whether users might benefit from a loading state during the API call to provide visual feedback that something is happening after the modal closes.

async function onSubmit(event: FormSubmitEvent<ChannelPaymentMethodCreateSchema>) {
  emit('submitted')
+  const isLoading = ref(true)
  
  const { data, error } = await useAsyncData(
    'create-payment-method',
    () => $fetch('/api/channel/payment-method', {
      method: 'POST',
      body: event.data,
    }),
  )
+  isLoading.value = false
packages/core/server/plugins/01.db.ts (1)

1-9: Redis storage driver integration looks good, but consider adding error handling

The plugin effectively integrates Redis as a storage driver with Nitro, making it available under the key 'db'. This aligns well with the new environment variable in .env.example.

Consider enhancing the plugin with error handling and logging:

import redisDriver from 'unstorage/drivers/redis'

export default defineNitroPlugin(() => {
  const { redisUrl: url } = useRuntimeConfig()

+  if (!url) {
+    console.warn('Redis URL not provided, db storage might not function correctly')
+  }
+
  const driver = redisDriver({ url })
+
+  // Optional: Add event listeners for connection status
+  driver.on?.('error', (err) => {
+    console.error('Redis connection error:', err)
+  })

  useStorage().mount('db', driver)
})
packages/core/server/services/db/index.ts (1)

10-26: Consider optimizing key filtering for large datasets

The implementation is clean and straightforward, but performs multiple iterations over the allKeys array (once for each filter). While likely not an issue for most cases, this could be optimized to a single-pass approach if dealing with a large number of keys.

export async function getKeys(): Promise<Keys> {
  const allKeys = await useStorage('db').getKeys()
-  const menuKeys = allKeys.filter((key) => key.startsWith('menu:'))
-  const productKeys = allKeys.filter((key) => key.startsWith('product:'))
-  const warehouseKeys = allKeys.filter((key) => key.startsWith('warehouse:'))
-  const paymentMethodKeys = allKeys.filter((key) => key.startsWith('payment:method:'))
-  const userKeys = allKeys.filter((key) => key.startsWith('user:'))
+  const menuKeys: string[] = []
+  const productKeys: string[] = []
+  const warehouseKeys: string[] = []
+  const paymentMethodKeys: string[] = []
+  const userKeys: string[] = []
+  
+  for (const key of allKeys) {
+    if (key.startsWith('menu:')) menuKeys.push(key)
+    else if (key.startsWith('product:')) productKeys.push(key)
+    else if (key.startsWith('warehouse:')) warehouseKeys.push(key)
+    else if (key.startsWith('payment:method:')) paymentMethodKeys.push(key)
+    else if (key.startsWith('user:')) userKeys.push(key)
+  }

  return {
    allKeys,
    menuKeys,
    productKeys,
    warehouseKeys,
    paymentMethodKeys,
    userKeys,
  }
}
apps/web-app/app/components/Cart/Line.vue (1)

39-40: Improved category lookup method for product URLs.

The change to use getMenuCategoryByProduct instead of directly accessing product category data is a good improvement. It centralizes category retrieval logic in the channel store and allows for more flexibility in how categories are determined.

However, you should handle the potential undefined value from category?.slug more robustly.

-const category = channel.getMenuCategoryByProduct(product.value?.id ?? '')
-const productUrl = computed(() => `/catalog/${category?.slug}/${product.value?.slug}`)
+const category = computed(() => channel.getMenuCategoryByProduct(product.value?.id ?? ''))
+const productUrl = computed(() => {
+  const categorySlug = category.value?.slug || 'uncategorized'
+  const productSlug = product.value?.slug || ''
+  return `/catalog/${categorySlug}/${productSlug}`
+})
apps/web-app/app/pages/command-center/system/index.vue (1)

94-94: Improve time display for clarity or localization.
Rendering {{ workingDay.open }} - {{ workingDay.close }} is a good start, but consider using date/time formatting utilities to handle locales, AM/PM, or 24-hour format.

apps/web-app/stores/checkout.ts (1)

14-38: Streamlined fetch approach with improved error handling.
Switching from useFetch to $fetch is straightforward and the try/catch block is an improvement. However, ensure that ignoring 'NotFound' errors is truly intentional—consider logging them or throwing a custom error to avoid hiding unexpected mistakes.

packages/core/server/services/db/media.ts (1)

5-12: Return the newly created object directly to avoid an additional read.
Currently, you write to storage and then perform a separate call to getMedia() to retrieve the just-created object. If you wish to optimize, you can return the object directly as populated in-memory.

 export async function createMedia(data: Omit<Media, 'createdAt' | 'updatedAt'>): Promise<Media | null> {
   const now = new Date().toISOString()
   const newMedia = {
     ...data,
-    createdAt: new Date().toISOString(),
-    updatedAt: new Date().toISOString(),
+    createdAt: now,
+    updatedAt: now,
   }
   await useStorage('db').setItem(`media:${data.id}`, newMedia)
-  return getMedia(data.id)
+  return newMedia
 }
packages/core/server/services/db/menu.ts (1)

1-43: LGTM: Well-structured menu service implementation.

The new getMenus service function is clearly written with good error handling and appropriate use of async/await patterns. The comments explaining the key formats are helpful for readability.

For a minor performance optimization, consider batching the awaits for storage operations. Currently, the Map stores promises which are then awaited individually, but you could initialize the Map and then await all promises at once to potentially improve performance.

- const menuStorage = new Map<string, unknown>(keys.map((key) => [key, useStorage('db').getItem(key)]))
+ const storagePromises = keys.map(key => [key, useStorage('db').getItem(key)])
+ const resolvedPromises = await Promise.all(storagePromises.map(([_, promise]) => promise))
+ const menuStorage = new Map<string, unknown>(
+   storagePromises.map(([key], index) => [key, resolvedPromises[index]])
+ )
apps/web-app/app/pages/command-center/product/[id]/index.vue (1)

10-10: Need to handle potential undefined values.

The current display format could show "//" if both category and product slugs are undefined. Consider adding a conditional check to avoid displaying empty slashes.

-        /{{ category?.slug }}/{{ product?.slug }}
+        {{ category?.slug ? `/${category.slug}` : '' }}{{ product?.slug ? `/${product?.slug}` : '' }}
apps/web-app/app/components/CategoryBlock.vue (1)

39-39: Consider performance optimization for product filtering.

The current implementation fetches all products and filters them in memory. For large product catalogs, this could impact performance.

Consider implementing server-side filtering or pagination if the product catalog grows significantly:

-const products = channel.getProductsInCategory(categoryId).value.filter((p) => p.isAvailableForPurchase && p.variants.length).slice(0, 8)
+const products = computed(() => {
+  const allProducts = channel.getProductsInCategory(categoryId).value
+  return allProducts.filter((p) => p.isAvailableForPurchase && p.variants.length).slice(0, 8)
+})

This change makes products reactive and will recalculate if the underlying data changes.

packages/core/server/api/channel/working-day/index.patch.ts (1)

18-20: Simplified loop with better error handling needed.

The loop has been simplified by delegating logic to the service layer, but consider adding transaction handling for multiple updates.

Consider implementing transaction handling to ensure atomicity of updates:

+    // Consider implementing transaction handling here
+    let hasErrors = false;
+    const errors = [];

     for (const day of data) {
-      await patchWorkingDay(day.day, day)
+      try {
+        await patchWorkingDay(day.day, day)
+      } catch (error) {
+        hasErrors = true;
+        errors.push(`Failed to update ${day.day}: ${error.message}`);
+      }
     }

+    if (hasErrors) {
+      throw createError({
+        statusCode: 500,
+        statusMessage: `Failed to update some working days: ${errors.join(', ')}`,
+      });
+    }
packages/core/server/services/db/channel.ts (4)

1-3: Add input validation for channel ID.

Consider adding validation to check if the id parameter is valid before querying the storage. Also, ensure that useStorage and Channel type are properly imported (not visible in this snippet).

export async function getChannel(id: string): Promise<Channel | null> {
+  if (!id) {
+    return null
+  }
  return useStorage('db').getItem<Channel>(`channel:${id}`)
}

5-20: Implementation looks good, consider consistency in return pattern.

The function properly handles cases where the channel doesn't exist and correctly updates the timestamp. However, I noticed that unlike other DB methods in this codebase, this function returns the in-memory object rather than fetching it again from storage.

Consider adopting a consistent approach across all DB service methods - either return the in-memory object or fetch it again from storage.


22-29: Add existence check before creating a channel.

The function correctly sets timestamps, but it doesn't check if a channel with the same ID already exists, which could lead to unintentional overwrites.

export async function createChannel(data: Omit<Channel, 'createdAt' | 'updatedAt'>): Promise<Channel | null> {
+  const existingChannel = await getChannel(data.id)
+  if (existingChannel) {
+    return null // or throw an error
+  }
  await useStorage('db').setItem(`channel:${data.id}`, {
    ...data,
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
  })
  return getChannel(data.id)
}

31-33: Redundant function implementation.

The setChannelAsUpdated function is redundant since patchChannel already updates the updatedAt timestamp automatically. Consider refactoring for simplicity.

export async function setChannelAsUpdated(id: string): Promise<void> {
-  await patchChannel(id, { updatedAt: new Date().toISOString() })
+  await patchChannel(id, {}) // This will update the timestamp automatically
}
packages/core/server/services/db/warehouse.ts (4)

1-3: Add input validation for warehouse ID.

Consider adding validation to check if the id parameter is valid before querying the storage.

export async function getWarehouse(id: string): Promise<Warehouse | null> {
+  if (!id) {
+    return null
+  }
  return useStorage('db').getItem<Warehouse>(`warehouse:${id}`)
}

5-19: Clarify parameter naming and improve code formatting.

The parameter is named keys but it's not clear if these are full storage keys or just warehouse IDs. Also, there's a minor formatting issue with the closing parenthesis.

-export async function getWarehouses(keys: string[]): Promise<Warehouse[]> {
+export async function getWarehouses(warehouseIds: string[]): Promise<Warehouse[]> {
  const warehouses: Warehouse[] = []

  await Promise.all(
-    keys.map(async (key) => {
+    warehouseIds.map(async (id) => {
-      const warehouse = await useStorage('db').getItem<Warehouse>(key)
+      const warehouse = await useStorage('db').getItem<Warehouse>(`warehouse:${id}`)
      if (!warehouse) {
        return
      }

      warehouses.push(warehouse)
-    }))
+    })
+  )

  return warehouses
}

21-28: Add existence check before creating a warehouse.

Similar to the channel service, consider adding a check to prevent overwriting existing warehouses.

export async function createWarehouse(data: Omit<Warehouse, 'createdAt' | 'updatedAt'>): Promise<Warehouse | null> {
+  const existingWarehouse = await getWarehouse(data.id)
+  if (existingWarehouse) {
+    return null // or throw an error
+  }
  await useStorage('db').setItem(`warehouse:${data.id}`, {
    ...data,
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
  })
  return getWarehouse(data.id)
}

30-45: Consider consistency in return pattern across DB services.

Unlike the patchChannel function that returns the in-memory object, this function fetches the warehouse again from storage after updating it. Adopt a consistent approach across all DB service methods.

export async function patchWarehouse(id: string, data: Partial<Warehouse>): Promise<Warehouse | null> {
  const warehouse = await getWarehouse(id)
  if (!warehouse) {
    return null
  }

  const newWarehouse = {
    ...warehouse,
    ...data,
    updatedAt: new Date().toISOString(),
  }

  await useStorage('db').setItem(`warehouse:${id}`, newWarehouse)

-  return getWarehouse(id)
+  return newWarehouse
}
packages/core/server/api/channel/payment-method/index.post.ts (1)

19-26: Add error handling for service function calls.

The code correctly uses the new service functions, but it lacks specific error handling if either createPaymentMethod or setChannelAsUpdated fails.

-    await createPaymentMethod({
-      id: createId(),
-      name: data.name,
-      type: data.type,
-    })
-
-    await setChannelAsUpdated(channelId)
+    const paymentMethodId = createId()
+    const paymentMethod = await createPaymentMethod({
+      id: paymentMethodId,
+      name: data.name,
+      type: data.type,
+    })
+    
+    if (!paymentMethod) {
+      throw createError({
+        statusCode: 500,
+        statusMessage: 'Failed to create payment method',
+      })
+    }
+
+    try {
+      await setChannelAsUpdated(channelId)
+    } catch (error) {
+      console.error('Failed to update channel timestamp:', error)
+      // Continue execution as this is non-critical
+    }
packages/core/server/services/db/work.ts (2)

5-19: Consider returning a value for error cases.

The function silently returns undefined in error cases, which might make debugging harder. Consider returning a more explicit response.

export async function changeWorkingDayActivity(day: DayCode, isActive: boolean): Promise<void> {
  const workingDays = await getWorkingDays()
  if (!workingDays) {
-    return
+    return undefined
  }

  const workingDay = workingDays.find((workingDay) => workingDay.day === day)
  if (!workingDay) {
-    return
+    return undefined
  }

  workingDay.isActive = isActive

  await useStorage('db').setItem('working-time', workingDays)
+  return undefined
}

39-42: Add validation for WorkingWeek data.

Consider adding validation to ensure the provided WorkingWeek data has a valid structure before saving it to storage.

export async function createWorkingDays(data: WorkingWeek): Promise<WorkingWeek | null> {
+  if (!Array.isArray(data) || data.length === 0) {
+    return null
+  }
+
+  // Validate that each working day has required properties
+  for (const day of data) {
+    if (!day.day || typeof day.isActive !== 'boolean') {
+      return null
+    }
+  }
  await useStorage('db').setItem('working-time', data)
  return getWorkingDays()
}
apps/web-app/app/pages/checkout/index.vue (2)

222-236: Consider distinct handling for empty cart vs maintenance mode.

Using a single <template v-else> covers both an empty cart and maintenance mode. If your intent is to differentiate these states, you may want to show a maintenance message separately rather than reusing the “empty cart” label.


276-276: Review maximum phone length limit.

Using 17 as a hard-coded limit might not account for varying country formats or future expansions. Consider referencing a config-based constant or a library for robust phone validation.

packages/core/server/api/channel/master.put.ts (1)

48-49: Consider credential collision checks.

Creating user credentials with a fresh ID is good practice. Ensure that if two masters are created concurrently (though unlikely), or a login collision occurs, the system fails gracefully and informs the caller.

packages/core/server/services/db/payment.ts (2)

5-19: Parallel retrieval of multiple payment methods is fine; watch for concurrency.

Pushing into paymentMethods inside map(async...) is acceptable in single-threaded environments, but in highly concurrent situations, external concurrency or merges might need more robust handling to avoid race conditions.


21-29: createPaymentMethod sets timestamps automatically, but confirm uniqueness.

Automatically populating createdAt and updatedAt is convenient, though consider verifying that payment:method:${data.id} does not already exist. Failing gracefully if an ID collision occurs might improve reliability.

apps/web-app/app/components/Checkout/Line.vue (1)

46-48: Consider null or undefined handling for product and category.

If productVariant.value?.id is empty or invalid, this could lead to channel.getProductByProductVariant returning null, and similarly getMenuCategoryByProduct might also return null. In these scenarios, building productUrl could result in broken or empty URLs such as /catalog/undefined/undefined. You may want to conditionally compute or provide a fallback route if the product or category is not found.

apps/web-app/app/components/Form/UpdateWorkingDays.vue (1)

48-48: Check reactivity approach for workingDays.

Setting workingDays = ref(channel.workingDays ?? []) might not capture future reactive changes if channel.workingDays updates. If you intend for the local array to track changes from channel.workingDays, consider either watching channel.workingDays or migrating to a fully reactive approach (e.g., using computed properties or watchers).

packages/core/server/services/db/user.ts (2)

3-5: Consider adding error handling or logs for getUser.

The function returns null if a user is not found, which is fine. However, you might want to log attempts to fetch invalid user IDs or handle cases where the user is unexpectedly missing.


11-32: Parallelize or streamline retrieval in getMaster.

Currently, the code builds a Map of promises without properly awaiting them in parallel (the for-loop awaits each entry sequentially). For a large user set, consider using Promise.all to improve performance, or confirm this logic is acceptable for your data volume.

packages/core/server/api/channel/index.put.ts (2)

27-40: Initialize optional fields or track usage.

Fields like description, conditions, phone, and minAmountForDelivery are set to null. Confirm that your downstream logic can handle null values and does not break if these fields remain unset. If needed, consider default strings or numbers to avoid potential null-pointer checks.


44-93: Consider custom or user-defined working day schedules.

Currently, all working days are initialized with "00:00". If you intend these defaults as placeholders, great. Otherwise, you might want to adopt a user-configurable approach or store partial availability. This ensures the data is meaningful if the channel is truly open or closed on certain days or times.

packages/core/server/api/channel/time-slots.get.ts (1)

26-27: Consider efficiency of working day retrieval

The implementation now fetches all working days and then filters, instead of finding one specific day. While this works for a small dataset of working days, consider adding a dedicated getWorkingDayByIndex function if this pattern is repeated in many places.

packages/core/server/services/db/product.ts (2)

7-49: Efficient product retrieval with variants

The getProducts function efficiently handles fetching multiple products along with their variants in a single pass. A couple of suggestions:

  1. Consider adding error handling for unexpected key formats
  2. Document the expected key format in comments for maintainability

136-147: Improve delete operation efficiency

Similar to getProductVariant, the deleteProductVariant function could be more efficient if you directly delete the variant when you know both product ID and variant ID, rather than searching through all keys.

apps/web-app/stores/channel.ts (3)

93-95: Naming clash risk in category’s products.
category.products is merely {id: string}[], which differs from Product[]. Consider renaming it or clarifying in docstrings to avoid confusion.


114-131: Potential multi-category edge case in query results.
getMenuCategoryByProduct only returns the first matching category. If products reside in multiple categories, consider how to handle them all.


132-148: Similar multi-category consideration for top searches.
Same logic as getProductsByQuery; products assigned to a single found category.

packages/core/types/index.d.ts (1)

48-56: Fixed-length WorkingWeek type.
Represents all seven days. If partial or variable schedules are allowed, consider a more flexible structure.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3d01a65 and 5de2c90.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (64)
  • .vscode/settings.json (1 hunks)
  • apps/web-app/.env.example (1 hunks)
  • apps/web-app/app/components/Cart/Line.vue (1 hunks)
  • apps/web-app/app/components/CategoryBlock.vue (2 hunks)
  • apps/web-app/app/components/Checkout/Line.vue (1 hunks)
  • apps/web-app/app/components/CommandCenter/ProductCard.vue (1 hunks)
  • apps/web-app/app/components/DeliveryInfoBlock.vue (1 hunks)
  • apps/web-app/app/components/Form/CreateChannelPaymentMethod.vue (2 hunks)
  • apps/web-app/app/components/Form/DeleteChannelPaymentMethod.vue (1 hunks)
  • apps/web-app/app/components/Form/DeleteProduct.vue (1 hunks)
  • apps/web-app/app/components/Form/DeleteProductVariant.vue (1 hunks)
  • apps/web-app/app/components/Form/UpdateWorkingDays.vue (3 hunks)
  • apps/web-app/app/components/Modal/CreateChannelPaymentMethod.vue (1 hunks)
  • apps/web-app/app/components/ProductCard.vue (1 hunks)
  • apps/web-app/app/components/SearchBlock.vue (2 hunks)
  • apps/web-app/app/middleware/02.staff.ts (1 hunks)
  • apps/web-app/app/pages/catalog/[categorySlug]/[productSlug]/index.vue (1 hunks)
  • apps/web-app/app/pages/catalog/[categorySlug]/index.vue (2 hunks)
  • apps/web-app/app/pages/checkout/index.vue (3 hunks)
  • apps/web-app/app/pages/command-center/product/[id]/index.vue (2 hunks)
  • apps/web-app/app/pages/command-center/system/index.vue (1 hunks)
  • apps/web-app/nuxt.config.ts (1 hunks)
  • apps/web-app/package.json (1 hunks)
  • apps/web-app/stores/channel.ts (3 hunks)
  • apps/web-app/stores/checkout.ts (1 hunks)
  • packages/core/nuxt.config.ts (1 hunks)
  • packages/core/package.json (1 hunks)
  • packages/core/server/api/channel/index.get.ts (3 hunks)
  • packages/core/server/api/channel/index.patch.ts (2 hunks)
  • packages/core/server/api/channel/index.put.ts (3 hunks)
  • packages/core/server/api/channel/master.put.ts (4 hunks)
  • packages/core/server/api/channel/payment-method/[id].delete.ts (2 hunks)
  • packages/core/server/api/channel/payment-method/[id].patch.ts (2 hunks)
  • packages/core/server/api/channel/payment-method/index.post.ts (2 hunks)
  • packages/core/server/api/channel/receiving-method/index.post.ts (2 hunks)
  • packages/core/server/api/channel/time-slots.get.ts (4 hunks)
  • packages/core/server/api/channel/working-day/activity.post.ts (2 hunks)
  • packages/core/server/api/channel/working-day/index.patch.ts (2 hunks)
  • packages/core/server/api/product/[id]/image.post.ts (2 hunks)
  • packages/core/server/api/product/[id]/index.delete.ts (2 hunks)
  • packages/core/server/api/product/[id]/index.get.ts (0 hunks)
  • packages/core/server/api/product/[id]/index.patch.ts (2 hunks)
  • packages/core/server/api/product/index.post.ts (2 hunks)
  • packages/core/server/api/product/slug/[slug].get.ts (0 hunks)
  • packages/core/server/api/product/variant/[id].delete.ts (2 hunks)
  • packages/core/server/api/product/variant/[id].patch.ts (2 hunks)
  • packages/core/server/api/product/variant/index.post.ts (2 hunks)
  • packages/core/server/api/user/[id]/index.get.ts (2 hunks)
  • packages/core/server/api/warehouse/[id]/index.get.ts (0 hunks)
  • packages/core/server/api/warehouse/[id]/index.patch.ts (2 hunks)
  • packages/core/server/api/warehouse/index.post.ts (2 hunks)
  • packages/core/server/plugins/01.db.ts (1 hunks)
  • packages/core/server/services/db/channel.ts (1 hunks)
  • packages/core/server/services/db/index.ts (1 hunks)
  • packages/core/server/services/db/media.ts (1 hunks)
  • packages/core/server/services/db/menu.ts (1 hunks)
  • packages/core/server/services/db/payment.ts (1 hunks)
  • packages/core/server/services/db/product.ts (1 hunks)
  • packages/core/server/services/db/user.ts (1 hunks)
  • packages/core/server/services/db/warehouse.ts (1 hunks)
  • packages/core/server/services/db/work.ts (1 hunks)
  • packages/core/shared/services/workingDay.ts (1 hunks)
  • packages/core/types/index.d.ts (5 hunks)
  • pnpm-workspace.yaml (1 hunks)
💤 Files with no reviewable changes (3)
  • packages/core/server/api/product/[id]/index.get.ts
  • packages/core/server/api/warehouse/[id]/index.get.ts
  • packages/core/server/api/product/slug/[slug].get.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (118)
apps/web-app/app/components/Modal/CreateChannelPaymentMethod.vue (1)

6-6: Verify behavior when form submission fails

Adding @submitted="modal.close()" will close the modal as soon as the form is submitted, regardless of success or failure. This is different from the existing behavior where the modal only closes on success.

Make sure this is the intended behavior and that users will still see error messages if the submission fails. If the intent is to keep the modal open on errors to display validation messages, this change might prevent that from happening.

apps/web-app/app/components/Form/CreateChannelPaymentMethod.vue (1)

47-47: Good addition of the 'submitted' event to the component's API.

Enhancing the component's events improves its flexibility. This addition of the 'submitted' event allows the parent component to react to form submissions immediately, rather than only on success.

packages/core/package.json (1)

16-16:

✅ Verification successful

Added cuid2 library for unique ID generation.

The addition of @paralleldrive/cuid2 introduces a collision-resistant ID generation library that's suitable for distributed systems. This is likely part of the database changes mentioned in the PR title.


🌐 Web query:

What are the advantages of using cuid2 over other ID generation methods?

💡 Result:

Cuid2 offers several significant advantages over traditional ID generation methods like UUIDs, legacy CUID, and NanoID, particularly for modern distributed systems requiring high security and collision resistance:

Enhanced Security

  • Cryptographic hashing using SHA3 ensures generated IDs don't leak system/time data[1][9]
  • Random salt per ID thwarts pattern recognition attacks[1]
  • Multiple entropy sources (system time, random values, session counter, host fingerprint) make brute-forcing impractical[1][7]

Collision Resistance

  • Default configuration provides 1.62e+37 entropy - 50% collision probability requires generating 4 quintillion IDs[1]
  • Far surpasses UUIDv4's 3.4e+38 theoretical maximum while being more practical[3][9]

Operational Advantages

  • Horizontal scaling without coordination between systems[1][3]
  • Deterministic length (default 24 chars) vs variable-length legacy CUID[1][7]
  • Base36 encoding makes URLs/database keys cleaner than UUID's hyphens[1][3]
// Example Cuid2 generation
import { createId } from '@paralleldrive/cuid2';
const id = createId(); // y3cfw1hafbtezzflns334sb2
Feature Cuid2 UUIDv4 NanoID
Entropy Source 5 independent Single PRNG Single PRNG
Hash Algorithm SHA3 None None
Default Length 24 chars 36 chars 21 chars
Collision Risk 1 in 4e+18 1 in 1e+38 1 in 1e+27
Sortable No No No

Modern System Optimization

  • Avoids database index fragmentation through non-sequential design[3][9]
  • Client-side generation capability reduces server roundtrips[1][3]
  • Tiny footprint (<5KB gzipped) suitable for browser apps[1]

For applications requiring maximum security in distributed environments (like financial systems or healthcare platforms), Cuid2 provides a robust balance of collision resistance and cryptographic safety that outperforms alternatives. However, simpler use cases might prefer NanoID for raw speed or UUIDv7 for time-sortable needs[3][9].

Citations:


Cuid2 Library Integration Verified and Approved

The addition of the @paralleldrive/cuid2 package is a robust choice for generating collision-resistant IDs. As confirmed by recent research, Cuid2 leverages SHA3 cryptographic hashing, employs a random salt per ID, and combines multiple entropy sources—ensuring enhanced security and extremely low collision probability. Its deterministic fixed-length (24 characters) and base36 encoding further support clean URL/database key designs, making it ideal for distributed systems and horizontal scaling.

  • Location: packages/core/package.json (line 16)
  • Impact: Aligns well with the database changes referenced in the PR title and supports the goals of high security and performance.

No further modifications are required based on this verification.

pnpm-workspace.yaml (1)

44-44:

✅ Verification successful

Added ioredis to workspace catalog.

The addition of ioredis: ^5.5.0 to the workspace catalog ensures consistent versioning across the monorepo. Version 5.5.0 is appropriate for the needed Redis functionality.


🌐 Web query:

What is the latest stable version of ioredis and are there any known issues with version 5.5.0?

💡 Result:

The latest stable version of ioredis is v5.5.0, released on February 7, 2025[1][8]. This release focuses on performance improvements and stability enhancements while maintaining backward compatibility with minimal breaking changes[1][2].

Known Issues in v5.5.0

No major issues are explicitly documented in the release notes or changelogs for this version[1][2][8]. However, developers should note:

  • ESM Import Syntax: While v5.x introduced support for ESM imports via import { Redis } from 'ioredis', older syntax (import Redis from 'ioredis') remains valid but will be deprecated in future major versions[1].

  • Cluster Reconnection: Some edge cases in cluster mode may require manual handling of transient connection errors during failover scenarios[8].

Key Features in Recent Versions

  • Native Promise support (no Bluebird dependency)[2]
  • Improved TypeScript declarations[2][8]
  • Redis v7 command support[2]
  • Enhanced auto-pipelining performance[2]

For production environments using Redis clusters or sentinels, ensure your retry strategy accounts for AWS ElastiCache's specific failover behaviors when using reconnectOnError configurations[8].

Citations:


Version 5.5.0 Confirmed: ioredis is Up-to-Date

The inclusion of ioredis: ^5.5.0 in the workspace catalog has been verified. Version 5.5.0 is the latest stable release, and no major issues are documented. This change ensures consistent versioning across the monorepo and meets our Redis functionality requirements. Note that while there are minor deprecation notes regarding ESM syntax and some cluster reconnection edge cases, these do not impact our current usage.

.vscode/settings.json (1)

54-57: SonarLint integration looks good

The addition of SonarLint connected mode configuration will help enforce consistent code quality standards across the project.

apps/web-app/.env.example (1)

17-18:

❓ Verification inconclusive

Redis configuration setup looks good

The Redis URL configuration is properly documented as being used for both database and cache functionality, which represents a significant architectural choice.

Since this represents a shift to using Redis as the main database, ensure this is adequately documented in your project:


🏁 Script executed:

#!/bin/bash
# Check if there's any migration documentation for this database change
fd -t f "migration|README|CHANGELOG" -E node_modules

# Check if there are any existing database implementations that might need updating
rg -t ts "useStorage\\(\\)\\.getItem\\(" --no-ignore-vcs

Length of output: 178


Attention: Verify Documentation Updates for Redis as Main Database

The Redis URL configuration in apps/web-app/.env.example now sets Redis as the primary database and cache. The configuration itself looks good; however, since this is an architectural shift, please double-check that the project documentation reflects this change. In particular:

  • Verify that files like CHANGELOG.md, README.md, and any migration guides in packages/core/README.md or packages/ui/README.md include notes or instructions regarding the switch to Redis.
  • Confirm that no outdated database implementations (e.g., code using useStorage().getItem() remain in the codebase.

Given the current automated searches produced limited output, a manual review of the documentation is recommended.

apps/web-app/nuxt.config.ts (2)

12-12:

❓ Verification inconclusive

Verify impact of channelId change

Changing the channelId from 'burger' to 'web-app' might impact how the application identifies itself or references data.

Make sure this change is consistent with any related code:


🏁 Script executed:

#!/bin/bash
# Check for references to the old channelId value
rg -t ts -t vue "burger" --no-ignore-vcs

# Check for places where channelId is used that might need updating
rg -t ts -t vue "channelId" --no-ignore-vcs

Length of output: 140


Double-check channelId Update Consistency
The change from 'burger' to 'web-app' in apps/web-app/nuxt.config.ts must be verified for consistency across the codebase. The initial search encountered an error due to the unrecognized file type "vue." Please re-run the above commands (which now correctly add Vue as a recognized type) to confirm that no outdated references to 'burger' remain and that all channelId usages are consistent.


🏁 Script executed:

#!/bin/bash
# Re-run search for references to the old channelId value "burger"
rg --type-add 'vue:*.vue' -t ts -t vue "burger" --no-ignore-vcs

# Re-run search for usages of "channelId"
rg --type-add 'vue:*.vue' -t ts -t vue "channelId" --no-ignore-vcs

Length of output: 11071


Action Required: Verify & Align channelId Configuration Across Modules

  • In apps/web-app/nuxt.config.ts, the channelId has been updated to 'web-app' as expected.
  • However, the search reveals that packages/core/nuxt.config.ts still sets channelId to 'burger'.
  • Please verify whether this divergence is intentional. If these environments should use a unified channel identifier, update the configuration in packages/core/nuxt.config.ts accordingly.
  • Additionally, review downstream usages (e.g., repository functions and API endpoints consuming channelId via useRuntimeConfig()) to ensure they behave as expected with the new value.

13-16:

✅ Verification successful

Check for impacts from locale removal

The locale property has been removed from the public runtime config, which aligns with the removal of NUXT_PUBLIC_LOCALE from .env.example.

Make sure this doesn't break locale-dependent functionality:


🏁 Script executed:

#!/bin/bash
# Check for references to the public locale configuration
rg -t ts -t vue "config\\.public\\.locale" --no-ignore-vcs
rg -t ts -t vue "useRuntimeConfig\\(\\)\\.public\\.locale" --no-ignore-vcs

Length of output: 187


Below is a revised shell script that uses glob patterns instead of file types so that we include Vue files in the search. Please execute this script and verify that no references to the removed locale configuration exist:

Once verified, let us know if you still see any references so we can reassess the potential locale-dependent functionality impacts.


🏁 Script executed:

[run_scripts]
#!/bin/bash
echo "Searching for references to 'config.public.locale' in TS and Vue files..."
rg -g "*.ts" -g "*.vue" "config\.public\.locale" --no-ignore-vcs

echo "Searching for references to 'useRuntimeConfig().public.locale' in TS and Vue files..."
rg -g "*.ts" -g "*.vue" "useRuntimeConfig\(\)\.public\.locale" --no-ignore-vcs

Length of output: 619


Locale Configuration Removal Verified

The search for references to config.public.locale and useRuntimeConfig().public.locale in both TS and Vue files returned no results. This confirms that removing the locale property from the public runtime configuration (and consequently NUXT_PUBLIC_LOCALE from the environment) does not leave any lingering dependencies or break locale-dependent functionality.

No further changes are required for this removal.

packages/core/server/api/warehouse/index.post.ts (3)

1-3: Good adoption of service pattern imports

The imports now correctly reflect the transition from repository pattern to service-oriented architecture, which aligns with the overall DB restructuring of this PR.


13-16: Appropriate warehouse creation implementation

The warehouse creation now uses createWarehouse function with a unique ID generated via createId(). This is a cleaner approach than using repository methods directly.


18-19: Good data consistency practice

Adding setChannelAsUpdated ensures the channel is marked as updated after warehouse creation, maintaining data integrity across related entities.

packages/core/server/api/user/[id]/index.get.ts (2)

1-1: Clean service function import

The import now correctly uses the service function rather than the repository, aligning with the overall architecture transition.


13-13: Appropriate repository replacement

The user retrieval now uses the getUser service function instead of repository.user.find, maintaining the same functionality while following the new architectural pattern.

packages/core/server/services/db/index.ts (1)

1-8: Well-structured Keys interface

This interface provides a clear contract for the different types of keys in the database, which helps with type safety and code organization.

packages/core/shared/services/workingDay.ts (1)

7-11:

❓ Verification inconclusive

Breaking schema change - ensure consumers are updated

The change from a record-based structure to an array-based structure for working days is more flexible but represents a breaking change. This shift requires updates to all code that consumes this schema.


🏁 Script executed:

#!/bin/bash
# Check for places that might be using the old schema structure
rg -A 10 "workingDaysUpdateSchema" --type ts

Length of output: 2374


Action: Confirm all consumers handle the new array schema correctly

The schema for working days has been refactored from a record-based structure to an array-based one. This is a breaking change, so please ensure that every consumer of workingDaysUpdateSchema has been updated accordingly. For example, in the file at packages/core/server/api/channel/working-day/index.patch.ts, the schema is used to parse the request body and then iterated over as an array. Verify that all other usages expect an array and that the client-side code (or any other upstream consumers) is also updated to send data in the new format.

  • Review in packages/core/server/api/channel/working-day/index.patch.ts: It uses workingDaysUpdateSchema.parse(body) and correctly iterates over the resulting array. Confirm that similar adaptations exist elsewhere.
  • Ensure tests are updated: Any tests or integrations relying on the old record structure should now validate against the new array structure.
apps/web-app/app/pages/catalog/[categorySlug]/index.vue (2)

11-11: Improved product iteration and navigation with category slug.

The changes to the ProductCard component usage are well-implemented. Moving from direct category filtering to using a pre-filtered products array improves template readability, and adding the category slug enables proper URL construction in child components.

Also applies to: 14-14


32-33: Good separation of concerns.

Moving the product filtering logic from the template to the script section is a solid improvement that follows Vue best practices. The filtering criteria correctly ensures that only available products with variants are displayed.

packages/core/server/api/channel/index.patch.ts (1)

1-1: Service-oriented refactoring improves modularity.

The migration from direct repository usage to a service function approach enhances code organization and follows a more maintainable architectural pattern. The explicit type casting to Partial<Channel> also adds clarity about the expected data structure.

Also applies to: 17-17

packages/core/server/api/channel/payment-method/[id].delete.ts (1)

1-2: Improved separation of concerns with service functions.

The refactoring to use dedicated service functions (deletePaymentMethod and setChannelAsUpdated) instead of direct repository access enhances modularity and maintainability. The addition of channel update notification ensures data consistency across the system.

Also applies to: 6-6, 15-16

apps/web-app/app/components/DeliveryInfoBlock.vue (1)

25-25: Simplified time formatting logic.

The refactoring to use the pre-formatted close property directly rather than manually constructing the time string reduces code complexity. This change is more maintainable and less error-prone, assuming the workingDay.close property is properly formatted.

apps/web-app/app/components/CommandCenter/ProductCard.vue (1)

46-46: Improved null safety with additional optional chaining

Adding the optional chaining operator to variants is a good defensive programming practice. It ensures the code gracefully handles cases where variants might be undefined, preventing potential runtime errors.

packages/core/server/api/product/index.post.ts (3)

1-3: Good architectural shift to dedicated service functions

The change in imports properly separates concerns by:

  1. Using a standardized external library (@paralleldrive/cuid2) for ID generation
  2. Importing specific service functions for database operations instead of using a repository directly

This refactoring improves modularity and maintainability.


13-20: Enhanced product creation with explicit default values

The implementation now properly initializes all required product fields with appropriate default values:

  • isAvailableForPurchase: true
  • mediaId: null
  • variants: []

This makes the contract between the API and service layer clearer and more explicit.


22-22: Consistent usage of service function for channel updates

Using the dedicated setChannelAsUpdated service function maintains consistency with other changes in this PR and centralizes the channel update logic.

apps/web-app/app/pages/catalog/[categorySlug]/[productSlug]/index.vue (1)

137-138: Improved category retrieval logic

Using channel.getMenuCategoryByProduct to retrieve the category centralizes the logic and follows the service-oriented approach of this PR.

packages/core/server/api/product/[id]/index.patch.ts (3)

1-2: Good separation of concerns with dedicated service imports

Importing specific service functions for database operations enhances code maintainability and readability.


20-20: Consistent usage of product service function

Using the dedicated patchProduct service function aligns with the architectural changes in this PR and improves separation of concerns.


22-22: Consistent usage of channel service function

Using the dedicated setChannelAsUpdated service function maintains consistency with other changes and centralizes the channel update logic.

packages/core/server/api/product/[id]/index.delete.ts (2)

1-2: Good architectural improvement: Moving to service-oriented design.

The shift from direct repository calls to service functions creates better separation of concerns and encapsulates database operations in dedicated service modules.


17-18:

❓ Verification inconclusive

Refactoring looks good, verify service implementation details.

The code properly replaces direct repository calls with service functions. This change improves maintainability and testability of the codebase.

Ensure the service implementations properly handle:

  1. Error conditions
  2. Transaction management (if multiple operations need to be atomic)

🏁 Script executed:

#!/bin/bash
# Check implementation of the deleteProduct and setChannelAsUpdated services

echo "Checking deleteProduct implementation:"
fd "deleteProduct" --type file --exec grep -A 10 "deleteProduct" {} \;

echo "Checking setChannelAsUpdated implementation:"
fd "setChannelAsUpdated" --type file --exec grep -A 10 "setChannelAsUpdated" {} \;

echo "Checking for transaction handling:"
fd "transaction|tx" --type file --exec grep -A 5 -B 5 "transaction|tx" {} \;

Length of output: 502


Manual Verification Required for Service Implementations

The refactoring looks good as it replaces direct repository calls with service functions. However, our automated checks did not return any evidence of the implementations of deleteProduct and setChannelAsUpdated, nor did they confirm transaction handling. Please manually verify that the service implementations:

  • Properly handle error conditions.
  • Include transaction management where multiple operations need to be atomic.
packages/core/server/api/product/variant/[id].delete.ts (2)

1-2: Good architectural change: Moving to service-oriented design.

The shift from direct repository access to service functions improves separation of concerns and code maintainability, aligning with the changes in other API endpoints.


16-17:

❓ Verification inconclusive

Implementation looks good, verify service implementation details.

The refactoring from direct repository calls to service functions is consistent with the changes in other endpoints and improves the architecture of the codebase.

Ensure the service implementations properly handle:

  1. Error conditions
  2. Transaction management (if multiple database operations need to be atomic)

🏁 Script executed:

#!/bin/bash
# Check implementation of the deleteProductVariant service

echo "Checking deleteProductVariant implementation:"
fd "deleteProductVariant" --type file --exec grep -A 10 "deleteProductVariant" {} \;

echo "Checking if deleteProductVariant handles any product relationships:"
fd "deleteProductVariant|productVariant" --type file --exec grep -B 10 -A 10 "delete.*ProductVariant|productVariant.*delete" {} \;

Length of output: 467


Please Manually Verify Service Error Handling & Transaction Management
The refactoring toward service functions in this endpoint is consistent and improves the codebase architecture. However, our automated checks did not yield sufficient details on the internal implementation of the deleteProductVariant (and by extension, setChannelAsUpdated) service functions. Please manually review their implementations to confirm that they correctly handle:

  • Error conditions (e.g., proper try/catch usage and error propagation)
  • Transaction management when multiple database operations must be atomic
packages/core/server/api/warehouse/[id]/index.patch.ts (2)

1-2: These new imports align well with the service-based refactor.
Adopting the patchWarehouse and setChannelAsUpdated services helps centralize your logic and improves maintainability.


7-7: Validate channelId and handle service errors carefully.
Retrieving channelId from the runtime config is fine; however, consider gracefully handling scenarios where channelId might be missing or invalid before calling setChannelAsUpdated(channelId). Additionally, confirm that patchWarehouse throws (or handles) descriptive errors when invalid inputs are passed.

Would you like a script to verify that channelId is consistently defined in your environment?

Also applies to: 19-19, 21-21

apps/web-app/app/pages/command-center/system/index.vue (2)

88-88: Watch out for non-unique keys.
Using workingDay.day as the key may cause collisions if multiple entries share the same day. Ensure each day field is guaranteed unique across the array.


91-91: Cleaner prop usage.
Directly passing workingDay.day simplifies usage. This is fine as long as every workingDay object has a valid day property.

packages/core/server/api/channel/payment-method/[id].patch.ts (2)

1-2: Service-based approach looks consistent.
Switching from the repository to patchPaymentMethod and setChannelAsUpdated keeps your codebase aligned with the new architecture.


7-7: Confirm channelId validity.
If channelId is undefined or invalid, setChannelAsUpdated(channelId) could fail silently or throw. Consider adding a safeguard or fallback for missing values.

Also applies to: 19-20

packages/core/server/services/db/media.ts (2)

1-3: Consider validating the media ID.
Although this logic is straightforward, ensure there’s always a valid id input. If id is incorrectly formatted or empty, this function could silently return null.


14-16: Confirm whether a non-existent item needs special handling.
If the item does not exist, this function will silently succeed. Verify whether you need to throw or otherwise handle the not-found case.

packages/core/server/api/product/variant/[id].patch.ts (3)

1-2: Service-based approach looks clean.
Importing these dedicated service functions rather than calling repository methods directly helps maintain separation of concerns.


20-20: Ensure proper handling if the patch operation returns nothing.
Double-check that patchProductVariant(id, data) always returns a valid result. If it can return null, consider throwing an error or handling it gracefully.


22-22: Channel update looks good.
Marking the channel as updated makes sense here, and the surrounding try/catch handles potential failures.

packages/core/server/api/channel/working-day/activity.post.ts (4)

1-2: Aligns with the service-based architecture.
These imports are consistent with the broader shift away from repository calls, improving readability and maintainability.


18-19: Distinguish between no data vs. empty array.
If getWorkingDays() returns an empty array (rather than null), the code will still skip throwing. Confirm that is the intended behavior.


26-27: Double-check behavior if the day is not found.
You’re toggling !day?.isActive, which defaults to true for a missing day. Decide whether you want to create a new entry, throw an error, or keep this behavior.


29-29: Channel update is appropriate.
Great job ensuring the channel state is marked as updated after changing working day activity. The error handling via the parent try/catch is sufficient.

packages/core/server/api/channel/receiving-method/index.post.ts (3)

1-1: LGTM: Clean service import.

The refactoring from repository pattern to service functions looks good, with clear imports of the specific functions needed.


17-17: LGTM: Successfully migrated to service function.

The code has been correctly updated to use the new getChannel service function.


20-22: LGTM: Update operations properly refactored.

The channel update operations have been successfully migrated to use the patchChannel service function while maintaining the same functionality.

Also applies to: 26-28

apps/web-app/app/components/SearchBlock.vue (2)

3-3: Added null safety with optional chaining.

Good defensive programming practice to prevent potential runtime errors if searchQuery is null or undefined.


41-41: Improved separation of concerns.

Moving the top results logic to the channel store (getTopSearchedProducts()) instead of directly manipulating the data in the component is a better architectural approach.

apps/web-app/app/components/ProductCard.vue (3)

45-48: LGTM: Added categorySlug prop.

Adding the categorySlug as a required prop improves component reusability and makes data flow clearer.


54-55: Verify variant selection behavior change.

The logic for selecting the smallest variant has changed. Previously, it likely found the variant with the lowest price, but now it always selects the first variant in the array. This could change the displayed price for products with multiple variants.

Make sure this change aligns with the intended business logic for displaying product prices.


60-60: LGTM: Improved URL construction.

Using the provided categorySlug prop directly for URL construction is more direct and reliable than extracting it from the product object.

apps/web-app/app/pages/command-center/product/[id]/index.vue (1)

141-143: Good refactoring of data access pattern.

Moving from direct property access to a service method improves maintainability and decouples the component from the underlying data structure.

apps/web-app/app/components/CategoryBlock.vue (1)

22-22: Template now uses precomputed products list.

Moving the filtering logic from the template to the script section improves readability and performance. The addition of the category-slug prop to ProductCard is consistent with the data access pattern changes.

Also applies to: 25-25

packages/core/server/api/product/variant/index.post.ts (3)

1-3: Good architectural change to service-based approach.

The transition from repository patterns to service functions improves code organization and maintainability.


12-21: Explicit default values improve code clarity.

Setting explicit default values for all fields ensures consistent data structure. The use of createId() for generating unique IDs is a good practice.

One suggestion - consider using nullish coalescing for all properties consistently:

const variant = await createProductVariant({
  ...data,
  id: createId(),
  sku: data.sku ?? null,
  net: data.net ?? null,
  calories: data.calories ?? null,
  protein: data.protein ?? null,
  fat: data.fat ?? null,
  carbohydrate: data.carbohydrate ?? null,
})

23-23: Good separation of concerns with channel update.

Moving the channel update logic to a dedicated service function improves code organization.

packages/core/server/api/channel/working-day/index.patch.ts (2)

1-2: Good architectural change to service-based approach.

The import of dedicated service functions improves code organization and follows the same pattern as other changes in this PR.


22-22: Good separation of concerns with channel update.

Moving the channel update logic outside the loop and to a dedicated service function is a good practice.

packages/core/server/api/channel/payment-method/index.post.ts (1)

1-3: Good use of service modules for improved architecture.

The imports demonstrate a shift from a repository pattern to a service-oriented architecture, which is a good design decision for maintainability.

packages/core/server/services/db/work.ts (1)

21-37: Immutable updates are correctly implemented.

Good job implementing immutable updates by creating a new array with the updated day instead of modifying the existing array directly. This helps prevent unexpected side effects.

apps/web-app/app/pages/checkout/index.vue (1)

2-220: Use <template> for cleaner conditional rendering, but confirm maintenance state handling.

Switching to <template v-if> is a good move to avoid adding extra DOM elements. However, consider whether you intend to show a distinct message or UI when channel.isOnMaintenance. Currently, the same "cart empty" screen is displayed in that scenario, which might confuse users.

packages/core/server/api/channel/master.put.ts (3)

1-3: Imports appear valid.

The new import statements for createId, createUser, createUserCredentials, and getMaster look consistent and properly structured. No concerns here.


17-17: Validate whether channel-specific master retrieval is required.

const master = await getMaster() might be insufficient if you ever support multiple channels. Verify that retrieving a single global master user is correct. Otherwise, consider scoping the master to a channelId.


28-38: Confirm active-but-unconfirmed user logic.

Creating the master user with isActive: true yet isConfirmed: false may be intentional, but can be confusing. Additionally, setting email to null could cause issues in areas expecting a valid email. Double-check flows that rely on an email or a confirmed status.

packages/core/server/services/db/payment.ts (3)

1-3: getPaymentMethod handles single retrieval well.

The function is straightforward, but note it returns null if not found. Be sure callers handle the null case properly.


30-45: patchPaymentMethod merges partial updates cleanly.

Merging existing fields with ...data is good. Ensure that updatedAt is consistently used by the rest of the codebase for out-of-band sync or auditing, if needed.


47-49: deletePaymentMethod straightforwardly removes by key.

Method looks good for your storage approach. Confirm whether failing to find a method is an error or not. Right now, removing a non-existent key silently succeeds.

apps/web-app/app/components/Form/UpdateWorkingDays.vue (2)

3-16: Validate existence of day.index and potential off-by-one issues.

You're indexing workingDays using day.index in the template (v-model="workingDays[day.index].open" and v-model="workingDays[day.index].close"). Ensure each day object actually has a valid, zero-based index property in sync with the array. Otherwise, you might encounter out-of-range errors or unintentional data mutations.


65-65: Ensure body is a plain object or array instead of a Ref.

When passing body: workingDays to $fetch, you're passing a Ref object. If your framework does not automatically unwrap Refs, consider using workingDays.value to send a plain array as the request body (unless you explicitly rely on auto-unwrap behavior).

packages/core/server/services/db/user.ts (3)

7-9: Clarify usage of getUserCredentials.

Similar to getUser, this also returns null if not found. Ensure callers handle the null case appropriately (e.g., throwing an error or returning a 404 to the client).


34-41: Check for overwrites or unique constraints when creating a new user.

The code does not guard against overwriting an existing user ID in storage. If you rely on globally unique IDs, ensure collisions are handled or validated before writing to storage.


43-50: Add error handling or duplication checks for createUserCredentials.

Similar to createUser, there's no check for existing credentials. Consider whether duplicates with the same ID should be disallowed or gracefully handled.

packages/core/server/api/channel/index.put.ts (2)

1-2: Imports look good.

The shift from repository calls to service-based functions (getChannel, createChannel, and createWorkingDays) aligns well with a service-oriented architecture.


16-16: Verify channel existence logic.

Early-stopping if a channel already exists is reasonable. Ensure you handle scenarios where the channelId might be malformed or not string-based, although the existing check is fine for standard usage.

packages/core/server/api/product/[id]/image.post.ts (6)

3-5: Code architecture improvement with service functions

The refactoring from repository pattern to dedicated service functions improves code organization and maintainability. Each service function has a clear purpose, making the code easier to understand and test.


75-75: Function usage looks good

Correctly replaced repository.media.create with the new createMedia service function.


77-77: Function usage looks good

Correctly replaced repository.product.find with the new getProduct service function.


85-85: Function usage looks good

Correctly replaced repository.media.delete with the new deleteMedia service function.


88-88: Function usage looks good

Correctly replaced repository.product.patch with the new patchProduct service function.


90-90: Function usage looks good

Correctly replaced repository.channel.setAsUpdated with the new setChannelAsUpdated service function.

packages/core/server/api/channel/time-slots.get.ts (5)

2-3: Clean service-based imports

Good choice to import specific service functions rather than importing the entire repository, improving code clarity.


15-15: Function usage looks good

Correctly replaced repository.channel.find with the new getChannel service function.


36-40: Improved time handling with string parsing

The transition to a string-based time format (e.g., "10:30") and parsing it is a more standard approach than using separate hour and minute fields. This makes the data format more human-readable and consistent with common time representations.


42-45: Consistent approach for close time

Good consistency in handling both open and close times with the same string parsing approach.


48-48: Updated conditional for midnight handling

Correctly updated to use timeCloseHours variable to match the new time format.

packages/core/server/api/channel/index.get.ts (6)

2-9: Well-organized service imports

The imports are now more specific and targeted to the service functions needed, which improves maintainability and provides better clarity on dependencies.


35-35: Function usage looks good

Correctly replaced repository.channel.find with the new getChannel service function in the shouldInvalidateCache method.


54-54: Function usage looks good

Correctly replaced repository.channel.find with the new getChannel service function in the main handler.


62-67: Enhanced data retrieval with service functions

Good use of service functions to fetch related entities. This approach centralizes data access logic in the service layer.


69-74: Simplified working day identification

The code now fetches all working days once and then filters by index, which is cleaner than making separate calls for each working day.


77-86: Enriched response data

The return object now includes more data (menus, products, warehouses, paymentMethods), providing a more comprehensive context for the client. This could reduce the number of API calls needed from the frontend.

packages/core/server/services/db/product.ts (3)

3-5: Clean and concise implementation

The getProduct function is straightforward and follows good separation of concerns.


51-66: Consistent pattern for update operations

Good pattern of fetch-modify-save-return for both product and variant updates. The code correctly handles the case where the entity doesn't exist and updates the timestamp.

Also applies to: 110-125


68-75: Consistent pattern for create operations

Good pattern for creating both products and variants with proper timestamp handling.

Also applies to: 127-134

apps/web-app/stores/channel.ts (15)

7-9: Check for multi-category product scenario.
Currently, ProductWithCategory associates only one MenuCategory per product. If products can belong to multiple categories, consider using an array for category or handling the multi-category use case elsewhere.


27-29: Configuration refs look good.
Declaring workingDays, menus, and products with clear types enhances readability and maintainability.


34-37: Computed properties are straightforward.
These computed values improve clarity for commonly accessed store data.


42-73: Validate the fetched data shape or consider partial updates.
This function relies on multiple properties in data. If the backend's contract changes or the response is partial, potential undefined errors could appear.

Would you like a script to scan for any usage of these properties that might be missing null checks?


75-86: Consistent time-slot fetching.
Error handling aligns well with early return on empty data. Implementation looks good.


87-89: Simple getter is fine.
Returning a ComputedRef<Menu | undefined> ensures reactive updates.


90-92: No issues with category lookup.
Returning a computed reference is aligned with the store’s reactive nature.


96-98: Active category retrieval lgtm.
Returning a computed reference matches the pattern used in other get functions.


99-101: Slug-based category retrieval is consistent.
Implementation aligns with prior getters—no issues found.


102-103: Direct product finder is fitting.
Simple logic, minimal overhead.


105-107: Slug-based product lookup is good.
No concerns with the straightforward find approach.


108-109: Variant-to-product relationship is clear.
Looks correct for bridging a product variant ID to its product.


112-113: Aggregation approach for product variants is valid.
Flattening variants is a common approach—no issues found.


150-153: Category-based product filter is clean.
Using a computed ref ensures reactivity for the displayed products.


189-198: Exporting new methods for global usability.
Adding these references in the returned object makes them straightforward to consume across the app.

packages/core/types/index.d.ts (5)

4-5: Verify string-based timestamps.
Switching from Date to string might require parsing or time-zone handling wherever these timestamps are used. Ensure consistency across the codebase.

Also applies to: 60-61, 97-98, 116-117, 199-200, 213-214


39-42: Simplified WorkingDay structure.
The new index, day, open, and close properties are easier to maintain. Verify that legacy usage of removed properties (e.g., createdAt) is fully updated.


46-46: DayCode enumeration.
A clear type for days of the week—this improves type safety.


80-80: products: { id: string }[] field.
Storing just the product ID might suffice for referencing. If you need more product data here, consider a nested Product or a dedicated relationship type.


206-206: Expanded user permissions.
Storing an array of PermissionCode offers flexible role-based access control.

@@ -16,6 +16,7 @@ export default defineNuxtConfig({
accessKeyId: '',
secretAccessKey: '',
},
redisUrl: '',
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Redis integration added to runtime configuration.

The addition of redisUrl to the runtime configuration enables Redis connection support. This is a significant architectural change that aligns with the PR's database focus.

Make sure you've also updated documentation to reflect this new configuration option. Users will need to know how to properly configure this for different environments.


🏁 Script executed:

#!/bin/bash
# Check if there's documentation for the new Redis configuration
fd -t f "README|\.md$" | xargs grep -l "redisUrl\|REDIS_URL" || echo "No documentation found for Redis configuration"

Length of output: 165


Documentation Update Required: Add Redis Configuration Guidance
The integration of redisUrl into the runtime configuration has been approved and aligns with the PR's database focus. However, the verification indicates that the new Redis configuration option is not documented. Please update the relevant documentation (e.g., README.md or other markdown files) to explain how users should configure redisUrl (or REDIS_URL) for various environments.

  • Ensure the documentation includes instructions on setting the configuration for different deployment scenarios.
  • Update any existing configuration guides to include this Redis integration.

@@ -18,6 +18,7 @@
"@next-orders/database": "workspace:*",
"@next-orders/ui": "workspace:*",
"@pinia/nuxt": "catalog:",
"ioredis": "catalog:",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Added ioredis client dependency.

The addition of ioredis provides the application with a Redis client, which is consistent with the Redis URL configuration added in the Nuxt config.

Check that the Redis implementation has proper error handling:


🏁 Script executed:

#!/bin/bash
# Look for Redis client implementation
fd -t f ".ts$|.js$" | xargs grep -l "new Redis\|createClient" | xargs grep -l "try\|catch\|error" || echo "Potential missing error handling in Redis client implementation"

Length of output: 236


Action Required: Enhance Redis Client Error Handling

The addition of the ioredis dependency is consistent with the Redis URL configuration in the Nuxt config. However, our verification indicates that the Redis client implementation is missing proper error handling (i.e., try/catch or error event listeners around the client instantiation/use).

  • Issue Identified: No try/catch blocks or other error handling mechanisms were found where the Redis client is initialized.
  • Recommendation: Review the Redis client instantiation code and add appropriate error handling. For instance, wrap the client creation and connection logic within try/catch blocks, and consider handling error events as necessary.

Comment on lines 139 to 145
const breadcrumbs = computed(() => [
{ label: t('common.home'), icon: 'food:home', to: '/' },
{
label: product.value?.category.name ?? '',
to: `/catalog/${product.value?.category?.slug}`,
label: category?.name ?? '',
to: `/catalog/${category?.slug}`,
},
])
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Potential issue with missing fallback for category slug

While there's a fallback for the category name with category?.name ?? '', there isn't a similar fallback for the category slug in the URL construction. If category is undefined, the URL would include "undefined" as part of the path.

Consider adding a fallback for the slug:

- to: `/catalog/${category?.slug}`,
+ to: `/catalog/${category?.slug ?? ''}`,
📝 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 breadcrumbs = computed(() => [
{ label: t('common.home'), icon: 'food:home', to: '/' },
{
label: product.value?.category.name ?? '',
to: `/catalog/${product.value?.category?.slug}`,
label: category?.name ?? '',
to: `/catalog/${category?.slug}`,
},
])
const breadcrumbs = computed(() => [
{ label: t('common.home'), icon: 'food:home', to: '/' },
{
label: category?.name ?? '',
to: `/catalog/${category?.slug ?? ''}`,
},
])

Comment on lines +9 to +10
const { error } = await useFetch(`/api/user/${user.value.id}`)
if (error.value) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential error with optional chaining removal.

The change removed optional chaining (?.) when accessing user.value.id, which could lead to runtime errors if user.value is undefined. While line 4 seems to check for user.value?.id, a race condition or state change could still make this risky.

-  const { error } = await useFetch(`/api/user/${user.value.id}`)
-  if (error.value) {
+  const { error } = await useFetch(`/api/user/${user.value?.id}`)
+  if (error.value) {

The broadening of the error condition from checking a specific message to just checking for any error is a good change for more robust error handling.

📝 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 { error } = await useFetch(`/api/user/${user.value.id}`)
if (error.value) {
const { error } = await useFetch(`/api/user/${user.value?.id}`)
if (error.value) {

const category = channel.getMenuCategoryByProduct(product.value?.id ?? '')
const menu = channel.menus.find((menu) => menu.categories.some((category) => category.id === category?.id))

const menuPageUrl = computed(() => `/command-center/menu/${menu?.id}`)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure menu is defined before constructing URL.

The menu?.id could be undefined if no menu is found, which would result in an invalid URL like /command-center/menu/undefined.

-const menuPageUrl = computed(() => `/command-center/menu/${menu?.id}`)
+const menuPageUrl = computed(() => menu?.id ? `/command-center/menu/${menu.id}` : '/command-center/menu')
📝 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 menuPageUrl = computed(() => `/command-center/menu/${menu?.id}`)
const menuPageUrl = computed(() => menu?.id ? `/command-center/menu/${menu.id}` : '/command-center/menu')

Comment on lines 1 to 3
export async function getWorkingDays(): Promise<WorkingWeek | null> {
return useStorage('db').getItem<WorkingWeek>('working-time')
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure types and utilities are imported.

The function looks good, but ensure that WorkingWeek type and useStorage utility are properly imported (not visible in this snippet).


🏁 Script executed:

#!/bin/bash
# Check if the WorkingWeek type and useStorage utility are imported
grep -A 5 "import.*WorkingWeek" packages/core/server/services/db/work.ts || echo "WorkingWeek type import not found"
grep -A 5 "import.*useStorage" packages/core/server/services/db/work.ts || echo "useStorage utility import not found"

Length of output: 306


Missing Import Declarations for WorkingWeek and useStorage

The current file does not import either the WorkingWeek type or the useStorage utility. Please add the appropriate import statements at the beginning of the file. For example:

  • Add an import for WorkingWeek, e.g.,
    import { WorkingWeek } from 'path/to/types';
  • Add an import for useStorage, e.g.,
    import { useStorage } from 'path/to/storage';

Ensure that the import paths match your project’s structure.

Comment on lines +95 to +108
export async function getProductVariant(id: string): Promise<ProductVariant | null> {
const { productKeys } = await getKeys()

for (const key of productKeys) {
const [, productId, variant, variantId] = key.split(':')

// product:id:variant:id
if (productId && variant === 'variant' && variantId === id) {
return useStorage('db').getItem<ProductVariant>(key)
}
}

return null
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize variant retrieval

The getProductVariant function iterates through all product keys, which could be inefficient as the number of products grows. Consider adding a way to directly access variants if you know both product ID and variant ID.

export async function getProductVariant(id: string): Promise<ProductVariant | null> {
-  const { productKeys } = await getKeys()
-
-  for (const key of productKeys) {
-    const [, productId, variant, variantId] = key.split(':')
-
-    // product:id:variant:id
-    if (productId && variant === 'variant' && variantId === id) {
-      return useStorage('db').getItem<ProductVariant>(key)
-    }
-  }
-
-  return null
+  // If we already know the product ID for this variant, we could use:
+  // return useStorage('db').getItem<ProductVariant>(`product:${productId}:variant:${id}`)
+  
+  // Without product ID, we still need to search:
+  const { productKeys } = await getKeys()
+  
+  // Filter keys first before fetching data
+  const variantKey = productKeys.find(key => {
+    const [, , variant, variantId] = key.split(':')
+    return variant === 'variant' && variantId === id
+  })
+  
+  if (variantKey) {
+    return useStorage('db').getItem<ProductVariant>(variantKey)
+  }
+  
+  return null
}
📝 Committable suggestion

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

Suggested change
export async function getProductVariant(id: string): Promise<ProductVariant | null> {
const { productKeys } = await getKeys()
for (const key of productKeys) {
const [, productId, variant, variantId] = key.split(':')
// product:id:variant:id
if (productId && variant === 'variant' && variantId === id) {
return useStorage('db').getItem<ProductVariant>(key)
}
}
return null
}
export async function getProductVariant(id: string): Promise<ProductVariant | null> {
// If we already know the product ID for this variant, we could use:
// return useStorage('db').getItem<ProductVariant>(`product:${productId}:variant:${id}`)
// Without product ID, we still need to search:
const { productKeys } = await getKeys()
// Filter keys first before fetching data
const variantKey = productKeys.find(key => {
const [, , variant, variantId] = key.split(':')
return variant === 'variant' && variantId === id
})
if (variantKey) {
return useStorage('db').getItem<ProductVariant>(variantKey)
}
return null
}

Comment on lines +77 to +93
export async function deleteProduct(id: string): Promise<void> {
const { productKeys } = await getKeys()

for (const key of productKeys) {
const [, productId, variant, variantId] = key.split(':')

// product:id
if (productId === id && !variant) {
await useStorage('db').removeItem(key)
}

// product:id:variant:id
if (productId === id && variant === 'variant' && variantId) {
await useStorage('db').removeItem(key)
}
}
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider transaction safety for delete operations

The deleteProduct function doesn't use transactions, which could lead to inconsistent data if an error occurs during deletion of product variants. Consider implementing a way to ensure atomicity (all-or-nothing operations) if your storage mechanism supports it.


🌐 Web query:

Does Redis support transactions for atomic operations?

💡 Result:

Yes, Redis supports atomic operations through transactional commands (MULTI, EXEC, DISCARD, WATCH) and Lua scripting. Here's how it works:


1. MULTI/EXEC Transactions

Redis groups commands into atomic blocks using MULTI (to start) and EXEC (to execute):

  • Atomic Execution: All commands between MULTI and EXEC are queued and executed sequentially as a single unit[2][4].

  • Example:

    > MULTI
    OK
    > INCR counter
    QUEUED
    > SET status "done"
    QUEUED
    > EXEC
    1) (integer) 1
    2) OK

    This increments counter and sets status atomically[2].

  • Error Handling:

    • Commands with syntax errors (e.g., invalid arguments) abort the transaction before execution[2].
    • Runtime errors (e.g., wrong data type) after EXEC don’t roll back—only failed commands are skipped[2][4].
  • Optimistic Locking with WATCH:
    Monitors keys for changes before committing:

    WATCH balance
    balance = GET balance
    MULTI
    SET balance $balance-10
    EXEC # Fails if "balance" changed after WATCH

    If balance is modified by another client before EXEC, the transaction aborts[2][4].


2. Lua Scripting

Redis executes Lua scripts atomically on the server:

  • Guaranteed Atomicity: Scripts run without interruption, combining multiple operations into one[3].
  • Example (conditional update):
    local key = KEYS[1]
    local value = ARGV[1]
    if redis.call("GET", key) == value then
      return redis.call("INCR", "success_count")
    end
    return nil
    Executed via EVAL or EVALSHA:
    // Jedis example in Java
    String script = "return redis.call('SET', KEYS[1], ARGV[1])";
    jedis.eval(script, 1, "key", "value"); // Atomic SET[3]

Key Differences Between Methods

Feature MULTI/EXEC Lua Scripting
Atomicity Commands queued then executed[2] Entire script runs atomically[3]
Error Handling Partial failures possible[2] All-or-nothing execution[3]
Network Overhead Multiple roundtrips Single request/response[3]
Complex Logic Limited to queued commands Supports conditionals/loops[3]

When to Use Each

  • Use MULTI/EXEC for simple command batches with optimistic locking via WATCH.
  • Use Lua scripting for complex logic requiring server-side execution or strict atomicity across conditional steps[3][4].

Redis transactions lack traditional rollbacks but provide atomicity through these mechanisms[2][4].

Citations:


**Atomic Deletion Consideration for Product and Variant Keys **

The current implementation in packages/core/server/services/db/product.ts (lines 77–93) individually removes each key. This exposes you to possible data inconsistency if an error occurs midway during the deletion process. Since your storage mechanism (Redis) supports transactions via MULTI/EXEC and Lua scripts—which provide atomic execution—it is advisable to wrap these removal operations in a transactional block. This approach would ensure that either all deletions succeed or none do, safeguarding against partial deletion states.

Please review and update the deletion logic to leverage Redis transactional commands (or Lua scripting for stricter atomicity), thereby ensuring all-or-nothing execution of product and variant deletions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (15)
packages/core/server/api/auth/sign-in.post.ts (1)

21-21: Consider clarifying password field naming

The code now compares against credentials.password rather than the previous credentials.passwordHash. Even if the value is still a hash, naming it "password" could be misleading to other developers who might assume it contains plaintext.

Consider renaming this field to passwordHash in both the service function and database schema to make it clear that it stores a hashed value, not plaintext.

packages/core/server/services/db/index.ts (1)

11-29: Efficient key retrieval and categorization.

The getKeys function efficiently retrieves all keys and categorizes them by prefix. This approach simplifies key management throughout the application and supports the new service-oriented architecture.

One observation: This implementation will scan all keys in the database on each call. For large databases, consider adding caching with appropriate invalidation if performance becomes an issue.

packages/core/server/services/db/menu.ts (2)

7-49: Menu and categories batch retrieval implementation.

The getMenus function efficiently retrieves multiple menus and their categories in a single operation. It uses a Map for storage and handles various edge cases like missing menus or categories.

However, there's a potential inefficiency in the nested loop (lines 22-29) that iterates through all keys for each menu to find its categories.

Consider reorganizing the key parsing to avoid the nested loop. You could pre-process all keys to categorize them by type and relationship:

-      const menuCategoriesKeys: string[] = []
-      for (const k of keys) {
-        const [, menuId, category, categoryId] = k.split(':')
-
-        // menu:id:category:id
-        if (menuId === menu.id && category === 'category' && categoryId) {
-          menuCategoriesKeys.push(k)
-        }
-      }
+      // Assuming we pre-processed keys into a map of menu IDs to category keys
+      const menuCategoriesKeys = menuCategoryKeysMap.get(menu.id) || []

This would require an initial pass to build the map but would avoid O(n²) complexity.


91-104: Menu category retrieval function implementation.

The getMenuCategory function retrieves a category by ID but has to iterate through all menu keys to find it. This could be inefficient for a large number of menus and categories.

Consider a more direct key lookup pattern based on category ID, perhaps using a secondary index or a more structured key format:

export async function getMenuCategory(id: string): Promise<MenuCategory | null> {
  // If you know the menuId, you could use a more direct approach:
  // return useStorage('db').getItem<MenuCategory>(`menu:${menuId}:category:${id}`)
  
  // Alternatively, consider creating a category index:
  // const categoryIndex = await useStorage('db').getItem<Record<string, string>>('category_index')
  // if (categoryIndex && categoryIndex[id]) {
  //   return useStorage('db').getItem<MenuCategory>(categoryIndex[id])
  // }
  
  // Current implementation (potentially inefficient for large datasets)
  const { menuKeys } = await getKeys()
  // ...rest of the implementation
}
packages/core/server/api/checkout/add/index.post.ts (3)

36-59: Validate checkout creation parameters.
When creating a new checkout, ensure that required fields match business requirements (e.g., shippingPrice ≥ 0, time not empty if needed, etc.). Consider applying validations or domain constraints here.


114-114: Consider a dedicated increment function.
Patching the line to increase quantity by 1 is correct. However, a specialized helper (e.g., incrementCheckoutLineQuantity) could be more expressive and encapsulate additional validations (like maximum quantity).


117-117: Recheck performance for recalculation.
Recalculating the entire checkout after adding a single product line might be suboptimal if the system scales or lines become numerous. Consider batching or deferring this recalculation if performance becomes an issue.

packages/core/server/api/checkout/index.patch.ts (3)

33-33: Validate checkout existence before finalizing.
Fetching again ensures the checkout is up-to-date, but consider concurrency or rate-limiting if repeated calls occur in quick succession.


46-50: Ensure patch data alignment with domain logic.
Patching checkout with fields like change converted to string could have domain implications. Validate that all transformations (e.g. for currency or numeric fields) are consistent throughout the system.


89-89: Consider lazy retrieval vs. single consolidated query.
If the system can unify calls to payment and warehouse keys, consider returning them in a single query or object to reduce overhead and keep logic simpler.

packages/core/server/services/db/checkout.ts (5)

3-5: Consider caching or indexing.
getCheckoutRegistryItems repeatedly fetches the entire list of checkouts. If usage is frequent, you might optimize by maintaining sorted or cached structures.


11-37: Check for potential concurrency issues.
getLatestFinishedCheckouts concurrently queries items from storage, then re-fetches them. If your system grows large, you might face performance bottlenecks or race conditions. A more direct approach (e.g., an indexed structure) could be beneficial.


48-61: Patch approach fosters flexibility.
Merging partial data is a nice pattern. If necessary, add validations to ensure that incorrectly typed partial data does not corrupt the existing checkout structure.


96-100: Finalize with caution.
Setting checkout status to 'FINISHED' might require additional domain-level validations (e.g., verify payment status). Ensure usage is consistent with the rest of the order lifecycle.


131-152: Partial patching fosters code readability.
Updating a specific line with minimal code duplication is beneficial. For advanced concurrency, consider implementing an optimistic concurrency control strategy or versioning to avoid accidental overwrites.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5de2c90 and 1896e97.

📒 Files selected for processing (33)
  • apps/web-app/app/components/CommandCenter/CheckoutLine.vue (2 hunks)
  • apps/web-app/app/pages/checkout/index.vue (4 hunks)
  • apps/web-app/stores/checkout.ts (3 hunks)
  • packages/core/server/api/auth/sign-in.post.ts (3 hunks)
  • packages/core/server/api/category/[id]/index.patch.ts (2 hunks)
  • packages/core/server/api/category/index.post.ts (2 hunks)
  • packages/core/server/api/category/slug/[slug].get.ts (0 hunks)
  • packages/core/server/api/channel/index.patch.ts (1 hunks)
  • packages/core/server/api/channel/index.put.ts (2 hunks)
  • packages/core/server/api/channel/master.put.ts (3 hunks)
  • packages/core/server/api/channel/payment-method/index.post.ts (1 hunks)
  • packages/core/server/api/channel/receiving-method/index.post.ts (1 hunks)
  • packages/core/server/api/channel/time-slots.get.ts (3 hunks)
  • packages/core/server/api/channel/working-day/activity.post.ts (1 hunks)
  • packages/core/server/api/channel/working-day/index.patch.ts (1 hunks)
  • packages/core/server/api/checkout/add/index.post.ts (5 hunks)
  • packages/core/server/api/checkout/id/[id].get.ts (2 hunks)
  • packages/core/server/api/checkout/index.get.ts (2 hunks)
  • packages/core/server/api/checkout/index.patch.ts (6 hunks)
  • packages/core/server/api/checkout/line/[id].post.ts (3 hunks)
  • packages/core/server/api/checkout/list/index.get.ts (1 hunks)
  • packages/core/server/api/health/index.get.ts (2 hunks)
  • packages/core/server/api/menu/[id]/activity.post.ts (2 hunks)
  • packages/core/server/api/menu/[id]/index.patch.ts (2 hunks)
  • packages/core/server/api/menu/index.post.ts (2 hunks)
  • packages/core/server/services/db/checkout.ts (1 hunks)
  • packages/core/server/services/db/index.ts (1 hunks)
  • packages/core/server/services/db/menu.ts (1 hunks)
  • packages/core/server/services/db/receiver.ts (1 hunks)
  • packages/core/server/services/db/user.ts (1 hunks)
  • packages/core/server/services/db/work.ts (1 hunks)
  • packages/core/shared/services/checkout.ts (1 hunks)
  • packages/core/types/index.d.ts (7 hunks)
💤 Files with no reviewable changes (1)
  • packages/core/server/api/category/slug/[slug].get.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/core/server/services/db/work.ts
  • packages/core/server/api/channel/payment-method/index.post.ts
  • apps/web-app/app/pages/checkout/index.vue
  • apps/web-app/stores/checkout.ts
  • packages/core/server/services/db/user.ts
  • packages/core/types/index.d.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (90)
apps/web-app/app/components/CommandCenter/CheckoutLine.vue (5)

6-6: Template now uses computed property for product name.

The template now accesses the product name directly from the product computed property instead of through the nested path. This approach is cleaner and follows better separation of concerns.


10-10: Template now references productVariant computed property.

Accessing the variant name through the dedicated computed property improves readability and maintainability.


13-13: Updated weight display to use computed property.

The template now correctly uses the productVariant computed property to access weight information, providing a more consistent data access pattern throughout the component.


41-41: Simplified totalAmount calculation.

Using line.value.totalPrice directly is cleaner than calculating it manually from gross price and quantity. This change ensures consistency with backend calculations.


13-13: Missing function reference.

The template uses getWeightLocalizedUnit() but this function isn't defined in the component.

Please ensure that this function is imported or defined elsewhere in the component. If it's a global utility, make sure it's properly registered.

packages/core/shared/services/checkout.ts (1)

20-20:

✅ Verification successful

Good addition of type definition for better type safety.

The new CheckoutDraft export type enhances type safety by providing a concrete type derived from the schema definition. This allows for more consistent usage of checkout data throughout the application and better IDE support.


🏁 Script executed:

#!/bin/bash
# Search for places where the new CheckoutDraft type is used
echo "Checking usages of the new CheckoutDraft type..."
rg "CheckoutDraft" --glob "*.{ts,tsx,vue,js,jsx}"

# Check for potential places where the type should be updated
echo "Checking for potential places where Partial<Checkout> might need updating..."
rg "Partial<Checkout>" --glob "*.{ts,tsx,vue,js,jsx}"

Length of output: 1427


CheckoutDraft type integration verified and approved

The new CheckoutDraft type is successfully integrated across the codebase and enhances type safety as expected. Our search confirms its usage in the web-app pages, stores, and database repositories, ensuring consistent and improved IDE support.

  • Usage verified in:
    • apps/web-app/app/pages/checkout/index.vue
    • apps/web-app/stores/checkout.ts
    • packages/database/src/types.ts and related repository files
  • Additional note:
    • There's one instance of Partial<Checkout> in packages/core/server/services/db/checkout.ts. Please double-check that its usage is intentional and doesn’t conflict with the adoption of CheckoutDraft elsewhere.

Overall, the changes are solid and the type addition is a clear win for type safety.

packages/core/server/api/auth/sign-in.post.ts (5)

2-2: Architectural shift to service functions

This change represents a transition from a repository pattern to using direct service functions, which aligns with the overall PR objective mentioned in the title "feat!: db changed".


16-16: Service function replaces repository call

The change from repository.userCredential.findByLogin to a dedicated service function follows the new architectural pattern and improves code readability.


26-26: Service function replaces user repository call

The change to using the getUser service function is consistent with the new architectural approach and maintains the same functionality.


36-36: Simplified permissions assignment

The direct assignment of user permissions to the session object is cleaner than the previous approach which may have involved mapping over the permissions array.


2-36:

❓ Verification inconclusive

Verify consistent implementation across dependent modules

The architectural change from repositories to services is significant and should be implemented consistently across related modules.


🏁 Script executed:

#!/bin/bash
# Check for any remaining repository.user or repository.userCredential references
# which might indicate inconsistent architectural patterns

echo "Checking for remaining repository.user references:"
rg "repository\.user\." --type ts

echo "Checking for remaining repository.userCredential references:"
rg "repository\.userCredential\." --type ts

Length of output: 323


Ensure consistent service usage across modules

The recent search for repository.user and repository.userCredential references in TypeScript files returned no matches, indicating that the migration from repositories to services appears to have been applied consistently in the parts of the codebase we checked. However, given the absence of output from the grep-based search and the possibility of variations in reference patterns, please perform a manual review of all dependent modules to ensure that no legacy repository calls remain.

  • Verify that all modules previously using repository calls (e.g., for user or user credential access) now correctly use the corresponding service functions.
  • Ensure that no alternative patterns or indirect references to repository usage exist.
packages/core/server/api/checkout/id/[id].get.ts (1)

1-1: Repository pattern replaced with service function call.

The code has been updated to use a dedicated service function getCheckout instead of directly accessing the repository. This change aligns with the broader shift to a service-oriented architecture mentioned in the PR description.

Also applies to: 13-13

packages/core/server/api/menu/[id]/activity.post.ts (1)

1-1: Repository calls replaced with service functions.

The code has been updated to use dedicated service functions (getMenu and setMenuAsActive) instead of directly accessing the repository. This change is consistent with the database changes mentioned in the PR title.

Also applies to: 13-13, 21-21

packages/core/server/services/db/receiver.ts (1)

1-18: New service function implements efficient receiver retrieval.

The getCheckoutReceivers function effectively retrieves and filters checkout receivers. Good approach to skip invalid receivers with the continue statement rather than including null values.

packages/core/server/services/db/index.ts (1)

1-9: Well-structured Keys interface definition.

The interface clearly defines all the necessary key categories that will be used throughout the application.

packages/core/server/api/channel/index.patch.ts (1)

1-1: Architecture shift from repository pattern to service functions.

The import has been updated to use a dedicated service function instead of the repository. This is part of a larger architectural change across the codebase to use service functions instead of direct repository access.

packages/core/server/api/checkout/index.get.ts (2)

1-1: Architecture shift from repository pattern to service functions.

The import has been updated to use a dedicated service function instead of direct repository access. This is consistent with the architectural changes being made across the codebase.


13-13: Simplified checkout retrieval.

The checkout retrieval logic has been simplified by directly using the getCheckout service function. The function no longer needs to validate channelId as it's not using the channel repository.

packages/core/server/api/checkout/list/index.get.ts (4)

1-1: Architecture shift from repository pattern to service functions.

The import has been updated to use a dedicated service function instead of direct repository access. This aligns with the broader architectural changes in the codebase.


5-6: Simplified checkout list retrieval with proper error handling.

The checkout retrieval has been simplified by directly calling the service function. The error handling has been updated to check if checkouts is falsy rather than checking for channelId.


8-10: Status code and message have been updated.

The error status code is now explicitly set to 404 and the message has been updated to "No checkouts". This provides more accurate error information to the client.


13-13: Direct return of service function result.

The function now directly returns the result from the service function rather than making another repository call. This simplifies the code and reduces potential for inconsistencies.

packages/core/server/api/category/[id]/index.patch.ts (3)

1-2: Architecture shift from repository pattern to service functions.

The imports have been updated to use dedicated service functions for channel and menu category operations. This is consistent with the architectural changes throughout the codebase.


20-20: Service function now handles menu category patching.

The code now uses patchMenuCategory service function instead of directly accessing the repository. The function also captures the returned category for inclusion in the response.


22-22: Channel update now uses service function.

The code now uses setChannelAsUpdated service function instead of directly accessing the repository to mark the channel as updated.

packages/core/server/api/health/index.get.ts (2)

1-1: Import change aligns with architectural shift from repositories to services.

The change from importing the repository directly to using a local service function aligns with the broader architectural changes indicated in the PR title "feat!: db changed".


12-13: Health check implementation changed to use key-based validation.

The implementation now checks for the existence of keys rather than using a repository health check method. This appears to be more specific but ensure that getKeys() properly handles all possible database failure scenarios.

Does the getKeys() function handle connection failures appropriately? Make sure it returns null or a falsy value for allKeys when the database is unavailable to ensure this health check properly detects all failure modes.

packages/core/server/api/channel/working-day/activity.post.ts (4)

1-2: Import statement updates align with new service architecture.

The imports have been updated to use service-based functions from the local codebase rather than direct repository access, which is consistent with the database architecture changes in this PR.


12-13: Working day retrieval now uses service function.

The implementation now fetches all working days and then filters them in-memory, rather than directly querying for a specific working day by ID.

Consider whether fetching all working days is efficient here. If there are many working days, a direct query for the specific day might be more performant. Does getWorkingDays() have filtering capabilities that could be used?


20-22: Working day activity toggle logic might have an edge case.

The code toggles the activity state of a working day based on its current state, but there's a potential issue if the day is not found.

If day is undefined (not found in workingDays), then !day?.isActive will be true, which might not be the intended behavior. Consider adding an explicit check to handle the case when the day is not found.

- const day = workingDays.find((workingDay) => workingDay.day === data.day)
- await changeWorkingDayActivity(data.day, !day?.isActive)
+ const day = workingDays.find((workingDay) => workingDay.day === data.day)
+ if (!day) {
+   throw createError({
+     statusCode: 404,
+     statusMessage: 'Specific working day not found',
+   })
+ }
+ await changeWorkingDayActivity(data.day, !day.isActive)

23-23: Channel update notification added.

Good addition of setChannelAsUpdated to notify that the channel has been modified, which is important for tracking changes and triggering any necessary updates.

packages/core/server/api/menu/[id]/index.patch.ts (3)

1-2: Import statements aligned with service architecture.

The imports have been updated to use service-based functions rather than direct repository access, which is consistent with the architectural changes in this PR.


7-7: Runtime configuration retrieval added.

Added retrieval of channelId from runtime configuration for use in the channel update notification.


19-21: Menu patching now uses service function with channel update.

The implementation has been updated to use the patchMenu service function instead of direct repository access, and now includes notifying that the channel has been updated.

Does the patchMenu function handle validation and error cases in the same way as the previous repository implementation? Ensure consistency in error handling to avoid breaking changes in behavior.

packages/core/server/api/menu/index.post.ts (3)

1-3: Import statements updated for service architecture.

The imports have been modified to use the ID generation utility and service-based functions rather than direct repository access.


14-20: Menu creation parameters changed.

The implementation now sets default values for isActive and categories, and no longer passes channelId directly.

Make sure that the createMenu function doesn't require channelId anymore. If the menu is supposed to be associated with a channel, verify that this relationship is established correctly through other means or that it's intentionally removed.


22-23: Channel update notification added.

Good addition of setChannelAsUpdated to notify that the channel has been modified, which is important for tracking changes and triggering any necessary updates.

packages/core/server/api/channel/receiving-method/index.post.ts (4)

1-1: Clean service-oriented import.

The code now imports specific service functions rather than a repository object, following a service-oriented approach. This is a good architectural change that promotes better separation of concerns.


11-11: Improved data access with service function.

Replacing repository access with a dedicated service function improves code maintainability and follows the service-oriented architecture pattern.


14-16: Consistent service function usage for updates.

Replacing the repository update with the patchChannel service function maintains consistent data access patterns throughout the application.


20-22: Consistent service function usage for updates.

Replacing the repository update with the patchChannel service function maintains consistent data access patterns throughout the application.

packages/core/server/api/category/index.post.ts (3)

1-3: Improved imports with proper dependency management.

The code now uses a standard library for ID creation and imports specific service functions for database operations. This is a good practice that follows the principle of using specialized modules for specific tasks.


14-20: Improved category creation with pre-initialized properties.

The code now initializes the products array during category creation, which prevents potential null/undefined issues when accessing the property later. This is a good defensive programming practice.


22-22: Consistent service function usage for channel updates.

Using a dedicated service function for updating the channel status improves code consistency and maintainability.

packages/core/server/api/channel/working-day/index.patch.ts (3)

1-2: Clean service-oriented imports.

The code now imports specific service functions rather than a repository object, following a service-oriented approach.


12-14: Simplified and improved working day update loop.

The loop has been simplified to iterate directly over the data array and use a service function, improving readability and maintainability. The complex parsing logic has been moved to the service layer, which is a better separation of concerns.


16-17: Efficient channel update.

Moving the channel update outside the loop ensures it only happens once after all working days are updated, improving performance.

packages/core/server/api/checkout/line/[id].post.ts (5)

1-1: Clean service-oriented import.

The code now imports specific service functions rather than a repository object, following a service-oriented approach.


26-26: Consistent service function usage for checkout retrieval.

Replacing repository access with a dedicated service function improves code maintainability and follows the service-oriented architecture pattern.


51-51: Explicit and improved checkout line update.

The code now explicitly sets the new quantity value when incrementing, which is more readable and maintainable than using a specialized increment method.


53-53: Explicit and improved checkout line update.

The code now explicitly sets the new quantity value when decrementing, which is more readable and maintainable than using a specialized decrement method.


56-56: Consistent service function usage for checkout recalculation.

Using a dedicated service function for recalculating the checkout improves code consistency and maintainability.

packages/core/server/api/channel/master.put.ts (5)

1-4: Dependencies updated to use service functions instead of direct repository access.

The file now imports service functions from dedicated modules, which is a good practice as it encapsulates database interactions and promotes better separation of concerns.


23-33: Enhanced user creation with explicit properties and a unique ID.

The user creation now uses a service function with more explicit properties and generates a unique ID using createId(). This is a good practice as it ensures all required fields are properly set.


43-48: Improved user credentials creation with a unique ID.

The user credentials creation now uses a service function and generates a unique ID. This approach is better than relying on auto-generated IDs from the database as it provides more control and predictability.


50-50: Channel update notification added.

A new function call setChannelAsUpdated(channelId) has been added to ensure the channel state is refreshed after user creation, which is important for maintaining data consistency.


12-12:

❓ Verification inconclusive

Verify channel-specific master user retrieval.

The getMaster() function no longer takes a channelId parameter, which differs from the previous repository call that was channel-specific.


🏁 Script executed:

#!/bin/bash
# Check implementation of getMaster function to ensure it properly handles channel context
rg -A 3 "export (async )?function getMaster" --glob "packages/core/server/**/*.ts"

Length of output: 450


Attention: Confirm Intended Master User Retrieval Behavior

The implementation in packages/core/server/services/db/user.ts shows that getMaster() now returns a global master user without accepting a channel-specific parameter. In the current packages/core/server/api/channel/master.put.ts file, this global retrieval (via await getMaster()) is being used. Please verify that this change in behavior—from a previously channel-specific call to a global call—is intentional for the channel API. If a channel-specific master user is still required, consider updating the implementation accordingly.

packages/core/server/api/channel/index.put.ts (4)

1-2: Dependencies updated to use service functions.

The imports now use dedicated service functions from specific modules, which improves code organization and maintainability.


10-10: Channel retrieval updated to use service function.

The function now uses getChannel(channelId) instead of directly accessing the repository, which is a good practice for encapsulation.


21-35: Enhanced channel creation with explicit properties.

The channel creation now includes more explicit fields with default values, making the intent clearer and ensuring all required fields are set.


38-87: Improved working days creation with a more explicit approach.

The previous implementation likely used a loop with a generic day array, whereas this version explicitly defines each day with its properties. This is more maintainable and less error-prone as it clearly shows the configuration for each day.

packages/core/server/api/channel/time-slots.get.ts (6)

2-3: Dependencies updated to use service functions.

The imports now use dedicated service functions, which aligns with the architectural changes across the codebase.


9-9: Channel retrieval updated to use service function.

Consistent with other files, channel retrieval now uses the service function getChannel.


36-39: Similar time parsing changes for closing time.

The same string parsing approach is used for closing time. This change maintains consistency with the opening time parsing.


42-42: Condition check updated for midnight closing time.

The check for midnight closing time now uses the parsed hour value instead of directly accessing a property.


20-21:

❓ Verification inconclusive

Working day retrieval approach changed.

Instead of fetching a specific working day by day and channelId, the code now fetches all working days and finds the relevant one by index. This approach may have performance implications if there are many working days.


🏁 Script executed:

#!/bin/bash
# Check implementation of getWorkingDays to understand if it's filtering by channelId
rg -A 5 "export (async )?function getWorkingDays" --glob "packages/core/server/**/*.ts"

Length of output: 613


Actionable: Review Working Day Retrieval Performance and Channel-Specific Filtering

The updated code now retrieves all working days via getWorkingDays (located in packages/core/server/services/db/work.ts) and then selects the needed day by matching its index, rather than performing a channel-specific fetch. Since getWorkingDays simply fetches the complete working time data from storage without filtering by channelId, please verify that the working time dataset remains limited (e.g., typically seven days). If the dataset could grow large or if channel-specific filtering is important for performance, consider reintroducing direct filtering to maintain efficiency.

  • Location: packages/core/server/api/channel/time-slots.get.ts lines 20-21
  • Function Involved: getWorkingDays (see implementation in packages/core/server/services/db/work.ts)

30-34:

❓ Verification inconclusive

Time parsing has changed to use string splitting.

The time parsing now extracts hours and minutes from strings in the format "HH:MM" instead of using separate fields. Ensure that the time values are consistently formatted throughout the application to avoid parsing errors.


🏁 Script executed:

#!/bin/bash
# Check for any inconsistent time formats in the codebase
rg "open\s*=\s*['\"]" --glob "packages/core/server/**/*.ts" | grep -v "[0-9][0-9]:[0-9][0-9]"
rg "close\s*=\s*['\"]" --glob "packages/core/server/**/*.ts" | grep -v "[0-9][0-9]:[0-9][0-9]"

Length of output: 196


Time Parsing Update Verified – Please Manually Confirm Consistency Across the Codebase

The changes in packages/core/server/api/channel/time-slots.get.ts (lines 30–34) correctly extract hours and minutes via string splitting using the "HH:MM" format. A regex check for time values using the command:

#!/bin/bash
rg "open\s*=\s*['\"]" --glob "packages/core/server/**/*.ts" | grep -v "[0-9][0-9]:[0-9][0-9]"
rg "close\s*=\s*['\"]" --glob "packages/core/server/**/*.ts" | grep -v "[0-9][0-9]:[0-9][0-9]"

did not produce any output, which suggests that no immediate inconsistencies were detected. However, since the automated check returned no results (possibly due to pattern limitations), please perform a manual verification to ensure that all time string assignments across the application strictly follow the "HH:MM" format to avoid any parsing errors.

packages/core/server/services/db/menu.ts (7)

1-2: Importing utility function for key retrieval.

The file imports a helper function getKeys from the parent directory, which is good for reusing common functionality.


3-6: Menu retrieval function implementation.

The getMenu function provides a straightforward way to retrieve a menu by ID, with proper typing and null handling.


51-58: Menu creation function implementation.

The createMenu function properly handles the creation of a menu with timestamps. It returns the created menu for immediate use, which is a good practice.


60-75: Menu update function implementation.

The patchMenu function includes proper error handling by checking if the menu exists before updating it. It also preserves all existing properties while updating only the specified ones.


77-89: Menu activation function implementation.

The setMenuAsActive function ensures only one menu is active at a time by deactivating all other menus first. This maintains data consistency and prevents having multiple active menus.


106-113: Menu category creation function implementation.

The createMenuCategory function properly handles the creation of a menu category with timestamps. It returns the created category, which allows for immediate use.


115-130: Menu category update function implementation.

The patchMenuCategory function includes proper error handling by checking if the category exists before updating it. It also preserves all existing properties while updating only the specified ones.

packages/core/server/api/checkout/add/index.post.ts (3)

1-3: Adopted service-based approach looks good.
The transition from direct repository calls to named service imports promotes modularity and maintainability.


18-18: Add error handling for missing or invalid channel data.
While channel activity checks exist, if getChannel(channelId) fails (e.g., returns null due to an invalid ID) before usage, it might cause an unexpected error.


81-81: Confirm concurrency handling.
Calls to getCheckout can potentially be stale if multiple services or requests update the same checkout simultaneously. Verify that upstream usage either locks or re-checks relevant data to avoid collisions.

packages/core/server/api/checkout/index.patch.ts (8)

2-5: Approach to centralizing business logic is solid.
Replacing direct DB calls with service-layer imports increases flexibility and consistency.


26-26: Handle invalid channel scenarios.
Same as in the add endpoint, consider verifying that channel is not null or undefined after fetching, to avoid potential runtime errors.


28-28: Confirm recalc necessity.
Invoking recalculateCheckout before finalizing changes is logical, but confirm with business rules if partial updates require an immediate recalculation.


54-54: Audit finalization timing.
Upon calling setCheckoutAsFinished, confirm that the external dependencies (like payment or inventory) have already cleared. Otherwise, you risk data inconsistencies if called prematurely.


79-79: Validate checkout data once again.
Fetching the checkout after finalization is valuable; ensure you handle an already-finished or invalid checkout gracefully.


84-84: Check channel references in final stage.
If the channel became inactive or changed mid-checkout, confirm if the system needs to handle that scenario carefully.


91-92: Guard for absent payment methods.
If the payment method ID is invalid, paymentMethodName could be undefined. Provide a default or handle the missing scenario to avoid potential runtime errors.


94-95: Similar retrieval approach for warehouse.
Like payment methods, confirm that a missing warehouse does not cause unexpected behavior or crashes down the line.

packages/core/server/services/db/checkout.ts (5)

7-9: Simple get function is straightforward.
Returning null for a nonexistent checkout is a clean approach. Just ensure trying to update a null checkout is handled gracefully downstream.


39-46: Enhance error handling upon creation.
If useStorage('db').setItem fails (due to network or other issues), consider capturing or surfacing these errors more explicitly.


63-94: Comprehensive recalculation flow.
Recomputing the line totals is accurate. However, removing lines with quantity <= 0 within the same loop modifies the iteration target. This is valid if you rely on immediate side effects, but watch for potential iteration pitfalls (e.g., using for ... of ... while mutating).


102-109: Simplicity is good.
Fetching a line from the lines array is straightforward. Just confirm that the line references remain correct if lines are manipulated concurrently by other processes.


154-163: Cleanup logic is appropriate.
Removing a line by filtering is valid. Confirm if there's a need to ensure reference integrity for related entities, e.g., discount codes or stock-limited items, that might link to that line.

Comment on lines +42 to +43
const productVariant = channel.getProductVariant(line.value?.productVariantId ?? '')
const product = channel.getProduct(productVariant.value?.productId ?? '')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing computed property reactivity.

These properties are defined as constants but should be reactive computed properties to ensure they update when dependencies change.

Apply this change to ensure proper reactivity:

-const productVariant = channel.getProductVariant(line.value?.productVariantId ?? '')
-const product = channel.getProduct(productVariant.value?.productId ?? '')
+const productVariant = computed(() => channel.getProductVariant(line.value?.productVariantId ?? ''))
+const product = computed(() => channel.getProduct(productVariant.value?.productId ?? ''))
📝 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 productVariant = channel.getProductVariant(line.value?.productVariantId ?? '')
const product = channel.getProduct(productVariant.value?.productId ?? '')
const productVariant = computed(() => channel.getProductVariant(line.value?.productVariantId ?? ''))
const product = computed(() => channel.getProduct(productVariant.value?.productId ?? ''))

@@ -13,6 +13,8 @@ export const checkoutUpdateSchema = z.object({
addressNote: z.string().max(250).optional(),
paymentMethodId: z.string().max(50).optional(),
time: z.number().optional(),
change: z.string().max(10).optional(),
change: z.number().optional(),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

❓ Verification inconclusive

Breaking change detected: field type changed from string to number.

The change field has been modified from z.string().max(10) to z.number(). This is a breaking change that will affect data validation and processing throughout the application. Ensure that:

  1. All places where this field is used have been updated to handle a number instead of a string
  2. Database schemas or APIs consuming this data are updated accordingly
  3. Frontend components are updated to input numbers rather than strings

🏁 Script executed:

#!/bin/bash
# Search for usages of the 'change' field in the codebase
echo "Searching for usages of the 'change' field in checkout..."
rg -A 3 -B 3 "change.*Checkout" --glob "*.{ts,tsx,vue,js,jsx}"

Length of output: 1118


Action Required: Validate 'change' Field Type Transition

The change field in packages/core/shared/services/checkout.ts now uses z.number().optional() instead of the previous z.string().max(10). This change remains breaking and impacts data validation and processing. Our search shows:

  • Frontend Usage: In apps/web-app/app/pages/checkout/index.vue, the field is accessed as remainingCheckout.value.change. Verify that this component now correctly handles a number.
  • Store Update: In apps/web-app/stores/checkout.ts, an async function named change exists, suggesting additional logic may need adjustments to work with a numeric type.

Please ensure that all consuming components, database schemas, and API endpoints have been reviewed and updated to accommodate the new numeric type for change.


const body = await readBody(event)
const data = channelUpdateSchema.parse(body)

await repository.channel.patch(channelId, data)
await patchChannel(channelId, data as Partial<Channel>)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Validation for channelId has been removed.

The previous implementation likely checked if channelId exists before trying to patch the channel. Now the code assumes channelId will always be present in the configuration. Ensure that patchChannel service handles the case when channelId is undefined or that this validation happens elsewhere.


🏁 Script executed:

#!/bin/bash
# Check if patchChannel handles validation for channelId
cd packages/core/server/services/db
grep -r "function patchChannel" --include="*.ts" .
# If found, check the implementation to see if it validates channelId

Length of output: 201


Action Required: Validate channelId or Handle Undefined Scenario

The updated code now directly calls:

await patchChannel(channelId, data as Partial<Channel>)

which assumes that a valid channelId is always provided. However, the implementation of patchChannel in packages/core/server/services/db/channel.ts has the signature:

export async function patchChannel(id: string, data: Partial<Channel>): Promise<Channel | null> {

There’s no evidence within patchChannel that it explicitly validates whether id is defined. Please ensure that one of the following is true:

  • The validation for channelId (i.e., ensuring it is defined and valid) is performed upstream before this call.
  • Or, the patchChannel service is updated to gracefully handle cases where channelId might be undefined.

This check is important to avoid potential runtime errors if an undefined value is inadvertently passed.

Comment on lines +111 to +129
export async function createCheckoutLine(data: Omit<CheckoutLine, 'createdAt' | 'updatedAt'>): Promise<CheckoutLine | null> {
const checkout = await getCheckout(data.checkoutId)
if (!checkout) {
return null
}

await patchCheckout(data.checkoutId, {
lines: [
...checkout.lines,
{
...data,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
],
})

return getCheckoutLine(data.checkoutId, data.id)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Creation logic is consistent with patch usage.
Creating a new line then patching the checkout is a neat approach. For high concurrency, consider atomic operations or version checks to prevent overwriting lines with stale data.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/core/nuxt.config.ts (1)

16-16: Consider adding a sensible default or error handling for Redis connection

The new redisUrl configuration has an empty string as the default value. If this configuration is required for the application to function correctly after this database change, this could lead to runtime errors when not explicitly set.

Consider one of these approaches:

  1. Provide a sensible default (e.g., 'redis://localhost:6379')
  2. Implement proper error handling to detect missing configuration
  3. Make Redis optional with a clear fallback mechanism
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1896e97 and 404a60e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • apps/web-app/package.json (1 hunks)
  • docker/.env.example (0 hunks)
  • docker/docker-compose.yml (0 hunks)
  • eslint.config.mjs (1 hunks)
  • package.json (0 hunks)
  • packages/core/nuxt.config.ts (1 hunks)
  • packages/core/package.json (1 hunks)
  • packages/core/server/api/auth/session.post.ts (1 hunks)
  • packages/core/server/preset.ts (0 hunks)
  • packages/core/server/tasks/db/migrate.ts (0 hunks)
  • packages/core/shared/utils/date.ts (0 hunks)
  • packages/database/.env.example (0 hunks)
  • packages/database/build.config.ts (0 hunks)
  • packages/database/drizzle.config.ts (0 hunks)
  • packages/database/migrations/0000_aspiring_sprite.sql (0 hunks)
  • packages/database/migrations/meta/0000_snapshot.json (0 hunks)
  • packages/database/migrations/meta/_journal.json (0 hunks)
  • packages/database/package.json (0 hunks)
  • packages/database/src/connection.ts (0 hunks)
  • packages/database/src/database.ts (0 hunks)
  • packages/database/src/index.ts (0 hunks)
  • packages/database/src/repository/channel.ts (0 hunks)
  • packages/database/src/repository/checkout.ts (0 hunks)
  • packages/database/src/repository/checkoutLine.ts (0 hunks)
  • packages/database/src/repository/checkoutReceiver.ts (0 hunks)
  • packages/database/src/repository/index.ts (0 hunks)
  • packages/database/src/repository/media.ts (0 hunks)
  • packages/database/src/repository/menu.ts (0 hunks)
  • packages/database/src/repository/menuCategory.ts (0 hunks)
  • packages/database/src/repository/paymentMethod.ts (0 hunks)
  • packages/database/src/repository/product.ts (0 hunks)
  • packages/database/src/repository/productVariant.ts (0 hunks)
  • packages/database/src/repository/user.ts (0 hunks)
  • packages/database/src/repository/userCredential.ts (0 hunks)
  • packages/database/src/repository/userPermission.ts (0 hunks)
  • packages/database/src/repository/warehouse.ts (0 hunks)
  • packages/database/src/repository/workingDay.ts (0 hunks)
  • packages/database/src/tables.ts (0 hunks)
  • packages/database/src/types.ts (0 hunks)
  • packages/database/tsconfig.json (0 hunks)
💤 Files with no reviewable changes (35)
  • packages/database/migrations/meta/_journal.json
  • packages/database/build.config.ts
  • packages/core/server/tasks/db/migrate.ts
  • packages/database/package.json
  • docker/.env.example
  • packages/database/src/repository/userPermission.ts
  • package.json
  • packages/database/src/repository/checkoutReceiver.ts
  • packages/database/src/repository/menuCategory.ts
  • packages/database/src/repository/warehouse.ts
  • packages/database/.env.example
  • packages/database/src/database.ts
  • packages/database/drizzle.config.ts
  • packages/database/migrations/meta/0000_snapshot.json
  • packages/database/src/repository/paymentMethod.ts
  • packages/database/src/repository/media.ts
  • packages/database/src/connection.ts
  • packages/database/src/repository/product.ts
  • packages/database/src/repository/checkout.ts
  • packages/core/shared/utils/date.ts
  • packages/database/tsconfig.json
  • packages/database/src/repository/channel.ts
  • packages/database/src/repository/userCredential.ts
  • packages/database/src/repository/user.ts
  • packages/database/src/index.ts
  • packages/database/src/repository/workingDay.ts
  • packages/database/src/repository/checkoutLine.ts
  • docker/docker-compose.yml
  • packages/database/src/tables.ts
  • packages/database/src/repository/menu.ts
  • packages/database/src/types.ts
  • packages/core/server/preset.ts
  • packages/database/migrations/0000_aspiring_sprite.sql
  • packages/database/src/repository/index.ts
  • packages/database/src/repository/productVariant.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/package.json
🔇 Additional comments (6)
apps/web-app/package.json (1)

20-20: Ensure Redis client implementation has proper error handling.

The addition of ioredis as a dependency is consistent with the broader database changes indicated in the PR title. Since Redis will now be part of your infrastructure, make sure to implement proper error handling in your Redis client code.

#!/bin/bash
# Search for Redis client implementation and check for error handling
echo "Looking for Redis client implementations and their error handling..."
grep -r --include="*.{ts,js,vue}" "new Redis\|createClient" ./apps ./packages 2>/dev/null | grep -v "node_modules"

echo -e "\nChecking for error handling in Redis-related files..."
# Find files that mention Redis and check if they have error handling
grep -r --include="*.{ts,js,vue}" -l "Redis\|redis" ./apps ./packages 2>/dev/null | 
  grep -v "node_modules" | 
  xargs grep -l "try\|catch\|error\|.on('error'" 2>/dev/null || 
  echo "No error handling found in Redis-related files"
packages/core/server/api/auth/session.post.ts (2)

3-23: Function logic remains sound.

The event handler logic is robust with proper error handling and a clear flow. The function correctly uses the new createId() from the updated import to generate user IDs.


1-1:

✅ Verification successful

Import source change is appropriate.

Good change replacing the database import with a direct dependency on @paralleldrive/cuid2. This aligns with the broader database architecture changes indicated in the PR and removes the dependency on the internal database package.


🏁 Script executed:

#!/bin/bash
# Verify that @paralleldrive/cuid2 is a dependency in the project
echo "Checking for @paralleldrive/cuid2 in package.json files:"
grep -r --include="package.json" "@paralleldrive/cuid2" ./packages ./apps 2>/dev/null || echo "Warning: @paralleldrive/cuid2 dependency not found in any package.json"

echo -e "\nChecking other createId imports to ensure consistency:"
grep -r --include="*.ts" "import.*createId" ./packages ./apps 2>/dev/null | grep -v "node_modules" | grep -v "@paralleldrive/cuid2"

Length of output: 506


Import Update Verified: @paralleldrive/cuid2 Dependency Is Consistent

The change to import createId directly from @paralleldrive/cuid2 has been verified. The dependency is declared in the project's package.json (e.g., in ./packages/core/package.json), and no additional inconsistent createId imports were found in the rest of the codebase. The adjustments align with the broader architectural updates regarding database changes.

packages/core/nuxt.config.ts (2)

1-36: Documentation Update Required: Add Redis Configuration Guidance

The integration of redisUrl into the runtime configuration has been approved and aligns with the PR's database focus. However, the previous verification indicated that the new Redis configuration option is not documented.


1-36:

❓ Verification inconclusive

Verify all dependent components are updated to work without channelId

According to the summary, channelId: 'burger' has been removed from the runtime config. This is a breaking change that could affect components that rely on this value.


🏁 Script executed:

#!/bin/bash
# Search for usage of channelId in components that might be affected
echo "Searching for references to channelId in the codebase..."
rg "channelId|channel[^a-zA-Z]" --type vue --type ts

Length of output: 205


Manual Verification Required: Confirm Removal of channelId Usage

The initial search did not return expected results due to an unrecognized file type for Vue files. Please re-run the search with updated parameters to include .vue files, for example:

rg --type-add "vue:*.vue" --type vue "channelId"

If the refined search confirms that there are no remaining references to channelId in your TypeScript or Vue files, then we can be confident that all dependent components have been updated accordingly following the removal of channelId: 'burger' from the runtime config.

eslint.config.mjs (1)

24-24:

❓ Verification inconclusive

Database migration files will now be linted

The 'packages/database/migrations/**' path has been removed from the ESLint ignore list. This means database migration files will now be subject to linting rules, which could enforce better code quality and consistency in migrations.

To understand the potential impact, check if existing migration files comply with current linting rules:


🏁 Script executed:

#!/bin/bash
# Check if existing migration files have linting issues
if [ -d "packages/database/migrations" ]; then
  echo "Checking migration files for linting issues..."
  npx eslint packages/database/migrations --ext .js,.ts,.mjs
else
  echo "Migration directory not found at expected path"
  # Find where migration files might be located
  echo "Searching for migration files in the repository..."
  find . -path "*/migrations/*" -type f -name "*.js" -o -name "*.ts" -o -name "*.mjs" | grep -v "node_modules"
fi

Length of output: 4595


Attention: Database Migrations Will Now Be Linted, but None Were Found in the Expected Location

The ESLint configuration update removes the exclusion of 'packages/database/migrations/**', so any migration files added to that path in the future will be subject to linting—improving code quality and consistency for migrations.

Verification Details:

  • A shell script check confirmed that the directory packages/database/migrations does not exist in the repository.
  • No migration files were located under the expected path. (We did find similar files elsewhere, but none matching this migration directory.)

Action Items:

  • Confirm whether database migration files are maintained in a different location or if they are expected to be added under packages/database/migrations.
  • If migration files are used in a different folder, update the ESLint ignore configuration accordingly to ensure the correct files are linted.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/core/server/services/db/checkout.ts (3)

35-39: Consider retrieving checkouts in parallel using Promise.all.

Currently, the code initiates multiple asynchronous fetches and stores promises in a Map before awaiting them in a loop. For improved clarity and performance, consider fetching them in parallel using Promise.all:

-const storage = new Map<string, unknown>(keys.map((key) => [key, useStorage('db').getItem(key)]))
-const checkouts: Checkout[] = []
-for (const key of keys) {
-  const checkout = await storage.get(key) as Checkout
-  if (!checkout) continue
-  checkouts.push(checkout)
-}
+const storageFetches = keys.map((key) => useStorage('db').getItem<Checkout>(key))
+const checkouts = await Promise.all(storageFetches)
+return checkouts.filter((c): c is Checkout => Boolean(c))

50-57: Optimize by returning the created checkout object directly.

The current approach sets the item in storage, then performs a subsequent getCheckout call. Since the newly created data is already known, you can directly return it without the extra read:

export async function createCheckout(data: Omit<Checkout, 'createdAt' | 'updatedAt'>): Promise<Checkout | null> {
  const now = new Date().toISOString()
  const newCheckout: Checkout = {
    ...data,
    createdAt: now,
    updatedAt: now,
  }

  await useStorage('db').setItem(`checkout:${data.id}`, newCheckout)
- return getCheckout(data.id)
+ return newCheckout
}

134-152: Trigger checkout total price recalculation after adding a checkout line.

When adding a new checkout line, the total price isn't automatically recalculated. Consider calling recalculateCheckout(data.checkoutId) after creating the new line to ensure the stored total price remains accurate and up-to-date.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 404a60e and ea54c69.

📒 Files selected for processing (5)
  • apps/web-app/app/components/CommandCenter/CheckoutCard.vue (1 hunks)
  • apps/web-app/app/components/CommandCenter/WarehouseCard.vue (1 hunks)
  • apps/web-app/app/pages/checkout/index.vue (4 hunks)
  • apps/web-app/app/pages/finish/index.vue (1 hunks)
  • packages/core/server/services/db/checkout.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/web-app/app/components/CommandCenter/CheckoutCard.vue
  • apps/web-app/app/components/CommandCenter/WarehouseCard.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web-app/app/pages/checkout/index.vue
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (7)
packages/core/server/services/db/checkout.ts (1)

74-109: Implement version checks or locking for concurrency consistency.

If multiple users or processes recalculate the same checkout simultaneously, updates can overwrite one another. Adopting version checks or a locking mechanism will prevent inconsistencies when modifying items under high concurrency.

apps/web-app/app/pages/finish/index.vue (6)

6-6: CSS variable adoption for background styling.

The background styling has been updated from explicit color classes to a CSS variable (--ui-bg-muted), which improves theme consistency and maintainability.


12-14: Updated text styling to use CSS variables.

Text color has been updated to use the --ui-text-muted CSS variable, improving theme consistency across the application.


54-57: Consistent styling update for section headings.

The heading for the ordered items section now uses the same text styling as other section headings.


68-71: Consistent styling update for total section heading.

The heading for the order total section now uses the same text styling as other section headings.


80-84: Enhanced button styling with gradient variant.

The home button has been updated to include a gradient variant, which improves visual appeal while maintaining functionality.


11-52:

❓ Verification inconclusive

Simplified component structure by removing ClientOnly wrapper.

The ClientOnly wrapper has been removed, and content is now directly rendered in a standard div. This simplifies the markup, but ensure that there are no hydration mismatches if this content depends on client-side only data.


🏁 Script executed:

#!/bin/bash
# Check if there are any client-side only libraries or browser APIs used in this component
rg -i "window\.|document\.|navigator\." apps/web-app/app/pages/finish/index.vue
# Look for other client-specific code that might require the ClientOnly wrapper
rg -i "process\.client" apps/web-app/app/pages/finish/index.vue

Length of output: 147


Action: Verify Hydration Consistency After Removing ClientOnly Wrapper

The ClientOnly wrapper has been removed to simplify the markup. Our automated checks did not find direct usages of browser-specific globals (e.g. window, document, navigator) or explicit client-only conditions (e.g. process.client) in this component. However, be aware that dynamic content—such as the localized date formatting via new Date(...).toLocaleString(...)—might behave differently between server and client renderings. Please manually verify that these differences do not lead to hydration mismatches in your testing environments.

@hmbanan666 hmbanan666 merged commit c8f369d into main Feb 28, 2025
5 checks passed
@hmbanan666 hmbanan666 deleted the db-rework branch February 28, 2025 15:03
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