Skip to content

(SP: 3) [SHOP] harden shipping lifecycle recovery and production-safe provider/logging guards#415

Merged
ViktorSvertoka merged 12 commits intodevelopfrom
lso/feat/shop-legal
Mar 25, 2026
Merged

(SP: 3) [SHOP] harden shipping lifecycle recovery and production-safe provider/logging guards#415
ViktorSvertoka merged 12 commits intodevelopfrom
lso/feat/shop-legal

Conversation

@liudmylasovetovs
Copy link
Copy Markdown
Collaborator

@liudmylasovetovs liudmylasovetovs commented Mar 24, 2026

Description

This PR combines two Shop launch-readiness workstreams:

  1. Workstream 2 — Shipping recovery + canonical lifecycle
  2. Workstream 3 — Production env safety + generic PII-safe logging

The goal is to make shipping recovery operationally safe, expose one canonical fulfillment lifecycle across Shop order surfaces, and harden runtime/logging behavior for production-like environments.


Related Issue

Issue: #<issue_number>


Changes

  • Added a controlled admin recovery path for paid eligible orders that are missing the initial shipment row
  • Reused the canonical shipping queue/create path for recovery instead of adding a parallel manual shipment flow
  • Preserved shipping/payment/inventory/refund eligibility checks and duplicate protection for repeated recovery attempts
  • Added a canonical fulfillment-stage mapping for order-facing lifecycle states
  • Explicitly mapped clear order-facing close-equivalent stages for:
    • packed
    • shipped
    • delivered
    • canceled
    • returned
  • Surfaced shared canonical fulfillmentStage across relevant customer/admin order detail and status APIs while keeping existing raw/internal state fields intact
  • Added fail-closed provider runtime validation for production-like environments so placeholder/test PSP or shipping config does not pass launch-safe runtime checks
  • Added a reusable generic Shop logging redaction layer for:
    • email-like values
    • phone-like values
    • address-like fields
    • token-like / secret-like values
  • Added regression coverage for real Shop log flows in:
    • checkout
    • admin
    • notifications
  • Tightened shared redaction so free-form token-like strings are also masked in real log paths
  • Included narrow review cleanups related to shipping/cart test hygiene without widening feature scope

Database Changes (if applicable)

  • Schema migration required
  • Seed data updated
  • Breaking changes to existing queries
  • Transaction-safe migration
  • Migration tested locally on Neon

How Has This Been Tested?

  • Tested locally
  • Verified in development environment
  • Checked responsive layout (if UI-related)
  • Tested accessibility (keyboard / screen reader)

Additional notes:

  • Used the local Shop test DB only
  • Ran targeted Vitest coverage for:
    • admin shipment recovery for missing shipment rows
    • shipping/payment/admin guardrails
    • CSRF contract for mutating admin shipping actions
    • canonical fulfillment-stage mapping
    • customer/admin/status API surfacing of fulfillmentStage
    • provider runtime safety in production-like env assertions
    • generic logging redaction behavior
    • real-flow logging regression for checkout/admin/notifications
  • Ran narrow file-scoped TypeScript / ESLint checks for touched files where needed

Screenshots (if applicable)

N/A — backend / API / lifecycle / runtime safety / logging hardening only.


Checklist

Before submitting

  • Code has been self-reviewed
  • No TypeScript or console errors
  • Code follows project conventions
  • Scope is limited to this feature/fix
  • No unrelated refactors included
  • English used in code, commits, and docs
  • New dependencies discussed with team
  • Database migration tested locally (if applicable)
  • GitHub Projects card moved to In Review

Reviewers

Summary by CodeRabbit

  • New Features

    • Orders now display a canonical fulfillment stage (processing, packed, shipped, delivered, canceled, returned) across order details and status views; UI translations added.
    • Admins can trigger recovery of missing initial shipments to resume shipment processing.
  • Improvements

    • Provider runtime validation: misconfigured payment/shipping providers (e.g., Nova Poshta, Monobank, Stripe) fail closed in shipping methods and checkout flows.
    • Server-side logging now redacts sensitive data (emails, phones, tokens) for safer logs.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
