跳到主要内容

Deploy Archive — Account Center UX, Data Plan SIM Checkout, and Device Nicknames

Date: 2026-05-16 Repo: aovis-direct-store Production: https://aovis.app

Scope

This archive records the account-center work completed in this session:

  1. Customer order management controls.
  2. /account/services device-first service view.
  3. Data plan purchase flow changed to select SIM before Stripe checkout.
  4. /account/devices multi-device review layout.
  5. Per-user device display names.
  6. Device nickname redirect and save-feedback hotfixes.
  7. Device section ordering, connected-device summaries, and share-access management.
  8. Safari-safe account sign-in forms.

Release Commits

CommitPurposeProduction status
8dc25cb5819e9766a56831f339884900bf58aec7Customer order archive/hide, restore, safe cancel, filters/searchDeployed
c09a52419361215150a84e205cafde6e9eeeb7a8Reorganized /account/services around devicesDeployed
c8a17ca272b59643298525526faae8d11de1c5baClarified billing/pending data-plan copy and account summary countsDeployed
040e953dd6e45346600818afea7b9141b8bcff17Replaced low-value summary grids with task-oriented account summariesDeployed
3622606Data-plan SIM-first checkout and service/device UXDeployed
29c2eef2bf8bf7c8243fcf905ba391d5196fa9f4Device display names on DeviceOwnershipDeployed
1cab3f4fa1aa53af53d7bc838458b91316976528Fixed device nickname redirect using env.appUrlDeployed
fe102b6Added device nickname save success/error feedbackDeployed
04f28cdDevice selector auto-navigates without a separate View buttonDeployed
509d1c0Moved connected devices up and removed redundant Network access cardDeployed
8998f4eAdded share-invite role explanations and feedbackDeployed
afb6f25Fixed device-share SMTP handling and invite email error messagesDeployed
a4c827fCopied owner device display name when a share invite is acceptedDeployed
d1ec735Added owner share-management UI for active users and pending invitesDeployed

Customer Order Management

Files included in the order-management release included:

  • prisma/schema.prisma
  • prisma/migrations/20260516120000_add_customer_order_archive_fields/migration.sql
  • lib/commerce.ts
  • app/api/account/orders/[id]/route.ts
  • components/account-order-actions.tsx
  • app/account/orders/page.tsx
  • app/account/orders/[id]/page.tsx

Customer capabilities added:

  • Search by order number, product name, SKU, and order-id prefix.
  • Filter by status and time range.
  • Hide/archive orders from the default list and restore them from the archived view.
  • Safe customer-side cancellation only for unpaid/unfulfilled orders.

Important decision: customer “delete” is implemented as archive/hide, not hard delete, because orders are tied to payments, tax, shipping, returns, and audit history.

Data Plan Purchase Flow

Before this session, data plans could be purchased without a SIM. That created DataPlanPurchase rows with simCardId = null, which moved to pending_assignment and could not call EIOTCLUB.

Current flow:

User selects SIM/device on /services/cellular-data
→ POST /api/checkout/data-plan with dataPlanId + simCardId
→ server verifies the SIM belongs to the current user
→ Stripe Checkout session metadata includes simCardId
→ data-plan webhook records DataPlanPurchase.simCardId
→ fulfillment can call EIOTCLUB with the SIM ICCID

Key files:

  • app/services/cellular-data/page.tsx
  • app/api/checkout/data-plan/route.ts
  • lib/data-plans.ts
  • lib/__tests__/data-plans.test.ts

Important details:

  • Full ICCID is not written to Stripe metadata; only simCardId is stored there.
  • The checkout API validates SIM ownership server-side.
  • Old sessions without simCardId remain compatible and store simCardId: null.
  • pending_assignment remains as a historical/exception fallback, not the normal purchase path.

Account Services and Devices UX

/account/services now uses device-centered cards. Each device card aggregates:

  • Device identity.
  • SIM tail and current EIOTCLUB usage.
  • Extra data-plan purchases bound to that SIM.
  • Cloud storage and included AI features.
  • Multi-cloud duplicate-plan warnings.

SIM-only cellular access is shown even if the user has no extra data-plan purchase. For example, a SIM with EIOTCLUB’s initial 100MB state can display usage instead of incorrectly saying no cellular plan is linked.

/account/devices now supports multi-device review with a device selector based on ?device=DEVICE_ID. The selected device detail shows:

  • Device identity.
  • SIM/network state.
  • Data plans.
  • Cloud storage & AI.
  • Sharing and transfer controls for the selected device.

The old repeated per-device large-card layout was replaced to reduce clutter for multi-device users.

