Context
Customer Support → User Search must support two types of users:
-
Internal users
- Created within our system
- Searchable by email, phone, name
- Have full account data (profile, devices, plans, QOSS, etc.)
-
External users
- Not created in our system
- Identified only by UUID
- Only QOSS data available (no account profile)
In production, external users were handled via:
- A filter dropdown ("External User")
- Manual selection
- Separate rendering behavior
This created:
- UX friction
- Architectural leakage
- Filter-driven mode switching
- Inconsistent mental model
Decision
Implement a unified lookup flow with automatic mode detection.
Single Search Input
Search supports:
- Email / phone / name (internal)
- UUID (external)
UUID Detection
Frontend detects UUID format using regex (src/constants/pattern.ts).
If UUID:
external=true(query param)- Mount QOSS module directly
If non-UUID:
- Clear
externalquery param - Unmount QOSS module
- Execute normal search API
Module Reuse
External flow reuses the same:
- QOSS module
- DataTable abstraction
- Pagination behavior
- Page size controls
No forked components were introduced.
URL-Driven Mode
Mode is represented in query params:
?external=true
This ensures:
- Reload safety
- Shareable URLs
- Back-button consistency
- Deterministic rendering
State Isolation
Switching modes:
- Unmounts previous module
- Resets pagination
- Clears stale state
This prevents cross-mode contamination.
Consequences
Positive
- Removes filter-based branching
- Reduces cognitive load for support engineers
- Hides backend architecture boundaries
- Improves UX clarity
- Preserves module reuse
- Strengthens query-param–driven architecture
- Scales to future modes
Tradeoffs
- Frontend decides mode based on identifier format
- Assumes UUID format will not overlap with internal identifiers
If identifier formats change in the future, backend detection should become authoritative.
Notes
This establishes a pattern:
Mode-based rendering should be driven by URL state and module boundaries, not filter toggles.
This pattern can be reused for:
- Other cross-domain lookups
- Hybrid entity resolution flows
- Partial-data user representations
- Investigation consoles