Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
514 changes: 514 additions & 0 deletions .sdd/manifest.json

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<!-- sdd-generated-metadata
doc_kind: agent-entry
generated_from: agents@0.2.2
generated_by: claude-cli
approved_by: pending
updated_at: 2026-08-04T00:00:00Z
validation_status: not-run
-->

# AGENTS.md — kitchenSink (Cisco Webex Android SDK Kitchen Sink)

> You are the agent entry point — read first. Next: router [`SPEC_INDEX.md`](ai-docs/SPEC_INDEX.md) · system [`ARCHITECTURE.md`](ai-docs/ARCHITECTURE.md). Load this + `SPEC_INDEX.md` first; pull module/standing docs on demand.
> Context-efficiency: link to canonical docs — don't duplicate them; keep this file under ~200 lines.

> Cross-tool context file. Auto-loaded by AI coding agents. A module's high-level design lives in the manifest-routed module spec, source-local as `<module-path>/ai-docs/<module-name>-spec.md`.
> **Assess-only onboarding:** this doc set was generated in assess-only mode. Generated content is draft/non-authoritative and code remains the source of truth. Items resolved by an automated run (no human present) are marked as non-human-verified assumptions and, where a human decision is still required, `[NEEDS HUMAN INPUT]`.

## Repo Overview
**kitchenSink** is an Android sample application (the "Kitchen Sink" demo) that showcases the Cisco Webex Android SDK (`com.ciscowebex:webexsdk`) capabilities — authentication, calling, messaging, people, search, webhooks, and push — as copy-paste reference code for developers. Evidence: `README.md`, `app/build.gradle`, `settings.gradle`.

**What it is:**
- A demonstration/sample app that calls Webex SDK APIs "by sequence" so developers can copy usage patterns (`README.md`).
- A single-module Android/Gradle app (`:app`) with four SDK build flavors: `full`, `meeting`, `wxc`, `message` (`app/build.gradle`).

**What it is NOT:**
- ❌ The Webex Android SDK itself — the SDK is an external dependency resolved from `devhub.cisco.com/artifactory/webexsdk` (`build.gradle`, `app/build.gradle`).
- ❌ A production client — credentials/scopes are supplied through `local.properties`/`gradle.properties` and default to empty (`app/build.gradle`, `README.md`).

## Tech Stack
- Kotlin 2.1.20, JDK/JVM 17, Android Gradle Plugin 8.7.3, compileSdk 34, minSdk 28 (`buildSrc/.../Versions.kt`, `build.gradle`).
- Koin (DI), RxJava2, AndroidX (Lifecycle/AppCompat/RecyclerView/ViewPager2), Firebase (Messaging/Analytics/Crashlytics), Glide, Gson, OkHttp (`app/build.gradle`).
- Tests: JUnit4 (unit), AndroidX Test + Espresso (instrumented) (`app/build.gradle`).

## Architecture
```
Android UI (Activities/Fragments/ViewModels)
│ observes LiveData / calls
Feature Repositories (auth, calling, messaging, person, search, webhooks, extras)
│ ▲ events via WebexRepository observers
▼ │
WebexRepository (app-wide SDK facade) ──► Cisco Webex Android SDK (external)
```
→ Full repo architecture & component responsibilities: **[ARCHITECTURE.md](./ai-docs/ARCHITECTURE.md)**

## Module / Package Structure
```
app/src/main/java/com/ciscowebex/androidsdk/kitchensink/
├── (core) # KitchenSinkApp, WebexRepository, WebexViewModel, Koin modules
├── auth/ # Login flows (JWT, OAuth, access-token)
├── calling/ # Call control, closed captions, calendar meetings
├── messaging/ # Spaces, teams, memberships, message composer
├── person/ # People CRUD
├── search/ # Space filter + call history
├── webhooks/ # Webhook CRUD
├── extras/ # Token utilities + crash/diagnostic triggers
└── firebase/ # FCM push handling
```
→ Per-module docs and the spec router: **[ai-docs/SPEC_INDEX.md](./ai-docs/SPEC_INDEX.md)**

## Critical Rules
1. **Code is the source of truth.** Every module here is `Untracked` in `.sdd/manifest.json`; never invent an SDK API, path, event, flag, or constant — read the real file and the SDK.
2. **Ask before coding.** Present a plan / Spec Summary; wait for confirmation.
3. **Never commit secrets.** `CLIENT_ID`, `CLIENT_SECRET`, `REDIRECT_URI`, `WEBHOOK_URL`, and `SCOPE` come from `local.properties`/`gradle.properties` and must stay out of source and logs (`app/build.gradle`, `README.md`).
4. **One WebexSDK flavor at a time.** Only one of the `full`/`meeting`/`wxc`/`message` SDK dependencies is active per build (`app/build.gradle`).

