Data Flows
This section details the critical paths data takes through the BSS stack.
1. CRM Subscriber Provisioning (gRPC)
When a telco administrator creates a new subscriber in the crm2 dashboard, the following sequence occurs:
sequenceDiagram
participant Admin as Operator (Web UI)
participant CRM2 as crm2.micro.bss (PHP)
participant gRPC as CRMServer (C++)
participant DB as DB_layer (C++)
participant MySQL as MySQL Database
Admin->>CRM2: POST /subscriber/new (Form Data)
CRM2->>CRM2: Validate form & create JWT
CRM2->>gRPC: AddSubscriber(Subscriber proto) + JWT
gRPC->>gRPC: auth_interceptor validates JWT
gRPC->>DB: DB_layer::insert(billing::Subscriber)
DB->>MySQL: INSERT INTO subscribers ...
MySQL-->>DB: Success (ID)
DB-->>gRPC: Return 0
gRPC-->>CRM2: CRMResponse(status: ACK_OK)
CRM2-->>Admin: HTTP 200 (Success Toast)
Security Notice
All gRPC calls from the CRM to the C++ Server must be signed with a JWT indicating an authorized admin user. The auth_interceptor.hpp validates the token before CRMServiceImpl executes any logic.
2. Real-Time Prepaid Charging (DIAMETER)
This scenario occurs when a prepaid subscriber initiates a mobile data session or a voice call.
sequenceDiagram
participant NE as Network Element (GGSN)
participant DIA as PrepaidServer (DIAMETER)
participant Charge as BalanceReserve / Charge
participant DB as DB_layer
%% INITIAL PHASE
NE->>DIA: CCR (INITIAL)
DIA->>Charge: fromCCR(ccr)
Charge->>DB: has_balance()
DB-->>Charge: true
Charge->>DB: reserve_balance(amount)
DIA-->>NE: CCA (GRANTED_UNITS)
%% UPDATE PHASE
loop While Session Active
NE->>DIA: CCR (UPDATE)
DIA->>Charge: Update usage / Request more
Charge->>DB: deduct_used() & reserve_new()
DIA-->>NE: CCA (GRANTED_UNITS)
end
%% TERMINATION PHASE
NE->>DIA: CCR (TERMINATE)
DIA->>Charge: Calculate final_price
Charge->>DB: debit_balance(final_price)
Charge->>DB: db_insert(Charge proto)
DIA-->>NE: CCA (2001 SUCCESS)
Balance Preconditions
Before authorizing any granted units, the system must invoke Subscriber::has_balance() and successfully execute DB_layer::reserve_balance. If this fails, a DIAMETER_CREDIT_LIMIT_REACHED (4012) CCA is returned, immediately terminating the network session.
3. Offline Postpaid Billing (CDR Loader)
For postpaid accounts, or flat-file scenarios, the server asynchronously polls a directory.
sequenceDiagram
participant Cron as ACE Reactor Timer
participant Loader as CDRLoader
participant Rater as Rater
participant DB as DB_layer
Cron->>Loader: handle_timeout()
Loader->>Loader: Scan /new_cdr directory
loop For each CDR file via std::filesystem
Loader->>Loader: Read and deserialize() CDR
Loader->>Loader: validate() CDR
Loader->>Rater: pre_rate()
Rater->>DB: Get Price Plan & Rates
Loader->>Rater: rate(CDR)
Loader->>Rater: post_rate()
Loader->>DB: DB_layer::insert(CDR)
Loader->>Loader: rename() file to /processed_cdr (or /error_cdr on failure)
end
4. Asynchronous Invoice Generation
When a bill run creates NEW bills, an asynchronous background task orchestrates PDF conversion without blocking the main event loops.
sequenceDiagram
participant Timer as ACE Reactor Timer
participant Handler as BillFormatterHandler
participant Inja as Inja Template Engine
participant Pluto as Plutobook (litehtml)
participant FS as File System
Timer->>Handler: handle_timeout()
Handler->>Handler: Scan DB for NEW bills
loop For each NEW bill
Handler->>Inja: inject pre-formatted context (month, year, amounts)
Inja->>Handler: render HTML string
Handler->>Pluto: load_html() & apply print CSS
Pluto->>Handler: render_pdf()
Handler->>FS: write to ./invoices/{year}/{month}/{type}/...
end