# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Rule 0: Never Guess — Investigate First

This is the most important rule. Do not give guess answers. Guessing leads to frustration, burns energy and time, and sends us down wrong paths.

Before answering any question or making any recommendation:

- **Investigate** — read files, grep code, check logs, search the web, test assumptions
- If you can't investigate due to tool limitations — **say so explicitly**. Tell the user exactly what to check and ask them to share the results
- **Never present uncertain information as fact** — if you're not sure, say "I don't know, let me check" not "I think it's X"
- **Don't propose solutions before understanding the problem** — read the code, check the actual file structure, verify before sharing
- **Don't make premature decisions** — gather data first, present options, let the user decide

When in doubt: **Ask.** A 30-second question saves hours of wrong-direction work.

## Rule 1: Token Efficiency — Without Sacrificing Quality

Output quality is non-negotiable. But the same quality can be achieved with fewer tokens by being smart about it.

**Core principle:** Don't do redundant work. Every token should contribute to a better outcome.

- **Use the smallest tool that gets the job done** — Grep before Explore agent, `offset`/`limit` before full-file read, direct action before plan mode
- **Don't re-read known patterns** — if session_status.md or memory documents a pattern, trust it and execute
- **Batch parallel reads** — think through what you need upfront, fetch it all at once

**Long sessions are expensive:** LLMs resend the full conversation history every message. After a task is complete and the next task is unrelated, suggest a new session — but **always update session_status.md first** (what was done, what's next, key decisions) so the next session picks up without quality loss. Never suggest a new session without saving context first.

## Project Overview

Flutter mobile community platform ("Fluent Community") — white-label app with offline-first support, dynamic UI rendering, and course/lesson management. Package name: `fc_mobile_stand_alone`.

## Build & Development Commands

This project uses **FVM** (Flutter Version Manager) with Flutter 3.35.6. Prefix all Flutter/Dart commands with `fvm`:

```bash
# Run code generation (JSON serialization, etc.) — required after modifying models with @JsonSerializable
fvm dart run build_runner build --delete-conflicting-outputs

# Static analysis
fvm flutter analyze

# Run the app
fvm flutter run

# Local APK build (includes Google Drive upload)
./local_build.sh

# Local AAB build
./local_aab_build.sh

# White-label build (configures app name, package, domain, signing, icons)
./build_flow.sh

# Update appza_engine dependency
./refresh_the_engine.sh
```

## Architecture

This is a **Server-Driven UI (SDUI)** app. The server sends JSON page configs containing `views[]` with `class_type`, `selected_design`, `items`, `pagination`, and `filters`. The client renders these dynamically via the `Renderer` system.

### SDUI Lifecycle

```
Controller.onInit() → page function (appza_pages.dart)
  → getAppzaPage() → GET /screen?slug={pageName}
  → Server returns {views: [{class_type, selected_design, items, ...}]}
  → Renderer(views, pageConfig) → PageRenderer (appza_engine)
  → GetSelectedCardView routes class_type → CardViewFactory
  → Factory.createCardView(designNumber, args) → Design Widget
```

### Layer Structure

- **`lib/data/services/network/`** — API layer: `services.dart` (base API classes + auth functions), `appza_pages.dart` (page config fetchers with transforms), `api_helpers.dart` (internal API call functions — see API Services below)
- **`lib/data/services/api_services/`** — 16 feature service classes with static methods centralizing all API calls (see API Services below)
- **`lib/data/services/session_manager/`** — SharedPreferences wrapper for auth/session
- **`lib/presentation/core/base/`** — `BaseController` (page state management), `SduiPageController` (base for SDUI pages — subclasses just implement `fetchPageConfig()`), `BasePageView` (state-driven UI rendering)
- **`lib/presentation/core/renderer/`** — SDUI rendering: card factories, data source resolver, appbar/navbar selection
- **`lib/presentation/features/`** — Feature-specific controllers and screens (course, landing)
- **`lib/presentation/pages/`** — Variant and non-variant screens
- **`lib/core/`** — Cache, database (Hive/SQLite), models, startup services, utilities

### State Management & Navigation

**GetX** (`get` package) for state management, dependency injection, and routing. Controllers extend GetX controllers and are bound via `Get.put()` / `Get.lazyPut()`.

### Key Patterns

**Barrel file** — `lib/importer.dart` re-exports common dependencies (GetX, Dio, appza_engine, core utilities). Import this instead of individual packages.

**SduiPageController** — Base controller for SDUI detail pages. Subclasses only implement `fetchPageConfig()` to specify which page function to call. Provides `renderer` and `refreshPage()` automatically.

**API Services** — 16 service classes in `lib/data/services/api_services/` with static methods wrapping all API calls. No DI needed — call directly via `CourseService.enrollInCourse(...)`. Services import `api_helpers.dart` internally; consumer code must NOT import `api_helpers.dart` directly.

Two API base URLs exist:
- `FcomApiService` → `/wp-json/appza/fcom-mobile/api/v1/` (most endpoints)
- `AppzaApiService` → `/wp-json/appza/api/v1/` (auth endpoints like `/app-logout`, `/auto-login`)

The 4 internal functions in `api_helpers.dart`:
- `getCommunityData()` — GET requests via FcomApiService
- `postCommunityData()` — POST requests via FcomApiService
- `getAppzaData()` — GET requests via AppzaApiService
- `postAppzaData()` — POST requests via AppzaApiService

All 16 services:
| Service | Purpose |
|---------|---------|
| `AuthService` | Login, logout, auto-login, OTP, Google login, forgot password, app config |
| `FeedService` | Feed actions (like, pin, move, delete, create, update, scheduled posts) |
| `FeedCommentService` | Comment CRUD, replies, likes |
| `CourseService` | Enrollment, lessons, quizzes, progress |
| `SpaceService` | Join/leave, members, settings, unread counts |
| `ChatService` | Messages, threads, block/unblock, mark read |
| `ProfileService` | Profile CRUD, photos, block/unblock users |
| `MemberService` | Member status changes, invites |
| `NotificationService` | Mark read, notification count |
| `DocumentService` | Upload, delete, update, download permissions |
| `MediaUploadService` | File/image uploads |
| `DrawerService` | Space groups, menu items, links |
| `SearchService` | Feed search, space dropdown |
| `OptionsService` | Translations, social link providers |
| `UserService` | User profile data |
| `LeaderboardService` | Leaderboard, levels, profile |

New API actions should be added to the appropriate service class, not scattered in controllers or card views.

**Card Factories** — `GetSelectedCardView` maps server `class_type` strings to `CardViewFactory` implementations. Each factory uses `switch(designNumber)` for design variants.

**Data Source Resolver** — `renderer_configs/data_source_resolver.dart` routes pagination `data_source.type` to `OnlineOnlyDataSource` or `OfflineFirstDataSource`.

**Offline-first with Hive** — `lib/core/database/hive_database.dart` manages Hive boxes for caching. `OfflineFirstDataSource` tries API first, caches to local DB, falls back to cache on failure.

**appza_engine** — Core SDUI dependency from a private git repo. Provides `PageRenderer`, `Views`, `BaseApiService`, `IPaginationDataSource`, and other SDUI infrastructure.

### Feature Flags

`lib/app_build_constant.dart` controls build-time toggles:
- `hasFirebase` — Firebase services (currently `false`)
- `hasGoogleLogin` — Google Sign-In

### Entry Point

`lib/main.dart` calls `initializeApp(Environment.premium)` which sets up Firebase (if enabled), Hive, EasyLoading, and other services in `lib/app_initializer.dart`.

## Key Dependencies

- `appza_engine`: Private GitHub dependency — the SDUI engine core. Provides `PageRenderer`, `Views`, `BaseApiService`, `IPaginationDataSource`, and other SDUI infrastructure. Shared by both appza_community and fc_mobile_stand_alone. When a task touches appza_engine types or imports, read `../appza_engine/CLAUDE.md` for context. If not found, ask user to clone it as a sibling directory.
- `fc_mobile_stand_alone`: Sibling project at `../fc_mobile_stand_alone/`. Reference it when porting patterns (SpaceEventService, non-variant controllers, local-first data). Read its CLAUDE.md for architecture details.

### Project Distinction (appza_community vs fc_mobile_stand_alone)

Both projects share the same package name (`fc_mobile_stand_alone`), the same `appza_engine`, and the same inner architecture (renderer, card views, factories). The difference is:

- **appza_community (this repo)** — SDUI + White-label. Single domain per build. Page JSON is **fetched from the server** (`GET /screen?slug=...`). Each client gets a custom build via `build_flow.sh`.
- **fc_mobile_stand_alone** — Multi-tenant. User switches domains at runtime (baseUrl changes). Page JSON is **hardcoded locally**; data is fetched separately and injected into the JSON.

Card views, factories, entities, and screen patterns can be ported directly between the two. Only page config source differs (server vs hardcoded).

## Task Workflow (when working from LazyTasks)

1. **Pick task** → set status to "In Progress" via background agent
2. **Understand** → read task description, investigate related code
3. **Clarify if needed** → if task description is vague or missing:
   - First investigate the code to understand current behavior
   - Ask user to help gather context (screenshots, screen recordings)
   - Then add a comment on the task via the comment API with gathered context, asking SQA specific questions
4. **Plan** → for multi-file changes, write a plan first and wait for approval
5. **Implement** → make the changes
6. **Verify** → follow Change Verification steps below (mandatory)
7. **Test steps** → provide exact steps for user to manually verify on device
8. **Wait for user confirmation** → don't mark done until user says it's verified
9. **Commit** → only when user explicitly asks
10. **Complete** → set task status to "Complete" via background agent
11. **Reassign** → if task was created by Nusrat (createdBy_id: 11), assign back to her. If created by someone else, ask user who to assign to.

All LazyTasks API calls go through background sub-agents — never block the main session.

## Change Verification (mandatory)

Never declare a change "done" without verification:

1. **Static analysis**: `fvm flutter analyze` on changed files
2. **Grep**: check for other occurrences that may need the same change
3. **UI changes**: build APK → install on connected device → ask user to navigate to the screen → capture recording → verify visually
4. **Logic changes**: run relevant tests (`fvm flutter test`)
5. **Provide test steps**: always tell the user exactly how to manually verify

## Memory

**IMPORTANT:** All memory files live in the **repo-local** `.claude/memory/` directory (git-tracked), NOT in `~/.claude/projects/`. Always read from and write to `.claude/memory/` relative to the project root.

Path to `.claude/memory/` files:
- `MEMORY.md` — index of all memory files
- `session_status.md` — what's in progress, what's next
- `feedback.md` — corrections and preferences
- `appza_engine_reference.md` — pointer to appza_engine
- `fc_mobile_reference.md` — pointer to fc_mobile_stand_alone for porting

## Start of Session Ritual

- Read `session_status.md` and `feedback.md` first
- Ask: "Is this still current, or are we working on something different today?"

## End of Session

- Update `session_status.md` to reflect next steps or "nothing pending"

## Git Conventions

- **All merges to main must be squash merges** — keeps main history clean with one commit per feature/refactor
- Force push to main is acceptable after squash merges (required to replace history)

## Conventions

- Models using `@JsonSerializable` require running `build_runner` after changes
- Variant screens (`presentation/pages/variant_screens/`) support multiple design variations; non-variant screens (`non_variant_screens/`) are shared across all variants
- The GetX import in `importer.dart` hides `StringExtension`, `Response`, `MultipartFile`, `FormData` to avoid conflicts with Dio
- `api_helpers.dart` is internal to `lib/data/services/` — never import it from controllers, views, or other consumer code
- Android: compileSdk 36, Java/Kotlin JVM target 17
- iOS: minimum deployment target 15.5