## Essential Commands
| Role | Command |
|---|---|
| Install | (Gradle resolves on build; ensure access to `devhub.cisco.com/artifactory/webexsdk`) |
| Build | `./gradlew assembleFullDebug` |
| Unit test | `./gradlew testFullDebugUnitTest` |
| Lint/format | `./gradlew lintFullDebug` |
→ Full command surface, toolchain, and registries: **[GETTING_STARTED.md](./ai-docs/GETTING_STARTED.md)** · test tiers & coverage gate: **[TEST_INDEX.md](./ai-docs/TEST_INDEX.md)**

## Common Gotchas
1. A missing/empty `local.properties` leaves `CLIENT_ID`/`CLIENT_SECRET`/`REDIRECT_URI` empty, so OAuth login silently cannot authorize (`app/build.gradle` defaults them to `""`).
2. Firebase requires `google-services` config; `KitchenSinkApp` calls `FirebaseApp.initializeApp` at startup and push handling depends on FCM being configured (`KitchenSinkApp.kt`, `firebase/KitchenSinkFCMService.kt`).
3. Koin modules are loaded lazily by login type; calling a feature view model before `loadKoinModules(type)` runs will fail DI resolution (`KitchenSinkApp.kt`).

## Pre-Commit Checklist
- [ ] Unit/instrumented tests pass for the touched flavor
- [ ] Spec/docs updated in the same change (spec-currency)
- [ ] No hardcoded secrets; credentials remain in `local.properties`
- [ ] Affected module spec under `<module>/ai-docs/` updated when SDK usage changes

---
**SDD coverage:** this repo's per-module coverage state lives in `.sdd/manifest.json` (mirror in
`ai-docs/SPEC_INDEX.md`). All modules are currently `Untracked` (assess-only baseline) — treat code as authoritative and cross-check before relying on any generated spec.
121 changes: 121 additions & 0 deletions ai-docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<!-- sdd-generated-metadata
doc_kind: standing-doc
generated_from: architecture@0.2.2
generated_by: claude-cli
approved_by: pending
updated_at: 2026-08-04T00:00:00Z
validation_status: not-run
-->

# ARCHITECTURE — kitchenSink

> Start here → root [`AGENTS.md`](../AGENTS.md) (agent entry) · router [`SPEC_INDEX.md`](SPEC_INDEX.md). This is the system architecture; per-module detail lives in each manifest-routed module spec, source-local as `<module-path>/ai-docs/<module-name>-spec.md`.
> Context-efficiency: link to canonical docs — don't duplicate them; this loads on demand, not upfront.

## Design Overview
kitchenSink is a single-module Android application (`:app`, `settings.gradle`) that demonstrates every capability of the Cisco Webex Android SDK. The app is organized as a thin UI layer (Activities/Fragments + AndroidX `ViewModel`s) over a set of feature **repositories**, each of which wraps a slice of the Webex SDK and exposes RxJava `Observable`s or Android `LiveData` to the UI. Evidence: `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/` package tree, `WebexRepository.kt`, `WebexViewModel.kt`.

The central design choice is a single app-wide facade, `WebexRepository`, that holds the `Webex` SDK instance, registers the SDK's observers (space/membership/message/calendar/call), tracks in-flight call state, and re-publishes SDK events as `LiveData`/typed events for the UI (`WebexRepository.kt`). Feature repositories (`auth`, `calling`, `messaging`, `person`, `search`, `webhooks`, `extras`) are wired through Koin dependency injection and loaded lazily according to the selected login type (`KitchenSinkApp.kt`, `WebexModule.kt`, `MainAppModule` referenced from `KitchenSinkApp.kt`).

Because the SDK ships as four mutually exclusive build flavors (`full`, `meeting`, `wxc`, `message`), the app selects exactly one Webex SDK artifact per build (`app/build.gradle`). The app persists no domain data of its own; state is either in-memory (call/observer maps in `WebexRepository`) or delegated to the SDK and remote Webex services.

