CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-binarywang--weixin-java-miniapp

Comprehensive Java SDK for WeChat MiniApp development with complete platform integration

Pending
Overview
Eval results
Files

analytics.mddocs/

Analytics

Comprehensive analytics and data insights including user trends, visit patterns, retention analysis, user demographics, and performance metrics for WeChat MiniApp data-driven decision making.

Capabilities

Analytics Service Interface

Core analytics operations providing detailed insights into mini program usage and user behavior.

public interface WxMaAnalysisService {
    // Overview Trends
    List<WxMaSummaryTrend> getDailySummaryTrend(Date beginDate, Date endDate) throws WxErrorException;
    
    // Visit Trends  
    List<WxMaVisitTrend> getDailyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
    List<WxMaVisitTrend> getWeeklyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
    List<WxMaVisitTrend> getMonthlyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
    
    // User Analysis
    WxMaVisitDistribution getVisitDistribution(Date beginDate, Date endDate) throws WxErrorException;
    WxMaRetainInfo getDailyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
    WxMaRetainInfo getWeeklyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
    WxMaRetainInfo getMonthlyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
    
    // Page Analysis
    List<WxMaVisitPage> getVisitPage(Date beginDate, Date endDate) throws WxErrorException;
    
    // User Demographics
    WxMaUserPortrait getUserPortrait(Date beginDate, Date endDate) throws WxErrorException;
}

Analytics Data Models

Comprehensive data models for different types of analytics and metrics.

public class WxMaSummaryTrend implements Serializable {
    private String refDate;         // Reference date (YYYYMMDD format)
    private Integer visitTotal;     // Total visits
    private Integer shareUv;        // Unique users who shared
    private Integer sharePv;        // Total shares
    
    // Getters and setters
    public String getRefDate();
    public void setRefDate(String refDate);
    public Integer getVisitTotal();
    public void setVisitTotal(Integer visitTotal);
    public Integer getShareUv();
    public void setShareUv(Integer shareUv);
    public Integer getSharePv();
    public void setSharePv(Integer sharePv);
    
    // Utility methods
    public Date getRefDateAsDate();
    public static WxMaSummaryTrend fromJson(String json);
    public String toJson();
}
public class WxMaVisitTrend implements Serializable {
    private String refDate;         // Reference date
    private Integer sessionCnt;     // Session count
    private Integer visitPv;        // Page views
    private Integer visitUv;        // Unique visitors
    private Integer visitUvNew;     // New unique visitors
    private Float stayTimeUv;       // Average stay time per user
    private Float stayTimeSession; // Average stay time per session
    private Float visitDepth;       // Average visit depth
    
    // Getters and setters
    public String getRefDate();
    public void setRefDate(String refDate);
    public Integer getSessionCnt();
    public void setSessionCnt(Integer sessionCnt);
    public Integer getVisitPv();
    public void setVisitPv(Integer visitPv);
    public Integer getVisitUv();
    public void setVisitUv(Integer visitUv);
    public Integer getVisitUvNew();
    public void setVisitUvNew(Integer visitUvNew);
    public Float getStayTimeUv();
    public void setStayTimeUv(Float stayTimeUv);
    public Float getStayTimeSession();
    public void setStayTimeSession(Float stayTimeSession);
    public Float getVisitDepth();
    public void setVisitDepth(Float visitDepth);
    
    // Utility methods
    public Date getRefDateAsDate();
    public static WxMaVisitTrend fromJson(String json);
}
public class WxMaVisitDistribution implements Serializable {
    private String refDate;                     // Reference date
    private List<AccessSource> accessSource;    // Traffic sources
    
    public static class AccessSource {
        private String accessSourceName;        // Source name
        private Integer accessSourceVisitUv;    // Unique visitors from source
        
        public String getAccessSourceName();
        public void setAccessSourceName(String accessSourceName);
        public Integer getAccessSourceVisitUv();
        public void setAccessSourceVisitUv(Integer accessSourceVisitUv);
    }
    
