You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.2 KiB
9.2 KiB
Architectural Overview
This document describes the architecture of the ngcp-csc-ui project (Customer Self-Care Web Interface).
High-level summary
- SPA built with Vue 2 + Quasar (see
package.json). - Migration to Vue 3 was started but was left unfinished.
- Uses Vuex 4 for centralized state management (
src/store/index.js+ many modules undersrc/store/). - Communicates with a REST backend via an axios wrapper in
src/api/common.js. - Integrates real-time VoIP (SIP) using JsSIP over WebSocket (see
src/api/ngcp-call.jsandsrc/boot/ngcp-call.js). - Internationalization via
vue-i18nwith boot registration insrc/boot/i18n.js. - Local persistence uses Quasar
LocalStorage/SessionStoragehelper insrc/storage.js.
Build and runtime
- Project scripts are defined in
package.json. Development:quasar dev. Production build:quasar build. - App configuration (base HTTP/WS URLs) is provided via
src/config/app.template.js/src/config/app.template.root.jsand runtime-injectedappConfig(used insrc/boot/ngcp-call.jsandsrc/boot/api.js).
Application structure
src/contains the application source.App.vue: root component.boot/: Quasar boot files that initialize global subsystems (store, i18n, API client, SIP integration). Note: The latest Quasar has dropped support for Vuex. We can still use Vuex as any Vue plugin, but we have to manage everything (installing the store, no store parameter in boot files, etc.). Notable files:src/boot/api.js— initializes API base URL by callinginitAPIfromsrc/api/common.js.src/boot/ngcp-call.js— wires the JsSIP-based call module into the store and configures the WebSocket URL used for SIP registration.src/boot/i18n.js— creates and registersvue-i18nand watches for language changes to reload language-dependent store data.src/boot/store.js— creates and registers the Vuex store instance with the app.
store/: Vuex modules (split by feature). The store is assembled insrc/store/index.jsand has modules such ascall,conversations,pbx*,user,communication,fax,voicebox, etc.api/: small wrappers for domain APIs and a robust HTTP API layer insrc/api/common.js.router/: route definitions and meta configuration insrc/router/routes.js.components/,pages/,layouts/: UI building blocks and pages organized by feature.assets/,helpers/,mixins/,validators/: supporting libraries and utilities.
HTTP API layer (src/api/common.js)
- Single axios instance
httpApiwith defaults and request/response handling. - Request configuration helpers for GET/POST/PUT/PATCH/DELETE with consistent headers (Content-Type, Prefer, Accept) and helper functions
getList,get,post,put,del,apiGet,apiPost,apiDownloadFile, etc. - Adds Authorization header automatically when a JWT is present (uses
src/auth.jshelpers which read JWT fromsrc/storage.js). - Centralized error handling in
handleResponseErrorthat translates some backend error codes/messages into UI actions (for example, password expired redirects toPATH_CHANGE_PASSWORD— route defined insrc/router/routes.js). - Utilities:
normalizeEntityremoves HAL_links,getJsonBody(insrc/api/utils.js) ensures JSON bodies are parsed.
Contract of API functions:
- Inputs: high-level options objects describing resource/path/params/body.
- Outputs: parsed JSON entities, blobs, or identifiers.
- Errors: throws
ApiResponseErrorwithcodeandmessagewhen backend returns structured errors; otherwise rethrows network/axios errors.
Authentication and storage
- JWT is stored in LocalStorage via
src/storage.jsandsrc/auth.jsprovidesgetJwt,hasJwt,setJwt,deleteJwt. src/api/common.jsattachesAuthorization: Bearer <jwt>automatically when present.
Real-time VoIP integration (JsSIP)
- The app integrates SIP over WebSocket using JsSIP (package
jssip, referenced inpackage.json). - Core SIP logic implemented in
src/api/ngcp-call.js:- Manages a JsSIP UA and WebSocket interface to Kamailio (or other SIP-over-WS proxy).
- Configures PC/RTCP/ICE options and handles trickle ICE via SIP INFO (sends/receives
application/trickle-ice-sdpfrag). - Emits domain events through an EventEmitter
callEventfor the rest of the app to react to (incoming calls, remote/local streams, ICE events, registration state). - Exposes functions:
callConfigure,callInitialize,callRegister,callUnregister,callStart,callAccept,callSendVideo,callGetRemoteMediaStream, etc.
- Boot file
src/boot/ngcp-call.jscallscallConfigurewithbaseWebSocketUrlbuilt fromapp.config.globalProperties.$appConfig.baseWsUrland registers handlers that commit or dispatch Vuex store mutations/actions. callEventis used in boot to updatecallstore state (e.g.,store.commit('call/enableCall'),store.commit('call/establishCall', {...})). Seesrc/boot/ngcp-call.js.
VoIP notes and constraints:
- SIP credentials (subscriber username/password) are supplied at runtime via the
callInitializeflow (seecallInitializeinsrc/api/ngcp-call.js). - Trickle ICE is implemented by sending ICE candidates over SIP INFO messages, and parsing incoming SDP fragments to add candidates to the current PeerConnection.
- Media is handled via WebRTC getUserMedia, MediaStream tracks, transceivers and explicit renegotiation.
- Limitations:
- Currently only one active call is supported at a time and video can be toggled only after the call has started.
- Video and screen sharing cannot be used simultaneously.
Routing and navigation
- Routes are declared in
src/router/routes.jsand use meta fields extensively to provide titles, subtitles, required licenses, features, and permissions such asadminOnly. - The root route base path is
/userand many feature pages live under it (dashboard, conversations, pbx settings, phonebooks, etc.). App.vuereads route meta to set the page title.- See document Router Navigation Guard for details on adding new pages and menu items.
State management (Vuex)
- The store is modular: each major feature has its own Vuex module under
src/store/(e.g.,call.js,conversations.js,pbx-*,user.js,communication.js). - The store factory is in
src/store/index.jsand is bootstrapped viasrc/boot/store.js. - The store contains some global getters for formatted dates, and actions for language reloads that can refresh language-dependent data.
Internationalization
- Implemented with
vue-i18n(src/boot/i18n.js) and messages are loaded fromsrc/i18n. - Store watches
i18n.localeto triggerreloadLanguageRelatedDataaction that refreshes data dependent on UI language (seesrc/store/index.jsactionreloadLanguageRelatedData).
Frontend UI patterns
- Quasar UI components are used across the app.
- The code follows a feature-based organization: pages, components, and store modules are grouped by feature (e.g., PBX, call features, phonebook).
- Reusable components and dialogs live in
src/components/.
Deployment and environment
- The app is built with Quasar using the Webpack-based CLI (the project depends on
@quasar/app-webpack), running thequasar buildscript (npm run build/yarn build) produces a production bundle. - Runtime configuration for backend endpoints (HTTP + WebSocket) is provided by
src/config/app.template.jsandsrc/config/app.template.root.js. These templates are used and can be manipulated at runtime by helper scripts such asbin/config-create.sh/bin/config-create.jsandenv/run_csc_ui. - Docker helper artifacts exist in the repo (
env/Dockerfile,bin/run-docker.sh) and there are package scripts that assist with Docker-related tasks (for exampledev:docker,docker:rebuild:local,docker:run:localinpackage.json).
Observability, errors and edge cases
- API errors are normalized in
src/api/common.jsand some server-side codes are translated into user-friendly messages (viai18n) or cause navigation changes (expired password -> change password route). - Network interruptions in WebSocket/SIP are handled by JsSIP events (
connected,disconnected,registrationFailed) and propagated to the store viacallEventhandlers insrc/boot/ngcp-call.js. - Local storage keys are all prefixed (
csc_) bysrc/storage.js.
Security considerations
- Currently, JWT tokens are used for HTTP requests and stored in LocalStorage. This is convenient but exposes tokens to XSS; review needed if stronger protection is required (HttpOnly cookies, refresh tokens).
- SIP credentials (password) are passed into JsSIP configuration at runtime — ensure transport is over wss (the code uses
baseWsUrlprefixed withwss://).
Key files (quick reference)
- App entry and boots:
src/App.vue,src/boot/api.js,src/boot/ngcp-call.js,src/boot/i18n.js,src/boot/store.js. - API core:
src/api/common.js,src/api/utils.js. - SIP/VoIP integration:
src/api/ngcp-call.js. - Routing:
src/router/routes.js. - Store:
src/store/index.jsand modules undersrc/store/. - Storage helpers:
src/storage.js. - Config templates:
src/config/app.template.js,src/config/app.template.root.js.