## Component Inventory & Responsibilities
| Component | Responsibility (one line) | Docs |
|---|---|---|
| `app/src/main/java/.../kitchensink/` (core) | Webex SDK facade, shared view model, Koin DI graph, app lifecycle | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/ai-docs/kitchensink-core-spec.md` |
| `.../kitchensink/auth/` | Login flows: JWT, OAuth web, access-token | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/auth/ai-docs/auth-spec.md` |
| `.../kitchensink/calling/` | Call control, closed captions, calendar meetings | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/calling/ai-docs/calling-spec.md` |
| `.../kitchensink/messaging/` | Spaces, teams, memberships, message composer | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/messaging/ai-docs/messaging-spec.md` |
| `.../kitchensink/person/` | People CRUD | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/person/ai-docs/person-spec.md` |
| `.../kitchensink/search/` | Space filter search + call history | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/search/ai-docs/search-spec.md` |
| `.../kitchensink/webhooks/` | Webhook CRUD | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/webhooks/ai-docs/webhooks-spec.md` |
| `.../kitchensink/extras/` | Token utilities + crash/diagnostic triggers | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/extras/ai-docs/extras-spec.md` |
| `.../kitchensink/firebase/` | FCM push handling | `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/firebase/ai-docs/firebase-spec.md` |

## Component Interaction
```mermaid
graph TD
UI[Activities / ViewModels] -->|calls| REPO[Feature Repositories]
UI -->|observes LiveData| WR[WebexRepository]
REPO -->|calls| SDK[Cisco Webex Android SDK]
WR -->|holds instance / registers observers| SDK
SDK -->|SDK events| WR
WR -->|LiveData / typed events| UI
FCM[KitchenSinkFCMService] -->|processPushNotification| WR
FCM -->|notifications| ANDROID[Android NotificationManager]
```
The main path: an Activity/ViewModel calls a feature repository, which invokes a Webex SDK API with a `CompletionHandler`; results are surfaced as RxJava `Observable`s. Asynchronous SDK events (incoming calls, space/membership/message/calendar changes) flow through observers registered by `WebexRepository` and are re-published as `LiveData`/typed events. Push messages enter through `KitchenSinkFCMService`, which routes them to `WebexRepository.webex.phone` and raises Android notifications. Evidence: `WebexRepository.kt`, `WebexViewModel.kt`, `firebase/KitchenSinkFCMService.kt`.

## Execution & Flow
### App Init & Call Flow
On process start, `KitchenSinkApp.onCreate` initializes Firebase and starts Koin; login type (persisted in shared prefs) drives `loadKoinModules(type)` to register the feature/DI modules (`KitchenSinkApp.kt`). A representative runtime flow: user authenticates via `auth/` → `WebexRepository` registers incoming-call and domain observers → an incoming call arrives (directly or via FCM push) → `WebexRepository` stores the `Call`, attaches a `WxCallObserver`, and fans events out to registered `CallObserver`s and `LiveData` consumed by `calling/` view models (`WebexRepository.kt`, `firebase/KitchenSinkFCMService.kt`).

## Dependencies
| Dependency | Type (internal / external / peer) | How used | Failure / version handling |
|---|---|---|---|
| Cisco Webex Android SDK (`com.ciscowebex:webexsdk` 3.16.3) | external | Core capability provider (phone, spaces, messages, people, calendar, webhooks, auth) | Resolved from Artifactory; one flavor per build; version pinned in `app/build.gradle` |
| Koin 2.2.3 | external | Dependency injection for repositories/view models | Version floor in `buildSrc/.../Versions.kt` |
| RxJava2 (rxjava 2.2.11, rxandroid, rxkotlin) | external | Async wrapping of SDK completion handlers | `app/build.gradle` |
| AndroidX Lifecycle / AppCompat / RecyclerView / ViewPager2 | external | UI + lifecycle-aware event delivery | `app/build.gradle`, `buildSrc/.../Dependencies.kt` |
| Firebase (BoM 26.1.0: Messaging/Analytics/Crashlytics) | external | Push messaging + crash/analytics reporting | Requires google-services config; `app/build.gradle`, `build.gradle` |
| Glide / Gson / OkHttp / Nimbus JOSE JWT | external | Image loading, JSON, HTTP, JWT handling | `app/build.gradle` |

### State Model
- The app holds transient, in-memory client state, not persisted domain data. `WebexRepository` maintains call/observer maps (`_callObservers`, `_incomingCallListeners`), current/old/space call ids, media toggles (audio/video mute, bandwidth, scaling mode), and UC login connection status. `KitchenSinkApp` holds process-level flags (`inForeground`, `isUCSSOLogin`, `isKoinModulesLoaded`). Evidence: `WebexRepository.kt` (lines with `var currentCallId`, `_callObservers`), `KitchenSinkApp.kt`.
- Small persisted preferences (login type, email) are stored via `SharedPrefUtils` in Android SharedPreferences, not an app-owned datastore. Evidence: `utils/SharedPrefUtils.kt`.