    // Getters and setters
    public String getRefDate();
    public void setRefDate(String refDate);
    public List<AccessSource> getAccessSource();
    public void setAccessSource(List<AccessSource> accessSource);
}
public class WxMaRetainInfo implements Serializable {
    private String refDate;                 // Reference date
    private List<RetainInfo> visitRetainInfo; // Retention data
    
    public static class RetainInfo {
        private Integer key;                // Day offset (0, 1, 2, 3...)
        private Float value;               // Retention rate (0-1)
        
        public Integer getKey();
        public void setKey(Integer key);
        public Float getValue();
        public void setValue(Float value);
    }
    
    // Getters and setters
    public String getRefDate();
    public void setRefDate(String refDate);
    public List<RetainInfo> getVisitRetainInfo();
    public void setVisitRetainInfo(List<RetainInfo> visitRetainInfo);
    
    // Convenience methods
    public Float getRetentionRate(int dayOffset);
    public Map<Integer, Float> getRetentionMap();
}
public class WxMaVisitPage implements Serializable {
    private String refDate;             // Reference date
    private String pagePath;            // Page path
    private Integer visitPv;            // Page views
    private Integer visitUv;            // Unique visitors
    private Float stayTimeUv;           // Average stay time per user
    private Float entryPagePv;          // Entry page views
    private Float exitPagePv;           // Exit page views
    private Float shareUv;              // Share unique users
    private Float sharePv;              // Share page views
    
    // Getters and setters
    public String getRefDate();
    public void setRefDate(String refDate);
    public String getPagePath();
    public void setPagePath(String pagePath);
    public Integer getVisitPv();
    public void setVisitPv(Integer visitPv);
    public Integer getVisitUv();
    public void setVisitUv(Integer visitUv);
    public Float getStayTimeUv();
    public void setStayTimeUv(Float stayTimeUv);
    public Float getEntryPagePv();
    public void setEntryPagePv(Float entryPagePv);
    public Float getExitPagePv();
    public void setExitPagePv(Float exitPagePv);
    public Float getShareUv();
    public void setShareUv(Float shareUv);
    public Float getSharePv();
    public void setSharePv(Float sharePv);
}
public class WxMaUserPortrait implements Serializable {
    private String refDate;             // Reference date
    private List<VisitUvNew> visitUvNew; // New user demographics
    
    public static class VisitUvNew {
        private Integer index;          // Index identifier
        private String province;        // Province
        private String city;           // City
        private Integer genders;       // Gender (0: unknown, 1: male, 2: female)
        private String platforms;      // Platform (iPhone, Android, etc.)
        private String devices;        // Device model
        private String ages;           // Age range
        private Integer value;         // User count
        
        // Getters and setters
        public Integer getIndex();
        public void setIndex(Integer index);
        public String getProvince();
        public void setProvince(String province);
        public String getCity();
        public void setCity(String city);
        public Integer getGenders();
        public void setGenders(Integer genders);
        public String getPlatforms();
        public void setPlatforms(String platforms);
        public String getDevices();
        public void setDevices(String devices);
        public String getAges();
        public void setAges(String ages);
        public Integer getValue();
        public void setValue(Integer value);
    }
    
    // Getters and setters
    public String getRefDate();
    public void setRefDate(String refDate);
    public List<VisitUvNew> getVisitUvNew();
    public void setVisitUvNew(List<VisitUvNew> visitUvNew);
    
    // Analysis methods
    public Map<String, Integer> getGenderDistribution();
    public Map<String, Integer> getPlatformDistribution();
    public Map<String, Integer> getLocationDistribution();
}

Usage Examples

Daily Analytics Overview

@Service
public class AnalyticsService {
    
    @Autowired
    private WxMaService wxMaService;
    
