feat: add cart, cartItem, etc. db tables and initial home page form #92

Merged
davide merged 5 commits from feat/order-management into main 2026-07-15 12:15:07 +00:00
Owner
No description provided.
feat: add db tables
Some checks failed
check-commitizen.yaml / Check the PR title (pull_request) Successful in 2s
check-formatter.yaml / Checks with formatters (pull_request) Failing after 13s
check-syntax.yaml / Checks with static tools (pull_request) Has been cancelled
check-linter.yaml / Checks with linters (pull_request) Has been cancelled
check-yamllint.yaml / Lint yaml files (pull_request) Has been cancelled
check-build.yaml / Check that project builds (pull_request) Has been cancelled
forgejo-agent / LLM Bot response generation (pull_request) Successful in 2s
fe7ed7cd38
chore: fix lints
Some checks failed
check-formatter.yaml / Checks with formatters (pull_request) Successful in 15s
check-linter.yaml / Checks with linters (pull_request) Successful in 32s
check-build.yaml / Check that project builds (pull_request) Successful in 1m7s
check-yamllint.yaml / Lint yaml files (pull_request) Successful in 2s
check-syntax.yaml / Checks with static tools (pull_request) Failing after 26s
68d3e63a79
chore: fix more lints
All checks were successful
check-formatter.yaml / Checks with formatters (pull_request) Successful in 13s
check-linter.yaml / Checks with linters (pull_request) Successful in 32s
check-build.yaml / Check that project builds (pull_request) Successful in 1m5s
check-yamllint.yaml / Lint yaml files (pull_request) Successful in 2s
check-syntax.yaml / Checks with static tools (pull_request) Successful in 27s
f18c9a605e
davide requested review from llm-bot 2026-07-15 10:03:56 +00:00
llm-bot left a comment

PR Review: feat: add cart, cartItem, etc. db tables and initial home page form

🔴 Critical Issues

1. order table has no primary key

File: src/lib/server/database/tables/order.ts

The order table definition has no id column — it only has cartId, counter, discount, and createdAt. An order should have a primary key to be uniquely identifiable.

export default sqliteTable("order", {
  cartId: text()...   // FK column, not a PK
  counter: integer().notNull(),
  discount: numeric().notNull(),
  createdAt: timestamp()...
  // ❌ No id column!
});

The migration SQL files (0007 and 0008) also lack an id column.

2. cartItemValue.productOptionId FK references product instead of productOption

Both migration 0007 and 0008 have this incorrect FK:

-- Migration 0007 & 0008
FOREIGN KEY (`productOptionId`) REFERENCES `product`(`id`)

This should reference productOption.id, not product.id. The Drizzle snapshot confirms:

cartItemValue.cartItemValue_productOptionId_product_id_fk: cartItemValue.['productOptionId'] -> product.['id']

3. Migration 0007 has incorrect FK references (self-referencing order)

Migration 0007 creates the order table with a self-referencing FK:

FOREIGN KEY (`cartId`) REFERENCES `order`(`id`)

This is a self-reference on a table that has no id column. It should reference cart.id. Similarly, cartItem.cartId references order.id instead of cart.id.

Migration 0008 partially fixes this by recreating the tables, but the initial migration is still incorrect and would fail on a fresh database if cart doesn't exist yet (which it doesn't in migration 0007).

🟡 Medium Issues

4. getSchema() in ProductOptionClient has no default return

File: src/lib/entities/products/option/client.ts

getSchema() {
  switch (this.data.data.type) {
    case "boolean":
      return v.optional(v.boolean(), false);
    case "choice":
      return v.pipe(v.string(), v.picklist(...));
    // ❌ No return for other cases — implicitly returns undefined
  }
}

If a new option type is added in the future without updating this switch, the method silently returns undefined, which could cause runtime errors in the form schema.

5. getPrice() returns inconsistent types

File: src/lib/entities/products/option/client.ts

case "boolean": {
  if (!parsed.success) return 0;   // returns 0
  return parsed.output ? ... : 0;
}
case "choice": {
  if (!parsed.success) return null; // returns null
  return ... ?? null;
}

The method returns null in some branches and 0 in others. This inconsistency could cause issues for callers expecting a consistent return type. Consider always returning number | null and using 0 only where it makes semantic sense.

6. Duplicate list-column CSS class across 5 files

The .list-column utility is duplicated in:

  • src/routes/+page.svelte
  • src/routes/admin/printers/+page.svelte
  • src/routes/admin/printers/[printerId]/+page.svelte
  • src/routes/admin/products/+page.svelte
  • src/routes/admin/products/[categoryId]/+page.svelte
  • src/routes/admin/products/[categoryId]/[productId]/+page.svelte

