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:
- Customer order management controls.
/account/servicesdevice-first service view.- Data plan purchase flow changed to select SIM before Stripe checkout.
/account/devicesmulti-device review layout.- Per-user device display names.
- Device nickname redirect and save-feedback hotfixes.
- Device section ordering, connected-device summaries, and share-access management.
- Safari-safe account sign-in forms.
Release Commits
| Commit | Purpose | Production status |
|---|---|---|
8dc25cb5819e9766a56831f339884900bf58aec7 | Customer order archive/hide, restore, safe cancel, filters/search | Deployed |
c09a52419361215150a84e205cafde6e9eeeb7a8 | Reorganized /account/services around devices | Deployed |
c8a17ca272b59643298525526faae8d11de1c5ba | Clarified billing/pending data-plan copy and account summary counts | Deployed |
040e953dd6e45346600818afea7b9141b8bcff17 | Replaced low-value summary grids with task-oriented account summaries | Deployed |
3622606 | Data-plan SIM-first checkout and service/device UX | Deployed |
29c2eef2bf8bf7c8243fcf905ba391d5196fa9f4 | Device display names on DeviceOwnership | Deployed |
1cab3f4fa1aa53af53d7bc838458b91316976528 | Fixed device nickname redirect using env.appUrl | Deployed |
fe102b6 | Added device nickname save success/error feedback | Deployed |
04f28cd | Device selector auto-navigates without a separate View button | Deployed |
509d1c0 | Moved connected devices up and removed redundant Network access card | Deployed |
8998f4e | Added share-invite role explanations and feedback | Deployed |
afb6f25 | Fixed device-share SMTP handling and invite email error messages | Deployed |
a4c827f | Copied owner device display name when a share invite is accepted | Deployed |
d1ec735 | Added owner share-management UI for active users and pending invites | Deployed |
Customer Order Management
Files included in the order-management release included:
prisma/schema.prismaprisma/migrations/20260516120000_add_customer_order_archive_fields/migration.sqllib/commerce.tsapp/api/account/orders/[id]/route.tscomponents/account-order-actions.tsxapp/account/orders/page.tsxapp/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.tsxapp/api/checkout/data-plan/route.tslib/data-plans.tslib/__tests__/data-plans.test.ts
Important details:
- Full ICCID is not written to Stripe metadata; only
simCardIdis stored there. - The checkout API validates SIM ownership server-side.
- Old sessions without
simCardIdremain compatible and storesimCardId: null. pending_assignmentremains 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.prismaprisma/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/devicesselected-device header and selector./account/servicesdevice cards./services/cellular-dataSIM selector labels.
Hotfixes:
1cab3f4: changed redirect base fromrequest.urltoenv.appUrlto 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 accesslists accepted shared users, their role, role explanation, and management controls.Pending inviteslists outstanding invitations with resend and cancel controls.Invite someone newremains 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 theGreeting never receivedproduction 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 whenprisma/or checkout paths changed; passed when acceptable.npx prisma migrate deploy: applied:20260516120000_add_customer_order_archive_fields20260516150000_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-datashows device/SIM labels after nickname changes./account/servicesshows custom device names and SIM usage./account/devicesselector 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.
/signinand/loginshould be checked in Safari after sign-in form changes.
High-Risk Paths Touched
Touched and explicitly reported:
prisma/schema.prismaprisma/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_assignmentdata-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.