    public DailyAnalyticsReport getDailyReport(Date targetDate) {
        try {
            Date endDate = targetDate;
            Date startDate = DateUtils.addDays(targetDate, -30); // Last 30 days
            
            // Get summary trends
            List<WxMaSummaryTrend> summaryTrends = wxMaService.getAnalysisService()
                .getDailySummaryTrend(startDate, endDate);
            
            // Get visit trends  
            List<WxMaVisitTrend> visitTrends = wxMaService.getAnalysisService()
                .getDailyVisitTrend(startDate, endDate);
            
            // Get traffic sources
            WxMaVisitDistribution distribution = wxMaService.getAnalysisService()
                .getVisitDistribution(startDate, endDate);
            
            // Get top pages
            List<WxMaVisitPage> topPages = wxMaService.getAnalysisService()
                .getVisitPage(startDate, endDate);
            
            return new DailyAnalyticsReport(summaryTrends, visitTrends, distribution, topPages);
            
        } catch (WxErrorException e) {
            logger.error("Failed to get daily analytics: {}", e.getMessage());
            throw new AnalyticsException("Could not retrieve daily analytics", e);
        }
    }
}

User Retention Analysis

public class RetentionAnalyzer {
    
    public RetentionReport analyzeRetention(Date startDate, int days) {
        try {
            Date endDate = DateUtils.addDays(startDate, days - 1);
            
            // Get daily retention
            WxMaRetainInfo dailyRetention = wxMaService.getAnalysisService()
                .getDailyRetainInfo(startDate, endDate);
            
            // Get weekly retention  
            WxMaRetainInfo weeklyRetention = wxMaService.getAnalysisService()
                .getWeeklyRetainInfo(startDate, endDate);
            
            // Get monthly retention
            WxMaRetainInfo monthlyRetention = wxMaService.getAnalysisService()
                .getMonthlyRetainInfo(startDate, endDate);
            
            // Analyze retention patterns
            RetentionReport report = new RetentionReport();
            report.setDailyRetention(analyzeRetentionData(dailyRetention));
            report.setWeeklyRetention(analyzeRetentionData(weeklyRetention));
            report.setMonthlyRetention(analyzeRetentionData(monthlyRetention));
            
            // Calculate key metrics
            report.setDay1Retention(dailyRetention.getRetentionRate(1));
            report.setDay7Retention(dailyRetention.getRetentionRate(7));
            report.setDay30Retention(dailyRetention.getRetentionRate(30));
            
            return report;
            
        } catch (WxErrorException e) {
            logger.error("Retention analysis failed: {}", e.getMessage());
            throw new AnalyticsException("Retention analysis failed", e);
        }
    }
    
    private Map<String, Object> analyzeRetentionData(WxMaRetainInfo retentionInfo) {
        Map<String, Object> analysis = new HashMap<>();
        Map<Integer, Float> retentionMap = retentionInfo.getRetentionMap();
        
        // Calculate retention trend
        List<Float> rates = new ArrayList<>(retentionMap.values());
        analysis.put("trend", calculateTrend(rates));
        analysis.put("avgRetention", calculateAverage(rates));
        analysis.put("retentionCurve", retentionMap);
        
        return analysis;
    }
}

Traffic Source Analysis

@Component
public class TrafficAnalyzer {
    
    public TrafficSourceReport analyzeTrafficSources(Date startDate, Date endDate) {
        try {
            WxMaVisitDistribution distribution = wxMaService.getAnalysisService()
                .getVisitDistribution(startDate, endDate);
            
            List<WxMaVisitDistribution.AccessSource> sources = distribution.getAccessSource();
            
            // Calculate total traffic
            int totalVisitors = sources.stream()
                .mapToInt(WxMaVisitDistribution.AccessSource::getAccessSourceVisitUv)
                .sum();
            
            // Analyze each source
            Map<String, SourceAnalysis> sourceAnalysis = new HashMap<>();
            for (WxMaVisitDistribution.AccessSource source : sources) {
                SourceAnalysis analysis = new SourceAnalysis();
                analysis.setName(source.getAccessSourceName());
                analysis.setVisitors(source.getAccessSourceVisitUv());
                analysis.setPercentage((float) source.getAccessSourceVisitUv() / totalVisitors * 100);
                
                sourceAnalysis.put(source.getAccessSourceName(), analysis);
            }
            
            // Identify top sources
            List<SourceAnalysis> topSources = sourceAnalysis.values().stream()
                .sorted((a, b) -> Integer.compare(b.getVisitors(), a.getVisitors()))
                .limit(10)
                .collect(Collectors.toList());
            
            TrafficSourceReport report = new TrafficSourceReport();
            report.setTotalVisitors(totalVisitors);
            report.setSourceBreakdown(sourceAnalysis);
            report.setTopSources(topSources);
            report.setReportDate(distribution.getRefDate());
            
            return report;
            
        } catch (WxErrorException e) {
            logger.error("Traffic source analysis failed: {}", e.getMessage());
            throw new AnalyticsException("Traffic analysis failed", e);
        }
    }
}

