Files
voipsimplicity/PORTAL-REQUIREMENTS.md
T

599 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# my.voipsimplicity.com — Portal Requirements
**Version:** 1.0
**Date:** 2026-07-24
**Status:** Pre-MVP documentation
**Owner:** Germaine Brown (VoIPSimplicity LLC)
**Platform:** RingLogix-powered, deployed on app3 (CloudPanel CE)
**Design:** Light, mobile-first, single-file HTML SPA (see [voip-portal-development skill](#sources--methodology))
---
## Table of Contents
1. [Sources & Methodology](#sources--methodology)
2. [Source of Truth & Data Architecture](#source-of-truth--data-architecture)
3. [RBAC, Tenant Isolation & Security](#rbac-tenant-isolation--security)
4. [Audit & Compliance](#audit--compliance)
5. [Phased MVP Sequence](#phased-mvp-sequence)
6. [Requirement Areas](#requirement-areas)
- [1. My Dashboard](#1-my-dashboard)
- [2. Call History](#2-call-history)
- [3. Marketplace](#3-marketplace)
- [4. Billing](#4-billing)
- [5. My Info](#5-my-info)
- [6. Site Login](#6-site-login)
- [7. Screenshot-Informed Requirements](#7-screenshot-informed-requirements)
7. [Nav Organization (Expanded Canonical)](#nav-organization-expanded-canonical)
8. [Acceptance Criteria by Phase](#acceptance-criteria-by-phase)
9. [Unknowns & Caveats](#unknowns--caveats)
10. [Out of Scope (Deferred to Post-MVP)](#out-of-scope-deferred-to-post-mvp)
---
## Sources & Methodology
### Owner-Provided Materials
- **Owner screenshots:** ViiBE seller-side views (Accounts, Quotes, Products, LNP, Number Orders, CNAM, Mobile Connect, Reports) and NetSapiens customer/manager views (Home/Statistics, Domains, SIP Trunks, Phone Inventory, E911 Inventory, Call History, Contacts, Answer Rules, Time Frames, User Voicemail/Settings, Music/Messages, Call-Center Queues/Statistics, Auto Attendants).
- **Owner Obsidian notes:** Captured preferences, design constraints, competitive feature wishlist, and operational requirements from Germaine Brown.
- **Owner business records:** [ENTITY.md](./ENTITY.md) — verified phone assets and legal entity.
### Existing Portal Artifacts
- **Deployed portal:** `/home/myvoip/htdocs/my.voipsimplicity.com/index.html` on app3 (533 lines production, 1,471 enhanced reference).
- **Skill documentation:** `voip-portal-development` skill in `~/.hermes/skills/devops/voip-portal-development/` with 13 reference files covering API integration, call patterns, marketplace flows, and deployment.
- **Domain roster:** 14 customer domains, 189 subscribers, 17 DIDs, 30 call queues, 19 auto attendants, 16 time frames — all on RingLogix.
---
## Source of Truth & Data Architecture
| Data Domain | Primary Source | API/Object | Notes |
|---|---|---|---|
| Subscribers/Extensions | RingLogix | `subscriber/read` | `domain` param required; filter to 100399 for real users |
| DIDs/Phone Numbers | RingLogix | `phonenumber/read` | Ignores domain filter — filter client-side by `dialrule_domain` |
| Call Queues | RingLogix | `callqueue/read` | `domain` param required |
| Auto Attendants | RingLogix | `attendant/read` | NOT `autoattendant` (returns 404) |
| Time Frames | RingLogix | `timeframe/read` | `domain` param required |
| Music on Hold | RingLogix | **Unknown** — no confirmed endpoint | Screenshots show MOH config; API availability TBD |
| Call History / CDRs | RingLogix | **NOT AVAILABLE**`cdr`, `call_detail_record`, `callhistory` all return 404 | Must use alternative source or NetSapiens CDR export |
| Call Recordings | RingLogix → Wasabi S3 | `s3:*` bucket policy for RingLogix IPs (192.92.8.0/24, 64.52.82.0/24, 64.52.83.0/24) | Portal would proxy through signed URLs |
| Billing / Invoices | RingLogix | **Unknown** — no confirmed billing API endpoint | Likely via RingLogix admin panel export or Stripe integration |
| Plans & Features | RingLogix / Manual | **Unknown** — no confirmed catalog API | Marketplace catalog maintained manually or via RingLogix reseller API |
| User Auth / RBAC | Custom (portal-local) | N/A — built in portal JS | No RingLogix customer-auth API; staff `info@voipsimplicity.com` hardcoded |
| E911 Inventory | RingLogix | **Unknown** — no confirmed endpoint | NetSapiens screenshots reference; API path TBD |
| SIP Trunks | RingLogix | **Unknown** — no confirmed endpoint | NetSapiens screenshots reference; API path TBD |
| Answer Rules | RingLogix | **Unknown** — no confirmed endpoint | NetSapiens screenshots reference; API path TBD |
| CNAM | RingLogix / ViiBE | **Unknown** — ViiBE screenshots show CNAM tab | API path and data model TBD |
**API base URL:** `https://api.ringlogix.com/pbx/v1/` (all calls POST with `object` and `action` in body — NOT RESTful GET).
**CRITICAL:** CDR/call-history, billing, and E911 endpoints are NOT available via the current RingLogix API. See [Unknowns & Caveats](#unknowns--caveats).
---
## RBAC, Tenant Isolation & Security
### Role Definitions
| Role | Access Scope | Auth Mechanism | Login Identifier |
|---|---|---|---|
| **IT Staff** | All 14 domains, all views, admin panel, audit log, domain selector | Hardcoded credentials: `info@voipsimplicity.com` + password | Email |
| **Customer Admin** | Single domain, all customer views, billing, add/remove authorized users | Domain ID or registered email + password | Domain ID, account email, or authorized-user email |
| **Authorized User** | Single domain, subset of views (no billing, no user management) — configurable by Customer Admin | Email + password, invited by Customer Admin | Authorized-user email |
| **View-Only User** | Single domain, read-only dashboard + call history | Email + password, invited by Customer Admin | Authorized-user email |
### Tenant Isolation Rules
- Every data query is scoped to `currentDomain` (customer) or selected domain (staff).
- Staff domain selector changes `currentDomain` and re-renders the active view — never leaks cross-domain data.
- Customer sessions are locked to a single domain ID returned on login.
- Staff audit log entries include `performedBy` (staff email), `domain` (affected domain), and `impersonated` flag if acting as customer.
### Security Constraints
- **Card data:** Never stored in browser session storage, `localStorage`, or cookies. Card updates go through a separate, secure payment-gateway path (Stripe Elements or equivalent hosted iframe).
- **Session tokens:** `sessionStorage` only — cleared on logout (`sessionStorage.clear() + location.reload()`).
- **No JWTs in URL:** Auth state never appears in query strings or URL fragments.
- **MFA recovery codes:** Generated server-side, shown once, never stored in browser.
- **Rate limiting:** Login attempts, MFA token requests, and password-reset requests rate-limited per IP and per account (5 attempts / 15 min window).
- **Password reset tokens:** Single-use, time-limited (15 min), delivered via email only (SMS fallback TBD per provider availability).
---
## Audit & Compliance
### Audit Trail Requirements
All state-changing operations produce immutable audit log entries:
| Operation | Audit Fields |
|---|---|
| Login/logout | `ts`, `user`, `role`, `domain`, `action`, `ip` (if available) |
| Marketplace add-on request | `ts`, `user`, `action:'addon_request'`, `domain`, `detail` (item name, extension, choice) |
| Plan change / upgrade | `ts`, `user`, `action:'plan_change'`, `domain`, `detail` (from → to plan) |
| Authorized user add/remove | `ts`, `user`, `action:'user_add'|'user_remove'`, `domain`, `detail` (affected user email + role) |
| Contact info update | `ts`, `user`, `action:'contact_update'`, `domain`, `detail` (changed fields, not values) |
| Payment method change | `ts`, `user`, `action:'payment_update'`, `domain` (no card details logged) |
| Password reset | `ts`, `user`, `action:'password_reset'`, `domain` |
| Staff domain switch | `ts`, `user`, `action:'domain_switch'`, `detail` (from → to domain) |
### Notification Rules
- All marketplace orders produce a notification (ticket-like) visible to staff.
- Authorized-user invitation emails are sent with a time-limited registration link.
- Password reset and MFA token delivery produce notifications with delivery method noted.
---
## Phased MVP Sequence
### Phase 1: Foundation (MVP Launch)
- Site login (split-half page, domain ID / email auth, password reset)
- My Dashboard (per-customer stats + lists, no topology graph)
- Call History (searchable, exportable — mock/placeholder data if CDR API unavailable)
- Nav: Dashboard, Call History, Billing (read-only), My Info (read-only)
### Phase 2: Self-Service
- My Info: editable contact info + payment method update (secure, separate path)
- Marketplace: catalog browsing, cart, per-extension vs per-account selection, immediate provisioning vs request-discussion choice
- Billing: invoice viewer, download, prior invoices list
- Authorized user management: add/remove with RBAC
### Phase 3: Advanced
- Graphical phone-system topology in Dashboard
- MFA / one-time token delivery (email/SMS)
- Recording playback in Call History (only if enabled)
- Voicemail inline in Call History
- Music on Hold, Time Frames displays
- Order-services contact form on login page
### Phase 4: Feature Parity
- E911 inventory display
- SIP trunk status
- Answer rules viewer
- CNAM management (if API available)
- Staff-only reports, LNP, number orders (ViiBE integration)
---
## Requirement Areas
### 1. My Dashboard
#### 1.1 Per-Customer Aggregate View
**Customer sees:**
| Metric | Data Source | Format |
|---|---|---|
| Total extensions | `subscriber/read` filtered to 100399 | Large stat card: "12 Extensions" |
| Call queues | `callqueue/read` count | Stat card: "3 Queues" |
| DID inventory | `phonenumber/read` filtered by `dialrule_domain` | Stat card: "5 Phone Numbers" |
| Auto attendants | `attendant/read` count | Stat card: "2 Attendants" |
| Subscribed plan | Manual / RingLogix catalog (TBD) | Badge: "Business Pro" |
**Staff sees (domain selector active):**
- Same metrics for the selected domain.
- Aggregate "All Domains" stats: total subscribers, DIDs, queues, attendants across all 14 domains.
#### 1.2 Detail Lists (Expandable Under Stats)
| List | Columns | Notes |
|---|---|---|
| Extensions | Name, Email, Extension #, Voicemail (badge) | Filtered to 100399. System routes hidden by toggle. |
| DIDs | Phone Number (formatted), Domain, Assigned Extension | Full DID list for domain. |
| Call Queues | Queue Name, Extension, Strategy (Linear Hunt, etc.), Members count | From `callqueue/read`. |
| Auto Attendants | Extension, Name, Schedule, Prompt Type | From `attendant/read`. Menu options NOT available via API — show note to use RingLogix admin. |
#### 1.3 Music on Hold
- **Data source:** Unknown endpoint. Screenshots (NetSapiens) show MOH configuration per domain.
- **Fallback:** Display "Configured via RingLogix Admin Panel" with a note until API endpoint is confirmed.
#### 1.4 Time Frames
- **Data source:** `timeframe/read` per domain.
- **Display:** Table of time frame names, schedules, and associated objects (attendants, routes).
- **Staff view:** Full edit capability (if API supports write), otherwise read-only with admin-panel link.
#### 1.5 Graphical Phone-System Topology (Phase 3)
- **Requirement:** Visual graph/flowchart showing:
- Inbound DID → Time Frame → Auto Attendant → Call Queue → Extensions
- Nodes color-coded by type (DID=gold, Attendant=blue, Queue=teal, Extension=green)
- Connected edges show full routing path
- **Rendering:** Canvas or SVG-based, mobile-responsive (scrollable on small screens).
- **Data:** Built from `phonenumber/read` (matchrule, dialrule_domain), `attendant/read` (timeframes, menus), `callqueue/read` (connect_to), `subscriber/read` relationships.
- **Note:** Menu-level routing (specific attendant option → extension) is NOT available via current API. Graph shows attendant → connected queues/extensions at the object level, not per-menu-option.
---
### 2. Call History
#### 2.1 Unified View
Single page merging incoming and outgoing calls — NOT separate "Call Logs" + "Recordings" tabs. Customers see one searchable list.
#### 2.2 Search
- **Searchable fields:** Caller name AND phone number.
- **Behavior:** `oninput` handler with no submit button. Real-time filtering across both inbound and outbound calls.
- **Implementation:** Single search box with `data-search` attribute on rows containing lowercase concatenation of caller name + phone number.
#### 2.3 Table Columns
| # | Column | Content | Notes |
|---|---|---|---|
| 1 | Date/Time | `YYYY-MM-DD HH:MM AM/PM` | Sortable |
| 2 | Direction | `↓ Incoming` (teal) or `↑ Outgoing` (gold) | Text label + arrow |
| 3 | Caller Name | Avatar circle + name | Unknown callers: gray "?" avatar + "Unknown" |
| 4 | Caller Phone | Formatted `(XXX) XXX-XXXX` | Muted secondary text |
| 5 | Destination | Extension number or queue name | Who handled the call |
| 6 | Status | Badge: Answered (teal), Missed (red), Voicemail (gray) | Color-coded |
| 7 | Voicemail | `📝 View Transcript` button or `—` | Opens modal with transcript text; only shown if call was missed → voicemail left |
| 8 | Recording | `▶ MM:SS` play button or `—` | **Only shown if recording is enabled for this domain/extension.** Inline playback. |
| 9 | Duration | `MM:SS` | Call duration |
#### 2.4 Recording Playback
- **Conditional:** Recording play button appears ONLY when recording is enabled. RingLogix recording toggle is per-domain or per-extension — portal must check this.
- **Playback:** Inline HTML5 `<audio>` or Web Audio API. Signed URLs from Wasabi S3 (proxy through portal or generate pre-signed URLs).
- **No download required:** Play in-page. Download button separate if needed.
#### 2.5 Export
- **"Export All":** Downloads entire call history dataset as CSV (all calls for the domain, unfiltered).
- **"Export Current View":** Downloads only the currently filtered/search-results as CSV.
- **Format:** Standard CSV with column headers matching table columns. Arrow characters cleaned: `↓``Incoming`, `↑``Outgoing`.
- **Implementation:** Build CSV string, create `Blob`, trigger download via temporary `<a>` element with `download` attribute.
#### 2.6 Data Source Caveat
**CDR endpoints all return 404** from RingLogix API (`cdr`, `call_detail_record`, `callhistory`). Until an alternative is found:
- **MVP fallback:** Placeholder/mock call data with clear labeling OR NetSapiens CDR export imported manually.
- **Target source:** NetSapiens CDR API (if RingLogix exposes it under a different object name), RingLogix reseller-level call reporting, or direct PBX CDR collection.
- **Recording source:** Wasabi S3 bucket (confirmed: RingLogix writes call recordings to Wasabi). Portal can list/stream recordings if bucket paths are structured by domain.
---
### 3. Marketplace
#### 3.1 Catalog & Cart
| Requirement | Detail |
|---|---|
| Plans/features browsing | Cards with plan name, price, included features, description |
| Cart metaphor | Add-on items collected in a running cart before submission |
| Per-extension vs per-account distinction | Each item tagged `perLine: true/false/'did'` |
| Per-extension selection | Modal with extension dropdown (100399) — user selects ONE, MULTIPLE (checkboxes), or ALL extensions |
| Per-DID selection | SMS/Text Messaging shows DID dropdown instead of extensions |
| Per-account items | No selector — applies to entire domain |
#### 3.2 Provisioning Choice
After selecting extensions/DIDs, user chooses:
| Option | Behavior |
|---|---|
| **Apply Now** *(Immediate Provisioning)* | If the applicable provider API supports the requested write action and the item is eligible for automation, provision the add-on immediately. Confirmation + audit log. |
| **Discuss with VoIPSimplicity** *(Request Discussion)* | Creates a ticket/order for staff review. Audit log entry. Notification to staff. |
**Note:** Immediate provisioning requires RingLogix write API access (not yet confirmed). Until confirmed, ALL additions default to "Request Discussion" flow.
#### 3.3 Audit, Ticket & Notification
- Every add-on request (immediate or discussion) produces:
1. **Audit log entry** with full detail (item, domain, extensions, provisioning choice).
2. **Staff-visible ticket** in Admin Panel → Audit Log tab.
3. **Confirmation notification** to the customer (on-screen success modal: "Our team will contact you within 24 hours.").
- Staff can view, approve, or reject requests.
#### 3.4 Approval Boundaries
| Item Type | Auto-Provision? | Requires Approval? |
|---|---|---|
| Per-account add-on (SMS, Analytics, DID, Fax, Priority Support) | No (Phase 2 target) | Yes — staff review |
| Per-extension add-on (Call Recording, Voicemail Transcription) | No (Phase 2 target) | Yes — staff review |
| Plan upgrade/downgrade | No | Yes — billing + provisioning review |
| International calling enablement | No | Yes — fraud review |
**Caveat:** Approval automation depends on RingLogix write API availability. Until confirmed, ALL changes go through manual staff review. This document must not claim RingLogix supports write endpoints that are unverified.
#### 3.5 Data-Source Caveat
The marketplace catalog (plans, add-ons, pricing) has no confirmed RingLogix API endpoint. Current implementation uses:
- **Hardcoded catalog** in portal JS (10 items with name, price, description, perLine flag).
- **Manual sync** from RingLogix reseller panel pricing.
- **Target:** RingLogix reseller catalog API (to be confirmed) or Stripe product catalog.
---
### 4. Billing
#### 4.1 Current Plan Summary
| Field | Data Source | Notes |
|---|---|---|
| Plan name | Hardcoded / RingLogix catalog | e.g., "Business Pro" |
| Plan price | Hardcoded / RingLogix | Monthly or annual |
| Included features | Hardcoded list | Teal "Active" badges |
| Available but unsubscribed options | Hardcoded list | Gray "Available" badges with "Add in Marketplace" link |
#### 4.2 Prior Invoices
| Column | Notes |
|---|---|
| Date | `YYYY-MM-DD` |
| Invoice Number | Unique identifier |
| Amount | Formatted currency |
| Status | Paid (teal), Pending (gold), Overdue (red) |
#### 4.3 Invoice Viewer
- **Inline framed viewer:** Opens an iframe/modal overlay showing the invoice PDF.
- **Closeable:** Close button, backdrop click, Escape key dismiss.
- **Download options:**
- Download individual invoice
- Download multiple (selected via checkboxes)
- Download all invoices
- **Data source caveat:** No confirmed RingLogix billing API. Invoice data likely from RingLogix admin panel export, Stripe billing portal, or manual upload.
#### 4.4 Payment Method
- **Separate, secure update path:** Card update form isolated from the main billing view.
- **Never stored in browser:** Card number, CVV, expiry never touch `sessionStorage`, `localStorage`, or in-memory JS objects longer than the update transaction.
- **Integration:** Stripe Elements (hosted iframe) or equivalent PCI-compliant solution. Portal sends a token, never raw card data.
- **Current implementation** (demo): `sessionStorage`-backed card display (`voip_cc`, `voip_cc_expiry`) — **NOT production-grade.** Migration to Stripe Elements required before go-live.
---
### 5. My Info
#### 5.1 Contact Information
| Field | Editable | Validation |
|---|---|---|
| Name | Yes | Required |
| Email (account) | Yes | Required, valid email format |
| Phone | Yes | Optional, US format |
| Address | Yes | Optional, street/city/state/ZIP |
| Company Name | No | Read-only, set at account creation |
| Domain ID | No | Read-only, displayed for reference |
**Edit pattern:** All fields disabled by default. "Edit" button toggles to "Cancel"; editable fields get teal border. "Save Changes" button appears during edit mode. Save writes to `currentUser` + `sessionStorage`, redraws header badge.
#### 5.2 Payment Method (Separate from Billing)
- **Update payment method:** Button opens a modal/section with secure card form (Stripe Elements).
- **Separate from Contact Info card:** Payment update is its own card/section, not mixed with personal info fields.
- **Card display in view mode:** `•••• 4242` (last 4 only) + expiry.
#### 5.3 Authorized Users
| Requirement | Detail |
|---|---|
| Add user | Customer Admin enters name, email, role (Authorized User / View-Only). Invitation email sent. |
| Manage users | Table of current authorized users: Name, Email, Role, Status (Active/Invited/Revoked). Revoke button. |
| RBAC | Per-user role controls which views are accessible (see [RBAC](#rbac-tenant-isolation--security)). |
| Invitation flow | Email with time-limited registration link → user sets password → added to domain. |
| Audit trail | All add/remove/role-change operations logged in audit. |
---
### 6. Site Login
#### 6.1 Split-Half Login Page
**Layout:**
- **LEFT (60% desktop, 100% mobile):** Navy gradient background. Login form: "Email or Domain ID" field + "Password" field + "Sign In" button + "Forgot Password?" link.
- **RIGHT (40% desktop, 100% mobile):** White/light background. "Need Help?" section: "Submit a Ticket" button (mailto:support@voipsimplicity.com), phone (888.601.1173), email (support@voipsimplicity.com), and order-services contact form.
- **Mobile (<768px):** Stack vertically — login on top, help/contact below.
#### 6.2 Authentication Methods
| Method | Identifier | Use Case |
|---|---|---|
| Domain ID | 6-digit numeric (e.g., `287275`) | Customer authenticates with their RingLogix domain ID + password |
| Account email | Registered email (e.g., `admin@grandlakeclub.com`) | Customer authenticates with account-level email |
| Authorized-user email | Individual user email (e.g., `deborah@grandlakeclub.com`) | Authorized users sign in with their own email |
| Staff email | `info@voipsimplicity.com` | IT staff — full admin access to all domains |
**Customer→domain mapping:** Real-time API lookup against RingLogix `domain/read` or a local domain-to-email mapping cache.
#### 6.3 Password Reset
- **Trigger:** "Forgot Password?" link on login page.
- **Flow:** Enter email or domain ID → email sent with single-use, time-limited (15 min) reset link → user sets new password → confirmation.
- **Rate limiting:** 3 reset requests per email per hour.
#### 6.4 MFA / One-Time Token (Phase 3)
| Aspect | Requirement |
|---|---|
| Delivery methods | Email (primary) + SMS (secondary, if provider supports) |
| Token lifetime | 5 minutes |
| Rate limiting | 5 attempts per 15 minutes per account |
| Recovery | Recovery codes generated on MFA enrollment (shown once, stored by user) |
| Exploration scope | Evaluate Twilio Verify, email OTP, and TOTP authenticator apps |
| Caveat | SMS delivery depends on Twilio number provisioning and A2P 10DLC registration |
#### 6.5 Order-Services Contact Form
- **Location:** Right panel of login page (below "Need Help?" section).
- **Fields:** Name, Email, Phone, Company, Service Interest (dropdown: New Phone System, Add Features, Porting Numbers, Other), Message.
- **Submission:** Emailed to `info@voipsimplicity.com` (or CRM integration). Confirmation message displayed.
- **Spam protection:** reCAPTCHA or honeypot field.
---
### 7. Screenshot-Informed Requirements
The owner provided screenshot groups from two platforms. These inform the portal's feature surface and data expectations but do NOT imply all features are available via API.
#### 7.1 ViiBE Seller-Side Views (Staff-Only)
| Screenshot Group | Portal Equivalent | API Availability |
|---|---|---|
| **Accounts** | Admin Panel → Domains list (already built: 14-domain roster with stats) | `domain/read` ✅ |
| **Quotes** | Marketplace → Quote requests / orders (staff review tab) | ❌ Unknown — RingLogix quoting API not confirmed |
| **Products** | Marketplace → Catalog management (staff) | ❌ Unknown — manual catalog in portal |
| **LNP (Local Number Porting)** | Admin Panel → Porting Status (staff) | ❌ Unknown — ViiBE LNP integration not confirmed for RingLogix |
| **Number Orders** | Admin Panel → Number Orders (staff) | ❌ Unknown — RingLogix number ordering API not confirmed |
| **CNAM** | Admin Panel → CNAM Management (staff) | ❌ Unknown — ViiBE screenshots show CNAM tab |
| **Mobile Connect** | Future: Mobile app pairing / softphone config | ❌ Not available via RingLogix API |
| **Reports** | Admin Panel → Reports (staff) | ⚠️ Partial — domain/subscriber/queue stats available; CDR reports NOT available |
#### 7.2 NetSapiens Customer/Manager Views
| Screenshot Group | Portal Equivalent | API Availability | Customer or Staff? |
|---|---|---|---|
| **Home / Statistics** | My Dashboard (stats + lists) | ✅ `subscriber/read`, `callqueue/read`, etc. | Customer |
| **Domains** | Admin Panel (staff domain selector) | ✅ `domain/read` | Staff |
| **SIP Trunks** | Dashboard → SIP Trunks card (Phase 4) | ❌ Unknown — no confirmed RingLogix endpoint | Customer/Staff |
| **Phone Inventory** | Dashboard → DIDs list | ✅ `phonenumber/read` (filter client-side) | Customer |
| **E911 Inventory** | Dashboard → E911 card (Phase 4) | ❌ Unknown — no confirmed RingLogix endpoint | Customer/Staff |
| **Call History** | Call History view | ❌ CDR endpoints all return 404 | Customer |
| **Contacts** | Future: Personal/speed-dial contacts | ❌ Not available via RingLogix API | Customer |
| **Answer Rules** | Extensions → Answer Rules tab (Phase 4) | ❌ Unknown — no confirmed RingLogix endpoint | Customer |
| **Time Frames** | Dashboard → Time Frames list | ✅ `timeframe/read` | Customer |
| **User Voicemail / Settings** | Voicemail view | ✅ `subscriber/read` (vmail fields) | Customer |
| **Music / Messages** | Dashboard → Music on Hold (Phase 3) | ❌ Unknown — no confirmed endpoint | Customer/Staff |
| **Call-Center Queues / Statistics** | Call Queues view + Dashboard stats | ✅ `callqueue/read` (queue list; real-time stats unknown) | Customer/Staff |
| **Auto Attendants** | Auto Attendants view | ✅ `attendant/read` (object list; menu detail NOT available) | Customer |
**Key:** ✅ Available | ⚠️ Partial | ❌ Unknown/Unavailable | 🔮 Future
---
## Nav Organization (Expanded Canonical)
Based on the existing portal skill's nav structure, expanded for the full requirement set:
```
Main
Dashboard # Per-customer stats, lists, topology (Phase 3)
Phone System
Extensions # List + detail: 100-399 users, voicemail status
Call History # Unified incoming/outgoing, search, export, recordings
Call Queues # Queue list, members, strategy
Auto Attendants # Attendant list, schedules, prompts
Voicemail # Voicemail messages, settings, transcription
Account
Billing # Plan, invoices, invoice viewer, payment method
Marketplace # Plans catalog, cart, add-on requests
My Info # Contact info, payment method, authorized users
Administration (staff only — hidden for customers)
Admin Panel # Domain selector, domain roster, audit log
Reports # Staff reports (Phase 4)
Number Orders # DIDs, LNP, CNAM (Phase 4)
```
---
## Acceptance Criteria by Phase
### Phase 1: Foundation
- [ ] Login page renders split-half layout; mobile stacks vertically.
- [ ] Customer can log in with domain ID (e.g., `287275`), account email, or authorized-user email.
- [ ] Staff can log in with `info@voipsimplicity.com` and see domain selector.
- [ ] Refresh/back button does NOT log out (sessionStorage persistence).
- [ ] Dashboard shows per-customer aggregate stats (extensions, queues, DIDs, attendants) — filtered to real extensions (100399).
- [ ] Dashboard extension list shows Name, Email, voicemail badge.
- [ ] Dashboard DID list, queue list, attendant list render with correct data.
- [ ] Call History table renders with search (if CDR data unavailable: clear "No data available — Call history coming soon" empty state).
- [ ] Navigation toggles active state; customer never sees Admin nav items.
- [ ] Domain selector hidden for customer-role users.
- [ ] All unwired views show canonical "No data available." empty state with RingLogix API note.
### Phase 2: Self-Service
- [ ] My Info: Name, Email, Phone editable with Edit/Save/Cancel pattern.
- [ ] Payment method: secure Stripe Elements form, card data never in browser storage.
- [ ] Authorized users: add/remove with RBAC, invitation email, audit log.
- [ ] Marketplace: catalog cards render with per-extension vs per-account distinction.
- [ ] Marketplace: extension/DID selector modal for per-line items (one, multiple, all).
- [ ] Marketplace: immediate provisioning vs request-discussion radio choice.
- [ ] Marketplace: all requests produce audit entry + staff notification.
- [ ] Billing: invoice list with date, number, amount, status.
- [ ] Billing: inline framed invoice viewer with close/ESC dismiss.
- [ ] Billing: download individual, multiple (checkbox-select), or all invoices.
### Phase 3: Advanced
- [ ] Graphical phone-system topology in Dashboard (DID → TF → AA → Queue → Ext).
- [ ] MFA enrollment flow with email OTP (SMS optional).
- [ ] Call History: recording playback (only when recording enabled).
- [ ] Call History: voicemail transcript inline.
- [ ] Dashboard: Music on Hold display.
- [ ] Dashboard: Time Frames list with schedules.
- [ ] Order-services contact form on login page.
### Phase 4: Feature Parity
- [ ] E911 inventory display.
- [ ] SIP trunk status.
- [ ] Answer rules viewer.
- [ ] CNAM management (if API available).
- [ ] Staff reports (aggregate call stats, domain comparisons).
- [ ] LNP porting status.
- [ ] Number orders.
---
## Unknowns & Caveats
### Confirmed Unavailable
| Feature | Detail | Impact |
|---|---|---|
| CDR / Call History API | `cdr`, `call_detail_record`, `callhistory` all return 404 | Call History requires alternative data source |
| Auto Attendant menu details | `attendant/read` returns object metadata but NOT per-option menu routing | Attendant detail view limited to name, schedule, prompt type |
| DID domain filtering | `phonenumber/read` ignores `domain` param — returns all DIDs across all domains | Client-side filtering required |
### Unconfirmed / Needs Investigation
| Feature | What to Verify | Priority |
|---|---|---|
| Billing/invoice API | Contact RingLogix: is there a billing API or reseller invoice endpoint? | High |
| Marketplace catalog API | Is there a reseller product catalog? If not, maintain hardcoded catalog synced manually. | High |
| Write API (provisioning) | Can add-ons be provisioned via API? `object=subscriber&action=update`? | High |
| Music on Hold endpoint | Is there an `musiconhold` or `moh` object? Test known NetSapiens object names. | Medium |
| E911 endpoint | Is there an `e911` or `emergency` object? | Medium |
| SIP trunk endpoint | Is there a `siptrunk` or `trunk` object? | Medium |
| Answer rules endpoint | Is there an `answerrule` or `callforward` object? | Medium |
| CNAM endpoint | ViiBE screenshots show CNAM tab — is this a ViiBE-only feature or available via RingLogix? | Medium |
| OAuth scope grants | Read endpoints may need scope grants from RingLogix support (Hussain Alkalaf, hussain@ringlogix.com, 440-382-3223) | Medium |
| Rate limiting | 429 observed — current sync script uses 0.5s delay. Portal must match. | Low |
### Design Constraints (from Owner)
- **Light/neutral theme ONLY** — white/light gray backgrounds, dark text. No dark mode for customer-facing portal.
- **Mobile-first** — all views must be usable on ≤375px screens.
- **No framework dependencies** — single-file HTML SPA, no React/Vue/Angular.
- **Google Fonts (Inter) only external dependency.**
- **No fabricated data** — every unwired view shows canonical "No data available." empty state.
- **Canonical nav** — sidebar with `data-view` attributes, `switchView()` dispatch.
---
## Out of Scope (Deferred to Post-MVP)
| Feature | Reason |
|---|---|
| AI Receptionist integration | Separate product (see [ai-receptionist.md](./ai-receptionist.md)), not portal-bound |
| Twilio call handling | Twilio setup is infrastructure, not portal feature |
| Competitor price monitoring | Covered in [competitor-analysis.md](./competitor-analysis.md) — not portal feature |
| WordPress marketing site | `voipsimplicity.com` is a separate WordPress site, out of portal scope |
| Full RingLogix admin replacement | Portal is customer-facing + staff review, NOT a full admin panel replacement |
| International numbers / multi-currency | US-only for MVP |
| Developer APIs / webhooks | Post-MVP |
| White-label reskinning | Post-MVP |
| Mobile native app | Web-only SPA for MVP; PWA wrapper considered for Phase 4 |
---
*Document maintained in `/root/projects/voipsimplicity/PORTAL-REQUIREMENTS.md`. Companion gap analysis at [PORTAL-GAP-ANALYSIS.md](./PORTAL-GAP-ANALYSIS.md).*