diff --git a/.claude/commands/gap-analysis.md b/.claude/commands/gap-analysis.md index 6cd087c73..e4721926b 100644 --- a/.claude/commands/gap-analysis.md +++ b/.claude/commands/gap-analysis.md @@ -1,114 +1,282 @@ # Gap Analysis Command -Brief entry point to analyze implementation status. Shows where work is needed across the 5-layer lifecycle. +Comprehensive analysis showing ALL implemented items and ALL gaps across the 5-layer lifecycle. Runs on O(1) by reading index files. ## Usage ``` -/gap-analysis # Brief overview (all layers summary) -/gap-analysis design # Design layer status -/gap-analysis design mockup # Design → Mockup sub-section only -/gap-analysis design spec # Design → Spec sub-section only -/gap-analysis server # Server layer status -/gap-analysis client # Client layer status -/gap-analysis client network # Client → Network sub-section -/gap-analysis client data # Client → Data sub-section -/gap-analysis feature # Feature layer status -/gap-analysis feature [name] # Feature → specific feature -/gap-analysis platform # Platform layer status -/gap-analysis platform android # Platform → Android only -/gap-analysis [feature-name] # Specific feature (all 5 layers) +/gap-analysis # FULL comprehensive view (recommended) +/gap-analysis design # Design layer only +/gap-analysis design mockup # Design → Mockup sub-section +/gap-analysis server # Server layer only +/gap-analysis client # Client layer only +/gap-analysis feature # Feature layer only +/gap-analysis feature [name] # Specific feature only +/gap-analysis platform # Platform layer only +/gap-analysis testing # Testing status (all layers) +/gap-analysis testing [layer] # Testing for specific layer +/gap-analysis [feature-name] # Single feature (all 5 layers) ``` -## 5-Layer Lifecycle with Sub-Sections +## Comprehensive Output (No Parameters) + +When `/gap-analysis` is called without parameters, show the **FULL comprehensive view**: ``` -1. Design → spec | mockup | api | status -2. Server → endpoints | availability -3. Client → network | data | model -4. Feature → viewmodel | screen | navigation | di -5. Platform → android | ios | desktop | web +╔══════════════════════════════════════════════════════════════════════════════╗ +║ MIFOS MOBILE - GAP ANALYSIS (O(1) Lookup) ║ +╠══════════════════════════════════════════════════════════════════════════════╣ + +## 5-Layer Health Overview + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Layer Progress Implemented Gaps Status │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 1. Design [████████░░] 80% 14/17 3 ⚠️ Mockups │ +│ 2. Server [██████████] 100% 11/11 0 ✅ Complete │ +│ 3. Client [██████████] 100% 30/30 0 ✅ Complete │ +│ 4. Feature [██████████] 100% 63/63 0 ✅ Complete │ +│ 5. Platform [█████████░] 95% 4/4 1 ⚠️ Web exp. │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ OVERALL [█████████░] 95% │ +└─────────────────────────────────────────────────────────────────────────────┘ + +--- + +## ✅ IMPLEMENTED (What's Complete) + +### Design Layer (17 features) +| Feature | SPEC | API | STATUS | Mockups | +|---------|:----:|:---:|:------:|:-------:| +| auth | ✅ | ✅ | ✅ | ✅ | +| home | ✅ | ✅ | ✅ | ⚠️ | +| accounts | ✅ | ✅ | ✅ | ⚠️ | +[... all 17 features ...] + +### Server Layer (11 endpoint categories) +| Category | Endpoints | Status | +|----------|:---------:|:------:| +| AUTH | 4 | ✅ | +| CLIENT | 5 | ✅ | +| SAVINGS | 8 | ✅ | +[... all 11 categories ...] + +### Client Layer (13 services, 17 repositories) +| Component | Count | Status | +|-----------|:-----:|:------:| +| Services | 13/13 | ✅ | +| Repositories | 17/17 | ✅ | +| DI Modules | 2/2 | ✅ | + +### Feature Layer (23 modules, 63 screens) +| Component | Count | Status | +|-----------|:-----:|:------:| +| Modules | 23/23 | ✅ | +| ViewModels | 49/49 | ✅ | +| Screens | 63/63 | ✅ | +| DI Modules | 21/21 | ✅ | + +### Platform Layer (4 platforms) +| Platform | Build | Status | +|----------|:-----:|:------:| +| Android | ✅ | Primary | +| iOS | ✅ | CocoaPods | +| Desktop | ✅ | JVM | +| Web | ⚠️ | Experimental | + +--- + +## ❌ GAPS (What Needs Work) + +### P0 - Critical (Blocks Other Work) +| Gap | Layer | Impact | Plan Command | +|-----|-------|--------|--------------| +| (none currently) | - | - | - | + +### P1 - High Priority (User-Facing) +| Gap | Layer | Impact | Plan Command | +|-----|-------|--------|--------------| +| Missing mockups (10) | Design | v2.0 UI blocked | `/gap-planning design mockup` | +| Missing design-tokens (9) | Design | Theme consistency | `/gap-planning design mockup` | + +### P2 - Nice to Have (Polish) +| Gap | Layer | Impact | Plan Command | +|-----|-------|--------|--------------| +| Web experimental | Platform | Limited browser support | `/gap-planning platform web` | + +--- + +## 🧪 TESTING STATUS + +| Layer | Unit | UI | Integration | Screenshot | Status | +|-------|:----:|:--:|:-----------:|:----------:|:------:| +| Client (Repo) | 14 | - | - | - | ⚠️ Partial | +| Feature (VM) | 0 | 0 | 0 | 0 | ⬜ Not Started | +| Platform (E2E) | - | - | 0 | 0 | ⬜ Not Started | + +**Testing Gaps** (P1): +| Gap | Impact | Plan Command | +|-----|--------|--------------| +| ViewModel tests (0/49) | No regression safety | `/gap-planning testing feature` | +| UI tests (0/63) | No UI verification | `/gap-planning testing feature` | +| E2E tests (0/8) | No flow coverage | `/gap-planning testing platform` | +| Screenshot tests (0/30) | No visual regression | `/gap-planning testing platform` | + +→ For detailed testing status: `/gap-analysis testing` + +--- + +## 🛠️ AVAILABLE ACTIONS + +### Create Plans +| Gap | Command | What It Does | +|-----|---------|--------------| +| All mockups | `/gap-planning design mockup` | Generate mockups for 10 features | +| Specific feature | `/gap-planning [feature]` | Plan single feature improvements | +| Web platform | `/gap-planning platform web` | Stabilize web build | + +### Implement +| Target | Command | What It Does | +|--------|---------|--------------| +| E2E feature | `/implement [feature]` | Full implementation | +| Client only | `/client [feature]` | Network + Data layers | +| UI only | `/feature [feature]` | ViewModel + Screen | + +### Verify +| Target | Command | What It Does | +|--------|---------|--------------| +| Any feature | `/verify [feature]` | Check implementation vs spec | + +### Testing +| Target | Command | What It Does | +|--------|---------|--------------| +| Run tests | `/verify-tests [feature]` | Run tests for feature | +| Test status | `/gap-analysis testing` | See testing coverage | +| Plan tests | `/gap-planning testing [layer]` | Plan test implementation | + +--- + +## 📊 O(1) PERFORMANCE + +| Metric | Before | After | Improvement | +|--------|:------:|:-----:|:-----------:| +| Files to scan | 10-50 | 1-2 | **90% fewer** | +| Lines to read | 500-3000 | 60-200 | **80-95% less** | +| Tool calls | 3-5 | 1-2 | **60% fewer** | + +--- + +## 📁 O(1) INDEX FILES + +| Layer | Index File | Lines | Use For | +|-------|------------|:-----:|---------| +| Feature | `MODULES_INDEX.md` | ~120 | Find any module | +| Feature | `SCREENS_INDEX.md` | ~180 | Find any screen | +| Design | `FEATURES_INDEX.md` | ~100 | Check feature status | +| Design | `MOCKUPS_INDEX.md` | ~100 | Check mockup status | +| Client | `FEATURE_MAP.md` | ~150 | Map feature → services | +| Server | `API_INDEX.md` | ~80 | Find any endpoint | +| Platform | `LAYER_STATUS.md` | ~80 | Platform commands | + +--- + +## 🎯 RECOMMENDED NEXT STEPS + +Based on current gaps: + +1. **Design Mockups** (P1) - 10 features need mockups + → `/gap-planning design mockup` + +2. **Web Platform** (P2) - Experimental status + → `/gap-planning platform web` + +3. **Verify Features** - Ensure all features match spec + → `/verify [feature-name]` + +╚══════════════════════════════════════════════════════════════════════════════╝ ``` -## Brief Overview Output (No Parameters) +--- -When `/gap-analysis` is called without parameters, show a **brief summary**: +## 5-Layer Lifecycle ``` -## Gap Analysis - Quick Overview - -| Layer | Progress | Gaps | Next Action | -|-------|:--------:|:----:|-------------| -| Design | 85% | mockups/ (16) | /gap-analysis design mockup | -| Server | 100% | - | - | -| Client | 95% | 1 service | /gap-analysis client | -| Feature | 94% | dashboard | /gap-analysis feature | -| Platform | 90% | web fixes | /gap-analysis platform | - -**Next Step**: Run `/gap-analysis [layer]` for details, or `/gap-planning [layer]` to plan. +┌─────────────────────────────────────────────────────────────────┐ +│ 1. Design → spec | mockup | api | status │ +│ 2. Server → endpoints | availability │ +│ 3. Client → network | data | model │ +│ 4. Feature → viewmodel | screen | navigation | di │ +│ 5. Platform → android | ios | desktop | web │ +└─────────────────────────────────────────────────────────────────┘ ``` +--- + ## Instructions -### Step 1: Determine Output Type +### Step 1: Read O(1) Index Files -**Layer Parameters**: -| Parameter | Template | Action | -|-----------|----------|--------| -| (none) | Brief summary | Quick overview of all layers | -| `design` | `layer-design.md` | Full design layer status | -| `server` | `layer-server.md` | Server layer status | -| `client` | `layer-client.md` | Client layer status | -| `feature` | `layer-feature.md` | Feature layer status | -| `platform` | `layer-platform.md` | Platform layer status | -| `[name]` | `feature-detail.md` | Specific feature (all layers) | +Read these files for instant status (DO NOT scan directories): -**Sub-Section Parameters** (layer + sub-section): -| Parameters | Template | Action | -|------------|----------|--------| -| `design mockup` | `subsection/design-mockup.md` | Mockup generation status | -| `design spec` | `subsection/design-spec.md` | Specification status | -| `design api` | `subsection/design-api.md` | API documentation status | -| `client network` | `subsection/client-network.md` | Network services status | -| `client data` | `subsection/client-data.md` | Repository status | -| `feature [name]` | `subsection/feature-single.md` | Single feature status | -| `platform android` | `subsection/platform-android.md` | Android-only status | -| `platform ios` | `subsection/platform-ios.md` | iOS-only status | -| `platform desktop` | `subsection/platform-desktop.md` | Desktop-only status | -| `platform web` | `subsection/platform-web.md` | Web-only status | +| Layer | Index File | Path | +|-------|------------|------| +| Feature | MODULES_INDEX.md | `claude-product-cycle/feature-layer/MODULES_INDEX.md` | +| Feature | SCREENS_INDEX.md | `claude-product-cycle/feature-layer/SCREENS_INDEX.md` | +| Design | FEATURES_INDEX.md | `claude-product-cycle/design-spec-layer/FEATURES_INDEX.md` | +| Design | MOCKUPS_INDEX.md | `claude-product-cycle/design-spec-layer/MOCKUPS_INDEX.md` | +| Client | FEATURE_MAP.md | `claude-product-cycle/client-layer/FEATURE_MAP.md` | +| Server | API_INDEX.md | `claude-product-cycle/server-layer/API_INDEX.md` | +| Platform | LAYER_STATUS.md | `claude-product-cycle/platform-layer/LAYER_STATUS.md` | +| Testing | TESTING_STATUS.md | `claude-product-cycle/*/TESTING_STATUS.md` (per layer) | -### Step 2: Read Status Files +### Step 2: Calculate Progress -| Layer | Files to Read | -|-------|---------------| -| Design | `design-spec-layer/STATUS.md`, check each `features/*/` folder | -| Server | `server-layer/FINERACT_API.md` | -| Client | `client-layer/LAYER_STATUS.md`, check `core/network/services/` | -| Feature | `feature-layer/LAYER_STATUS.md`, check `feature/*/` folders | -| Platform | Check `cmp-android/`, `cmp-ios/`, `cmp-desktop/`, `cmp-web/` | +From index files, calculate: +- **Design**: Count ✅ in FEATURES_INDEX.md + MOCKUPS_INDEX.md +- **Server**: All 11 categories = 100% +- **Client**: Count services + repositories in FEATURE_MAP.md +- **Feature**: Count modules + screens in MODULES_INDEX.md + SCREENS_INDEX.md +- **Platform**: Count working platforms in LAYER_STATUS.md -### Step 3: Calculate Percentages +### Step 3: Identify Gaps -For each layer, count actual files: -- Design: Count SPEC.md, MOCKUP.md, API.md, STATUS.md per feature -- Client: Count *Service.kt in `core/network/services/` -- Feature: Count *ViewModel.kt, *Screen.kt in `feature/*/` -- Calculate: `exists / expected * 100` +From index files, find items marked ⚠️ or ❌: +- Missing mockups → `MOCKUPS_INDEX.md` +- Missing services → `FEATURE_MAP.md` +- Missing screens → `SCREENS_INDEX.md` +- Platform issues → `LAYER_STATUS.md` -### Step 4: Fill Template +### Step 4: Generate Output -Read template from `claude-product-cycle/templates/gap-analysis/` and replace placeholders with real data. +Fill the comprehensive template with: +1. Real percentages from index files +2. All implemented items (✅) +3. All gaps (⚠️/❌) with `/gap-planning` commands +4. Recommended next steps based on priorities -**Progress Bar Reference**: -``` -100% = [██████████] | 50% = [█████░░░░░] - 90% = [█████████░] | 40% = [████░░░░░░] - 80% = [████████░░] | 30% = [███░░░░░░░] - 70% = [███████░░░] | 20% = [██░░░░░░░░] - 60% = [██████░░░░] | 10% = [█░░░░░░░░░] -``` +--- -**Status Icons**: ✅ Complete | ⚠️ Partial | ❌ Missing | `-` N/A +## Layer-Specific Parameters + +When a layer parameter is provided, show detailed view for that layer: + +| Parameter | Shows | +|-----------|-------| +| `design` | All 17 features: SPEC, API, STATUS, Mockups status | +| `design mockup` | Mockup-specific: Figma links, Stitch prompts, design-tokens | +| `design spec` | Specification status for all features | +| `server` | All 11 endpoint categories with endpoint counts | +| `client` | All services (13) and repositories (17) | +| `client network` | Network services only | +| `client data` | Repositories only | +| `feature` | All 23 modules with screens, ViewModels, DI | +| `feature [name]` | Single feature: all layers | +| `platform` | All 4 platforms with build commands | +| `platform [name]` | Single platform details | +| `testing` | Testing coverage across all layers | +| `testing [layer]` | Testing for specific layer (design/client/feature/platform) | + +--- ## Feature Reference @@ -132,10 +300,29 @@ Read template from `claude-product-cycle/templates/gap-analysis/` and replace pl | 16 | client-charge | features/client-charge/ | feature/user-profile/ | | 17 | dashboard | features/dashboard/ | feature/dashboard/ | +--- + ## Output Rules -1. Read actual files - don't assume -2. Calculate real percentages -3. Use progress bars for visibility -4. List specific gaps with file paths -5. Suggest next command (gap-planning or implement) +1. **Read index files only** - Never scan directories when index files exist +2. **Show everything** - All implemented + all gaps in one view +3. **Include all `/gap-planning` commands** - For every gap found +4. **Use progress bars** - Visual at-a-glance status +5. **Prioritize gaps** - P0 → P1 → P2 +6. **Show recommended next steps** - Based on current gaps +7. **NO interactive questions** - Comprehensive view, user decides + +--- + +## Progress Bar Reference + +``` +100% = [██████████] | 50% = [█████░░░░░] + 95% = [█████████▌] | 40% = [████░░░░░░] + 90% = [█████████░] | 30% = [███░░░░░░░] + 80% = [████████░░] | 20% = [██░░░░░░░░] + 70% = [███████░░░] | 10% = [█░░░░░░░░░] + 60% = [██████░░░░] | 0% = [░░░░░░░░░░] +``` + +**Status Icons**: ✅ Complete | ⚠️ Partial | ❌ Missing | `-` N/A diff --git a/.claude/commands/gap-planning.md b/.claude/commands/gap-planning.md index efed9b37a..16f38dfbd 100644 --- a/.claude/commands/gap-planning.md +++ b/.claude/commands/gap-planning.md @@ -1,154 +1,346 @@ # Gap Planning Command -Brief entry point to plan implementation tasks. Creates step-by-step plans that persist across sessions. +Creates step-by-step implementation plans for identified gaps. Runs on O(1) by reading index files. ## Usage ``` -/gap-planning # Brief overview (what needs planning) -/gap-planning design # Plan design layer work -/gap-planning design mockup # Plan mockup generation specifically -/gap-planning design spec # Plan specification work -/gap-planning server # Plan server layer work -/gap-planning client # Plan client layer work +/gap-planning # Show ALL gaps with ALL plan commands +/gap-planning design # Plan all design layer work +/gap-planning design mockup # Plan mockup generation (10 features) +/gap-planning design spec # Plan specification updates +/gap-planning server # Plan server documentation +/gap-planning client # Plan all client layer work /gap-planning client network # Plan network services /gap-planning client data # Plan repositories -/gap-planning feature # Plan feature layer work +/gap-planning feature # Plan all feature layer work /gap-planning feature [name] # Plan specific feature -/gap-planning platform # Plan platform layer work -/gap-planning platform android # Plan Android-specific work -/gap-planning [feature-name] # Plan specific feature (all layers) +/gap-planning platform # Plan all platform work +/gap-planning platform web # Plan web stabilization +/gap-planning testing # Plan all testing work +/gap-planning testing client # Plan client layer tests +/gap-planning testing feature # Plan feature layer tests (VM + UI) +/gap-planning testing platform # Plan E2E + screenshot tests +/gap-planning testing [feature] # Plan tests for specific feature +/gap-planning [feature-name] # Plan specific feature (all 5 layers) ``` -## Brief Overview Output (No Parameters) +--- -When `/gap-planning` is called without parameters, show a **brief summary**: +## Comprehensive Output (No Parameters) + +When `/gap-planning` is called without parameters, show **ALL gaps with ALL implementation plans**: ``` -## Gap Planning - What Needs Work +╔══════════════════════════════════════════════════════════════════════════════╗ +║ MIFOS MOBILE - GAP PLANNING (O(1) Lookup) ║ +║ All Gaps → All Plans → You Choose ║ +╠══════════════════════════════════════════════════════════════════════════════╣ -| Layer | Gaps | Priority | Next Plan | -|-------|:----:|:--------:|-----------| -| Design | mockups (16) | P1 | /gap-planning design mockup | -| Server | - | - | - | -| Client | 1 service | P2 | /gap-planning client | -| Feature | dashboard | P0 | /gap-planning feature dashboard | -| Platform | web fixes | P2 | /gap-planning platform web | +## Current Gaps Overview -**Current Focus**: Design Layer → Mockup Generation (Phase 2) -**Next Step**: Run `/gap-planning design mockup` to get step-by-step tasks. +| Layer | Gaps | Priority | Status | +|-------|:----:|:--------:|--------| +| Design | 10 mockups | P1 | Ready to plan | +| Server | 0 | - | ✅ Complete | +| Client | 0 | - | ✅ Complete | +| Feature | 0 | - | ✅ Complete | +| Platform | 1 (web) | P2 | Ready to plan | + +--- + +## 📋 ALL AVAILABLE PLANS + +### P0 - Critical (Blocks Other Work) + +| Gap | Plan Command | Tasks | Effort | +|-----|--------------|:-----:|:------:| +| (none currently) | - | - | - | + +### P1 - High Priority (User-Facing) + +| # | Gap | Plan Command | Tasks | Effort | +|:-:|-----|--------------|:-----:|:------:| +| 1 | Missing mockups (10 features) | `/gap-planning design mockup` | 30 | L | +| 2 | Missing design-tokens (9 features) | `/gap-planning design mockup` | 18 | M | + +**Design Mockup Tasks Preview**: +``` +Features needing mockups: +1. accounts → 3 screens (List, Detail, Transactions) +2. beneficiary → 4 screens (List, Add, Edit, Detail) +3. dashboard → 1 screen (Overview) +4. home → 2 screens (Home, Profile) +5. loan-account → 4 screens (List, Detail, Schedule, Summary) +6. notification → 1 screen (List) +7. recent-transaction → 1 screen (List) +8. savings-account → 4 screens (List, Detail, Update, Withdraw) +9. share-account → 2 screens (List, Detail) +10. transfer → 2 screens (Form, Confirmation) + +Run `/gap-planning design mockup` for step-by-step tasks. ``` -## Prerequisites +### P2 - Nice to Have (Polish) -Run `/gap-analysis` first to identify gaps, or run `/gap-planning` directly to see what needs work. +| # | Gap | Plan Command | Tasks | Effort | +|:-:|-----|--------------|:-----:|:------:| +| 1 | Web experimental | `/gap-planning platform web` | 5 | M | -## Instructions +**Web Platform Tasks Preview**: +``` +1. Fix Kotlin/JS compilation warnings +2. Add CORS handling for production +3. Implement WebSocket fallback +4. Optimize bundle size +5. Add Safari compatibility fixes -### Step 1: Determine Template +Run `/gap-planning platform web` for step-by-step tasks. +``` -**Layer Parameters**: -| Parameter | Template | Plans For | -|-----------|----------|-----------| -| (none) | Brief summary | What needs planning | -| `design` | `layer-design.md` | Design layer (specs + mockups) | -| `server` | `layer-server.md` | Server documentation | -| `client` | `layer-client.md` | Network + Data layers | -| `feature` | `layer-feature.md` | Feature implementation | -| `platform` | `layer-platform.md` | Platform-specific work | -| `[name]` | `feature-*.md` | Specific feature | +### 🧪 Testing (Embedded in Layers) -**Sub-Section Parameters** (layer + sub-section): -| Parameters | Template | Plans For | -|------------|----------|-----------| -| `design mockup` | `subsection/design-mockup.md` | Mockup generation (Google Stitch) | -| `design spec` | `subsection/design-spec.md` | Specification updates | -| `design api` | `subsection/design-api.md` | API documentation | -| `client network` | `subsection/client-network.md` | Network services | -| `client data` | `subsection/client-data.md` | Repositories | -| `feature [name]` | `subsection/feature-single.md` | Single feature plan | -| `platform android` | `subsection/platform-android.md` | Android-specific | -| `platform ios` | `subsection/platform-ios.md` | iOS-specific | -| `platform desktop` | `subsection/platform-desktop.md` | Desktop-specific | -| `platform web` | `subsection/platform-web.md` | Web-specific | +| # | Gap | Plan Command | Tests | Effort | +|:-:|-----|--------------|:-----:|:------:| +| 1 | ViewModel tests (0/49) | `/gap-planning testing feature` | 200+ | L | +| 2 | UI tests (0/63 screens) | `/gap-planning testing feature` | 150+ | L | +| 3 | E2E tests (0/8 flows) | `/gap-planning testing platform` | 30+ | M | +| 4 | Screenshot tests (0/30) | `/gap-planning testing platform` | 60+ | M | +| 5 | Repository tests (partial) | `/gap-planning testing client` | 50+ | M | -### Step 2: For Feature Parameter +**Testing Priority by Feature**: +``` +P0 - Core: auth, home, accounts, transfer +P1 - Accounts: beneficiary, loan, savings +P2 - Supporting: settings, notification, qr, passcode +P3 - Other: guarantor, location, dashboard +``` -Determine gap type by checking if `feature/[name]/` exists: +→ Run `/gap-planning testing [feature]` for per-feature test plan. -| Condition | Gap Type | Template | -|-----------|----------|----------| -| Directory missing | New feature | `templates/gap-planning/feature-new.md` | -| Directory exists | v2.0 UI update | `templates/gap-planning/feature-v2.md` | +--- -### Step 3: Read Required Files +## 🎯 QUICK START -| Layer | Files to Read | -|-------|---------------| -| Design | `design-spec-layer/STATUS.md`, feature STATUS.md files | -| Server | `server-layer/FINERACT_API.md`, feature API.md files | -| Client | `client-layer/LAYER_STATUS.md`, check `core/` | -| Feature | `feature-layer/LAYER_STATUS.md`, check `feature/` | -| Platform | Check `cmp-*/` modules | -| [name] | All design files + current implementation | +Pick a plan based on priority: -### Step 4: Fill Template +| Priority | Recommendation | Command | +|:--------:|----------------|---------| +| **P1** | Start with mockups | `/gap-planning design mockup` | +| **P2** | Then web platform | `/gap-planning platform web` | -Read template and replace placeholders with: -- Actual gaps from status files -- Concrete task lists -- Real file paths -- Code sketches -- Verification steps +Or jump directly to implementation: -## Template Reference +| Target | Command | +|--------|---------| +| Single feature mockup | `/design [feature-name]` | +| Feature implementation | `/implement [feature-name]` | +| Verify existing | `/verify [feature-name]` | + +--- + +## 🔄 WORKFLOW ``` -templates/gap-planning/ -├── dashboard.md # Full planning dashboard -├── layer-design.md # Design layer plan -├── layer-server.md # Server layer plan -├── layer-client.md # Client layer plan -├── layer-feature.md # Feature layer plan -├── layer-platform.md # Platform layer plan -├── feature-new.md # New feature creation -├── feature-v2.md # v2.0 UI upgrade -└── task-template.md # Individual task format +/gap-analysis → See all status (O(1) comprehensive view) + │ + ▼ +/gap-planning → See all plans (this view) + │ + ▼ +/gap-planning [target] → Get detailed step-by-step tasks + │ + ▼ +/implement [target] → Execute the plan + │ + ▼ +/verify [target] → Confirm completion + │ + ▼ +/gap-analysis → Updated status (loop back) ``` +╚══════════════════════════════════════════════════════════════════════════════╝ +``` + +--- + +## Detailed Plans (With Parameter) + +When a specific target is provided, show the **detailed step-by-step plan**. + +### Design Mockup Plan (`/gap-planning design mockup`) + +``` +## Design Mockup Generation Plan + +**Target**: 10 features needing mockups +**Effort**: Large (30 tasks across 10 features) +**Tool**: Google Stitch / Figma + +### Features & Tasks + +| # | Feature | Screens | Tasks | Priority | +|:-:|---------|:-------:|:-----:|:--------:| +| 1 | accounts | 3 | 6 | P1 | +| 2 | beneficiary | 4 | 8 | P1 | +| 3 | dashboard | 1 | 2 | P0 | +| 4 | home | 2 | 4 | P1 | +| 5 | loan-account | 4 | 8 | P1 | +| 6 | notification | 1 | 2 | P2 | +| 7 | recent-transaction | 1 | 2 | P2 | +| 8 | savings-account | 4 | 8 | P1 | +| 9 | share-account | 2 | 4 | P2 | +| 10 | transfer | 2 | 4 | P1 | + +### Per-Feature Tasks + +For each feature: +1. Read SPEC.md to understand screens +2. Read API.md to understand data +3. Generate PROMPTS_STITCH.md for Google Stitch +4. Generate mockup images +5. Create design-tokens.json +6. Update FIGMA_LINKS.md with URLs + +### Execution Commands + +| Feature | Command | +|---------|---------| +| dashboard (P0) | `/design dashboard mockup` | +| accounts | `/design accounts mockup` | +| beneficiary | `/design beneficiary mockup` | +| home | `/design home mockup` | +| loan-account | `/design loan-account mockup` | +| savings-account | `/design savings-account mockup` | +| transfer | `/design transfer mockup` | +| notification | `/design notification mockup` | +| recent-transaction | `/design recent-transaction mockup` | +| share-account | `/design share-account mockup` | + +### Verification + +After each feature: +- [ ] PROMPTS_STITCH.md exists +- [ ] Mockup images generated +- [ ] design-tokens.json created +- [ ] FIGMA_LINKS.md updated +- [ ] MOCKUPS_INDEX.md updated +``` + +### Platform Web Plan (`/gap-planning platform web`) + +``` +## Web Platform Stabilization Plan + +**Target**: Move web from experimental to stable +**Effort**: Medium (5 tasks) +**Module**: cmp-web + +### Current Status + +| Issue | Impact | Fix | +|-------|--------|-----| +| Kotlin/JS warnings | Build noise | Suppress/fix | +| CORS in production | API blocked | Server headers | +| WebSocket issues | Real-time fails | Polling fallback | +| Large bundle | Slow load | Tree shaking | +| Safari compat | 15% users | Polyfills | + +### Tasks + +1. **Fix compilation warnings** + - File: `cmp-web/build.gradle.kts` + - Action: Add suppressions or fix warnings + +2. **CORS configuration** + - File: Server config (Fineract) + - Action: Add Access-Control-Allow-Origin headers + +3. **WebSocket fallback** + - File: `cmp-shared/.../network/` + - Action: Implement polling when WebSocket fails + +4. **Bundle optimization** + - File: `cmp-web/build.gradle.kts` + - Action: Enable tree shaking, code splitting + +5. **Safari compatibility** + - File: `cmp-web/src/jsMain/resources/` + - Action: Add polyfills for missing APIs + +### Verification + +- [ ] `./gradlew :cmp-web:jsBrowserProductionWebpack` builds clean +- [ ] App loads in Safari +- [ ] API calls work in production +- [ ] Bundle size < 2MB +``` + +--- + +## Instructions for Claude + +### Step 1: Read O(1) Index Files + +Read these files for gap information: + +| Need | Index File | Path | +|------|------------|------| +| Design gaps | MOCKUPS_INDEX.md | `design-spec-layer/MOCKUPS_INDEX.md` | +| Feature gaps | MODULES_INDEX.md | `feature-layer/MODULES_INDEX.md` | +| Client gaps | FEATURE_MAP.md | `client-layer/FEATURE_MAP.md` | +| Platform gaps | LAYER_STATUS.md | `platform-layer/LAYER_STATUS.md` | + +### Step 2: Identify Gaps + +From index files, find items marked ⚠️ or ❌: +- Design: Features missing mockups, design-tokens +- Client: Missing services or repositories +- Feature: Missing screens or ViewModels +- Platform: Experimental or broken builds + +### Step 3: Generate Plans + +For each gap found: +1. Determine priority (P0/P1/P2) +2. List specific tasks +3. Estimate effort (S/M/L) +4. Provide execution commands +5. Add verification checklist + +### Step 4: Output Format + +- **No parameters**: Show all gaps + all plan summaries +- **With layer**: Show detailed plan for that layer +- **With feature**: Show detailed plan for that feature + +--- + ## Priority Guidelines | Priority | Criteria | Examples | |----------|----------|----------| | P0 | Critical - blocks other work | Missing feature module | -| P1 | High value - user-facing | v2.0 UI, new screens | -| P2 | Polish - nice to have | Animations, dark mode | +| P1 | High value - user-facing | v2.0 UI, mockups | +| P2 | Polish - nice to have | Animations, web fixes | ## Effort Guidelines -| Effort | Time | Scope | -|--------|------|-------| -| S | <1 hour | Single file, styling | -| M | 1-4 hours | Multiple files, component | -| L | >4 hours | Feature module, architecture | +| Effort | Scope | Tasks | +|--------|-------|:-----:| +| S | Single file change | 1-3 | +| M | Multiple files, one area | 4-10 | +| L | Feature-wide or cross-cutting | 10+ | + +--- ## Output Rules -1. Read actual status files first -2. Create prioritized task list (P0 → P1 → P2) -3. Include specific file paths -4. Provide code sketches (not full code) -5. Add verification steps -6. End with next command suggestion - -## Workflow - -``` -/gap-analysis → Identify gaps - ↓ -/gap-planning [target] → Create task list (this command) - ↓ -/implement [target] → Execute tasks - ↓ -/verify [target] → Confirm completion -``` +1. **Read index files only** - Use O(1) lookup +2. **Show all gaps** - No hidden information +3. **Show all commands** - For every gap +4. **Include effort estimates** - S/M/L +5. **Prioritize** - P0 → P1 → P2 +6. **Provide verification** - Checklist for each plan +7. **NO interactive questions** - Show everything, user decides diff --git a/.claude/commands/verify-tests.md b/.claude/commands/verify-tests.md new file mode 100644 index 000000000..1f8278998 --- /dev/null +++ b/.claude/commands/verify-tests.md @@ -0,0 +1,197 @@ +# Verify Tests Command + +Run and verify tests for features across the project. + +## Usage + +``` +/verify-tests # Run all tests, show status +/verify-tests auth # Run auth feature tests +/verify-tests auth unit # Run auth ViewModel tests only +/verify-tests auth ui # Run auth UI tests only +/verify-tests auth integration # Run auth integration tests +/verify-tests auth screenshot # Run auth screenshot tests +/verify-tests client # Run all client layer tests +/verify-tests feature # Run all feature layer tests +/verify-tests platform # Run all platform tests +``` + +--- + +## Output Format + +``` +╔══════════════════════════════════════════════════════════════════════════════╗ +║ VERIFY TESTS - [target] ║ +╠══════════════════════════════════════════════════════════════════════════════╣ + +## Test Execution + +| Type | Command | Tests | Passed | Failed | Status | +|------|---------|:-----:|:------:|:------:|:------:| +| Unit | `./gradlew :feature:auth:test` | 45 | 45 | 0 | ✅ | +| UI | `./gradlew :feature:auth:connectedDebugAndroidTest` | 25 | 23 | 2 | ⚠️ | +| Integration | `./gradlew :cmp-android:connectedDebugAndroidTest` | 8 | 8 | 0 | ✅ | +| Screenshot | `./gradlew :core:designsystem:compareRoborazziDebug` | 12 | 12 | 0 | ✅ | + +## Failed Tests + +| Test | Error | File | +|------|-------|------| +| LoginScreenTest.testErrorState | AssertionError | LoginScreenTest.kt:45 | +| LoginScreenTest.testLoading | TimeoutException | LoginScreenTest.kt:32 | + +## Coverage Summary + +| Component | Coverage | Target | Status | +|-----------|:--------:|:------:|:------:| +| ViewModel | 85% | 80% | ✅ | +| Screen | 72% | 60% | ✅ | +| Repository | 90% | 80% | ✅ | + +--- + +## Next Steps + +1. Fix failing tests: `/gap-planning auth testing` +2. Increase coverage: Add tests for uncovered paths +3. Re-run: `/verify-tests auth` + +╚══════════════════════════════════════════════════════════════════════════════╝ +``` + +--- + +## Test Commands Reference + +### Unit Tests (ViewModel + Repository) + +```bash +# All unit tests +./gradlew test + +# Specific module +./gradlew :feature:auth:test +./gradlew :core:data:test + +# With coverage +./gradlew test jacocoTestReport +``` + +### UI Tests (Compose) + +```bash +# All UI tests (requires emulator/device) +./gradlew connectedDebugAndroidTest + +# Specific feature +./gradlew :feature:auth:connectedDebugAndroidTest +``` + +### Integration Tests (E2E) + +```bash +# Full E2E tests +./gradlew :cmp-android:connectedDebugAndroidTest + +# Specific test class +./gradlew :cmp-android:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.mifos.mobile.AuthFlowTest +``` + +### Screenshot Tests (Roborazzi) + +```bash +# Record golden images +./gradlew :core:designsystem:recordRoborazziDebug + +# Compare against golden images +./gradlew :core:designsystem:compareRoborazziDebug + +# View differences +open build/reports/roborazzi/ +``` + +--- + +## Instructions for Claude + +### Step 1: Determine Test Scope + +| Parameter | Test Type | Gradle Command | +|-----------|-----------|----------------| +| (none) | All tests | `./gradlew test connectedDebugAndroidTest` | +| `[feature]` | Feature tests | `./gradlew :feature:[name]:test` | +| `[feature] unit` | ViewModel only | `./gradlew :feature:[name]:test` | +| `[feature] ui` | Screen tests | `./gradlew :feature:[name]:connectedDebugAndroidTest` | +| `[feature] integration` | E2E flow | `./gradlew :cmp-android:connectedDebugAndroidTest` | +| `[feature] screenshot` | Visual | `./gradlew :core:designsystem:compareRoborazziDebug` | +| `client` | Repositories | `./gradlew :core:data:test` | +| `feature` | All ViewModels | `./gradlew feature:test` | +| `platform` | All E2E | `./gradlew :cmp-android:connectedDebugAndroidTest` | + +### Step 2: Execute Tests + +Run the appropriate Gradle command and capture output. + +### Step 3: Parse Results + +From Gradle output, extract: +- Total tests run +- Tests passed +- Tests failed +- Failed test names and errors +- Coverage percentages (if available) + +### Step 4: Generate Report + +Display results in the formatted output above. + +### Step 5: Suggest Next Steps + +Based on results: +- If all pass: "All tests passing. Coverage: X%" +- If failures: List fixes needed with file paths +- If low coverage: Suggest adding tests + +--- + +## Feature Test Mapping + +| Feature | Unit Test Path | UI Test Path | +|---------|----------------|--------------| +| auth | `feature/auth/src/commonTest/` | `feature/auth/src/androidInstrumentedTest/` | +| home | `feature/home/src/commonTest/` | `feature/home/src/androidInstrumentedTest/` | +| accounts | `feature/account/src/commonTest/` | `feature/account/src/androidInstrumentedTest/` | +| beneficiary | `feature/beneficiary/src/commonTest/` | `feature/beneficiary/src/androidInstrumentedTest/` | +| loan-account | `feature/loan-account/src/commonTest/` | `feature/loan-account/src/androidInstrumentedTest/` | +| savings-account | `feature/savings-account/src/commonTest/` | `feature/savings-account/src/androidInstrumentedTest/` | +| transfer | `feature/transfer-process/src/commonTest/` | `feature/transfer-process/src/androidInstrumentedTest/` | +| notification | `feature/notification/src/commonTest/` | `feature/notification/src/androidInstrumentedTest/` | +| settings | `feature/settings/src/commonTest/` | `feature/settings/src/androidInstrumentedTest/` | +| qr | `feature/qr-code/src/commonTest/` | `feature/qr-code/src/androidInstrumentedTest/` | +| guarantor | `feature/guarantor/src/commonTest/` | `feature/guarantor/src/androidInstrumentedTest/` | +| passcode | `libs/mifos-passcode/src/commonTest/` | `libs/mifos-passcode/src/androidInstrumentedTest/` | +| location | `feature/location/src/commonTest/` | `feature/location/src/androidInstrumentedTest/` | +| user-profile | `feature/user-profile/src/commonTest/` | `feature/user-profile/src/androidInstrumentedTest/` | + +--- + +## Coverage Targets + +| Component | Minimum | Target | Excellent | +|-----------|:-------:|:------:|:---------:| +| ViewModel | 60% | 80% | 90%+ | +| Repository | 70% | 80% | 90%+ | +| Screen | 40% | 60% | 80%+ | +| Integration | - | 8 flows | 15+ flows | +| Screenshot | - | 30 golden | 60+ golden | + +--- + +## Related Commands + +- `/gap-analysis testing` - View testing status +- `/gap-planning testing [layer]` - Plan test implementation +- `/verify [feature]` - Verify implementation vs spec + +ARGUMENTS: $ARGUMENTS diff --git a/claude-product-cycle/client-layer/FEATURE_MAP.md b/claude-product-cycle/client-layer/FEATURE_MAP.md new file mode 100644 index 000000000..ab0499c49 --- /dev/null +++ b/claude-product-cycle/client-layer/FEATURE_MAP.md @@ -0,0 +1,169 @@ +# Feature → Client Components Map + +> **13 services** | **17 repositories** | **2 DI modules** + +--- + +## Feature to Components (O(1) Lookup) + +| Feature | Services | Repositories | Notes | +|---------|----------|--------------|-------| +| auth | AuthenticationService, RegistrationService, UserDetailsService | UserAuthRepository, UserDataRepository | Login, Register, Password | +| home | ClientService, NotificationService | HomeRepository, NotificationRepository | Dashboard, Profile | +| accounts | ClientService | AccountsRepository | Account listing | +| loan-account | LoanAccountsListService, GuarantorService | LoanRepository, GuarantorRepository, ReviewLoanApplicationRepository | Loan details | +| savings-account | SavingAccountsListService | SavingsAccountRepository | Savings details | +| share-account | ShareAccountService | ShareAccountRepository | Share details | +| beneficiary | BeneficiaryService | BeneficiaryRepository | TPT beneficiaries | +| transfer | ThirdPartyTransferService, SavingAccountsListService | TransferRepository, ThirdPartyTransferRepository | Fund transfer | +| notification | NotificationService | NotificationRepository | Push notifications | +| recent-transaction | RecentTransactionsService | RecentTransactionRepository | Transaction history | +| client-charge | ClientChargeService | ClientChargeRepository | Client charges | +| settings | UserDetailsService | UserDetailRepository | Password change | +| guarantor | GuarantorService | GuarantorRepository | Loan guarantors | +| user-profile | ClientService | ClientRepository, UserDetailRepository | Profile display | + +--- + +## Services Inventory (13) + +| Service | File | Key Methods | +|---------|------|-------------| +| AuthenticationService | AuthenticationService.kt | `authenticate()` | +| RegistrationService | RegistrationService.kt | `registerUser()`, `verifyUser()` | +| ClientService | ClientService.kt | `clients()`, `getClientForId()`, `getClientAccounts()`, `getClientImage()` | +| LoanAccountsListService | LoanAccountsListService.kt | `getLoanWithAssociations()`, `createLoansAccount()`, `withdrawLoanAccount()` | +| SavingAccountsListService | SavingAccountsListService.kt | `getSavingsWithAssociations()`, `makeTransfer()`, `submitSavingAccountApplication()` | +| BeneficiaryService | BeneficiaryService.kt | `beneficiaryList()`, `createBeneficiary()`, `updateBeneficiary()`, `deleteBeneficiary()` | +| ThirdPartyTransferService | ThirdPartyTransferService.kt | `accountTransferTemplate()`, `makeTransfer()` | +| NotificationService | NotificationService.kt | `getUserNotificationId()`, `registerNotification()`, `updateRegisterNotification()` | +| RecentTransactionsService | RecentTransactionsService.kt | `getRecentTransactionsList()` | +| UserDetailsService | UserDetailsService.kt | `updateAccountPassword()` | +| ShareAccountService | ShareAccountService.kt | `getShareProducts()`, `submitShareApplication()`, `getShareAccountDetails()` | +| GuarantorService | GuarantorService.kt | `getGuarantorList()`, `getGuarantorTemplate()`, `createGuarantor()` | +| ClientChargeService | ClientChargeService.kt | `getClientChargeList()`, `getChargeList()` | + +--- + +## Repositories Inventory (17) + +| Repository | Implementation | Depends On | +|------------|----------------|------------| +| AccountsRepository | AccountsRepositoryImp | ClientService | +| BeneficiaryRepository | BeneficiaryRepositoryImp | BeneficiaryService | +| ClientChargeRepository | ClientChargeRepositoryImp | ClientChargeService | +| ClientRepository | ClientRepositoryImp | ClientService | +| GuarantorRepository | GuarantorRepositoryImp | GuarantorService | +| HomeRepository | HomeRepositoryImp | ClientService | +| LoanRepository | LoanRepositoryImp | LoanAccountsListService | +| NotificationRepository | NotificationRepositoryImp | NotificationService | +| RecentTransactionRepository | RecentTransactionRepositoryImp | RecentTransactionsService | +| ReviewLoanApplicationRepository | ReviewLoanApplicationRepositoryImpl | LoanAccountsListService | +| SavingsAccountRepository | SavingsAccountRepositoryImp | SavingAccountsListService | +| ShareAccountRepository | ShareAccountRepositoryImp | ShareAccountService | +| ThirdPartyTransferRepository | ThirdPartyTransferRepositoryImp | ThirdPartyTransferService | +| TransferRepository | TransferRepositoryImp | SavingAccountsListService | +| UserAuthRepository | UserAuthRepositoryImp | AuthenticationService | +| UserDataRepository | AuthenticationUserRepository | DataStore | +| UserDetailRepository | UserDetailRepositoryImp | UserDetailsService | + +--- + +## DI Modules + +| Module | Location | Provides | +|--------|----------|----------| +| NetworkModule | `core/network/di/NetworkModule.kt` | HttpClient, KtorfitClient, DataManager | +| RepositoryModule | `core/data/di/RepositoryModule.kt` | All 17 repositories as singletons | + +--- + +## Reverse Lookup: Service → Features + +| Service | Used By Features | +|---------|------------------| +| AuthenticationService | auth | +| RegistrationService | auth | +| ClientService | home, accounts, user-profile | +| LoanAccountsListService | loan-account | +| SavingAccountsListService | savings-account, transfer | +| BeneficiaryService | beneficiary | +| ThirdPartyTransferService | transfer | +| NotificationService | home, notification | +| RecentTransactionsService | recent-transaction | +| UserDetailsService | auth, settings | +| ShareAccountService | share-account | +| GuarantorService | loan-account, guarantor | +| ClientChargeService | client-charge | + +--- + +## Reverse Lookup: Repository → Features + +| Repository | Used By Features | +|------------|------------------| +| AccountsRepository | accounts | +| BeneficiaryRepository | beneficiary | +| ClientChargeRepository | client-charge | +| ClientRepository | user-profile | +| GuarantorRepository | loan-account, guarantor | +| HomeRepository | home | +| LoanRepository | loan-account | +| NotificationRepository | home, notification | +| RecentTransactionRepository | recent-transaction | +| ReviewLoanApplicationRepository | loan-account | +| SavingsAccountRepository | savings-account | +| ShareAccountRepository | share-account | +| ThirdPartyTransferRepository | transfer | +| TransferRepository | transfer | +| UserAuthRepository | auth | +| UserDataRepository | auth | +| UserDetailRepository | settings, user-profile | + +--- + +## O(1) File Access + +| Need | Path | +|------|------| +| Service | `core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/services/[Name]Service.kt` | +| Repository Interface | `core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/repository/[Name]Repository.kt` | +| Repository Impl | `core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/repository/[Name]RepositoryImp.kt` | +| Network DI | `core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/di/NetworkModule.kt` | +| Data DI | `core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/di/RepositoryModule.kt` | + +--- + +## Architecture Flow + +``` +Feature (ViewModel) + ↓ +Repository (Interface) + ↓ +RepositoryImpl (Implementation) + ↓ +DataManager (Service Accessor) + ↓ +Service (Ktorfit API) + ↓ +HttpClient (Ktor) +``` + +--- + +## Related Files + +- [LAYER_STATUS.md](LAYER_STATUS.md) - Implementation status +- [LAYER_GUIDE.md](LAYER_GUIDE.md) - Architecture patterns +- [server-layer/API_INDEX.md](../server-layer/API_INDEX.md) - API endpoints + +--- + +## Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| New service added | Add to Services Inventory | +| New repository added | Add to Repositories Inventory + Reverse Lookup | +| Feature uses new service | Update Feature to Components table | diff --git a/claude-product-cycle/client-layer/TESTING_STATUS.md b/claude-product-cycle/client-layer/TESTING_STATUS.md new file mode 100644 index 000000000..ea23a8bde --- /dev/null +++ b/claude-product-cycle/client-layer/TESTING_STATUS.md @@ -0,0 +1,192 @@ +# Client Layer - Testing Status + +> Repository and service testing documentation + +--- + +## Overview + +The client layer handles data operations. Testing ensures repositories correctly transform API responses and handle errors. + +--- + +## Current State + +| Component | Total | Tested | Coverage | +|-----------|:-----:|:------:|:--------:| +| Services | 13 | 0 | 0% | +| Repositories | 17 | 14 | 82% | +| DataStore | 3 | 3 | 100% | + +--- + +## Testing Scope + +| Component | Test Type | Purpose | +|-----------|-----------|---------| +| Services | Unit Tests | Verify API call construction | +| Repositories | Unit Tests | Verify data transformation | +| DataStore | Unit Tests | Verify local persistence | + +--- + +## Repository Testing Status + +### Existing Tests (14) + +| # | Repository | Tests | File | +|:-:|------------|:-----:|------| +| 1 | AccountsRepository | 2 | `AccountsRepositoryTest.kt` | +| 2 | BeneficiaryRepository | 1 | `BeneficiaryRepositoryTest.kt` | +| 3 | ClientChargeRepository | 1 | `ClientChargeRepositoryTest.kt` | +| 4 | ClientRepository | 1 | `ClientRepositoryTest.kt` | +| 5 | GuarantorRepository | 1 | `GuarantorRepositoryTest.kt` | +| 6 | HomeRepository | 1 | `HomeRepositoryTest.kt` | +| 7 | LoanRepository | 1 | `LoanRepositoryTest.kt` | +| 8 | NotificationRepository | 1 | `NotificationRepositoryTest.kt` | +| 9 | RecentTransactionRepository | 1 | `RecentTransactionRepositoryTest.kt` | +| 10 | SavingsAccountRepository | 1 | `SavingsAccountRepositoryTest.kt` | +| 11 | ShareAccountRepository | 1 | `ShareAccountRepositoryTest.kt` | +| 12 | ThirdPartyTransferRepository | 1 | `ThirdPartyTransferRepositoryTest.kt` | +| 13 | TransferRepository | 1 | `TransferRepositoryTest.kt` | +| 14 | UserAuthRepository | - | (needs tests) | + +**Location**: `core/data/src/commonTest/kotlin/org/mifos/mobile/core/data/repository/` + +--- + +## Repository Test Coverage Matrix + +| # | Repository | Success | Error | Empty | Offline | Status | +|:-:|------------|:-------:|:-----:|:-----:|:-------:|:------:| +| 1 | AccountsRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 2 | BeneficiaryRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 3 | ClientChargeRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 4 | ClientRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 5 | GuarantorRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 6 | HomeRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 7 | LoanRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 8 | NotificationRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 9 | RecentTransactionRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 10 | SavingsAccountRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 11 | ShareAccountRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 12 | ThirdPartyTransferRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 13 | TransferRepository | ✅ | ⬜ | ⬜ | ⬜ | Partial | +| 14 | UserAuthRepository | ⬜ | ⬜ | ⬜ | ⬜ | Not Started | +| 15 | UserDataRepository | ⬜ | ⬜ | ⬜ | ⬜ | Not Started | +| 16 | UserPreferencesRepository | ⬜ | ⬜ | ⬜ | ⬜ | Not Started | +| 17 | RegistrationRepository | ⬜ | ⬜ | ⬜ | ⬜ | Not Started | + +**Legend**: ✅ Tested | ⬜ Not Tested + +--- + +## Missing Tests + +### Priority 1 - Auth Flow +- [ ] UserAuthRepository (login, logout, token refresh) +- [ ] UserPreferencesRepository (user settings) +- [ ] RegistrationRepository (sign up flow) + +### Priority 2 - Error Handling +- [ ] All repositories: error scenarios +- [ ] All repositories: empty response handling +- [ ] All repositories: offline caching + +### Priority 3 - Edge Cases +- [ ] Pagination handling +- [ ] Concurrent request handling +- [ ] Cache invalidation + +--- + +## Fake Repository Implementations + +For ViewModel testing, create fake repositories: + +**Location**: `core/testing/src/commonMain/kotlin/org/mifos/mobile/core/testing/fake/` + +```kotlin +class FakeHomeRepository : HomeRepository { + private var result: DataState = DataState.Loading + + fun setResult(result: DataState) { + this.result = result + } + + override suspend fun getHomeData(): Flow> = flow { + emit(result) + } +} +``` + +### Fake Repositories Needed + +| # | Fake Repository | For Testing | +|:-:|-----------------|-------------| +| 1 | FakeHomeRepository | HomeViewModel | +| 2 | FakeUserAuthRepository | LoginViewModel | +| 3 | FakeAccountsRepository | AccountsViewModel | +| 4 | FakeBeneficiaryRepository | BeneficiaryViewModel | +| 5 | FakeLoanRepository | LoanViewModel | +| 6 | FakeSavingsAccountRepository | SavingsViewModel | +| 7 | FakeTransferRepository | TransferViewModel | +| 8 | FakeNotificationRepository | NotificationViewModel | +| 9 | FakeSettingsRepository | SettingsViewModel | + +--- + +## Test Fixtures + +**Location**: `core/testing/src/commonMain/kotlin/org/mifos/mobile/core/testing/fixture/` + +```kotlin +object ClientAccountsFixture { + fun create( + savingsAccounts: List = emptyList(), + loanAccounts: List = emptyList(), + shareAccounts: List = emptyList() + ) = ClientAccounts( + savingsAccounts = savingsAccounts, + loanAccounts = loanAccounts, + shareAccounts = shareAccounts + ) + + fun withSavings() = create( + savingsAccounts = listOf(SavingAccountFixture.create()) + ) +} +``` + +--- + +## Implementation Priority + +| Phase | Scope | Tests | +|:-----:|-------|:-----:| +| 1 | Auth repositories | 15 | +| 2 | Error handling (all repos) | 34 | +| 3 | Fake implementations | 9 | +| 4 | Test fixtures | 12 | + +--- + +## Commands + +```bash +# Run client layer tests +./gradlew :core:data:test + +# Check test coverage +/gap-analysis client testing + +# Plan missing tests +/gap-planning client testing +``` + +--- + +## Related Files + +- [FEATURE_MAP.md](./FEATURE_MAP.md) - Feature to service mapping +- [LAYER_STATUS.md](./LAYER_STATUS.md) - Implementation status diff --git a/claude-product-cycle/design-spec-layer/FEATURES_INDEX.md b/claude-product-cycle/design-spec-layer/FEATURES_INDEX.md new file mode 100644 index 000000000..32c98d472 --- /dev/null +++ b/claude-product-cycle/design-spec-layer/FEATURES_INDEX.md @@ -0,0 +1,116 @@ +# Features Index - O(1) Lookup + +> **18 features** | All have SPEC + API + STATUS + +--- + +## Quick Lookup + +| # | Feature | Dir | SPEC | API | STATUS | Mockups | +|:-:|---------|-----|:----:|:---:|:------:|:-------:| +| 1 | accounts | features/accounts/ | ✅ | ✅ | ✅ | ⚠️ | +| 2 | auth | features/auth/ | ✅ | ✅ | ✅ | ✅ | +| 3 | beneficiary | features/beneficiary/ | ✅ | ✅ | ✅ | ⚠️ | +| 4 | client-charge | features/client-charge/ | ✅ | ✅ | ✅ | ⚠️ | +| 5 | dashboard | features/dashboard/ | ✅ | ✅ | ✅ | ⚠️ | +| 6 | guarantor | features/guarantor/ | ✅ | ✅ | ✅ | ⚠️ | +| 7 | home | features/home/ | ✅ | ✅ | ✅ | ⚠️ | +| 8 | loan-account | features/loan-account/ | ✅ | ✅ | ✅ | ⚠️ | +| 9 | location | features/location/ | ✅ | ✅ | ✅ | ⚠️ | +| 10 | notification | features/notification/ | ✅ | ✅ | ✅ | ⚠️ | +| 11 | passcode | features/passcode/ | ✅ | ✅ | ✅ | ⚠️ | +| 12 | qr | features/qr/ | ✅ | ✅ | ✅ | ⚠️ | +| 13 | recent-transaction | features/recent-transaction/ | ✅ | ✅ | ✅ | ⚠️ | +| 14 | savings-account | features/savings-account/ | ✅ | ✅ | ✅ | ⚠️ | +| 15 | settings | features/settings/ | ✅ | ✅ | ✅ | ⚠️ | +| 16 | share-account | features/share-account/ | ✅ | ✅ | ✅ | ⚠️ | +| 17 | transfer | features/transfer/ | ✅ | ✅ | ✅ | ⚠️ | + +**Legend**: ✅ Complete | ⚠️ Partial | ❌ Missing + +--- + +## O(1) File Access + +| Need | Path | +|------|------| +| Specification | `features/[name]/SPEC.md` | +| API Endpoints | `features/[name]/API.md` | +| Feature Status | `features/[name]/STATUS.md` | +| Mockups | `features/[name]/mockups/` | +| Design Tokens | `features/[name]/mockups/design-tokens.json` | + +--- + +## Feature Categories + +### Authentication & Security (3) + +| Feature | Purpose | +|---------|---------| +| auth | Login, Registration, Password recovery | +| passcode | Biometric/PIN security | +| settings | Password change, security settings | + +### Account Management (4) + +| Feature | Purpose | +|---------|---------| +| accounts | Account overview, all account types | +| savings-account | Savings account details, operations | +| loan-account | Loan details, repayment schedule | +| share-account | Share account details | + +### Transactions (3) + +| Feature | Purpose | +|---------|---------| +| beneficiary | Third-party transfer beneficiaries | +| transfer | Fund transfers (self & TPT) | +| recent-transaction | Transaction history | + +### Information & Utilities (5) + +| Feature | Purpose | +|---------|---------| +| home | Dashboard, quick actions | +| notification | Push notifications | +| qr | QR code generation/scanning | +| location | Branch locator | +| client-charge | Client charges/fees | + +### Supporting Features (2) + +| Feature | Purpose | +|---------|---------| +| guarantor | Loan guarantor management | +| dashboard | Main navigation hub | + +--- + +## Design Progress Summary + +| Status | Count | Features | +|--------|:-----:|----------| +| Complete (all mockups) | 1 | auth | +| Partial (some mockups) | 16 | All others | +| Not Started | 0 | - | + +--- + +## Related Files + +- [MOCKUPS_INDEX.md](MOCKUPS_INDEX.md) - Mockup completion status +- [STATUS.md](STATUS.md) - Layer-wide status tracker +- [TOOL_CONFIG.md](TOOL_CONFIG.md) - Design tool configuration + +--- + +## Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| New feature added | Add row to Quick Lookup | +| SPEC.md created | Update SPEC column to ✅ | +| API.md created | Update API column to ✅ | +| Mockups complete | Update Mockups column to ✅ | diff --git a/claude-product-cycle/design-spec-layer/MOCKUPS_INDEX.md b/claude-product-cycle/design-spec-layer/MOCKUPS_INDEX.md new file mode 100644 index 000000000..0255c8f63 --- /dev/null +++ b/claude-product-cycle/design-spec-layer/MOCKUPS_INDEX.md @@ -0,0 +1,152 @@ +# Mockups Index - O(1) Lookup + +> **Figma**: 7/18 | **Stitch**: 11/18 | **Tokens**: 8/18 + +--- + +## Status Matrix + +| Feature | FIGMA_LINKS | PROMPTS_FIGMA | PROMPTS_STITCH | design-tokens | +|---------|:-----------:|:-------------:|:--------------:|:-------------:| +| accounts | ❌ | ✅ | ✅ | ❌ | +| auth | ✅ | ✅ | ✅ | ✅ | +| beneficiary | ❌ | ✅ | ✅ | ❌ | +| client-charge | ✅ | ❌ | ❌ | ✅ | +| dashboard | ❌ | ✅ | ✅ | ✅ | +| guarantor | ✅ | ❌ | ❌ | ✅ | +| home | ❌ | ✅ | ✅ | ❌ | +| loan-account | ❌ | ✅ | ✅ | ❌ | +| location | ✅ | ❌ | ❌ | ✅ | +| notification | ❌ | ✅ | ✅ | ❌ | +| passcode | ✅ | ❌ | ❌ | ✅ | +| qr | ✅ | ❌ | ❌ | ✅ | +| recent-transaction | ❌ | ✅ | ✅ | ❌ | +| savings-account | ❌ | ✅ | ✅ | ❌ | +| settings | ✅ | ❌ | ❌ | ✅ | +| share-account | ❌ | ✅ | ✅ | ❌ | +| transfer | ❌ | ✅ | ✅ | ❌ | + +**Legend**: ✅ Exists | ❌ Missing + +--- + +## O(1) File Access + +| Need | Path | +|------|------| +| Figma Links | `features/[name]/mockups/FIGMA_LINKS.md` | +| Figma Prompts | `features/[name]/mockups/PROMPTS_FIGMA.md` | +| Stitch Prompts | `features/[name]/mockups/PROMPTS_STITCH.md` | +| Design Tokens | `features/[name]/mockups/design-tokens.json` | + +--- + +## Completion Summary + +### Complete (All 4 Files) + +| Feature | Status | +|---------|--------| +| auth | ✅ All mockup files present | + +### Has Figma Links + Tokens (Need Prompts) + +| Feature | Has | Needs | +|---------|-----|-------| +| client-charge | FIGMA_LINKS, design-tokens | PROMPTS_FIGMA, PROMPTS_STITCH | +| guarantor | FIGMA_LINKS, design-tokens | PROMPTS_FIGMA, PROMPTS_STITCH | +| location | FIGMA_LINKS, design-tokens | PROMPTS_FIGMA, PROMPTS_STITCH | +| passcode | FIGMA_LINKS, design-tokens | PROMPTS_FIGMA, PROMPTS_STITCH | +| qr | FIGMA_LINKS, design-tokens | PROMPTS_FIGMA, PROMPTS_STITCH | +| settings | FIGMA_LINKS, design-tokens | PROMPTS_FIGMA, PROMPTS_STITCH | + +### Has Prompts (Need Figma Links + Tokens) + +| Feature | Has | Needs | +|---------|-----|-------| +| accounts | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| beneficiary | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| home | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| loan-account | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| notification | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| recent-transaction | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| savings-account | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| share-account | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | +| transfer | PROMPTS_FIGMA, PROMPTS_STITCH | FIGMA_LINKS, design-tokens | + +### Has Prompts + Tokens (Need Figma Links) + +| Feature | Has | Needs | +|---------|-----|-------| +| dashboard | PROMPTS_FIGMA, PROMPTS_STITCH, design-tokens | FIGMA_LINKS | + +--- + +## Gaps by File Type + +### Need FIGMA_LINKS.md (11 features) + +``` +accounts, beneficiary, dashboard, home, loan-account, +notification, recent-transaction, savings-account, +share-account, transfer +``` + +### Need design-tokens.json (9 features) + +``` +accounts, beneficiary, home, loan-account, notification, +recent-transaction, savings-account, share-account, transfer +``` + +### Need PROMPTS_FIGMA.md (6 features) + +``` +client-charge, guarantor, location, passcode, qr, settings +``` + +### Need PROMPTS_STITCH.md (6 features) + +``` +client-charge, guarantor, location, passcode, qr, settings +``` + +--- + +## Design Tool Workflows + +### Figma-First Workflow + +``` +1. Create in Figma +2. Add link to FIGMA_LINKS.md +3. Export design-tokens.json +``` + +### AI-Generation Workflow (Google Stitch) + +``` +1. Write PROMPTS_STITCH.md +2. Generate mockups +3. Export to Figma +4. Update FIGMA_LINKS.md +``` + +--- + +## Related Files + +- [FEATURES_INDEX.md](FEATURES_INDEX.md) - Feature overview +- [TOOL_CONFIG.md](TOOL_CONFIG.md) - Tool configuration +- [STATUS.md](STATUS.md) - Layer status + +--- + +## Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| Figma link added | Update FIGMA_LINKS column to ✅ | +| Prompts created | Update respective column to ✅ | +| Tokens exported | Update design-tokens column to ✅ | +| All 4 files done | Move to "Complete" section | diff --git a/claude-product-cycle/design-spec-layer/TESTING_STATUS.md b/claude-product-cycle/design-spec-layer/TESTING_STATUS.md new file mode 100644 index 000000000..8941ef2ca --- /dev/null +++ b/claude-product-cycle/design-spec-layer/TESTING_STATUS.md @@ -0,0 +1,125 @@ +# Design Layer - Testing Status + +> Testing specifications for design layer validation + +--- + +## Overview + +The design layer defines **what** should be tested. Each feature specification includes acceptance criteria that translate directly to test cases. + +--- + +## Testing Scope + +| Component | Test Type | Purpose | +|-----------|-----------|---------| +| SPEC.md | Contract Tests | Verify implementation matches specification | +| API.md | API Contract Tests | Verify API usage matches documentation | +| Mockups | Screenshot Tests | Visual regression testing | +| design-tokens.json | Theme Tests | Verify design tokens applied correctly | + +--- + +## Per-Feature Testing Requirements + +### Test Coverage Matrix + +| # | Feature | Contract | API | Screenshot | Status | +|:-:|---------|:--------:|:---:|:----------:|:------:| +| 1 | auth | ⬜ | ⬜ | ⬜ | Not Started | +| 2 | home | ⬜ | ⬜ | ⬜ | Not Started | +| 3 | accounts | ⬜ | ⬜ | ⬜ | Not Started | +| 4 | savings-account | ⬜ | ⬜ | ⬜ | Not Started | +| 5 | loan-account | ⬜ | ⬜ | ⬜ | Not Started | +| 6 | share-account | ⬜ | ⬜ | ⬜ | Not Started | +| 7 | beneficiary | ⬜ | ⬜ | ⬜ | Not Started | +| 8 | transfer | ⬜ | ⬜ | ⬜ | Not Started | +| 9 | recent-transaction | ⬜ | ⬜ | ⬜ | Not Started | +| 10 | notification | ⬜ | ⬜ | ⬜ | Not Started | +| 11 | settings | ⬜ | ⬜ | ⬜ | Not Started | +| 12 | passcode | ⬜ | - | ⬜ | Not Started | +| 13 | guarantor | ⬜ | ⬜ | ⬜ | Not Started | +| 14 | qr | ⬜ | - | ⬜ | Not Started | +| 15 | location | ⬜ | - | ⬜ | Not Started | +| 16 | client-charge | ⬜ | ⬜ | ⬜ | Not Started | +| 17 | dashboard | ⬜ | ⬜ | ⬜ | Not Started | + +**Legend**: ✅ Complete | ⬜ Not Started | - N/A + +--- + +## Testing Specification Template + +Each feature's SPEC.md should include a `## Test Scenarios` section: + +```markdown +## Test Scenarios + +### Loading State +- [ ] Shows loading indicator when data is being fetched +- [ ] Disables user interaction during loading + +### Success State +- [ ] Displays all required data fields +- [ ] Data matches API response +- [ ] Navigation works correctly + +### Error State +- [ ] Shows error message for network failures +- [ ] Retry button is visible and functional +- [ ] Error message is user-friendly + +### Empty State +- [ ] Shows appropriate message when no data +- [ ] Optional: Call-to-action for creating data + +### Validation +- [ ] Required fields show error when empty +- [ ] Format validation (email, phone, etc.) +- [ ] Business rules validation +``` + +--- + +## Screenshot Test Baseline + +For mockups to become screenshot test baselines: + +| Step | Action | Output | +|:----:|--------|--------| +| 1 | Generate mockups (Google Stitch/Figma) | PNG/SVG files | +| 2 | Export to `mockups/` folder | Light + Dark variants | +| 3 | Configure Roborazzi | Golden images | +| 4 | Run screenshot tests | Compare against baseline | + +--- + +## Implementation Priority + +| Priority | Features | Reason | +|:--------:|----------|--------| +| P0 | auth, home | Core user flow | +| P1 | accounts, transfer, beneficiary | Primary functionality | +| P2 | loan-account, savings-account | Account management | +| P3 | Others | Supporting features | + +--- + +## Commands + +```bash +# Validate feature spec has test scenarios +/verify [feature] testing + +# Generate test cases from spec +/gap-planning [feature] testing +``` + +--- + +## Related Files + +- [FEATURES_INDEX.md](./FEATURES_INDEX.md) - Feature status +- [MOCKUPS_INDEX.md](./MOCKUPS_INDEX.md) - Mockup status +- Each feature's `SPEC.md` - Detailed specifications diff --git a/claude-product-cycle/feature-layer/MODULES_INDEX.md b/claude-product-cycle/feature-layer/MODULES_INDEX.md new file mode 100644 index 000000000..278d69457 --- /dev/null +++ b/claude-product-cycle/feature-layer/MODULES_INDEX.md @@ -0,0 +1,113 @@ +# Feature Modules Index - O(1) Lookup + +> **23 modules** | **63 screens** | **49 ViewModels** | **21 DI modules** + +--- + +## Quick Lookup + +| # | Module | Path | DI | VMs | Screens | +|:-:|--------|------|:--:|:---:|:-------:| +| 1 | accounts | feature/accounts | ✅ | 3 | 3 | +| 2 | auth | feature/auth | ✅ | 5 | 6 | +| 3 | beneficiary | feature/beneficiary | ✅ | 4 | 4 | +| 4 | client-charge | feature/client-charge | ✅ | 2 | 2 | +| 5 | guarantor | feature/guarantor | ✅ | 3 | 3 | +| 6 | home | feature/home | ✅ | 1 | 1 | +| 7 | loan-account | feature/loan-account | ✅ | 4 | 4 | +| 8 | loan-application | feature/loan-application | ✅ | 4 | 3 | +| 9 | location | feature/location | ❌ | 0 | 1 | +| 10 | notification | feature/notification | ✅ | 1 | 1 | +| 11 | onboarding-language | feature/onboarding-language | ✅ | 1 | 1 | +| 12 | passcode | feature/passcode | ✅ | 2 | 2 | +| 13 | qr | feature/qr | ✅ | 3 | 3 | +| 14 | recent-transaction | feature/recent-transaction | ✅ | 1 | 1 | +| 15 | savings-account | feature/savings-account | ✅ | 3 | 4 | +| 16 | savings-application | feature/savings-application | ✅ | 2 | 2 | +| 17 | settings | feature/settings | ✅ | 5 | 9 | +| 18 | share-account | feature/share-account | ✅ | 2 | 2 | +| 19 | share-application | feature/share-application | ✅ | 2 | 2 | +| 20 | status | feature/status | ✅ | 1 | 0 | +| 21 | third-party-transfer | feature/third-party-transfer | ✅ | 1 | 1 | +| 22 | transfer-process | feature/transfer-process | ✅ | 2 | 2 | +| 23 | user-profile | feature/user-profile | ✅ | 1 | 1 | + +--- + +## Base Path Pattern + +``` +feature/[module]/src/commonMain/kotlin/org/mifos/mobile/feature/[package]/ +``` + +--- + +## O(1) File Access + +| Need | Path Pattern | +|------|--------------| +| Screen | `feature/[module]/.../ui/[Name]Screen.kt` | +| ViewModel | `feature/[module]/.../viewmodel/[Name]ViewModel.kt` | +| DI Module | `feature/[module]/.../di/[Name]Module.kt` | +| Navigation | `feature/[module]/.../navigation/[Name]Navigation.kt` | + +--- + +## Module Details + +### High-Complexity Modules (5+ screens/VMs) + +| Module | Screens | ViewModels | Key Features | +|--------|:-------:|:----------:|--------------| +| auth | 6 | 5 | Login, Registration, OTP, Password | +| settings | 9 | 5 | Theme, Language, Password, About | +| loan-account | 4 | 4 | Details, Repayment, Summary | +| beneficiary | 4 | 4 | List, Add, Edit, Delete | + +### Standard Modules (2-4 screens/VMs) + +| Module | Screens | ViewModels | Key Features | +|--------|:-------:|:----------:|--------------| +| accounts | 3 | 3 | List, Transactions, Details | +| guarantor | 3 | 3 | List, Add, Details | +| loan-application | 3 | 4 | Apply, Confirm, Upload | +| passcode | 2 | 2 | Set, Verify | +| qr | 3 | 3 | Display, Read, Import | +| savings-account | 4 | 3 | Details, Update, Withdraw | +| savings-application | 2 | 2 | Apply, Fill | +| share-account | 2 | 2 | List, Details | +| share-application | 2 | 2 | Apply, Fill | +| transfer-process | 2 | 2 | Make, Process | + +### Simple Modules (1 screen/VM) + +| Module | Screens | ViewModels | Key Features | +|--------|:-------:|:----------:|--------------| +| home | 1 | 1 | Dashboard | +| notification | 1 | 1 | List | +| recent-transaction | 1 | 1 | History | +| location | 1 | 0 | Branch Map | +| onboarding-language | 1 | 1 | Language Selection | +| third-party-transfer | 1 | 1 | TPT | +| user-profile | 1 | 1 | Profile | +| client-charge | 2 | 2 | List, Details | +| status | 0 | 1 | Status tracking | + +--- + +## Related Files + +- [SCREENS_INDEX.md](SCREENS_INDEX.md) - All 63 screens with ViewModels +- [LAYER_STATUS.md](LAYER_STATUS.md) - Implementation status +- [LAYER_GUIDE.md](LAYER_GUIDE.md) - Architecture patterns + +--- + +## Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| New module added | Add row to Quick Lookup table | +| Screen added to module | Update Screens count | +| ViewModel added | Update VMs count | +| DI module added | Update DI column | diff --git a/claude-product-cycle/feature-layer/SCREENS_INDEX.md b/claude-product-cycle/feature-layer/SCREENS_INDEX.md new file mode 100644 index 000000000..54848594a --- /dev/null +++ b/claude-product-cycle/feature-layer/SCREENS_INDEX.md @@ -0,0 +1,266 @@ +# Screens Index - O(1) Lookup + +> **63 screens** across **23 modules** + +--- + +## By Module (Alphabetical) + +### accounts (3 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| AccountsScreen | AccountsViewModel | ui/AccountsScreen.kt | +| TransactionScreen | TransactionViewModel | ui/TransactionScreen.kt | +| TransactionDetailsScreen | TransactionDetailsViewModel | ui/TransactionDetailsScreen.kt | + +### auth (6 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| LoginScreen | LoginViewModel | ui/LoginScreen.kt | +| OtpAuthenticationScreen | OtpAuthenticationViewModel | ui/OtpAuthenticationScreen.kt | +| RecoverPasswordScreen | RecoverPasswordViewModel | ui/RecoverPasswordScreen.kt | +| RegistrationScreen | RegistrationViewModel | ui/RegistrationScreen.kt | +| SetPasswordScreen | SetPasswordViewModel | ui/SetPasswordScreen.kt | +| UploadIdScreen | - | ui/UploadIdScreen.kt | + +### beneficiary (4 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| BeneficiaryApplicationScreen | BeneficiaryApplicationViewModel | ui/BeneficiaryApplicationScreen.kt | +| BeneficiaryApplicationConfirmationScreen | BeneficiaryApplicationConfirmationViewModel | ui/BeneficiaryApplicationConfirmationScreen.kt | +| BeneficiaryDetailScreen | BeneficiaryDetailViewModel | ui/BeneficiaryDetailScreen.kt | +| BeneficiaryListScreen | BeneficiaryListViewModel | ui/BeneficiaryListScreen.kt | + +### client-charge (2 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| ChargeDetailScreen | ChargeDetailsViewModel | ui/ChargeDetailScreen.kt | +| ClientChargeScreen | ClientChargeViewModel | ui/ClientChargeScreen.kt | + +### guarantor (3 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| AddGuarantorScreen | AddGuarantorViewModel | ui/AddGuarantorScreen.kt | +| GuarantorDetailScreen | GuarantorDetailViewModel | ui/GuarantorDetailScreen.kt | +| GuarantorListScreen | GuarantorListViewModel | ui/GuarantorListScreen.kt | + +### home (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| HomeScreen | HomeViewModel | ui/HomeScreen.kt | + +### loan-account (4 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| AccountSummaryScreen | AccountSummaryViewModel | ui/AccountSummaryScreen.kt | +| LoanAccountDetailsScreen | LoanAccountDetailsViewModel | ui/LoanAccountDetailsScreen.kt | +| LoanAccountScreen | LoanAccountViewModel | ui/LoanAccountScreen.kt | +| RepaymentScheduleScreen | RepaymentScheduleViewModel | ui/RepaymentScheduleScreen.kt | + +### loan-application (3 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| ConfirmDetailsScreen | ConfirmDetailsViewModel | ui/ConfirmDetailsScreen.kt | +| LoanApplyScreen | LoanApplyViewModel | ui/LoanApplyScreen.kt | +| UploadDocsScreen | - | ui/UploadDocsScreen.kt | + +### location (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| LocationScreen | - | ui/LocationScreen.kt | + +### notification (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| NotificationScreen | NotificationViewModel | ui/NotificationScreen.kt | + +### onboarding-language (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| SetOnboardingLanguageScreen | SetOnboardingLanguageViewModel | ui/SetOnboardingLanguageScreen.kt | + +### passcode (2 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| PasscodeScreen | PasscodeViewModel | ui/PasscodeScreen.kt | +| VerifyPasscodeScreen | VerifyPasscodeViewModel | ui/VerifyPasscodeScreen.kt | + +### qr (3 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| QrCodeDisplayScreen | QrCodeDisplayViewModel | ui/QrCodeDisplayScreen.kt | +| QrCodeImportScreen | QrCodeImportViewModel | ui/QrCodeImportScreen.kt | +| QrCodeReaderScreen | QrCodeReaderViewModel | ui/QrCodeReaderScreen.kt | + +### recent-transaction (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| RecentTransactionScreen | RecentTransactionViewModel | ui/RecentTransactionScreen.kt | + +### savings-account (4 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| AccountUpdateScreen | AccountUpdateViewModel | ui/AccountUpdateScreen.kt | +| AccountWithdrawScreen | AccountWithdrawViewModel | ui/AccountWithdrawScreen.kt | +| SavingsAccountDetailsScreen | SavingsAccountDetailsViewModel | ui/SavingsAccountDetailsScreen.kt | +| SavingsAccountScreen | - | ui/SavingsAccountScreen.kt | + +### savings-application (2 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| FillApplicationScreen | FillApplicationViewModel | ui/FillApplicationScreen.kt | +| SavingsApplyScreen | SavingsApplyViewModel | ui/SavingsApplyScreen.kt | + +### settings (9 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| AboutScreen | - | ui/AboutScreen.kt | +| AppInfoScreen | - | ui/AppInfoScreen.kt | +| ChangePasswordScreen | ChangePasswordViewModel | ui/ChangePasswordScreen.kt | +| ChangeThemeScreen | ChangeThemeViewModel | ui/ChangeThemeScreen.kt | +| FaqScreen | - | ui/FaqScreen.kt | +| HelpScreen | - | ui/HelpScreen.kt | +| LanguageScreen | LanguageViewModel | ui/LanguageScreen.kt | +| SettingsScreen | SettingsViewModel | ui/SettingsScreen.kt | +| UpdatePasscodeScreen | UpdatePasscodeViewModel | ui/UpdatePasscodeScreen.kt | + +### share-account (2 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| ShareAccountDetailsScreen | ShareAccountDetailsViewModel | ui/ShareAccountDetailsScreen.kt | +| ShareAccountScreen | ShareAccountViewModel | ui/ShareAccountScreen.kt | + +### share-application (2 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| FillApplicationScreen | FillApplicationViewModel | ui/FillApplicationScreen.kt | +| ShareApplyScreen | ShareApplyViewModel | ui/ShareApplyScreen.kt | + +### third-party-transfer (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| TptScreen | TptViewModel | ui/TptScreen.kt | + +### transfer-process (2 screens) + +| Screen | ViewModel | File | +|--------|-----------|------| +| MakeTransferScreen | MakeTransferViewModel | ui/MakeTransferScreen.kt | +| TransferProcessScreen | TransferProcessViewModel | ui/TransferProcessScreen.kt | + +### user-profile (1 screen) + +| Screen | ViewModel | File | +|--------|-----------|------| +| UserProfileScreen | UserProfileViewModel | ui/UserProfileScreen.kt | + +--- + +## Search by Screen Name (Alphabetical) + +| Screen | Module | +|--------|--------| +| AboutScreen | settings | +| AccountsScreen | accounts | +| AccountSummaryScreen | loan-account | +| AccountUpdateScreen | savings-account | +| AccountWithdrawScreen | savings-account | +| AddGuarantorScreen | guarantor | +| AppInfoScreen | settings | +| BeneficiaryApplicationConfirmationScreen | beneficiary | +| BeneficiaryApplicationScreen | beneficiary | +| BeneficiaryDetailScreen | beneficiary | +| BeneficiaryListScreen | beneficiary | +| ChangePasswordScreen | settings | +| ChangeThemeScreen | settings | +| ChargeDetailScreen | client-charge | +| ClientChargeScreen | client-charge | +| ConfirmDetailsScreen | loan-application | +| FaqScreen | settings | +| FillApplicationScreen | savings-application, share-application | +| GuarantorDetailScreen | guarantor | +| GuarantorListScreen | guarantor | +| HelpScreen | settings | +| HomeScreen | home | +| LanguageScreen | settings | +| LoanAccountDetailsScreen | loan-account | +| LoanAccountScreen | loan-account | +| LoanApplyScreen | loan-application | +| LocationScreen | location | +| LoginScreen | auth | +| MakeTransferScreen | transfer-process | +| NotificationScreen | notification | +| OtpAuthenticationScreen | auth | +| PasscodeScreen | passcode | +| QrCodeDisplayScreen | qr | +| QrCodeImportScreen | qr | +| QrCodeReaderScreen | qr | +| RecentTransactionScreen | recent-transaction | +| RecoverPasswordScreen | auth | +| RegistrationScreen | auth | +| RepaymentScheduleScreen | loan-account | +| SavingsAccountDetailsScreen | savings-account | +| SavingsAccountScreen | savings-account | +| SavingsApplyScreen | savings-application | +| SetOnboardingLanguageScreen | onboarding-language | +| SetPasswordScreen | auth | +| SettingsScreen | settings | +| ShareAccountDetailsScreen | share-account | +| ShareAccountScreen | share-account | +| ShareApplyScreen | share-application | +| TptScreen | third-party-transfer | +| TransactionDetailsScreen | accounts | +| TransactionScreen | accounts | +| TransferProcessScreen | transfer-process | +| UpdatePasscodeScreen | settings | +| UploadDocsScreen | loan-application | +| UploadIdScreen | auth | +| UserProfileScreen | user-profile | +| VerifyPasscodeScreen | passcode | + +--- + +## O(1) File Access + +| Need | Path Pattern | +|------|--------------| +| Screen file | `feature/[module]/src/commonMain/kotlin/org/mifos/mobile/feature/../ui/[Screen].kt` | +| ViewModel | Same directory structure, `viewmodel/[ViewModel].kt` | + +--- + +## Related Files + +- [MODULES_INDEX.md](MODULES_INDEX.md) - Module overview +- [LAYER_STATUS.md](LAYER_STATUS.md) - Implementation status +- [LAYER_GUIDE.md](LAYER_GUIDE.md) - Architecture patterns + +--- + +## Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| New screen added | Add to module section + alphabetical list | +| Screen renamed | Update both tables | +| ViewModel added | Update ViewModel column | diff --git a/claude-product-cycle/feature-layer/TESTING_STATUS.md b/claude-product-cycle/feature-layer/TESTING_STATUS.md new file mode 100644 index 000000000..03256fe0f --- /dev/null +++ b/claude-product-cycle/feature-layer/TESTING_STATUS.md @@ -0,0 +1,323 @@ +# Feature Layer - Testing Status + +> ViewModel, Screen, and Integration testing documentation + +--- + +## Overview + +The feature layer is the primary testing target. Each feature needs: +- ViewModel unit tests (state, events, actions) +- Screen UI tests (rendering, interactions) +- Integration tests (full user flows) + +--- + +## Current State + +| Component | Total | Tested | Coverage | +|-----------|:-----:|:------:|:--------:| +| ViewModels | 49 | 0 | 0% | +| Screens | 63 | 0 | 0% | +| Integration Flows | 8 | 0 | 0% | + +--- + +## Testing Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ FEATURE LAYER TESTING STACK │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────────┐ │ +│ │ Integration Tests (E2E Flows) │ │ +│ │ - Login → Passcode → Home │ │ +│ │ - Home → Transfer → Confirm │ │ +│ │ - Location: cmp-android/src/androidTest/ │ │ +│ └──────────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌──────────────────────────────────────────────────────────────────────┐ │ +│ │ UI Tests (Screen Tests) │ │ +│ │ - Compose test rules │ │ +│ │ - TestTag-based assertions │ │ +│ │ - Location: feature/*/src/androidInstrumentedTest/ │ │ +│ └──────────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌──────────────────────────────────────────────────────────────────────┐ │ +│ │ Unit Tests (ViewModel Tests) │ │ +│ │ - StateFlow testing with Turbine │ │ +│ │ - Event emission testing │ │ +│ │ - Action handling testing │ │ +│ │ - Location: feature/*/src/commonTest/ │ │ +│ └──────────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## ViewModel Testing Status + +### By Feature + +| # | Feature | VMs | Tests | Coverage | Status | +|:-:|---------|:---:|:-----:|:--------:|:------:| +| 1 | auth | 5 | 0 | 0% | ⬜ Not Started | +| 2 | home | 1 | 0 | 0% | ⬜ Not Started | +| 3 | accounts | 3 | 0 | 0% | ⬜ Not Started | +| 4 | savings-account | 3 | 0 | 0% | ⬜ Not Started | +| 5 | loan-account | 4 | 0 | 0% | ⬜ Not Started | +| 6 | share-account | 2 | 0 | 0% | ⬜ Not Started | +| 7 | beneficiary | 4 | 0 | 0% | ⬜ Not Started | +| 8 | transfer-process | 2 | 0 | 0% | ⬜ Not Started | +| 9 | recent-transaction | 1 | 0 | 0% | ⬜ Not Started | +| 10 | notification | 1 | 0 | 0% | ⬜ Not Started | +| 11 | settings | 5 | 0 | 0% | ⬜ Not Started | +| 12 | mifos-passcode | 2 | 0 | 0% | ⬜ Not Started | +| 13 | guarantor | 3 | 0 | 0% | ⬜ Not Started | +| 14 | qr-code | 3 | 0 | 0% | ⬜ Not Started | +| 15 | location | 1 | 0 | 0% | ⬜ Not Started | +| 16 | user-profile | 2 | 0 | 0% | ⬜ Not Started | + +**Legend**: ✅ 80%+ | ⚠️ <80% | ⬜ 0% + +--- + +## UI Testing Status + +### TestTag Coverage + +| # | Feature | Screens | TestTags | Coverage | Status | +|:-:|---------|:-------:|:--------:|:--------:|:------:| +| 1 | auth | 6 | ~40% | Partial | ⚠️ | +| 2 | home | 1 | ~30% | Partial | ⚠️ | +| 3 | accounts | 3 | ~30% | Partial | ⚠️ | +| 4 | savings-account | 4 | ~30% | Partial | ⚠️ | +| 5 | loan-account | 4 | ~30% | Partial | ⚠️ | +| 6 | share-account | 2 | ~30% | Partial | ⚠️ | +| 7 | beneficiary | 4 | ~30% | Partial | ⚠️ | +| 8 | transfer-process | 2 | ~30% | Partial | ⚠️ | +| 9 | recent-transaction | 1 | ~30% | Partial | ⚠️ | +| 10 | notification | 1 | ~30% | Partial | ⚠️ | +| 11 | settings | 9 | ~30% | Partial | ⚠️ | +| 12 | mifos-passcode | 2 | ~30% | Partial | ⚠️ | +| 13 | guarantor | 3 | ~30% | Partial | ⚠️ | +| 14 | qr-code | 3 | ~30% | Partial | ⚠️ | +| 15 | location | 1 | ~30% | Partial | ⚠️ | +| 16 | user-profile | 2 | ~30% | Partial | ⚠️ | + +**Legend**: ✅ 80%+ TestTags | ⚠️ <80% TestTags | ⬜ No TestTags + +--- + +## Integration Test Status + +### Critical User Flows + +| # | Flow | Screens | Tests | Status | +|:-:|------|:-------:|:-----:|:------:| +| 1 | Login → Passcode → Home | 3 | 0 | ⬜ | +| 2 | Registration → OTP → Login | 4 | 0 | ⬜ | +| 3 | Home → Account Details | 2 | 0 | ⬜ | +| 4 | Home → Transfer → Confirm | 3 | 0 | ⬜ | +| 5 | Home → Beneficiary → Add | 2 | 0 | ⬜ | +| 6 | Settings → Change Password | 2 | 0 | ⬜ | +| 7 | Loan → Schedule → Summary | 3 | 0 | ⬜ | +| 8 | QR → Scan → Transfer | 3 | 0 | ⬜ | + +--- + +## TestTag System + +### Pattern: `feature:component:element` + +```kotlin +object TestTags { + object Auth { + const val SCREEN = "auth:screen" + const val USERNAME_FIELD = "auth:username" + const val PASSWORD_FIELD = "auth:password" + const val LOGIN_BUTTON = "auth:loginButton" + const val ERROR_MESSAGE = "auth:error" + const val LOADING_INDICATOR = "auth:loading" + } + + object Home { + const val SCREEN = "home:screen" + const val LOAN_BALANCE = "home:loanBalance" + const val SAVINGS_BALANCE = "home:savingsBalance" + const val TRANSFER_BUTTON = "home:transferButton" + const val ACCOUNTS_CARD = "home:accountsCard" + } + + // ... for all 17 features +} +``` + +### Usage in Screens + +```kotlin +@Composable +fun LoginScreenContent( + state: LoginState, + onAction: (LoginAction) -> Unit +) { + Column(modifier = Modifier.testTag(TestTags.Auth.SCREEN)) { + MifosOutlinedTextField( + value = state.username, + onValueChange = { onAction(LoginAction.UsernameChanged(it)) }, + modifier = Modifier.testTag(TestTags.Auth.USERNAME_FIELD) + ) + // ... + } +} +``` + +--- + +## ViewModel Test Template + +```kotlin +class LoginViewModelTest { + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + + private lateinit var viewModel: LoginViewModel + private lateinit var fakeUserAuthRepository: FakeUserAuthRepository + + @BeforeTest + fun setup() { + fakeUserAuthRepository = FakeUserAuthRepository() + viewModel = LoginViewModel( + userAuthRepository = fakeUserAuthRepository, + savedStateHandle = SavedStateHandle() + ) + } + + // STATE TESTS + @Test + fun `initial state has empty credentials`() = runTest { + viewModel.stateFlow.test { + val state = awaitItem() + assertEquals("", state.username) + assertEquals("", state.password) + } + } + + // ACTION TESTS + @Test + fun `username changed updates state`() = runTest { + viewModel.trySendAction(LoginAction.UsernameChanged("testuser")) + + viewModel.stateFlow.test { + assertEquals("testuser", expectMostRecentItem().username) + } + } + + // EVENT TESTS + @Test + fun `login success navigates to passcode`() = runTest { + fakeUserAuthRepository.setResult(DataState.Success(UserFixture.create())) + + viewModel.trySendAction(LoginAction.LoginClicked) + + viewModel.eventFlow.test { + assertEquals(LoginEvent.NavigateToPasscode, awaitItem()) + } + } +} +``` + +--- + +## UI Test Template + +```kotlin +class LoginScreenTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun `login screen displays all elements`() { + composeTestRule.setContent { + LoginScreenContent(state = LoginState(), onAction = {}) + } + + composeTestRule.onNodeWithTag(TestTags.Auth.USERNAME_FIELD).assertIsDisplayed() + composeTestRule.onNodeWithTag(TestTags.Auth.PASSWORD_FIELD).assertIsDisplayed() + composeTestRule.onNodeWithTag(TestTags.Auth.LOGIN_BUTTON).assertIsDisplayed() + } + + @Test + fun `login button disabled when credentials empty`() { + composeTestRule.setContent { + LoginScreenContent( + state = LoginState(username = "", password = ""), + onAction = {} + ) + } + + composeTestRule.onNodeWithTag(TestTags.Auth.LOGIN_BUTTON).assertIsNotEnabled() + } +} +``` + +--- + +## Implementation Priority + +### Phase 1: Core Features (P0) +| Feature | VMs | Tests Needed | Effort | +|---------|:---:|:------------:|:------:| +| auth | 5 | 50 | L | +| home | 1 | 12 | M | +| accounts | 3 | 24 | M | +| transfer-process | 2 | 20 | M | + +### Phase 2: Account Features (P1) +| Feature | VMs | Tests Needed | Effort | +|---------|:---:|:------------:|:------:| +| beneficiary | 4 | 32 | M | +| loan-account | 4 | 32 | M | +| savings-account | 3 | 24 | M | +| share-account | 2 | 16 | S | + +### Phase 3: Supporting Features (P2) +| Feature | VMs | Tests Needed | Effort | +|---------|:---:|:------------:|:------:| +| settings | 5 | 40 | L | +| notification | 1 | 8 | S | +| recent-transaction | 1 | 8 | S | +| qr-code | 3 | 24 | M | +| mifos-passcode | 2 | 16 | M | +| guarantor | 3 | 24 | M | +| user-profile | 2 | 16 | S | +| location | 1 | 8 | S | + +--- + +## Commands + +```bash +# Run feature tests +./gradlew :feature:auth:test +./gradlew :feature:home:test + +# Run UI tests +./gradlew :cmp-android:connectedDebugAndroidTest + +# Check test status +/gap-analysis feature testing + +# Plan feature tests +/gap-planning feature auth testing +``` + +--- + +## Related Files + +- [MODULES_INDEX.md](./MODULES_INDEX.md) - All feature modules +- [SCREENS_INDEX.md](./SCREENS_INDEX.md) - All screens +- [LAYER_GUIDE.md](./LAYER_GUIDE.md) - Architecture patterns diff --git a/claude-product-cycle/platform-layer/LAYER_GUIDE.md b/claude-product-cycle/platform-layer/LAYER_GUIDE.md new file mode 100644 index 000000000..4fd0b7f14 --- /dev/null +++ b/claude-product-cycle/platform-layer/LAYER_GUIDE.md @@ -0,0 +1,195 @@ +# Platform Layer Guide + +> Platform-specific patterns and configurations for Mifos Mobile KMP + +--- + +## Architecture Overview + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Platform Layer (cmp-android, cmp-ios, cmp-desktop, cmp-web) │ +├─────────────────────────────────────────────────────────────────┤ +│ Shared Layer (cmp-shared, cmp-navigation) │ +├─────────────────────────────────────────────────────────────────┤ +│ Feature Layer (feature/*) │ +├─────────────────────────────────────────────────────────────────┤ +│ Core Layer (core/*) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Kotlin Multiplatform Targets + +| Target | Platform | Kotlin Target | +|--------|----------|---------------| +| Android | Android 7.0+ | `android()` | +| iOS | iOS 14+ | `iosArm64()`, `iosSimulatorArm64()` | +| Desktop | JVM 17+ | `jvm()` | +| Web | Modern browsers | `js(IR)` | + +--- + +## Platform-Specific Code + +### Source Sets Structure + +``` +src/ +├── commonMain/ # Shared code (all platforms) +├── commonTest/ # Shared tests +├── androidMain/ # Android-specific +├── iosMain/ # iOS-specific +├── jvmMain/ # Desktop-specific +└── jsMain/ # Web-specific +``` + +### Expect/Actual Pattern + +```kotlin +// commonMain - expect declaration +expect fun getPlatformName(): String + +// androidMain - actual implementation +actual fun getPlatformName(): String = "Android" + +// iosMain - actual implementation +actual fun getPlatformName(): String = "iOS" +``` + +--- + +## Dependency Injection + +### Koin Setup Per Platform + +**Android** (`cmp-android`): +```kotlin +class MifosApplication : Application() { + override fun onCreate() { + super.onCreate() + startKoin { + androidContext(this@MifosApplication) + modules(appModule) + } + } +} +``` + +**iOS** (`cmp-ios`): +```swift +KoinKt.doInitKoin() +``` + +**Desktop/Web**: +```kotlin +fun main() { + startKoin { + modules(appModule) + } +} +``` + +--- + +## Navigation + +### Compose Navigation (Cross-Platform) + +```kotlin +// cmp-navigation/ +NavHost( + navController = navController, + startDestination = ROOT_GRAPH, +) { + authGraph(navController) + passcodeGraph(navController) + mainGraph(navController) +} +``` + +### Navigation Graphs + +| Graph | Content | +|-------|---------| +| ROOT_GRAPH | Entry point, splash | +| AUTH_GRAPH | Login, Registration | +| PASSCODE_GRAPH | Passcode setup/verify | +| MAIN_GRAPH | Main app content | + +--- + +## Platform Capabilities + +| Capability | Android | iOS | Desktop | Web | +|------------|:-------:|:---:|:-------:|:---:| +| Biometrics | ✅ | ✅ | ❌ | ❌ | +| Push Notifications | ✅ | ✅ | ❌ | ⚠️ | +| Camera (QR) | ✅ | ✅ | ⚠️ | ⚠️ | +| Location | ✅ | ✅ | ❌ | ⚠️ | +| Local Storage | ✅ | ✅ | ✅ | ✅ | +| Deep Links | ✅ | ✅ | ❌ | ✅ | + +--- + +## Build Variants + +### Android Flavors + +| Flavor | Purpose | Base URL | +|--------|---------|----------| +| demo | Development | tt.mifos.community | +| prod | Production | Configurable | + +### Build Types + +| Type | Debug | Minify | Signing | +|------|:-----:|:------:|---------| +| debug | ✅ | ❌ | Debug key | +| release | ❌ | ✅ | Release key | + +--- + +## Testing + +### Platform Testing Strategy + +| Test Type | Location | Runner | +|-----------|----------|--------| +| Unit Tests | `commonTest/` | JUnit/Kotest | +| Android Tests | `androidTest/` | Android Instrumented | +| iOS Tests | `iosTest/` | XCTest | +| UI Tests | Platform-specific | Compose Test | + +--- + +## Resources + +### Platform Resources Location + +| Platform | Resources | +|----------|-----------| +| Android | `cmp-android/src/main/res/` | +| iOS | `cmp-ios/iosApp/Assets.xcassets/` | +| Desktop | `cmp-desktop/src/main/resources/` | +| Web | `cmp-web/src/jsMain/resources/` | + +### Shared Resources (Compose Resources) + +``` +core/designsystem/src/commonMain/composeResources/ +├── drawable/ +├── values/ +└── font/ +``` + +--- + +## Related Files + +- [LAYER_STATUS.md](LAYER_STATUS.md) - Platform status +- [platforms/ANDROID.md](platforms/ANDROID.md) - Android details +- [platforms/IOS.md](platforms/IOS.md) - iOS details +- [platforms/DESKTOP.md](platforms/DESKTOP.md) - Desktop details +- [platforms/WEB.md](platforms/WEB.md) - Web details diff --git a/claude-product-cycle/platform-layer/LAYER_STATUS.md b/claude-product-cycle/platform-layer/LAYER_STATUS.md new file mode 100644 index 000000000..b448c8508 --- /dev/null +++ b/claude-product-cycle/platform-layer/LAYER_STATUS.md @@ -0,0 +1,102 @@ +# Platform Layer Status + +> **4 platforms** | Android primary | KMP shared code + +--- + +## Platform Matrix + +| Platform | Module | Build | Flavors | Status | +|----------|--------|:-----:|:-------:|:------:| +| Android | cmp-android | ✅ | demo, prod | Primary | +| iOS | cmp-ios | ✅ | - | CocoaPods | +| Desktop | cmp-desktop | ✅ | - | JVM | +| Web | cmp-web | ⚠️ | - | Kotlin/JS | + +**Legend**: ✅ Working | ⚠️ Experimental | ❌ Not Working + +--- + +## O(1) Platform Lookup + +| Need | Read File | +|------|-----------| +| Android build | [platforms/ANDROID.md](platforms/ANDROID.md) | +| iOS setup | [platforms/IOS.md](platforms/IOS.md) | +| Desktop config | [platforms/DESKTOP.md](platforms/DESKTOP.md) | +| Web config | [platforms/WEB.md](platforms/WEB.md) | + +--- + +## Shared Modules + +| Module | Purpose | Target | +|--------|---------|--------| +| cmp-shared | KMP shared code | All platforms | +| cmp-navigation | Cross-platform navigation | All platforms | +| core/* | Core business logic | All platforms | +| feature/* | Feature modules | All platforms | + +--- + +## Build Commands Quick Reference + +| Platform | Debug | Release | +|----------|-------|---------| +| Android | `./gradlew :cmp-android:assembleDemoDebug` | `./gradlew :cmp-android:assembleProdRelease` | +| Desktop | `./gradlew :cmp-desktop:run` | `./gradlew :cmp-desktop:packageDmg` | +| Web | `./gradlew :cmp-web:jsBrowserRun` | `./gradlew :cmp-web:jsBrowserProductionWebpack` | +| iOS | Xcode Build | Archive & Distribute | + +--- + +## Platform Entry Points + +| Platform | Entry Point | Location | +|----------|-------------|----------| +| Android | MainActivity | `cmp-android/src/main/kotlin/.../MainActivity.kt` | +| iOS | iosApp | `cmp-ios/iosApp/` | +| Desktop | Main.kt | `cmp-desktop/src/main/kotlin/.../Main.kt` | +| Web | Main.kt | `cmp-web/src/jsMain/kotlin/.../Main.kt` | + +--- + +## Gradle Module Configuration + +| Module | Build File | +|--------|------------| +| cmp-android | `cmp-android/build.gradle.kts` | +| cmp-ios | Uses CocoaPods via `cmp-shared` | +| cmp-desktop | `cmp-desktop/build.gradle.kts` | +| cmp-web | `cmp-web/build.gradle.kts` | +| cmp-shared | `cmp-shared/build.gradle.kts` | +| cmp-navigation | `cmp-navigation/build.gradle.kts` | + +--- + +## CI/CD Status + +| Platform | CI Pipeline | Status | +|----------|-------------|--------| +| Android | GitHub Actions | ✅ | +| iOS | - | ⚠️ Manual | +| Desktop | - | ⚠️ Manual | +| Web | - | ⚠️ Manual | + +--- + +## Related Files + +- [LAYER_GUIDE.md](LAYER_GUIDE.md) - Platform-specific patterns +- [platforms/](platforms/) - Platform-specific documentation +- [../CLAUDE.md](../../CLAUDE.md) - Project overview + +--- + +## Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| Platform status changes | Update Platform Matrix | +| New build variant added | Update Build Commands | +| CI/CD configured | Update CI/CD Status | diff --git a/claude-product-cycle/platform-layer/TESTING_STATUS.md b/claude-product-cycle/platform-layer/TESTING_STATUS.md new file mode 100644 index 000000000..2e8914c12 --- /dev/null +++ b/claude-product-cycle/platform-layer/TESTING_STATUS.md @@ -0,0 +1,279 @@ +# Platform Layer - Testing Status + +> E2E, Screenshot, and Platform-specific testing documentation + +--- + +## Overview + +The platform layer handles platform-specific testing: +- E2E integration tests (full user journeys) +- Screenshot/visual regression tests (Roborazzi) +- Platform-specific functionality tests + +--- + +## Current State + +| Platform | E2E Tests | Screenshot Tests | Status | +|----------|:---------:|:----------------:|:------:| +| Android | 0 | 0 | ⬜ Not Started | +| iOS | - | - | ⚠️ Manual | +| Desktop | 0 | 0 | ⬜ Not Started | +| Web | 0 | 0 | ⬜ Not Started | + +--- + +## Testing by Platform + +### Android (Primary) + +| Test Type | Framework | Location | Status | +|-----------|-----------|----------|:------:| +| E2E Tests | Compose UI Test | `cmp-android/src/androidTest/` | ⬜ | +| Screenshot | Roborazzi | `core/designsystem/src/test/` | ⬜ | +| Unit Tests | JUnit | `cmp-android/src/test/` | ⬜ | + +### iOS (CocoaPods) + +| Test Type | Framework | Location | Status | +|-----------|-----------|----------|:------:| +| UI Tests | XCUITest | `cmp-ios/iosApp/` | ⬜ | +| Unit Tests | XCTest | `cmp-ios/iosApp/` | ⬜ | + +### Desktop (JVM) + +| Test Type | Framework | Location | Status | +|-----------|-----------|----------|:------:| +| UI Tests | Compose Desktop Test | `cmp-desktop/src/test/` | ⬜ | +| Unit Tests | JUnit | `cmp-desktop/src/test/` | ⬜ | + +### Web (Kotlin/JS) + +| Test Type | Framework | Location | Status | +|-----------|-----------|----------|:------:| +| E2E Tests | Playwright/Cypress | TBD | ⬜ | +| Unit Tests | kotlin.test | `cmp-web/src/jsTest/` | ⬜ | + +--- + +## E2E Test Scenarios + +### Critical User Journeys + +| # | Journey | Platforms | Tests | Status | +|:-:|---------|-----------|:-----:|:------:| +| 1 | Onboarding → Login → Home | Android | 0 | ⬜ | +| 2 | Registration → OTP → Login | Android | 0 | ⬜ | +| 3 | Home → Account Details | Android | 0 | ⬜ | +| 4 | Home → Transfer → Confirm | Android | 0 | ⬜ | +| 5 | Home → Loan Details → Schedule | Android | 0 | ⬜ | +| 6 | Settings → Change Password | Android | 0 | ⬜ | +| 7 | QR Scan → Transfer | Android | 0 | ⬜ | +| 8 | Offline → Online Sync | Android | 0 | ⬜ | + +--- + +## Screenshot Testing (Roborazzi) + +### Configuration + +**Location**: `core/designsystem/src/test/` + +```kotlin +@RunWith(RobolectricTestRunner::class) +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class ComponentScreenshotTest { + @get:Rule + val roborazziRule = RoborazziRule( + options = RoborazziRule.Options( + captureType = RoborazziRule.CaptureType.LastImage + ) + ) + + @Test + fun mifosButton_light() { + composeTestRule.setContent { + MifosTheme(darkTheme = false) { + MifosButton(text = "Login", onClick = {}) + } + } + composeTestRule.onRoot().captureRoboImage() + } + + @Test + fun mifosButton_dark() { + composeTestRule.setContent { + MifosTheme(darkTheme = true) { + MifosButton(text = "Login", onClick = {}) + } + } + composeTestRule.onRoot().captureRoboImage() + } +} +``` + +### Screenshot Test Coverage + +| Component | Light | Dark | Status | +|-----------|:-----:|:----:|:------:| +| MifosButton | ⬜ | ⬜ | Not Started | +| MifosTextField | ⬜ | ⬜ | Not Started | +| MifosCard | ⬜ | ⬜ | Not Started | +| MifosTopBar | ⬜ | ⬜ | Not Started | +| MifosBottomNav | ⬜ | ⬜ | Not Started | +| MifosDialog | ⬜ | ⬜ | Not Started | +| MifosLoadingWheel | ⬜ | ⬜ | Not Started | +| AccountCard | ⬜ | ⬜ | Not Started | +| TransactionItem | ⬜ | ⬜ | Not Started | +| BeneficiaryItem | ⬜ | ⬜ | Not Started | + +--- + +## Screen Screenshot Tests + +| # | Feature | Screens | Golden Images | Status | +|:-:|---------|:-------:|:-------------:|:------:| +| 1 | auth | 6 | 0 | ⬜ | +| 2 | home | 1 | 0 | ⬜ | +| 3 | accounts | 3 | 0 | ⬜ | +| 4 | savings-account | 4 | 0 | ⬜ | +| 5 | loan-account | 4 | 0 | ⬜ | +| 6 | share-account | 2 | 0 | ⬜ | +| 7 | beneficiary | 4 | 0 | ⬜ | +| 8 | transfer | 2 | 0 | ⬜ | +| 9 | recent-transaction | 1 | 0 | ⬜ | +| 10 | notification | 1 | 0 | ⬜ | +| 11 | settings | 9 | 0 | ⬜ | +| 12 | passcode | 2 | 0 | ⬜ | +| 13 | guarantor | 3 | 0 | ⬜ | +| 14 | qr | 3 | 0 | ⬜ | +| 15 | location | 1 | 0 | ⬜ | +| 16 | user-profile | 2 | 0 | ⬜ | + +--- + +## Platform-Specific Tests + +### Android-Specific + +| Test | Description | Status | +|------|-------------|:------:| +| Deep Links | Verify deep link handling | ⬜ | +| Notifications | Push notification handling | ⬜ | +| Biometrics | Fingerprint/Face ID login | ⬜ | +| Camera | QR code scanning | ⬜ | +| Location | Branch finder | ⬜ | +| Back Navigation | System back button | ⬜ | + +### iOS-Specific + +| Test | Description | Status | +|------|-------------|:------:| +| Deep Links | Universal links | ⬜ | +| Notifications | APNs handling | ⬜ | +| Biometrics | Touch ID/Face ID | ⬜ | +| Camera | QR code scanning | ⬜ | +| Location | Core Location | ⬜ | + +### Desktop-Specific + +| Test | Description | Status | +|------|-------------|:------:| +| Window Management | Resize, minimize | ⬜ | +| Keyboard Shortcuts | Standard shortcuts | ⬜ | +| System Tray | Optional integration | ⬜ | + +### Web-Specific + +| Test | Description | Status | +|------|-------------|:------:| +| Browser Compat | Chrome, Firefox, Safari | ⬜ | +| CORS Handling | API requests | ⬜ | +| Responsive | Mobile/Tablet/Desktop | ⬜ | +| PWA | Service worker, offline | ⬜ | + +--- + +## CI/CD Integration + +### GitHub Actions Workflow + +```yaml +# .github/workflows/test.yml +name: Tests + +on: [push, pull_request] + +jobs: + unit-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + - name: Run unit tests + run: ./gradlew test + + android-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Android tests + run: ./gradlew :cmp-android:connectedDebugAndroidTest + + screenshot-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Roborazzi tests + run: ./gradlew :core:designsystem:testDebugUnitTest + - name: Compare screenshots + run: ./gradlew :core:designsystem:compareRoborazziDebug +``` + +--- + +## Implementation Priority + +| Phase | Platform | Tests | Effort | +|:-----:|----------|:-----:|:------:| +| 1 | Android E2E | 20 | L | +| 2 | Screenshot (Roborazzi) | 30 | M | +| 3 | iOS UI | 10 | M | +| 4 | Desktop | 5 | S | +| 5 | Web | 10 | M | + +--- + +## Commands + +```bash +# Run Android E2E tests +./gradlew :cmp-android:connectedDebugAndroidTest + +# Run screenshot tests +./gradlew :core:designsystem:testDebugUnitTest + +# Record new screenshots +./gradlew :core:designsystem:recordRoborazziDebug + +# Compare screenshots +./gradlew :core:designsystem:compareRoborazziDebug + +# Check platform test status +/gap-analysis platform testing +``` + +--- + +## Related Files + +- [LAYER_STATUS.md](./LAYER_STATUS.md) - Platform status +- [platforms/ANDROID.md](./platforms/ANDROID.md) - Android details +- [platforms/IOS.md](./platforms/IOS.md) - iOS details +- [platforms/DESKTOP.md](./platforms/DESKTOP.md) - Desktop details +- [platforms/WEB.md](./platforms/WEB.md) - Web details diff --git a/claude-product-cycle/platform-layer/platforms/ANDROID.md b/claude-product-cycle/platform-layer/platforms/ANDROID.md new file mode 100644 index 000000000..5eb563e46 --- /dev/null +++ b/claude-product-cycle/platform-layer/platforms/ANDROID.md @@ -0,0 +1,109 @@ +# Android Platform + +## Module: cmp-android + +> Primary platform target for Mifos Mobile + +--- + +## Build Flavors + +| Flavor | API Base | Use Case | +|--------|----------|----------| +| demo | tt.mifos.community | Development/Testing | +| prod | Configurable | Production | + +--- + +## Build Commands + +| Command | Output | +|---------|--------| +| `./gradlew :cmp-android:assembleDemoDebug` | Demo debug APK | +| `./gradlew :cmp-android:assembleDemoRelease` | Demo release APK | +| `./gradlew :cmp-android:assembleProdDebug` | Prod debug APK | +| `./gradlew :cmp-android:assembleProdRelease` | Production release APK | +| `./gradlew :cmp-android:lintRelease` | Lint checks | +| `./gradlew :cmp-android:testDebug` | Run unit tests | + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `cmp-android/build.gradle.kts` | Module configuration | +| `cmp-android/src/main/AndroidManifest.xml` | App manifest | +| `cmp-android/src/main/kotlin/.../MainActivity.kt` | Entry point | +| `cmp-android/src/main/kotlin/.../MifosApplication.kt` | Application class | + +--- + +## Gradle Configuration + +```kotlin +android { + namespace = "org.mifos.mobile" + compileSdk = 34 + + defaultConfig { + applicationId = "org.mifos.mobile" + minSdk = 24 + targetSdk = 34 + } + + productFlavors { + create("demo") { ... } + create("prod") { ... } + } +} +``` + +--- + +## Signing Configuration + +### Debug +- Auto-generated debug keystore +- Location: `~/.android/debug.keystore` + +### Release +- Requires `keystore.properties` file +- Keys: `storeFile`, `storePassword`, `keyAlias`, `keyPassword` + +--- + +## Dependencies + +| Category | Key Dependencies | +|----------|------------------| +| Compose | Compose BOM, Material3 | +| DI | Koin Android | +| Network | Ktor Android | +| Storage | DataStore, Room | + +--- + +## Android-Specific Features + +| Feature | Implementation | +|---------|----------------| +| Biometrics | AndroidX Biometric | +| Push Notifications | Firebase Cloud Messaging | +| Deep Links | Intent Filters | +| Splash Screen | SplashScreen API | + +--- + +## ProGuard/R8 + +- Rules in `proguard-rules.pro` +- Keep rules for serialization +- Ktor client rules + +--- + +## Related + +- [LAYER_STATUS.md](../LAYER_STATUS.md) - Platform overview +- [LAYER_GUIDE.md](../LAYER_GUIDE.md) - Architecture patterns diff --git a/claude-product-cycle/platform-layer/platforms/DESKTOP.md b/claude-product-cycle/platform-layer/platforms/DESKTOP.md new file mode 100644 index 000000000..e76faa1e9 --- /dev/null +++ b/claude-product-cycle/platform-layer/platforms/DESKTOP.md @@ -0,0 +1,109 @@ +# Desktop Platform + +## Module: cmp-desktop + +> JVM-based desktop application using Compose for Desktop + +--- + +## Build Commands + +| Command | Action | +|---------|--------| +| `./gradlew :cmp-desktop:run` | Run desktop app | +| `./gradlew :cmp-desktop:packageDmg` | Package macOS DMG | +| `./gradlew :cmp-desktop:packageMsi` | Package Windows MSI | +| `./gradlew :cmp-desktop:packageDeb` | Package Linux DEB | +| `./gradlew :cmp-desktop:packageRpm` | Package Linux RPM | + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `cmp-desktop/build.gradle.kts` | Module configuration | +| `cmp-desktop/src/main/kotlin/.../Main.kt` | Entry point | +| `cmp-desktop/src/main/resources/` | Desktop resources | + +--- + +## Gradle Configuration + +```kotlin +compose.desktop { + application { + mainClass = "org.mifos.mobile.MainKt" + + nativeDistributions { + targetFormats( + TargetFormat.Dmg, + TargetFormat.Msi, + TargetFormat.Deb + ) + packageName = "Mifos Mobile" + packageVersion = "1.0.0" + } + } +} +``` + +--- + +## Entry Point + +```kotlin +fun main() = application { + Window( + onCloseRequest = ::exitApplication, + title = "Mifos Mobile" + ) { + App() + } +} +``` + +--- + +## Platform Support + +| OS | Target Format | Status | +|----|---------------|:------:| +| macOS | DMG | ✅ | +| Windows | MSI | ✅ | +| Linux | DEB/RPM | ✅ | + +--- + +## Desktop-Specific Features + +| Feature | Status | Notes | +|---------|:------:|-------| +| Window Management | ✅ | Resize, minimize, maximize | +| System Tray | ⚠️ | Optional | +| Keyboard Shortcuts | ✅ | Standard shortcuts | +| File System Access | ✅ | Full access | + +--- + +## Requirements + +| Requirement | Version | +|-------------|---------| +| JVM | 17+ | +| Compose Desktop | 1.5+ | + +--- + +## Development Notes + +- Uses Compose for Desktop (Multiplatform) +- Shares UI code with Android/iOS +- Platform-specific code in `jvmMain/` + +--- + +## Related + +- [LAYER_STATUS.md](../LAYER_STATUS.md) - Platform overview +- [LAYER_GUIDE.md](../LAYER_GUIDE.md) - Architecture patterns diff --git a/claude-product-cycle/platform-layer/platforms/IOS.md b/claude-product-cycle/platform-layer/platforms/IOS.md new file mode 100644 index 000000000..1955fe473 --- /dev/null +++ b/claude-product-cycle/platform-layer/platforms/IOS.md @@ -0,0 +1,134 @@ +# iOS Platform + +## Module: cmp-ios + +> iOS platform target using CocoaPods integration + +--- + +## Setup + +1. Install CocoaPods dependencies: + ```bash + cd cmp-ios + pod install + ``` + +2. Open Xcode workspace: + ```bash + open iosApp.xcworkspace + ``` + +3. Build and run in Xcode + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `cmp-ios/Podfile` | CocoaPods dependencies | +| `cmp-ios/iosApp/` | iOS app source | +| `cmp-ios/iosApp/Info.plist` | App configuration | +| `cmp-ios/iosApp/ContentView.swift` | Main UI entry | +| `cmp-shared/` | Shared KMP framework | + +--- + +## Build Commands + +| Command | Action | +|---------|--------| +| `pod install` | Install dependencies | +| `pod update` | Update dependencies | +| Xcode Build (Cmd+B) | Build app | +| Xcode Run (Cmd+R) | Run on simulator/device | + +### Terminal Build + +```bash +xcodebuild -workspace iosApp.xcworkspace \ + -scheme iosApp \ + -sdk iphonesimulator \ + -configuration Debug \ + build +``` + +--- + +## KMP Framework Integration + +### Shared Framework + +```ruby +# Podfile +target 'iosApp' do + use_frameworks! + pod 'cmp_shared', :path => '../cmp-shared' +end +``` + +### Using Shared Code + +```swift +import cmp_shared + +struct ContentView: View { + var body: some View { + ComposeView() + } +} +``` + +--- + +## Xcode Project Structure + +``` +iosApp/ +├── iosApp.xcodeproj/ +├── iosApp.xcworkspace/ +├── iosApp/ +│ ├── Assets.xcassets/ +│ ├── ContentView.swift +│ ├── Info.plist +│ └── iosApp.swift +└── Podfile +``` + +--- + +## iOS-Specific Features + +| Feature | Implementation | +|---------|----------------| +| Biometrics | LocalAuthentication | +| Push Notifications | APNs | +| Deep Links | URL Schemes | + +--- + +## Requirements + +| Requirement | Version | +|-------------|---------| +| iOS Deployment Target | 14.0+ | +| Xcode | 15.0+ | +| CocoaPods | 1.12+ | + +--- + +## Troubleshooting + +| Issue | Solution | +|-------|----------| +| Pod install fails | Run `pod repo update` first | +| Framework not found | Clean build folder (Cmd+Shift+K) | +| Simulator issues | Reset simulator content | + +--- + +## Related + +- [LAYER_STATUS.md](../LAYER_STATUS.md) - Platform overview +- [LAYER_GUIDE.md](../LAYER_GUIDE.md) - Architecture patterns diff --git a/claude-product-cycle/platform-layer/platforms/WEB.md b/claude-product-cycle/platform-layer/platforms/WEB.md new file mode 100644 index 000000000..6e9b2e809 --- /dev/null +++ b/claude-product-cycle/platform-layer/platforms/WEB.md @@ -0,0 +1,135 @@ +# Web Platform + +## Module: cmp-web + +> Kotlin/JS web application (Experimental) + +--- + +## Status: Experimental + +The web platform is currently in experimental status. Some features may not be fully functional. + +--- + +## Build Commands + +| Command | Action | +|---------|--------| +| `./gradlew :cmp-web:jsBrowserRun` | Run in browser (dev) | +| `./gradlew :cmp-web:jsBrowserProductionWebpack` | Production build | +| `./gradlew :cmp-web:jsBrowserDevelopmentWebpack` | Development build | + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `cmp-web/build.gradle.kts` | Module configuration | +| `cmp-web/src/jsMain/kotlin/.../Main.kt` | Entry point | +| `cmp-web/src/jsMain/resources/index.html` | HTML template | + +--- + +## Gradle Configuration + +```kotlin +kotlin { + js(IR) { + browser { + commonWebpackConfig { + cssSupport { + enabled.set(true) + } + } + } + binaries.executable() + } +} +``` + +--- + +## Entry Point + +```kotlin +fun main() { + onWasmReady { + BrowserViewportWindow("Mifos Mobile") { + App() + } + } +} +``` + +--- + +## Output Location + +| Build Type | Output | +|------------|--------| +| Development | `build/dist/js/developmentExecutable/` | +| Production | `build/dist/js/productionExecutable/` | + +--- + +## Browser Support + +| Browser | Status | +|---------|:------:| +| Chrome | ✅ | +| Firefox | ✅ | +| Safari | ⚠️ | +| Edge | ✅ | + +--- + +## Web-Specific Limitations + +| Feature | Status | Notes | +|---------|:------:|-------| +| Local Storage | ✅ | Using browser storage | +| Network | ✅ | CORS considerations | +| Biometrics | ❌ | Not available | +| Camera | ⚠️ | Browser permissions | +| Notifications | ⚠️ | Web Push API | + +--- + +## Development Server + +When running `jsBrowserRun`: +- Default URL: `http://localhost:8080` +- Hot reload enabled +- Source maps available + +--- + +## Production Deployment + +1. Build production bundle: + ```bash + ./gradlew :cmp-web:jsBrowserProductionWebpack + ``` + +2. Deploy `build/dist/js/productionExecutable/` to web server + +3. Configure server for SPA routing + +--- + +## Known Issues + +| Issue | Workaround | +|-------|------------| +| Large bundle size | Tree shaking, code splitting | +| CORS errors | Configure server headers | +| WebSocket issues | Use polling fallback | + +--- + +## Related + +- [LAYER_STATUS.md](../LAYER_STATUS.md) - Platform overview +- [LAYER_GUIDE.md](../LAYER_GUIDE.md) - Architecture patterns diff --git a/claude-product-cycle/server-layer/API_INDEX.md b/claude-product-cycle/server-layer/API_INDEX.md new file mode 100644 index 000000000..6120c47ae --- /dev/null +++ b/claude-product-cycle/server-layer/API_INDEX.md @@ -0,0 +1,551 @@ +# Fineract Self-Service API Index + +> **Purpose**: Fast API lookup with service method references +> **Pattern**: Static table first → API_REFERENCE.md for details → Design layer for source + +--- + +## Source of Truth Hierarchy + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Design Layer: features/*/API.md │ +│ └─→ ULTIMATE SOURCE OF TRUTH │ +│ └─→ Where APIs are first designed/documented │ +├─────────────────────────────────────────────────────────────────┤ +│ Server Layer: (This directory) │ +│ └─→ DERIVED but COMPLETE for client layer │ +│ ├─→ API_INDEX.md (this file) - Quick lookup │ +│ ├─→ API_REFERENCE.md - Complete endpoint details │ +│ ├─→ CLIENT_PATTERNS.md - Service/Repository patterns │ +│ └─→ ERROR_HANDLING.md - Exception handling │ +├─────────────────────────────────────────────────────────────────┤ +│ Client Layer: core/network/, core/data/ │ +│ └─→ IMPLEMENTATION based on server layer docs │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Table of Contents +1. [Overview](#overview) +2. [Quick Lookup](#quick-lookup) +3. [By Category](#by-category) +4. [Common Patterns](#common-patterns) +5. [Lookup Strategy](#lookup-strategy) +6. [Update Flow](#update-flow) +7. [How to Add New API](#how-to-add-new-api) + +--- + +## Overview + +### Server Layer Documentation + +| Document | Purpose | +|----------|---------| +| [API_INDEX.md](API_INDEX.md) | Quick lookup table (this file) | +| [endpoints/*.md](endpoints/) | **O(1) Lookup** - Category-specific endpoint docs | +| [API_REFERENCE.md](API_REFERENCE.md) | Complete endpoint overview | +| [CLIENT_PATTERNS.md](CLIENT_PATTERNS.md) | Service/Repository implementation patterns | +| [ERROR_HANDLING.md](ERROR_HANDLING.md) | Exception types and error extraction | + +### Endpoint Files (O(1) Lookup) + +| File | Category | Endpoints | +|------|----------|:---------:| +| [AUTH.md](endpoints/AUTH.md) | Authentication | 3 | +| [CLIENT.md](endpoints/CLIENT.md) | Client | 4 | +| [SAVINGS.md](endpoints/SAVINGS.md) | Savings Account | 7 | +| [LOAN.md](endpoints/LOAN.md) | Loan Account | 6 | +| [BENEFICIARY.md](endpoints/BENEFICIARY.md) | Beneficiary | 5 | +| [TRANSFER.md](endpoints/TRANSFER.md) | Transfer | 2 | +| [GUARANTOR.md](endpoints/GUARANTOR.md) | Guarantor | 5 | +| [NOTIFICATION.md](endpoints/NOTIFICATION.md) | Notification | 3 | +| [CHARGES.md](endpoints/CHARGES.md) | Charges | 3 | +| [SHARE.md](endpoints/SHARE.md) | Share Account | 3 | +| [USER.md](endpoints/USER.md) | User Settings | 1 | + +### External References + +| Resource | URL | +|----------|-----| +| **Swagger UI** | [sandbox.mifos.community/fineract-provider/swagger-ui](https://sandbox.mifos.community/fineract-provider/swagger-ui/index.html#/) | +| **Self-Service APIs** | Filter by `/self/` endpoints in Swagger | +| **Full API Docs** | [fineract.apache.org](https://fineract.apache.org/) | + +### Base URL +``` +https://{server}/fineract-provider/api/v1/self/ +``` + +### Authentication +All requests require: +``` +Headers: + Authorization: Basic {base64(username:password)} + Fineract-Platform-TenantId: {tenant} + Content-Type: application/json +``` + +### Demo Server +- **Server**: `tt.mifos.community` or `gsoc.mifos.community` +- **Tenant**: `mobile` or `default` +- **Test User**: `maria` / `password` + +--- + +## Quick Lookup + +| Endpoint | Method | Purpose | Service Method | Docs | +|----------|--------|---------|----------------|------| +| `/authentication` | POST | Login user | `authenticate()` | [auth](../design-spec-layer/features/auth/API.md) | +| `/registration` | POST | Register client | `register()` | [auth](../design-spec-layer/features/auth/API.md) | +| `/registration/user` | POST | Verify OTP | `verifyOtp()` | [auth](../design-spec-layer/features/auth/API.md) | +| `/clients` | GET | Get client list | `clients()` | [home](../design-spec-layer/features/home/API.md) | +| `/clients/{clientId}` | GET | Get client details | `getClientDetails()` | [home](../design-spec-layer/features/home/API.md) | +| `/clients/{clientId}/images` | GET | Get client image | `getClientImage()` | [home](../design-spec-layer/features/home/API.md) | +| `/clients/{clientId}/accounts` | GET | Get all accounts | `getClientAccounts()` | [accounts](../design-spec-layer/features/accounts/API.md) | +| `/savingsaccounts/{accountId}` | GET | Savings details | `getSavingsWithAssociations()` | [savings](../design-spec-layer/features/savings-account/API.md) | +| `/savingsaccounts` | POST | Apply for savings | `submitSavingAccountApplication()` | [savings](../design-spec-layer/features/savings-account/API.md) | +| `/savingsaccounts/{id}?command=withdrawnByApplicant` | POST | Withdraw application | `submitWithdrawSavingsAccount()` | [savings](../design-spec-layer/features/savings-account/API.md) | +| `/savingsaccounts/{id}/transactions` | GET | Savings transactions | `getSavingsAccountTransactionTemplate()` | [savings](../design-spec-layer/features/savings-account/API.md) | +| `/savingsproducts` | GET | Savings products | `getSavingsProducts()` | [savings](../design-spec-layer/features/savings-account/API.md) | +| `/loans/{loanId}` | GET | Loan details | `getLoanWithAssociations()` | [loan](../design-spec-layer/features/loan-account/API.md) | +| `/loans` | POST | Apply for loan | `createLoansAccount()` | [loan](../design-spec-layer/features/loan-account/API.md) | +| `/loans/{loanId}?command=withdrawnByApplicant` | POST | Withdraw loan | `withdrawLoanAccount()` | [loan](../design-spec-layer/features/loan-account/API.md) | +| `/loans/{loanId}/transactions/{transId}` | GET | Loan transaction | `getLoanAccountTransaction()` | [loan](../design-spec-layer/features/loan-account/API.md) | +| `/loanproducts` | GET | Loan products | `getLoanProducts()` | [loan](../design-spec-layer/features/loan-account/API.md) | +| `/loans/{loanId}/template?templateType=repayment` | GET | Repayment template | `getLoanRepaymentTemplate()` | [loan](../design-spec-layer/features/loan-account/API.md) | +| `/products/share` | GET | Share products | `getShareProducts()` | [share](../design-spec-layer/features/share-account/API.md) | +| `/shareaccounts` | POST | Apply for shares | `submitShareApplication()` | [share](../design-spec-layer/features/share-account/API.md) | +| `/shareaccounts/{accountId}` | GET | Share details | `getShareAccountDetails()` | [share](../design-spec-layer/features/share-account/API.md) | +| `/beneficiaries/tpt` | GET | List beneficiaries | `beneficiaryList()` | [beneficiary](../design-spec-layer/features/beneficiary/API.md) | +| `/beneficiaries/tpt` | POST | Add beneficiary | `createBeneficiary()` | [beneficiary](../design-spec-layer/features/beneficiary/API.md) | +| `/beneficiaries/tpt/{id}` | PUT | Update beneficiary | `updateBeneficiary()` | [beneficiary](../design-spec-layer/features/beneficiary/API.md) | +| `/beneficiaries/tpt/{id}` | DELETE | Delete beneficiary | `deleteBeneficiary()` | [beneficiary](../design-spec-layer/features/beneficiary/API.md) | +| `/beneficiaries/tpt/template` | GET | Beneficiary template | `beneficiaryTemplate()` | [beneficiary](../design-spec-layer/features/beneficiary/API.md) | +| `/accounttransfers/template` | GET | Transfer template | `accountTransferTemplate()` | [transfer](../design-spec-layer/features/transfer/API.md) | +| `/accounttransfers` | POST | Execute transfer | `makeTransfer()` | [transfer](../design-spec-layer/features/transfer/API.md) | +| `/loans/{loanId}/guarantors` | GET | List guarantors | `getGuarantorList()` | [guarantor](../design-spec-layer/features/guarantor/API.md) | +| `/loans/{loanId}/guarantors/template` | GET | Guarantor template | `getGuarantorTemplate()` | [guarantor](../design-spec-layer/features/guarantor/API.md) | +| `/loans/{loanId}/guarantors` | POST | Add guarantor | `addGuarantor()` | [guarantor](../design-spec-layer/features/guarantor/API.md) | +| `/loans/{loanId}/guarantors/{id}` | PUT | Update guarantor | `updateGuarantor()` | [guarantor](../design-spec-layer/features/guarantor/API.md) | +| `/loans/{loanId}/guarantors/{id}` | DELETE | Delete guarantor | `deleteGuarantor()` | [guarantor](../design-spec-layer/features/guarantor/API.md) | +| `/device/registration/client/{clientId}` | GET | Get notification ID | `getUserNotificationId()` | [notification](../design-spec-layer/features/notification/API.md) | +| `/device/registration` | POST | Register device | `registerNotification()` | [notification](../design-spec-layer/features/notification/API.md) | +| `/device/registration/{id}` | PUT | Update registration | `updateRegisterNotification()` | [notification](../design-spec-layer/features/notification/API.md) | +| `/clients/{clientId}/charges` | GET | Client charges | `getClientChargeList()` | [client-charge](../design-spec-layer/features/client-charge/API.md) | +| `/loans/{loanId}/charges` | GET | Loan charges | `getChargeList()` | [client-charge](../design-spec-layer/features/client-charge/API.md) | +| `/savingsaccounts/{id}/charges` | GET | Savings charges | `getChargeList()` | [client-charge](../design-spec-layer/features/client-charge/API.md) | +| `/user/password` | PUT | Change password | `updatePassword()` | [settings](../design-spec-layer/features/settings/API.md) | + +--- + +## By Category + +### Authentication (3 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/authentication` | POST | `authenticate()` | Login with username/password | +| `/registration` | POST | `register()` | Register new client | +| `/registration/user` | POST | `verifyOtp()` | Verify OTP for registration | + +**Service**: `AuthenticationService` +**Docs**: [auth/API.md](../design-spec-layer/features/auth/API.md) + +--- + +### Client (3 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/clients` | GET | `clients()` | Get client list | +| `/clients/{clientId}` | GET | `getClientDetails()` | Get client details | +| `/clients/{clientId}/images` | GET | `getClientImage()` | Get client profile image | + +**Service**: `ClientService` +**Docs**: [home/API.md](../design-spec-layer/features/home/API.md) + +--- + +### Accounts (1 endpoint) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/clients/{clientId}/accounts` | GET | `getClientAccounts()` | Get all client accounts | + +**Service**: `ClientService` +**Docs**: [accounts/API.md](../design-spec-layer/features/accounts/API.md) + +--- + +### Savings Account (5 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/savingsaccounts/{accountId}` | GET | `getSavingsWithAssociations()` | Get savings details | +| `/savingsaccounts` | POST | `submitSavingAccountApplication()` | Apply for savings account | +| `/savingsaccounts/{id}?command=withdrawnByApplicant` | POST | `submitWithdrawSavingsAccount()` | Withdraw application | +| `/savingsaccounts/{id}/transactions` | GET | `getSavingsAccountTransactionTemplate()` | Get transaction history | +| `/savingsproducts` | GET | `getSavingsProducts()` | Get available products | + +**Service**: `SavingAccountsService` +**Docs**: [savings-account/API.md](../design-spec-layer/features/savings-account/API.md) + +--- + +### Loan Account (6 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/loans/{loanId}` | GET | `getLoanWithAssociations()` | Get loan details | +| `/loans` | POST | `createLoansAccount()` | Apply for loan | +| `/loans/{loanId}?command=withdrawnByApplicant` | POST | `withdrawLoanAccount()` | Withdraw application | +| `/loans/{loanId}/transactions/{transId}` | GET | `getLoanAccountTransaction()` | Get transaction details | +| `/loanproducts` | GET | `getLoanProducts()` | Get available products | +| `/loans/{loanId}/template?templateType=repayment` | GET | `getLoanRepaymentTemplate()` | Get repayment schedule | + +**Service**: `LoanService` +**Docs**: [loan-account/API.md](../design-spec-layer/features/loan-account/API.md) + +--- + +### Share Account (3 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/products/share` | GET | `getShareProducts()` | Get share products | +| `/shareaccounts` | POST | `submitShareApplication()` | Apply for shares | +| `/shareaccounts/{accountId}` | GET | `getShareAccountDetails()` | Get share details | + +**Service**: `ShareAccountService` +**Docs**: [share-account/API.md](../design-spec-layer/features/share-account/API.md) + +--- + +### Beneficiary (5 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/beneficiaries/tpt` | GET | `beneficiaryList()` | List all beneficiaries | +| `/beneficiaries/tpt` | POST | `createBeneficiary()` | Add beneficiary | +| `/beneficiaries/tpt/{id}` | PUT | `updateBeneficiary()` | Update beneficiary | +| `/beneficiaries/tpt/{id}` | DELETE | `deleteBeneficiary()` | Delete beneficiary | +| `/beneficiaries/tpt/template` | GET | `beneficiaryTemplate()` | Get template for adding | + +**Service**: `BeneficiaryService` +**Docs**: [beneficiary/API.md](../design-spec-layer/features/beneficiary/API.md) + +--- + +### Transfer (2 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/accounttransfers/template` | GET | `accountTransferTemplate()` | Get transfer template | +| `/accounttransfers` | POST | `makeTransfer()` | Execute transfer | + +**Service**: `TransferService` +**Docs**: [transfer/API.md](../design-spec-layer/features/transfer/API.md) + +--- + +### Guarantor (5 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/loans/{loanId}/guarantors` | GET | `getGuarantorList()` | List guarantors | +| `/loans/{loanId}/guarantors/template` | GET | `getGuarantorTemplate()` | Get add template | +| `/loans/{loanId}/guarantors` | POST | `addGuarantor()` | Add guarantor | +| `/loans/{loanId}/guarantors/{id}` | PUT | `updateGuarantor()` | Update guarantor | +| `/loans/{loanId}/guarantors/{id}` | DELETE | `deleteGuarantor()` | Delete guarantor | + +**Service**: `GuarantorService` +**Docs**: [guarantor/API.md](../design-spec-layer/features/guarantor/API.md) + +--- + +### Notification (3 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/device/registration/client/{clientId}` | GET | `getUserNotificationId()` | Get notification ID | +| `/device/registration` | POST | `registerNotification()` | Register device | +| `/device/registration/{id}` | PUT | `updateRegisterNotification()` | Update registration | + +**Service**: `NotificationService` +**Docs**: [notification/API.md](../design-spec-layer/features/notification/API.md) + +--- + +### Charges (3 endpoints) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/clients/{clientId}/charges` | GET | `getClientChargeList()` | Get client charges | +| `/loans/{loanId}/charges` | GET | `getChargeList()` | Get loan charges | +| `/savingsaccounts/{id}/charges` | GET | `getChargeList()` | Get savings charges | + +**Service**: `ClientChargeService` +**Docs**: [client-charge/API.md](../design-spec-layer/features/client-charge/API.md) + +--- + +### User Settings (1 endpoint) + +| Endpoint | Method | Service Method | Purpose | +|----------|--------|----------------|---------| +| `/user/password` | PUT | `updatePassword()` | Change user password | + +**Service**: `UserService` +**Docs**: [settings/API.md](../design-spec-layer/features/settings/API.md) + +--- + +## Local-Only Features + +These features do not require backend API calls: + +| Feature | Storage | Notes | +|---------|---------|-------| +| QR Code | - | Local generation/scanning | +| Location | Static | Hardcoded branch locations | +| Passcode | DataStore | Local biometric/PIN storage | + +--- + +## Common Patterns + +### Date Format +``` +Format: dd MMMM yyyy +Example: 15 January 2025 +``` + +### Locale +``` +locale=en +dateFormat=dd MMMM yyyy +``` + +### Error Responses + +| Status | Description | Handling | +|--------|-------------|----------| +| 401 | Unauthorized | Redirect to login | +| 403 | Forbidden | Show permission error | +| 404 | Not found | Show "not found" message | +| 500 | Server error | Show generic error with retry | + +### Error Response Format +```json +{ + "developerMessage": "...", + "httpStatusCode": "...", + "defaultUserMessage": "...", + "userMessageGlobalisationCode": "...", + "errors": [] +} +``` + +### Query Parameters + +Common query parameters used across endpoints: + +| Parameter | Usage | Example | +|-----------|-------|---------| +| `associations` | Include related data | `?associations=transactions` | +| `command` | Execute command | `?command=withdrawnByApplicant` | +| `templateType` | Specify template | `?templateType=repayment` | +| `locale` | Response locale | `?locale=en` | +| `dateFormat` | Date format | `?dateFormat=dd MMMM yyyy` | + +--- + +## Lookup Strategy + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ STEP 1: STATIC LOOKUP - O(1) (Fastest) │ +│ → Know category? Read endpoints/[CATEGORY].md directly │ +│ → Don't know? Scan Endpoint Files table above │ +│ → ~50-100 lines per file vs 600+ in single file │ +├─────────────────────────────────────────────────────────────────┤ +│ STEP 2: DYNAMIC SEARCH (If Not Found in Static) │ +│ → Search codebase: core/network/services/*.kt │ +│ → Search design layer: design-spec-layer/features/*/API.md │ +│ → Check Swagger UI for endpoint existence │ +├─────────────────────────────────────────────────────────────────┤ +│ STEP 3: AUTO-UPDATE (After Dynamic Find or Manual Implement) │ +│ → Add to endpoints/[CATEGORY].md (O(1) lookup) │ +│ → Add row to API_INDEX.md Quick Lookup table │ +│ → Update design-layer/*/API.md (source of truth) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 1: Static Lookup (O(1)) + +**Direct file access by category:** + +| Need | Read This File | Lines | +|------|----------------|:-----:| +| Auth/Login/Register | `endpoints/AUTH.md` | ~90 | +| Client/Profile | `endpoints/CLIENT.md` | ~80 | +| Savings Account | `endpoints/SAVINGS.md` | ~150 | +| Loan Account | `endpoints/LOAN.md` | ~120 | +| Beneficiary | `endpoints/BENEFICIARY.md` | ~130 | +| Transfer | `endpoints/TRANSFER.md` | ~90 | +| Guarantor | `endpoints/GUARANTOR.md` | ~100 | +| Notification | `endpoints/NOTIFICATION.md` | ~70 | +| Charges | `endpoints/CHARGES.md` | ~100 | +| Share Account | `endpoints/SHARE.md` | ~90 | +| Password/Settings | `endpoints/USER.md` | ~50 | + +**Then for patterns:** + +| Step | File | What to Find | +|------|------|--------------| +| 1b | `CLIENT_PATTERNS.md` | Service/Repository patterns | +| 1c | `ERROR_HANDLING.md` | Exception handling | + +### Step 2: Dynamic Search (If Not Found) + +**Search commands:** + +```bash +# Search in service files +grep -r "@GET\|@POST\|@PUT\|@DELETE" core/network/src/commonMain/kotlin/**/services/ + +# Search for specific endpoint +grep -r "/beneficiaries" core/network/ + +# Search in design layer +grep -r "Endpoint" claude-product-cycle/design-spec-layer/features/*/API.md + +# List all service files +ls core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/services/ +``` + +**Claude Glob Patterns:** +``` +core/network/**/services/*.kt +design-spec-layer/features/*/API.md +``` + +**External Reference:** +- [Swagger UI](https://sandbox.mifos.community/fineract-provider/swagger-ui/index.html#/) - Filter by `/self/` + +### Step 3: Auto-Update Rules + +| Scenario | Action | +|----------|--------| +| Found in static lookup | No update needed | +| Found via dynamic search | **ADD** to server layer docs | +| Manually implemented new API | **ADD** to server layer + design layer | +| API deprecated/removed | **REMOVE** from server layer | + +**Update Checklist:** +- [ ] Add row to `API_INDEX.md` Quick Lookup table +- [ ] Add row to `API_INDEX.md` By Category table +- [ ] Add full documentation to `API_REFERENCE.md` +- [ ] Update `design-spec-layer/features/[feature]/API.md` (source) + +--- + +## Update Flow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ NEW API DESIGNED │ +│ └─→ Add to design-layer/features/*/API.md (SOURCE) │ +├─────────────────────────────────────────────────────────────────┤ +│ READY FOR CLIENT IMPLEMENTATION │ +│ └─→ Add to server-layer/API_REFERENCE.md (DETAILS) │ +│ └─→ Add row to server-layer/API_INDEX.md (INDEX) │ +├─────────────────────────────────────────────────────────────────┤ +│ CLIENT IMPLEMENTS │ +│ └─→ Uses server-layer docs for implementation │ +├─────────────────────────────────────────────────────────────────┤ +│ FOUND DYNAMICALLY (not in docs) │ +│ └─→ UPDATE server layer docs immediately │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## How to Add New API + +### Format for API_INDEX.md + +```markdown +| /endpoint | METHOD | Purpose | `serviceMethod()` | [feature](link) | +``` + +### Format for API_REFERENCE.md + +```markdown +### METHOD /endpoint +**Purpose**: Description + +**Service**: `ServiceName.methodName()` + +**Request**: +```json +{ ... } +``` + +**Response**: +```json +{ ... } +``` + +**DTO**: `DtoName` +``` + +--- + +## Service File Locations + +``` +core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/services/ +├── AuthenticationService.kt +├── BeneficiaryService.kt +├── ClientChargeService.kt +├── ClientService.kt +├── GuarantorService.kt +├── LoanService.kt +├── NotificationService.kt +├── RegistrationService.kt +├── SavingAccountsService.kt +├── ShareAccountService.kt +├── ThirdPartyTransferService.kt +└── UserService.kt +``` + +--- + +## Related Files + +### Server Layer (This Directory) +- [API_REFERENCE.md](API_REFERENCE.md) - Complete endpoint documentation +- [CLIENT_PATTERNS.md](CLIENT_PATTERNS.md) - Service/Repository patterns +- [ERROR_HANDLING.md](ERROR_HANDLING.md) - Exception handling reference + +### Design Layer (Source of Truth) +- Feature API Docs: `design-spec-layer/features/*/API.md` + +### Client Layer (Implementation) +- Service Implementations: `core/network/services/` +- Repository Layer: `core/data/repository/` +- Kotlin DTOs: `core/model/entity/` + +--- + +## Changelog + +| Date | Change | +|------|--------| +| 2025-01-05 | Restructured as part of modular server layer docs | +| 2025-01-05 | Created with merged content from FINERACT_API.md + feature API.md files | diff --git a/claude-product-cycle/server-layer/API_REFERENCE.md b/claude-product-cycle/server-layer/API_REFERENCE.md new file mode 100644 index 000000000..b14134562 --- /dev/null +++ b/claude-product-cycle/server-layer/API_REFERENCE.md @@ -0,0 +1,865 @@ +# Fineract Self-Service API Reference + +> **Purpose**: Complete endpoint documentation for client layer implementation +> **Derived from**: Design layer `features/*/API.md` files +> **Swagger UI**: [sandbox.mifos.community/swagger-ui](https://sandbox.mifos.community/fineract-provider/swagger-ui/index.html#/) + +--- + +## Table of Contents +1. [Overview](#overview) +2. [Authentication](#authentication) +3. [Client](#client) +4. [Accounts](#accounts) +5. [Savings Account](#savings-account) +6. [Loan Account](#loan-account) +7. [Share Account](#share-account) +8. [Beneficiary](#beneficiary) +9. [Transfer](#transfer) +10. [Guarantor](#guarantor) +11. [Notification](#notification) +12. [Charges](#charges) +13. [User Settings](#user-settings) + +--- + +## Overview + +### Base URL +``` +https://{server}/fineract-provider/api/v1/self/ +``` + +### Servers +| Environment | Server | +|-------------|--------| +| Sandbox | `sandbox.mifos.community` | +| Demo | `tt.mifos.community` or `gsoc.mifos.community` | + +### Headers (All Requests) +``` +Authorization: Basic {base64(username:password)} +Fineract-Platform-TenantId: {tenant} +Content-Type: application/json +``` + +### Common Query Parameters +| Parameter | Type | Description | +|-----------|------|-------------| +| `locale` | String | Response locale (default: "en") | +| `dateFormat` | String | Date format (default: "dd MMMM yyyy") | +| `associations` | String | Include related data | + +--- + +## Authentication + +### POST /authentication +**Purpose**: Login with username and password + +**Service**: `AuthenticationService.authenticate()` + +**Request**: +```json +{ + "username": "string", + "password": "string" +} +``` + +**Response**: +```json +{ + "userId": 123, + "username": "john_doe", + "clients": [456], + "isAuthenticated": true, + "base64EncodedAuthenticationKey": "encoded_key", + "officeName": "Head Office" +} +``` + +**DTO**: `User` +```kotlin +@Serializable +data class User( + val userId: Long, + val username: String?, + val clients: List, + val isAuthenticated: Boolean, + val base64EncodedAuthenticationKey: String?, + val officeName: String?, +) +``` + +--- + +### POST /registration +**Purpose**: Register new client + +**Service**: `RegistrationService.register()` + +**Request**: +```json +{ + "accountNumber": "string", + "authenticationMode": "email", + "email": "user@example.com", + "firstName": "John", + "middleName": "M", + "lastName": "Doe", + "mobileNumber": "1234567890", + "password": "securePassword123", + "username": "john_doe" +} +``` + +**Response**: +```json +{ + "requestId": "12345" +} +``` + +**DTO**: `RegisterPayload` + +--- + +### POST /registration/user +**Purpose**: Verify OTP for registration + +**Service**: `RegistrationService.verifyOtp()` + +**Request**: +```json +{ + "authenticationToken": "123456", + "requestId": "12345" +} +``` + +**Response**: +```json +{ + "message": "User verified successfully" +} +``` + +--- + +## Client + +### GET /clients +**Purpose**: Get client list for authenticated user + +**Service**: `ClientService.clients()` + +**Response**: +```json +{ + "pageItems": [ + { + "id": 1, + "accountNo": "000000001", + "displayName": "John Doe", + "officeId": 1, + "officeName": "Head Office" + } + ] +} +``` + +**DTO**: `Page` + +--- + +### GET /clients/{clientId} +**Purpose**: Get client details + +**Service**: `ClientService.getClientDetails(clientId)` + +**Response**: +```json +{ + "id": 1, + "accountNo": "000000001", + "displayName": "John Doe", + "firstname": "John", + "lastname": "Doe", + "mobileNo": "1234567890", + "emailAddress": "john@example.com", + "dateOfBirth": [1990, 1, 15], + "officeId": 1, + "officeName": "Head Office" +} +``` + +**DTO**: `Client` + +--- + +### GET /clients/{clientId}/images +**Purpose**: Get client profile image + +**Service**: `ClientService.getClientImage(clientId)` + +**Response**: Base64 encoded image or image URL + +--- + +### GET /clients/{clientId}/accounts +**Purpose**: Get all accounts for a client + +**Service**: `ClientService.getClientAccounts(clientId)` + +**Response**: +```json +{ + "savingsAccounts": [ + { + "id": 12345, + "accountNo": "000000012345", + "productName": "Basic Savings", + "accountBalance": 1234.56, + "status": { "id": 300, "value": "Active" } + } + ], + "loanAccounts": [ + { + "id": 67890, + "accountNo": "000000067890", + "productName": "Personal Loan", + "loanBalance": 5000.00, + "status": { "id": 300, "value": "Active" } + } + ], + "shareAccounts": [] +} +``` + +**DTO**: `ClientAccounts` + +--- + +## Savings Account + +### GET /savingsaccounts/{accountId} +**Purpose**: Get savings account details with optional associations + +**Service**: `SavingAccountsListService.getSavingsWithAssociations(accountId, associations)` + +**Query Parameters**: +| Parameter | Type | Values | +|-----------|------|--------| +| `associations` | String | `transactions`, `charges` | + +**Response**: +```json +{ + "id": 12345, + "accountNo": "000000012345", + "depositType": { "id": 100, "value": "Savings" }, + "clientId": 1, + "clientName": "John Doe", + "savingsProductId": 1, + "savingsProductName": "Basic Savings", + "status": { + "id": 300, + "code": "savingsAccountStatusType.active", + "value": "Active" + }, + "currency": { + "code": "USD", + "displaySymbol": "$", + "decimalPlaces": 2 + }, + "summary": { + "totalDeposits": 5000.00, + "totalWithdrawals": 3765.44, + "accountBalance": 1234.56 + }, + "transactions": [...] +} +``` + +**DTO**: `SavingsWithAssociations` + +--- + +### GET /savingsaccounts/template +**Purpose**: Get template for savings application + +**Service**: `SavingAccountsListService.getSavingsAccountApplicationTemplate(clientId)` + +**Query Parameters**: +| Parameter | Type | Required | +|-----------|------|----------| +| `clientId` | Long | Yes | +| `productId` | Long | No | + +**Response**: +```json +{ + "clientId": 1, + "clientName": "John Doe", + "productOptions": [ + { + "id": 1, + "name": "Basic Savings", + "allowOverdraft": false + } + ] +} +``` + +**DTO**: `SavingsAccountTemplate` + +--- + +### POST /savingsaccounts +**Purpose**: Submit savings account application + +**Service**: `SavingAccountsListService.submitSavingAccountApplication(payload)` + +**Request**: +```json +{ + "clientId": 1, + "productId": 1, + "locale": "en", + "dateFormat": "dd MMMM yyyy", + "submittedOnDate": "29 December 2025" +} +``` + +**Response**: +```json +{ + "officeId": 1, + "clientId": 1, + "savingsId": 12345, + "resourceId": 12345 +} +``` + +**DTO**: `SavingsAccountApplicationPayload` + +--- + +### PUT /savingsaccounts/{accountId} +**Purpose**: Update pending savings account + +**Service**: `SavingAccountsListService.updateSavingsAccountUpdate(accountId, payload)` + +**Request**: +```json +{ + "clientId": 1, + "productId": 2 +} +``` + +**DTO**: `SavingsAccountUpdatePayload` + +--- + +### POST /savingsaccounts/{savingsId}?command=withdrawnByApplicant +**Purpose**: Withdraw savings application + +**Service**: `SavingAccountsListService.submitWithdrawSavingsAccount(savingsId, payload)` + +**Request**: +```json +{ + "locale": "en", + "dateFormat": "dd MMMM yyyy", + "withdrawnOnDate": "29 December 2025", + "note": "User requested withdrawal" +} +``` + +**DTO**: `SavingsAccountWithdrawPayload` + +--- + +## Loan Account + +### GET /loans/{loanId} +**Purpose**: Get loan account details with associations + +**Service**: `LoanService.getLoanWithAssociations(loanId, associations)` + +**Query Parameters**: +| Parameter | Values | +|-----------|--------| +| `associations` | `transactions`, `repaymentSchedule`, `charges` | + +**Response**: +```json +{ + "id": 67890, + "accountNo": "000000067890", + "clientId": 1, + "clientName": "John Doe", + "loanProductId": 1, + "loanProductName": "Personal Loan", + "principal": 10000.00, + "status": { "id": 300, "value": "Active" }, + "summary": { + "principalDisbursed": 10000.00, + "principalPaid": 5000.00, + "principalOutstanding": 5000.00, + "interestCharged": 500.00, + "totalExpectedRepayment": 10500.00 + }, + "repaymentSchedule": {...}, + "transactions": [...] +} +``` + +**DTO**: `LoanWithAssociations` + +--- + +### GET /loanproducts +**Purpose**: Get available loan products + +**Service**: `LoanService.getLoanProducts()` + +**Response**: +```json +[ + { + "id": 1, + "name": "Personal Loan", + "principal": 10000.00, + "interestRatePerPeriod": 12.0 + } +] +``` + +**DTO**: `List` + +--- + +### POST /loans +**Purpose**: Submit loan application + +**Service**: `LoanService.createLoansAccount(payload)` + +**Request**: +```json +{ + "clientId": 1, + "productId": 1, + "principal": 10000.00, + "loanTermFrequency": 12, + "loanTermFrequencyType": 2, + "numberOfRepayments": 12, + "repaymentEvery": 1, + "repaymentFrequencyType": 2, + "interestRatePerPeriod": 12.0, + "expectedDisbursementDate": "29 December 2025", + "submittedOnDate": "29 December 2025", + "locale": "en", + "dateFormat": "dd MMMM yyyy" +} +``` + +**DTO**: `LoansPayload` + +--- + +### POST /loans/{loanId}?command=withdrawnByApplicant +**Purpose**: Withdraw loan application + +**Service**: `LoanService.withdrawLoanAccount(loanId, payload)` + +--- + +### GET /loans/{loanId}/template?templateType=repayment +**Purpose**: Get loan repayment template + +**Service**: `LoanService.getLoanRepaymentTemplate(loanId)` + +--- + +### GET /loans/{loanId}/transactions/{transactionId} +**Purpose**: Get loan transaction details + +**Service**: `LoanService.getLoanAccountTransaction(loanId, transactionId)` + +--- + +## Share Account + +### GET /products/share +**Purpose**: Get available share products + +**Service**: `ShareAccountService.getShareProducts()` + +**Response**: +```json +[ + { + "id": 1, + "name": "Common Shares", + "shortName": "CS", + "unitPrice": 100.00, + "currency": { "code": "USD", "displaySymbol": "$" } + } +] +``` + +--- + +### POST /shareaccounts +**Purpose**: Submit share account application + +**Service**: `ShareAccountService.submitShareApplication(payload)` + +--- + +### GET /shareaccounts/{accountId} +**Purpose**: Get share account details + +**Service**: `ShareAccountService.getShareAccountDetails(accountId)` + +--- + +## Beneficiary + +### GET /beneficiaries/tpt +**Purpose**: Get list of beneficiaries + +**Service**: `BeneficiaryService.beneficiaryList()` + +**Response**: +```json +[ + { + "id": 5001, + "name": "John Doe", + "officeName": "Head Office", + "clientName": "John Doe", + "accountType": { "id": 2, "value": "Savings Account" }, + "accountNumber": "SA-0001234567", + "transferLimit": 10000.00 + } +] +``` + +**DTO**: `Beneficiary` + +--- + +### GET /beneficiaries/tpt/template +**Purpose**: Get beneficiary template (account type options) + +**Service**: `BeneficiaryService.beneficiaryTemplate()` + +**Response**: +```json +{ + "accountTypeOptions": [ + { "id": 0, "value": "Share Account" }, + { "id": 1, "value": "Loan Account" }, + { "id": 2, "value": "Savings Account" } + ] +} +``` + +**DTO**: `BeneficiaryTemplate` + +--- + +### POST /beneficiaries/tpt +**Purpose**: Create new beneficiary + +**Service**: `BeneficiaryService.createBeneficiary(payload)` + +**Request**: +```json +{ + "locale": "en", + "name": "John Doe", + "accountNumber": "SA-0001234567", + "accountType": 2, + "transferLimit": 10000, + "officeName": "Head Office" +} +``` + +**Response**: +```json +{ + "resourceId": 5003 +} +``` + +**DTO**: `BeneficiaryPayload` + +--- + +### PUT /beneficiaries/tpt/{beneficiaryId} +**Purpose**: Update beneficiary + +**Service**: `BeneficiaryService.updateBeneficiary(beneficiaryId, payload)` + +**Request**: +```json +{ + "name": "John Doe Updated", + "transferLimit": 15000 +} +``` + +**DTO**: `BeneficiaryUpdatePayload` + +--- + +### DELETE /beneficiaries/tpt/{beneficiaryId} +**Purpose**: Delete beneficiary + +**Service**: `BeneficiaryService.deleteBeneficiary(beneficiaryId)` + +--- + +## Transfer + +### GET /accounttransfers/template +**Purpose**: Get transfer template with account options + +**Service**: `SavingAccountsListService.accountTransferTemplate(fromAccountId, fromAccountType)` + +**Query Parameters**: +| Parameter | Type | +|-----------|------| +| `fromAccountId` | Long | +| `fromAccountType` | Long (2 = Savings) | + +**Response**: +```json +{ + "fromAccountTypeOptions": [...], + "toAccountTypeOptions": [...], + "fromAccountOptions": [ + { + "accountId": 12345, + "accountNo": "000000012345", + "accountType": { "id": 2, "value": "Savings Account" }, + "clientId": 1, + "clientName": "John Doe" + } + ], + "toAccountOptions": [...] +} +``` + +**DTO**: `AccountOptionsTemplate` + +--- + +### POST /accounttransfers +**Purpose**: Execute account transfer + +**Service**: `SavingAccountsListService.makeTransfer(payload)` + +**Request**: +```json +{ + "fromOfficeId": 1, + "fromClientId": 1, + "fromAccountType": 2, + "fromAccountId": 12345, + "toOfficeId": 1, + "toClientId": 2, + "toAccountType": 2, + "toAccountId": 12346, + "transferDate": "29 December 2025", + "transferAmount": 100.00, + "transferDescription": "Transfer to beneficiary", + "dateFormat": "dd MMMM yyyy", + "locale": "en" +} +``` + +**DTO**: `TransferPayload` + +--- + +## Guarantor + +### GET /loans/{loanId}/guarantors +**Purpose**: Get list of guarantors for a loan + +**Service**: `GuarantorService.getGuarantorList(loanId)` + +--- + +### GET /loans/{loanId}/guarantors/template +**Purpose**: Get guarantor template + +**Service**: `GuarantorService.getGuarantorTemplate(loanId)` + +--- + +### POST /loans/{loanId}/guarantors +**Purpose**: Add guarantor to loan + +**Service**: `GuarantorService.addGuarantor(loanId, payload)` + +--- + +### PUT /loans/{loanId}/guarantors/{guarantorId} +**Purpose**: Update guarantor + +**Service**: `GuarantorService.updateGuarantor(loanId, guarantorId, payload)` + +--- + +### DELETE /loans/{loanId}/guarantors/{guarantorId} +**Purpose**: Delete guarantor + +**Service**: `GuarantorService.deleteGuarantor(loanId, guarantorId)` + +--- + +## Notification + +### GET /device/registration/client/{clientId} +**Purpose**: Get notification registration ID + +**Service**: `NotificationService.getUserNotificationId(clientId)` + +--- + +### POST /device/registration +**Purpose**: Register device for notifications + +**Service**: `NotificationService.registerNotification(payload)` + +**Request**: +```json +{ + "clientId": 1, + "registrationId": "fcm_token_here" +} +``` + +--- + +### PUT /device/registration/{id} +**Purpose**: Update notification registration + +**Service**: `NotificationService.updateRegisterNotification(id, payload)` + +--- + +## Charges + +### GET /clients/{clientId}/charges +**Purpose**: Get client charges + +**Service**: `ClientChargeService.getClientChargeList(clientId)` + +**Response**: +```json +{ + "totalFilteredRecords": 3, + "pageItems": [ + { + "clientId": 1, + "chargeId": 101, + "name": "Processing Fee", + "dueDate": [2025, 1, 15], + "amount": 50.00, + "amountPaid": 0.00, + "amountOutstanding": 50.00, + "penalty": false, + "isActive": true, + "paid": false + } + ] +} +``` + +**DTO**: `Page` + +--- + +### GET /loans/{loanId}/charges +**Purpose**: Get loan charges + +**Service**: `ClientChargeService.getChargeList("loans", loanId)` + +--- + +### GET /savingsaccounts/{accountId}/charges +**Purpose**: Get savings account charges + +**Service**: `ClientChargeService.getChargeList("savingsaccounts", accountId)` + +--- + +## User Settings + +### PUT /user/password +**Purpose**: Update user password + +**Service**: `UserService.updatePassword(payload)` + +**Request**: +```json +{ + "newPassword": "newSecurePassword123", + "confirmPassword": "newSecurePassword123" +} +``` + +--- + +## Local-Only Features + +These features do not require API calls: + +| Feature | Storage | Notes | +|---------|---------|-------| +| QR Code | - | Local generation/scanning | +| Location | Static | Hardcoded branch locations | +| Passcode | DataStore | Local biometric/PIN | + +--- + +## Error Response Format + +All endpoints return errors in this format: + +```json +{ + "developerMessage": "Detailed error for debugging", + "httpStatusCode": "400", + "defaultUserMessage": "User-friendly message", + "userMessageGlobalisationCode": "error.msg.code", + "errors": [] +} +``` + +See [ERROR_HANDLING.md](ERROR_HANDLING.md) for complete error handling guide. + +--- + +## Related Files + +- Quick Lookup: [API_INDEX.md](API_INDEX.md) +- Client Patterns: [CLIENT_PATTERNS.md](CLIENT_PATTERNS.md) +- Error Handling: [ERROR_HANDLING.md](ERROR_HANDLING.md) +- Design Layer: `design-spec-layer/features/*/API.md` + +--- + +## Changelog + +| Date | Change | +|------|--------| +| 2025-01-05 | Created - aggregated from design layer API.md files | diff --git a/claude-product-cycle/server-layer/CLIENT_PATTERNS.md b/claude-product-cycle/server-layer/CLIENT_PATTERNS.md new file mode 100644 index 000000000..776d8363d --- /dev/null +++ b/claude-product-cycle/server-layer/CLIENT_PATTERNS.md @@ -0,0 +1,517 @@ +# Client Layer Implementation Patterns + +> **Purpose**: Service and Repository implementation patterns for client layer +> **Derived from**: Design layer API.md files +> **Location**: `core/network/` (services), `core/data/` (repositories) + +--- + +## Table of Contents +1. [Overview](#overview) +2. [Service Interface Pattern](#service-interface-pattern) +3. [Repository Interface Pattern](#repository-interface-pattern) +4. [Repository Implementation Pattern](#repository-implementation-pattern) +5. [DTO Patterns](#dto-patterns) +6. [DataState Pattern](#datastate-pattern) +7. [Flow vs Suspend Guidelines](#flow-vs-suspend-guidelines) +8. [Complete Examples](#complete-examples) + +--- + +## Overview + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ SERVICE (core/network/services/) │ +│ └─→ Ktorfit interface with HTTP annotations │ +│ └─→ Returns Flow or HttpResponse │ +├─────────────────────────────────────────────────────────────────┤ +│ REPOSITORY INTERFACE (core/data/repository/) │ +│ └─→ Defines contract for data operations │ +│ └─→ Returns Flow> or DataState │ +├─────────────────────────────────────────────────────────────────┤ +│ REPOSITORY IMPLEMENTATION (core/data/repositoryImpl/) │ +│ └─→ Implements repository interface │ +│ └─→ Handles error mapping and dispatcher context │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Service Interface Pattern + +### Location +`core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/services/` + +### Template + +```kotlin +package org.mifos.mobile.core.network.services + +import de.jensklingenberg.ktorfit.http.* +import io.ktor.client.statement.HttpResponse +import kotlinx.coroutines.flow.Flow + +interface [Feature]Service { + + // GET - List (returns typed Flow) + @GET(ApiEndPoints.[FEATURE]) + fun get[Feature]List(): Flow> + + // GET - Single item (returns typed Flow) + @GET(ApiEndPoints.[FEATURE] + "/{id}") + fun get[Feature]Details( + @Path("id") id: Long, + ): Flow<[Entity]> + + // GET - With query params + @GET(ApiEndPoints.[FEATURE] + "/{id}") + fun get[Feature]WithAssociations( + @Path("id") id: Long, + @Query("associations") associations: String?, + ): Flow<[EntityWithAssociations]> + + // GET - Template + @GET(ApiEndPoints.[FEATURE] + "/template") + fun get[Feature]Template(): Flow<[Feature]Template> + + // POST - Create (returns HttpResponse for error handling) + @POST(ApiEndPoints.[FEATURE]) + suspend fun create[Feature]( + @Body payload: [Feature]Payload?, + ): HttpResponse + + // PUT - Update + @PUT(ApiEndPoints.[FEATURE] + "/{id}") + suspend fun update[Feature]( + @Path("id") id: Long, + @Body payload: [Feature]UpdatePayload?, + ): HttpResponse + + // DELETE - Remove + @DELETE(ApiEndPoints.[FEATURE] + "/{id}") + suspend fun delete[Feature]( + @Path("id") id: Long, + ): HttpResponse + + // POST - With command + @POST(ApiEndPoints.[FEATURE] + "/{id}?command=action") + suspend fun [feature]Action( + @Path("id") id: Long, + @Body payload: [Action]Payload?, + ): HttpResponse +} +``` + +### Key Rules + +| Annotation | Usage | Return Type | +|------------|-------|-------------| +| `@GET` | Read operations | `Flow` | +| `@POST` | Create operations | `suspend HttpResponse` | +| `@PUT` | Update operations | `suspend HttpResponse` | +| `@DELETE` | Delete operations | `suspend HttpResponse` | +| `@Path` | URL path variable | N/A | +| `@Query` | Query parameter | N/A | +| `@Body` | Request body | N/A | + +### When to Use Flow vs HttpResponse + +| Scenario | Return Type | Reason | +|----------|-------------|--------| +| GET typed response | `Flow` | Direct deserialization | +| POST/PUT/DELETE | `suspend HttpResponse` | Need to handle errors manually | +| GET with error handling | `suspend HttpResponse` | Custom error extraction | + +--- + +## Repository Interface Pattern + +### Location +`core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/repository/` + +### Template + +```kotlin +package org.mifos.mobile.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifos.mobile.core.common.DataState + +interface [Feature]Repository { + + // GET - List + fun get[Feature]List(): Flow>> + + // GET - Single + fun get[Feature]Details(id: Long): Flow> + + // GET - Template + fun get[Feature]Template(): Flow> + + // POST - Create + suspend fun create[Feature](payload: [Feature]Payload?): DataState + + // PUT - Update + suspend fun update[Feature]( + id: Long?, + payload: [Feature]UpdatePayload?, + ): DataState + + // DELETE - Remove + suspend fun delete[Feature](id: Long?): DataState +} +``` + +### Key Rules + +| Operation | Return Type | Pattern | +|-----------|-------------|---------| +| Read (list/single) | `Flow>` | Streaming updates | +| Create/Update/Delete | `DataState` | One-shot operation | +| Template fetching | `Flow>` | May update | + +--- + +## Repository Implementation Pattern + +### Location +`core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/repositoryImpl/` + +### Template + +```kotlin +package org.mifos.mobile.core.data.repositoryImpl + +import io.ktor.client.call.body +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.plugins.ServerResponseException +import io.ktor.client.statement.bodyAsText +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext +import org.mifos.mobile.core.common.DataState +import org.mifos.mobile.core.network.DataManager +import java.io.IOException + +class [Feature]RepositoryImpl( + private val dataManager: DataManager, + private val ioDispatcher: CoroutineDispatcher, +) : [Feature]Repository { + + // Pattern 1: Flow-based GET (for lists and details) + override fun get[Feature]List(): Flow>> = flow { + try { + dataManager.[feature]Api.get[Feature]List() + .collect { response -> + emit(DataState.Success(response)) + } + } catch (e: Exception) { + emit(DataState.Error(e, null)) + } + }.flowOn(ioDispatcher) + + // Pattern 2: Alternative Flow with map/catch + override fun get[Feature]Details(id: Long): Flow> { + return dataManager.[feature]Api.get[Feature]Details(id) + .map { DataState.Success(it) } + .catch { emit(DataState.Error(it, null)) } + .flowOn(ioDispatcher) + } + + // Pattern 3: Suspend-based POST/PUT/DELETE with error handling + override suspend fun create[Feature](payload: [Feature]Payload?): DataState { + return withContext(ioDispatcher) { + try { + val response = dataManager.[feature]Api.create[Feature](payload) + DataState.Success(response.bodyAsText()) + } catch (e: ClientRequestException) { + val errorMessage = extractErrorMessage(e.response) + DataState.Error(Exception(errorMessage), null) + } catch (e: IOException) { + DataState.Error( + Exception("Network error: ${e.message ?: "Please check your connection"}"), + null + ) + } catch (e: ServerResponseException) { + DataState.Error(Exception("Server error: ${e.message}"), null) + } + } + } + + // Pattern 4: Update with path parameter + override suspend fun update[Feature]( + id: Long?, + payload: [Feature]UpdatePayload?, + ): DataState { + return withContext(ioDispatcher) { + try { + val response = dataManager.[feature]Api.update[Feature](id!!, payload) + DataState.Success(response.bodyAsText()) + } catch (e: ClientRequestException) { + val errorMessage = extractErrorMessage(e.response) + DataState.Error(Exception(errorMessage), null) + } catch (e: IOException) { + DataState.Error( + Exception("Network error: ${e.message ?: "Please check your connection"}"), + null + ) + } catch (e: ServerResponseException) { + DataState.Error(Exception("Server error: ${e.message}"), null) + } + } + } + + // Pattern 5: Delete operation + override suspend fun delete[Feature](id: Long?): DataState { + return withContext(ioDispatcher) { + try { + val response = dataManager.[feature]Api.delete[Feature](id!!) + DataState.Success(response.bodyAsText()) + } catch (e: ClientRequestException) { + val errorMessage = extractErrorMessage(e.response) + DataState.Error(Exception(errorMessage), null) + } catch (e: IOException) { + DataState.Error( + Exception("Network error: ${e.message ?: "Please check your connection"}"), + null + ) + } catch (e: ServerResponseException) { + DataState.Error(Exception("Server error: ${e.message}"), null) + } + } + } +} +``` + +--- + +## DTO Patterns + +### Location +`core/model/src/commonMain/kotlin/org/mifos/mobile/core/model/entity/` + +### Response DTO (Entity) + +```kotlin +@Serializable +@Parcelize +data class [Entity]( + val id: Long? = null, + val name: String? = null, + val status: Status? = null, + val createdDate: List? = null, + // All fields nullable with defaults +) : Parcelable +``` + +### Request DTO (Payload) + +```kotlin +@Serializable +@Parcelize +data class [Feature]Payload( + val locale: String? = null, + val dateFormat: String? = null, + val name: String? = null, + val amount: Double? = null, + // Fields matching API request body +) : Parcelable +``` + +### Update DTO + +```kotlin +@Serializable +data class [Feature]UpdatePayload( + val name: String? = null, + val amount: Int = 0, + // Only updatable fields +) +``` + +### Template DTO + +```kotlin +@Serializable +@Parcelize +data class [Feature]Template( + val options: List