Page Performance Analysis

public class PagePerformanceAnalyzer {
    
    public PagePerformanceReport analyzePagePerformance(Date startDate, Date endDate) {
        try {
            List<WxMaVisitPage> pages = wxMaService.getAnalysisService()
                .getVisitPage(startDate, endDate);
            
            // Sort pages by different metrics
            List<WxMaVisitPage> topPagesByViews = pages.stream()
                .sorted((a, b) -> Integer.compare(b.getVisitPv(), a.getVisitPv()))
                .limit(20)
                .collect(Collectors.toList());
            
            List<WxMaVisitPage> topPagesByUniqueVisitors = pages.stream()
                .sorted((a, b) -> Integer.compare(b.getVisitUv(), a.getVisitUv()))
                .limit(20)
                .collect(Collectors.toList());
            
            List<WxMaVisitPage> topPagesByEngagement = pages.stream()
                .filter(p -> p.getStayTimeUv() != null)
                .sorted((a, b) -> Float.compare(b.getStayTimeUv(), a.getStayTimeUv()))
                .limit(20)
                .collect(Collectors.toList());
            
            // Calculate performance metrics
            Map<String, PageMetrics> pageMetrics = new HashMap<>();
            for (WxMaVisitPage page : pages) {
                PageMetrics metrics = new PageMetrics();
                metrics.setPath(page.getPagePath());
                metrics.setPageViews(page.getVisitPv());
                metrics.setUniqueVisitors(page.getVisitUv());
                metrics.setAvgStayTime(page.getStayTimeUv());
                metrics.setBounceRate(calculateBounceRate(page));
                metrics.setShareRate(calculateShareRate(page));
                
                pageMetrics.put(page.getPagePath(), metrics);
            }
            
            PagePerformanceReport report = new PagePerformanceReport();
            report.setTopPagesByViews(topPagesByViews);
            report.setTopPagesByUniqueVisitors(topPagesByUniqueVisitors);
            report.setTopPagesByEngagement(topPagesByEngagement);
            report.setPageMetrics(pageMetrics);
            
            return report;
            
        } catch (WxErrorException e) {
            logger.error("Page performance analysis failed: {}", e.getMessage());
            throw new AnalyticsException("Page analysis failed", e);
        }
    }
    
    private Float calculateBounceRate(WxMaVisitPage page) {
        if (page.getEntryPagePv() != null && page.getEntryPagePv() > 0) {
            return (page.getExitPagePv() / page.getEntryPagePv()) * 100;
        }
        return null;
    }
    
    private Float calculateShareRate(WxMaVisitPage page) {
        if (page.getVisitUv() != null && page.getVisitUv() > 0 && page.getShareUv() != null) {
            return (page.getShareUv() / page.getVisitUv()) * 100;
        }
        return null;
    }
}

User Demographics Analysis

@Component  
public class UserDemographicsAnalyzer {
    
    public DemographicsReport analyzeDemographics(Date startDate, Date endDate) {
        try {
            WxMaUserPortrait portrait = wxMaService.getAnalysisService()
                .getUserPortrait(startDate, endDate);
            
            List<WxMaUserPortrait.VisitUvNew> userData = portrait.getVisitUvNew();
            
            // Analyze gender distribution
            Map<String, Integer> genderDist = analyzeGenderDistribution(userData);
            
            // Analyze platform distribution
            Map<String, Integer> platformDist = analyzePlatformDistribution(userData);
            
            // Analyze geographic distribution
            Map<String, Integer> geoDist = analyzeGeographicDistribution(userData);
            
            // Analyze age distribution
            Map<String, Integer> ageDist = analyzeAgeDistribution(userData);
            
            // Analyze device distribution
            Map<String, Integer> deviceDist = analyzeDeviceDistribution(userData);
            
            DemographicsReport report = new DemographicsReport();
            report.setGenderDistribution(genderDist);
            report.setPlatformDistribution(platformDist);
            report.setGeographicDistribution(geoDist);
            report.setAgeDistribution(ageDist);
            report.setDeviceDistribution(deviceDist);
            report.setTotalNewUsers(userData.stream().mapToInt(WxMaUserPortrait.VisitUvNew::getValue).sum());
            report.setReportDate(portrait.getRefDate());
            
            return report;
            
        } catch (WxErrorException e) {
            logger.error("Demographics analysis failed: {}", e.getMessage());
            throw new AnalyticsException("Demographics analysis failed", e);
        }
    }
    