devlovers-net Ignored Ignored Preview Mar 25, 2026 8:47pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

Warning

Rate limit exceeded

@liudmylasovetovs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 14 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 02bc0835-e947-42ec-b066-92128a7fce7b

📥 Commits

Reviewing files that changed from the base of the PR and between c9a18b7 and bbc00ef.

📒 Files selected for processing (1)
  • frontend/.env.example
📝 Walkthrough

Walkthrough

Adds canonical fulfillment-stage derivation and surfaces it across order APIs, pages, and summaries; introduces provider runtime validations (Stripe, Monobank, Nova Poshta); adds logging redaction utilities; implements transactional ensureQueuedInitialShipment and a recover_initial_shipment admin action; and updates tests, env docs, and translations.

Changes

Cohort / File(s) Summary
Fulfillment stage core & validation
frontend/lib/services/shop/fulfillment-stage.ts, frontend/lib/validation/shop.ts
New canonical fulfillment-stage constants/types, SQL helpers (latestShipmentStatusSql, latestReturnStatusSql), readCanonicalFulfillmentSignals, deriveCanonicalFulfillmentStage, and Zod enum fulfillmentStageSchema / exported CanonicalFulfillmentStage.
Order pages & API surfaces
frontend/app/[locale]/shop/orders/[id]/page.tsx, frontend/app/[locale]/admin/shop/orders/[id]/page.tsx, frontend/app/api/shop/orders/[id]/route.ts
DB selects now include orders.status, computed shipmentStatus/returnStatus; derive fulfillmentStage and expose it on order detail responses and UI; explicit field mappings replace prior spread usage.
Order summary & payment flows
frontend/lib/services/orders/summary.ts, frontend/lib/services/orders/payment-intent.ts, frontend/lib/services/orders/monobank-webhook.ts, frontend/lib/services/orders/checkout.ts
Parse/summary APIs and payment-intent flows now accept/propagate fulfillmentStage; monobank webhook uses ensureQueuedInitialShipment; checkout shipping checks Nova Poshta readiness and fails closed on config error.
Shipping admin & queueing
frontend/lib/services/shop/shipping/admin-actions.ts, frontend/lib/services/shop/shipping/ensure-queued-initial-shipment.ts, frontend/app/api/shop/admin/orders/[id]/shipping/route.ts
Added recover_initial_shipment admin action; new transactional ensureQueuedInitialShipment ensures queued shipments and resyncs order shipping_status; admin action invokes it and updates audit/metrics.
Provider runtime checks & env helpers
frontend/lib/env/provider-runtime.ts, frontend/lib/env/nova-poshta.ts, frontend/lib/env/monobank.ts, frontend/lib/env/stripe.ts, frontend/lib/env/payments.ts
Added ShopProviderConfigError, production-like assertion helpers for provider envs, Nova Poshta/Monobank/Stripe runtime validations, and guarded provider resolution/error handling.
Logging redaction & integration
frontend/lib/services/shop/logging-redaction.ts, frontend/lib/logging.ts
New sanitizers for strings/meta/errors with regex/recursive redaction; logging now calls sanitizers before JSON serialization (removed prior key-based replacer).
Shipping methods route behavior
frontend/app/api/shop/shipping/methods/route.ts
Calls assertNovaPoshtaProductionLikeReady() and returns HTTP 503 { success: false, code: 'NP_MISCONFIG', message: 'Nova Poshta configuration is invalid' } for misconfigured NP in production-like runtime.
Env docs & example
frontend/.env.example
Added APP_ENV, APP_ORIGIN, DATABASE_URL_LOCAL, payment/shipping knobs, and NP flat-price env examples; updated comments.
Translations
frontend/messages/en.json, frontend/messages/pl.json, frontend/messages/uk.json
Added orders.detail.fulfillmentStage and orders.detail.fulfillmentStages entries for all canonical stages.
Tests: new & updated suites
frontend/lib/tests/...
Extensive new and updated Vitest suites covering fulfillment-stage derivation/surfacing, recover_initial_shipment behavior/idempotency, provider env safety, logging redaction, checkout shipping closed-fail, and related API assertions.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as Shop API
  participant DB
  participant Service as Fulfillment Service

  Client->>API: GET /api/shop/orders/{id}
  API->>DB: SELECT order + orders.status + shipping_status + latestShipmentStatusSql(...) + latestReturnStatusSql(...)
  DB-->>API: row with orderStatus, shippingStatus, shipmentStatus, returnStatus
  API->>Service: deriveCanonicalFulfillmentStage({orderStatus, shippingStatus, shipmentStatus, returnStatus})
  Service-->>API: CanonicalFulfillmentStage
  API-->>Client: 200 { order: {..., fulfillmentStage } }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • LesiaUKR
  • AM1007
  • ViktorSvertoka

