mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-20 20:04:24 +00:00
feat: Add MVNO onboarding validator with business, plan, and technical validation
- Add OnboardingValidator struct with ValidateRequest and ValidateMVNO methods in validator.go - Add business info validation with name length, ID format, email regex, and phone length checks - Add plan validation with subscriber limits for Starter (1000) and Growth (10000) plans - Add technical requirements validation with country code format and use case length checks - Add compliance validation with country-specific regulatory checks and restricted country filtering - Add technical feasibility validation
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
package mvno
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// OnboardingValidator validates MVNO onboarding requests and configurations
|
||||
type OnboardingValidator struct {
|
||||
logger *logrus.Logger
|
||||
}
|
||||
|
||||
// NewOnboardingValidator creates a new validator instance
|
||||
func NewOnboardingValidator(logger *logrus.Logger) *OnboardingValidator {
|
||||
return &OnboardingValidator{logger: logger}
|
||||
}
|
||||
|
||||
// ValidateRequest validates the initial onboarding request
|
||||
func (v *OnboardingValidator) ValidateRequest(req *OnboardingRequest) error {
|
||||
if err := v.validateBusinessInfo(req); err != nil {
|
||||
return fmt.Errorf("business validation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := v.validatePlan(req); err != nil {
|
||||
return fmt.Errorf("plan validation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := v.validateTechnicalRequirements(req); err != nil {
|
||||
return fmt.Errorf("technical validation failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateMVNO performs comprehensive MVNO validation
|
||||
func (v *OnboardingValidator) ValidateMVNO(ctx context.Context, mvno *MVNO) error {
|
||||
// Validate business registration
|
||||
if err := v.validateBusinessRegistration(mvno.BusinessID); err != nil {
|
||||
return fmt.Errorf("business registration validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate compliance requirements
|
||||
if err := v.validateCompliance(ctx, mvno); err != nil {
|
||||
return fmt.Errorf("compliance validation failed: %w", err)
|
||||
}
|
||||
|
||||
// Validate technical feasibility
|
||||
if err := v.validateTechnicalFeasibility(mvno); err != nil {
|
||||
return fmt.Errorf("technical feasibility validation failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateBusinessInfo validates business information
|
||||
func (v *OnboardingValidator) validateBusinessInfo(req *OnboardingRequest) error {
|
||||
if len(req.BusinessName) < 3 {
|
||||
return fmt.Errorf("business name must be at least 3 characters")
|
||||
}
|
||||
|
||||
if !v.isValidBusinessID(req.BusinessID) {
|
||||
return fmt.Errorf("invalid business ID format")
|
||||
}
|
||||
|
||||
if !v.isValidEmail(req.ContactEmail) {
|
||||
return fmt.Errorf("invalid contact email format")
|
||||
}
|
||||
|
||||
if len(req.ContactPhone) < 10 {
|
||||
return fmt.Errorf("contact phone must be at least 10 digits")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePlan validates the selected plan
|
||||
func (v *OnboardingValidator) validatePlan(req *OnboardingRequest) error {
|
||||
validPlans := []MVNOPlan{PlanStarter, PlanGrowth, PlanScale, PlanEnterprise}
|
||||
isValid := slices.Contains(validPlans, req.Plan)
|
||||
if !isValid {
|
||||
return fmt.Errorf("invalid plan selected")
|
||||
}
|
||||
|
||||
if req.EstimatedSubs < 1 {
|
||||
return fmt.Errorf("estimated subscribers must be at least 1")
|
||||
}
|
||||
|
||||
// Validate plan-specific requirements
|
||||
switch req.Plan {
|
||||
case PlanStarter:
|
||||
if req.EstimatedSubs > 1000 {
|
||||
return fmt.Errorf("starter plan limited to 1000 subscribers")
|
||||
}
|
||||
case PlanGrowth:
|
||||
if req.EstimatedSubs > 10000 {
|
||||
return fmt.Errorf("growth plan limited to 10000 subscribers")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateTechnicalRequirements validates technical requirements
|
||||
func (v *OnboardingValidator) validateTechnicalRequirements(req *OnboardingRequest) error {
|
||||
if len(req.TargetCountries) == 0 {
|
||||
return fmt.Errorf("at least one target country must be specified")
|
||||
}
|
||||
|
||||
if len(req.UseCase) < 10 {
|
||||
return fmt.Errorf("use case description too short")
|
||||
}
|
||||
|
||||
// Validate country codes
|
||||
for _, country := range req.TargetCountries {
|
||||
if len(country) != 2 {
|
||||
return fmt.Errorf("invalid country code format: %s", country)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateBusinessRegistration validates business registration
|
||||
func (v *OnboardingValidator) validateBusinessRegistration(businessID string) error {
|
||||
// In production, this would validate against business registry
|
||||
// For now, basic format validation
|
||||
if len(businessID) < 8 {
|
||||
return fmt.Errorf("business ID too short")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateCompliance validates regulatory compliance
|
||||
func (v *OnboardingValidator) validateCompliance(ctx context.Context, mvno *MVNO) error {
|
||||
// Check regulatory compliance for target countries
|
||||
for _, country := range mvno.Config.AllowedCountries {
|
||||
if err := v.checkCountryCompliance(country); err != nil {
|
||||
return fmt.Errorf("compliance check failed for %s: %w", country, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateTechnicalFeasibility validates technical implementation feasibility
|
||||
func (v *OnboardingValidator) validateTechnicalFeasibility(mvno *MVNO) error {
|
||||
// Validate carrier availability for target countries
|
||||
for _, country := range mvno.Config.AllowedCountries {
|
||||
if !v.hasCarrierCoverage(country) {
|
||||
return fmt.Errorf("no carrier coverage available for %s", country)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isValidBusinessID validates business ID format
|
||||
func (v *OnboardingValidator) isValidBusinessID(id string) bool {
|
||||
// Basic validation - alphanumeric with possible hyphens
|
||||
matched, _ := regexp.MatchString(`^[A-Za-z0-9\-]{8,}$`, id)
|
||||
return matched
|
||||
}
|
||||
|
||||
// isValidEmail validates email format
|
||||
func (v *OnboardingValidator) isValidEmail(email string) bool {
|
||||
matched, _ := regexp.MatchString(`^[^\s@]+@[^\s@]+\.[^\s@]+$`, email)
|
||||
return matched
|
||||
}
|
||||
|
||||
// checkCountryCompliance checks if country is compliant
|
||||
func (v *OnboardingValidator) checkCountryCompliance(country string) error {
|
||||
// In production, this would check regulatory requirements
|
||||
// For now, basic validation
|
||||
restricted := []string{"XX", "YY"} // Example restricted countries
|
||||
if slices.Contains(restricted, strings.ToUpper(country)) {
|
||||
return fmt.Errorf("country not supported")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// hasCarrierCoverage checks if carrier coverage exists
|
||||
func (v *OnboardingValidator) hasCarrierCoverage(country string) bool {
|
||||
// In production, this would check carrier availability
|
||||
// For now, assume most countries have coverage
|
||||
supported := []string{"US", "GB", "DE", "FR", "JP", "AU", "CA"}
|
||||
return slices.Contains(supported, strings.ToUpper(country))
|
||||
}
|
||||
Reference in New Issue
Block a user