    private Map<String, Integer> analyzeGenderDistribution(List<WxMaUserPortrait.VisitUvNew> userData) {
        Map<String, Integer> distribution = new HashMap<>();
        
        for (WxMaUserPortrait.VisitUvNew user : userData) {
            String gender = getGenderLabel(user.getGenders());
            distribution.merge(gender, user.getValue(), Integer::sum);
        }
        
        return distribution;
    }
    
    private String getGenderLabel(Integer genderCode) {
        switch (genderCode) {
            case 1: return "Male";
            case 2: return "Female";
            default: return "Unknown";
        }
    }
    
    private Map<String, Integer> analyzeGeographicDistribution(List<WxMaUserPortrait.VisitUvNew> userData) {
        Map<String, Integer> distribution = new HashMap<>();
        
        for (WxMaUserPortrait.VisitUvNew user : userData) {
            String location = user.getProvince();
            if (location != null && !location.isEmpty()) {
                distribution.merge(location, user.getValue(), Integer::sum);
            }
        }
        
        return distribution.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .limit(20)
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (e1, e2) -> e1,
                LinkedHashMap::new
            ));
    }
}

Real-time Analytics Dashboard

@RestController
@RequestMapping("/api/analytics")
public class AnalyticsDashboardController {
    
    @GetMapping("/dashboard")
    public ResponseEntity<AnalyticsDashboard> getDashboard(
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
        
        try {
            AnalyticsDashboard dashboard = new AnalyticsDashboard();
            
            // Get overview metrics
            List<WxMaSummaryTrend> summary = wxMaService.getAnalysisService()
                .getDailySummaryTrend(startDate, endDate);
            
            List<WxMaVisitTrend> visits = wxMaService.getAnalysisService()
                .getDailyVisitTrend(startDate, endDate);
            
            // Calculate key metrics
            dashboard.setTotalVisits(summary.stream().mapToInt(WxMaSummaryTrend::getVisitTotal).sum());
            dashboard.setTotalUniqueVisitors(visits.stream().mapToInt(WxMaVisitTrend::getVisitUv).sum());
            dashboard.setTotalPageViews(visits.stream().mapToInt(WxMaVisitTrend::getVisitPv).sum());
            dashboard.setAvgSessionDuration(visits.stream()
                .filter(v -> v.getStayTimeSession() != null)
                .mapToDouble(WxMaVisitTrend::getStayTimeSession)
                .average().orElse(0.0));
            
            // Get retention data
            WxMaRetainInfo retention = wxMaService.getAnalysisService()
                .getDailyRetainInfo(startDate, endDate);
            dashboard.setRetentionData(retention.getRetentionMap());
            
            // Get traffic sources
            WxMaVisitDistribution traffic = wxMaService.getAnalysisService()
                .getVisitDistribution(startDate, endDate);
            dashboard.setTrafficSources(traffic.getAccessSource());
            
            // Get top pages
            List<WxMaVisitPage> topPages = wxMaService.getAnalysisService()
                .getVisitPage(startDate, endDate);
            dashboard.setTopPages(topPages.stream()
                .sorted((a, b) -> Integer.compare(b.getVisitPv(), a.getVisitPv()))
                .limit(10)
                .collect(Collectors.toList()));
            
            return ResponseEntity.ok(dashboard);
            
        } catch (WxErrorException e) {
            logger.error("Dashboard data retrieval failed: {}", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}

Automated Analytics Reports

@Component
public class AutomatedReportingService {
    
    @Scheduled(cron = "0 0 9 * * ?") // Daily at 9 AM
    public void generateDailyReport() {
        Date yesterday = DateUtils.addDays(new Date(), -1);
        Date lastWeek = DateUtils.addDays(yesterday, -6);
        
        try {
            // Generate comprehensive daily report
            DailyReport report = new DailyReport();
            
            // Get yesterday's data
            List<WxMaSummaryTrend> summary = wxMaService.getAnalysisService()
                .getDailySummaryTrend(yesterday, yesterday);
            
            List<WxMaVisitTrend> visits = wxMaService.getAnalysisService()
                .getDailyVisitTrend(yesterday, yesterday);
            
            // Get week-over-week comparison
            List<WxMaVisitTrend> weekTrend = wxMaService.getAnalysisService()
                .getDailyVisitTrend(lastWeek, yesterday);
            
            report.setDate(yesterday);
            report.setSummary(summary.get(0));
            report.setVisits(visits.get(0));
            report.setWeeklyComparison(calculateWeeklyGrowth(weekTrend));
            
            // Send report via email/notification
            reportNotificationService.sendDailyReport(report);
            
        } catch (WxErrorException e) {
            logger.error("Failed to generate daily report: {}", e.getMessage());
        }
    }
    
    @Scheduled(cron = "0 0 10 ? * MON") // Weekly on Monday at 10 AM
    public void generateWeeklyReport() {
        Date endDate = DateUtils.addDays(new Date(), -1);
        Date startDate = DateUtils.addDays(endDate, -6);
        
        try {
            WeeklyReport report = new WeeklyReport();
            
            // Get weekly analytics data
            List<WxMaVisitTrend> weeklyData = wxMaService.getAnalysisService()
                .getWeeklyVisitTrend(startDate, endDate);
            
            WxMaRetainInfo retention = wxMaService.getAnalysisService()
                .getWeeklyRetainInfo(startDate, endDate);
            
            List<WxMaVisitPage> pagePerformance = wxMaService.getAnalysisService()
                .getVisitPage(startDate, endDate);
            
            WxMaUserPortrait demographics = wxMaService.getAnalysisService()
                .getUserPortrait(startDate, endDate);
            
            report.setWeeklyTrends(weeklyData);
            report.setRetentionAnalysis(retention);
            report.setTopPages(pagePerformance.stream()
                .sorted((a, b) -> Integer.compare(b.getVisitPv(), a.getVisitPv()))
                .limit(20)
                .collect(Collectors.toList()));
            report.setUserDemographics(demographics);
            
            // Generate insights and recommendations
            report.setInsights(generateInsights(report));
            
            reportNotificationService.sendWeeklyReport(report);
            
        } catch (WxErrorException e) {
            logger.error("Failed to generate weekly report: {}", e.getMessage());
        }
    }
}

Performance Monitoring

@Component
public class PerformanceMonitor {
    
    @EventListener
    @Async
    public void onAnalyticsRequest(AnalyticsRequestEvent event) {
        long startTime = System.currentTimeMillis();
        
        try {
            // Monitor API response times
            Object result = event.getAnalyticsCall().call();
            
            long duration = System.currentTimeMillis() - startTime;
            
            // Log performance metrics
            logger.info("Analytics API call completed: {} ms for {}", 
                       duration, event.getApiMethod());
            
            // Alert if slow
            if (duration > 5000) {
                alertService.sendSlowApiAlert(event.getApiMethod(), duration);
            }
            
        } catch (Exception e) {
            logger.error("Analytics API call failed: {}", e.getMessage());
            alertService.sendApiFailureAlert(event.getApiMethod(), e);
        }
    }
}

The analytics service provides comprehensive insights into mini program performance with detailed metrics, trend analysis, user behavior patterns, and automated reporting capabilities.

Install with Tessl CLI

npx tessl i tessl/maven-com-github-binarywang--weixin-java-miniapp

docs

analytics.md

cloud-development.md

configuration.md

core-services.md

development-tools.md

ecommerce.md

index.md

live-streaming.md

logistics.md

media-content.md

messaging.md

qr-codes.md

user-management.md

tile.json