DEV Community

sharkflow ltd
sharkflow ltd

Posted on

SharkFlow CFA — devto

{
  "title": "Building a CFA Study Platform That Actually Works on African Mobile Networks: SharkFlow's Technical Deep Dive",
  "content": "# Building a CFA Study Platform That Actually Works on African Mobile Networks: SharkFlow's Technical Deep Dive\n\nPreparing for the CFA exam is brutal. Doing it on a 2G connection in Nairobi? That's a different kind of hell.\n\nWhen we started building SharkFlow's CFA preparation module, we realized most EdTech platforms treat African markets as afterthoughts. They optimize for Wi-Fi. They assume reliable power. They ignore that Kenya's 60M+ mobile money users work on devices with 512MB RAM and unstable networks.\n\nThis article breaks down how we engineered a CFA study platform that doesn't just *exist* in Africa—it genuinely thrives here.\n\n## The Problem We Solved\n\nThe CFA curriculum is dense: 300+ hours of study across derivatives, portfolio management, ethics, and quantitative methods. Traditional platforms require constant connectivity and heavy data transfer. In Kenya, where mobile data costs ~KES 50 ($0.38 USD) for 100MB, every kilobyte matters.\n\nWe had three non-negotiable constraints:\n1. **Work offline-first**: Download once, study everywhere\n2. **Handle ~10Mbps fluctuations**: Network conditions are real\n3. **Scale to 50,000 concurrent users** without melting our infrastructure\n\n## Our Architecture: Offline-First by Default\n\n### Progressive Data Sync\n\nWe built a two-tier content system:\n\n```

typescript\n// Content strategy: Cloud-sourced, device-stored\ninterface ContentTier {\n  tier1: {\n    size: '85MB',\n    content: 'Core curriculum (Ethics, Quantitative)',\n    syncStrategy: 'aggressive_prefetch',\n    frequency: 'weekly'\n  },\n  tier2: {\n    size: '250MB',\n    content: 'Full question banks + video lectures',\n    syncStrategy: 'background_sync',\n    frequency: 'on_demand'\n  },\n  tier3: {\n    size: '15MB',\n    content: 'Real-time market data + performance analytics',\n    syncStrategy: 'delta_sync',\n    frequency: 'hourly'\n  }\n}\n

```\n\nUsers can start studying immediately with Tier 1 (~85MB), which covers the essentials. Tier 2 downloads in the background during low-cost hours (most Kenyan carriers offer off-peak data). Tier 3 syncs only when connected.\n\n### Smart Compression\n\nOur content pipeline compresses ruthlessly:\n\n```

python\n# Content compression strategy\nclass ContentCompressor:\n    def compress_materials(self, material_type: str):\n        if material_type == 'video':\n            # H.265 codec, 480p target (not 4K)\n            # Bitrate: 800kbps (vs 5Mbps standard)\n            return self._transcode_video()\n        \n        elif material_type == 'pdf':\n            # Remove embedded fonts, compress images\n            # Target: 60% size reduction\n            return self._optimize_pdf()\n        \n        elif material_type == 'questions':\n            # Plain JSON with heavy gzip\n            # 10,000 questions = 12MB (uncompressed: 85MB)\n            return self._serialize_questions()\n

```\n\nOur question bank of 10,000 CFA questions compressed from 85MB to 12MB. That's the difference between \"I'll download later\" and \"done in 2 minutes.\"\n\n## Database Architecture: SQLite Locally, PostgreSQL Globally\n\nMost EdTech platforms use Firebase or MongoDB. Both are overkill and expensive at scale in Africa.\n\nWe use a hybrid:\n\n```

sql\n-- Local SQLite schema (device-side)\nCREATE TABLE questions (\n    id INTEGER PRIMARY KEY,\n    level INTEGER,  -- L1, L2, L3\n    topic TEXT,\n    question_text BLOB,  -- Compressed\n    answers BLOB,\n    explanation BLOB,\n    last_reviewed INTEGER,\n    performance_score REAL,\n    FOREIGN KEY(topic) REFERENCES topics(id)\n);\n\nCREATE INDEX idx_topic_level ON questions(topic, level);\nCREATE INDEX idx_performance ON questions(performance_score);\n\n-- User progress (syncs bidirectionally)\nCREATE TABLE sync_queue (\n    id INTEGER PRIMARY KEY,\n    action TEXT,  -- 'quiz_completed', 'bookmark_added'\n    payload BLOB,\n    timestamp INTEGER,\n    synced BOOLEAN DEFAULT 0\n);\n

```\n\n**Why SQLite?**\n- Zero setup. Instant. ~300KB footprint.\n- Handles 100K+ records per device without breaking a sweat\n- Built-in on iOS and Android\n- Sync conflicts? We handle them client-side with timestamp-based resolution\n\n**Backend (PostgreSQL):**\n\n```

sql\n-- Aggregates user progress across 50K students\nCREATE TABLE user_performance (\n    user_id UUID PRIMARY KEY,\n    level_1_score REAL,\n    level_2_score REAL,\n    level_3_score REAL,\n    total_questions_answered INTEGER,\n    last_active TIMESTAMP,\n    device_type TEXT,  -- iOS, Android, Web\n    region TEXT  -- For performance tracking\n);\n\nCREATE MATERIALIZED VIEW topic_difficulty AS\nSELECT \n    topic,\n    AVG(performance_score) as avg_difficulty,\n    COUNT(*) as attempts,\n    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY time_spent) as median_time\nFROM user_attempts\nGROUP
Enter fullscreen mode Exit fullscreen mode

Top comments (0)