Compare commits

...

86 Commits

Author SHA1 Message Date
Mark Rizkalla
1600b41ad2
feat(share-account): Add language support for share-account details (#3096)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 19:03:01 +02:00
Piyush
eb3f1f9b66
feat(loan-application): Add language support for loan application module (#3100)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-04 18:35:17 +05:30
Aditya002500
2b72ee5077
Added strings in each language (#3104) 2026-02-04 06:36:49 -05:00
Aryan Baglane
7516d55272
Fix: Handle missing fields in client profile API response (#3097) 2026-02-03 12:04:09 -05:00
Aryan Baglane
36206fa808
fix- consistent currency format for all regions [MM - 540] (#3093)
Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
2026-01-29 01:10:18 -05:00
rho023
a5bc7b5680
Fix ripple to match service button border radius (#3072) 2026-01-28 19:10:08 +05:30
Kartikey Shukla
6f052759ee
fix(core-ui): ensure dropdown menu items are visible on iOS (#3092) 2026-01-27 12:49:16 -05:00
Sahl Shivekar
16d6edeefe
feat(beneficiary): (MM-519 & 538) Add language support for beneficiary module (#3087)
Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
2026-01-26 07:53:06 +00:00
Naman Kumar
d6673677d0
MM-542 loan account details doesnt render properly the values in the button table (#3083)
Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
2026-01-26 12:38:11 +05:30
gurnoor
4cf1f60e38
feat: replace grid with vertical list layout for loan selection (MM-530) (#3079)
Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
2026-01-26 12:22:24 +05:30
rho023
9c1f4e29b7
Fix crash when opening approved savings account with no transactions (#3089)
Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
2026-01-23 21:24:01 +05:30
Aryan Baglane
be4180422e
chore: Update docs of recent transaction screen (#3090)
Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
2026-01-23 21:16:55 +05:30
Kartikey Shukla
91b46f13ee
feat(feature):add malayalam translations (#3078) 2026-01-23 21:13:22 +05:30
Aryan Baglane
be1b948e79
feat(client-charge): add client charges screen accessible from home (#3049) 2026-01-23 07:24:43 -05:00
Mina Rizkalla Azmy
835646ce98
fix(core): restore missing transfer description (#3077) 2026-01-22 12:25:41 -05:00
Víctor Romero
d91186bf89
MM-543 Spanish Translation for Savings Application Screen (#3080) 2026-01-22 12:23:24 -05:00
Kartikey Shukla
37b6bd9aa3
fix(core-base/platform): prevent crash on Profile tab tap (#3073) 2026-01-17 03:33:23 -05:00
Mark Rizkalla
c5e270b2f0
Add account available balance and balance validation in TPT (#3070) 2026-01-16 12:02:48 -05:00
Mark Rizkalla
29f5fd3a3c
fix(ui): fix account status is being cut & standardize status color (#3047) 2026-01-16 12:01:13 -05:00
Nagarjuna
53c766b343
refactor(core): update RegisterPayloadMapper to include additional us… (#3076) 2026-01-16 17:44:28 +05:30
Nagarjuna
5c961c6937
feat(network): migrate domain models to DTOs and update API services (#3065) 2026-01-14 11:19:37 -05:00
Kartikey Shukla
f161292c84
Adding centralized unauthorized handling on 401 responses (#3030) 2026-01-13 12:12:59 +05:30
Mina Rizkalla Azmy
adb54d3b64
feat(accounts): add transfer description to transaction details (#3069) 2026-01-12 14:14:31 -05:00
Ambarish Manna
8b3f4f915c
fix: language revert to system default after switching back from a custom language (#3060) 2026-01-12 14:14:19 -05:00
Mark Rizkalla
e4ef866b56
fix(thirdPartyTransfer): exclude loan accounts from transfer source selector (#3063) 2026-01-12 14:14:06 -05:00
Víctor Romero
b389ccf02a
MM-528: Translation To Selected Languages (#3068) 2026-01-12 14:13:41 -05:00
Mina Rizkalla Azmy
86ff1757c2
refactor(loan-application): UI cleanup and dynamic amount validation (#3050) 2026-01-12 11:59:28 -05:00
Aryan Baglane
6d2e08e897
fix(home): improve service grid alignment on home screen (#3064) 2026-01-12 11:54:14 -05:00
Rajan Maurya
145ab0cf7c
chore: remove claude-product-cycle directory (#3061) 2026-01-07 05:04:34 -05:00
Rajan Maurya
fd1525e032 Revert "feat(design): add design-tokens.json for 9 features"
This reverts commit 3460d29fdb.
2026-01-07 15:26:34 +05:30
Rajan Maurya
3460d29fdb feat(design): add design-tokens.json for 9 features
Generate design token specifications for mockup generation:
- accounts: Financial command center tokens
- beneficiary: Beneficiary management tokens
- home: Dashboard tokens
- loan-account: Loan detail tokens
- notification: Notification list tokens
- recent-transaction: Transaction list tokens
- savings-account: Savings detail tokens
- share-account: Share account tokens
- transfer: Transfer flow tokens

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 15:23:11 +05:30
Rajan Maurya
a66f6c2252 docs: add prompt layer integration to CLAUDE.md
- Add automatic trigger system instructions
- Document runtime prompts for plans
- Reference prompt-layer files for cross-instruction rules
- Add table of all triggers and their prompts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 15:03:09 +05:30
Rajan Maurya
d7b5c65ff4 feat(commands): add plan prompts to gap-planning and gap-status
- Add plan-ready and plan-layer triggers to gap-planning command
- Add plan-continue prompts to gap-status command
- Reference prompt-layer for consistent user interactions
- Support step execution, review, and pause workflows

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 14:55:13 +05:30
Rajan Maurya
b351148ac2
feat(testing): add core:testing module with fakes, fixtures, and TestTags (#3059)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 01:43:35 -05:00
Rajan Maurya
cd556ffc99
chore: add iOS generated files to gitignore (#3058)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 04:20:05 -05:00
Rajan Maurya
4bb7e78ffd
docs: add testing documentation to claude-product-cycle (#3057)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 04:13:20 -05:00
Rajan Maurya
caa4285fa3
docs: add feature branch workflow requirement to CLAUDE.md (#3055) 2026-01-04 22:42:13 -05:00
Rajan Maurya
ee27d4aa95 feat(docs): add comprehensive feature layer instructions and component registry
- Add feature-layer/instructions/ with modular implementation guides:
  - VIEWMODEL.md: MVI patterns (State, Event, Action, Internal Actions)
  - COMPOSE.md: Screen patterns, theming, component hierarchy
  - NAVIGATION.md: Type-safe routes, NavGraph, transitions
  - DI.md: Koin module patterns and registration
  - UPDATING_FEATURE.md: v2.0 UI redesign and improvement workflow

- Add core-layer/COMPONENTS.md with hybrid lookup strategy:
  - Static registry for fast O(1) component lookup
  - Dynamic fallback for discovering new components
  - Auto-update rules to keep registry current
  - Naming conventions (Kpt*, Mifos*, [Feature]*, [Screen]*)

- Update LAYER_GUIDE.md:
  - Add Table of Contents for quick navigation
  - Add "Creating New Feature" step-by-step guide
  - Add component hierarchy and placement rules
  - Add Component Creation cross-update rules
  - Reference modular instruction files
2026-01-05 03:21:41 +05:30
Rajan Maurya
c4bcc50352
docs: add comprehensive Getting Started guide to CLAUDE_PRODUCT_CYCLE.md (#3054) 2026-01-04 08:03:59 -05:00
Rajan Maurya
fdc2ff5d57
feat: add v2.0 MOCKUP.md designs and gap analysis commands (#3044)
Co-authored-by: therajanmaurya <therajanmaurya@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 06:26:29 -05:00
Pronay Sarker
aca5f620d3
fix: Transfer screen's description field does not allow numbers. (#3040) 2026-01-02 14:09:32 -05:00
Naman Kumar
55dbbb5bee
MM-484 Transfer page doesn't allow to transfer amounts with decimals (#3041)
Co-authored-by: NAMAN KUMAR <namankumar@NAMANs-MacBook-Air-2.local>
2026-01-02 14:07:13 -05:00
Pronay Sarker
791c7b91db
update password in readme.md (#3042) 2026-01-02 14:05:34 -05:00
Nagarjuna
73648d9fd9
feat(recent-transaction): redesign screen and update state management (#3045) 2026-01-02 12:42:13 -05:00
Mina Rizkalla Azmy
88824d51a9
refactor(accounts): separate loan and savings DTOs and implement doma… (#3016) 2026-01-02 12:25:08 -05:00
Biplab Dutta
411af7287f
fix(workflows): correct sync directory workflow for scheduled runs (#3046) 2025-12-31 11:54:16 -05:00
Nagarjuna
99c8d68587
fix(core): correct date format to include day instead of month number (#3043) 2025-12-30 04:41:47 +00:00
Rajan Maurya
75dbc74713
feat: add claude-product-cycle documentation and mockup pipeline (#3038) 2025-12-29 11:07:43 -05:00
Rajan Maurya
9816e6fc8d Revert "feat: add claude-product-cycle documentation and mockup pipeline"
This reverts commit 8bcb50c87f.
2025-12-29 20:38:38 +05:30
Rajan Maurya
8bcb50c87f feat: add claude-product-cycle documentation and mockup pipeline
- Add CLAUDE.md with project guidance for Claude Code
- Create claude-product-cycle structure with design-spec-layer,
  mockup-layer, client-layer, feature-layer, and commands-layer
- Add feature specifications (SPEC.md, API.md) for auth, home, dashboard
- Create Figma plugin for programmatic mockup generation with
  Material Design 3 tokens and component generators
- Add /mockup skill with AI tool prompts (Google Stitch, Uizard, Visily)
- Generate dashboard mockup prompts and design tokens
- Add shared patterns and Fineract API reference documentation
- Register Claude Code skills: /design, /client, /feature, /implement,
  /verify, /projectstatus, /mockup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 20:34:47 +05:30
JILAKARA REVANTH KUMAR
830b54f823
fix: make middle name optional in Registration Screen (#3036) 2025-12-28 19:32:35 +05:30
JILAKARA REVANTH KUMAR
9271d2b146
fix: update transfer details screen (#3037) 2025-12-28 19:32:06 +05:30
Hekmatullah
51e630d4cd
add macOS TestFlight and App Store distribution inputs (#3035) 2025-12-27 16:44:54 +00:00
Biplab Dutta
97c3695885
refactor(core): replace MaterialTheme with KptMaterialTheme (#3027) 2025-12-26 05:39:29 -05:00
Nagarjuna
b4a0e10687
fix: display server response message in error dialogs and status screens (#3032) 2025-12-26 02:27:40 -05:00
Víctor Romero
64a240a809
MM-467: Spanish Translation (#3029) 2025-12-25 10:21:48 -05:00
Nagarjuna
725fb66887
feat(settings): add Urdu and Telugu translations and update logout string keys (#3031) 2025-12-25 10:14:27 -05:00
JILAKARA REVANTH KUMAR
8f725939bf
feat : Added Time Based Theming (#3022) 2025-12-24 23:56:19 +05:30
Mina Rizkalla Azmy
237738efe8
Implemented "Rate Us" functionality in the Settings screen. (#3024) 2025-12-24 11:39:15 -05:00
Mark Rizkalla
39a158e6e4
feat(share-account): implement details screen (#3010) 2025-12-23 11:37:36 -05:00
Biplab Dutta
bdb6b33d51
refactor(feature): replace MaterialTheme with KptTheme (#3013) 2025-12-23 10:39:19 -05:00
JILAKARA REVANTH KUMAR
9b822f0edc
fix : Logout dialog colour in settings (#3021) 2025-12-21 17:20:43 +00:00
JILAKARA REVANTH KUMAR
de5a60fc78
fix: updated Dialog Title for UnSaved Changes Dialog (#3020) 2025-12-21 21:40:00 +05:30
Mina Rizkalla Azmy
cc0049f407
feat(accounts): implement transaction details screen (#3008) 2025-12-17 13:03:13 -05:00
Aryan Baglane
153fd2091d
Doc update: feature/loan application( MM-434) (#3012) 2025-12-16 02:14:19 -05:00
Hekmatullah
adbcdc319c
chore(ci): add workflow to sync directories from upstream template (#3006) 2025-12-12 11:58:23 -05:00
Aryan Baglane
2b49ad9ed6
Mm 441 docs update (#3000) 2025-12-12 11:57:52 -05:00
Aryan Baglane
92ee759d03
Features/recent transaction screen (#3007) 2025-12-12 11:56:29 -05:00
Rajan Maurya
2c69ebfa3b
Add CI-specific Gradle configuration (#3005) 2025-12-06 09:37:04 -05:00
Aryan Baglane
768a6a657d
Docs update[ feature/savingAccounts] MM-440 (#2998) 2025-11-07 06:08:44 -05:00
Aryan Baglane
989d07e69e
docs update/MM-442 (#2997) 2025-11-04 04:36:29 -05:00
Sayam Sharma
35d7fca0fc
Implemented Account Filters in Bottom Sheet (Saving Account, Loan Account, Share Account) (#2994) 2025-11-02 08:51:49 -05:00
Sayam Sharma
43af85e118
Documentation Done for feature/share-account. (#2993) 2025-10-31 12:51:00 -04:00
Sayam Sharma
6268b3b2e4
Documentation Done for feature/share-application (#2992) 2025-10-31 12:50:47 -04:00
Sayam Sharma
3af50cd94b
Documentation Done for feature/notification (#2991) 2025-10-31 12:50:35 -04:00
Sayam Sharma
0d1046452c
Documentation done for feature/third-party-transfer (#2989) 2025-10-31 12:50:24 -04:00
Sayam Sharma
a07a625366
Order Savings Accounts by Active State Etc (#2986) 2025-10-31 12:50:12 -04:00
Sayam Sharma
70c39c6e20
Documentation for features/location (#2985) 2025-10-28 06:41:54 -04:00
Sayam Sharma
df79b2681c
Documentation for features/loan-account (#2984) 2025-10-28 06:41:37 -04:00
Sayam Sharma
bc3d86bdb9
Show Basic Options for All Savings Accounts (#2983) 2025-10-27 12:41:20 -04:00
Sayam Sharma
9e45f31e74
Documentation Added for feature/client-charge (#2980) 2025-10-21 13:13:56 -04:00
Sayam Sharma
2bcafd7e88
Documentation Added for feature/accounts (#2981) 2025-10-21 13:12:05 -04:00
Nagarjuna
6eb1d22caa
feat(savings-account): fetch savings products (#2982) 2025-10-18 13:39:20 +05:30
Sayam Sharma
ddab8ad444
documentation added properly. (#2979) 2025-10-17 06:34:26 -04:00
Hekmatullah
7702fcb6ea
chore(workflows,fastlane): configure macOS App Store distribution for desktop app (lanes, workflow, screenshots) (#2976) 2025-10-07 12:15:54 -04:00
Nagarjuna
f65ef09d8a
feat(core-ui): implement cross-platform file and text sharing (#2974) 2025-10-01 17:40:39 +05:30
1569 changed files with 36135 additions and 4843 deletions

268
.claude/commands/README.md Normal file
View File

@ -0,0 +1,268 @@
# Commands Layer
Slash command definitions for Claude Code integration with Mifos Mobile.
## Quick Reference
```
SESSION MANAGEMENT
├── /session-start # Load context for new session
└── /session-end # Save progress before ending
GAP ANALYSIS (Where are we?)
├── /gap-analysis # Brief overview of all layers
├── /gap-analysis design # Design layer status
│ ├── /gap-analysis design spec # Specifications status
│ ├── /gap-analysis design mockup # Mockups generation status
│ └── /gap-analysis design api # API documentation status
├── /gap-analysis server # Server layer status
├── /gap-analysis client # Client layer status
│ ├── /gap-analysis client network # Network services status
│ └── /gap-analysis client data # Repositories status
├── /gap-analysis feature # Feature layer status
│ └── /gap-analysis feature [name] # Single feature status
├── /gap-analysis platform # Platform layer status
│ ├── /gap-analysis platform android
│ ├── /gap-analysis platform ios
│ ├── /gap-analysis platform desktop
│ └── /gap-analysis platform web
└── /gap-analysis [feature] # Specific feature (all 5 layers)
GAP PLANNING (What needs work?)
├── /gap-planning # Brief overview of what needs planning
├── /gap-planning design # Plan design layer work
│ ├── /gap-planning design spec # Plan specification work
│ ├── /gap-planning design mockup # Plan mockup generation
│ └── /gap-planning design api # Plan API documentation
├── /gap-planning server # Plan server layer work
├── /gap-planning client # Plan 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 [name] # Plan specific feature
├── /gap-planning platform # Plan platform layer work
│ ├── /gap-planning platform android
│ ├── /gap-planning platform ios
│ ├── /gap-planning platform desktop
│ └── /gap-planning platform web
└── /gap-planning [feature] # Plan specific feature (all layers)
GAP STATUS (Track plan progress)
├── /gap-status # Show all active plans
├── /gap-status [plan-name] # Show specific plan progress
├── /gap-status complete [plan] # Mark plan as complete
├── /gap-status pause [plan] # Pause a plan
└── /gap-status resume [plan] # Resume a paused plan
DESIGN LAYER (Specifications & Mockups)
├── /design # Show feature list
├── /design [feature] # Full spec review/create
├── /design [feature] add [section] # Add specific section
├── /design [feature] improve # Suggest improvements
├── /design [feature] mockup # Generate Figma mockups for feature
└── /design mockup # Generate mockups for all features
IMPLEMENTATION
├── /implement [feature] # Full E2E implementation (all layers)
├── /client [feature] # Client layer only (Network + Data)
└── /feature [feature] # Feature layer only (ViewModel + Screen)
VERIFICATION
├── /verify [feature] # Validate implementation vs spec
└── /projectstatus # Project overview and status
```
## Command Details
### Session Management
| Command | Purpose | When to Use |
|---------|---------|-------------|
| `/session-start` | Load context from CURRENT_WORK.md | Start of new session |
| `/session-end` | Save progress, update CURRENT_WORK.md | Before ending session |
### Gap Analysis
| Command | Purpose | Output |
|---------|---------|--------|
| `/gap-analysis` | Quick overview | Brief table of all 5 layers |
| `/gap-analysis design` | Design layer status | SPEC, API, MOCKUP, mockups/ status |
| `/gap-analysis design mockup` | Mockups status only | 17-feature mockup progress table |
| `/gap-analysis client` | Client layer status | Services + repositories status |
| `/gap-analysis feature` | Feature layer status | All features VM+Screen status |
| `/gap-analysis [name]` | Single feature status | All 5 layers for one feature |
### Gap Planning
| Command | Purpose | Output |
|---------|---------|--------|
| `/gap-planning` | What needs work | Priority-sorted task list |
| `/gap-planning design mockup` | Mockup generation plan | Step-by-step with commands |
| `/gap-planning client network` | Network services plan | Service implementation tasks |
| `/gap-planning feature [name]` | Feature implementation plan | v2.0 UI update tasks |
### Gap Status
| Command | Purpose | Output |
|---------|---------|--------|
| `/gap-status` | Show all active plans | Summary table with progress bars |
| `/gap-status [plan]` | Show specific plan | Detailed steps, current step, progress log |
| `/gap-status complete [plan]` | Mark plan done | Move to completed, update index |
| `/gap-status pause [plan]` | Pause a plan | Mark as paused with reason |
| `/gap-status resume [plan]` | Resume plan | Mark as active again |
### Design Layer
| Command | Purpose | Output |
|---------|---------|--------|
| `/design` | Feature list | Available features with status |
| `/design [feature]` | Spec review | SPEC.md + API.md analysis |
| `/design [feature] mockup` | Generate mockups | PROMPTS.md + design-tokens.json |
| `/design mockup` | Generate all | Batch mockup generation |
### Implementation
| Command | Purpose | Layers |
|---------|---------|--------|
| `/implement [feature]` | Full E2E | Network → Data → ViewModel → Screen |
| `/client [feature]` | Client only | Network services + repositories |
| `/feature [feature]` | Feature only | ViewModel + Screen + Navigation |
### Verification
| Command | Purpose | Checks |
|---------|---------|--------|
| `/verify [feature]` | Implementation check | Spec compliance, tests, platforms |
| `/projectstatus` | Project overview | All features, all layers, metrics |
## 5-Layer Product Lifecycle
```
┌─────────────────────────────────────────────────────────────────┐
│ PRODUCT LIFECYCLE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. DESIGN LAYER (Entry Point) │
│ ├── SPEC.md → Requirements, user stories │
│ ├── API.md → Endpoint definitions │
│ ├── MOCKUP.md → ASCII design v2.0 │
│ └── mockups/ → Generated Figma prompts │
│ │
│ 2. SERVER LAYER │
│ └── Fineract API → Endpoint availability │
│ │
│ 3. CLIENT LAYER │
│ ├── Network → Ktorfit services (core/network/) │
│ └── Data → Repositories (core/data/) │
│ │
│ 4. FEATURE LAYER │
│ ├── ViewModel → State management │
│ ├── Screen → Compose UI │
│ ├── Navigation → Route definitions │
│ └── DI → Koin modules │
│ │
│ 5. PLATFORM LAYER │
│ ├── Android → cmp-android/ │
│ ├── iOS → cmp-ios/ │
│ ├── Desktop → cmp-desktop/ │
│ └── Web → cmp-web/ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
## Workflow Examples
### Start New Session
```
/session-start
/gap-analysis # See overview
/gap-planning design mockup # Plan next work
/design auth mockup # Execute task
```
### Check Feature Status
```
/gap-analysis home # All layers for home
/gap-planning feature home # Plan v2.0 UI update
/feature home # Implement UI changes
/verify home # Validate implementation
```
### Full Feature Implementation
```
/design dashboard # Review/create spec
/design dashboard mockup # Generate mockups
/implement dashboard # Full E2E implementation
/verify dashboard # Validate
```
### End Session
```
/session-end # Save progress
```
## Design Layer Deep Dive
The Design Layer is the entry point where we design the whole application. All other layers depend on it.
### Sub-Sections
| Sub-Section | Files | Purpose |
|-------------|-------|---------|
| spec | SPEC.md | Requirements, user stories, acceptance criteria |
| api | API.md | Endpoint definitions, request/response schemas |
| mockup | MOCKUP.md | ASCII design v2.0 (visual layout) |
| mockups/ | PROMPTS.md, design-tokens.json | Generated AI prompts for Figma |
### Mockup Generation Workflow
```
MOCKUP.md (ASCII v2.0)
/design [feature] mockup
mockups/PROMPTS.md + design-tokens.json
User: Google Stitch → Figma
User: Update FIGMA_LINKS.md
/implement [feature] (uses Figma via MCP)
```
### Feature List
| # | Feature | Design Path | Command |
|:-:|---------|-------------|---------|
| 1 | auth | features/auth/ | `/design auth` |
| 2 | home | features/home/ | `/design home` |
| 3 | accounts | features/accounts/ | `/design accounts` |
| 4 | savings-account | features/savings-account/ | `/design savings-account` |
| 5 | loan-account | features/loan-account/ | `/design loan-account` |
| 6 | share-account | features/share-account/ | `/design share-account` |
| 7 | beneficiary | features/beneficiary/ | `/design beneficiary` |
| 8 | transfer | features/transfer/ | `/design transfer` |
| 9 | recent-transaction | features/recent-transaction/ | `/design recent-transaction` |
| 10 | notification | features/notification/ | `/design notification` |
| 11 | settings | features/settings/ | `/design settings` |
| 12 | passcode | features/passcode/ | `/design passcode` |
| 13 | guarantor | features/guarantor/ | `/design guarantor` |
| 14 | qr | features/qr/ | `/design qr` |
| 15 | location | features/location/ | `/design location` |
| 16 | client-charge | features/client-charge/ | `/design client-charge` |
| 17 | dashboard | features/dashboard/ | `/design dashboard` |
## Files
| File | Command | Description |
|------|---------|-------------|
| `session-start.md` | `/session-start` | Load context for new session |
| `session-end.md` | `/session-end` | Save progress before ending |
| `gap-analysis.md` | `/gap-analysis` | Analyze implementation gaps |
| `gap-planning.md` | `/gap-planning` | Plan implementation tasks |
| `design.md` | `/design` | Feature specification |
| `implement.md` | `/implement` | Full E2E implementation |
| `client.md` | `/client` | Client layer implementation |
| `feature.md` | `/feature` | Feature layer implementation |
| `verify.md` | `/verify` | Validate implementation |
| `projectstatus.md` | `/projectstatus` | Project overview |

502
.claude/commands/client.md Normal file
View File

@ -0,0 +1,502 @@
# /client - Client Layer Implementation
## Purpose
Implement the client layer (Network + Data) using O(1) lookup and pattern detection. Creates Services, Repositories, and DI registration with code matching existing codebase conventions.
---
## Command Variants
```
/client # Show client layer status
/client [Feature] # Implement client layer for feature
/client [Feature] --network # Network layer only (Service)
/client [Feature] --data # Data layer only (Repository)
```
---
## Workflow with O(1) Optimization
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ /client [Feature] - O(1) OPTIMIZED WORKFLOW │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ PHASE 0: O(1) CONTEXT LOADING │
│ ├─→ Read FEATURE_MAP.md → Check if service/repo exist │
│ ├─→ Read API_INDEX.md → Get endpoint definitions │
│ ├─→ Read features/[name]/API.md → Get feature-specific endpoints │
│ └─→ Read features/[name]/SPEC.md → Get data requirements │
│ │
│ PHASE 1: PATTERN DETECTION │
│ ├─→ Read existing Service → Extract interface pattern │
│ ├─→ Read existing Repository → Extract implementation pattern │
│ └─→ Read NetworkModule/DataModule → Extract DI pattern │
│ │
│ PHASE 2: NETWORK LAYER (if needed) │
│ ├─→ Check FEATURE_MAP for existing → Skip if exists │
│ ├─→ Create Service interface → Pattern-matched code │
│ └─→ Register in NetworkModule → DI registration │
│ │
│ PHASE 3: DATA LAYER (if needed) │
│ ├─→ Check FEATURE_MAP for existing → Skip if exists │
│ ├─→ Create Repository interface → Pattern-matched code │
│ ├─→ Create RepositoryImpl → Pattern-matched code │
│ └─→ Register in RepositoryModule → DI registration │
│ │
│ PHASE 4: BUILD & VERIFY │
│ ├─→ ./gradlew :core:network:build │
│ ├─→ ./gradlew :core:data:build │
│ ├─→ ./gradlew spotlessApply │
│ └─→ Update FEATURE_MAP.md → Maintain O(1) index │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## PHASE 0: O(1) Context Loading
### Files to Read
| File | Purpose | Data Extracted |
|------|---------|----------------|
| `client-layer/FEATURE_MAP.md` | Service/Repo inventory | existingServices[], existingRepos[] |
| `server-layer/API_INDEX.md` | All API endpoints | endpoints[], dtos[] |
| `design-spec-layer/features/[name]/API.md` | Feature endpoints | featureEndpoints[] |
| `design-spec-layer/features/[name]/SPEC.md` | Data requirements | models[], fields[] |
### Decision Matrix (from FEATURE_MAP.md lookup)
```markdown
| Component | Exists | Action |
|-----------|:------:|--------|
| ${Feature}Service | ✅/❌ | SKIP/CREATE |
| ${Feature}Repository | ✅/❌ | SKIP/CREATE |
```
---
## PHASE 1: Pattern Detection
### Reference Files
```
1. Service Reference:
core/network/src/commonMain/.../services/BeneficiaryService.kt
2. Repository Reference:
core/data/src/commonMain/.../repository/BeneficiaryRepository.kt
core/data/src/commonMain/.../repository/BeneficiaryRepositoryImp.kt
3. DI Reference:
core/network/src/commonMain/.../di/NetworkModule.kt
core/data/src/commonMain/.../di/RepositoryModule.kt
```
### Extracted Patterns
```kotlin
// Service Pattern
val servicePattern = ServicePattern(
returnFlow = "Flow<Type>", // GET returns Flow
returnSuspend = "HttpResponse", // POST/PUT/DELETE returns HttpResponse
pathAnnotation = "@Path(\"id\")",
bodyAnnotation = "@Body",
endpointConstant = "ApiEndPoints.CONSTANT"
)
// Repository Pattern
val repoPattern = RepositoryPattern(
interfaceReturn = "Flow<DataState<T>>",
implUsesFlow = "= flow { emit(...) }",
loadingEmit = "emit(DataState.Loading)",
successEmit = "emit(DataState.Success(data))",
errorEmit = "emit(DataState.Error(e.message ?: \"Unknown error\"))"
)
// DI Pattern
val diPattern = DiPattern(
serviceDeclaration = "single<Service> { get<Ktorfit>().create<Service>() }",
repoDeclaration = "single<Repository> { RepositoryImp(get()) }"
)
```
---
## PHASE 2: Network Layer
### File Locations
| Component | Location |
|-----------|----------|
| Service Interface | `core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/services/` |
| API Endpoints | `core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/ApiEndPoints.kt` |
| Network DI | `core/network/src/commonMain/kotlin/org/mifos/mobile/core/network/di/NetworkModule.kt` |
### Service Template (Pattern-Matched)
```kotlin
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package org.mifos.mobile.core.network.services
import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.DELETE
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.POST
import de.jensklingenberg.ktorfit.http.PUT
import de.jensklingenberg.ktorfit.http.Path
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.flow.Flow
import org.mifos.mobile.core.network.ApiEndPoints
import org.mifos.mobile.core.network.model.${Dto}
interface ${Feature}Service {
@GET(ApiEndPoints.${ENDPOINT_CONSTANT})
fun get${Feature}List(): Flow<List<${Dto}>>
@GET(ApiEndPoints.${ENDPOINT_CONSTANT} + "/{id}")
fun get${Feature}ById(@Path("id") id: Long): Flow<${Dto}>
@POST(ApiEndPoints.${ENDPOINT_CONSTANT})
suspend fun create${Feature}(@Body payload: ${Payload}): HttpResponse
@PUT(ApiEndPoints.${ENDPOINT_CONSTANT} + "/{id}")
suspend fun update${Feature}(
@Path("id") id: Long,
@Body payload: ${Payload},
): HttpResponse
@DELETE(ApiEndPoints.${ENDPOINT_CONSTANT} + "/{id}")
suspend fun delete${Feature}(@Path("id") id: Long): HttpResponse
}
```
### Add Endpoint Constant (if needed)
```kotlin
// ApiEndPoints.kt
object ApiEndPoints {
// ... existing constants
const val ${ENDPOINT_CONSTANT} = "${endpoint_path}"
}
```
### Register in NetworkModule
```kotlin
// NetworkModule.kt
val networkModule = module {
// ... existing registrations
single<${Feature}Service> { get<Ktorfit>().create<${Feature}Service>() }
}
```
---
## PHASE 3: Data Layer
### File Locations
| Component | Location |
|-----------|----------|
| Repository Interface | `core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/repository/` |
| Repository Impl | `core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/repository/` |
| Data DI | `core/data/src/commonMain/kotlin/org/mifos/mobile/core/data/di/RepositoryModule.kt` |
### Repository Interface Template
```kotlin
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package org.mifos.mobile.core.data.repository
import kotlinx.coroutines.flow.Flow
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.model.${Model}
interface ${Feature}Repository {
fun get${Feature}List(): Flow<DataState<List<${Model}>>>
fun get${Feature}ById(id: Long): Flow<DataState<${Model}>>
suspend fun create${Feature}(data: ${Model}): DataState<Unit>
suspend fun update${Feature}(id: Long, data: ${Model}): DataState<Unit>
suspend fun delete${Feature}(id: Long): DataState<Unit>
}
```
### Repository Implementation Template
```kotlin
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package org.mifos.mobile.core.data.repository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.model.${Model}
import org.mifos.mobile.core.network.services.${Feature}Service
class ${Feature}RepositoryImp(
private val ${feature}Service: ${Feature}Service,
) : ${Feature}Repository {
override fun get${Feature}List(): Flow<DataState<List<${Model}>>> = flow {
emit(DataState.Loading)
try {
val result = ${feature}Service.get${Feature}List().first()
emit(DataState.Success(result))
} catch (e: Exception) {
emit(DataState.Error(e.message ?: "Unknown error"))
}
}
override fun get${Feature}ById(id: Long): Flow<DataState<${Model}>> = flow {
emit(DataState.Loading)
try {
val result = ${feature}Service.get${Feature}ById(id).first()
emit(DataState.Success(result))
} catch (e: Exception) {
emit(DataState.Error(e.message ?: "Unknown error"))
}
}
override suspend fun create${Feature}(data: ${Model}): DataState<Unit> {
return try {
${feature}Service.create${Feature}(data.toPayload())
DataState.Success(Unit)
} catch (e: Exception) {
DataState.Error(e.message ?: "Unknown error")
}
}
override suspend fun update${Feature}(id: Long, data: ${Model}): DataState<Unit> {
return try {
${feature}Service.update${Feature}(id, data.toPayload())
DataState.Success(Unit)
} catch (e: Exception) {
DataState.Error(e.message ?: "Unknown error")
}
}
override suspend fun delete${Feature}(id: Long): DataState<Unit> {
return try {
${feature}Service.delete${Feature}(id)
DataState.Success(Unit)
} catch (e: Exception) {
DataState.Error(e.message ?: "Unknown error")
}
}
}
```
### Register in RepositoryModule
```kotlin
// RepositoryModule.kt
val repositoryModule = module {
// ... existing registrations
single<${Feature}Repository> { ${Feature}RepositoryImp(get()) }
}
```
---
## PHASE 4: Build & Verify
### Build Commands
```bash
# Build network module
./gradlew :core:network:build
# Build data module
./gradlew :core:data:build
# Format code
./gradlew spotlessApply --no-configuration-cache
# Run detekt
./gradlew detekt
```
### Update FEATURE_MAP.md
Add new entry to maintain O(1) lookup:
```markdown
| ${feature} | ${Feature}Service | ${Feature}Repository | ${Notes} |
```
---
## Output Template
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ ✅ CLIENT LAYER COMPLETE │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ 📚 O(1) Context Used: │
│ ├─ FEATURE_MAP.md → Checked existing: [existing services/repos] │
│ ├─ API_INDEX.md → Mapped [n] endpoints │
│ └─ API.md → Feature endpoints: [list] │
│ │
│ 📊 Pattern Matching: │
│ ├─ Service pattern from: BeneficiaryService.kt │
│ └─ Repository pattern from: BeneficiaryRepositoryImp.kt │
│ │
│ 🔧 Network Layer: │
│ ├─ ${Feature}Service.kt [CREATED|SKIPPED] │
│ ├─ ApiEndPoints.${CONSTANT} [ADDED|EXISTS] │
│ └─ NetworkModule registration [ADDED|EXISTS] │
│ │
│ 🔧 Data Layer: │
│ ├─ ${Feature}Repository.kt [CREATED|SKIPPED] │
│ ├─ ${Feature}RepositoryImp.kt [CREATED|SKIPPED] │
│ └─ RepositoryModule registration [ADDED|EXISTS] │
│ │
│ 📋 Index Updated: │
│ └─ FEATURE_MAP.md [UPDATED] │
│ │
│ 🔨 BUILD: │
│ ├─ :core:network ✅ │
│ └─ :core:data ✅ │
│ │
│ 🧹 LINT: spotlessApply ✅ │
│ │
├──────────────────────────────────────────────────────────────────────────────┤
│ NEXT STEP: │
│ Run: /feature ${Feature} │
└──────────────────────────────────────────────────────────────────────────────┘
```
---
## Client Status (No Argument)
When `/client` called without arguments, read FEATURE_MAP.md:
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ 📋 CLIENT LAYER STATUS (from FEATURE_MAP.md) │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Summary: 13 services | 17 repositories | 2 DI modules │
│ │
│ | Feature | Service | Repository | Status │ │
│ |-----------------|-------------------|--------------------|-----------│ │
│ | auth | AuthenticationSvc | UserAuthRepository | ✅ Complete│ │
│ | home | ClientService | HomeRepository | ✅ Complete│ │
│ | accounts | ClientService | AccountsRepository | ✅ Complete│ │
│ | beneficiary | BeneficiaryService| BeneficiaryRepo | ✅ Complete│ │
│ | ... │
│ │
│ Commands: │
│ • /client [feature] → Implement client layer │
│ • /gap-analysis client → Check for gaps │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
---
## Error Handling
### Missing API Endpoint
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ ⚠️ MISSING API ENDPOINT │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Feature: ${feature} │
│ Expected: API.md with endpoint definitions │
│ Found: File missing or empty │
│ │
│ Options: │
│ • d / design → Run /design ${feature} api first │
│ • m / manual → Enter endpoints manually │
│ • a / abort → Cancel implementation │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
### Build Failure
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ ❌ BUILD FAILED: :core:network │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Error: Unresolved reference: ${Dto} │
│ │
│ 📍 Auto-Fix Suggestion: │
│ Create DTO in core/network/model/: │
│ │
│ ```kotlin │
@Serializable
│ data class ${Dto}( │
│ val id: Long, │
│ // ... fields from API.md │
│ ) │
│ ``` │
│ │
│ Options: │
│ • f / fix → Create DTO and rebuild │
│ • m / manual → Show full DTO template │
│ • a / abort → Stop implementation │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
---
## Related Files
### O(1) Index Files
| File | Purpose |
|------|---------|
| `client-layer/FEATURE_MAP.md` | Service/Repository inventory |
| `server-layer/API_INDEX.md` | All API endpoints |
| `client-layer/LAYER_STATUS.md` | Implementation status |
### Reference Code
| Component | Reference File |
|-----------|----------------|
| Service | `BeneficiaryService.kt` |
| Repository | `BeneficiaryRepositoryImp.kt` |
| DI | `NetworkModule.kt`, `RepositoryModule.kt` |
---
## Related Commands
| Command | Purpose |
|---------|---------|
| `/feature [Feature]` | Feature layer (ViewModel + Screen) |
| `/implement [Feature]` | Full E2E (Client + Feature) |
| `/gap-analysis client` | Check client layer gaps |
| `/verify [Feature]` | Verify implementation |

585
.claude/commands/design.md Normal file
View File

@ -0,0 +1,585 @@
# /design - Feature Specification (O(1) Enhanced)
## Purpose
Create or update feature specifications (SPEC.md + API.md) that define what to build and how to build it.
---
## Command Variants
```
/design # Show feature list with status (O(1)
/design [Feature] # Full spec review/create
/design [Feature] add [section] # Add specific section
/design [Feature] improve # Suggest improvements
/design [Feature] mockup # Generate Figma mockups for feature
/design mockup # Generate Figma mockups for all features
```
---
## O(1) Workflow
```
+-------------------------------------------------------------------------+
| /design WORKFLOW (O(1) ENHANCED) |
+-------------------------------------------------------------------------+
| |
| PHASE 0: O(1) CONTEXT LOADING (~300 lines total) |
| +--> Read FEATURES_INDEX.md --> Feature exists? SPEC/API status? |
| +--> Read MOCKUPS_INDEX.md --> Mockup status (4 file types) |
| +--> Read API_INDEX.md --> All endpoints for reference |
| +--> O(1) path: features/[name]/ --> Direct file access |
| |
| PHASE 1: FEATURE STATUS (From Index) |
| +--> Check if feature exists in FEATURES_INDEX |
| +--> Get SPEC/API/STATUS/Mockups status from index |
| +--> Determine: Create new vs Update existing |
| |
| PHASE 2: GATHER CONTEXT (O(1) Paths) |
| +--> Read features/[feature]/SPEC.md (if exists) |
| +--> Read features/[feature]/API.md (if exists) |
| +--> Read features/[feature]/STATUS.md (if exists) |
| +--> Lookup API endpoints from API_INDEX.md |
| |
| PHASE 3: ANALYZE & UPDATE |
| +--> Compare current spec vs requirements |
| +--> Identify gaps, outdated sections |
| +--> Update/create spec files |
| |
| PHASE 4: INDEX UPDATE (Mandatory) |
| +--> Update FEATURES_INDEX.md (if new feature) |
| +--> Update STATUS.md (layer status) |
| +--> Update feature STATUS.md |
| |
+-------------------------------------------------------------------------+
```
---
## Phase 0: O(1) Context Loading
### Index Files to Read
| File | Purpose | Lines |
|------|---------|:-----:|
| `design-spec-layer/FEATURES_INDEX.md` | All features + SPEC/API status | ~120 |
| `design-spec-layer/MOCKUPS_INDEX.md` | Mockup completion matrix | ~150 |
| `server-layer/API_INDEX.md` | All API endpoints | ~400 |
### O(1) Path Pattern
```
features/[name]/SPEC.md # Specification
features/[name]/API.md # API requirements
features/[name]/STATUS.md # Feature status
features/[name]/MOCKUP.md # v2.0 ASCII mockup
features/[name]/mockups/ # Generated mockup files
```
---
## If No Feature Name Provided
Read from FEATURES_INDEX.md and show:
```
+========================================================================+
| DESIGN LAYER - FEATURE STATUS (O(1) Lookup) |
+========================================================================+
| # | Feature | SPEC | API | STATUS | Mockups | Command |
|:-:|---------|:----:|:---:|:------:|:-------:|---------|
| 1 | accounts | [s] | [a] | [st] | [m] | /design accounts |
| 2 | auth | [s] | [a] | [st] | [m] | /design auth |
| ... (all from FEATURES_INDEX.md)
Legend: [s]=SPEC [a]=API [st]=STATUS [m]=Mockups
**Design Progress**: {complete}/{total} features ({percentage}%)
+------------------------------------------------------------------------+
| QUICK ACTIONS |
+------------------------------------------------------------------------+
| Create/Update Spec | /design [feature] |
| Generate Mockups | /design [feature] mockup |
| All Mockups | /design mockup |
| Improve Feature | /design [feature] improve |
+------------------------------------------------------------------------+
```
---
## Mockup Sub-Command (O(1) Enhanced)
### `/design [Feature] mockup`
```
+-------------------------------------------------------------------------+
| /design [Feature] mockup WORKFLOW |
+-------------------------------------------------------------------------+
| |
| PHASE 0: O(1) STATUS CHECK |
| +--> Read MOCKUPS_INDEX.md |
| +--> Check feature row: FIGMA | PROMPTS_FIGMA | PROMPTS_STITCH | tokens|
| +--> Identify: What exists? What's missing? |
| |
| PHASE 1: MCP & TOOL CHECK |
| +--> Check MCP: claude mcp list |
| +--> If stitch-ai configured: Use Google Stitch |
| +--> If figma configured: Use Figma MCP |
| +--> Otherwise: Ask user to select tool |
| |
| PHASE 2: READ MOCKUP.md |
| +--> Read features/[feature]/MOCKUP.md (v2.0 ASCII design) |
| +--> Parse screen layouts, components, colors |
| +--> Identify all screens and UI elements |
| |
| PHASE 3: GENERATE OUTPUTS |
| +--> If missing: Generate PROMPTS_FIGMA.md |
| +--> If missing: Generate PROMPTS_STITCH.md |
| +--> If missing: Generate design-tokens.json |
| +--> Skip files that already exist (from MOCKUPS_INDEX) |
| |
| PHASE 4: INDEX UPDATE |
| +--> Update MOCKUPS_INDEX.md with new status |
| +--> Update FEATURES_INDEX.md Mockups column |
| |
+-------------------------------------------------------------------------+
```
### `/design mockup` (All Features)
Uses O(1) lookup from MOCKUPS_INDEX.md to identify all gaps:
```
+-------------------------------------------------------------------------+
| MOCKUP GENERATION STATUS (from MOCKUPS_INDEX.md) |
+-------------------------------------------------------------------------+
| Feature | FIGMA | PROMPTS_F | PROMPTS_S | Tokens | Status |
|---------|:-----:|:---------:|:---------:|:------:|--------|
| auth | [x] | [x] | [x] | [x] | Complete |
| dashboard | [ ] | [x] | [x] | [x] | Need FIGMA |
| accounts | [ ] | [x] | [x] | [ ] | Need FIGMA, tokens |
| ... (from MOCKUPS_INDEX)
**Summary**:
- Complete: {n} features
- Need FIGMA_LINKS: {n} features
- Need Prompts: {n} features
- Need Tokens: {n} features
**Next Step**: Generate missing files for [first-incomplete-feature]
```
---
## Tool Selection
### Check MCP First
```bash
claude mcp list
```
### AI Design Tools
| Tool | MCP | Best For | Setup |
|------|:---:|----------|-------|
| **Google Stitch** | YES | Material Design 3, Android/KMP | `claude mcp add stitch-ai -- npx -y stitch-ai-mcp` |
| **Figma** | YES | Team collaboration | `claude mcp add figma -- npx -y figma-mcp --token TOKEN` |
| Uizard | NO | Quick prototypes | Manual (web) |
| Visily | NO | Component-focused | Manual (web) |
**Recommended**: Google Stitch (MD3 native, has MCP)
### Tool Selection Prompt (If Not Configured)
```
Select AI Design Tool:
1. Google Stitch (Recommended) - Material Design 3 native
MCP: claude mcp add stitch-ai -- npx -y stitch-ai-mcp
Web: https://stitch.withgoogle.com/
2. Figma + AI - Team collaboration
MCP: claude mcp add figma -- npx -y figma-mcp --token TOKEN
3. Uizard - Quick prototypes (no MCP)
Web: https://uizard.io/
4. Visily - Component-focused (no MCP)
Web: https://www.visily.ai/
Which tool? (1-4, default: 1)
```
---
## Output Files Structure
```
features/[Feature]/mockups/
+-- PROMPTS_FIGMA.md # Figma-specific prompts
+-- PROMPTS_STITCH.md # Google Stitch prompts
+-- design-tokens.json # Structured design tokens
+-- FIGMA_LINKS.md # Figma URLs (user fills after export)
```
---
## PROMPTS_STITCH.md Format
```markdown
# [Feature] - Google Stitch Prompts
> **Generated from**: features/[feature]/MOCKUP.md
> **Generated on**: [DATE]
> **AI Tool**: Google Stitch
## Screen 1: [Screen Name]
### Google Stitch Prompt
Create a mobile [screen type] screen with Material Design 3:
**App Context:**
Mifos Mobile - Self-service banking app for viewing accounts and transactions.
**Screen Size:** 393 x 852 pixels (iPhone 14 Pro equivalent)
**Header Section:**
- [Component details from MOCKUP.md]
**Main Content:**
- [Section details from MOCKUP.md]
**Style Guidelines:**
- Primary Gradient: #667EEA -> #764BA2
- Surface: #FFFBFE
- Typography: Inter font family
- Spacing: 16px standard padding
```
---
## Main Workflow: `/design [Feature]`
```
+-------------------------------------------------------------------------+
| /design [Feature] WORKFLOW |
+-------------------------------------------------------------------------+
| |
| PHASE 0: O(1) CONTEXT LOADING |
| +--> Read FEATURES_INDEX.md --> Feature exists? Status? |
| +--> Read MOCKUPS_INDEX.md --> Mockup status |
| +--> Read API_INDEX.md --> Related endpoints |
| |
| PHASE 1: DETERMINE ACTION |
| +--> If feature NOT in index: Create new feature |
| +--> If SPEC missing: Create SPEC.md |
| +--> If API missing: Create API.md |
| +--> If exists: Update/improve existing |
| |
| PHASE 2: GATHER CONTEXT (O(1) Paths) |
| +--> Read features/[feature]/SPEC.md |
| +--> Read features/[feature]/API.md |
| +--> Read features/[feature]/STATUS.md |
| +--> Lookup endpoints from API_INDEX.md |
| +--> Read actual code: feature/[feature]/ (if exists) |
| |
| PHASE 3: ANALYZE |
| +--> Compare current spec vs implementation |
| +--> Identify gaps, outdated sections |
| +--> Check API availability in API_INDEX |
| +--> Report findings to user |
| |
| PHASE 4: UPDATE FILES |
| +--> Update/create SPEC.md with ASCII mockups |
| +--> Update/create API.md with endpoints |
| +--> Update feature STATUS.md |
| |
| PHASE 5: INDEX UPDATE (Mandatory) |
| +--> Update FEATURES_INDEX.md (status columns) |
| +--> Update design-spec-layer/STATUS.md |
| |
| PHASE 6: OUTPUT SUMMARY |
| +--> Implementation requirements |
| +--> Next command suggestion |
| |
+-------------------------------------------------------------------------+
```
---
## SPEC.md Template
```markdown
# [Feature Name] - Feature Specification
> **Purpose**: [One-line description]
> **User Value**: [Why users need this]
> **Last Updated**: [Date]
---
## 1. Overview
### 1.1 Feature Summary
[2-3 sentences describing the feature]
### 1.2 User Stories
- As a user, I want to [action] so that [benefit]
---
## 2. Screen Layout
### 2.1 ASCII Mockup
+-------------------------------------------+
| <- Back [Title] : | <- TopBar
+-------------------------------------------+
| |
| +-----------------------------------+ |
| | Section 1 | |
| +-----------------------------------+ |
| |
+-------------------------------------------+
### 2.2 Sections Table
| # | Section | Description | API | Priority |
|---|---------|-------------|-----|----------|
| 1 | [Name] | [What it shows] | [Endpoint] | P0 |
---
## 3. User Interactions
| Action | Trigger | Result | API Call |
|--------|---------|--------|----------|
| Tap item | Click | Navigate | - |
| Pull refresh | Swipe down | Reload data | [Endpoint] |
---
## 4. State Model
@Immutable
data class [Feature]State(
val isLoading: Boolean = false,
val data: List<Item> = emptyList(),
val error: String? = null,
)
sealed interface [Feature]ScreenState {
data object Loading : [Feature]ScreenState
data object Success : [Feature]ScreenState
data class Error(val message: StringResource) : [Feature]ScreenState
}
---
## 5. API Requirements
| Endpoint | Method | Purpose | Status |
|----------|--------|---------|--------|
| /self/[path] | GET | [Description] | Exists |
---
## 6. Edge Cases & Error Handling
| Scenario | Behavior | UI Feedback |
|----------|----------|-------------|
| No internet | Show cached | Toast |
| Empty results | Show empty state | Illustration |
| API error | Retry logic | Snackbar |
---
## Changelog
| Date | Change |
|------|--------|
| [date] | Initial spec |
```
---
## API.md Template
```markdown
# [Feature Name] - API Reference
## Endpoints Required
### [Endpoint Name]
**Endpoint**: `GET /self/[path]`
**Description**: [What this endpoint does]
**Request**:
Headers:
Authorization: Basic {token}
Fineract-Platform-TenantId: {tenant}
**Response**:
{
"field": "value"
}
**Kotlin DTO**:
@Serializable
data class [Name]Dto(
@SerialName("field") val field: String,
)
**Status**: Implemented / Missing
---
## API Summary
| Endpoint | Service | Repository | Status |
|----------|---------|------------|--------|
| /self/[path] | [Name]Service | [Name]Repository | Done |
```
---
## Output Template
After completing design, output:
```
+=========================================================================+
| IMPLEMENTATION REQUIREMENTS |
| Ready for /implement in Sonnet session |
+=========================================================================+
| |
| FEATURE: [Feature Name] |
| SPEC UPDATED: features/[feature]/SPEC.md |
| |
| ================================================================ |
| |
| CLIENT WORK NEEDED: |
| [ ] Network: [DTO/Service changes] |
| [ ] Data: [Repository changes] |
| |
| FEATURE WORK NEEDED: |
| [ ] ViewModel: [changes] |
| [ ] Screen: [changes] |
| [ ] Components: [new components] |
| |
| ================================================================ |
| |
| INDEXES UPDATED: |
| [x] FEATURES_INDEX.md - Status updated |
| [x] design-spec-layer/STATUS.md - Layer status |
| [x] features/[feature]/STATUS.md - Feature status |
| |
| ================================================================ |
| |
| NEXT STEP: |
| Run: /implement [Feature] |
| |
+=========================================================================+
```
---
## Feature Reference (From FEATURES_INDEX.md)
| # | Feature | Design Dir | Feature Dir |
|:-:|---------|------------|-------------|
| 1 | accounts | features/accounts/ | feature/account/ |
| 2 | auth | features/auth/ | feature/auth/ |
| 3 | beneficiary | features/beneficiary/ | feature/beneficiary/ |
| 4 | client-charge | features/client-charge/ | feature/user-profile/ |
| 5 | dashboard | features/dashboard/ | feature/dashboard/ |
| 6 | guarantor | features/guarantor/ | feature/guarantor/ |
| 7 | home | features/home/ | feature/home/ |
| 8 | loan-account | features/loan-account/ | feature/loan-account/ |
| 9 | location | features/location/ | feature/location/ |
| 10 | notification | features/notification/ | feature/notification/ |
| 11 | passcode | features/passcode/ | libs/mifos-passcode/ |
| 12 | qr | features/qr/ | feature/qr-code/ |
| 13 | recent-transaction | features/recent-transaction/ | feature/recent-transaction/ |
| 14 | savings-account | features/savings-account/ | feature/savings-account/ |
| 15 | settings | features/settings/ | feature/settings/ |
| 16 | share-account | features/share-account/ | feature/share-account/ |
| 17 | transfer | features/transfer/ | feature/transfer-process/ |
---
## Error Handling
### Feature Not Found
```
+-------------------------------------------------------------------------+
| ERROR: Feature '[name]' not found |
+-------------------------------------------------------------------------+
| |
| The feature '[name]' does not exist in FEATURES_INDEX.md |
| |
| OPTIONS: |
| 1. Create new feature: /design [name] |
| 2. Check available features: /design |
| 3. Similar features: [suggestions based on name] |
| |
+-------------------------------------------------------------------------+
```
### Invalid Sub-command
```
+-------------------------------------------------------------------------+
| ERROR: Invalid sub-command '[sub]' |
+-------------------------------------------------------------------------+
| |
| Valid sub-commands: |
| - mockup : Generate mockup prompts |
| - improve : Suggest improvements |
| - add [x] : Add specific section |
| |
+-------------------------------------------------------------------------+
```
---
## Model Recommendation
**This command is optimized for Opus** for complex architectural decisions and comprehensive specification writing.
---
## Related Commands
| Command | Purpose |
|---------|---------|
| `/gap-analysis design` | See design layer gaps |
| `/gap-analysis design mockup` | See mockup gaps specifically |
| `/implement [feature]` | Implement the designed feature |
| `/verify [feature]` | Verify implementation vs spec |
---
## Key Files
```
claude-product-cycle/design-spec-layer/
+-- FEATURES_INDEX.md # O(1) feature lookup
+-- MOCKUPS_INDEX.md # O(1) mockup status
+-- STATUS.md # Layer status
+-- features/[feature]/
+-- SPEC.md # What to build (UI, flows)
+-- API.md # APIs needed
+-- STATUS.md # Feature implementation status
+-- MOCKUP.md # v2.0 ASCII mockup
+-- mockups/ # Generated mockup files
```

1115
.claude/commands/feature.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,328 @@
# Gap Analysis Command
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 # 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)
```
## Comprehensive Output (No Parameters)
When `/gap-analysis` is called without parameters, show the **FULL comprehensive view**:
```
╔══════════════════════════════════════════════════════════════════════════════╗
║ 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]`
╚══════════════════════════════════════════════════════════════════════════════╝
```
---
## 5-Layer Lifecycle
```
┌─────────────────────────────────────────────────────────────────┐
│ 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: Read O(1) Index Files
Read these files for instant status (DO NOT scan directories):
| 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: Calculate Progress
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: Identify Gaps
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: Generate Output
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
---
## 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
| # | Feature | Design Dir | Feature Dir |
|:-:|---------|------------|-------------|
| 1 | auth | features/auth/ | feature/auth/ |
| 2 | home | features/home/ | feature/home/ |
| 3 | accounts | features/accounts/ | feature/account/ |
| 4 | savings-account | features/savings-account/ | feature/savings-account/ |
| 5 | loan-account | features/loan-account/ | feature/loan-account/ |
| 6 | share-account | features/share-account/ | feature/share-account/ |
| 7 | beneficiary | features/beneficiary/ | feature/beneficiary/ |
| 8 | transfer | features/transfer/ | feature/transfer-process/ |
| 9 | recent-transaction | features/recent-transaction/ | feature/recent-transaction/ |
| 10 | notification | features/notification/ | feature/notification/ |
| 11 | settings | features/settings/ | feature/settings/ |
| 12 | passcode | features/passcode/ | libs/mifos-passcode/ |
| 13 | guarantor | features/guarantor/ | feature/guarantor/ |
| 14 | qr | features/qr/ | feature/qr-code/ |
| 15 | location | features/location/ | feature/location/ |
| 16 | client-charge | features/client-charge/ | feature/user-profile/ |
| 17 | dashboard | features/dashboard/ | feature/dashboard/ |
---
## Output Rules
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

View File

@ -0,0 +1,502 @@
# Gap Planning Command
Creates step-by-step implementation plans for identified gaps. Runs on O(1) by reading index files.
## Usage
```
/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 all feature layer work
/gap-planning feature [name] # Plan specific feature
/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)
```
---
## Comprehensive Output (No Parameters)
When `/gap-planning` is called without parameters, show **ALL gaps with ALL implementation plans**:
```
╔══════════════════════════════════════════════════════════════════════════════╗
║ MIFOS MOBILE - GAP PLANNING (O(1) Lookup) ║
║ All Gaps → All Plans → You Choose ║
╠══════════════════════════════════════════════════════════════════════════════╣
## Current Gaps Overview
| 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.
```
### P2 - Nice to Have (Polish)
| # | Gap | Plan Command | Tasks | Effort |
|:-:|-----|--------------|:-----:|:------:|
| 1 | Web experimental | `/gap-planning platform web` | 5 | M |
**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
Run `/gap-planning platform web` for step-by-step tasks.
```
### 🧪 Testing (Embedded in Layers)
| # | 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 |
**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
```
→ Run `/gap-planning testing [feature]` for per-feature test plan.
---
## 🎯 QUICK START
Pick a plan based on priority:
| Priority | Recommendation | Command |
|:--------:|----------------|---------|
| **P1** | Start with mockups | `/gap-planning design mockup` |
| **P2** | Then web platform | `/gap-planning platform web` |
Or jump directly to implementation:
| Target | Command |
|--------|---------|
| Single feature mockup | `/design [feature-name]` |
| Feature implementation | `/implement [feature-name]` |
| Verify existing | `/verify [feature-name]` |
---
## 🔄 WORKFLOW
```
/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, mockups |
| P2 | Polish - nice to have | Animations, web fixes |
## Effort Guidelines
| 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 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
8. **Save plan to file** - Persist for tracking (see below)
---
## Plan Persistence
When creating a detailed plan (with parameters), **save it to a file** for tracking:
### Save Location
```
claude-product-cycle/plans/active/[target]-[type].md
```
Examples:
- `/gap-planning design mockup``plans/active/design-mockup.md`
- `/gap-planning testing auth``plans/active/testing-auth.md`
- `/gap-planning feature beneficiary``plans/active/feature-beneficiary.md`
- `/gap-planning platform web``plans/active/platform-web.md`
### Plan File Format
```markdown
# Plan: [Target Description]
**Created**: YYYY-MM-DD
**Status**: 🔄 Active
**Command**: /gap-planning [args]
**Progress**: 0/N steps (0%)
---
## Overview
[Brief description of what this plan accomplishes]
---
## Steps
- [ ] **Step 1**: [Description]
- Sub-task 1
- Sub-task 2
- Command: `[execution command]`
- Files: `path/to/expected/files`
- [ ] **Step 2**: [Description]
- Sub-task 1
- Command: `[execution command]`
[... more steps ...]
---
## Verification
- [ ] All expected files exist
- [ ] Tests pass (if applicable)
- [ ] Index files updated
---
## Progress Log
| Date | Step | Action | Notes |
|------|:----:|--------|-------|
| YYYY-MM-DD | 0 | Created | Plan initialized |
```
### Update PLANS_INDEX.md
After creating a plan file, also update `plans/PLANS_INDEX.md`:
```markdown
## Active Plans
| # | Plan | Target | Progress | Current Step | Created |
|:-:|------|--------|:--------:|--------------|---------|
| 1 | design-mockup | Design mockups | [░░░░░░░░░░] 0% (0/10) | Step 1 | 2026-01-05 |
```
### Check Progress
After plan is saved, show:
```
✅ Plan saved to: plans/active/[name].md
Track progress with: /gap-status [name]
```
---
## Plan Completion Triggers
After creating a plan, **TRIGGER user prompts** using the Prompt Layer.
### After Plan Created
**TRIGGER**: `plan-ready`
**Reference**: `prompt-layer/PROMPTS.md``plan-ready`
**Context Variables**: `{FEATURE}`, `{TOTAL_TASKS}`
**Route User Selection**:
| Selection | Action |
|-----------|--------|
| Start implementation | Execute first step of plan |
| Review plan | Show detailed task breakdown |
| Modify plan | Allow user to adjust tasks |
| Save for later | End without executing |
### After Layer Plan Created
**TRIGGER**: `plan-layer`
**Reference**: `prompt-layer/PROMPTS.md``plan-layer`
**Context Variables**: `{LAYER}`, `{TOTAL_TASKS}`
**Route User Selection**:
| Selection | Action |
|-----------|--------|
| Execute plan | Start implementing the layer |
| View tasks | Show detailed task list |
| Plan next layer | Continue planning |
| Stop here | Save plan, implement later |
### During Plan Execution
When executing a plan step-by-step:
**After Each Step:**
**TRIGGER**: `task-completion`
**Reference**: `prompt-layer/PROMPTS.md``task-completion`
**After All Steps Complete:**
**TRIGGER**: `task-completion:all`
**Reference**: `prompt-layer/PROMPTS.md``task-completion:all`
**On Build Success:**
**TRIGGER**: `build-success`
**Reference**: `prompt-layer/PROMPTS.md``build-success`
**On Build Failure:**
**TRIGGER**: `build-failure`
**Reference**: `prompt-layer/PROMPTS.md``build-failure`
---
## Related Commands
| Command | Purpose |
|---------|---------|
| `/gap-analysis` | Identify gaps (run first) |
| `/gap-planning` | Create implementation plans (this command) |
| `/gap-status` | Track plan progress |
| `/implement` | Execute implementation |
| `/verify` | Confirm completion |

View File

@ -0,0 +1,433 @@
# /gap-status - Plan Progress Tracking
## Purpose
Track progress on implementation plans created by `/gap-planning`. Shows current step, completed steps, and what's next.
---
## Usage
```
/gap-status # Show all active plans summary
/gap-status [plan-name] # Show detailed progress for plan
/gap-status design # Show design layer plans
/gap-status testing # Show testing layer plans
/gap-status feature [name] # Show feature-specific plan
/gap-status complete [plan] # Mark plan as complete
/gap-status pause [plan] # Pause a plan
/gap-status resume [plan] # Resume a paused plan
```
---
## Workflow
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ /gap-status WORKFLOW │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ PHASE 0: O(1) CONTEXT LOADING │
│ ├─→ Read plans/PLANS_INDEX.md → Get all plans overview │
│ ├─→ Read plans/active/*.md → Get active plan details │
│ └─→ Count completed steps → Calculate progress │
│ │
│ PHASE 1: DETERMINE OUTPUT │
│ ├─→ If no args: Show all active plans summary │
│ ├─→ If [plan-name]: Show detailed plan progress │
│ └─→ If action (complete/pause/resume): Update plan status │
│ │
│ PHASE 2: GENERATE REPORT │
│ ├─→ Progress bars for each plan │
│ ├─→ Current step highlight │
│ ├─→ Next steps preview │
│ └─→ Suggested commands │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## Output: All Plans Summary (No Args)
```
╔══════════════════════════════════════════════════════════════════════════════╗
║ MIFOS MOBILE - PLAN STATUS ║
╠══════════════════════════════════════════════════════════════════════════════╣
## 🔄 Active Plans
| # | Plan | Progress | Current Step | Last Updated |
|:-:|------|:--------:|--------------|--------------|
| 1 | design-mockup | [████████░░] 80% (8/10) | Step 9: transfer mockups | 2026-01-05 |
| 2 | testing-auth | [████░░░░░░] 40% (4/10) | Step 5: LoginViewModel tests | 2026-01-05 |
| 3 | feature-dashboard | [██░░░░░░░░] 20% (2/10) | Step 3: Create DashboardViewModel | 2026-01-04 |
## ⏸️ Paused Plans
| # | Plan | Progress | Paused At | Reason |
|:-:|------|:--------:|-----------|--------|
| - | (none) | - | - | - |
## ✅ Recently Completed
| # | Plan | Steps | Completed |
|:-:|------|:-----:|-----------|
| 1 | client-layer | 12/12 | 2026-01-03 |
---
## Commands
| Action | Command |
|--------|---------|
| View plan details | `/gap-status [plan-name]` |
| Continue implementation | `/implement [target]` |
| Mark complete | `/gap-status complete [plan]` |
| Create new plan | `/gap-planning [target]` |
╚══════════════════════════════════════════════════════════════════════════════╝
```
---
## Output: Specific Plan (With Args)
```
╔══════════════════════════════════════════════════════════════════════════════╗
║ PLAN: design-mockup ║
╠══════════════════════════════════════════════════════════════════════════════╣
**Status**: 🔄 Active
**Progress**: [████████░░] 80% (8/10 steps)
**Created**: 2026-01-03
**Last Updated**: 2026-01-05
---
## Steps
| # | Step | Status | Description |
|:-:|------|:------:|-------------|
| 1 | ✅ | Done | Generate auth mockups |
| 2 | ✅ | Done | Generate home mockups |
| 3 | ✅ | Done | Generate accounts mockups |
| 4 | ✅ | Done | Generate beneficiary mockups |
| 5 | ✅ | Done | Generate loan-account mockups |
| 6 | ✅ | Done | Generate savings-account mockups |
| 7 | ✅ | Done | Generate share-account mockups |
| 8 | ✅ | Done | Generate notification mockups |
| 9 | 🔄 | **Current** | Generate transfer mockups |
| 10 | ⬜ | Pending | Generate recent-transaction mockups |
---
## Current Step Details
### Step 9: Generate transfer mockups
**Target**: `design-spec-layer/features/transfer/mockups/`
**Tasks**:
- [ ] Run `/design transfer mockup`
- [ ] Review generated PROMPTS.md
- [ ] Execute prompts in Google Stitch
- [ ] Save design-tokens.json
- [ ] Update MOCKUPS_INDEX.md
**Expected Files**:
```
features/transfer/mockups/
├── PROMPTS.md
├── PROMPTS_FIGMA.md (if MCP)
├── design-tokens.json
└── screenshots/ (optional)
```
---
## Next Step Preview
### Step 10: Generate recent-transaction mockups
**Target**: `design-spec-layer/features/recent-transaction/mockups/`
Same process as Step 9 but for recent-transaction feature.
---
## Progress Log
| Date | Step | Action |
|------|:----:|--------|
| 2026-01-05 | 8 | Completed notification mockups |
| 2026-01-05 | 9 | Started transfer mockups |
| 2026-01-04 | 5-7 | Completed account mockups |
| 2026-01-03 | 1-4 | Initial mockups complete |
---
## Commands
| Action | Command |
|--------|---------|
| Execute current step | `/design transfer mockup` |
| Mark step complete | Update plan file, re-run `/gap-status` |
| Pause plan | `/gap-status pause design-mockup` |
| Mark plan complete | `/gap-status complete design-mockup` |
╚══════════════════════════════════════════════════════════════════════════════╝
```
---
## Phase 0: O(1) Context Loading
### Files to Read
| File | Purpose | Data Extracted |
|------|---------|----------------|
| `plans/PLANS_INDEX.md` | Plan inventory | activePlans[], completedPlans[] |
| `plans/active/[plan].md` | Plan details | steps[], currentStep, progress |
---
## Plan File Structure
When `/gap-planning` creates a plan, it saves to `plans/active/[name].md`:
```markdown
# Plan: Design Layer - Mockups
**Created**: 2026-01-03
**Status**: 🔄 Active
**Command**: /gap-planning design mockup
**Progress**: 8/10 steps (80%)
---
## Overview
Generate mockups for all features missing UI designs.
---
## Steps
- [x] **Step 1**: Generate auth mockups
- Run `/design auth mockup`
- Files: `features/auth/mockups/`
- Completed: 2026-01-03
- [x] **Step 2**: Generate home mockups
- Run `/design home mockup`
- Files: `features/home/mockups/`
- Completed: 2026-01-04
- [ ] **Step 9**: Generate transfer mockups ← CURRENT
- Run `/design transfer mockup`
- Files: `features/transfer/mockups/`
- [ ] **Step 10**: Generate recent-transaction mockups
- Run `/design recent-transaction mockup`
- Files: `features/recent-transaction/mockups/`
---
## Progress Log
| Date | Step | Action | Notes |
|------|:----:|--------|-------|
| 2026-01-05 | 8 | ✅ Completed | notification mockups done |
| 2026-01-05 | 9 | 🔄 Started | transfer in progress |
```
---
## Step Status Icons
| Icon | Status | Meaning |
|:----:|--------|---------|
| ✅ | Done | Step completed |
| 🔄 | Current | Currently working on |
| ⬜ | Pending | Not started |
| ⏸️ | Blocked | Waiting on dependency |
| ❌ | Failed | Step failed, needs retry |
---
## Instructions
### When `/gap-status` is called (no args):
1. Read `plans/PLANS_INDEX.md`
2. For each active plan, read `plans/active/[plan].md`
3. Count `[x]` vs `[ ]` checkboxes to calculate progress
4. Display summary table with progress bars
### When `/gap-status [plan]` is called:
1. Read `plans/active/[plan].md`
2. Find current step (first `[ ]` after last `[x]`)
3. Display detailed view with:
- All steps with status
- Current step details
- Next step preview
- Progress log
### When `/gap-status complete [plan]` is called:
1. Read `plans/active/[plan].md`
2. Update status to "✅ Completed"
3. Move file to `plans/completed/[plan].md`
4. Update `plans/PLANS_INDEX.md`
---
## Integration with Other Commands
| When This Runs | Update Plan |
|----------------|-------------|
| `/gap-planning [target]` | Create new plan file |
| `/implement` checkpoint | Update related plan step |
| `/design [feature] mockup` | Update mockup plan step |
| `/verify [feature]` | Update verification plan |
---
## Progress Bar Reference
```
100% = [██████████] | 50% = [█████░░░░░]
90% = [█████████░] | 40% = [████░░░░░░]
80% = [████████░░] | 30% = [███░░░░░░░]
70% = [███████░░░] | 20% = [██░░░░░░░░]
60% = [██████░░░░] | 10% = [█░░░░░░░░░]
```
---
## Example: Creating and Tracking a Plan
```bash
# 1. Create plan
/gap-planning design mockup
# → Creates plans/active/design-mockup.md with 10 steps
# 2. Check status
/gap-status
# → Shows design-mockup at 0% (0/10)
# 3. Work on step 1
/design auth mockup
# → Completes auth mockups
# 4. Update plan (manual or via command)
# Edit plans/active/design-mockup.md, mark step 1 as [x]
# 5. Check status again
/gap-status design-mockup
# → Shows 10% (1/10), current step is now step 2
# 6. Continue until done
# ...
# 7. Mark complete
/gap-status complete design-mockup
# → Moves to plans/completed/
```
---
## Plan Progress Triggers
After showing plan status, **TRIGGER user prompts** using the Prompt Layer.
### After Showing Active Plan
When showing a specific plan with pending steps, prompt user:
**TRIGGER**: `plan-continue`
**Reference**: `prompt-layer/PROMPTS.md``plan-continue`
**Context Variables**: `{PLAN_NAME}`, `{CURRENT_STEP}`, `{PROGRESS}`
```json
{
"questions": [
{
"question": "Plan {PLAN_NAME} is {PROGRESS}% complete. Current step: {CURRENT_STEP}. What would you like to do?",
"header": "Plan",
"options": [
{
"label": "Execute current step (Recommended)",
"description": "Run the command for current step"
},
{
"label": "Skip to specific step",
"description": "Choose a different step to work on"
},
{
"label": "Mark step complete",
"description": "I've completed this step manually"
},
{
"label": "Pause plan",
"description": "Stop working on this plan for now"
}
],
"multiSelect": false
}
]
}
```
**Route User Selection**:
| Selection | Action |
|-----------|--------|
| Execute current step | Run the step's command (e.g., `/design transfer mockup`) |
| Skip to specific step | Show step list, let user choose |
| Mark step complete | Update plan file, show next step |
| Pause plan | Set plan status to paused |
### After Step Execution
When a step is completed (via any command that updates the plan):
**TRIGGER**: `task-completion`
**Reference**: `prompt-layer/PROMPTS.md``task-completion`
**Context Variables**: `{TASK_NUMBER}`, `{TASK_NAME}`, `{NEXT_TASK_NUMBER}`, `{NEXT_TASK_DESCRIPTION}`
**Route User Selection**:
| Selection | Action |
|-----------|--------|
| Continue to next step | Execute next step's command |
| Review this step | Show files created/modified |
| Commit progress | **TRIGGER**: `commit` |
| Stop here | Update plan, end session |
### After All Steps Complete
When the last step is completed:
**TRIGGER**: `task-completion:all`
**Reference**: `prompt-layer/PROMPTS.md``task-completion:all`
**Context Variables**: `{PLAN_NAME}`, `{TOTAL_TASKS}`
**Route User Selection**:
| Selection | Action |
|-----------|--------|
| Mark plan complete | Move to completed, update index |
| Run verification | `/verify` relevant targets |
| Commit all changes | **TRIGGER**: `commit` |
| Review changes | Show all files created during plan |
### After Marking Plan Complete
**TRIGGER**: `commit`
**Reference**: `prompt-layer/PROMPTS.md``commit`
Then:
**TRIGGER**: `commit-post`
**Reference**: `prompt-layer/PROMPTS.md``commit-post`

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,207 @@
# /project-add - Add New Project (Interactive)
Create a new project workspace with the 5-layer structure.
## Usage
```
/project-add # Interactive project creation
/project-add "project-name" # Create with specified name
```
## Instructions
### Step 1: Gather Project Info
If no name provided, ask:
```markdown
## New Project Setup
Please provide:
1. **Project Name** (lowercase, hyphenated): e.g., `my-app`, `fineract-client`
2. **Project Type**: Android | iOS | KMP | Web
3. **Description**: Brief project description
```
### Step 2: Create Workspace Structure
```bash
# Create workspace directory
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}
# Create 6 layer directories
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}/design-spec-layer/features
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}/server-layer/endpoints
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}/client-layer
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}/feature-layer
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}/platform-layer
mkdir -p claude-product-cycle/workspaces/{{PROJECT_NAME}}/testing-layer
```
### Step 3: Create PROJECT.md
Create `workspaces/{{PROJECT_NAME}}/PROJECT.md`:
```markdown
# {{PROJECT_NAME}}
**Type**: {{PROJECT_TYPE}}
**Created**: {{DATE}}
**Description**: {{DESCRIPTION}}
---
## Quick Start
```bash
/project-set {{PROJECT_NAME}} # Activate this project
/gap-analysis # Check status
/design [feature] # Start designing
```
---
## Structure
```
workspaces/{{PROJECT_NAME}}/
├── PROJECT.md # This file
├── design-spec-layer/ # Feature specifications
│ └── features/ # Per-feature specs
├── server-layer/ # API documentation
│ └── endpoints/ # Per-endpoint docs
├── client-layer/ # Network/data layer tracking
├── feature-layer/ # UI layer tracking
├── platform-layer/ # Platform-specific tracking
└── testing-layer/ # Test tracking
```
---
## Status
| Layer | Progress | Next Action |
|-------|:--------:|-------------|
| Design | 0% | `/design [feature]` |
| Server | 0% | Document APIs |
| Client | 0% | `/client [feature]` |
| Feature | 0% | `/feature [feature]` |
| Platform | 0% | Platform setup |
```
### Step 4: Create Layer Index Files
**design-spec-layer/STATUS.md**:
```markdown
# Design Layer Status
**Project**: {{PROJECT_NAME}}
**Last Updated**: {{DATE}}
## Features
| Feature | SPEC | MOCKUP | API | STATUS | Complete |
|---------|:----:|:------:|:---:|:------:|:--------:|
| (none yet) | - | - | - | - | - |
---
**Next**: Run `/design [feature]` to add first feature
```
**client-layer/LAYER_STATUS.md**:
```markdown
# Client Layer Status
**Project**: {{PROJECT_NAME}}
**Last Updated**: {{DATE}}
## Services
| Service | Repository | Models | DI | Complete |
|---------|:----------:|:------:|:--:|:--------:|
| (none yet) | - | - | - | - |
```
**feature-layer/LAYER_STATUS.md**:
```markdown
# Feature Layer Status
**Project**: {{PROJECT_NAME}}
**Last Updated**: {{DATE}}
## Features
| Feature | ViewModel | Screen | Navigation | DI | Complete |
|---------|:---------:|:------:|:----------:|:--:|:--------:|
| (none yet) | - | - | - | - | - |
```
### Step 5: Optionally Set Active
Ask user:
```markdown
## Project Created
**Name**: {{PROJECT_NAME}}
**Location**: `workspaces/{{PROJECT_NAME}}/`
Would you like to set this as the active project?
1. **Yes** - Set active and start working
2. **No** - Keep current project active
```
If yes:
```bash
echo "{{PROJECT_NAME}}" > claude-product-cycle/ACTIVE_PROJECT
```
### Step 6: Show Completion
```markdown
## Project Created Successfully
**Project**: {{PROJECT_NAME}}
**Workspace**: `workspaces/{{PROJECT_NAME}}/`
**Active**: {{IS_ACTIVE}}
---
### Structure Created
```
workspaces/{{PROJECT_NAME}}/
├── PROJECT.md ✅
├── design-spec-layer/ ✅
│ ├── STATUS.md ✅
│ └── features/ ✅
├── server-layer/ ✅
│ └── endpoints/ ✅
├── client-layer/ ✅
│ └── LAYER_STATUS.md ✅
├── feature-layer/ ✅
│ └── LAYER_STATUS.md ✅
├── platform-layer/ ✅
└── testing-layer/ ✅
```
---
### Next Steps
1. `/project-set {{PROJECT_NAME}}` - Activate (if not active)
2. `/design [feature]` - Create first feature spec
3. `/gap-analysis` - View project status
---
**Ready to build!**
```
## Output Rules
1. Create complete workspace structure
2. Initialize all index/status files
3. Ask before setting as active
4. Show clear next steps

View File

@ -0,0 +1,48 @@
# /project-list - List All Projects
List all available projects in the multi-project workspace.
## Usage
```
/project-list # List all projects
```
## Instructions
### Step 1: Read Workspaces
```bash
ls claude-product-cycle/workspaces/
```
### Step 2: Get Active Project
```bash
cat claude-product-cycle/ACTIVE_PROJECT
```
### Step 3: Display Project List
```markdown
## Available Projects
| # | Project | Status | Path |
|:-:|---------|:------:|------|
{{PROJECT_ROWS}}
**Active**: {{ACTIVE_PROJECT}}
---
### Commands
- `/project-set [name]` - Switch to a project
- `/project-add` - Add new project
```
## Output Rules
1. List all directories in workspaces/
2. Mark active project with arrow (→)
3. Show path to each workspace

View File

@ -0,0 +1,67 @@
# /project-set - Set Active Project
Switch the active project for all commands.
## Usage
```
/project-set mifos-mobile # Switch to mifos-mobile project
/project-set test-project # Switch to test-project
```
## Instructions
### Step 1: Validate Project Exists
```bash
ls claude-product-cycle/workspaces/{{PROJECT_NAME}}/
```
If directory doesn't exist, show error:
```markdown
## Error: Project Not Found
Project `{{PROJECT_NAME}}` does not exist.
**Available projects**:
{{PROJECT_LIST}}
Run `/project-add` to create a new project.
```
### Step 2: Update ACTIVE_PROJECT
```bash
echo "{{PROJECT_NAME}}" > claude-product-cycle/ACTIVE_PROJECT
```
### Step 3: Confirm Switch
```markdown
## Project Switched
**Active Project**: {{PROJECT_NAME}}
**Workspace**: `workspaces/{{PROJECT_NAME}}/`
---
### Project Summary
| Layer | Status |
|-------|:------:|
| Design | {{DESIGN_STATUS}} |
| Server | {{SERVER_STATUS}} |
| Client | {{CLIENT_STATUS}} |
| Feature | {{FEATURE_STATUS}} |
| Platform | {{PLATFORM_STATUS}} |
---
**Next**: Run `/gap-analysis` to see current status
```
## Output Rules
1. Validate project exists before switching
2. Update ACTIVE_PROJECT file
3. Show project summary after switch

View File

@ -0,0 +1,115 @@
# /projectstatus - Project Overview
## Purpose
Display the current state of the Mifos Mobile project, including feature implementation status, available commands, and suggested next steps.
---
## Workflow
```
┌───────────────────────────────────────────────────────────────────┐
│ /projectstatus WORKFLOW │
├───────────────────────────────────────────────────────────────────┤
│ │
│ STEP 1: READ STATUS FILES │
│ ├─→ claude-product-cycle/design-spec-layer/STATUS.md │
│ └─→ Individual feature STATUS.md files │
│ │
│ STEP 2: ANALYZE CODEBASE │
│ ├─→ Check feature/ directory for implemented features │
│ ├─→ Check core/network/services/ for API services │
│ ├─→ Check core/data/repository/ for repositories │
│ └─→ Compare spec vs implementation │
│ │
│ STEP 3: GENERATE DASHBOARD │
│ ├─→ Feature status table │
│ ├─→ Layer completion summary │
│ ├─→ Available commands │
│ └─→ Suggested next steps │
│ │
└───────────────────────────────────────────────────────────────────┘
```
---
## Output Template
```
╔══════════════════════════════════════════════════════════════════════╗
║ MIFOS MOBILE - PROJECT STATUS ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ PROJECT: Mifos Mobile (Self-Service Banking App) ║
║ TECH STACK: Kotlin Multiplatform + Compose + Fineract API ║
║ LAST UPDATED: [Date] ║
║ ║
╠══════════════════════════════════════════════════════════════════════╣
║ FEATURE STATUS ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ | Feature | Status | Client | Feature | Gaps | ║
║ |-------------------|------------|--------|---------|------| ║
║ | Auth | ✅ Done | ✅ | ✅ | 0 | ║
║ | Home | ✅ Done | ✅ | ✅ | 0 | ║
║ | Accounts | ✅ Done | ✅ | ✅ | 0 | ║
║ | Loan Account | ✅ Done | ✅ | ✅ | 0 | ║
║ | Savings Account | ✅ Done | ✅ | ✅ | 0 | ║
║ | Share Account | ✅ Done | ✅ | ✅ | 0 | ║
║ | Beneficiary | ✅ Done | ✅ | ✅ | 0 | ║
║ | Transfer | ✅ Done | ✅ | ✅ | 0 | ║
║ | Recent Transaction| ✅ Done | ✅ | ✅ | 0 | ║
║ | Notification | ✅ Done | ✅ | ✅ | 0 | ║
║ | Settings | ✅ Done | ✅ | ✅ | 0 | ║
║ | Passcode | ✅ Done | - | ✅ | 0 | ║
║ | Guarantor | ✅ Done | ✅ | ✅ | 0 | ║
║ | QR Code | ✅ Done | - | ✅ | 0 | ║
║ | Location | ✅ Done | - | ✅ | 0 | ║
║ | Client Charges | ✅ Done | ✅ | ✅ | 0 | ║
║ ║
╠══════════════════════════════════════════════════════════════════════╣
║ AVAILABLE COMMANDS ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ Design: ║
║ /design [Feature] → Create/update feature specification ║
║ ║
║ Implement: ║
║ /implement [Feature] → Full E2E implementation ║
║ /client [Feature] → Network + Data layers ║
║ /feature [Feature] → UI layer (ViewModel + Screen) ║
║ ║
║ Verify: ║
║ /verify [Feature] → Validate implementation vs spec ║
║ ║
╠══════════════════════════════════════════════════════════════════════╣
║ SUGGESTED NEXT STEPS ║
╠══════════════════════════════════════════════════════════════════════╣
║ ║
║ 1. Review existing features: /verify [Feature] ║
║ 2. Improve feature: /design [Feature] for enhancements ║
║ 3. Add new feature: /design [NewFeature] ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝
```
---
## Key Files to Read
1. `claude-product-cycle/design-spec-layer/STATUS.md` - Master status tracker
2. `feature/*/` - Feature module directories
3. `core/network/services/` - API services
4. `core/data/repository/` - Repositories
---
## Status Legend
| Status | Meaning |
|--------|---------|
| ✅ Done | Feature complete, all working |
| ⚠️ Needs Update | Has gaps, spec changed, or incomplete |
| 🔄 In Progress | Currently being implemented |
| 📋 Planned | Spec exists, not started |
| 🆕 Not Started | No work done |

View File

@ -0,0 +1,125 @@
# Session End Command
Save current work context for the next session.
## Usage
```
/session-end # Save context and summarize session
/session-end "brief note" # Save with custom note
```
## Instructions
### Step 1: Gather Session Information
1. Check git status: `git status`
2. Check recent commits this session: `git log --oneline -5`
3. Review any uncommitted changes
### Step 2: Update CURRENT_WORK.md
**Update** `claude-product-cycle/CURRENT_WORK.md`:
```markdown
# Current Work
**Last Updated**: {{DATE}} {{TIME}}
**Branch**: {{BRANCH}}
**Session Note**: {{USER_NOTE_OR_AUTO_SUMMARY}}
---
## Active Tasks
| # | Task | Feature | Status | Files | Notes |
|---|------|---------|:------:|-------|-------|
{{ACTIVE_TASKS_FROM_SESSION}}
---
## In Progress
### {{FEATURE_NAME}}
**What was done**:
- {{COMPLETED_ITEMS}}
**What's next**:
- {{NEXT_ITEMS}}
**Key files touched**:
- {{FILE_LIST}}
---
## Uncommitted Changes
```
{{GIT_STATUS_OUTPUT}}
```
---
## Resume Instructions
1. Run `/session-start` to load this context
2. Continue with: {{NEXT_ACTION}}
3. Key context: {{IMPORTANT_NOTES}}
```
### Step 3: Prompt for Commit
If there are uncommitted changes:
```markdown
---
### Uncommitted Changes Detected
You have uncommitted changes. Shall I:
1. **Commit now** - Create a WIP commit to save progress
2. **Stash changes** - Save for later without committing
3. **Leave as-is** - Keep changes uncommitted
Recommended: Option 1 with message:
`wip: [feature] - {{AUTO_SUMMARY}}`
```
### Step 4: Output Session Summary
```markdown
## Session Saved
**Duration**: {{APPROXIMATE_WORK}}
**Commits**: {{COMMIT_COUNT}} commits this session
**Files Changed**: {{FILES_CHANGED}}
---
### What We Accomplished
- {{ACCOMPLISHMENT_1}}
- {{ACCOMPLISHMENT_2}}
- {{ACCOMPLISHMENT_3}}
---
### Next Session
Start with: `/session-start`
Continue: {{NEXT_TASK}}
---
**Context saved to**: `claude-product-cycle/CURRENT_WORK.md`
```
## Output Rules
1. Always update CURRENT_WORK.md
2. Capture uncommitted changes
3. Note specific files and line numbers if relevant
4. Be specific about next actions
5. Prompt for commit if changes exist

View File

@ -0,0 +1,65 @@
# Session Start Command
Resume context from previous sessions and identify current work.
## Instructions
### Step 1: Read Context Files
Read these files in order:
1. `claude-product-cycle/CURRENT_WORK.md` - Active work from last session
2. `claude-product-cycle/PRODUCT_MAP.md` - Master status tracker
3. Recent git commits: `git log --oneline -10`
### Step 2: Generate Session Summary
```markdown
## Session Resumed
**Last Session**: {{LAST_SESSION_DATE}}
**Branch**: {{CURRENT_BRANCH}}
---
### Active Work (from CURRENT_WORK.md)
| Task | Feature | Status | Next Action |
|------|---------|:------:|-------------|
{{ACTIVE_TASKS}}
---
### Recent Changes
```
{{RECENT_COMMITS}}
```
---
### Quick Status
| Layer | Progress | Gaps |
|-------|:--------:|------|
| Design | {{DESIGN_PCT}}% | {{DESIGN_GAPS}} |
| Client | {{CLIENT_PCT}}% | {{CLIENT_GAPS}} |
| Feature | {{FEATURE_PCT}}% | {{FEATURE_GAPS}} |
---
### Suggested Actions
1. {{CONTINUE_TASK}} - Continue from last session
2. `/gap-analysis` - Full status dashboard
3. `/gap-planning [feature]` - Plan next implementation
**Ready to continue?**
```
## Output Rules
1. Always read CURRENT_WORK.md first
2. Show what was in progress
3. Show recent commits for context
4. Suggest clear next action
5. Be concise - user wants to resume quickly

View File

@ -0,0 +1,446 @@
# /verify-tests - Test Verification (O(1) Enhanced)
Run and verify tests for features across the project with O(1) status lookups.
## Usage
```
/verify-tests # Show test status dashboard (O(1))
/verify-tests [feature] # Run all tests for feature
/verify-tests [feature] unit # Run ViewModel tests only
/verify-tests [feature] ui # Run UI tests only
/verify-tests [feature] integration # Run integration tests
/verify-tests [feature] screenshot # Run 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
```
---
## O(1) Workflow
```
+-------------------------------------------------------------------------+
| /verify-tests WORKFLOW (O(1) ENHANCED) |
+-------------------------------------------------------------------------+
| |
| PHASE 0: O(1) CONTEXT LOADING |
| +--> Read feature-layer/TESTING_STATUS.md --> VM/Screen test status|
| +--> Read client-layer/TESTING_STATUS.md --> Repository test status|
| +--> Read platform-layer/TESTING_STATUS.md --> E2E/Screenshot status|
| +--> Read feature-layer/MODULES_INDEX.md --> Feature paths |
| |
| PHASE 1: DETERMINE TEST SCOPE |
| +--> If no args: Show test dashboard from indexes |
| +--> If [feature]: Get paths from MODULES_INDEX |
| +--> If [layer]: Get layer test config |
| |
| PHASE 2: EXECUTE TESTS |
| +--> Build appropriate Gradle command |
| +--> Run tests via Bash |
| +--> Capture output |
| |
| PHASE 3: PARSE RESULTS |
| +--> Extract: passed, failed, skipped |
| +--> Extract: failure details |
| +--> Calculate coverage (if available) |
| |
| PHASE 4: UPDATE STATUS |
| +--> Update TESTING_STATUS.md with new results |
| +--> Log test run timestamp |
| |
| PHASE 5: REPORT |
| +--> Show results with next steps |
| |
+-------------------------------------------------------------------------+
```
---
## Phase 0: O(1) Context Loading
### Index Files to Read
| File | Purpose | Lines |
|------|---------|:-----:|
| `testing-layer/LAYER_STATUS.md` | **Primary** test dashboard | ~200 |
| `testing-layer/TEST_PATTERNS.md` | Test patterns & conventions | ~300 |
| `testing-layer/TEST_TAGS_INDEX.md` | TestTag specifications | ~350 |
| `testing-layer/TEST_FIXTURES_INDEX.md` | Test fixtures inventory | ~250 |
| `testing-layer/FAKE_REPOS_INDEX.md` | Fake repositories status | ~200 |
| `feature-layer/MODULES_INDEX.md` | Feature → Path mapping | ~115 |
### O(1) Path Pattern
```
feature/[module]/src/commonTest/ # Unit tests (ViewModel)
feature/[module]/src/androidInstrumentedTest/ # UI tests (Screen)
core/data/src/commonTest/ # Repository tests
cmp-android/src/androidTest/ # E2E integration tests
core/designsystem/src/test/ # Screenshot tests
```
---
## If No Arguments: Test Dashboard
Read from TESTING_STATUS.md files and show:
```
+=========================================================================+
| TEST STATUS DASHBOARD (O(1)) |
+=========================================================================+
## Layer Summary
| Layer | Tests | Passed | Failed | Coverage | Status |
|-------|:-----:|:------:|:------:|:--------:|:------:|
| Client | 14 | 14 | 0 | 82% | [======= ] |
| Feature | 0 | 0 | 0 | 0% | [ ] |
| Platform | 0 | 0 | 0 | 0% | [ ] |
## Feature Testing Matrix (from TESTING_STATUS.md)
| Feature | VMs | VM Tests | Screens | UI Tests | Status |
|---------|:---:|:--------:|:-------:|:--------:|:------:|
| auth | 5 | 0 | 6 | 0 | [ ] Not Started |
| home | 1 | 0 | 1 | 0 | [ ] Not Started |
| accounts | 3 | 0 | 3 | 0 | [ ] Not Started |
| ... (from feature-layer/TESTING_STATUS.md)
## Repository Testing (from client-layer/TESTING_STATUS.md)
| Repository | Tests | Success | Error | Empty | Status |
|------------|:-----:|:-------:|:-----:|:-----:|:------:|
| AccountsRepository | 2 | [x] | [ ] | [ ] | Partial |
| UserAuthRepository | 0 | [ ] | [ ] | [ ] | Not Started |
| ... (from client-layer/TESTING_STATUS.md)
## Quick Commands
| Action | Command |
|--------|---------|
| Run all tests | `./gradlew test` |
| Run feature tests | `/verify-tests [feature]` |
| Run client tests | `/verify-tests client` |
| Check gaps | `/gap-analysis testing` |
+=========================================================================+
```
---
## Feature Test Mapping (from MODULES_INDEX.md)
| # | Feature | Module Path | Unit Test Path | UI Test Path |
|:-:|---------|-------------|----------------|--------------|
| 1 | auth | feature/auth | feature/auth/src/commonTest/ | feature/auth/src/androidInstrumentedTest/ |
| 2 | home | feature/home | feature/home/src/commonTest/ | feature/home/src/androidInstrumentedTest/ |
| 3 | accounts | feature/accounts | feature/accounts/src/commonTest/ | feature/accounts/src/androidInstrumentedTest/ |
| 4 | beneficiary | feature/beneficiary | feature/beneficiary/src/commonTest/ | feature/beneficiary/src/androidInstrumentedTest/ |
| 5 | loan-account | feature/loan-account | feature/loan-account/src/commonTest/ | feature/loan-account/src/androidInstrumentedTest/ |
| 6 | savings-account | feature/savings-account | feature/savings-account/src/commonTest/ | feature/savings-account/src/androidInstrumentedTest/ |
| 7 | share-account | feature/share-account | feature/share-account/src/commonTest/ | feature/share-account/src/androidInstrumentedTest/ |
| 8 | transfer | feature/transfer-process | feature/transfer-process/src/commonTest/ | feature/transfer-process/src/androidInstrumentedTest/ |
| 9 | recent-transaction | feature/recent-transaction | feature/recent-transaction/src/commonTest/ | feature/recent-transaction/src/androidInstrumentedTest/ |
| 10 | notification | feature/notification | feature/notification/src/commonTest/ | feature/notification/src/androidInstrumentedTest/ |
| 11 | settings | feature/settings | feature/settings/src/commonTest/ | feature/settings/src/androidInstrumentedTest/ |
| 12 | passcode | libs/mifos-passcode | libs/mifos-passcode/src/commonTest/ | libs/mifos-passcode/src/androidInstrumentedTest/ |
| 13 | guarantor | feature/guarantor | feature/guarantor/src/commonTest/ | feature/guarantor/src/androidInstrumentedTest/ |
| 14 | qr | feature/qr-code | feature/qr-code/src/commonTest/ | feature/qr-code/src/androidInstrumentedTest/ |
| 15 | location | feature/location | feature/location/src/commonTest/ | feature/location/src/androidInstrumentedTest/ |
| 16 | user-profile | feature/user-profile | feature/user-profile/src/commonTest/ | feature/user-profile/src/androidInstrumentedTest/ |
---
## Test Type Commands
### `/verify-tests [feature]` - All Tests
```bash
# Unit tests (ViewModel)
./gradlew :feature:[module]:test
# UI tests (Screen) - requires emulator
./gradlew :feature:[module]:connectedDebugAndroidTest
```
### `/verify-tests [feature] unit` - ViewModel Only
```bash
./gradlew :feature:[module]:test
```
### `/verify-tests [feature] ui` - Screen Only
```bash
./gradlew :feature:[module]:connectedDebugAndroidTest
```
### `/verify-tests [feature] integration` - E2E Flow
```bash
./gradlew :cmp-android:connectedDebugAndroidTest \
-Pandroid.testInstrumentationRunnerArguments.class=org.mifos.mobile.[Feature]FlowTest
```
### `/verify-tests [feature] screenshot` - Visual
```bash
# Compare against golden images
./gradlew :core:designsystem:compareRoborazziDebug
# Record new golden images
./gradlew :core:designsystem:recordRoborazziDebug
```
---
## Layer Test Commands
### `/verify-tests client` - Repository Tests
```bash
./gradlew :core:data:test
```
### `/verify-tests feature` - All Feature Tests
```bash
./gradlew feature:test
```
### `/verify-tests platform` - Platform Tests
```bash
# E2E tests
./gradlew :cmp-android:connectedDebugAndroidTest
# Screenshot tests
./gradlew :core:designsystem:compareRoborazziDebug
```
---
## Output Format
### After Running Tests
```
+=========================================================================+
| VERIFY TESTS - [target] |
+=========================================================================+
## Test Execution
| Type | Command | Tests | Passed | Failed | Status |
|------|---------|:-----:|:------:|:------:|:------:|
| Unit | `./gradlew :feature:auth:test` | 45 | 45 | 0 | [x] |
| UI | `./gradlew :feature:auth:connectedDebugAndroidTest` | 25 | 23 | 2 | [!] |
## 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% | [x] Pass |
| Screen | 72% | 60% | [x] Pass |
| Repository | 90% | 80% | [x] Pass |
## Index Updated
[x] feature-layer/TESTING_STATUS.md - Updated test counts
[x] Last run: [timestamp]
+---------+----------------------------------------------------------+
| NEXT STEPS |
+---------+----------------------------------------------------------+
| 1 | Fix failing tests: LoginScreenTest.kt:45, :32 |
| 2 | Increase coverage: Add tests for uncovered paths |
| 3 | Re-run: /verify-tests auth |
+---------+----------------------------------------------------------+
```
---
## Error Handling
### Feature Not Found
```
+-------------------------------------------------------------------------+
| ERROR: Feature '[name]' not found |
+-------------------------------------------------------------------------+
| |
| The feature '[name]' does not exist in MODULES_INDEX.md |
| |
| Available features: |
| auth, home, accounts, beneficiary, loan-account, savings-account, |
| share-account, transfer, recent-transaction, notification, settings, |
| passcode, guarantor, qr, location, user-profile |
| |
| Did you mean: [closest match]? |
| |
+-------------------------------------------------------------------------+
```
### No Tests Found
```
+-------------------------------------------------------------------------+
| WARNING: No tests found for '[feature]' |
+-------------------------------------------------------------------------+
| |
| Test directory: feature/[module]/src/commonTest/ |
| Status: Empty |
| |
| To create tests: |
| 1. Run /gap-planning [feature] testing |
| 2. Follow TDD pattern in TESTING_STATUS.md |
| |
+-------------------------------------------------------------------------+
```
### Gradle Error
```
+-------------------------------------------------------------------------+
| ERROR: Gradle build failed |
+-------------------------------------------------------------------------+
| |
| Command: ./gradlew :feature:[module]:test |
| Exit code: 1 |
| |
| Error output: |
| [Gradle error message] |
| |
| Suggestions: |
| 1. Check compilation errors: ./gradlew :feature:[module]:compileKotlin |
| 2. Clean build: ./gradlew clean |
| 3. Check dependencies: ./gradlew :feature:[module]:dependencies |
| |
+-------------------------------------------------------------------------+
```
---
## 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 |
---
## TestTag System (from TESTING_STATUS.md)
### 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"
}
// ... for all features
}
```
---
## Integration Test Flows (from platform-layer/TESTING_STATUS.md)
| # | 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 | [ ] |
---
## Related Commands
| Command | Purpose |
|---------|---------|
| `/gap-analysis testing` | View all testing gaps |
| `/gap-analysis [layer] testing` | Layer-specific test gaps |
| `/gap-planning [feature] testing` | Plan test implementation |
| `/verify [feature]` | Verify implementation vs spec |
---
## Key Files
```
claude-product-cycle/
+-- feature-layer/
| +-- TESTING_STATUS.md # O(1) ViewModel/Screen test status
| +-- MODULES_INDEX.md # Feature -> path mapping
+-- client-layer/
| +-- TESTING_STATUS.md # O(1) Repository test status
+-- platform-layer/
| +-- TESTING_STATUS.md # O(1) E2E/Screenshot status
```
---
## Gradle Commands Reference
### Unit Tests
```bash
# All unit tests
./gradlew test
# Specific module
./gradlew :feature:auth:test
./gradlew :core:data:test
# With coverage
./gradlew test jacocoTestReport
```
### UI Tests
```bash
# All UI tests (requires emulator/device)
./gradlew connectedDebugAndroidTest
# Specific feature
./gradlew :feature:auth:connectedDebugAndroidTest
```
### 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/
```
ARGUMENTS: $ARGUMENTS

736
.claude/commands/verify.md Normal file
View File

@ -0,0 +1,736 @@
# /verify - Implementation Verification
## Purpose
Validate implementation matches specification using O(1) lookup. Compares SPEC.md requirements against actual code and identifies gaps with actionable fixes.
---
## Command Variants
```
/verify # Show all features verification status
/verify [Feature] # Full verification for feature
/verify [Feature] --quick # Skip detailed code analysis
/verify [Feature] --spec # Verify spec completeness only
/verify [Feature] --code # Verify code completeness only
/verify all # Verify all features (summary)
```
---
## Verification Pipeline with O(1) Optimization
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ /verify [Feature] - O(1) OPTIMIZED PIPELINE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ PHASE 0: O(1) CONTEXT LOADING │
│ ├─→ Read FEATURES_INDEX.md → Feature exists? Spec status? │
│ ├─→ Read FEATURE_MAP.md → Expected services/repos │
│ ├─→ Read MODULES_INDEX.md → Expected VMs/Screens │
│ ├─→ Read SCREENS_INDEX.md → Screen-ViewModel mapping │
│ └─→ Read API_INDEX.md → Expected endpoints │
│ │
│ PHASE 1: SPEC ANALYSIS │
│ ├─→ Read features/[name]/SPEC.md → Extract requirements │
│ ├─→ Read features/[name]/API.md → Extract API requirements │
│ ├─→ Read features/[name]/STATUS.md → Current status claims │
│ └─→ Build requirement checklist → What SHOULD exist │
│ │
│ PHASE 2: CODE ANALYSIS (O(1) paths from indexes) │
│ ├─→ Check ViewModel exists → From SCREENS_INDEX.md path │
│ ├─→ Check Screen exists → From SCREENS_INDEX.md path │
│ ├─→ Check Service exists → From FEATURE_MAP.md path │
│ ├─→ Check Repository exists → From FEATURE_MAP.md path │
│ └─→ Build implementation checklist → What DOES exist │
│ │
│ PHASE 3: DEEP VERIFICATION (if not --quick) │
│ ├─→ Read ViewModel code → Check State/Event/Action │
│ ├─→ Read Screen code → Check UI states, TestTags │
│ ├─→ Compare SPEC actions vs code → All actions handled? │
│ ├─→ Compare SPEC states vs code → All states rendered? │
│ └─→ Check DI registration → Koin modules complete? │
│ │
│ PHASE 4: GAP DETECTION │
│ ├─→ Compare requirement vs impl → Identify missing items │
│ ├─→ Categorize gaps by severity → P0 (critical) → P2 (polish) │
│ ├─→ Generate fix suggestions → Actionable steps │
│ └─→ Calculate verification score → Percentage complete │
│ │
│ PHASE 5: REPORT & UPDATE │
│ ├─→ Generate verification report → Structured output │
│ ├─→ Update STATUS.md (optional) → If user approves │
│ └─→ Suggest next command → /implement or /gap-planning │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## PHASE 0: O(1) Context Loading
### Files to Read (~500 lines total instead of scanning)
| File | Purpose | Data Extracted |
|------|---------|----------------|
| `design-spec-layer/FEATURES_INDEX.md` | Feature inventory | featureExists, specStatus |
| `client-layer/FEATURE_MAP.md` | Service/Repo mapping | expectedServices[], expectedRepos[] |
| `feature-layer/MODULES_INDEX.md` | Module structure | expectedVMs, expectedScreens |
| `feature-layer/SCREENS_INDEX.md` | Screen details | screenPaths[], vmPaths[] |
| `server-layer/API_INDEX.md` | Endpoint inventory | expectedEndpoints[] |
| `testing-layer/TEST_TAGS_INDEX.md` | TestTag specs | expectedTags[], namingPattern |
| `testing-layer/LAYER_STATUS.md` | Test coverage | testCoverage, fakeRepos |
### Context Object Built
```kotlin
val context = VerifyContext(
feature = "beneficiary",
// From FEATURES_INDEX.md
specExists = true,
specStatus = "✅ Complete",
// From FEATURE_MAP.md
expectedServices = ["BeneficiaryService"],
expectedRepositories = ["BeneficiaryRepository"],
// From MODULES_INDEX.md
expectedVMs = 4,
expectedScreens = 4,
// From SCREENS_INDEX.md
screens = [
Screen("BeneficiaryListScreen", "BeneficiaryListViewModel"),
Screen("BeneficiaryDetailScreen", "BeneficiaryDetailViewModel"),
Screen("BeneficiaryApplicationScreen", "BeneficiaryApplicationViewModel"),
Screen("BeneficiaryApplicationConfirmationScreen", "BeneficiaryApplicationConfirmationViewModel")
],
// From API_INDEX.md
expectedEndpoints = [
"GET /beneficiaries",
"POST /beneficiaries",
"PUT /beneficiaries/{id}",
"DELETE /beneficiaries/{id}"
]
)
```
---
## PHASE 1: Spec Analysis
### Read Specification Files
```
design-spec-layer/features/[feature]/
├── SPEC.md → UI sections, user actions, state model
├── API.md → Required endpoints, DTOs
└── STATUS.md → Claimed implementation status
```
### Extract Requirements from SPEC.md
```kotlin
val specRequirements = SpecRequirements(
// From SPEC.md Section 2: Screen Layout
uiSections = ["Header", "List", "EmptyState", "ErrorState", "LoadingState"],
// From SPEC.md Section 3: User Interactions
userActions = [
Action("Retry", "Reload data on error"),
Action("PullRefresh", "Refresh list"),
Action("ItemClick", "Navigate to detail"),
Action("AddClick", "Navigate to add form"),
Action("DeleteClick", "Delete with confirmation")
],
// From SPEC.md Section 4: State Model
stateFields = ["data", "uiState", "isRefreshing", "selectedItem"],
screenStates = ["Loading", "Success", "Error", "Empty"],
// From SPEC.md Section 5: API Requirements
apiEndpoints = ["GET /beneficiaries", "POST /beneficiaries", ...]
)
```
---
## PHASE 2: Code Analysis (O(1) Paths)
### File Paths from Index Files
| Component | Path Source | Example Path |
|-----------|-------------|--------------|
| ViewModel | SCREENS_INDEX.md | `feature/beneficiary/.../viewmodel/BeneficiaryListViewModel.kt` |
| Screen | SCREENS_INDEX.md | `feature/beneficiary/.../ui/BeneficiaryListScreen.kt` |
| Service | FEATURE_MAP.md | `core/network/.../services/BeneficiaryService.kt` |
| Repository | FEATURE_MAP.md | `core/data/.../repository/BeneficiaryRepository.kt` |
| DI Module | MODULES_INDEX.md | `feature/beneficiary/.../di/BeneficiaryModule.kt` |
### Check File Existence
```kotlin
val codeAnalysis = CodeAnalysis(
// File existence checks
viewModelsExist = [true, true, true, true], // 4/4
screensExist = [true, true, true, true], // 4/4
serviceExists = true,
repositoryExists = true,
diModuleExists = true,
// Navigation check
navigationRegistered = true,
// TestTags check
testTagsExist = false // Gap detected!
)
```
---
## PHASE 3: Deep Verification
### ViewModel Verification
```kotlin
// Read ViewModel and check:
val vmVerification = ViewModelVerification(
// State class
hasStateClass = true,
stateFieldsMatch = compareFields(spec.stateFields, vm.stateFields),
missingStateFields = ["selectedItem"], // Gap!
// Screen states
hasScreenStates = true,
screenStatesMatch = compareStates(spec.screenStates, vm.screenStates),
missingScreenStates = [],
// Actions
hasActionInterface = true,
actionsMatch = compareActions(spec.userActions, vm.actions),
missingActions = ["DeleteClick"], // Gap!
// Events
hasEventInterface = true,
eventsImplemented = true
)
```
### Screen Verification
```kotlin
// Read Screen and check:
val screenVerification = ScreenVerification(
// UI states rendered
hasLoadingState = true,
hasSuccessState = true,
hasErrorState = true,
hasEmptyState = false, // Gap!
// TestTags
hasTestTags = false, // Gap!
testTagsObject = null,
// Event collection
collectsEvents = true,
// Content separation
hasContentComposable = true
)
```
### DI Verification
```kotlin
val diVerification = DiVerification(
viewModelRegistered = true,
repositoryRegistered = true,
serviceRegistered = true
)
```
---
## PHASE 4: Gap Detection
### Gap Categories
| Severity | Description | Examples |
|:--------:|-------------|----------|
| P0 | Critical - App won't work | Missing ViewModel, Service not registered |
| P1 | Major - Feature incomplete | Missing action handler, Empty state |
| P2 | Minor - Polish needed | Missing TestTags, Missing Preview |
### Gap Report Structure
```kotlin
val gaps = GapReport(
feature = "beneficiary",
score = 85, // 85% complete
p0Gaps = [], // None - critical items present
p1Gaps = [
Gap(
category = "ViewModel",
item = "DeleteClick action",
specReference = "SPEC.md Section 3.5",
suggestedFix = "Add DeleteClick to BeneficiaryAction sealed interface"
),
Gap(
category = "Screen",
item = "Empty state",
specReference = "SPEC.md Section 2.4",
suggestedFix = "Add BeneficiaryEmpty composable when data.isEmpty()"
)
],
p2Gaps = [
Gap(
category = "Testing",
item = "TestTags object",
specReference = "Testing standards",
suggestedFix = "Add BeneficiaryTestTags object with feature:component pattern"
)
]
)
```
---
## PHASE 5: Report Generation
### Full Verification Report
```
╔═══════════════════════════════════════════════════════════════════════════════╗
║ /verify beneficiary - VERIFICATION REPORT ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ 📊 VERIFICATION SCORE: 85% [████████░░] ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ 📚 O(1) CONTEXT LOADED ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ FEATURES_INDEX.md → Feature exists: ✅ Spec status: ✅ Complete ║
║ FEATURE_MAP.md → Services: 1 expected Repos: 1 expected ║
║ MODULES_INDEX.md → VMs: 4 expected Screens: 4 expected ║
║ SCREENS_INDEX.md → 4 screen-VM mappings found ║
║ API_INDEX.md → 4 endpoints expected ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ✅ PASSING CHECKS ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ CLIENT LAYER: ║
║ ├─ BeneficiaryService.kt ✅ Exists ║
║ ├─ BeneficiaryRepository.kt ✅ Exists ║
║ ├─ BeneficiaryRepositoryImp.kt ✅ Exists ║
║ ├─ NetworkModule registration ✅ Registered ║
║ └─ RepositoryModule registration ✅ Registered ║
║ ║
║ FEATURE LAYER: ║
║ ├─ BeneficiaryListViewModel.kt ✅ Exists ║
║ ├─ BeneficiaryDetailViewModel.kt ✅ Exists ║
║ ├─ BeneficiaryApplicationViewModel.kt ✅ Exists ║
║ ├─ BeneficiaryApplicationConfirmationVM.kt ✅ Exists ║
║ ├─ 4 Screen files ✅ All exist ║
║ ├─ BeneficiaryModule.kt ✅ DI registered ║
║ └─ Navigation ✅ Configured ║
║ ║
║ STATE MODEL: ║
║ ├─ State class ✅ Defined ║
║ ├─ ScreenState sealed interface ✅ Loading/Success/Error ║
║ ├─ Event sealed interface ✅ Navigation events ║
║ └─ Action sealed interface ✅ User actions ║
║ ║
║ API INTEGRATION: ║
║ ├─ GET /beneficiaries ✅ Called ║
║ ├─ POST /beneficiaries ✅ Called ║
║ ├─ PUT /beneficiaries/{id} ✅ Called ║
║ └─ DELETE /beneficiaries/{id} ✅ Called ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ⚠️ GAPS FOUND (3) ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ P1 - MAJOR (2): ║
║ ┌────────────────────────────────────────────────────────────────────────┐ ║
║ │ Gap: Empty state not implemented │ ║
║ │ Spec: SPEC.md Section 2.4 - "Show empty illustration when no data" │ ║
║ │ File: feature/beneficiary/.../ui/BeneficiaryListScreen.kt │ ║
║ │ │ ║
║ │ 📍 Fix: │ ║
║ │ Add to BeneficiaryListScreen: │ ║
║ │ ```kotlin │ ║
║ │ is BeneficiaryUiState.Empty -> { │ ║
║ │ BeneficiaryEmpty( │ ║
║ │ onAddClick = { onAction(BeneficiaryAction.OnAddClick) } │ ║
║ │ ) │ ║
║ │ } │ ║
║ │ ``` │ ║
║ └────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ ┌────────────────────────────────────────────────────────────────────────┐ ║
║ │ Gap: selectedItem state field missing │ ║
║ │ Spec: SPEC.md Section 4.1 - State includes selectedItem for delete │ ║
║ │ File: feature/beneficiary/.../viewmodel/BeneficiaryListViewModel.kt │ ║
║ │ │ ║
║ │ 📍 Fix: │ ║
║ │ Add to BeneficiaryState: │ ║
║ │ ```kotlin │ ║
║ │ val selectedItem: Beneficiary? = null, │ ║
║ │ ``` │ ║
║ └────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ P2 - MINOR (1): ║
║ ┌────────────────────────────────────────────────────────────────────────┐ ║
║ │ Gap: TestTags object missing │ ║
║ │ Spec: Testing standards - All screens should have TestTags │ ║
║ │ File: feature/beneficiary/.../ui/BeneficiaryTestTags.kt (create) │ ║
║ │ │ ║
║ │ 📍 Fix: Run /feature beneficiary --tags to generate │ ║
║ └────────────────────────────────────────────────────────────────────────┘ ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ 📋 SUMMARY ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ | Category | Expected | Found | Score | ║
║ |---------------|:--------:|:-----:|:-----:| ║
║ | Client Layer | 5 | 5 | 100% | ║
║ | Feature Layer | 10 | 9 | 90% | ║
║ | State Model | 8 | 7 | 87% | ║
║ | API Calls | 4 | 4 | 100% | ║
║ | Testing | 2 | 1 | 50% | ║
║ |---------------|----------|-------|-------| ║
║ | TOTAL | 29 | 26 | 85% | ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ 🎯 NEXT STEPS ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Options: ║
║ • f / fix → Run /implement beneficiary to auto-fix gaps ║
║ • m / manual → Fix gaps manually using suggestions above ║
║ • u / update → Update STATUS.md to reflect current state ║
║ • i / ignore → Mark gaps as intentional (document reason) ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
```
---
## All Features Verification (No Argument)
When `/verify` called without arguments, show summary from index files:
```
╔═══════════════════════════════════════════════════════════════════════════════╗
║ /verify - ALL FEATURES VERIFICATION STATUS ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Data from: FEATURES_INDEX.md, MODULES_INDEX.md, FEATURE_MAP.md ║
║ ║
║ | # | Feature | Spec | Client | Feature | Score | Gaps | ║
║ |:-:|-------------------|:----:|:------:|:-------:|:-----:|:----:| ║
║ | 1 | auth | ✅ | ✅ | ✅ | 95% | 1 | ║
║ | 2 | home | ✅ | ✅ | ✅ | 100% | 0 | ║
║ | 3 | accounts | ✅ | ✅ | ✅ | 98% | 1 | ║
║ | 4 | beneficiary | ✅ | ✅ | ✅ | 85% | 3 | ║
║ | 5 | loan-account | ✅ | ✅ | ✅ | 92% | 2 | ║
║ | 6 | savings-account | ✅ | ✅ | ✅ | 90% | 2 | ║
║ | 7 | share-account | ✅ | ✅ | ✅ | 88% | 2 | ║
║ | 8 | transfer | ✅ | ✅ | ✅ | 95% | 1 | ║
║ | 9 | recent-transaction| ✅ | ✅ | ✅ | 100% | 0 | ║
║ | 10| notification | ✅ | ✅ | ✅ | 100% | 0 | ║
║ | 11| settings | ✅ | ✅ | ✅ | 85% | 3 | ║
║ | 12| passcode | ✅ | - | ✅ | 100% | 0 | ║
║ | 13| guarantor | ✅ | ✅ | ✅ | 90% | 2 | ║
║ | 14| qr | ✅ | - | ✅ | 95% | 1 | ║
║ | 15| location | ✅ | - | ✅ | 80% | 2 | ║
║ | 16| client-charge | ✅ | ✅ | ✅ | 92% | 1 | ║
║ | 17| dashboard | ⚠️ | ❌ | ❌ | 20% | 8 | ║
║ ║
║ OVERALL: 89% verified | Total Gaps: 29 ║
║ ║
║ Commands: ║
║ • /verify [feature] → Detailed verification ║
║ • /verify all --fix → Show all gaps with fixes ║
║ • /gap-planning feature → Plan to fix gaps ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
```
---
## Verification Checklist (Quick Reference)
### Client Layer Checks
| Check | Source | Verification |
|-------|--------|--------------|
| Service exists | FEATURE_MAP.md | File exists at path |
| Repository exists | FEATURE_MAP.md | File exists at path |
| RepositoryImpl exists | FEATURE_MAP.md | File exists at path |
| NetworkModule registration | NetworkModule.kt | Contains service binding |
| RepositoryModule registration | RepositoryModule.kt | Contains repo binding |
### Feature Layer Checks
| Check | Source | Verification |
|-------|--------|--------------|
| ViewModel exists | SCREENS_INDEX.md | File exists at path |
| Screen exists | SCREENS_INDEX.md | File exists at path |
| DI Module exists | MODULES_INDEX.md | File exists at path |
| Navigation registered | Navigation graph | Contains route |
### State Model Checks
| Check | Source | Verification |
|-------|--------|--------------|
| State class defined | ViewModel file | `data class ${Feature}State` |
| ScreenState sealed | ViewModel file | `sealed interface ${Feature}UiState` |
| Event sealed | ViewModel file | `sealed interface ${Feature}Event` |
| Action sealed | ViewModel file | `sealed interface ${Feature}Action` |
| handleAction implemented | ViewModel file | `override fun handleAction` |
### UI State Checks
| Check | Source | Verification |
|-------|--------|--------------|
| Loading state | Screen file | `${Feature}UiState.Loading` branch |
| Success state | Screen file | `${Feature}UiState.Success` branch |
| Error state | Screen file | `${Feature}UiState.Error` branch |
| Empty state | Screen file | `${Feature}UiState.Empty` branch (if in spec) |
### Testing Checks
| Check | Source | Verification |
|-------|--------|--------------|
| TestTags object | Screen directory | `${Feature}TestTags.kt` exists |
| testTag modifiers | Screen file | `Modifier.testTag()` used |
| TestTag naming | TestTags object | Follows `feature:component:id` pattern |
| All states tagged | Screen file | Loading, Success, Error have tags |
| Interactive elements | Screen file | Buttons, inputs have tags |
---
## TestTag Validation (Enhanced)
### TestTag Naming Convention
Pattern: `feature:component:element`
| Component | Pattern | Example |
|-----------|---------|---------|
| Screen | `{feature}:screen` | `beneficiary:screen` |
| Loading | `{feature}:loading` | `beneficiary:loading` |
| Error | `{feature}:error` | `beneficiary:error` |
| List | `{feature}:list` | `beneficiary:list` |
| Item | `{feature}:item:{id}` | `beneficiary:item:123` |
| Button | `{feature}:{action}` | `beneficiary:retry`, `beneficiary:add` |
| Input | `{feature}:input:{name}` | `auth:input:username` |
### TestTag Validation Rules
```kotlin
val testTagValidation = TestTagValidation(
// Required TestTags (P2 if missing)
required = [
"${feature}:screen",
"${feature}:loading",
"${feature}:error",
],
// Recommended TestTags (suggestions only)
recommended = [
"${feature}:list", // For list screens
"${feature}:item:{id}", // For list items
"${feature}:retry", // For error retry
"${feature}:empty", // For empty state
],
// Validate naming convention
namingConvention = regex("^[a-z-]+:[a-z-]+(?::[a-z0-9-]+)?$")
)
```
### TestTag Validation Report
```
╠═══════════════════════════════════════════════════════════════════════════════╣
║ 🏷️ TESTTAG VALIDATION ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ TestTags Object: ${Feature}TestTags.kt ║
║ Location: feature/${name}/.../ui/${Feature}TestTags.kt ║
║ Status: [✅ EXISTS | ❌ MISSING] ║
║ ║
║ Required Tags: ║
║ ├─ ${feature}:screen [✅ Found | ❌ Missing] ║
║ ├─ ${feature}:loading [✅ Found | ❌ Missing] ║
║ └─ ${feature}:error [✅ Found | ❌ Missing] ║
║ ║
║ Screen Usage: ║
║ ├─ ${Feature}Screen.kt testTag() calls: [n] ║
║ ├─ ${Feature}Content.kt testTag() calls: [n] ║
║ └─ Total coverage: [n] / [expected] ║
║ ║
║ Naming Convention: ║
║ ├─ Valid tags: [n] ║
║ └─ Invalid tags: [list of non-conforming tags] ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════╣
```
### TestTag Gap Examples
```
┌────────────────────────────────────────────────────────────────────────┐
│ Gap: TestTags object missing │
│ Severity: P2 (Testing) │
│ File: feature/${name}/.../ui/${Feature}TestTags.kt (create) │
│ │
│ 📍 Fix: Generate TestTags │
│ ```kotlin │
│ internal object ${Feature}TestTags { │
│ const val SCREEN = "${feature}:screen" │
│ const val LOADING = "${feature}:loading" │
│ const val ERROR = "${feature}:error" │
│ const val LIST = "${feature}:list" │
│ const val RETRY_BUTTON = "${feature}:retry" │
│ const val ITEM_PREFIX = "${feature}:item:" // + id │
│ } │
│ ``` │
│ │
│ Command: /feature ${feature} --tags │
└────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────┐
│ Gap: Missing testTag modifiers in Screen │
│ Severity: P2 (Testing) │
│ File: feature/${name}/.../ui/${Feature}Screen.kt │
│ │
│ 📍 Fix: Add testTag modifiers to composables │
│ ```kotlin │
│ // Loading state │
│ MifosLoadingWheel( │
│ modifier = Modifier.testTag(${Feature}TestTags.LOADING) │
│ ) │
│ │
│ // Error state │
│ MifosErrorContent( │
│ modifier = Modifier.testTag(${Feature}TestTags.ERROR) │
│ ) │
│ │
│ // List │
│ LazyColumn( │
│ modifier = Modifier.testTag(${Feature}TestTags.LIST) │
│ ) │
│ ``` │
└────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────┐
│ Gap: TestTag naming doesn't follow convention │
│ Severity: P2 (Polish) │
│ File: feature/${name}/.../ui/${Feature}TestTags.kt │
│ │
│ Found: "BeneficiaryScreen", "LoadingIndicator" │
│ Expected: "beneficiary:screen", "beneficiary:loading" │
│ │
│ 📍 Fix: Update to feature:component:element pattern │
│ ```kotlin │
│ // Before (invalid) │
│ const val SCREEN = "BeneficiaryScreen" │
│ const val LOADING = "LoadingIndicator" │
│ │
│ // After (valid) │
│ const val SCREEN = "beneficiary:screen" │
│ const val LOADING = "beneficiary:loading" │
│ ``` │
└────────────────────────────────────────────────────────────────────────┘
```
### TestTag Scoring
| Criterion | Weight | Passed | Score |
|-----------|:------:|:------:|:-----:|
| TestTags object exists | 40% | ✅/❌ | x/40 |
| Required tags defined | 30% | n/3 | x/30 |
| testTag() modifiers used | 20% | n/m | x/20 |
| Naming convention | 10% | n/n | x/10 |
| **Total** | 100% | | x/100 |
---
## Error Handling
### Feature Not Found
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ ❌ FEATURE NOT FOUND │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Feature: "xyz" │
│ Checked: FEATURES_INDEX.md │
│ │
│ Did you mean one of these? │
│ • beneficiary │
│ • beneficiary-detail │
│ │
│ Or run /verify to see all features. │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
### Spec Missing
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ ⚠️ SPEC MISSING │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Feature: dashboard │
│ Expected: design-spec-layer/features/dashboard/SPEC.md │
│ Found: File does not exist │
│ │
│ Cannot verify without specification. │
│ │
│ Options: │
│ • d / design → Run /design dashboard to create spec │
│ • c / code → Verify code only (--code flag) │
│ • a / abort → Cancel verification │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
---
## O(1) File Reference
| Index File | Data Used For |
|------------|---------------|
| `design-spec-layer/FEATURES_INDEX.md` | Feature list, spec status |
| `client-layer/FEATURE_MAP.md` | Service/Repository paths |
| `feature-layer/MODULES_INDEX.md` | Module structure, VM/Screen counts |
| `feature-layer/SCREENS_INDEX.md` | Screen-ViewModel mappings, file paths |
| `server-layer/API_INDEX.md` | Expected API endpoints |
---
## Related Commands
| Command | Purpose |
|---------|---------|
| `/implement [Feature]` | Fix gaps automatically |
| `/gap-analysis [Feature]` | Broader gap analysis |
| `/gap-planning [Feature]` | Plan fixes for gaps |
| `/design [Feature]` | Update specification |
| `/verify-tests [Feature]` | Verify test coverage |

17
.github/ci-gradle.properties vendored Normal file
View File

@ -0,0 +1,17 @@
# Disable daemon for CI to avoid leftover processes
org.gradle.daemon=false
# Run tasks in parallel where possible
org.gradle.parallel=true
# Increase heap and metaspace for larger builds (macOS-latest has ~7 GB available)
org.gradle.jvmargs=-Xmx7g
# Limit max workers to avoid memory pressure in CI
org.gradle.workers.max=3
# Disable Kotlin incremental compilation in CI for clean, consistent builds
kotlin.incremental=false
# Use in-process Kotlin compiler to avoid extra forked processes
kotlin.compiler.execution.strategy=in-process

View File

@ -62,5 +62,5 @@ concurrency:
jobs:
monthly_release:
name: Tag Monthly Release
uses: openMF/mifos-x-actionhub/.github/workflows/monthly-version-tag.yaml@v1.0.0
uses: openMF/mifos-x-actionhub/.github/workflows/monthly-version-tag.yaml@v1.0.7
secrets: inherit

View File

@ -0,0 +1,181 @@
# GitHub Actions Workflow for Kotlin Multi-Platform Application Deployment
#
# OVERVIEW:
# This workflow supports building and publishing applications across multiple platforms:
# - Android (APK/AAB)
# - iOS (IPA)
# - Desktop (EXE, MSI, DMG, DEB)
# - Web (GitHub Pages)
#
# PREREQUISITES:
# Ensure your project is configured with:
# - Gradle build system
# - Kotlin Multiplatform Project with Android, iOS, Desktop, and Web modules
# - Fastlane for deployment automation
# - Separate modules/package names for each platform
#
# REQUIRED SECRETS:
# Configure the following secrets in GitHub repository settings:
# - ORIGINAL_KEYSTORE_FILE: Base64 encoded Android release keystore
# - ORIGINAL_KEYSTORE_FILE_PASSWORD: Keystore password
# - ORIGINAL_KEYSTORE_ALIAS: Keystore alias
# - ORIGINAL_KEYSTORE_ALIAS_PASSWORD: Keystore alias password
# - UPLOAD_KEYSTORE_FILE: Base64 encoded Android release keystore
# - UPLOAD_KEYSTORE_FILE_PASSWORD: Keystore password
# - UPLOAD_KEYSTORE_ALIAS: Keystore alias
# - UPLOAD_KEYSTORE_ALIAS_PASSWORD: Keystore alias password
# - GOOGLESERVICES: Google Services configuration JSON
# - PLAYSTORECREDS: Play Store service account credentials
# - FIREBASECREDS: Firebase distribution credentials
# - NOTARIZATION_APPLE_ID: Apple ID for macOS app notarization
# - NOTARIZATION_PASSWORD: Notarization password
# - NOTARIZATION_TEAM_ID: Apple developer team ID
# WORKFLOW INPUTS:
# - release_type: 'internal' (default) or 'beta'
# - target_branch: Branch to use for release (default: 'dev')
# - android_package_name: Name of Android module
# - ios_package_name: Name of iOS module
# - desktop_package_name: Name of desktop module
# - web_package_name: Name of web module
# - publish_android: Enable/disable Android Play Store publishing
# - build_ios: Enable/disable iOS build
# - publish_ios: Enable/disable iOS App Store publishing
# USAGE:
# 1. Ensure all required secrets are configured
# 2. Customize package names in workflow inputs
# 3. Toggle platform-specific publishing flags
# 4. Trigger workflow manually or via GitHub Actions UI
# https://github.com/openMF/mifos-x-actionhub/blob/main/.github/workflows/multi-platform-build-and-publish.yaml
# ##############################################################################
# DON'T EDIT THIS FILE UNLESS NECESSARY #
# ##############################################################################
name: Multi-Platform Build and Publish
on:
workflow_dispatch:
inputs:
release_type:
type: choice
options:
- internal
- beta
default: internal
description: Release Type
target_branch:
type: string
default: 'development'
description: 'Target branch for release'
distribute_ios_firebase:
type: boolean
default: false
description: Distribute iOS App via Firebase App Distribution
distribute_ios_testflight:
type: boolean
default: false
description: Distribute iOS App via TestFlight (App Store Connect)
distribute_ios_appstore:
type: boolean
default: false
description: Distribute iOS App to Appstore
distribute_macos_testflight:
type: boolean
default: false
description: Distribute macOS App via TestFlight (App Store Connect)
distribute_macos_appstore:
type: boolean
default: false
description: Distribute macOS App to Appstore
permissions:
contents: write
id-token: write
pages: write
concurrency:
group: "reusable"
cancel-in-progress: false
jobs:
multi_platform_build_and_publish:
name: Multi-Platform Build and Publish
uses: openMF/mifos-x-actionhub/.github/workflows/multi-platform-build-and-publish.yaml@v1.0.7
with:
java-version: 21
release_type: ${{ inputs.release_type }}
target_branch: ${{ inputs.target_branch }}
android_package_name: 'cmp-android'
ios_package_name: 'cmp-ios'
desktop_package_name: 'cmp-desktop'
web_package_name: 'cmp-web'
tester_groups: 'mifos-mobile-apps'
app_identifier: 'org.mifos.mobile'
git_url: 'git@github.com:openMF/ios-provisioning-profile.git'
git_branch: 'mifos-mobile'
match_type: 'adhoc'
provisioning_profile_name: 'match AdHoc org.mifos.mobile'
firebase_app_id: '1:728434912738:ios:ee2e0815a6915b351a1dbb'
metadata_path: './fastlane/metadata/ios'
use_cocoapods: true # <-- Set to true if using CocoaPods integration for KMP
shared_module: ':cmp-shared' # <-- Gradle path to your shared KMP module (e.g., :shared)
cmp_desktop_dir: 'cmp-desktop'
keychain_name: signing.keychain-db # optional
distribute_ios_firebase: ${{ inputs.distribute_ios_firebase }}
distribute_ios_testflight: ${{ inputs.distribute_ios_testflight }}
distribute_ios_appstore: ${{ inputs.distribute_ios_appstore }}
distribute_macos_testflight: ${{ inputs.distribute_macos_testflight }}
distribute_macos_appstore: ${{ inputs.distribute_macos_appstore }}
secrets:
original_keystore_file: ${{ secrets.ORIGINAL_KEYSTORE_FILE }}
original_keystore_file_password: ${{ secrets.ORIGINAL_KEYSTORE_FILE_PASSWORD }}
original_keystore_alias: ${{ secrets.ORIGINAL_KEYSTORE_ALIAS }}
original_keystore_alias_password: ${{ secrets.ORIGINAL_KEYSTORE_ALIAS_PASSWORD }}
upload_keystore_file: ${{ secrets.UPLOAD_KEYSTORE_FILE }}
upload_keystore_file_password: ${{ secrets.UPLOAD_KEYSTORE_FILE_PASSWORD }}
upload_keystore_alias: ${{ secrets.UPLOAD_KEYSTORE_ALIAS }}
upload_keystore_alias_password: ${{ secrets.UPLOAD_KEYSTORE_ALIAS_PASSWORD }}
notarization_apple_id: ${{ secrets.NOTARIZATION_APPLE_ID }}
notarization_password: ${{ secrets.NOTARIZATION_PASSWORD }}
notarization_team_id: ${{ secrets.NOTARIZATION_TEAM_ID }}
keychain_password: ${{ secrets.KEYCHAIN_PASSWORD }}
certificates_password: ${{ secrets.CERTIFICATES_PASSWORD }}
mac_app_distribution_certificate_b64: ${{ secrets.MAC_APP_DISTRIBUTION_CERTIFICATE_B64 }}
mac_installer_distribution_certificate_b64: ${{ secrets.MAC_INSTALLER_DISTRIBUTION_CERTIFICATE_B64 }}
mac_embedded_provision_b64: ${{ secrets.MAC_EMBEDDED_PROVISION_B64 }}
mac_runtime_provision_b64: ${{ secrets.MAC_RUNTIME_PROVISION_B64 }}
appstore_key_id: ${{ secrets.APPSTORE_KEY_ID }}
appstore_issuer_id: ${{ secrets.APPSTORE_ISSUER_ID }}
appstore_auth_key: ${{ secrets.APPSTORE_AUTH_KEY }}
match_password: ${{ secrets.MATCH_PASSWORD }}
match_ssh_private_key: ${{ secrets.MATCH_SSH_PRIVATE_KEY }}
windows_signing_key: ${{ secrets.WINDOWS_SIGNING_KEY }}
windows_signing_password: ${{ secrets.WINDOWS_SIGNING_PASSWORD }}
windows_signing_certificate: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE }}
macos_signing_key: ${{ secrets.MACOS_SIGNING_KEY }}
macos_signing_password: ${{ secrets.MACOS_SIGNING_PASSWORD }}
macos_signing_certificate: ${{ secrets.MACOS_SIGNING_CERTIFICATE }}
linux_signing_key: ${{ secrets.LINUX_SIGNING_KEY }}
linux_signing_password: ${{ secrets.LINUX_SIGNING_PASSWORD }}
linux_signing_certificate: ${{ secrets.LINUX_SIGNING_CERTIFICATE }}
google_services: ${{ secrets.GOOGLESERVICES }}
firebase_creds: ${{ secrets.FIREBASECREDS }}
playstore_creds: ${{ secrets.PLAYSTORECREDS }}
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -13,7 +13,7 @@
### Workflow Jobs
# 1. **Setup**: Prepares the build environment
# - Checks out repository code
# - Sets up Java 17
# - Sets up Java (configurable; defaults to 17)
# - Configures Gradle
# - Manages dependency caching
#
@ -36,7 +36,7 @@
# - Generates platform-specific executables and packages
#
### Prerequisites
# - Java 17
# - Java (configurable; default 17)
# - Gradle
# - Configured build scripts for:
# - Android module
@ -49,13 +49,19 @@
### Configuration Parameters
# The workflow requires two input parameters:
#
# | Parameter | Description | Type | Required |
# |------------------------|------------------------------------|--------|----------|
# | `android_package_name` | Name of the Android project module | String | Yes |
# | `desktop_package_name` | Name of the Desktop project module | String | Yes |
# | Parameter | Description | Type | Required |
# |------------------------|------------------------------------|--------|-----------|
# | `android_package_name` | Name of the Android project module | String | Yes |
# | `desktop_package_name` | Name of the Desktop project module | String | Yes |
# |`web_package_name` | Name of the Web (Kotlin/JS) project/module | String | No|
# |`ios_package_name` | Name of the iOS project/module | String | No |
# |`build_ios` | Build iOS targets as part of PR checks | Boolean | No |
# |`use_cocoapods` | Use CocoaPods for iOS integration | Boolean | No |
# |`shared_module | Path of the shared KMP module | String | (required when build_ios=true) |
# |`java-version | Java version to use (configurable; defaults to 17)| No |
#
# https://github.com/openMF/mifos-mobile-github-actions/blob/main/.github/workflows/pr-check.yaml
# https://github.com/openMF/mifos-x-actionhub/blob/main/.github/workflows/pr-check.yaml
# ##############################################################################
# DON'T EDIT THIS FILE UNLESS NECESSARY #
@ -82,7 +88,7 @@ permissions:
jobs:
pr_checks:
name: PR Checks KMP
uses: openMF/mifos-x-actionhub/.github/workflows/pr-check.yaml@v1.0.0
uses: openMF/mifos-x-actionhub/.github/workflows/pr-check.yaml@v1.0.7
secrets: inherit
with:
android_package_name: 'cmp-android' # <-- Change Your Android Package Name
@ -90,3 +96,6 @@ jobs:
web_package_name: 'cmp-web' # <-- Change Your Web Package Name
ios_package_name: 'cmp-ios' # <-- Change Your iOS Package Name
build_ios: true # <-- Change to 'false' if you don't want to build iOS
use_cocoapods: true
shared_module: ':cmp-shared'
java-version: '21'

View File

@ -70,6 +70,6 @@ jobs:
# Job to promote app from beta to production in Play Store
play_promote_production:
name: Promote Beta to Production Play Store
uses: openMF/mifos-x-actionhub/.github/workflows/promote-to-production.yaml@main
uses: openMF/mifos-x-actionhub/.github/workflows/promote-to-production.yaml@v1.0.7
secrets:
playstore_creds: ${{ secrets.PLAYSTORECREDS }}

273
.github/workflows/sync-dirs.yaml vendored Normal file
View File

@ -0,0 +1,273 @@
name: Sync CMP Directories
on:
workflow_dispatch:
inputs:
upstream:
description: 'Upstream repository to sync directories from'
default: 'https://github.com/openMF/kmp-project-template.git'
required: true
type: string
schedule:
- cron: '0 0 * * 1'
jobs:
sync-directories:
if: github.repository != 'openMF/kmp-project-template'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: development
- name: Setup Git config
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Add upstream remote and fetch
run: |
UPSTREAM="${{ inputs.upstream || 'https://github.com/openMF/kmp-project-template.git' }}"
git remote add upstream "$UPSTREAM" || true
git fetch upstream || exit 1
- name: Check upstream/dev exists
run: |
if ! git rev-parse --verify upstream/dev >/dev/null 2>&1; then
echo "Error: upstream/dev branch does not exist"
exit 1
fi
- name: Create and checkout temporary branch
run: |
TEMP_BRANCH="temp-sync-branch-${{ github.run_number }}"
git checkout -b "$TEMP_BRANCH" upstream/dev || exit 1
echo "TEMP_BRANCH=$TEMP_BRANCH" >> $GITHUB_ENV
- name: Sync directories and files
run: |
# Declare directories and files to sync
DIRS=(
"cmp-android"
"cmp-desktop"
"cmp-ios"
"cmp-web"
"cmp-shared"
"core-base"
"build-logic"
"fastlane"
"scripts"
"config"
".github"
".run"
)
FILES=(
"Gemfile"
"Gemfile.lock"
"ci-prepush.bat"
"ci-prepush.sh"
)
# Define exclusions
declare -A EXCLUSIONS=(
["cmp-android"]="src/main/res dependencies src/main/ic_launcher-playstore.png google-services.json"
["cmp-web"]="src/jsMain/resources src/wasmJsMain/resources"
["cmp-desktop"]="icons"
["cmp-ios"]="iosApp/Assets.xcassets"
["root"]="secrets.env"
)
# Function to check if path should be excluded
should_exclude() {
local dir=$1
local path=$2
# Check for root exclusions
if [[ "$dir" == "." && -n "${EXCLUSIONS["root"]}" ]]; then
local root_excluded_paths=(${EXCLUSIONS["root"]})
for excluded in "${root_excluded_paths[@]}"; do
if [[ "$path" == *"$excluded"* ]]; then
return 0
fi
done
fi
# Check directory-specific exclusions
if [[ -n "${EXCLUSIONS[$dir]}" ]]; then
local excluded_paths=(${EXCLUSIONS[$dir]})
for excluded in "${excluded_paths[@]}"; do
if [[ "$path" == *"$excluded"* ]]; then
return 0
fi
done
fi
return 1
}
# Function to preserve excluded paths
preserve_excluded() {
local dir=$1
if [[ -n "${EXCLUSIONS[$dir]}" ]]; then
local excluded_paths=(${EXCLUSIONS[$dir]})
for excluded in "${excluded_paths[@]}"; do
local full_path="$dir/$excluded"
if [[ -e "$full_path" ]]; then
echo "Preserving excluded path: $full_path"
local temp_path="temp_excluded/$full_path"
mkdir -p "$(dirname "$temp_path")"
cp -r "$full_path" "$(dirname "$temp_path")"
fi
done
fi
}
# Function to restore excluded paths
restore_excluded() {
local dir=$1
if [[ -n "${EXCLUSIONS[$dir]}" ]]; then
local excluded_paths=(${EXCLUSIONS[$dir]})
for excluded in "${excluded_paths[@]}"; do
local full_path="$dir/$excluded"
local temp_path="temp_excluded/$full_path"
if [[ -e "$temp_path" ]]; then
echo "Restoring excluded path: $full_path"
mkdir -p "$(dirname "$full_path")"
rm -rf "$full_path"
cp -r "$temp_path" "$(dirname "$full_path")"
fi
done
fi
}
# Function to preserve root-level excluded files
preserve_root_files() {
if [[ -n "${EXCLUSIONS["root"]}" ]]; then
local excluded_paths=(${EXCLUSIONS["root"]})
for excluded in "${excluded_paths[@]}"; do
if [[ -e "$excluded" ]]; then
echo "Preserving root-level excluded file: $excluded"
mkdir -p "temp_excluded/root"
cp -r "$excluded" "temp_excluded/root/"
fi
done
fi
}
# Function to restore root-level excluded files
restore_root_files() {
if [[ -n "${EXCLUSIONS["root"]}" ]]; then
local excluded_paths=(${EXCLUSIONS["root"]})
for excluded in "${excluded_paths[@]}"; do
if [[ -e "temp_excluded/root/$excluded" ]]; then
echo "Restoring root-level excluded file: $excluded"
cp -r "temp_excluded/root/$excluded" "./"
fi
done
fi
}
# Create temp directory for exclusions
mkdir -p temp_excluded
# Preserve root-level exclusions before sync
preserve_root_files
# Switch to development branch
git checkout development
# Sync directories
for dir in "${DIRS[@]}"; do
if [ ! -d "$dir" ]; then
echo "Creating $dir..."
mkdir -p "$dir"
fi
# Preserve excluded paths before sync
if [[ -d "$dir" ]]; then
preserve_excluded "$dir"
fi
echo "Syncing $dir..."
git checkout "${{ env.TEMP_BRANCH }}" -- "$dir" || exit 1
# Restore excluded paths after sync
restore_excluded "$dir"
done
# Sync files
for file in "${FILES[@]}"; do
dir=$(dirname "$file")
if ! should_exclude "$dir" "$file"; then
echo "Syncing $file..."
git checkout "${{ env.TEMP_BRANCH }}" -- "$file" || true
else
echo "Skipping excluded file: $file"
fi
done
# Restore root-level excluded files
restore_root_files
# Cleanup temp directory
rm -rf temp_excluded
- name: Clean up temporary branch
if: always()
run: git branch -D "${{ env.TEMP_BRANCH }}" || true
- name: Check for changes
id: check_changes
run: |
if [[ -n "$(git status --porcelain)" ]]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
fi
- name: Create Pull Request
if: steps.check_changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT_TOKEN }}
commit-message: "chore: Sync directories and files from upstream"
title: "chore: Sync directories and files from upstream"
body: |
Automated sync of directories and files from upstream repository.
Changes included in this sync:
Directories:
- cmp-android (excluding src/main/res, dependencies, ic_launcher-playstore.png, google-services.json)
- cmp-desktop (excluding icons)
- cmp-ios (excluding iosApp/Assets.xcassets)
- cmp-web (excluding src/jsMain/resources, src/wasmJsMain/resources)
- cmp-shared
- build-logic
- fastlane
- scripts
- config
- .github
- .run
Files:
- Gemfile
- Gemfile.lock
- ci-prepush.bat
- ci-prepush.sh
Root-level exclusions:
- secrets.env
Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
branch: sync-dirs-${{ github.run_number }}
delete-branch: true
labels: |
sync
automated pr
base: development

View File

@ -13,11 +13,11 @@ jobs:
with:
fetch-depth: 0
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4.2.2
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'
- name: Tag Weekly Release
env:

7
.gitignore vendored
View File

@ -54,3 +54,10 @@ playStorePublishServiceCredentialsFile.json
# Ruby stuff we don't care about
.bundle/
vendor/
# iOS / Xcode
cmp-ios/Pods/
cmp-ios/iosApp.xcodeproj/xcuserdata/
cmp-ios/iosApp.xcworkspace/xcuserdata/
*.xcuserstate
*.xcuserdatad/

View File

@ -1,6 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="cmp-desktop" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="DEVELOPER_DIR" value="/Applications/Xcode.app/Contents/Developer" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />

View File

@ -10,7 +10,7 @@
</option>
<option name="taskNames">
<list>
<option value=":cmp-web:wasmJsBrowserRun" />
<option value=":cmp-web:wasmJsBrowserDevelopmentRun" />
</list>
</option>
<option name="vmOptions" />

192
CLAUDE.md Normal file
View File

@ -0,0 +1,192 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Quick Context (Start Here)
**Current Focus**: v2.0 UI Redesign (2025 Fintech Patterns)
### Session Workflow (Never Lose Context)
```bash
# START of session
/session-start # Load context from previous session
# DURING session - use these commands
/gap-analysis # What's done vs what's needed (5 layers)
/gap-analysis [layer] # Layer-specific (design|server|client|feature|platform)
/gap-planning [feature] # Plan specific improvements
/implement [feature] # Execute implementation
/verify [feature] # Confirm implementation
# END of session
/session-end # Save context for next session
```
### Claude Product Cycle Framework
This project uses the [claude-product-cycle](https://github.com/mobilebytesensei/claude-product-cycle) framework for AI-assisted development.
**Workspace**: [mifos-x-claude-cycle-workspaces](https://github.com/therajanmaurya/mifos-x-claude-cycle-workspaces)
### 5-Layer Lifecycle
```
Design → Server → Client → Feature → Platform
```
---
## Prompt Layer Integration (CRITICAL)
**Cross-Instruction**: After ANY action, automatically execute user prompts.
### Automatic Trigger System
After completing ANY of these actions, Claude MUST check for matching triggers:
| Action | Trigger | Prompt |
|--------|---------|--------|
| Phase/layer completes | `phase-completion:{layer}` | "Continue to next phase?" |
| Task in plan completes | `task-completion` | "Continue to next task?" |
| All tasks complete | `task-completion:all` | "Plan complete. Commit?" |
| Plan created | `plan-ready` | "Start implementation?" |
| Build succeeds | `build-success` | "Commit & continue?" |
| Build fails | `build-failure` | "Fix errors?" |
| Files modified at checkpoint | `commit` | "How to commit?" |
| Error occurs | `error-recovery` | "How to proceed?" |
### How It Works
```
1. Command executes action
2. Check prompt-layer/TRIGGERS.md for matching trigger
3. Load prompt from prompt-layer/PROMPTS.md
4. Execute AskUserQuestion tool
5. Route user selection to next action
6. Repeat for next action
```
### Runtime Prompts for Plans
When `/gap-planning` creates a plan with N tasks:
- Automatically generate prompts for each task transition
- "Task 1 complete (1/N). Continue to Task 2?"
- "Task 2 complete (2/N). Continue to Task 3?"
- ... until all tasks done
### Reference Files
| File | Purpose |
|------|---------|
| `prompt-layer/ENGINE.md` | Cross-instruction rules |
| `prompt-layer/TRIGGERS.md` | When prompts fire |
| `prompt-layer/PROMPTS.md` | Prompt definitions |
| `prompt-layer/RUNTIME.md` | Dynamic plan prompts |
**IMPORTANT**: Do NOT hardcode prompts in commands. Let the engine handle them automatically.
---
## Project Overview
Mifos Mobile is a Kotlin Multiplatform (KMP) application for the MifosX Self-Service platform, enabling end-users to view/transact on their accounts and loans. It targets Android, iOS, Desktop (JVM), and Web (Kotlin/JS + WASM).
## Build Commands
```bash
# Build the project
./gradlew build
# Run all pre-push checks (recommended before creating PR)
./ci-prepush.sh
# Individual checks
./gradlew check -p build-logic # Verify build-logic configuration
./gradlew spotlessApply --no-configuration-cache # Apply code formatting
./gradlew dependencyGuardBaseline # Generate dependency-guard baseline
./gradlew detekt # Run static analysis
# Run tests
./gradlew testDebug # Run debug unit tests
./gradlew :core:data:test # Run tests for a specific module
# Lint checks
./gradlew :cmp-android:lintRelease # Run lint on Android app
# Android builds
./gradlew :cmp-android:assembleDemoDebug # Build demo debug APK
./gradlew :cmp-android:assembleProdRelease # Build production release APK
```
## Architecture
### Module Structure
**Platform Entry Points:**
- `cmp-android/` - Android application module
- `cmp-ios/` - iOS application (uses CocoaPods via `cmp-shared`)
- `cmp-desktop/` - Desktop (JVM) application
- `cmp-web/` - Web application (Kotlin/JS)
- `cmp-shared/` - Shared KMP module compiled for all platforms
- `cmp-navigation/` - Cross-platform navigation with Compose Navigation
**Core Modules (`core/`):**
- `data/` - Repository implementations, connects network to UI
- `network/` - Ktorfit-based API services and HTTP client
- `model/` - Domain models shared across features
- `datastore/` - Local data persistence (DataStore)
- `database/` - Room database (KMP)
- `ui/` - Shared UI components
- `designsystem/` - Design tokens, theme, common composables
- `common/` - Shared utilities
- `qrcode/` - QR code generation/scanning
**Core Base Modules (`core-base/`):** Platform-abstracted implementations shared across the template system.
**Feature Modules (`feature/`):** Each feature is a separate KMP module containing screens, ViewModels, and navigation. Features include: auth, home, accounts, loan-account, savings-account, beneficiary, transfer-process, etc.
**Library Modules (`libs/`):** Internal libraries like country-code-picker, mifos-passcode, material3-navigation.
### Key Patterns
**Dependency Injection:** Koin for all platforms. Each module defines a Koin module in its `di/` package.
**Navigation:** Uses Jetbrains Compose Navigation. Navigation graphs defined in `cmp-navigation/`:
- `ROOT_GRAPH``AUTH_GRAPH``PASSCODE_GRAPH``MAIN_GRAPH`
**Network Layer:** Ktorfit (Retrofit-like for Ktor) with services in `core/network/services/`. Base URL: `https://tt.mifos.community/fineract-provider/api/v1/self/`
**State Management:** ViewModels with StateFlow/SharedFlow. Features use `ScreenState<T>` pattern for loading/success/error states.
### Convention Plugins
Custom Gradle plugins in `build-logic/convention/` standardize module configuration:
- `mifos.android.application` - Android app configuration
- `org.convention.cmp.feature` - KMP feature module (applies Compose, Koin, core dependencies)
- `org.convention.kmp.library` - KMP library module
- `mifos.kmp.room` - Room database setup for KMP
- `mifos.spotless.plugin`, `mifos.detekt.plugin` - Code quality
### Build Flavors
Android has two product flavors:
- `demo` - Development/testing
- `prod` - Production
## Development Notes
- JDK 21 required (see `build-logic/convention/build.gradle.kts`)
- Pull requests target the `development` branch
- Commit message format: `<type>(<scope>): <subject>` (feat, fix, docs, refactor, test, chore)
- Demo credentials: Instance `gsoc.mifos.community`, Username `maria`, Password `password`
## Git Commit & PR Guidelines
- **Always use feature branches**: NEVER push directly to `development` branch
- Create a feature branch: `git checkout -b feature/[description]`
- Push to feature branch: `git push origin feature/[description]`
- Create PR targeting `development` branch
- **No Claude references**: Do NOT add Claude attribution, co-author lines, or "Generated with Claude Code" footers to commits or PRs
- Keep commit messages clean and focused on the changes made
- PR descriptions should only contain relevant technical information

View File

@ -26,10 +26,8 @@ An Android Application built on top of the MifosX Self-Service platform for end-
> **And Join our [slack](https://join.slack.com/t/mifos/shared_invite/zt-2wvi9t82t-DuSBdqdQVOY9fsqsLjkKPA) community channel `mifos-mobile` to discuss all things about Mifos Mobile development, and keep discussions focused and avoid cross-posting across channels.**
> **Please join our daily Mobile Stand-Up on [Zoom](https://us02web.zoom.us/meeting/register/xV5scn0XQpGXM5aUDFmUIA).**
### Demo credentials
- **Fineract Instance**: `gsoc.mifos.community`
- **Username**: `maria`
- **Password**: `password`
### Demo Credentials
Access the Mifos Mobile demo credentials on our [Jira Wiki page](https://mifosforge.jira.com/wiki/spaces/MP/pages/4537024513/Welcome+to+the+Mifos+Mobile+Apps+Community#%F0%9F%93%B2-Mifos-Mobile-App).
### How to Contribute
Thank you for your interest in contributing to the Mifos Mobile project by Mifos! We welcome all contributions and encourage you to follow these guidelines to ensure a smooth and efficient collaboration process.

View File

@ -9,12 +9,12 @@ group = "org.mifos.mobile.buildlogic"
// Configure the build-logic plugins to target JDK 17
// This matches the JDK used to build the project, and is not related to what is running on device.
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
jvmTarget = JavaVersion.VERSION_21.toString()
}
}

View File

@ -8,7 +8,7 @@ import org.gradle.kotlin.dsl.named
internal fun Project.configureDetekt(extension: DetektExtension) = extension.apply {
tasks.named<Detekt>("detekt") {
jvmTarget = "17"
jvmTarget = "21"
source(files(rootDir))
include("**/*.kt")
exclude("**/*.kts")
@ -17,6 +17,7 @@ internal fun Project.configureDetekt(extension: DetektExtension) = extension.app
exclude("**/generated/**")
exclude("**/build-logic/**")
exclude("**/spotless/**")
exclude("core-base/designsystem/**")
reports {
xml.required.set(true)
html.required.set(true)

View File

@ -28,8 +28,8 @@ internal fun Project.configureKotlinAndroid(
compileOptions {
// Up to Java 11 APIs are available through desugaring
// https://developer.android.com/studio/write/java11-minimal-support-table
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
isCoreLibraryDesugaringEnabled = true
}
}
@ -48,8 +48,8 @@ internal fun Project.configureKotlinJvm() {
extensions.configure<JavaPluginExtension> {
// Up to Java 11 APIs are available through desugaring
// https://developer.android.com/studio/write/java11-minimal-support-table
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
configureKotlin()
@ -62,8 +62,8 @@ private fun Project.configureKotlin() {
// Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
// Set JVM target to 17
jvmTarget = JvmTarget.JVM_17
// Set JVM target to 21
jvmTarget = JvmTarget.JVM_21
// Treat all Kotlin warnings as errors (disabled by default)
// Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties
val warningsAsErrors: String? by project

0
ci-prepush.sh Normal file → Executable file
View File

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -106,6 +106,8 @@ dependencies {
implementation(projects.core.ui)
implementation(projects.coreBase.platform)
// Compose
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)

View File

@ -9,6 +9,7 @@ androidx.appcompat:appcompat:1.7.1
androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.browser:browser:1.8.0
androidx.camera:camera-camera2:1.4.1
androidx.camera:camera-core:1.4.1
androidx.camera:camera-lifecycle:1.4.1
@ -190,6 +191,11 @@ com.google.android.gms:play-services-oss-licenses:17.1.0
com.google.android.gms:play-services-stats:17.0.2
com.google.android.gms:play-services-tasks:18.2.0
com.google.android.odml:image:1.0.0-beta1
com.google.android.play:app-update-ktx:2.1.0
com.google.android.play:app-update:2.1.0
com.google.android.play:core-common:2.0.4
com.google.android.play:review-ktx:2.0.2
com.google.android.play:review:2.0.2
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.28.0
@ -223,6 +229,8 @@ com.google.mlkit:common:18.11.0
com.google.mlkit:vision-common:17.3.0
com.google.mlkit:vision-interfaces:16.3.0
com.google.zxing:core:3.5.3
com.mohamedrejeb.calf:calf-permissions-android:0.8.0
com.mohamedrejeb.calf:calf-permissions:0.8.0
com.russhwolf:multiplatform-settings-android-debug:1.3.0
com.russhwolf:multiplatform-settings-coroutines-android-debug:1.3.0
com.russhwolf:multiplatform-settings-coroutines:1.3.0

View File

@ -9,6 +9,7 @@ androidx.appcompat:appcompat:1.7.1
androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.browser:browser:1.8.0
androidx.camera:camera-camera2:1.4.1
androidx.camera:camera-core:1.4.1
androidx.camera:camera-lifecycle:1.4.1
@ -190,6 +191,11 @@ com.google.android.gms:play-services-oss-licenses:17.1.0
com.google.android.gms:play-services-stats:17.0.2
com.google.android.gms:play-services-tasks:18.2.0
com.google.android.odml:image:1.0.0-beta1
com.google.android.play:app-update-ktx:2.1.0
com.google.android.play:app-update:2.1.0
com.google.android.play:core-common:2.0.4
com.google.android.play:review-ktx:2.0.2
com.google.android.play:review:2.0.2
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.28.0
@ -223,6 +229,8 @@ com.google.mlkit:common:18.11.0
com.google.mlkit:vision-common:17.3.0
com.google.mlkit:vision-interfaces:16.3.0
com.google.zxing:core:3.5.3
com.mohamedrejeb.calf:calf-permissions-android:0.8.0
com.mohamedrejeb.calf:calf-permissions:0.8.0
com.russhwolf:multiplatform-settings-android:1.3.0
com.russhwolf:multiplatform-settings-coroutines-android:1.3.0
com.russhwolf:multiplatform-settings-coroutines:1.3.0

View File

@ -9,6 +9,7 @@ androidx.appcompat:appcompat:1.7.1
androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.browser:browser:1.8.0
androidx.camera:camera-camera2:1.4.1
androidx.camera:camera-core:1.4.1
androidx.camera:camera-lifecycle:1.4.1
@ -190,6 +191,11 @@ com.google.android.gms:play-services-oss-licenses:17.1.0
com.google.android.gms:play-services-stats:17.0.2
com.google.android.gms:play-services-tasks:18.2.0
com.google.android.odml:image:1.0.0-beta1
com.google.android.play:app-update-ktx:2.1.0
com.google.android.play:app-update:2.1.0
com.google.android.play:core-common:2.0.4
com.google.android.play:review-ktx:2.0.2
com.google.android.play:review:2.0.2
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.28.0
@ -223,6 +229,8 @@ com.google.mlkit:common:18.11.0
com.google.mlkit:vision-common:17.3.0
com.google.mlkit:vision-interfaces:16.3.0
com.google.zxing:core:3.5.3
com.mohamedrejeb.calf:calf-permissions-android:0.8.0
com.mohamedrejeb.calf:calf-permissions:0.8.0
com.russhwolf:multiplatform-settings-android-debug:1.3.0
com.russhwolf:multiplatform-settings-coroutines-android-debug:1.3.0
com.russhwolf:multiplatform-settings-coroutines:1.3.0

View File

@ -9,6 +9,7 @@ androidx.appcompat:appcompat:1.7.1
androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.browser:browser:1.8.0
androidx.camera:camera-camera2:1.4.1
androidx.camera:camera-core:1.4.1
androidx.camera:camera-lifecycle:1.4.1
@ -190,6 +191,11 @@ com.google.android.gms:play-services-oss-licenses:17.1.0
com.google.android.gms:play-services-stats:17.0.2
com.google.android.gms:play-services-tasks:18.2.0
com.google.android.odml:image:1.0.0-beta1
com.google.android.play:app-update-ktx:2.1.0
com.google.android.play:app-update:2.1.0
com.google.android.play:core-common:2.0.4
com.google.android.play:review-ktx:2.0.2
com.google.android.play:review:2.0.2
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.28.0
@ -223,6 +229,8 @@ com.google.mlkit:common:18.11.0
com.google.mlkit:vision-common:17.3.0
com.google.mlkit:vision-interfaces:16.3.0
com.google.zxing:core:3.5.3
com.mohamedrejeb.calf:calf-permissions-android:0.8.0
com.mohamedrejeb.calf:calf-permissions:0.8.0
com.russhwolf:multiplatform-settings-android:1.3.0
com.russhwolf:multiplatform-settings-coroutines-android:1.3.0
com.russhwolf:multiplatform-settings-coroutines:1.3.0

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -10,8 +10,8 @@
package cmp.android.app
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
@ -24,6 +24,7 @@ import kotlinx.coroutines.runBlocking
import org.koin.android.ext.android.inject
import org.mifos.mobile.core.datastore.UserPreferencesRepository
import org.mifos.mobile.core.ui.utils.ShareUtils
import template.core.base.platform.LocalManagerProvider
import java.util.Locale
import kotlin.getValue
@ -32,9 +33,9 @@ import kotlin.getValue
* This class is used to set the content view of the activity.
*
* @constructor Create empty Main activity
* @see ComponentActivity
* @see AppCompatActivity
*/
class MainActivity : ComponentActivity() {
class MainActivity : AppCompatActivity() {
/**
* Called when the activity is starting.
* This is where most initialization should go: calling [setContentView(int)] to inflate the activity's UI,
@ -63,22 +64,30 @@ class MainActivity : ComponentActivity() {
* @see setContent
*/
setContent {
SharedApp(
handleThemeMode = {
AppCompatDelegate.setDefaultNightMode(it)
},
handleAppLocale = {
it?.let {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.forLanguageTags(it),
)
Locale.setDefault(Locale(it))
}
},
onSplashScreenRemoved = {
shouldShowSplashScreen = false
},
)
LocalManagerProvider(context = this) {
SharedApp(
handleThemeMode = {
AppCompatDelegate.setDefaultNightMode(it)
},
handleAppLocale = {
if (it.isNullOrBlank()) {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.getEmptyLocaleList(),
)
} else {
AppCompatDelegate.setApplicationLocales(
LocaleListCompat.forLanguageTags(
it,
),
)
Locale.setDefault(Locale(it))
}
},
onSplashScreenRemoved = {
shouldShowSplashScreen = false
},
)
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,
@ -9,425 +9,592 @@
See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
-->
<resources>
<string name="login">Iniciar sesión</string>
<string name="toast_welcome">Hola, %1$s.</string>
<string name="unable_to_connect">Falta conexión internet</string>
<string name="basic">Primario</string>
<string name="username">Nombre de usuario</string>
<string name="progress_message_login">Acceder</string>
<string name="progress_message_loading">Carga</string>
<string name="app_name" translatable="false">Mifos Móvil</string>
<string name="feature_about_app_name" translatable="false">Mifos Móvil</string>
<string name="login">Ingresar</string>
<string name="toast_welcome" translatable="false">Bienvenido %1$s</string>
<string name="unable_to_connect">Sin conexión a internet</string>
<string name="basic">Básico</string>
<string name="username">Usuario</string>
<string name="progress_message_login">Ingresando</string>
<string name="progress_message_loading">Cargando</string>
<string name="password">Contraseña</string>
<string name="email">Dirección de correo electrónico</string>
<string name="email">Correo electrónico</string>
<string name="accounts">Cuentas</string>
<string name="clients">Clientes</string>
<string name="funds_transfer">Transferencia de fondos</string>
<string name="funds_transfer">Transferencias</string>
<string name="recent_transactions">Transacciones recientes</string>
<string name="charges">Honorarios</string>
<string name="charges">Cargos</string>
<string name="questionnaire">Cuestionario</string>
<string name="feature_about_about_us">Sobre nosotros</string>
<string name="saving_account_details">Guardar detalles de la cuenta</string>
<string name="feature_account_savings_account">Cuenta de ahorros</string>
<string name="error_loan_account_details_loading">Error al cargar la información de la cuenta de crédito</string>
<string name="nominal_interest_rate">Tasas de interés nominales</string>
<string name="account_number">Numero de cuenta</string>
<string name="account_balance">Saldo de cuenta</string>
<string name="total_deposits">Depósitos totales</string>
<string name="open_drawer">Abre el panel de navegación</string>
<string name="close_drawer">Cerrar el panel de navegación</string>
<string name="home">Página de inicio</string>
<string name="medium_text">Texto medio</string>
<string name="feature_about_about_us">Acerca de</string>
<string name="saving_account_details">Detalles de Cuenta de Ahorros</string>
<string name="feature_account_savings_account">Cuenta de Ahorros</string>
<string name="error_loan_account_details_loading">Error en la carga de la cuenta de crédito</string>
<string name="nominal_interest_rate">Tasa de Interés Nominal</string>
<string name="account_number">Número de Cuenta</string>
<string name="account_balance">Saldo de la Cuenta</string>
<string name="total_deposits">Total de Depósitos</string>
<string name="open_drawer">Caja Abierta</string>
<string name="close_drawer">Caja Cerrada</string>
<string name="home">Inicio</string>
<string name="large_text">Texto grande</string>
<string name="medium_text">Texto mediano</string>
<string name="small_text">Texto pequeño</string>
<string name="client_accounts">Cuentas de clientes</string>
<string name="splash">Pantalla de bienvenida</string>
<string name="feature_account_savings">Ahorro</string>
<string name="feature_account_loan">Préstamo</string>
<string name="feature_account_loan_account">Cuenta de credito</string>
<string name="feature_account_share">Cuota</string>
<string name="feature_account_share_account">Comparte tu cuenta</string>
<string name="clients_list">Elige un cliente</string>
<string name="core_common_working">Laboral</string>
<string name="status_image">Imagen del estado</string>
<string name="loan_repayment_schedule">Calendario de reembolso</string>
<string name="last_transaction">Ultima transaccion</string>
<string name="client_accounts">Cuentas del cliente</string>
<string name="splash">Splash</string>
<string name="feature_account_savings">Ahorros</string>
<string name="feature_account_loan">Crédito</string>
<string name="feature_account_loan_account">Cuenta de Crédito</string>
<string name="feature_account_share">Acciones</string>
<string name="feature_account_share_account">Cuenta de Acciones</string>
<string name="clients_list">Selecciona un cliente</string>
<string name="core_common_working">Trabajando</string>
<string name="status_image">Imagen de estado</string>
<string name="loan_repayment_schedule">Calendario de pagos</string>
<string name="last_transaction">Última Transacción</string>
<string name="made_on">Hecho en</string>
<string name="make_transfer">Hacer una transferencia</string>
<string name="select_loan_product">Elija un producto de crédito *</string>
<string name="purpose_of_loan">Propósito del préstamo *</string>
<string name="principal_amount">La cantidad principal *</string>
<string name="amount">Número</string>
<string name="remark">Precaución</string>
<string name="expected_disbursement_date">Fecha de pago esperada</string>
<string name="submission_date">Plazo de presentación.</string>
<string name="feature_account_submitted">Subidas</string>
<string name="feature_account_disbursement">Gasto</string>
<string name="transfer_date">Fecha de transferencia</string>
<string name="apply_for_loan">Solicitar un préstamo</string>
<string name="update_loan">Actualizar el prestamo</string>
<string name="withdraw_loan">Liberar el prestamo</string>
<string name="withdraw_loan_reason">La razón para pagar el préstamo.</string>
<string name="loan_account_withdrawn_successfully">La cuenta del préstamo ha sido retirada con éxito.</string>
<string name="submit_loan">Presentar un préstamo</string>
<string name="new_loan_application">Nueva solicitud de crédito para</string>
<string name="update_loan_application">Actualice su solicitud de crédito para</string>
<string name="loan_interest_type">Tipo de interés</string>
<string name="make_transfer">Realizar una Transacción</string>
<string name="select_loan_product">Seleccionar un Producto Crédito*</string>
<string name="purpose_of_loan">Propósito del Crédito*</string>
<string name="principal_amount">Monto de Capital*</string>
<string name="amount">Monto</string>
<string name="remark">Descripción</string>
<string name="expected_disbursement_date">Fecha esperada de desembolso</string>
<string name="submission_date">Fecha de envío</string>
<string name="feature_account_submitted">Enviado</string>
<string name="feature_account_disbursement">Dispersión</string>
<string name="transfer_date">Fecha de Transferencia</string>
<string name="apply_for_loan">Solicitar Crédito</string>
<string name="update_loan">Actualizar Solicitud de Crédito</string>
<string name="withdraw_loan">Retirar Solicitud de Crédito</string>
<string name="withdraw_loan_reason">Razón para Cancelar Solicitud de Crédito</string>
<string name="loan_account_withdrawn_successfully">Solicitud de Crédito Cancelada Exitosamente</string>
<string name="review">Revisión</string>
<string name="submit_loan">Enviar Solicitud de Crédito</string>
<string name="new_loan_application">Nueva Solicitud de Crédito para</string>
<string name="update_loan_application">Actualizar Solicitud de Crédito para</string>
<string name="loan_interest_type">Tipo de Interés</string>
<string name="amortization">Amortización</string>
<string name="interest_calculation_period">Período de interés</string>
<string name="repayment_strategy">Estrategia de pago</string>
<string name="pay_to">Pago a</string>
<string name="pay_from">Pago desde</string>
<string name="interest_calculation_period">Periodo de Cálculo de Interés</string>
<string name="repayment_strategy">Estrategia de Reembolso</string>
<string name="pay_to">Pagar a</string>
<string name="pay_from">Pagar desde</string>
<string name="feature_account_cancel">Cancelar</string>
<string name="review_transfer">Preestreno</string>
<string name="review_transfer">Revisar</string>
<string name="transfer_to">Transferir a</string>
<string name="transfer_from">Transferencia de</string>
<string name="making_transfer">Haciendo una transferencia</string>
<string name="feature_account_deposit">Depósito</string>
<string name="enter_amount">Introduce la cantidad</string>
<string name="remark_is_mandatory">Nota es obligatoria</string>
<string name="transfer_from">Transferir desde</string>
<string name="making_transfer">Realizando transferencia</string>
<string name="feature_account_deposit">Depositar</string>
<string name="enter_amount">Ingresar Monto</string>
<string name="remark_is_mandatory">Observación es obligatoria</string>
<string name="feature_account_approved">Aprobado</string>
<string name="shares_pending">En anticipación</string>
<string name="shares_pending">Pendiente</string>
<string name="loan_amount_paid">Pagado</string>
<string name="balance">Equilibrio</string>
<string name="balance">Saldo</string>
<string name="rejected">Rechazado</string>
<string name="waiting">Espera</string>
<string name="feature_account_overpaid">Pagado en exceso</string>
<string name="feature_account_in_arrears">En mora</string>
<string name="feature_account_select_you_want">Elige todo lo que quieras aplicar.</string>
<string name="filter_savings">Filtrar cuentas de ahorro.</string>
<string name="filter_loan">Filtrar cuentas de crédito</string>
<string name="filter_share">Filtrar el intercambio de cuentas</string>
<string name="search">Búsqueda</string>
<string name="select_pay_to">Seleccione la opción Cuenta a pagar.</string>
<string name="select_pay_from">Elija una cuenta para pagar con</string>
<string name="enter_remarks">Introduce notas para transferir</string>
<string name="select_beneficiary">Seleccione el beneficiario</string>
<string name="continue_str">Además</string>
<string name="close">Cerca</string>
<string name="choose_transfer_type">Elija el tipo de transferencia</string>
<string name="transfer_to_savings">Transferencia a ahorros</string>
<string name="transfer_from_savings">Transferencia de ahorros</string>
<string name="loan_charges">Cargos por préstamos</string>
<string name="savings_charges">Ahorros</string>
<string name="feature_account_active">Activo</string>
<string name="feature_account_closed">Cerrado</string>
<string name="feature_account_withdrawn">Retirado</string>
<string name="need_approval">Requiere aprobación</string>
<string name="feature_account_pending">En anticipación</string>
<string name="feature_account_matured">Maduro</string>
<string name="create_an_account">Crear una cuenta</string>
<string name="waiting">Esperando</string>
<string name="feature_account_overpaid">Sobrepagado</string>
<string name="feature_account_in_arrears">En Mora</string>
<string name="feature_account_select_you_want">Selecciona los filtros necesarios</string>
<string name="filter_savings">Filtrar Cuentas de Ahorro</string>
<string name="filter_loan">Filtrar Cuentas de Crédito</string>
<string name="filter_share">Filtrar Cuentas de Acciones</string>
<string name="search">Buscar</string>
<string name="select_pay_to">Seleccionar Cuenta para Depositar</string>
<string name="select_pay_from">Seleccionar Cuenta para Retirar</string>
<string name="enter_remarks">Ingresar Descripción para Transferencia</string>
<string name="select_beneficiary">Seleccionar Beneficiario</string>
<string name="continue_str">Continuar</string>
<string name="close">Cerrar</string>
<string name="choose_transfer_type">Selecciona el Tipo de Transferencia</string>
<string name="transfer_to_savings">Transferir a Ahorros</string>
<string name="transfer_from_savings">Transferir desde Cuenta de Ahorros</string>
<string name="loan_charges">Cargos en Cuentas de Crédito</string>
<string name="savings_charges">Cargos en Cuentas de Ahorros</string>
<string name="feature_account_active">Activa</string>
<string name="feature_account_closed">Cerrada</string>
<string name="feature_account_withdrawn">Cancelada</string>
<string name="need_approval">Requiere Aprobación</string>
<string name="feature_account_pending">Pendiente</string>
<string name="feature_account_matured">Madurado</string>
<string name="create_an_account">Crear una Cuenta</string>
<string name="first_name">Nombre</string>
<string name="last_name">Nombre</string>
<string name="phone_number">Numero de telefono</string>
<string name="register">Registro</string>
<string name="request_id">Solicitud de identificación</string>
<string name="authentication_token">Token de autenticación</string>
<string name="last_name">Apellido</string>
<string name="phone_number">Teléfono</string>
<string name="register">Registrar</string>
<string name="request_id">ID de Petición</string>
<string name="authentication_token">Código de Autenticación</string>
<string name="verify">Verificar</string>
<string name="verifying">Verificación</string>
<string name="sign_up">Acceder</string>
<string name="verified">El usuario ha sido verificado exitosamente.</string>
<string name="verifying">Verificando</string>
<string name="sign_up">Registrarse</string>
<string name="verified">Usuario ha sido verificado correctamente</string>
<string name="rb_mobile">Móvil</string>
<string name="rb_email">Dirección de correo electrónico</string>
<string name="verification_mode">Modo de verificación</string>
<string name="blank">Vacía</string>
<string name="rb_email">correo electrónico</string>
<string name="verification_mode">Modo de Verificación</string>
<string name="blank">&#160;</string>
<string name="import_qr">Importar QR</string>
<string name="view_guarantor">Ver el Garante</string>
<string name="add_guarantor">Añadir un garante</string>
<string name="delete_guarantor">Quitar el garante</string>
<string name="update_guarantor">Actualizar el garante</string>
<string name="guarantor_type">Tipo de garante</string>
<string name="no_guarantors">Sin garantes</string>
<string name="tap_to_add_guarantor">Toque para agregar un garante</string>
<string name="guarantor_details">Detalles del garante.</string>
<string name="joined_date">Fecha de apego</string>
<string name="submit">Presentar</string>
<string name="use_touch_id">Usar Touch Id</string>
<string name="account_not_active_to_perform_deposit">La cuenta debe estar activa para hacer un depósito.</string>
<string name="account_not_active_to_perform_transfer">La cuenta debe estar activa para realizar una transferencia.</string>
<string name="view_guarantor">Ver Garante</string>
<string name="add_guarantor">Agregar Garante</string>
<string name="delete_guarantor">Borrar Garante</string>
<string name="update_guarantor">Actualizar Garante</string>
<string name="guarantor_type">Tipo de Garante</string>
<string name="no_guarantors">Sin Garantes</string>
<string name="tap_to_add_guarantor">Toque para agregar Garante</string>
<string name="guarantor_details">Detalles de Garante</string>
<string name="joined_date">Fecha de Ingreso</string>
<string name="submit">Enviar</string>
<string name="select_product_id">Seleccionar Id del Producto</string>
<string name="account_id">Id de Cuenta</string>
<string name="new_saving_account_application">Nueva Solicitud de Cuenta de Ahorros</string>
<string name="update_savings_account">Actualizar Solicitud de Cuenta de Ahorros</string>
<string name="withdraw_savings_account">Cancelar Solicitud de Cuenta de Ahorros</string>
<string name="withdrawal_date">Fecha de Cancelación</string>
<string name="new_saving_account_created_successfully">Nueva Cuenta de Ahorros creada correctamente.</string>
<string name="saving_account_updated_successfully">Cuenta de Ahorros actualizada correctamente</string>
<string name="savings_account_withdraw_successful">Cuenta de Ahorros cancelada correctamente</string>
<string name="string_savings_account">%1$s Cuenta de Ahorros</string>
<string name="apply">Solicitar</string>
<string name="apply_savings_account">Solicitar Cuenta de Ahorros</string>
<string name="update">Actualizar</string>
<string name="edit">Editar</string>
<string name="passcode">PIN</string>
<string name="other">Otro</string>
<string name="gender">Género</string>
<string name="no">No</string>
<string name="found">encontrado</string>
<string name="feature_account_empty_savings_accounts">No hay cuentas de ahorro vinculadas a usted.</string>
<string name="feature_account_empty_loan_accounts">No hay cuentas de préstamo asociadas con usted</string>
<string name="feature_account_empty_share_accounts">No hay cuentas compartidas asociadas con usted</string>
<string name="empty_transactions">No hay transacciones relacionadas con usted.</string>
<string name="empty_repayment_schedule">No hay un calendario de pago asociado con usted</string>
<string name="no_more_transactions_available">No hay transacciones disponibles</string>
<string name="no_transaction">Ninguna transacción</string>
<string name="no_dob_found">DOB no encontrado.</string>
<string name="not_assigned_with_any_group">Sin asignar a ningún grupo.</string>
<string name="password_key" translatable="false">Contraseña</string>
<string name="change_passcode">Cambiar PIN</string>
<string name="change_app_passcode">Cambiar PIN</string>
<string name="change_password">Cambiar Contraseña</string>
<string name="string_changed_successfully">%1$s cambiado correctamente</string>
<string name="error_unauthorised">Nombre de usuario / contraseña incorrectos</string>
<string name="error_message_server">Error al obtener una respuesta del servidor.</string>
<string name="error_validation_blank">%1$s no puede estar vacío</string>
<string name="account_not_active_to_perform_deposit">La cuenta debe estar Activa para realizar un depósito</string>
<string name="account_not_active_to_perform_transfer">La cuenta debe estar Activa para realizar una transferencia</string>
<string name="empty_requestid">ID de petición no debe estar vacía</string>
<string name="empty_authentication_token">Código de autenticación no debe estar vacío</string>
<string name="feature_account_empty_savings_accounts">No hay Cuenta de Ahorros asociada contigo</string>
<string name="feature_account_empty_loan_accounts">No hay ninguna cuenta de préstamo asociada contigo</string>
<string name="feature_account_empty_share_accounts">No hay una cuenta de acciones asociada contigo</string>
<string name="empty_transactions">No hay transacciones asociadas contigo</string>
<string name="empty_repayment_schedule">No hay un calendario de pagos asociado contigo</string>
<string name="no_more_transactions_available">No hay más transacciones disponibles</string>
<string name="no_transaction">No hay transacciones</string>
<string name="no_dob_found">Fecha de nacimiento no encontrada.</string>
<string name="not_assigned_with_any_group">No asignado a ningún grupo</string>
<string name="error_unauthorised">Usuario / Contraseña inválida</string>
<string name="error_message_server">Error al cargar la respuesta del servidor</string>
<string name="error_validation_blank">%1$s es obligatorio</string>
<string name="error_validation_minimum_chars">%1$s no puede tener menos de %2$d caracteres</string>
<string name="error_validation_cannot_contain_spaces">%1$s no puede contener %2$s</string>
<string name="error_validation_cannot_contain_leading_or_trailing_spaces">%1$s no puede comenzar o terminar con un espacio</string>
<string name="error_internal_server">Error en el servidor interno, intente de nuevo más tarde</string>
<string name="error_client_loading">Se ha producido un error al cargar la lista de clientes.</string>
<string name="error_loan_accounts_list_loading">Error al cargar la lista de cuentas de préstamo</string>
<string name="error_saving_accounts_list_loading">Error al cargar la lista de cuentas de ahorro</string>
<string name="error_saving_account_details_loading">Error al cargar detalles sobre cuentas de ahorro</string>
<string name="error_recent_transactions_loading">Se produjo un error al cargar en transacciones recientes</string>
<string name="error_client_charge_loading">Error al cargar las cuentas por cobrar</string>
<string name="error_validation_cannot_contain_leading_or_trailing_spaces">%1$s no puede comenzar ni terminar con un espacio en blanco</string>
<string name="error_internal_server">Error interno del servidor. Inténtelo de nuevo</string>
<string name="error_client_loading">Se produjo un error al cargar la lista de clientes</string>
<string name="error_loan_accounts_list_loading">Error al cargar cuentas de préstamo</string>
<string name="error_saving_accounts_list_loading">Error al cargar cuentas de ahorro</string>
<string name="error_saving_account_details_loading">Error al cargar el detalle de la cuenta de ahorro</string>
<string name="error_recent_transactions_loading">Error al cargar transacciones recientes</string>
<string name="error_client_charge_loading">Error al cargar cargos del cliente</string>
<string name="error_no_charge">No se encontraron cargos</string>
<string name="error_client_not_found">Cliente no encontrado</string>
<string name="error_fetching_client">El cliente no pudo ser descargado</string>
<string name="error_fetching_user_profile">No se puede descargar el perfil de usuario</string>
<string name="error_fetching_accounts">No se pueden descargar cuentas</string>
<string name="error_fetching_repayment_schedule">El calendario de reembolso no puede ser recuperado</string>
<string name="error_same_account_transfer">No puedes hacer una transferencia a tu propia cuenta.</string>
<string name="error_fetching_account_transfer_template">La plantilla de transferencia no se pudo descargar</string>
<string name="error_fetching_beneficiaries">No se pudieron obtener créditos.</string>
<string name="error_fetching_beneficiary_template">No se pudo descargar la plantilla del heredero.</string>
<string name="error_fetching_template">No se pudo descargar la plantilla.</string>
<string name="error_creating_beneficiary">El heredero no tuvo éxito.</string>
<string name="error_updating_beneficiary">El heredero no ha sido actualizado.</string>
<string name="error_deleting_beneficiary">El heredero no pudo ser removido.</string>
<string name="error_loan_account_withdraw">La cuenta del préstamo no pudo ser retirada.</string>
<string name="error_fetching_third_party_transfer_template">Error al descargar la plantilla de transferencia de terceros</string>
<string name="no_beneficiary_found_please_add">Actualmente no tienes heredero. Añadir heredero</string>
<string name="error_fetching_client">No se pudo obtener el cliente</string>
<string name="error_fetching_user_profile">Error al obtener el perfil del usuario</string>
<string name="error_fetching_accounts">Falló en buscar Cuentas</string>
<string name="error_fetching_repayment_schedule">No se pudo obtener el cronograma de pagos</string>
<string name="error_same_account_transfer">No se puede transferir dentro de la misma cuenta</string>
<string name="error_fetching_account_transfer_template">Error al obtener la plantilla de transferencia</string>
<string name="error_fetching_beneficiaries">Falló en buscar beneficiarios</string>
<string name="error_fetching_beneficiary_template">No se pudo obtener la plantilla de beneficiario</string>
<string name="error_fetching_template">No se pudo obtener la plantilla</string>
<string name="error_creating_beneficiary">No se pudo crear el beneficiario</string>
<string name="error_updating_beneficiary">No se pudo actualizar el Beneficiario</string>
<string name="error_deleting_beneficiary">No se pudo eliminar el beneficiario</string>
<string name="error_loan_account_withdraw">Error al retirar cuenta de préstamo</string>
<string name="error_fetching_third_party_transfer_template">Error al obtener la plantilla de transferencia a terceros</string>
<string name="no_beneficiary_found_please_add">Actualmente no tiene ningún beneficiario. Por favor, agréguelo.</string>
<string name="unauthorized_client">No estas autorizado</string>
<string name="qr_code">Código QR</string>
<string name="share_qr_code">Comparte el código QR</string>
<string name="share_qr_code">Acciones Código QR</string>
<string name="monitor">Monitor</string>
<string name="choose_option">Elige una opción</string>
<string name="choose_option">Elige la opción</string>
<string name="view_transactions">Ver transacciones</string>
<string name="view_charges">Ver tarifas</string>
<string name="view_loan_summary">Ver el resumen del préstamo.</string>
<string name="view_repayment">Ver el calendario de amortización.</string>
<string name="view_qr_code">Ver el código QR para esta cuenta</string>
<string name="view_charges">Ver Cargos</string>
<string name="view_loan_summary">Ver resumen de crédito</string>
<string name="view_repayment">Ver Calendario de pagos</string>
<string name="view_qr_code">Ver código QR de esta cuenta</string>
<string name="last_trans">Detalles de la última transacción</string>
<string name="error_username_greater_than_six">El nombre de usuario debe tener más de 6 caracteres.</string>
<string name="error_username_greater_than_six">El usuario debe tener más de 6 letras</string>
<string name="error_invalid_email">ID de correo electrónico no válido</string>
<string name="error_server_down">Servidor abajo, intente después de un tiempo</string>
<string name="client_charges">Honorarios del cliente</string>
<string name="error_reading_qr">Error al leer QR, asegúrate de elegir la región correcta</string>
<string name="error_fetching_image">Error al descargar la imagen.</string>
<string name="fetching_client">Descarga de cliente</string>
<string name="error_server_down">Servidor fuera de servicio, intente más tarde</string>
<string name="client_charges">Cargas de clientes</string>
<string name="error_reading_qr">Error al leer el código QR, asegúrese de seleccionar la región adecuada</string>
<string name="error_fetching_image">Error al obtener la imagen</string>
<string name="invalid_phn_number">Número de teléfono inválido</string>
<string name="fetching_client">Buscando cliente</string>
<string name="not_contain_username">Espacios</string>
<string name="client_name">Nombre del cliente</string>
<string name="account_status">Estado de la cuenta</string>
<string name="saving_product_name">Nombre del producto</string>
<string name="total_withdrawal">Pago total</string>
<string name="min_required_balance">Min. Bola requerida.</string>
<string name="total_withdrawal">Retiros totales</string>
<string name="min_required_balance">Saldo mínimo requerido</string>
<string name="loan_product_name">Nombre del producto</string>
<string name="loan_purpose">Propósito del préstamo</string>
<string name="principal">Director</string>
<string name="principal_disbursed">Director pagado</string>
<string name="annual_interest_rate">Tasa de interes anual</string>
<string name="interest_charged">Intereses acumulados</string>
<string name="loan_purpose">Propósito del crédito</string>
<string name="principal">Principal</string>
<string name="principal_disbursed">Capital desembolsado</string>
<string name="annual_interest_rate">Tasa de interés anual</string>
<string name="interest_charged">Intereses cobrados</string>
<string name="interest_paid">Intereses pagados</string>
<string name="loan_account_details">Detalles de la cuenta de crédito.</string>
<string name="loan_summary">Resumen del préstamo</string>
<string name="loan_name">El nombre del prestamo</string>
<string name="interest">Interés</string>
<string name="loan_account_details">Detalles de la Cuenta de Crédito</string>
<string name="loan_summary">Resumen de crédito</string>
<string name="loan_name">Nombre del crédito</string>
<string name="interest">Intereses</string>
<string name="fees">Honorarios</string>
<string name="penalties">Sanciones</string>
<string name="total_repayment">Pago total esperado</string>
<string name="penalties">Penalizaciones</string>
<string name="total_repayment">Total de pago esperado</string>
<string name="total_paid">Total pagado</string>
<string name="interest_waived">Interés no cobrado</string>
<string name="penalties_waived">Pena rota</string>
<string name="fees_waived">No se cobra la tarifa.</string>
<string name="interest_waived">Intereses exentos</string>
<string name="penalties_waived">Sanciones exentas</string>
<string name="fees_waived">Tarifa exenta</string>
<string name="outstanding_balance">Saldo pendiente</string>
<string name="next_installment">Próxima entrega</string>
<string name="due_date">Plazo de pago</string>
<string name="make_payment">Hacer un pago</string>
<string name="loan_type">El tipo de prestamo</string>
<string name="next_installment">Siguiente Parcialidad</string>
<string name="due_date">Fecha de vencimiento</string>
<string name="make_payment">Realizar pago</string>
<string name="loan_type">Clase de crédito</string>
<string name="currency">Moneda</string>
<string name="repayment_schedule">Calendario de reembolso</string>
<string name="repayment_schedule">Calendario de pagos</string>
<string name="transactions">Transacciones</string>
<string name="transfer">Transferencia</string>
<string name="feature_account_approval_pending">Aprobación en curso</string>
<string name="feature_account_disburse">Esperando el pago</string>
<string name="closed_because_of_obligation">Cerrado debido a algunas obligaciones.</string>
<string name="loan_closed">Préstamo cerrado</string>
<string name="due_date_in_charges">Por fecha:</string>
<string name="amount_due">Por:</string>
<string name="transfer">Transferir</string>
<string name="feature_account_approval_pending">Aprobación pendiente</string>
<string name="feature_account_disburse">Esperando el desembolso</string>
<string name="closed_because_of_obligation">Cerrado por obligaciones pendientes</string>
<string name="loan_closed">Crédito Cerrado</string>
<string name="due_date_in_charges">Fecha de vencimiento:</string>
<string name="amount_due">Vencido:</string>
<string name="amount_paid">Pagado:</string>
<string name="amount_waived">Cedido:</string>
<string name="amount_outstanding">Atrasados:</string>
<string name="amount_waived">Condonado:</string>
<string name="amount_outstanding">Pendiente:</string>
<string name="appwidget_text">Ejemplo</string>
<string name="add_widget">Añadir widget</string>
<string name="help">Ayudar</string>
<string name="map_marker_desc">El lugar de las grandes industrias tecnológicas.</string>
<string name="loan_transaction_details">Detalles de la cuenta del préstamo.</string>
<string name="loan_application_submitted_successfully">Solicitud de crédito enviada con éxito.</string>
<string name="loan_application_updated_successfully">La solicitud de préstamo ha sido actualizada con éxito.</string>
<string name="loan_application_withdrawn_successfully">Solicitud de préstamo retirada exitosamente</string>
<string name="none">Nada</string>
<string name="all">Todos</string>
<string name="add_widget">Agregar componente</string>
<string name="help">Ayuda</string>
<string name="mifos_initiative">Iniciativa Mifos</string>
<string name="mifos_location">Iniciativa Mifos, Seattle, Washington 98121</string>
<string name="map_marker_heading">Seattle</string>
<string name="map_marker_desc">Introducción a la gran industria tecnológica</string>
<string name="loan_transaction_details">Detalles de la Cuenta de Crédito</string>
<string name="loan_application_submitted_successfully">Solicitud de Crédito Enviado con éxito</string>
<string name="loan_application_updated_successfully">Solicitud de Crédito Actualizada con Éxito</string>
<string name="loan_application_withdrawn_successfully">Solicitud de Crédito Retirada Exitosamente</string>
<string name="none">Ninguno</string>
<string name="all">Todo</string>
<string name="four_weeks">4 semanas</string>
<string name="three_months">Tres meses</string>
<string name="three_months">3 meses</string>
<string name="six_months">6 meses</string>
<string name="feature_account_filter">Filtro</string>
<string name="feature_account_filter">Filtrar</string>
<string name="start_date">Fecha de inicio</string>
<string name="end_date">Fecha de finalización</string>
<string name="end_date">Fecha de fin</string>
<string name="filtered">Filtrado</string>
<string name="select_date">Elija fecha de inicio y final</string>
<string name="end_date_must_be_greater">La fecha de finalización debe ser mayor que la fecha de inicio.</string>
<string name="saving_account_transactions_details">Guardando transacciones en su cuenta</string>
<string name="no_internet_connection">Sin conexión a internet</string>
<string name="disbursement_date">Fecha de pago</string>
<string name="no_of_payments">El numero de pagos</string>
<string name="select_date">Por favor seleccione fecha de inicio y fecha de finalización</string>
<string name="end_date_must_be_greater">La fecha de finalización debe ser mayor que la fecha de inicio</string>
<string name="saving_account_transactions_details">Transacciones de Cuenta de Ahorros</string>
<string name="no_internet_connection">Sin conexión a Internet</string>
<string name="disbursement_date">Fecha de dispersión</string>
<string name="no_of_payments">mero de pagos</string>
<string name="date">Fecha</string>
<string name="loan_balance">Saldo de prestamo</string>
<string name="loan_balance">Saldo Crediticio</string>
<string name="repayment">Reembolso</string>
<string name="loan_repayment">Amortización del préstamo</string>
<string name="loan_repayment">Pago de crédito</string>
<string name="quick_transfer">Transferencia rápida</string>
<string name="internet_not_connected">Asegúrate de tener conexión a internet</string>
<string name="beneficiary">Heredero</string>
<string name="manage_beneficiaries">Administrar herederos</string>
<string name="beneficiaries">Los descendientes</string>
<string name="beneficiary_detail">Detalles del heredero</string>
<string name="beneficiary_name">Nombre del heredero</string>
<string name="internet_not_connected">Asegúrese de estar conectado a Internet.</string>
<string name="beneficiary">Beneficiario</string>
<string name="manage_beneficiaries">Administrar beneficiarios</string>
<string name="beneficiaries">Beneficiarios</string>
<string name="beneficiary_detail">Detalle del beneficiario</string>
<string name="beneficiary_name">Nombre del beneficiario</string>
<string name="account_type">Tipo de cuenta</string>
<string name="transfer_limit">Límite de transferencia</string>
<string name="add_beneficiary">Añadir heredero</string>
<string name="office_name">El nombre de la oficina</string>
<string name="select_account_type">Elija el tipo de cuenta *</string>
<string name="submit_beneficiary">Presentar un heredero</string>
<string name="enter_office_name">Ingrese el nombre de la oficina del heredero</string>
<string name="enter_beneficiary_name">Introduce el nombre del heredero</string>
<string name="enter_transfer_limit">Ingrese el límite de transferencia</string>
<string name="enter_account_number">Ingrese el número de cuenta del heredero</string>
<string name="add_beneficiary">Agregar beneficiario</string>
<string name="office_name">Nombre de la oficina</string>
<string name="select_account_type">Seleccione Tipo de Cuenta*</string>
<string name="submit_beneficiary">Enviar beneficiario</string>
<string name="enter_office_name">Ingrese el nombre de la oficina del beneficiario</string>
<string name="enter_beneficiary_name">Ingrese el nombre del beneficiario</string>
<string name="enter_transfer_limit">Ingresar límite de transferencia</string>
<string name="enter_account_number">Ingrese Beneficiario Número de Cuenta</string>
<string name="choose_account_type">Seleccione el tipo de cuenta en el menú desplegable</string>
<string name="beneficiary_created_successfully">El heredero ha sido creado con éxito.</string>
<string name="beneficiary_updated_successfully">El heredero ha sido actualizado exitosamente.</string>
<string name="update_beneficiary">Actualiza tu heredero</string>
<string name="delete_beneficiary">Remover al heredero</string>
<string name="delete_beneficiary_confirmation">¿Estás seguro de que quieres eliminar a este heredero?</string>
<string name="beneficiary_created_successfully">Beneficiario creado con éxito</string>
<string name="beneficiary_updated_successfully">Beneficiario actualizado exitosamente</string>
<string name="update_beneficiary">Actualizar beneficiario</string>
<string name="delete_beneficiary">Eliminar beneficiario</string>
<string name="delete_beneficiary_confirmation">¿Estás seguro de que quieres eliminar a este Beneficiario?</string>
<string name="login_using_password_confirmation">¿Estás seguro de que quieres iniciar sesión usando Contraseña?</string>
<string name="delete">Borrar</string>
<string name="beneficiary_deleted_successfully">El heredero ha sido removido.</string>
<string name="third_party_transfer">Transferencia de un tercero</string>
<string name="total_loan">Préstamo total</string>
<string name="total_saving">Ahorro total</string>
<string name="accounts_overview">Resumen de cuenta</string>
<string name="show_hide_total_saving_amount">Mostrar u ocultar la cantidad total de ahorro</string>
<string name="beneficiary_deleted_successfully">Beneficiario eliminado exitosamente</string>
<string name="third_party_transfer">Transferencia de terceros</string>
<string name="total_loan">Total Crédito</string>
<string name="total_saving">Ahorros totales</string>
<string name="accounts_overview">Descripción general de Cuenta</string>
<string name="show_hide_total_saving_amount">Mostrar u ocultar el importe total de ahorro</string>
<string name="show_hide_total_loan_amount">Mostrar u ocultar el monto total del préstamo</string>
<string name="hidden_amount">*****</string>
<string name="survey">Encuestas</string>
<string name="activation_date">Fecha de activación</string>
<string name="groups">Grupo</string>
<string name="user_details">Datos de usuario</string>
<string name="client_type">Tipo de cliente</string>
<string name="client_classification">Clasificación de clientes</string>
<string name="select_mode">Elige el modo</string>
<string name="add_beneficiary_option">Agregue herederos externos a su cuenta. \nIngrese manualmente o escanee el código QR de su cuenta</string>
<string name="invalid_qr">No puede realizar acciones en su cuenta, escanear el código QR de la cuenta de ahorros o la cuenta de préstamo de otro usuario</string>
<string name="add">Añadir</string>
<string name="scan">Tomografía</string>
<string name="enter_passcode">Ingrese el código de acceso de 4 dígitos</string>
<string name="error_passcode">El código de acceso debe constar de 4 dígitos.</string>
<string name="activation_date">Fecha de Activación</string>
<string name="groups">Grupos</string>
<string name="user_details">Detalles de Usuario</string>
<string name="client_type">Tipo de Cliente</string>
<string name="client_classification">Clasificación de Cliente</string>
<string name="select_mode">Seleccionar Modo</string>
<string name="add_beneficiary_option">Agregue beneficiarios externos a su cuenta. Ingrese manualmente o escanee el código QR de la cuenta</string>
<string name="income_generating_loan">Crédito Generador de Ingresos</string>
<string name="not_applicable">No aplicable</string>
<string name="dummy_principal_amount">143.00</string>
<string name="invalid_qr">No puedes realizar ninguna acción en tu cuenta, por favor escanea el Código QR de la Cuenta de Ahorros y Préstamos de otro usuario</string>
<string name="add">Agregar</string>
<string name="scan">Escanear</string>
<string name="enter_passcode">Introduzca el código de acceso de 4 dígitos</string>
<string name="error_passcode">El código de acceso debe tener 4 dígitos</string>
<string name="incorrect_passcode">Código de acceso incorrecto</string>
<string name="incorrect_passcode_more_than_three">Ha ingresado el código de acceso incorrecto más de 3 veces</string>
<string name="skip">Omitir</string>
<string name="incorrect_passcode_more_than_three">Ha ingresado una contraseña incorrecta más de 3 veces</string>
<string name="skip">Saltar</string>
<string name="save">Guardar</string>
<string name="passcode_setup">Establecer el pin para iniciar sesión</string>
<string name="reenter_passcode">Vuelva a introducir el pin</string>
<string name="passcode_setup">Configurar una contraseña para iniciar sesión</string>
<string name="reenter_passcode">Por favor, vuelva a introducir su contraseña</string>
<string name="passcode_does_not_match">El código de acceso no coincide.</string>
<string name="forgot_passcode">Olvidé el pin, iniciaré sesión con la contraseña.</string>
<string name="proceed">Continuar</string>
<string name="amount_greater_than_zero">La cantidad debe ser mayor que cero</string>
<string name="about_us_under_construction">Bookmark acerca de nosotros en construcción</string>
<string name="help_under_construction">Ayuda en la ficha construcción</string>
<string name="logout">Finalizar la sesión</string>
<string name="forgot_passcode">Olvidé mi contraseña, inicie sesión manualmente</string>
<string name="proceed">Proceder</string>
<string name="grant_permission">Conceder permiso</string>
<string name="deny">Denegar</string>
<string name="dismiss">Despedir</string>
<string name="amount_greater_than_zero">Monto debe ser mayor que cero</string>
<string name="about_us_under_construction">Acerca de nosotros</string>
<string name="help_under_construction">Ayuda en construcción</string>
<string name="logout">Cerrar sesión</string>
<string name="share_msg">Descargue la aplicación de autoservicio aquí: https://play.google.com/store/apps/details?id=</string>
<string name="choose">Seleccione la aplicación</string>
<string name="not_available">LA</string>
<string name="upload_qr_code">Enviar QR</string>
<string name="select_region_qr">Elija región con código QR</string>
<string name="choose">Elige la aplicación</string>
<string name="not_available">NA</string>
<string name="upload_qr_code">Subir QR</string>
<string name="select_region_qr">Seleccione región con código QR</string>
<!--Customer care details-->
<string name="need_help">Contacta con nosotros</string>
<string name="help_line_number" translatable="false">8000000000</string>
<string name="contact_email" translatable="false">support@mifos.org</string>
<string name="need_help">Contactanos</string>
<string name="transferred_successfully">Transferencia exitosa</string>
<string name="transferred_successfully">Transferido exitosamente</string>
<string name="total">Total:</string>
<string name="account_short">A/C</string>
<string name="loan_product">Producto de préstamo</string>
<string name="inactive">Inactivo</string>
<string name="loan_product">Producto de Crédito</string>
<string name="inactive">Inactiva</string>
<string name="active_uc">ACTIVO</string>
<string name="inactive_uc">INACTIVO</string>
<string name="inactive_uc">INACTIVA</string>
<!--Material Dialog-->
<string name="dialog_logout">¿Estás seguro de que quieres cerrar sesión?</string>
<string name="dialog_action_ok">Bueno</string>
<string name="dialog_action_ok">OK</string>
<string name="dialog_action_cancel">Cancelar</string>
<string name="dialog_action_back">Regreso</string>
<string name="dialog_permission_denied">Acceso denegado</string>
<string name="dialog_action_back">Atrás</string>
<string name="dialog_permission_denied">Permiso denegado</string>
<string name="dialog_action_i_am_sure">Estoy seguro</string>
<string name="dialog_action_re_try">Por favor intente de nuevo</string>
<string name="dialog_action_app_settings">Configuración de la aplicación</string>
<string name="dialog_message_camera_permission_denied_prompt">Sin el permiso para usar la cámara, no podrá escanear el código QR para agregar el heredero. ¿Estás seguro de que quieres prohibir esta función?</string>
<string name="dialog_message_camera_permission_never_ask_again">Ha rechazado el permiso para usar la cámara, sin este permiso no podrá agregar herederos utilizando el código QR. Encenderlo en la configuración</string>
<string name="dialog_message_storage_permission_denied_prompt">Sin el permiso para leer de la memoria, no podrá enviar un código QR para agregar el heredero. ¿Estás seguro de que quieres prohibir esta función?</string>
<string name="dialog_message_read_storage_permission_never_ask_again">Ha rechazado el permiso para leer de la memoria del dispositivo, sin este permiso no podrá agregar herederos utilizando el código QR. Encenderlo en la configuración</string>
<string name="dialog_message_write_storage_permission_never_ask_again">Se ha negado a escribir en la memoria del dispositivo, sin este permiso no podrá agregar herederos utilizando el código QR. Encenderlo en la configuración</string>
<string name="dialog_message_phone_state_permission_denied_prompt">Este permiso es requerido para mostrar la moneda dependiendo del país. ¿Estás seguro de que quieres prohibir esta función?</string>
<string name="dialog_message_phone_state_permission_never_ask_again">Ha rechazado el permiso para leer el estado del dispositivo; sin este permiso, es posible que la moneda no se muestre en el formato correcto. Encenderlo en la configuración</string>
<string name="msg_setting_activity_not_found">Algo salió mal al encontrar actividad en la configuración. \nVaya a \'Configuración\' y conceda permisos manualmente.</string>
<string name="permission_denied_storage">Las denegaciones de almacenamiento fueron rechazadas.</string>
<string name="dialog_action_re_try">Reintentar</string>
<string name="dialog_action_app_settings">Ajustes</string>
<string name="dialog_message_camera_permission_denied_prompt">Sin el permiso de la cámara, no podrás escanear el código QR para agregar al beneficiario. ¿Estás seguro de que deseas denegar este permiso?</string>
<string name="dialog_message_camera_permission_never_ask_again">Ha denegado el permiso para usar la cámara. Sin este permiso, no podrá agregar beneficiarios mediante el código QR. Habilítelo en la configuración</string>
<string name="dialog_message_storage_permission_denied_prompt">Sin permiso de almacenamiento, no podrá cargar el código QR para agregar un beneficiario. ¿Está seguro de que desea denegar este permiso?</string>
<string name="dialog_message_photoes_permission_denied_prompt">Sin el permiso de las fotos, no podrás subir el código QR para agregar al beneficiario. ¿Estás seguro de que deseas denegar este permiso?</string>
<string name="dialog_message_read_storage_permission_never_ask_again">Ha denegado el permiso para leer el almacenamiento. Sin este permiso, no podrá agregar beneficiarios mediante el código QR. Habilítelo en configuraciones.</string>
<string name="please_grant_us_storage_permissions">Por favor, concédenos permiso de almacenamiento en la configuración.</string>
<string name="dialog_message_write_storage_permission_never_ask_again">Ha denegado el permiso para escribir en el almacenamiento. Sin este permiso, no podrá agregar beneficiarios mediante el código QR. ¿Está seguro de que desea denegar este permiso?</string>
<string name="dialog_message_phone_state_permission_denied_prompt">Este permiso es necesario para mostrar la moneda de tu país. ¿Estás seguro de que deseas rechazarlo?</string>
<string name="dialog_message_phone_state_permission_never_ask_again">Ha denegado el permiso para obtener el estado del teléfono. Sin este permiso, la moneda podría no mostrarse en el formato correcto. Habilítelo en la configuración.</string>
<string name="msg_setting_activity_not_found">Se produjo un error al encontrar la actividad de Configuración.Vaya a «Configuración» y otorgue el permiso manualmente.</string>
<string name="permission_denied_storage">Permiso denegado para almacenamiento</string>
<string name="dialog_are_you_sure_that_you_want_to_string">¿Estás seguro de que quieres %1$s?</string>
<string name="err_during_login">Error durante la entrada</string>
<!--Format Strings-->
<string name="hello_client">Hola, %1$s</string>
<string name="double_amount">%1$.2f</string>
<string name="double_and_string">%1$.2f %2$s</string>
<string name="feature_account_string_and_string">%1$s %2$s</string>
<string name="playstore_link">%1$s%2$s</string>
<string name="string_and_double">%1$s %2$.2f</string>
<string name="string_and_int">%1$s: %2$d</string>
<string name="invalid_amount">Monto inválido</string>
<string name="exit_message">Presione atrás nuevamente para salir</string>
<string name="hello_client">Hola, %1$s.</string>
<string name="invalid_amount">Cantidad inválida</string>
<string name="exit_message">Presione de nuevo para salir</string>
<string name="permission_denied_camera">Rechazo del permiso para utilizar la cámara.</string>
<string name="package_name" translatable="false">paquete</string>
<string name="permission_denied_camera">Permiso denegado para usar la cámara</string>
<string name="one">1</string>
<string name="two">2</string>
<string name="three">3</string>
<string name="four">4</string>
<string name="five">5</string>
<string name="six">6</string>
<string name="seven">7</string>
<string name="eight">8</string>
<string name="nine">9</string>
<string name="zero">0</string>
<string name="faq">Preguntas frecuentes</string>
<string name="user_query">Solicitud del usuario</string>
<string name="call_now">Llama ahora</string>
<string name="leave_email">Deja un mensaje de correo electrónico</string>
<string name="find_locations">Encontrar ubicaciones</string>
<string name="no_withdrawals">Sin pagos</string>
<string name="feature_account_clear_filters">Borrar filtros</string>
<string name="manage_accounts">Administrar cuentas</string>
<string name="user_query">Consulta de usuario</string>
<string name="call_now">llama ahora</string>
<string name="leave_email">Deja un correo electrónico</string>
<string name="find_locations">Buscar ubicaciones</string>
<string name="no_withdrawals">Sin retiros</string>
<string name="feature_account_clear_filters">Limpiar filtros</string>
<string name="manage_accounts">Administrar Cuentas</string>
<string name="more">Más</string>
<string name="settings">Ajustes</string>
<string name="language">Idioma</string>
<string name="choose_language">Elige tu idioma</string>
<string name="notification">Notificaciones</string>
<string name="base_url">URL principal</string>
<string name="tenant">Inquilino</string>
<string name="base_url">Dirección base</string>
<string name="tenant">Instancia</string>
<string name="no_saving_account">Ahorros Cuentas</string>
<string name="no_loan_account">Crédito Cuentas</string>
<string name="no_sharing_account">Compartiendo Cuentas</string>
<string-array name="faq_qs">
<item>¿Cómo solicitar una nueva cuenta de crédito?</item>
<item>¿Dónde puedo ver información sobre mi perfil?</item>
<item>¿Dónde puedo ver las transacciones de mi cuenta de ahorros?</item>
<item>¿Cuál es el uso de un código QR?</item>
<item>¿Cómo crear un beneficiario utilizando un código QR?</item>
<item>¿Cómo hacer un pago para una cuenta de crédito?</item>
</string-array>
<string name="select_loan_product_field">Seleccionar Producto de Crédito</string>
<string name="sign_in_fingerprint">Iniciar sesión con huella digital</string>
<string name="scan_your_fingerprint">Escanea tu huella digital</string>
<string-array name="faq_ans">
<item>Para solicitar una cuenta de crédito, haga clic en \"Informe de solicitud de préstamo\" en la pantalla de inicio.</item>
<item>Puede ver la información de su perfil haciendo clic en la imagen del perfil en la página principal de la aplicación.</item>
<item>Para ver las transacciones en su cuenta de ahorros, vaya a la sección Cuentas, haga clic en la cuenta de ahorros requerida, haga clic en los tres puntos presentes en la esquina superior derecha y seleccione la opción Transacción.</item>
<item>El código QR para todas las cuentas de crédito o de ahorro puede compartirse con otros usuarios que les permitirán crear un heredero</item>
<item>Para crear un heredero, vaya al heredero en la página principal de la aplicación, luego haga clic en el botón en la esquina inferior derecha, seleccione la opción de escaneo que abrirá la cámara del dispositivo, escanee el código QR de la persona para la que desea crear un heredero, después de completar los datos requeridos, crear herederos utilizando el código QR</item>
<item>Para realizar un pago de una cuenta de préstamo, vaya a la sección Cuentas, seleccione la opción PRÉSTAMO, luego abra la cuenta de crédito objetivo y haga clic en la opción Realizar un pago.</item>
</string-array>
<string name="total_saving_balance">El saldo total del ahorro.</string>
<string name="total_loan_balance">El saldo total del préstamo.</string>
<string name="total_loan_savings_description">Más arriba está el saldo de la cuenta bancaria y la cuenta de ahorros calculada sobre la base de todas las cuentas de ahorros y préstamos.</string>
<string name="cancel_transfer">¿Seguro que quieres cancelar la transferencia?</string>
<string name="yes">Tan</string>
<string name="confirm_password">Confirmar contraseña</string>
<string name="error_password_not_match">La contraseña no coincide.</string>
<string name="app_version">Versión%1$s</string>
<string name="all_rights_reserved">Todos los derechos reservados.</string>
<string name="feature_about_licenses">La concesión de licencias</string>
<string name="transfer_error">No se puede hacer una transferencia, por favor intente de nuevo más tarde</string>
<string name="please_wait">Por favor espere&#8320;</string>
<string name="message">Mensaje</string>
<string name="core_common_language_type" translatable="false">Tipo_idioma</string>
<string name="core_common_default_system_language" translatable="false">idioma_del_sistema_predeterminado</string>
<string name="theme_type" translatable="false">tipo_tema</string>
<string name="total_saving_balance">Saldo total de ahorro</string>
<string name="total_loan_balance">Saldo Total de Crédito</string>
<string name="total_loan_savings_description">Los saldos de Crédito y Cuenta de Ahorros mostrados arriba se calculan en base a la totalidad de sus cuentas de ahorro y préstamos.</string>
<string name="cancel_transfer">¿Estás seguro de que deseas cancelar la transferencia?</string>
<string name="yes"></string>
<string name="confirm_password">Confirmar Contraseña</string>
<string name="error_password_not_match">Contraseña no coincide.</string>
<string name="app_version">Versión %1$s</string>
<string name="feature_about_copyright_mifos">©2016-%1$s Iniciativa Mifos.</string>
<string name="all_rights_reserved">Reservados todos los derechos.</string>
<string name="feature_about_licenses">Licencias</string>
<string name="feature_about_privacy_policy">política de privacidad</string>
<string name="feature_about_policy_host" translatable="false">openmf.github.io/privacy_policy_mifos_mobile.html</string>
<string name="feature_about_policy_url" translatable="false">https://openmf.github.io/privacy_policy_mifos_mobile.html</string>
<string name="transfer_error">No se puede completar la transferencia, inténtelo de nuevo</string>
<string name="please_wait">Espere por favor...</string>
<string name="message">mensaje</string>
<string name="no_image_selected_or_something_went_wrong">No se ha seleccionado ninguna imagen o algo ha salido mal</string>
<string name="seleted_qr_image">Imagen QR seleccionada</string>
<string name="no_notification">Sin notificación</string>
<string name="pref_base_url_title">Actualizar punto final</string>
<string name="pref_base_url_desc">Haga clic aquí para cambiar las configuraciones de punto final.</string>
<string name="enter_base_url">Introduce la URL principal</string>
<string name="enter_tenant">Ir al inquilino</string>
<string name="app_info">Informacion de la applicacion</string>
<string name="login_failed">No se pudo entrar Inténtelo más tarde.</string>
<string name="pref_base_url_title">Actualizar punto de conexión</string>
<string name="pref_base_url_desc">Haga clic aquí para cambiar las configuraciones</string>
<string name="pref_configuration" translatable="false">pref_configuration</string>
<string name="enter_base_url">Ingrese la URL</string>
<string name="enter_tenant">Ingrese su cuenta</string>
<string name="account_type_loan" translatable="false">accountType.loan</string>
<string name="refresh">Refrescar</string>
<!--Contraseña strength strings-->
<string name="password_strength_weak">Débil</string>
<string name="password_strength_medium">Medio</string>
<string name="password_strength_strong">Segura</string>
<string name="password_strength_very_strong">Muy segura</string>
<string name="loan_purpose_not_provided">No proporcionado</string>
<string name="details">Detalles</string>
<string name="product">Producto</string>
<string name="feature_account_dividend_payout">Pago de dividendos</string>
<string name="feature_account_withdrawal">Retiro</string>
<string name="feature_account_interest_posting">Publicación de intereses</string>
<string name="feature_account_fee_deduction">Deducción de tarifa</string>
<string name="feature_account_withdrawal_transfer">Transferencia de retiro</string>
<string name="feature_account_rejected_transfer">Transferencia Rechazada</string>
<string name="feature_account_overdraft_fee">Cargo por sobregiro</string>
<string name="savings_account_transaction">Transacción de Cuenta de Ahorros</string>
<string name="transaction_period">Período de transacción</string>
<string name="transaction_type">Tipo de transacción</string>
<string name="questions">Preguntas</string>
<string name="logged_out_successfully">Cerró sesión exitosamente</string>
<string name="dialog_cancel_registration_message">¿Quieres cancelar el registro de Nueva Cuenta?</string>
<string name="dialog_cancel_registration_title">Cancelar registro</string>
<string name="feature_about_sources">Código fuente</string>
<string name="feature_about_official_website">Sitio web oficial</string>
<string name="feature_about_app_version">Versión de la aplicación 1.0</string>
<string name="feature_about_license">Licencia: MPL-2.0</string>
<string name="feature_about_description">Una aplicación de Android creada sobre la plataforma de autoservicio MifosX para que los clientes finales puedan ver y realizar transacciones en las cuentas y préstamos que poseen.</string>
<string name="or">o</string>
<string name="no_app_to_support_action">No existe ninguna aplicación que admita esta acción</string>
<string name="theme">Tema</string>
<string name="change_app_theme">Cambiar tema</string>
<string-array name="languages" translatable="false">
<item>Idiomas de la Aplicación</item>
<item>Inglés</item>
<item>हिंदी</item>
<item>عربى</item>
<item>اُردُو</item>
<item>বাঙালি</item>
<item>Español</item>
<item>Francés</item>
<item>bahasa Indonesia</item>
<item>ភាសាខ្មែរ</item>
<item>ಕನ್ನಡ</item>
<item>తెలుగు</item>
<item>မြန်မာ</item>
<item>Polski</item>
<item>Português</item>
<item>русский</item>
<item>Kiswahili</item>
<item>فارسی</item>
</string-array>
<string-array name="core_common_languages_value" translatable="false">
<item>Idiomas de la Aplicación</item>
<item>en</item>
<item>hi</item>
<item>ar</item>
<item>ur</item>
<item>bn</item>
<item>es</item>
<item>fr</item>
<item>in</item>
<item>km</item>
<item>kn</item>
<item>te</item>
<item>my</item>
<item>pl</item>
<item>pt</item>
<item>ru</item>
<item>sw</item>
<item>fa</item>
</string-array>
<string-array name="themes">
<item>Tema del sistema</item>
<item>Tema Claro</item>
<item>Tema Oscuro</item>
</string-array>
<string name="app_info">Información de la aplicación</string>
<string name="login_failed">No se pudo iniciar sesión. Reintente más tarde.</string>
<string name="password_changed_successfully">Contraseña actualizada correctamente</string>
<string name="could_not_register_user_error">No pudimos registrar al usuario.</string>
<string name="no_questions_found">No se encontraron preguntas</string>
<string name="something_went_wrong">Algo salió mal</string>
<string name="atm_icon">Icono ATM</string>
<string name="title_activity_guarantor">Actividad del Garante</string>
<string name="screen_guarantor_list">Lista de Garantes</string>
<string name="screen_guarantor_details">Detalles del Garante</string>
<string name="screen_guarantor_add">Agregar Garante</string>
<string name="city">Ciudad</string>
<string name="guarantor_deleted_successfully">Garante eliminado con éxito</string>
<string name="guarantor_created_successfully">Garante creado con éxito</string>
<string name="guarantor_updated_successfully">Garante actualizada con éxito</string>
<string name="required">Requerido</string>
<string name="s_no">S.No</string>
<string name="no_transaction_found">No se encontró ninguna transacción</string>
<string name="not_connected">⚠️ No estás conectado a Internet</string>
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">AIzaSyBbeT2BaMWLj-lReCgYoNmXs_TIyRLr9qQ</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -0,0 +1,528 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,
You can obtain one at https://mozilla.org/MPL/2.0/.
See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
-->
<resources>
<string name="feature_about_app_name">മിഫോസ് മൊബൈൽ</string>
<string name="login">ലോഗിൻ ചെയ്യുക</string>
<string name="toast_welcome">സ്വാഗതം %1$s</string>
<string name="unable_to_connect">ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല</string>
<string name="basic">അടിസ്ഥാനം</string>
<string name="username">ഉപയോക്തൃനാമം</string>
<string name="progress_message_login">ലോഗിൻ ചെയ്യുന്നു</string>
<string name="progress_message_loading">ലോഡ് ചെയ്യുന്നു</string>
<string name="password">പാസ്‌വേഡ്</string>
<string name="email">ഇമെയിൽ</string>
<string name="accounts">അക്കൗണ്ട്</string>
<string name="clients">ഉപഭോക്താക്കൾ</string>
<string name="funds_transfer">ഫണ്ട് ട്രാൻസ്ഫർ</string>
<string name="recent_transactions">സമീപകാല ഇടപാടുകൾ</string>
<string name="charges">ചാർജുകൾ</string>
<string name="questionnaire">ചോദ്യാവലി</string>
<string name="feature_about_about_us">ഞങ്ങളെക്കുറിച്ച്</string>
<string name="saving_account_details">സേവിംഗ്സ് അക്കൗണ്ട് വിശദാംശങ്ങൾ</string>
<string name="feature_account_savings_account">സേവിംഗ്സ് അക്കൗണ്ട്</string>
<string name="error_loan_account_details_loading">വായ്പാ അക്കൗണ്ട് വിശദാംശങ്ങൾ ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="nominal_interest_rate">നാമമാത്ര പലിശ നിരക്ക്</string>
<string name="create_an_account">അക്കൗണ്ട് ഉണ്ടാക്കുക</string>
<string name="account_number">അക്കൗണ്ട് നമ്പർ</string>
<string name="account_balance">അക്കൗണ്ട് ബാലൻസ്</string>
<string name="total_deposits">ആകെ നിക്ഷേപം</string>
<string name="open_drawer">ഡ്രോയർ തുറക്കുക</string>
<string name="close_drawer">ഡ്രോയർ അടയ്ക്കുക</string>
<string name="home">ഹോം</string>
<string name="medium_text">മധ്യസ്ഥ വാചകം</string>
<string name="small_text">ചെറിയ വാചകം</string>
<string name="client_accounts">ഉപഭോക്തൃ അക്കൗണ്ടുകൾ</string>
<string name="splash">സ്പ്ലാഷ്</string>
<string name="feature_account_savings">സേവിംഗ്സ്</string>
<string name="feature_account_loan">ലോൺ</string>
<string name="feature_account_loan_account">വായ്പ അക്കൗണ്ട്</string>
<string name="savings_charges">സേവിംഗ്സ് ചാർജുകൾ</string>
<string name="feature_account_share">ഷെയർ</string>
<string name="feature_account_share_account">ഷെയർ അക്കൗണ്ട്</string>
<string name="clients_list">ഒരു ഉപഭോക്താവിനെ തിരഞ്ഞെടുക്കുക</string>
<string name="core_common_working">പ്രവർത്തിക്കുന്നു</string>
<string name="feature_account_submitted">സമർപ്പിച്ചു</string>
<string name="feature_account_disbursement">വിതരണം</string>
<string name="status_image">സ്റ്റാറ്റസ് ചിത്രം</string>
<string name="loan_repayment_schedule">തിരിച്ചടവ് ഷെഡ്യൂൾ</string>
<string name="last_transaction">കഴിഞ്ഞ ഇടപാട്</string>
<string name="made_on">ഉണ്ടാക്കിയത്</string>
<string name="make_transfer">ട്രാൻസ്ഫർ ചെയ്യുക</string>
<string name="last_name">കുടുംബപ്പേര്</string>
<string name="phone_number">ഫോൺ നമ്പർ</string>
<string name="rb_email">ഇമെയിൽ</string>
<string name="rb_mobile">മൊബൈൽ</string>
<string name="verification_mode">പരിശോധനാ രീതി</string>
<string name="select_loan_product">ലോൺ ഉൽപ്പന്നം തിരഞ്ഞെടുക്കുക*</string>
<string name="purpose_of_loan">വായ്പയുടെ ഉദ്ദേശ്യം*</string>
<string name="principal_amount">അടിസ്ഥാന തുക*</string>
<string name="amount">തുക</string>
<string name="remark">പരാമർശം</string>
<string name="expected_disbursement_date">പ്രതീക്ഷിക്കുന്ന വിതരണ തീയതി</string>
<string name="submission_date">സമർപ്പണ തീയതി</string>
<string name="transfer_date">ട്രാൻസ്ഫർ തീയതി</string>
<string name="apply_for_loan">വായ്പയ്ക്ക് അപേക്ഷിക്കുക</string>
<string name="update_loan">വായ്പ അപ്‌ഡേറ്റ് ചെയ്യുക</string>
<string name="withdraw_loan">വായ്പ പിൻവലിക്കുക</string>
<string name="withdraw_loan_reason">വായ്പ പിൻവലിക്കുന്നതിനുള്ള കാരണം</string>
<string name="loan_account_withdrawn_successfully">വായ്പ അക്കൗണ്ട് വിജയകരമായി പിൻവലിച്ചു</string>
<string name="review">അവലോകനം</string>
<string name="submit_loan">വായ്പ സമർപ്പിക്കുക</string>
<string name="new_loan_application">പുതിയ വായ്പാ അപേക്ഷ:</string>
<string name="update_loan_application">വായ്പാ അപേക്ഷ അപ്‌ഡേറ്റ് ചെയ്യുക:</string>
<string name="loan_interest_type">പലിശ തരം</string>
<string name="amortization">അമോർട്ടൈസേഷൻ</string>
<string name="interest_calculation_period">പലിശ കണക്കാക്കുന്ന കാലയളവ്</string>
<string name="repayment_strategy">തിരിച്ചടവ് തന്ത്രം</string>
<string name="pay_to">ഇതിലേക്ക് നൽകുക</string>
<string name="pay_from">ഇതിൽ നിന്ന് നൽകുക</string>
<string name="feature_account_cancel">റദ്ദാക്കുക</string>
<string name="review_transfer">ട്രാൻസ്ഫർ അവലോകനം</string>
<string name="transfer_to">ഇതിലേക്ക് ട്രാൻസ്ഫർ ചെയ്യുക</string>
<string name="transfer_from">ഇതിൽ നിന്ന് ട്രാൻസ്ഫർ ചെയ്യുക</string>
<string name="making_transfer">ട്രാൻസ്ഫർ ചെയ്യുന്നു</string>
<string name="feature_account_deposit">നിക്ഷേപം</string>
<string name="enter_amount">തുക നൽകുക</string>
<string name="enter_remarks">ട്രാൻസ്ഫറിനുള്ള പരാമർശം നൽകുക</string>
<string name="select_beneficiary">ഗുണഭോക്താവിനെ തിരഞ്ഞെടുക്കുക</string>
<string name="remark_is_mandatory">പരാമർശം നിർബന്ധമാണ്</string>
<string name="feature_account_approved">അംഗീകരിച്ചു</string>
<string name="shares_pending">തീർപ്പുകല്പിക്കാത്തവ</string>
<string name="loan_amount_paid">അടച്ച തുക</string>
<string name="balance">ബാക്കി തുക</string>
<string name="rejected">നിരസിച്ചു</string>
<string name="waiting">കാത്തിരിക്കുന്നു</string>
<string name="register">രജിസ്റ്റർ ചെയ്യുക</string>
<string name="request_id">അഭ്യർത്ഥന ഐഡി</string>
<string name="feature_account_overpaid">അധിക തുക നൽകി</string>
<string name="feature_account_in_arrears">കുടിശ്ശിക</string>
<string name="feature_account_select_you_want">നിങ്ങൾ അപേക്ഷിക്കാൻ ആഗ്രഹിക്കുന്നവ തിരഞ്ഞെടുക്കുക</string>
<string name="filter_savings">സേവിംഗ്സ് അക്കൗണ്ട് ഫിൽട്ടർ ചെയ്യുക</string>
<string name="filter_loan">വായ്പാ അക്കൗണ്ടുകൾ ഫിൽട്ടർ ചെയ്യുക</string>
<string name="filter_share">ഷെയർ അക്കൗണ്ടുകൾ ഫിൽട്ടർ ചെയ്യുക</string>
<string name="search">തിരയുക</string>
<string name="choose_transfer_type">ട്രാൻസ്ഫർ തരം തിരഞ്ഞെടുക്കുക</string>
<string name="feature_account_active">സജീവം</string>
<string name="feature_account_closed">അടച്ചു</string>
<string name="need_approval">അംഗീകാരം ആവശ്യമാണ്</string>
<string name="feature_account_pending">തീർപ്പുകല്പിക്കാത്തവ</string>
<string name="feature_account_matured">കാലാവധി പൂർത്തിയായി</string>
<string name="continue_str">തുടരുക</string>
<string name="close">അടയ്ക്കുക</string>
<string name="transfer_to_savings">സേവിംഗ്സ് അക്കൗണ്ടിലേക്ക് ട്രാൻസ്ഫർ</string>
<string name="transfer_from_savings">സേവിംഗ്സ് അക്കൗണ്ടിൽ നിന്ന് ട്രാൻസ്ഫർ</string>
<string name="feature_account_withdrawn">പിൻവലിച്ചു</string>
<string name="blank">&#160;</string>
<string name="import_qr">ക്യുആർ ഇമ്പോർട്ട് ചെയ്യുക</string>
<string name="authentication_token">ഓതന്റിക്കേഷൻ ടോക്കൺ</string>
<string name="verify">പരിശോധിക്കുക</string>
<string name="verifying">പരിശോധിക്കുന്നു</string>
<string name="sign_up">സൈൻ അപ്പ് ചെയ്യുന്നു</string>
<string name="verified">ഉപയോക്താവിനെ വിജയകരമായി പരിശോധിച്ചു</string>
<string name="use_touch_id">ടച്ച് ഐഡി ഉപയോഗിക്കുക</string>
<string name="view_guarantor">ജാമ്യക്കാരനെ കാണുക</string>
<string name="add_guarantor">ജാമ്യക്കാരനെ ചേർക്കുക</string>
<string name="delete_guarantor">ജാമ്യക്കാരനെ നീക്കം ചെയ്യുക</string>
<string name="update_guarantor">ജാമ്യക്കാരനെ അപ്‌ഡേറ്റ് ചെയ്യുക</string>
<string name="guarantor_type">ജാമ്യ തരം</string>
<string name="no_guarantors">ജാമ്യക്കാർ ഇല്ല</string>
<string name="tap_to_add_guarantor">ജാമ്യക്കാരനെ ചേർക്കാൻ ടാപ്പുചെയ്യുക</string>
<string name="guarantor_details">ജാമ്യക്കാരന്റെ വിവരങ്ങൾ</string>
<string name="joined_date">ചേർന്ന തീയതി</string>
<string name="submit">സമർപ്പിക്കുക</string>
<string name="select_product_id">ഉൽപ്പന്ന ഐഡി തിരഞ്ഞെടുക്കുക</string>
<string name="account_id">അക്കൗണ്ട് ഐഡി</string>
<string name="new_saving_account_application">പുതിയ സേവിംഗ്സ് അക്കൗണ്ട് അപേക്ഷ</string>
<string name="update_savings_account">സേവിംഗ്സ് അക്കൗണ്ട് അപ്‌ഡേറ്റ് ചെയ്യുക</string>
<string name="withdraw_savings_account">സേവിംഗ്സ് അക്കൗണ്ട് പിൻവലിക്കുക</string>
<string name="withdrawal_date">പിൻവലിക്കൽ തീയതി</string>
<string name="new_saving_account_created_successfully">പുതിയ സേവിംഗ്സ് അക്കൗണ്ട് വിജയകരമായി സൃഷ്ടിച്ചു.</string>
<string name="saving_account_updated_successfully">സേവിംഗ്സ് അക്കൗണ്ട് വിജയകരമായി അപ്‌ഡേറ്റ് ചെയ്തു</string>
<string name="savings_account_withdraw_successful">സേവിംഗ്സ് അക്കൗണ്ടിൽ നിന്നുള്ള പിൻവലിക്കൽ വിജയകരം</string>
<string name="string_savings_account">%1$s സേവിംഗ്സ് അക്കൗണ്ട്</string>
<string name="apply">അപേക്ഷിക്കുക</string>
<string name="apply_savings_account">സേവിംഗ്സ് അക്കൗണ്ടിന് അപേക്ഷിക്കുക</string>
<string name="update">അപ്‌ഡേറ്റ് ചെയ്യുക</string>
<string name="edit">എഡിറ്റ് ചെയ്യുക</string>
<string name="passcode">പാസ്‌കോഡ്</string>
<string name="other">മറ്റുള്ളവ</string>
<string name="gender">ലിംഗഭേദം</string>
<string name="no">അല്ല</string>
<string name="found">കണ്ടെത്തി</string>
<string name="feature_account_empty_savings_accounts">നിങ്ങൾക്ക് സേവിംഗ്സ് അക്കൗണ്ടുകൾ ഒന്നുമില്ല</string>
<string name="feature_account_empty_loan_accounts">നിങ്ങൾക്ക് വായ്പാ അക്കൗണ്ടുകൾ ഒന്നുമില്ല</string>
<string name="feature_account_empty_share_accounts">നിങ്ങൾക്ക് ഷെയർ അക്കൗണ്ടുകൾ ഒന്നുമില്ല</string>
<string name="empty_transactions">നിങ്ങളുടെ അക്കൗണ്ടുമായി ബന്ധപ്പെട്ട ഇടപാടുകൾ ഒന്നുമില്ല</string>
<string name="empty_repayment_schedule">നിങ്ങളുടെ അക്കൗണ്ടുമായി ബന്ധപ്പെട്ട തിരിച്ചടവ് ഷെഡ്യൂളുകൾ ഒന്നുമില്ല</string>
<string name="no_more_transactions_available">കൂടുതൽ ഇടപാടുകൾ ലഭ്യമല്ല</string>
<string name="no_transaction">ഇടപാടുകൾ ഇല്ല</string>
<string name="no_dob_found">ജനനത്തീയതി കണ്ടെത്തിയില്ല.</string>
<string name="not_assigned_with_any_group">ഒരു ഗ്രൂപ്പിലുമായി ബന്ധിപ്പിച്ചിട്ടില്ല</string>
<string name="transfer_error">ട്രാൻസ്ഫർ പൂർത്തിയാക്കാൻ കഴിഞ്ഞില്ല, ദയവായി പിന്നീട് വീണ്ടും ശ്രമിക്കുക</string>
<string name="error_unauthorised">തെറ്റായ ഉപയോക്തൃനാമം / പാസ്‌വേഡ്</string>
<string name="error_message_server">സെർവറിൽ നിന്നുള്ള പ്രതികരണം ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="error_validation_blank">%1$s ശൂന്യമാകാൻ പാടില്ല</string>
<string name="error_validation_minimum_chars">%1$s %2$d അക്ഷരങ്ങളിൽ കുറയാൻ പാടില്ല</string>
<string name="error_validation_cannot_contain_spaces">%1$s ൽ %2$s അടങ്ങാൻ പാടില്ല</string>
<string name="error_internal_server">ഇന്റേണൽ സെർവർ പിശക്, ദയവായി വീണ്ടും ശ്രമിക്കുക</string>
<string name="error_client_loading">ഉപഭോക്തൃ പട്ടിക ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="error_loan_accounts_list_loading">വായ്പാ അക്കൗണ്ടുകളുടെ പട്ടിക ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="error_saving_accounts_list_loading">സേവിംഗ്സ് അക്കൗണ്ടുകളുടെ പട്ടിക ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="error_saving_account_details_loading">സേവിംഗ്സ് അക്കൗണ്ട് വിശദാംശങ്ങൾ ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="qr_code">ക്യുആർ കോഡ്</string>
<string name="error_recent_transactions_loading">സമീപകാല ഇടപാടുകൾ ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="error_client_charge_loading">ഉപഭോക്തൃ ചാർജ് ലോഡ് ചെയ്യുന്നതിൽ പിശക്</string>
<string name="error_no_charge">ചാർജുകൾ ഒന്നും കണ്ടെത്തിയില്ല</string>
<string name="error_client_not_found">ഉപഭോക്താവിനെ കണ്ടെത്തിയില്ല</string>
<string name="error_fetching_client">ഉപഭോക്താവിനെ ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_fetching_user_profile">ഉപയോക്തൃ പ്രൊഫൈൽ ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_fetching_accounts">അക്കൗണ്ടുകൾ ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_fetching_repayment_schedule">തിരിച്ചടവ് ഷെഡ്യൂൾ ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_same_account_transfer">ഒരേ അക്കൗണ്ടിലേക്ക് ട്രാൻസ്ഫർ ചെയ്യാൻ കഴിയില്ല</string>
<string name="error_fetching_account_transfer_template">അക്കൗണ്ട് ട്രാൻസ്ഫർ ടെംപ്ലേറ്റ് ലഭ്യമാക്കുന്നതിൽ പിശക്</string>
<string name="error_fetching_beneficiaries">ഗുണഭോക്താക്കളെ ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_fetching_beneficiary_template">ഗുണഭോക്തൃ ടെംപ്ലേറ്റ് ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="user_details">ഉപയോക്തൃ വിവരങ്ങൾ</string>
<string name="activation_date">ആക്ടിവേഷൻ തീയതി</string>
<string name="client_type">ഉപഭോക്തൃ തരം</string>
<string name="groups">ഗ്രൂപ്പുകൾ</string>
<string name="client_classification">ഉപഭോക്തൃ വർഗ്ഗീകരണം</string>
<string name="error_fetching_template">ടെംപ്ലേറ്റ് ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_creating_beneficiary">ഗുണഭോക്താവിനെ സൃഷ്ടിക്കുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_updating_beneficiary">ഗുണഭോക്താവിനെ അപ്‌ഡേറ്റ് ചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_deleting_beneficiary">ഗുണഭോക്താവിനെ നീക്കം ചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു</string>
<string name="error_loan_account_withdraw">വായ്പാ അക്കൗണ്ട് പിൻവലിക്കുന്നതിൽ പിശക്</string>
<string name="no_beneficiary_found_please_add">നിലവിൽ, നിങ്ങൾക്ക് ഗുണഭോക്താക്കൾ ആരുമില്ല. ദയവായി ഗുണഭോക്താവിനെ ചേർക്കുക</string>
<string name="unauthorized_client">നിങ്ങൾക്ക് അനുമതിയില്ല</string>
<string name="invalid_qr">നിങ്ങൾക്ക് സ്വന്തം അക്കൗണ്ടിൽ നിന്ന് പ്രവർത്തിക്കാൻ കഴിയില്ല, ദയവായി മറ്റൊരു ഉപയോക്താവിന്റെ സേവിംഗ്സ് അല്ലെങ്കിൽ വായ്പാ അക്കൗണ്ടിന്റെ ക്യുആർ സ്കാൻ ചെയ്യുക</string>
<string name="add">ചേർക്കുക</string>
<string name="scan">സ്കാൻ ചെയ്യുക</string>
<string name="select_mode">മോഡ് തിരഞ്ഞെടുക്കുക</string>
<string name="share_msg">ഇവിടെ സെൽഫ് സർവീസ് ആപ്പ് ഡൗൺലോഡ് ചെയ്യുക: https://play.google.com/store/apps/details?id=</string>
<string name="enter_passcode">4 അക്ക പാസ്‌കോഡ് നൽകുക</string>
<string name="error_passcode">പാസ്‌കോഡിൽ 4 അക്കങ്ങൾ ഉണ്ടായിരിക്കണം</string>
<string name="incorrect_passcode">പാസ്‌കോഡ് തെറ്റാണ്</string>
<string name="incorrect_passcode_more_than_three">നിങ്ങൾ 3 തവണയിൽ കൂടുതൽ തെറ്റായ പാസ്‌കോഡ് നൽകി</string>
<string name="forgot_passcode">പാസ്‌കോഡ് മറന്നോ, നേരിട്ട് ലോഗിൻ ചെയ്യുക</string>
<string name="proceed">മുന്നോട്ട് പോകുക</string>
<string name="skip">ഒഴിവാക്കുക</string>
<string name="save">സേവ് ചെയ്യുക</string>
<string name="amount_greater_than_zero">തുക പൂജ്യത്തേക്കാൾ കൂടുതലായിരിക്കണം</string>
<string name="help_under_construction">സഹായം നിർമ്മാണത്തിലാണ്</string>
<string name="logout">ലോഗൗട്ട്</string>
<string name="loan_charges">വായ്പാ ചാർജുകൾ</string>
<string name="view_transactions">ഇടപാടുകൾ കാണുക</string>
<string name="view_charges">ചാർജുകൾ കാണുക</string>
<string name="view_loan_summary">വായ്പാ സംഗ്രഹം കാണുക</string>
<string name="view_repayment">തിരിച്ചടവ് ഷെഡ്യൂൾ കാണുക</string>
<string name="share_qr_code">ക്യുആർ കോഡ് പങ്കിടുക</string>
<string name="monitor">നിരീക്ഷിക്കുക</string>
<string name="choose_option">ഓപ്ഷൻ തിരഞ്ഞെടുക്കുക</string>
<string name="view_qr_code">ഈ അക്കൗണ്ടിനുള്ള ക്യുആർ കോഡ് കാണുക</string>
<string name="last_trans">അവസാന ഇടപാട് വിവരങ്ങൾ</string>
<string name="passcode_setup">ലോഗിൻ ചെയ്യുന്നതിന് ഒരു പാസ്‌കോഡ് സജ്ജീകരിക്കുക</string>
<string name="reenter_passcode">ദയവായി നിങ്ങളുടെ പാസ്‌കോഡ് വീണ്ടും നൽകുക</string>
<string name="passcode_does_not_match">പാസ്‌കോഡ് പൊരുത്തപ്പെടുന്നില്ല</string>
<string name="error_fetching_third_party_transfer_template">തേർഡ് പാർട്ടി ട്രാൻസ്ഫർ ടെംപ്ലേറ്റ് ലഭ്യമാക്കുന്നതിൽ പിശക്</string>
<string name="choose">ആപ്ലിക്കേഷൻ തിരഞ്ഞെടുക്കുക</string>
<string name="upload_qr_code">ക്യുആർ അപ്‌ലോഡ് ചെയ്യുക</string>
<string name="select_region_qr">ക്യുആർ കോഡ് ഉള്ള ഭാഗം തിരഞ്ഞെടുക്കുക</string>
<string name="error_username_greater_than_six">ഉപയോക്തൃനാമം 6 അക്ഷരങ്ങളിൽ കൂടുതലായിരിക്കണം</string>
<string name="error_invalid_email">അസാധുവായ ഇമെയിൽ ഐഡി</string>
<string name="error_server_down">സെർവർ പ്രവർത്തനരഹിതമാണ്, അൽപ്പസമയത്തിന് ശേഷം ശ്രമിക്കുക</string>
<string name="client_charges">ഉപഭോക്തൃ ചാർജുകൾ</string>
<string name="error_reading_qr">ക്യുആർ റീഡ് ചെയ്യുന്നതിൽ പിശക്, നിങ്ങൾ ശരിയായ ഭാഗം തിരഞ്ഞെടുത്തുവെന്ന് ഉറപ്പാക്കുക</string>
<string name="error_fetching_image">ചിത്രം ലഭ്യമാക്കുന്നതിൽ പിശക്</string>
<string name="invalid_phn_number">അസാധുവായ ഫോൺ നമ്പർ</string>
<string name="fetching_client">ഉപഭോക്താവിനെ ലഭ്യമാക്കുന്നു</string>
<string name="not_contain_username">സ്പേസുകൾ</string>
<string name="client_name">ഉപഭോക്താവിന്റെ പേര്</string>
<string name="account_status">അക്കൗണ്ട് നില</string>
<string name="saving_product_name">ഉൽപ്പന്നത്തിന്റെ പേര്</string>
<string name="total_withdrawal">ആകെ പിൻവലിക്കൽ</string>
<string name="min_required_balance">ആവശ്യമായ കുറഞ്ഞ ബാലൻസ്</string>
<string name="loan_product_name">ഉൽപ്പന്നത്തിന്റെ പേര്</string>
<string name="loan_purpose">വായ്പയുടെ ഉദ്ദേശ്യം</string>
<string name="principal">അടിസ്ഥാന തുക</string>
<string name="principal_disbursed">വിതരണം ചെയ്ത അടിസ്ഥാന തുക</string>
<string name="annual_interest_rate">വാർഷിക പലിശ നിരക്ക്</string>
<string name="interest_charged">ഈടാക്കിയ പലിശ</string>
<string name="interest_paid">അടച്ച പലിശ</string>
<string name="loan_account_details">വായ്പാ അക്കൗണ്ട് വിവരങ്ങൾ</string>
<string name="loan_summary">വായ്പാ സംഗ്രഹം</string>
<string name="loan_name">വായ്പയുടെ പേര്</string>
<string name="interest">പലിശ</string>
<string name="fees">ഫീസ്</string>
<string name="penalties">പിഴകൾ</string>
<string name="total_repayment">മൊത്തം പ്രതീക്ഷിക്കുന്ന തിരിച്ചടവ്</string>
<string name="total_paid">മൊത്തം അടച്ച തുക</string>
<string name="interest_waived">ഒഴിവാക്കിയ പലിശ</string>
<string name="penalties_waived">ഒഴിവാക്കിയ പിഴകൾ</string>
<string name="fees_waived">ഒഴിവാക്കിയ ഫീസ്</string>
<string name="outstanding_balance">കുടിശ്ശിക തുക</string>
<string name="next_installment">അടുത്ത ഗഡു</string>
<string name="due_date">അടയ്ക്കേണ്ട തീയതി</string>
<string name="make_payment">പണമടയ്ക്കുക</string>
<string name="loan_type">വായ്പ തരം</string>
<string name="currency">കറൻസി</string>
<string name="repayment_schedule">തിരിച്ചടവ് ഷെഡ്യൂൾ</string>
<string name="transactions">ഇടപാടുകൾ</string>
<string name="transfer">ട്രാൻസ്ഫർ</string>
<string name="feature_account_approval_pending">അംഗീകാരം ലഭിക്കാൻ കാത്തിരിക്കുന്നു</string>
<string name="feature_account_disburse">വിതരണം ചെയ്യാൻ കാത്തിരിക്കുന്നു</string>
<string name="closed_because_of_obligation">ചില ബാധ്യതകൾ കാരണം അടച്ചു</string>
<string name="loan_closed">വായ്പ അടച്ചു</string>
<string name="due_date_in_charges">അടയ്ക്കേണ്ട തീയതി:</string>
<string name="amount_due">നൽകേണ്ട തുക:</string>
<string name="amount_paid">അടച്ച തുക:</string>
<string name="amount_waived">ഒഴിവാക്കിയ തുക:</string>
<string name="amount_outstanding">കുടിശ്ശിക:</string>
<string name="appwidget_text">ഉദാഹരണം</string>
<string name="add_widget">വിജറ്റ് ചേർക്കുക</string>
<string name="help">സഹായം</string>
<string name="mifos_initiative">മിഫോസ് ഇനിഷ്യേറ്റീവ്</string>
<string name="mifos_location">മിഫോസ് ഇനിഷ്യേറ്റീവ്, സിയാറ്റിൽ, വാഷിംഗ്ടൺ 98121</string>
<string name="map_marker_heading">സിയാറ്റിൽ</string>
<string name="map_marker_desc">വലിയ ടെക് വ്യവസായത്തിന്റെ ആസ്ഥാനം</string>
<string name="loan_transaction_details">വായ്പാ അക്കൗണ്ട് വിവരങ്ങൾ</string>
<string name="loan_application_submitted_successfully">വായ്പാ അപേക്ഷ വിജയകരമായി സമർപ്പിച്ചു</string>
<string name="loan_application_updated_successfully">വായ്പാ അപേക്ഷ വിജയകരമായി അപ്‌ഡേറ്റ് ചെയ്തു</string>
<string name="loan_application_withdrawn_successfully">വായ്പാ അപേക്ഷ വിജയകരമായി പിൻവലിച്ചു</string>
<string name="none">ഒന്നുമില്ല</string>
<string name="all">എല്ലാം</string>
<string name="four_weeks">4 ആഴ്ച</string>
<string name="three_months">3 മാസം</string>
<string name="six_months">6 മാസം</string>
<string name="feature_account_filter">ഫിൽട്ടർ</string>
<string name="start_date">ആരംഭ തീയതി</string>
<string name="end_date">അവസാന തീയതി</string>
<string name="filtered">ഫിൽറ്റർ ചെയ്‌തത്</string>
<string name="select_date">ആരംഭ തീയതിയും അവസാന തീയതിയും തിരഞ്ഞെടുക്കുക</string>
<string name="end_date_must_be_greater">അവസാന തീയതി ആരംഭ തീയതിയേക്കാൾ വലുതായിരിക്കണം</string>
<string name="saving_account_transactions_details">സേവിംഗ്സ് അക്കൗണ്ട് ഇടപാട്</string>
<string name="no_internet_connection">ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല</string>
<string name="disbursement_date">വിതരണ തീയതി</string>
<string name="no_of_payments">പേയ്മെന്റുകളുടെ എണ്ണം</string>
<string name="date">തീയതി</string>
<string name="loan_balance">വായ്പ ബാലൻസ്</string>
<string name="repayment">തിരിച്ചടവ്</string>
<string name="loan_repayment">വായ്പാ തിരിച്ചടവ്</string>
<string name="quick_transfer">ദ്രുത ട്രാൻസ്ഫർ</string>
<string name="internet_not_connected">നിങ്ങൾ ഇന്റർനെറ്റുമായി കണക്റ്റുചെയ്‌തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക</string>
<string name="beneficiary">ഗുണഭോക്താവ്</string>
<string name="manage_beneficiaries">ഗുണഭോക്താക്കളെ നിയന്ത്രിക്കുക</string>
<string name="beneficiaries">ഗുണഭോക്താക്കൾ</string>
<string name="beneficiary_detail">ഗുണഭോക്താവിന്റെ വിവരങ്ങൾ</string>
<string name="beneficiary_name">ഗുണഭോക്താവിന്റെ പേര്</string>
<string name="account_type">അക്കൗണ്ട് തരം</string>
<string name="transfer_limit">ട്രാൻസ്ഫർ പരിധി</string>
<string name="add_beneficiary">ഗുണഭോക്താവിനെ ചേർക്കുക</string>
<string name="office_name">ഓഫീസ് പേര്</string>
<string name="add_beneficiary_option">നിങ്ങളുടെ അക്കൗണ്ടിലേക്ക് തേർഡ് പാർട്ടി ഗുണഭോക്താക്കളെ ചേർക്കുക, നേരിട്ട് നൽകുകയോ അക്കൗണ്ട് ക്യുആർ കോഡ് സ്കാൻ ചെയ്യുകയോ ചെയ്യാം</string>
<string name="income_generating_loan">വരുമാനം ഉണ്ടാക്കുന്ന വായ്പ</string>
<string name="not_applicable">ബാധകമല്ല</string>
<string name="dummy_principal_amount">143.00</string>
<string name="select_account_type">അക്കൗണ്ട് തരം തിരഞ്ഞെടുക്കുക*</string>
<string name="submit_beneficiary">ഗുണഭോക്താവിനെ സമർപ്പിക്കുക</string>
<string name="enter_office_name">ഗുണഭോക്താവിന്റെ ഓഫീസ് പേര് നൽകുക</string>
<string name="enter_beneficiary_name">ഗുണഭോക്താവിന്റെ പേര് നൽകുക</string>
<string name="enter_transfer_limit">ട്രാൻസ്ഫർ പരിധി നൽകുക</string>
<string name="enter_account_number">ഗുണഭോക്താവിന്റെ അക്കൗണ്ട് നമ്പർ നൽകുക</string>
<string name="choose_account_type">ഡ്രോപ്പ്ഡൗണിൽ നിന്ന് അക്കൗണ്ട് തരം തിരഞ്ഞെടുക്കുക</string>
<string name="beneficiary_created_successfully">ഗുണഭോക്താവിനെ വിജയകരമായി സൃഷ്ടിച്ചു</string>
<string name="beneficiary_updated_successfully">ഗുണഭോക്താവിനെ വിജയകരമായി അപ്‌ഡേറ്റ് ചെയ്തു</string>
<string name="update_beneficiary">ഗുണഭോക്താവിനെ അപ്‌ഡേറ്റ് ചെയ്യുക</string>
<string name="delete_beneficiary">ഗുണഭോക്താവിനെ നീക്കം ചെയ്യുക</string>
<string name="total_loan">ആകെ വായ്പ</string>
<string name="total_saving">ആകെ സമ്പാദ്യം</string>
<string name="accounts_overview">അക്കൗണ്ട് അവലോകനം</string>
<string name="show_hide_total_saving_amount">ആകെ സമ്പാദ്യ തുക കാണിക്കുകയോ മറയ്ക്കുകയോ ചെയ്യുക</string>
<string name="show_hide_total_loan_amount">ആകെ വായ്പാ തുക കാണിക്കുകയോ മറയ്ക്കുകയോ ചെയ്യുക</string>
<string name="hidden_amount">*****</string>
<string name="survey">സർവേ</string>
<string name="first_name">ആദ്യ പേര്</string>
<string name="delete_beneficiary_confirmation">ഈ ഗുണഭോക്താവിനെ നീക്കം ചെയ്യണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ</string>
<string name="login_using_password_confirmation">പാസ്‌വേഡ് ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?</string>
<string name="delete">നീക്കം ചെയ്യുക</string>
<string name="about_us_under_construction">"ഞങ്ങളെക്കുറിച്ച്" നിർമ്മാണത്തിലാണ്</string>
<string name="beneficiary_deleted_successfully">ഗുണഭോക്താവിനെ വിജയകരമായി നീക്കം ചെയ്തു</string>
<string name="third_party_transfer">തേർഡ് പാർട്ടി ട്രാൻസ്ഫർ</string>
<!--Customer care details-->
<string name="need_help">ഞങ്ങളെ ബന്ധപ്പെടുക</string>
<string name="transferred_successfully">വിജയകരമായി ട്രാൻസ്ഫർ ചെയ്തു</string>
<string name="total">ആകെ: </string>
<string name="account_short">അക്കൗണ്ട്</string>
<string name="loan_product">വായ്പാ ഉൽപ്പന്നം</string>
<string name="inactive">നിഷ്ക്രിയ</string>
<string name="active_uc">സജീവം</string>
<string name="inactive_uc">നിഷ്ക്രിയ</string>
<!--Material Dialog-->
<string name="dialog_logout">നിങ്ങൾക്ക് ലോഗൗട്ട് ചെയ്യണോ?</string>
<string name="dialog_action_ok">ശരി</string>
<string name="dialog_action_cancel">റദ്ദാക്കുക</string>
<string name="dialog_action_back">തിരികെ</string>
<string name="dialog_permission_denied">അനുമതി നിഷേധിച്ചു</string>
<string name="dialog_action_i_am_sure">എനിക്ക് ഉറപ്പാണ്</string>
<string name="dialog_action_re_try">വീണ്ടും ശ്രമിക്കുക</string>
<string name="dialog_action_app_settings">ആപ്പ് ക്രമീകരണങ്ങൾ</string>
<string name="dialog_message_camera_permission_denied_prompt">ക്യാമറ അനുമതിയില്ലാതെ നിങ്ങൾക്ക് ഗുണഭോക്താവിനെ ചേർക്കാൻ ക്യുആർ കോഡ് സ്കാൻ ചെയ്യാൻ കഴിയില്ല. ഈ അനുമതി നിഷേധിക്കണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?</string>
<string name="dialog_message_storage_permission_denied_prompt">സ്റ്റോറേജ് അനുമതിയില്ലാതെ നിങ്ങൾക്ക് ഗുണഭോക്താവിനെ ചേർക്കാൻ ക്യുആർ കോഡ് അപ്‌ലോഡ് ചെയ്യാൻ കഴിയില്ല. ഈ അനുമതി നിഷേധിക്കണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?</string>
<string name="dialog_message_read_storage_permission_never_ask_again">സ്റ്റോറേജ് റീഡ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾ നിഷേധിച്ചു. ഈ അനുമതിയില്ലാതെ ക്യുആർ കോഡ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഗുണഭോക്താക്കളെ ചേർക്കാൻ കഴിയില്ല. ക്രമീകരണങ്ങളിൽ ഇത് പ്രവർത്തനക്ഷമമാക്കുക.</string>
<string name="dialog_message_write_storage_permission_never_ask_again">സ്റ്റോറേജ് റൈറ്റ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾ നിഷേധിച്ചു. ഈ അനുമതിയില്ലാതെ ക്യുആർ കോഡ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഗുണഭോക്താക്കളെ ചേർക്കാൻ കഴിയില്ല. ക്രമീകരണങ്ങളിൽ ഇത് പ്രവർത്തനക്ഷമമാക്കുക.</string>
<string name="dialog_message_camera_permission_never_ask_again">ഈ അനുമതിയില്ലാതെ, ക്യാമറ ഉപയോഗിക്കുന്നതിനുള്ള അനുമതി നിഷേധിക്കപ്പെട്ടു, നിങ്ങൾക്ക് ക്യുആർ കോഡ് ഉപയോഗിച്ച് ഗുണഭോക്താക്കളെ ചേർക്കാൻ കഴിയില്ല. ക്രമീകരണങ്ങളിൽ ഇത് പ്രവർത്തനക്ഷമമാക്കുക.</string>
<string name="dialog_message_phone_state_permission_denied_prompt">നിങ്ങളുടെ രാജ്യത്തിനനുസരിച്ചുള്ള കറൻസി കാണിക്കാൻ ഈ അനുമതി ആവശ്യമാണ്. ഇത് നിഷേധിക്കണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?</string>
<string name="dialog_message_phone_state_permission_never_ask_again">ഫോൺ സ്റ്റേറ്റ് ലഭ്യമാക്കാനുള്ള അനുമതി നിങ്ങൾ നിഷേധിച്ചു. ഈ അനുമതിയില്ലാതെ കറൻസി ശരിയായ ഫോർമാറ്റിൽ കാണിക്കാൻ കഴിയില്ല. ക്രമീകരണങ്ങളിൽ ഇത് പ്രവർത്തനക്ഷമമാക്കുക.</string>
<string name="msg_setting_activity_not_found">ക്രമീകരണ ആക്റ്റിവിറ്റി കണ്ടെത്തുന്നതിൽ എന്തോ തെറ്റ് സംഭവിച്ചു. ക്രമീകരണങ്ങളിലേക്ക് പോയി സ്വയം അനുമതി നൽകുക.</string>
<string name="permission_denied_storage">സ്റ്റോറേജ് അനുമതി നൽകിയിട്ടില്ല</string>
<string name="dialog_are_you_sure_that_you_want_to_string">ഇങ്ങനെ ചെയ്യാൻ ആഗ്രഹിക്കുന്നുവെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ %1$s?</string>
<string name="err_during_login">ലോഗിൻ ചെയ്യുന്നതിനിടെ പിശക് സംഭവിച്ചു</string>
<!--Format Strings-->
<string name="hello_client">ഹലോ, %1$s</string>
<string name="double_and_string">%1$.2f %2$s</string>
<string name="feature_account_string_and_string">%1$s %2$s</string>
<string name="string_and_double">%1$s: %2$.2f</string>
<string name="string_and_int">%1$s: %2$d</string>
<string name="invalid_amount">അസാധുവായ തുക</string>
<string name="exit_message">പുറത്തുകടക്കാൻ ബാക്ക് ബട്ടൺ വീണ്ടും അമർത്തുക</string>
<string name="one">1</string>
<string name="two">2</string>
<string name="three">3</string>
<string name="four">4</string>
<string name="five">5</string>
<string name="six">6</string>
<string name="seven">7</string>
<string name="eight">8</string>
<string name="nine">9</string>
<string name="zero">0</string>
<string name="faq">പതിവുചോദ്യങ്ങൾ</string>
<string name="user_query">ഉപയോക്തൃ അന്വേഷണം</string>
<string name="call_now">ഇപ്പോൾ വിളിക്കുക</string>
<string name="leave_email">ഒരു ഇമെയിൽ അയയ്ക്കുക</string>
<string name="find_locations">ലൊക്കേഷനുകൾ കണ്ടെത്തുക</string>
<string name="settings">ക്രമീകരണങ്ങൾ</string>
<string name="language">ഭാഷ</string>
<string name="choose_language">നിങ്ങളുടെ ഭാഷ തിരഞ്ഞെടുക്കുക</string>
<string name="permission_denied_camera">ക്യാമറ ഉപയോഗിക്കാനുള്ള അനുമതി നിഷേധിച്ചു</string>
<string name="no_withdrawals">പിൻവലിക്കലുകൾ ഇല്ല</string>
<string name="feature_account_clear_filters">ഫിൽട്ടറുകൾ നീക്കം ചെയ്യുക</string>
<string name="notification">അറിയിപ്പുകൾ</string>
<string name="base_url">ബേസ് URL</string>
<string name="tenant">ടെനന്റ്</string>
<string name="no_saving_account">സേവിംഗ്സ് അക്കൗണ്ട് ഇല്ല</string>
<string name="no_loan_account">വായ്പാ അക്കൗണ്ടുകൾ ഇല്ല</string>
<string name="no_sharing_account">ഷെയറിംഗ് അക്കൗണ്ടുകൾ ഇല്ല</string>
<string name="select_loan_product_field">വായ്പാ ഉൽപ്പന്നം തിരഞ്ഞെടുക്കുക</string>
<string name="sign_in_fingerprint">ഫിംഗർപ്രിന്റ് ഉപയോഗിച്ച് സൈൻ ഇൻ ചെയ്യുക</string>
<string name="scan_your_fingerprint">നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് സ്കാൻ ചെയ്യുക</string>
<string name="manage_accounts">അക്കൗണ്ടുകൾ നിയന്ത്രിക്കുക</string>
<string name="more">കൂടുതൽ</string>
<string name="total_saving_balance">ആകെ സമ്പാദ്യ ബാലൻസ്</string>
<string name="total_loan_balance">ആകെ വായ്പ ബാലൻസ്</string>
<string name="total_loan_savings_description">മുകളിലുള്ള വായ്പ, സേവിംഗ്സ് അക്കൗണ്ട് ബാലൻസുകൾ നിങ്ങളുടെ എല്ലാ സേവിംഗ്സ്, വായ്പാ അക്കൗണ്ടുകളെയും അടിസ്ഥാനപ്പെടുത്തി കണക്കാക്കിയതാണ്.
</string>
<string name="cancel_transfer">ട്രാൻസ്ഫർ റദ്ദാക്കണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?</string>
<string name="yes">അതെ</string>
<string name="confirm_password">പാസ്‌വേഡ് സ്ഥിരീകരിക്കുക</string>
<string name="error_password_not_match">പാസ്‌വേഡ് പൊരുത്തപ്പെടുന്നില്ല.</string>
<string name="app_version">പതിപ്പ് %1$s</string>
<string name="feature_about_copyright_mifos">©2016-%1$s മിഫോസ് ഇനിഷ്യേറ്റീവ്.</string>
<string name="all_rights_reserved">എല്ലാ അവകാശങ്ങളും നിക്ഷിപ്തം.</string>
<string name="feature_about_licenses">ലൈസൻസുകൾ</string>
<string name="feature_about_privacy_policy">സ്വകാര്യതാ നയം</string>
<string name="change_passcode">പാസ്‌കോഡ് മാറ്റുക</string>
<string name="change_app_passcode">ആപ്പ് പാസ്‌കോഡ് മാറ്റുക</string>
<string name="change_password">പാസ്‍വേഡ് മാറ്റുക</string>
<string name="change_account_password">നിങ്ങളുടെ അക്കൗണ്ട് പാസ്‌വേഡ് മാറ്റുക</string>
<string name="current_password">നിലവിലെ പാസ്‍വേഡ്</string>
<string name="new_password">പുതിയ പാസ്‍വേഡ്</string>
<string name="string_changed_successfully">%1$s വിജയകരമായി മാറ്റി</string>
<string name="message">സന്ദേശം</string>
<string name="no_notification">അറിയിപ്പുകൾ ഒന്നുമില്ല</string>
<string name="account_not_active_to_perform_deposit">നിക്ഷേപം നടത്താൻ അക്കൗണ്ട് സജീവമായിരിക്കണം</string>
<string name="account_not_active_to_perform_transfer">ട്രാൻസ്ഫർ നടത്താൻ അക്കൗണ്ട് സജീവമായിരിക്കണം</string>
<string-array name="faq_qs">
<item>പുതിയ ലോൺ അക്കൗണ്ടിനായി എങ്ങനെ അപേക്ഷിക്കാം?</item>
<item>എന്റെ പ്രൊഫൈൽ വിവരങ്ങൾ എവിടെ കാണാൻ കഴിയും?</item>
<item>എന്റെ സേവിംഗ്സ് അക്കൗണ്ട് ഇടപാടുകൾ എവിടെ കാണാൻ കഴിയും?</item>
<item>QR കോഡ് കൊണ്ടുള്ള ഉപയോഗം എന്താണ്?</item>
<item>QR കോഡ് ഉപയോഗിച്ച് എങ്ങനെ ഒരു ഗുണഭോക്താവിനെ (beneficiary) സൃഷ്ടിക്കാം?</item>
<item>ഒരു ലോൺ അക്കൗണ്ടിലേക്ക് എങ്ങനെ പണമടയ്ക്കാം?</item>
</string-array>
<string-array name="faq_ans">
<item>വായ്പാ അക്കൗണ്ടിനായി അപേക്ഷിക്കാൻ, ഹോം സ്‌ക്രീനിൽ നൽകിയിരിക്കുന്ന \"വായ്‌പയ്‌ക്ക് അപേക്ഷിക്കുക\" ക്ലിക്ക് ചെയ്യുക.</item>
<item>ഹോം സ്‌ക്രീനിലുള്ള യൂസർ ഇമേജിൽ ക്ലിക്ക് ചെയ്‌ത് നിങ്ങൾക്ക് പ്രൊഫൈൽ വിവരങ്ങൾ കാണാനാകും.</item>
<item>സേവിംഗ്‌സ് അക്കൗണ്ട് ഇടപാടുകൾ കാണുന്നതിന്, അക്കൗണ്ട്‌സ് വിഭാഗത്തിലേക്ക് പോയി, ആവശ്യമുള്ള സേവിംഗ്‌സ് അക്കൗണ്ടിൽ ക്ലിക്ക് ചെയ്യുക, മുകളിൽ വലതുവശത്തുള്ള മൂന്ന് ഡോട്ടുകളിൽ ക്ലിക്ക് ചെയ്‌ത് ഇടപാടുകൾ (Transactions) ഓപ്‌ഷൻ തിരഞ്ഞെടുക്കുക.</item>
<item>ഏതൊരു വായ്പ അല്ലെങ്കിൽ സേവിംഗ്‌സ് അക്കൗണ്ടിനുമുള്ള QR കോഡ് മറ്റ് ഉപയോക്താക്കളുമായി പങ്കിടാം, ഇത് ഒരു ഗുണഭോക്താവിനെ (beneficiary) സൃഷ്ടിക്കാൻ അവരെ അനുവദിക്കും.</item>
<item>ഒരു ഗുണഭോക്താവിനെ സൃഷ്ടിക്കാൻ, ഹോം സ്‌ക്രീനിൽ നിന്ന് ബെനിഫിഷ്യറി ഓപ്ഷനിലേക്ക് പോകുക, താഴെ വലതുവശത്തുള്ള വട്ടത്തിലുള്ള ബട്ടൺ ക്ലിക്ക് ചെയ്യുക, സ്കാൻ ചെയ്യാനുള്ള ഓപ്ഷൻ തിരഞ്ഞെടുക്കുക (ഇത് ക്യാമറ തുറക്കും), ഗുണഭോക്താവിനെ ചേർക്കേണ്ട വ്യക്തിയുടെ QR കോഡ് സ്കാൻ ചെയ്യുക. ആവശ്യമായ മറ്റ് വിവരങ്ങൾ നൽകിയ ശേഷം QR കോഡ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഗുണഭോക്താവിനെ സൃഷ്ടിക്കാൻ കഴിയും.</item>
<item>വായ്പാ അക്കൗണ്ടിലേക്ക് പണമടയ്ക്കാൻ, അക്കൗണ്ട്‌സ് വിഭാഗത്തിലേക്ക് പോയി, LOAN തിരഞ്ഞെടുക്കുക, ആവശ്യമുള്ള വായ്പാ അക്കൗണ്ട് തുറന്ന് \'Make Payment\' ഓപ്ഷൻ ക്ലിക്ക് ചെയ്യുക.</item>
</string-array>
<string name="please_wait">ദയവായി കാത്തിരിക്കൂ</string>
<string name="app_info">ആപ്പ് വിവരങ്ങൾ</string>
<string name="login_failed">ലോഗിൻ പരാജയപ്പെട്ടു, ദയവായി പിന്നീട് ശ്രമിക്കുക.</string>
<string name="pref_base_url_title">എൻഡ്‌പോയിന്റ് അപ്‌ഡേറ്റ് ചെയ്യുക</string>
<string name="pref_base_url_desc">നിങ്ങളുടെ എൻഡ്‌പോയിന്റ് കോൺഫിഗറേഷനുകൾ മാറ്റാൻ ഇവിടെ ക്ലിക്ക് ചെയ്യുക</string>
<string name="enter_base_url">ബേസ് URL നൽകുക</string>
<string name="enter_tenant">ടെനന്റ് നൽകുക</string>
<string name="refresh">പുതുക്കുക</string>
<!--Password strength strings-->
<string name="password_strength_weak">ദുർബലം</string>
<string name="password_strength_medium">ഇടത്തരം</string>
<string name="password_strength_strong">ശക്തം</string>
<string name="password_strength_very_strong">വളരെ ശക്തം</string>
<string name="loan_purpose_not_provided">ലഭ്യമാക്കിയിട്ടില്ല</string>
<string name="details">വിശദാംശങ്ങൾ</string>
<string name="product">ഉൽപ്പന്നം</string>
<string name="feature_account_dividend_payout">ലാഭവിഹിത വിതരണം</string>
<string name="feature_account_withdrawal">പിൻവലിക്കൽ</string>
<string name="feature_account_interest_posting">പലിശ രേഖപ്പെടുത്തൽ</string>
<string name="feature_account_fee_deduction">ഫീസ് കിഴിവ്</string>
<string name="feature_account_withdrawal_transfer">പിൻവലിക്കൽ ട്രാൻസ്ഫർ</string>
<string name="feature_account_rejected_transfer">നിരസിച്ച ട്രാൻസ്ഫർ</string>
<string name="feature_account_overdraft_fee">ഓവർഡ്രാഫ്റ്റ് ഫീസ്</string>
<string name="savings_account_transaction">സേവിംഗ്സ് അക്കൗണ്ട് ഇടപാട്</string>
<string name="transaction_period">ഇടപാട് കാലയളവ്</string>
<string name="transaction_type">ഇടപാട് തരം</string>
<string name="questions">ചോദ്യങ്ങൾ</string>
<string name="logged_out_successfully">വിജയകരമായി ലോഗൗട്ട് ചെയ്തു</string>
<string name="dialog_cancel_registration_message">പുതിയ അക്കൗണ്ട് രജിസ്ട്രേഷൻ റദ്ദാക്കണമെന്ന് നിങ്ങൾക്ക് ഉറപ്പാണോ?</string>
<string name="dialog_cancel_registration_title">രജിസ്ട്രേഷൻ റദ്ദാക്കുക</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -21,7 +21,7 @@ kotlin {
withJava()
}
jvmToolchain(17)
jvmToolchain(21)
sourceSets {
jvmMain.dependencies {
@ -46,8 +46,19 @@ val appVersion: String = libs.versions.packageVersion.get()
compose.desktop {
application {
mainClass = "MainKt"
val buildNumber: String = (project.findProperty("buildNumber") as String?) ?: "1"
val isAppStoreRelease: Boolean =
(project.findProperty("macOsAppStoreRelease") as String?)?.toBoolean() ?: false
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Exe, TargetFormat.Deb)
targetFormats(
TargetFormat.Pkg,
TargetFormat.Dmg,
TargetFormat.Msi,
TargetFormat.Exe,
TargetFormat.Deb
)
packageName = appName
packageVersion = appVersion
description = "Desktop Application"
@ -55,16 +66,39 @@ compose.desktop {
vendor = "Mifos Initiative"
licenseFile.set(project.file("../LICENSE"))
includeAllModules = true
outputBaseDir.set(project.layout.buildDirectory.dir("release"))
macOS {
bundleID = packageNameSpace
dockName = appName
iconFile.set(project.file("icons/ic_launcher.icns"))
notarization {
val providers = project.providers
appleID.set(providers.environmentVariable("NOTARIZATION_APPLE_ID"))
password.set(providers.environmentVariable("NOTARIZATION_PASSWORD"))
teamID.set(providers.environmentVariable("NOTARIZATION_TEAM_ID"))
minimumSystemVersion = "12.0"
appStore = isAppStoreRelease
infoPlist {
packageBuildVersion = buildNumber
extraKeysRawXml = """
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
""".trimIndent()
}
if (isAppStoreRelease) {
signing {
sign.set(true)
identity.set("The Mifos Initiative")
}
provisioningProfile.set(project.file("embedded.provisionprofile"))
runtimeProvisioningProfile.set(project.file("runtime.provisionprofile"))
entitlementsFile.set(project.file("entitlements.plist"))
runtimeEntitlementsFile.set(project.file("runtime-entitlements.plist"))
} else {
notarization {
val providers = project.providers
appleID.set(providers.environmentVariable("NOTARIZATION_APPLE_ID"))
password.set(providers.environmentVariable("NOTARIZATION_PASSWORD"))
teamID.set(providers.environmentVariable("NOTARIZATION_TEAM_ID"))
}
}
}
@ -82,9 +116,36 @@ compose.desktop {
}
}
buildTypes.release.proguard {
configurationFiles.from(file("compose-desktop.pro"))
obfuscate.set(true)
optimize.set(true)
isEnabled = false
// configurationFiles.from(file("compose-desktop.pro"))
// obfuscate.set(true)
// optimize.set(true)
}
}
}
/**
* Removes the `com.apple.quarantine` extended attribute from the built `.app`.
*
* Why:
* Gatekeeper may mark files from the Internet with `com.apple.quarantine`.
* If any such file ends up inside the `.app`, App Store validation can fail.
*/
val unquarantineApp = tasks.register<Exec>("unquarantineMacApp") {
group = "macOS"
description = "Remove com.apple.quarantine from the built .app before signing"
onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX }
dependsOn("createReleaseDistributable")
val appName = "$appName.app" // set to your final .app name
val appPath = layout.buildDirectory
.dir("release/main-release/app/$appName")
.map { it.asFile.absolutePath }
commandLine("xattr", "-dr", "com.apple.quarantine", appPath.get())
}
tasks.matching { it.name == "packageReleasePkg" }.configureEach {
dependsOn(unquarantineApp)
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.disable-library-validation</key><true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key><true/>
<key>com.apple.security.cs.debugger</key><true/>
<key>com.apple.security.device.audio-input</key><true/>
<key>com.apple.application-identifier</key><string>L432S2FZP5.org.mifos.mobile</string>
<key>com.apple.developer.team-identifier</key><string>L432S2FZP5</string>
<!-- Add more entitlements as needed -->
</dict>
</plist>

Binary file not shown.

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.disable-library-validation</key><true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key><true/>
<key>com.apple.security.cs.debugger</key><true/>
<key>com.apple.security.device.audio-input</key><true/>
</dict>
</plist>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -0,0 +1,20 @@
/*
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
actual fun getPopRules(): Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
)

View File

@ -0,0 +1,20 @@
/*
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
actual fun getPopRules(): Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
)

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,
You can obtain one at https://mozilla.org/MPL/2.0/.
See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
-->
<resources>
<string name="app_name">Mifos Móvil</string>
<string name="home">Inicio</string>
<string name="transfer">Transferir</string>
<string name="profile">Perfil</string>
<string name="not_connected">⚠️ No estás conectado a Internet</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
Copyright 2026 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -18,8 +18,10 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.mifos.mobile.core.common.DateHelper
import org.mifos.mobile.core.data.util.NetworkMonitor
import org.mifos.mobile.core.datastore.UserPreferencesRepository
import org.mifos.mobile.core.datastore.model.TimeBasedTheme
import org.mifos.mobile.core.model.LanguageConfig
import org.mifos.mobile.core.model.MifosThemeConfig
import org.mifos.mobile.core.ui.utils.BaseViewModel
@ -48,6 +50,11 @@ class ComposeAppViewModel(
.onEach { handleNetworkStatus(it) }
.launchIn(viewModelScope)
userPreferencesRepository
.observeTimeBasedThemeConfig
.onEach { trySendAction(AppAction.Internal.TimeBasedThemeUpdate(it)) }
.launchIn(viewModelScope)
userPreferencesRepository
.observeDarkThemeConfig
.onEach { trySendAction(AppAction.Internal.ThemeUpdate(it)) }
@ -137,6 +144,30 @@ class ComposeAppViewModel(
is AppAction.Internal.DynamicColorsUpdate -> handleDynamicColorsUpdate(action)
is AppAction.Internal.SystemThemeUpdate -> handleSystemThemeUpdate(action)
is AppAction.Internal.TimeBasedThemeUpdate -> handleTimeBasedThemeUpdate(action)
}
}
private fun handleTimeBasedThemeUpdate(action: AppAction.Internal.TimeBasedThemeUpdate) {
val currentThemeConfig = mutableStateFlow.value.themeConfig
val isDark = if (currentThemeConfig == MifosThemeConfig.BASED_ON_TIME) {
DateHelper.isDarkModeBasedOnTime(
startHour = action.timeBasedTheme.hourStart,
startMinute = action.timeBasedTheme.timeStart,
endHour = action.timeBasedTheme.hourEnd,
endMinute = action.timeBasedTheme.timeEnd,
)
} else {
mutableStateFlow.value.darkTheme
}
mutableStateFlow.update {
it.copy(
darkTheme = isDark,
timeBasedTheme = action.timeBasedTheme,
)
}
}
@ -147,12 +178,20 @@ class ComposeAppViewModel(
}
private fun handleAppThemeUpdated(action: AppAction.Internal.ThemeUpdate) {
val state = mutableStateFlow.value
val isDark = when (action.theme) {
MifosThemeConfig.FOLLOW_SYSTEM -> {
mutableStateFlow.value.darkTheme
}
MifosThemeConfig.FOLLOW_SYSTEM -> state.darkTheme
MifosThemeConfig.DARK -> true
MifosThemeConfig.LIGHT -> false
MifosThemeConfig.BASED_ON_TIME -> {
DateHelper.isDarkModeBasedOnTime(
startHour = state.timeBasedTheme.hourStart,
startMinute = state.timeBasedTheme.timeStart,
endHour = state.timeBasedTheme.hourEnd,
endMinute = state.timeBasedTheme.timeEnd,
)
}
}
mutableStateFlow.update {
@ -161,6 +200,7 @@ class ComposeAppViewModel(
themeConfig = action.theme,
)
}
sendEvent(AppEvent.UpdateAppTheme(osValue = action.theme.osValue))
}
@ -182,6 +222,12 @@ data class AppState(
val isDynamicColorsEnabled: Boolean,
val networkBanner: NetworkBannerState = NetworkBannerState.None,
val themeConfig: MifosThemeConfig = MifosThemeConfig.FOLLOW_SYSTEM,
val timeBasedTheme: TimeBasedTheme = TimeBasedTheme(
hourStart = 6,
hourEnd = 18,
timeStart = 0,
timeEnd = 0,
),
)
sealed interface AppEvent {
@ -210,5 +256,9 @@ sealed interface AppAction {
) : Internal()
data class SystemThemeUpdate(val isSystemDark: Boolean) : Internal()
data class TimeBasedThemeUpdate(
val timeBasedTheme: TimeBasedTheme,
) : Internal()
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -14,7 +14,6 @@ package cmp.navigation.authenticated
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.navOptions
import androidx.navigation.navigation
import cmp.navigation.authenticatednavbar.AuthenticatedNavbarRoute
import cmp.navigation.authenticatednavbar.authenticatedNavbarGraph
@ -30,10 +29,11 @@ import org.mifos.mobile.feature.accounts.accountTransactions.navigateToAccountTr
import org.mifos.mobile.feature.accounts.accounts.AccountNavRoute
import org.mifos.mobile.feature.accounts.accounts.accountsDestination
import org.mifos.mobile.feature.accounts.accounts.navigateToAccountsScreen
import org.mifos.mobile.feature.accounts.transactionDetail.navigateToTransactionDetails
import org.mifos.mobile.feature.accounts.transactionDetail.transactionDetailDestination
import org.mifos.mobile.feature.auth.login.navigateToLoginScreen
import org.mifos.mobile.feature.auth.navigation.AuthGraphRoute
import org.mifos.mobile.feature.beneficiary.beneficiaryApplication.navigateToManualBeneficiaryAddScreen
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.beneficiary.navigation.BeneficiaryNavRoute
import org.mifos.mobile.feature.beneficiary.navigation.beneficiaryNavGraph
import org.mifos.mobile.feature.beneficiary.navigation.navigateToBeneficiaryNavGraph
@ -41,7 +41,6 @@ import org.mifos.mobile.feature.charge.charges.navigateToClientChargeScreen
import org.mifos.mobile.feature.charge.navigation.clientChargeNavGraph
import org.mifos.mobile.feature.charge.navigation.navigateToChargeGraph
import org.mifos.mobile.feature.home.navigation.HomeNavigationDestination
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.loan.application.navigation.loanApplicationNavGraph
import org.mifos.mobile.feature.loan.application.navigation.navigateToLoanApplicationGraph
import org.mifos.mobile.feature.loanaccount.loanAccountDetails.navigateToLoanAccountDetailsScreen
@ -55,7 +54,8 @@ import org.mifos.mobile.feature.passcode.verifyPasscode.passcodeDestination
import org.mifos.mobile.feature.qr.navigation.qrNavGraph
import org.mifos.mobile.feature.qr.qr.navigateToQrReaderScreen
import org.mifos.mobile.feature.qr.qrCodeDisplay.navigateToQrDisplayScreen
import org.mifos.mobile.feature.recent.transaction.navigation.recentTransactionNavGraph
import org.mifos.mobile.feature.recent.transaction.navigation.navigateToRecentTransactionScreen
import org.mifos.mobile.feature.recent.transaction.navigation.recentTransactionDestination
import org.mifos.mobile.feature.savings.application.navigation.navigateToSavingsApplicationGraph
import org.mifos.mobile.feature.savings.application.navigation.savingsApplicationNavGraph
import org.mifos.mobile.feature.savingsaccount.navigation.savingsNavGraph
@ -64,18 +64,21 @@ import org.mifos.mobile.feature.settings.faq.faqDestination
import org.mifos.mobile.feature.settings.faq.navigateToFaq
import org.mifos.mobile.feature.share.application.navigation.navigateToShareApplicationGraph
import org.mifos.mobile.feature.share.application.navigation.shareApplicationNavGraph
import org.mifos.mobile.feature.shareaccount.navigation.shareNavGraph
import org.mifos.mobile.feature.shareaccount.shareAccountDetails.navigateToShareAccountDetailsScreen
import org.mifos.mobile.feature.status.navigation.StatusNavigationRoute
import org.mifos.mobile.feature.status.navigation.statusDestination
import org.mifos.mobile.feature.third.party.transfer.navigation.TptNavigationDestination
import org.mifos.mobile.feature.transfer.process.makeTransfer.makeTransferDestination
import org.mifos.mobile.feature.transfer.process.makeTransfer.navigateToMakeTransferScreen
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.navigateToTransferProcessScreen
import org.mifos.mobile.feature.transfer.process.transferProcess.transferProcessDestination
@Serializable
internal data object AuthenticatedGraphRoute
expect fun getPopRules(): Map<String, Int>
internal fun NavController.navigateToAuthenticatedGraph(navOptions: NavOptions? = null) {
navigate(route = AuthenticatedGraphRoute, navOptions = navOptions)
}
@ -114,11 +117,8 @@ internal fun NavGraphBuilder.authenticatedGraph(
is HomeNavigationDestination.Beneficiary ->
navController.navigateToBeneficiaryNavGraph()
is HomeNavigationDestination.Transaction ->
navController.navigateToAccountTransactionsScreen(
Constants.RECENT_TRANSACTIONS,
-1L,
)
is HomeNavigationDestination.TransactionHistory ->
navController.navigateToRecentTransactionScreen()
is HomeNavigationDestination.ApplyLoan ->
navController.navigateToLoanApplicationGraph()
@ -160,12 +160,25 @@ internal fun NavGraphBuilder.authenticatedGraph(
navController.navigateToSavingsAccountDetailsScreen(accountId)
} else if (accountType == Constants.LOAN_ACCOUNT) {
navController.navigateToLoanAccountDetailsScreen(accountId)
} else if (accountType == Constants.SHARE_ACCOUNTS) {
navController.navigateToShareAccountDetailsScreen(accountId)
}
},
)
accountTransactionsDestination(
navigateBack = navController::popBackStack,
navigateToDetails = { transactionId, accountType, accountId ->
navController.navigateToTransactionDetails(
transactionId = transactionId,
accountType = accountType,
accountId = accountId,
)
},
)
transactionDetailDestination(
navigateBack = navController::popBackStack,
)
clientChargeNavGraph(
@ -250,6 +263,15 @@ internal fun NavGraphBuilder.authenticatedGraph(
},
)
shareNavGraph(
navController = navController,
navigateToClientChargeScreen = navController::navigateToClientChargeScreen,
navigateToShareAccountTransactionScreen = { accountId ->
navController.navigateToAccountTransactionsScreen(Constants.SHARE_ACCOUNTS, accountId)
},
navigateToQrCodeScreen = navController::navigateToQrDisplayScreen,
)
loanApplicationNavGraph(
navController = navController,
navigateToAuthenticateScreen = navController::navigateToVerifyPasscodeScreen,
@ -274,8 +296,15 @@ internal fun NavGraphBuilder.authenticatedGraph(
locationsNavGraph()
recentTransactionNavGraph(
navController = navController,
recentTransactionDestination(
navigateBack = navController::popBackStack,
navigateToDetails = { transactionId, accountType, accountId ->
navController.navigateToTransactionDetails(
transactionId = transactionId,
accountType = accountType,
accountId = accountId,
)
},
)
beneficiaryNavGraph(
@ -471,11 +500,7 @@ fun NavController.navigateToBeneficiaryFromStatus() {
}
fun NavController.popScreens(
popRules: Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
),
popRules: Map<String, Int> = getPopRules(),
) {
val lastEntry = previousBackStackEntry?.destination?.route

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.mifos.mobile.core.data.repository.UserDataRepository
import org.mifos.mobile.core.datastore.model.AppSettings
import org.mifos.mobile.core.model.AuthState
@ -27,6 +28,16 @@ class RootNavViewModel(
) {
init {
viewModelScope.launch {
userDataRepository.authState
.collect { authState ->
if (authState is AuthState.Unauthenticated) {
if (mutableStateFlow.value !is RootNavState.Auth) {
mutableStateFlow.update { RootNavState.Auth }
}
}
}
}
combine(
userDataRepository.authState,
userDataRepository.settingsState,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2025 Mifos Initiative
* Copyright 2026 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this

Some files were not shown because too many files have changed in this diff Show More