Poem

🐰
I hopped through rows where statuses play,
Packed, shipped, returned — I found the way.
I hid the secrets, checked the keys,
Queued parcels swift with nimble ease,
A carrot clap for staged display!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main changes: hardening shipping lifecycle recovery and adding production-safe provider/logging guards, which aligns with the primary objectives.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lso/feat/shop-legal

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

❤️ Share

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a5dfce41a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
frontend/lib/validation/shop.ts (1)

40-47: Make the canonical fulfillment stages a single source of truth.

These literals are now encoded separately here and in @/lib/services/shop/fulfillment-stage. Exporting a shared canonicalFulfillmentStageValues constant and deriving both the Zod enum and TS union from it would remove an easy drift point.

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

In `@frontend/lib/validation/shop.ts` around lines 40 - 47, Introduce and export a
single array constant (e.g., canonicalFulfillmentStageValues) containing the
literal stages, then derive the Zod enum and a TypeScript union from that array
instead of hardcoding literals: replace the current fulfillmentStageSchema =
z.enum([...]) with fulfillmentStageSchema =
z.enum(canonicalFulfillmentStageValues) and export a type like FulfillmentStage
= (typeof canonicalFulfillmentStageValues)[number]; update the other module that
currently duplicates the literals (the one exporting fulfillment-stage values)
to import and reuse canonicalFulfillmentStageValues so both the Zod schema
(fulfillmentStageSchema) and the service layer share the same single source of
truth.
frontend/lib/services/orders/summary.ts (1)

442-449: Intentional simplification: getOrderByIdempotencyKey omits shipment/return signals.

This function only passes orderStatus and shippingStatus to deriveCanonicalFulfillmentStage, omitting shipmentStatus and returnStatus. Per the derivation logic, when shipmentStatus and returnStatus are both null, the function falls through and returns 'processing' as the default.

This is likely intentional since this function is used during checkout flows before shipments exist. However, if this function could be called for orders that already have shipments/returns, the derived stage would be inaccurate.

Consider adding a brief comment documenting this intentional simplification for future maintainers.