## Cross-Cutting Concerns
- **Security:** Authentication is delegated to Webex SDK authenticators (JWT/OAuth/token) selected in `auth/` (`auth/LoginRepository.kt`, `auth/LoginModule.kt`). Client credentials/scopes are injected from `local.properties`/`gradle.properties` into `BuildConfig` and default to empty (`app/build.gradle`). See `SECURITY.md`.
- **Observability:** Android `Log` is used throughout for diagnostics (e.g. `WebexRepository.kt`, `firebase/KitchenSinkFCMService.kt`); Firebase Crashlytics is enabled on the SDK (`WebexModule.buildCrashEnabledWebex`) and via the Crashlytics Gradle plugin (`app/build.gradle`). `extras/` provides deliberate crash triggers for diagnostics.

## Non-Functional Posture
Performance & footprint: a demo app, not SLO-bound. The build produces per-ABI split APKs plus a universal APK for `x86`, `x86_64`, `armeabi-v7a`, `arm64-v8a` (`app/build.gradle` `splits.abi`). Release builds enable R8/minify with ProGuard rules (`app/build.gradle`). No performance targets are declared in the repo; `[NEEDS HUMAN INPUT]` if formal targets are expected.

## Dependency / Interaction Topology
```mermaid
graph LR
auth --> WebexRepository
calling --> WebexRepository
messaging --> WebexRepository
person --> WebexRepository
search --> WebexRepository
webhooks --> WebexRepository
extras --> WebexRepository
firebase --> WebexRepository
WebexRepository --> SDK[Webex SDK]
```
| From | To | Kind (call / event) | Purpose |
|---|---|---|---|
| Feature repositories | Webex SDK | call | Invoke SDK APIs (people, spaces, messages, phone, webhooks, calendar) |
| Webex SDK | WebexRepository | event | Observer callbacks (call/space/membership/message/calendar) re-published as LiveData |
| KitchenSinkFCMService | WebexRepository | call | Route push payloads to `webex.phone` and raise notifications |
| KitchenSinkApp | Koin modules | call | Load/unload DI modules per login type |

## Observability Patterns
- **Logging:** Android `Log.d/e/i/w` with per-class TAGs (e.g. `"WebexRepository"`, `"PUSHREST"` in the FCM service). No structured/correlation-id convention is enforced. Evidence: `WebexRepository.kt`, `firebase/KitchenSinkFCMService.kt`.
- **Metrics:** None app-owned. Firebase Analytics is included as a dependency (`app/build.gradle`).
- **Audit:** Not applicable — no audit trail in this demo app.

## Cross-Repo Dependency Graph
- **Internal (same org):** Cisco Webex Android SDK (`com.ciscowebex:webexsdk*`), consumed from `devhub.cisco.com/artifactory/webexsdk`; this app is a consumer only (`build.gradle`, `app/build.gradle`). The related SDK source repo is linked from `README.md` (`webex/webex-android-sdk`).
- **Cross-project:** none recorded.
- **External read-only:** none recorded.
- **External services:** Cisco Webex cloud services (reached through the SDK); Firebase Cloud Messaging for push.

## Security Architecture
Trust boundary: the app is an untrusted client to Webex cloud services. Identity is established through Webex SDK authenticators — JWT, OAuth 2.0 web flow, or access token — chosen in `auth/`. Tokens are held/refreshed by the SDK authenticator; the app can read the current token via `extras/ExtrasRepository.getAccessToken()`/`getRefreshToken()` (`extras/ExtrasRepository.kt`). No encryption-at-rest is implemented by the app beyond Android SharedPreferences for non-secret preferences. Transport security to Webex/Firebase is provided by the SDK/Firebase over HTTPS. See `SECURITY.md` for the full posture; formal trust-boundary review is `[NEEDS HUMAN INPUT]`.

---
→ Per-module orientation and detailed design live in each manifest-routed module spec, source-local as `<module-path>/ai-docs/<module-name>-spec.md`. Routing: `SPEC_INDEX.md`.

## Architecture Reference Links
| Reference | Location | When to read |
|---|---|---|
| Architecture decisions | `adr/` | To understand why major design choices were made (no ADRs recorded yet in this assess-only pass) |
| Repo patterns | `patterns/` | To follow established implementation conventions (not extracted in this assess-only pass) |
| Enforceable rules | `RULES.md` | To understand constraints every architecture-affecting change must obey |

## WS6 References
| WS6 artifact | Relevance to this repo | Link |
|---|---|---|
| — | No WS6 specs, platform architecture, or enterprise architecture documents were found in this repo during assess-only onboarding. | — |
Loading