This should be defined once in src/assets/tailwind.css as a @utility (like bg-default and text-default already are).

7. orders/+page.svelte is an empty stub

File: src/routes/orders/+page.svelte

Contains only requireUser() with no UI. This creates a route that exists but does nothing. Either implement the functionality or remove the file.

8. Product options removed from AddProductForm

The AddProductFormOption.svelte component and the dynamic options-adding functionality were removed from AddProductForm.svelte. This means admins can no longer add options when creating products. If this was intentional, the PR description should explain why, and there should be a follow-up task to restore this functionality.

ℹ️ Notes

9. @reference and @apply CSS warnings

The svelte-check warnings about @reference and @apply being "unknown at rules" are false positives — Tailwind v4 uses these directives and they work correctly at runtime.

10. Biome internal crash

Biome crashed with an internal error (index out of bounds), but this is a Biome bug, not a code issue. It still checked 193 files before crashing.


Summary

Severity Count Description
🔴 Critical 3 Missing PK on order, wrong FK on cartItemValue, self-referencing FK in migration 0007
🟡 Medium 5 Missing return in getSchema(), inconsistent return types in getPrice(), duplicate CSS, empty orders page, removed product options

I recommend addressing the critical issues before merging, particularly the missing primary key on the order table and the incorrect FK references, as these would cause data integrity issues in production.

# PR Review: feat: add cart, cartItem, etc. db tables and initial home page form ## 🔴 Critical Issues ### 1. `order` table has no primary key **File:** `src/lib/server/database/tables/order.ts` The `order` table definition has no `id` column — it only has `cartId`, `counter`, `discount`, and `createdAt`. An order should have a primary key to be uniquely identifiable. ```typescript export default sqliteTable("order", { cartId: text()... // FK column, not a PK counter: integer().notNull(), discount: numeric().notNull(), createdAt: timestamp()... // ❌ No id column! }); ``` The migration SQL files (0007 and 0008) also lack an `id` column. ### 2. `cartItemValue.productOptionId` FK references `product` instead of `productOption` Both migration 0007 and 0008 have this incorrect FK: ```sql -- Migration 0007 & 0008 FOREIGN KEY (`productOptionId`) REFERENCES `product`(`id`) ``` This should reference `productOption.id`, not `product.id`. The Drizzle snapshot confirms: ``` cartItemValue.cartItemValue_productOptionId_product_id_fk: cartItemValue.['productOptionId'] -> product.['id'] ``` ### 3. Migration 0007 has incorrect FK references (self-referencing `order`) Migration 0007 creates the `order` table with a self-referencing FK: ```sql FOREIGN KEY (`cartId`) REFERENCES `order`(`id`) ``` This is a self-reference on a table that has no `id` column. It should reference `cart.id`. Similarly, `cartItem.cartId` references `order.id` instead of `cart.id`. Migration 0008 partially fixes this by recreating the tables, but the initial migration is still incorrect and would fail on a fresh database if `cart` doesn't exist yet (which it doesn't in migration 0007). ## 🟡 Medium Issues ### 4. `getSchema()` in `ProductOptionClient` has no default return **File:** `src/lib/entities/products/option/client.ts` ```typescript getSchema() { switch (this.data.data.type) { case "boolean": return v.optional(v.boolean(), false); case "choice": return v.pipe(v.string(), v.picklist(...)); // ❌ No return for other cases — implicitly returns undefined } } ``` If a new option type is added in the future without updating this switch, the method silently returns `undefined`, which could cause runtime errors in the form schema. ### 5. `getPrice()` returns inconsistent types **File:** `src/lib/entities/products/option/client.ts` ```typescript case "boolean": { if (!parsed.success) return 0; // returns 0 return parsed.output ? ... : 0; } case "choice": { if (!parsed.success) return null; // returns null return ... ?? null; } ``` The method returns `null` in some branches and `0` in others. This inconsistency could cause issues for callers expecting a consistent return type. Consider always returning `number | null` and using `0` only where it makes semantic sense. ### 6. Duplicate `list-column` CSS class across 5 files The `.list-column` utility is duplicated in: - `src/routes/+page.svelte` - `src/routes/admin/printers/+page.svelte` - `src/routes/admin/printers/[printerId]/+page.svelte` - `src/routes/admin/products/+page.svelte` - `src/routes/admin/products/[categoryId]/+page.svelte` - `src/routes/admin/products/[categoryId]/[productId]/+page.svelte` This should be defined once in `src/assets/tailwind.css` as a `@utility` (like `bg-default` and `text-default` already are). ### 7. `orders/+page.svelte` is an empty stub **File:** `src/routes/orders/+page.svelte` Contains only `requireUser()` with no UI. This creates a route that exists but does nothing. Either implement the functionality or remove the file. ### 8. Product options removed from `AddProductForm` The `AddProductFormOption.svelte` component and the dynamic options-adding functionality were removed from `AddProductForm.svelte`. This means admins can no longer add options when creating products. If this was intentional, the PR description should explain why, and there should be a follow-up task to restore this functionality. ## ℹ️ Notes ### 9. `@reference` and `@apply` CSS warnings The `svelte-check` warnings about `@reference` and `@apply` being "unknown at rules" are false positives — Tailwind v4 uses these directives and they work correctly at runtime. ### 10. Biome internal crash Biome crashed with an internal error (`index out of bounds`), but this is a Biome bug, not a code issue. It still checked 193 files before crashing. --- ## Summary | Severity | Count | Description | |----------|-------|-------------| | 🔴 Critical | 3 | Missing PK on `order`, wrong FK on `cartItemValue`, self-referencing FK in migration 0007 | | 🟡 Medium | 5 | Missing return in `getSchema()`, inconsistent return types in `getPrice()`, duplicate CSS, empty orders page, removed product options | I recommend addressing the **critical issues** before merging, particularly the missing primary key on the `order` table and the incorrect FK references, as these would cause data integrity issues in production.
@ -0,0 +3,4 @@
`counter` integer NOT NULL,
`discount` numeric NOT NULL,
`createdAt` text NOT NULL,
FOREIGN KEY (`cartId`) REFERENCES `order`(`id`) ON UPDATE cascade ON DELETE restrict
Member

