5. Backend validates the checkout session token, queries order data through Admin GraphQL, reads the `$app:dreame_activity` Metaobject config, checks order-level idempotency, calls Dreame status API, then calls Dreame push API.
Business failures return `{ "success": false }`; route-level validation errors can include an `error` object and non-2xx status. The extension renders nothing for either case and does not block the native Thank You Page.
The Shopify CLI was not available in this workspace, and remote `npm create @shopify/app@latest` execution was blocked by local safety policy. The project has therefore been initialized as a local scaffold matching the requested Shopify Remix structure.
The optional script upserts the singleton Metaobject entry. The definition itself is managed through `shopify.app.toml` and applied by Shopify CLI during `shopify app dev` or `shopify app deploy`.
Route-level validation failures include an error code and use the matching HTTP status:
```json
{
"success": false,
"error": {
"code": "ORDER_ID_REQUIRED",
"message": "orderId is required."
}
}
```
All route responses include `Cache-Control: no-store, max-age=0`. Authenticated `POST` and `OPTIONS` responses are wrapped with Shopify's checkout CORS helper; fallback CORS is only used when authentication itself fails before the helper is available. Source trust relies on Shopify checkout session token validation.
The implementation serializes the payload once with `JSON.stringify(payload)`. The exact same `bodyString` is used both for signing and as the `fetch` body.
## Mock Mode
Default mock behavior:
- Status API returns `code=0` and `data.status=true`.
Switch to live calls only after third-party endpoints and credentials are available:
```env
THIRD_PARTY_MODE=live
```
## Database
Development uses SQLite:
```env
DATABASE_URL="file:./dev.sqlite"
```
Production should use Postgres. The same Prisma schema applies after changing the datasource provider and connection string as part of production hardening.
Tables added by this scaffold:
-`ActivityPushLog`: one row per status/push attempt or failure.
-`ActivityPushIdempotency`: unique key on `shop + orderId + activityId`; prevents duplicate push for the same order and activity.
Logs are sanitized before persistence and must not store `api_secret` or `dreame-api-sign`.
## Checkout UI Extension
Location:
```text
extensions/thank-you-activity
```
Target:
```text
purchase.thank-you.block.render
```
Capabilities:
```toml
[extensions.capabilities]
network_access = true
```
Set the extension setting `app_url` to the public HTTPS backend URL. During `shopify app dev`, this is the tunnel URL produced by Shopify CLI.
`purchase.thank-you.block.render` is a valid latest Thank You Page block target. Merchants can control placement in the checkout and accounts editor; changing to a static target such as `purchase.thank-you.header.render-after` requires TOML/code review and redeployment.
The extension sets `default_placement = "ORDER_STATUS1"` so the first suggested placement is above the order status card. Merchants can still move the block in the checkout and accounts editor.