📝 Suggested documentation
 export async function getOrderByIdempotencyKey(
   dbClient: DbClient,
   key: string
 ): Promise<OrderSummaryWithMinor | null> {
+  // Note: This function is primarily used during checkout flows where shipments
+  // don't exist yet, so we only derive stage from order/shipping status.
   const [order] = await dbClient
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/lib/services/orders/summary.ts` around lines 442 - 449, Add a brief
inline comment at the call site where parseOrderSummary invokes
deriveCanonicalFulfillmentStage (the call passing only order.status and
order.shippingStatus) explaining that shipmentStatus and returnStatus are
intentionally omitted in this simplified path (used by
getOrderByIdempotencyKey/checkout flows before shipments/returns exist), and
note the caveat that if this function is ever reused for orders with existing
shipments/returns the derived stage may be inaccurate and those fields should be
included; reference deriveCanonicalFulfillmentStage and getOrderByIdempotencyKey
in the comment for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/lib/env/monobank.ts`:
- Around line 168-179: resolveShopPaymentProvider() currently calls
isMonobankEnabled() without protection, so assertions from
assertMonobankRuntimeConfig() can throw ShopProviderConfigError and crash; wrap
the call to isMonobankEnabled() inside a try-catch in
resolveShopPaymentProvider(), catch ShopProviderConfigError (or any Error) and
treat it as "disabled" (return false / fallthrough to other providers) so
invalid Monobank config no longer causes an unhandled exception; ensure the
catch is narrow enough to recognize configuration validation errors but still
safe (refer to resolveShopPaymentProvider(), isMonobankEnabled(), and
resolveMonobankCheckoutEnabled() to mirror existing error-handling patterns).

In `@frontend/lib/env/stripe.ts`:
- Around line 71-77: The current assertProductionLikeProviderString call for
provider 'stripe' only checks format (requiredPrefix 'whsec_') and can allow
test webhook secrets in production; update the validation so that when running
in production (e.g. process.env.NODE_ENV === 'production' or your existing
production flag) you additionally verify the Stripe API key indicates a live
account (check process.env.STRIPE_API_KEY.startsWith('sk_live_') or an
equivalent "is live" indicator) and throw/log a clear error if a test API key is
present while STRIPE_WEBHOOK_SECRET is set, keeping the existing minLength and
prefix checks and updating the error message to reference STRIPE_WEBHOOK_SECRET
and STRIPE_API_KEY; the check should be implemented alongside or inside
assertProductionLikeProviderString usage for 'stripe' (refer to provider:
'stripe', envName: 'STRIPE_WEBHOOK_SECRET', value: webhookSecret).

In `@frontend/lib/logging.ts`:
- Around line 53-55: The top-level log message is not being redacted: update the
redactJsonStringify function to actually perform redaction on strings and
objects (e.g., detect and mask emails, tokens, phone numbers, and sensitive
keys) rather than just returning JSON.stringify(value), and ensure the message
field passed to the logger is passed through this redactor as well; specifically
modify redactJsonStringify and the places that emit msg (the same call sites
around the existing redactJsonStringify usage at the msg/meta/err emission and
the block referenced at lines 65-70) so msg is sanitized consistently with meta
and err before logging.

In `@frontend/lib/services/orders/payment-intent.ts`:
- Around line 58-65: The updated branch is deriving fulfillmentStage from orders
alone which misses shipment/return-only signals; before calling
deriveCanonicalFulfillmentStage in both the current and updated branches, call
readCanonicalFulfillmentSignals(...) to load signals from
shipping_shipments/return_requests (mirror the getOrderById path), then pass the
returned signals into deriveCanonicalFulfillmentStage; also add
readCanonicalFulfillmentSignals to the import list from
../shop/fulfillment-stage so the function is available where parseOrderSummary
and deriveCanonicalFulfillmentStage are used.

In `@frontend/lib/services/shop/shipping/admin-actions.ts`:
- Around line 505-539: The branch that handles state.shipment_status ===
'queued' currently returns early after appendAuditEntry and thus never calls
ensureQueuedInitialShipment to repair drift; remove the early return and invoke
ensureQueuedInitialShipment (passing the orderId and state.shipment_id /
relevant args) so the order shipping_status can be resynchronized from the
existing queued shipment row, then use the result of ensureQueuedInitialShipment
to determine the returned shippingStatus/shipmentStatus/changed values (preserve
the audit append via appendAuditEntry and keep dedupe logic using
buildShippingAdminAuditDedupe).

In `@frontend/lib/services/shop/shipping/ensure-queued-initial-shipment.ts`:
- Around line 76-80: The conflict handler is requeuing a
concurrently-created/advanced shipment by running "on conflict (order_id) do
update set status = 'queued'...", which can regress live shipments; in the
ensureQueuedInitialShipment helper replace that conflict update with a no-op
conflict policy (e.g., "on conflict (order_id) do nothing") so concurrent
inserts are ignored rather than resetting status, and remove the conditional
update that forces status back to 'queued' in that statement; keep the rest of
the insert/transition logic intact and rely on queued_order_ids for idempotency.

---

Nitpick comments:
In `@frontend/lib/services/orders/summary.ts`:
- Around line 442-449: Add a brief inline comment at the call site where
parseOrderSummary invokes deriveCanonicalFulfillmentStage (the call passing only
order.status and order.shippingStatus) explaining that shipmentStatus and
returnStatus are intentionally omitted in this simplified path (used by
getOrderByIdempotencyKey/checkout flows before shipments/returns exist), and
note the caveat that if this function is ever reused for orders with existing
shipments/returns the derived stage may be inaccurate and those fields should be
included; reference deriveCanonicalFulfillmentStage and getOrderByIdempotencyKey
in the comment for clarity.

In `@frontend/lib/validation/shop.ts`:
- Around line 40-47: Introduce and export a single array constant (e.g.,
canonicalFulfillmentStageValues) containing the literal stages, then derive the
Zod enum and a TypeScript union from that array instead of hardcoding literals:
replace the current fulfillmentStageSchema = z.enum([...]) with
fulfillmentStageSchema = z.enum(canonicalFulfillmentStageValues) and export a
type like FulfillmentStage = (typeof canonicalFulfillmentStageValues)[number];
update the other module that currently duplicates the literals (the one
exporting fulfillment-stage values) to import and reuse
canonicalFulfillmentStageValues so both the Zod schema (fulfillmentStageSchema)
and the service layer share the same single source of truth.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3718592f-af72-4f86-8297-6eef6455e392

📥 Commits

Reviewing files that changed from the base of the PR and between 8310e18 and 4a5dfce.

📒 Files selected for processing (35)
  • frontend/app/[locale]/admin/shop/orders/[id]/page.tsx
  • frontend/app/[locale]/shop/orders/[id]/page.tsx
  • frontend/app/api/shop/admin/orders/[id]/shipping/route.ts
  • frontend/app/api/shop/orders/[id]/route.ts
  • frontend/app/api/shop/shipping/methods/route.ts
  • frontend/lib/env/monobank.ts
  • frontend/lib/env/nova-poshta.ts
  • frontend/lib/env/provider-runtime.ts
  • frontend/lib/env/stripe.ts
  • frontend/lib/logging.ts
  • frontend/lib/services/orders/checkout.ts
  • frontend/lib/services/orders/monobank-webhook.ts
  • frontend/lib/services/orders/payment-intent.ts
  • frontend/lib/services/orders/summary.ts
  • frontend/lib/services/shop/fulfillment-stage.ts
  • frontend/lib/services/shop/logging-redaction.ts
  • frontend/lib/services/shop/shipping/admin-actions.ts
  • frontend/lib/services/shop/shipping/ensure-queued-initial-shipment.ts
  • frontend/lib/tests/shop/admin-shipping-canonical-audit.test.ts
  • frontend/lib/tests/shop/admin-shipping-payment-gate.test.ts
  • frontend/lib/tests/shop/admin-shipping-state-sync.test.ts
  • frontend/lib/tests/shop/checkout-shipping-authoritative-total.test.ts
  • frontend/lib/tests/shop/fulfillment-stage.test.ts
  • frontend/lib/tests/shop/logging-redaction-generic.test.ts
  • frontend/lib/tests/shop/logging-redaction-real-flows.test.ts
  • frontend/lib/tests/shop/order-fulfillment-stage-surfaces.test.ts
  • frontend/lib/tests/shop/order-status-token.test.ts
  • frontend/lib/tests/shop/orders-access.test.ts
  • frontend/lib/tests/shop/orders-status-ownership.test.ts
  • frontend/lib/tests/shop/provider-env-runtime-safety.test.ts
  • frontend/lib/tests/shop/shipping-methods-route-p2.test.ts
  • frontend/lib/validation/shop.ts
  • frontend/messages/en.json
  • frontend/messages/pl.json
  • frontend/messages/uk.json

Copy link
Copy Markdown
Contributor

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/lib/tests/shop/provider-env-runtime-safety.test.ts`:
- Around line 59-72: Swap the order of calling vi.unstubAllEnvs() and the manual
environment operations in the test hooks: in beforeEach call vi.unstubAllEnvs()
first, then delete process.env keys and resetEnvCache(), and in afterEach call
vi.unstubAllEnvs() before restoreEnv() and resetEnvCache(); update the
beforeEach and afterEach blocks that reference ENV_KEYS, previousEnv,
restoreEnv(), resetEnvCache(), and vi.unstubAllEnvs() accordingly so stubs are
cleared prior to manual env modifications/restoration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 68d4e640-c318-4819-a6d2-6858851e735c

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5dfce and 0e212d7.

📒 Files selected for processing (14)
  • frontend/lib/env/payments.ts
  • frontend/lib/logging.ts
  • frontend/lib/services/orders/payment-intent.ts
  • frontend/lib/services/orders/summary.ts
  • frontend/lib/services/shop/fulfillment-stage.ts
  • frontend/lib/services/shop/shipping/admin-actions.ts
  • frontend/lib/services/shop/shipping/ensure-queued-initial-shipment.ts
  • frontend/lib/tests/shop/admin-shipping-canonical-audit.test.ts
  • frontend/lib/tests/shop/admin-shipping-state-sync.test.ts
  • frontend/lib/tests/shop/fulfillment-stage.test.ts
  • frontend/lib/tests/shop/logging-redaction-generic.test.ts
  • frontend/lib/tests/shop/payment-intent-fulfillment-stage.test.ts
  • frontend/lib/tests/shop/provider-env-runtime-safety.test.ts
  • frontend/lib/validation/shop.ts
✅ Files skipped from review due to trivial changes (2)
  • frontend/lib/services/orders/summary.ts
  • frontend/lib/tests/shop/fulfillment-stage.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • frontend/lib/services/orders/payment-intent.ts
  • frontend/lib/validation/shop.ts
  • frontend/lib/tests/shop/logging-redaction-generic.test.ts
  • frontend/lib/tests/shop/admin-shipping-canonical-audit.test.ts
  • frontend/lib/tests/shop/admin-shipping-state-sync.test.ts
  • frontend/lib/services/shop/shipping/ensure-queued-initial-shipment.ts
  • frontend/lib/logging.ts

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (3)
frontend/.env.example (3)

68-71: Clarify which payment toggle gates these Stripe requirements.

The comment states "Required when Stripe payments are enabled" but doesn't specify which environment variable controls this. Based on the code snippet from frontend/lib/env/stripe.ts:27,42-43, Stripe credentials are gated by PAYMENTS_ENABLED (line 91), not STRIPE_PAYMENTS_ENABLED (line 66). Consider updating the comment to explicitly reference the controlling variable.

📝 Proposed clarification
-# Required when Stripe payments are enabled.
+# Required when PAYMENTS_ENABLED=true (see line 91).
 # In production-like runtime, invalid or placeholder config must fail closed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/.env.example` around lines 68 - 71, Update the env example comment
to reference the actual toggle used in code: state that STRIPE_SECRET_KEY and
STRIPE_WEBHOOK_SECRET are required when PAYMENTS_ENABLED is true (not
STRIPE_PAYMENTS_ENABLED), so change the comment text near
STRIPE_SECRET_KEY/STRIPE_WEBHOOK_SECRET to mention PAYMENTS_ENABLED as the
controlling variable and ensure consistency with the logic in
frontend/lib/env/stripe.ts which checks PAYMENTS_ENABLED.

80-83: Clarify which payment toggle gates these Monobank requirements.

Similar to the Stripe section, the comment states "Required when Monobank checkout/webhooks are enabled" but doesn't specify which environment variable controls this. Based on the code snippet from frontend/lib/env/monobank.ts:135, Monobank credentials are gated by PAYMENTS_ENABLED (line 91). Consider updating the comment to explicitly reference the controlling variable.

📝 Proposed clarification
-# Required when Monobank checkout/webhooks are enabled.
+# Required when PAYMENTS_ENABLED=true (see line 91).
 # In production-like runtime, invalid or placeholder config must fail closed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/.env.example` around lines 80 - 83, Update the env example comment
to explicitly state which feature flag controls Monobank being required: mention
PAYMENTS_ENABLED as the toggle that gates Monobank checkout/webhooks and
therefore requires MONO_MERCHANT_TOKEN and MONO_PUBLIC_KEY; edit the existing
comment above MONO_MERCHANT_TOKEN and MONO_PUBLIC_KEY to mirror the Stripe
section style and reference PAYMENTS_ENABLED so it's clear when these variables
must be non-placeholder.

77-78: Document the default fallback values for MONO_INVOICE_TIMEOUT_MS.

The code snippet from frontend/lib/env/monobank.ts:138-141 shows that this variable has fallback defaults: 8000ms in production or 12000ms in development. Consider documenting these defaults to help operators understand the behavior when this variable is not set.

📝 Proposed enhancement
-# Optional invoice timeout override in milliseconds.
+# Optional invoice timeout override in milliseconds.
+# Defaults: 8000ms (production), 12000ms (development).
 MONO_INVOICE_TIMEOUT_MS=
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/.env.example` around lines 77 - 78, Update the .env.example comment
for MONO_INVOICE_TIMEOUT_MS to document its runtime fallbacks: state that when
unset the app uses 8000 (ms) in production and 12000 (ms) in development as
implemented in the code that reads MONO_INVOICE_TIMEOUT_MS; mention the units
(milliseconds) and that these are applied only when the env var is not provided
so operators know the default behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/.env.example`:
- Around line 68-71: Update the env example comment to reference the actual
toggle used in code: state that STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET are
required when PAYMENTS_ENABLED is true (not STRIPE_PAYMENTS_ENABLED), so change
the comment text near STRIPE_SECRET_KEY/STRIPE_WEBHOOK_SECRET to mention
PAYMENTS_ENABLED as the controlling variable and ensure consistency with the
logic in frontend/lib/env/stripe.ts which checks PAYMENTS_ENABLED.
- Around line 80-83: Update the env example comment to explicitly state which
feature flag controls Monobank being required: mention PAYMENTS_ENABLED as the
toggle that gates Monobank checkout/webhooks and therefore requires
MONO_MERCHANT_TOKEN and MONO_PUBLIC_KEY; edit the existing comment above
MONO_MERCHANT_TOKEN and MONO_PUBLIC_KEY to mirror the Stripe section style and
reference PAYMENTS_ENABLED so it's clear when these variables must be
non-placeholder.
- Around line 77-78: Update the .env.example comment for MONO_INVOICE_TIMEOUT_MS
to document its runtime fallbacks: state that when unset the app uses 8000 (ms)
in production and 12000 (ms) in development as implemented in the code that
reads MONO_INVOICE_TIMEOUT_MS; mention the units (milliseconds) and that these
are applied only when the env var is not provided so operators know the default
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 854c04f0-0391-4b36-a8c5-6061edfd03cb

📥 Commits

Reviewing files that changed from the base of the PR and between 41afea4 and c9a18b7.

📒 Files selected for processing (2)
  • frontend/.env.example
  • frontend/lib/services/shop/logging-redaction.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/lib/services/shop/logging-redaction.ts

@ViktorSvertoka ViktorSvertoka merged commit 8730038 into develop Mar 25, 2026
7 checks passed
@ViktorSvertoka ViktorSvertoka deleted the lso/feat/shop-legal branch March 25, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants