feat(guest): guest checkout without login (Swish + QR) #17

Merged
jocke merged 5 commits from feature/guest-checkout into master 2026-06-22 11:16:16 +00:00
Showing only changes of commit d16f048630 - Show all commits

View file

@ -1,24 +1,25 @@
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- Allows orders without a registered user (guest checkout).
-- Users can place and pay for letters without creating an account.
--
-- user_id: previously NOT NULL drop the constraint so guest orders
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- user_id: previously NOT NULL - drop the constraint so guest orders
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- can be created without a registered user. The FK stays in
-- place (NULL user_id is FK-legal).
-- guest_email: contact address for the guest. Used to send the magic
-- link that lets them revisit their order status.
-- guest_token: opaque UUID v4 the only credential a guest has. Acts
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- guest_token: opaque UUID v4 - the only credential a guest has. Acts
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- as their session token for order lookup + payment confirm.
ALTER TABLE orders ALTER COLUMN user_id DROP NOT NULL;
ALTER TABLE orders ADD COLUMN guest_email VARCHAR(255);
ALTER TABLE orders ADD COLUMN guest_token UUID;
-- Partial unique index: only enforce uniqueness on non-NULL tokens.
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- Multiple NULLs allowed — existing user-owned orders have no token,
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- and that's fine.
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- Unique index on guest_token. Both H2 (tests/dev) and PostgreSQL (prod)
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- treat NULLs as distinct in a UNIQUE index, so user-owned orders (which
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- have a NULL token) never collide, while non-NULL guest tokens are
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- enforced unique. A plain index is used instead of a partial
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- (WHERE guest_token IS NOT NULL) index because H2 does not support
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
-- partial indexes, and the plain form preserves the intended semantics.
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
CREATE UNIQUE INDEX idx_orders_guest_token
ON orders(guest_token)
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
WHERE guest_token IS NOT NULL;
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
ON orders(guest_token);
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
CREATE INDEX idx_orders_guest_email
ON orders(guest_email)
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
WHERE guest_email IS NOT NULL;
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
ON orders(guest_email);
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
Review

🟡 Missing DB-level orphan guard. The Order Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only onCreate() enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions:

ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest
    CHECK ((user_id IS NULL) <> (guest_token IS NULL));
🟡 **Missing DB-level orphan guard.** The `Order` Javadoc asserts "Either userId or guestToken is set; never both, never neither" — but only `onCreate()` enforces this in Java. A stray INSERT (admin tooling, future script) can violate it. Suggest adding after the column additions: ```sql ALTER TABLE orders ADD CONSTRAINT chk_user_or_guest CHECK ((user_id IS NULL) <> (guest_token IS NULL)); ```
Review

🔵 Unused index. idx_orders_guest_email is created but findByGuestEmail was never added to OrderRepository (the PR body lists it, but only findByGuestToken is there), so there's no read path on guest_email yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.

🔵 **Unused index.** `idx_orders_guest_email` is created but `findByGuestEmail` was never added to `OrderRepository` (the PR body lists it, but only `findByGuestToken` is there), so there's no read path on `guest_email` yet. Either add the lookup now or defer the index until the email-link phase to avoid an unused schema object.
Review

Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.

✅ Correct approach - a plain `UNIQUE INDEX` on `guest_token` treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial `WHERE guest_token IS NOT NULL` index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.