Later UX cleanup moved Connected devices to the top of the page, removed the redundant account-level Network access card, and kept SIM/network usage inside the selected device detail. A lightweight Network attention section is only shown for unlinked or problematic SIMs.

The multi-device selector now auto-navigates on change using /account/devices?device=..., so users do not need to select a device and then click a separate View button.

Device Display Names

Device nicknames are stored on DeviceOwnership.displayName, not Device, so each user can name the same shared device independently.

Schema/migration:

  • prisma/schema.prisma
  • prisma/migrations/20260516150000_add_device_ownership_display_name/migration.sql

Nickname API:

  • POST /api/account/devices/[deviceId]/nickname

Behavior:

  • Requires login.
  • Updates only the current user’s active ownership row.
  • Trims whitespace.
  • Empty string clears the nickname.
  • Max length is 60 characters.
  • Success redirects back to /account/devices?device=...&deviceName=updated.
  • Overlength redirects back with deviceName=too_long.

Display priority:

DeviceOwnership.displayName
→ Device.model
→ NEXA Device

Device names are used in:

  • /account/devices selected-device header and selector.
  • /account/services device cards.
  • /services/cellular-data SIM selector labels.

Hotfixes:

  • 1cab3f4: changed redirect base from request.url to env.appUrl to avoid localhost redirects behind Nginx/PM2.
  • fe102b6: added visible success/error feedback near the Device name form.

Device Sharing Management

The selected device detail includes a share-management section for owners:

  • People with access lists accepted shared users, their role, role explanation, and management controls.
  • Pending invites lists outstanding invitations with resend and cancel controls.
  • Invite someone new remains at the bottom of the share section.

This replaced the earlier pattern where an owner had to remember and re-enter a full email address to revoke access.

Roles use customer-facing descriptions:

  • Viewer: can view live video, events, and cloud playback.
  • Member: can view, use talk, and take snapshots.
  • Owner-only management: billing, SIM, sharing, and transfer ownership.

Invite email work:

  • SMTP configuration is parsed with parseSmtpServer() before nodemailer use, which fixed the Greeting never received production email failure.
  • Invite forms show sending state and success/error feedback.
  • Accepted invitees receive the owner's current device display name as their initial alias; afterward each user can rename the device independently.

Safari-Safe Account Sign-In

/signin and /login were changed from client-only button click handlers to native HTML forms backed by Auth.js server actions for:

  • Google OAuth
  • Apple OAuth
  • Email Magic Link

Reason: Safari could render the sign-in page but clicks on the client-side sign-in buttons could appear to do nothing. Native forms provide a no-client-JS fallback path and keep the user action as a standard browser form submit.

Verification Summary

Reported checks across the releases:

  • npm test: 172/172 pass after nickname/helper tests were added.
  • npm run build: passed locally and on VM.
  • npm run deploy:scope-check: expected high-risk warnings when prisma/ or checkout paths changed; passed when acceptable.
  • npx prisma migrate deploy: applied:
    • 20260516120000_add_customer_order_archive_fields
    • 20260516150000_add_device_ownership_display_name
  • PM2 service aovis-store-aws: restarted and online after releases.
  • npm run deploy:verify: 7/7 passed after production deploys.

Manual verification notes:

  • /services/cellular-data shows device/SIM labels after nickname changes.
  • /account/services shows custom device names and SIM usage.
  • /account/devices selector reflects custom names.
  • Device nickname save originally redirected to localhost; fixed by 1cab3f4.
  • Device nickname save originally had no visible feedback; fixed by fe102b6.
  • Owners can now see active shared users and pending invites without re-entering email addresses.
  • Invite email sending and accept flow were verified after the SMTP fix.
  • /signin and /login should be checked in Safari after sign-in form changes.

High-Risk Paths Touched

Touched and explicitly reported:

  • prisma/schema.prisma
  • prisma/migrations/*
  • app/api/checkout/data-plan/route.ts

Not touched during the final nickname/feedback hotfixes:

  • Hardware checkout main route.
  • Main Stripe webhook.
  • EIOTCLUB webhook.
  • Auth config.
  • Admin pages.

Sign-in form changes touch login UI and Auth.js server-action calls, but do not modify auth.ts, lib/auth-config.ts, providers, secrets, callbacks, checkout, or webhook code.

Current Open Notes

  • Device binding and entitlement automation remain out of scope unless explicitly requested.
  • pending_assignment data-plan purchases should now be treated as older/exception records.
  • The project phrase “live payment readiness” refers to Stripe live-payment readiness, not livestream commerce.