Migration 0007 creates order with a self-referencing FK to order.id, but the table has no id column. The FK should reference cart.id, but cart doesn't exist in migration 0007. Consider creating cart first in migration 0007, or reordering migrations.

Migration 0007 creates `order` with a self-referencing FK to `order.id`, but the table has no `id` column. The FK should reference `cart.id`, but `cart` doesn't exist in migration 0007. Consider creating `cart` first in migration 0007, or reordering migrations.
@ -5,2 +5,4 @@
export class ProductOptionClient extends Serializable<ProductOptionData> {
getSchema() {
switch (this.data.data.type) {
Member

No default return when type is neither 'boolean' nor 'choice'. If a new type is added, this silently returns undefined.

No default return when type is neither 'boolean' nor 'choice'. If a new type is added, this silently returns `undefined`.
@ -0,0 +12,4 @@
.notNull()
.references(() => product.id, { onDelete: "restrict", onUpdate: "cascade" }),
cartItemId: text()
Member

FK references product.id but should reference productOption.id. The column is productOptionId and should point to the productOption table.

FK references `product.id` but should reference `productOption.id`. The column is `productOptionId` and should point to the `productOption` table.
@ -0,0 +2,4 @@
import type { CartId } from "#lib/entities/cart/id.ts";
import { timestamp } from "./_utils.ts";
import cart from "./cart.ts";
Member

The order table has no id column. It should have a primary key for unique identification. Consider adding: id: text().$type<OrderId>().primaryKey().$default(() => randomUUID() as OrderId)

The `order` table has no `id` column. It should have a primary key for unique identification. Consider adding: `id: text().$type<OrderId>().primaryKey().$default(() => randomUUID() as OrderId)`
@ -9,0 +77,4 @@
<style>
@reference "#assets/tailwind.css";
Member

Consider defining this as a @utility in src/assets/tailwind.css instead of duplicating across 6 files.

Consider defining this as a `@utility` in `src/assets/tailwind.css` instead of duplicating across 6 files.
@ -0,0 +1,5 @@
<script lang="ts">
Member

This page is an empty stub — just requireUser() with no UI. Either implement it or remove the route.

This page is an empty stub — just `requireUser()` with no UI. Either implement it or remove the route.
feat: add cart read queries (#93)
All checks were successful
check-formatter.yaml / Checks with formatters (pull_request) Successful in 14s
check-linter.yaml / Checks with linters (pull_request) Successful in 33s
check-build.yaml / Check that project builds (pull_request) Successful in 1m6s
check-yamllint.yaml / Lint yaml files (pull_request) Successful in 2s
check-syntax.yaml / Checks with static tools (pull_request) Successful in 26s
f67eafb56f
davide scheduled this pull request to auto merge when all checks succeed 2026-07-15 12:14:01 +00:00
davide merged commit cf85c469f4 into main 2026-07-15 12:15:07 +00:00
davide deleted branch feat/order-management 2026-07-15 12:15:07 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
projects/events-cash-register!92
No description provided.