Skip to content
Open
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
196 changes: 196 additions & 0 deletions .sdd/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
{
"manifest_version": 1,
"repository": {
"name": "kitchenSink",
"purpose": "Android Kitchen Sink demo app that exercises the Cisco Webex Android SDK (auth, calling, messaging, meetings, webhooks) through a sample UI.",
"category": "cat1-legacy",
"primary_languages": ["kotlin"]
},
"topology": "Single-repo",
"commands": {
"assemble": { "command": "./gradlew assembleFullDebug", "source_file": "app/build.gradle", "role": "package" },
"build": { "command": "./gradlew build", "source_file": "build.gradle", "role": "build" },
"unit-test": { "command": "./gradlew testFullDebugUnitTest", "source_file": "app/build.gradle", "role": "unit-test" },
"instrumented-test": { "command": "./gradlew connectedFullDebugAndroidTest", "source_file": "app/build.gradle", "role": "e2e" },
"clean": { "command": "./gradlew clean", "source_file": "build.gradle", "role": "other" }
},
"toolchain": [
{ "name": "gradle", "version": "8.9", "origin": "repo-config", "source_file": "gradle/wrapper/gradle-wrapper.properties" },
{ "name": "android-gradle-plugin", "version": "8.7.3", "origin": "repo-config", "source_file": "build.gradle" },
{ "name": "jdk", "origin": "unknown" }
],
"registries": [
{
"name": "google-maven",
"type": "maven",
"host": "dl.google.com",
"settings_file": "build.gradle",
"egress_required": true,
"origin": "repo-config",
"source_file": "build.gradle"
},
{
"name": "maven-central",
"type": "maven",
"host": "repo.maven.apache.org",
"settings_file": "build.gradle",
"egress_required": true,
"origin": "repo-config",
"source_file": "build.gradle"
},
{
"name": "webex-artifactory",
"type": "maven",
"host": "devhub.cisco.com",
"settings_file": "build.gradle",
"egress_required": true,
"origin": "repo-config",
"source_file": "build.gradle"
}
],
"artifacts": [
{
"name": "Cisco Webex Android SDK (full)",
"type": "maven-dependency",
"coordinates": "com.ciscowebex:webexsdk",
"version": "3.16.3",
"registry": "webex-artifactory",
"source_file": "app/build.gradle"
},
{
"name": "Cisco Webex Android SDK (meeting)",
"type": "maven-dependency",
"coordinates": "com.ciscowebex:webexsdk-meeting",
"version": "3.16.3",
"registry": "webex-artifactory",
"source_file": "app/build.gradle"
},
{
"name": "Cisco Webex Android SDK (wxc)",
"type": "maven-dependency",
"coordinates": "com.ciscowebex:webexsdk-wxc",
"version": "3.16.3",
"registry": "webex-artifactory",
"source_file": "app/build.gradle"
},
{
"name": "Cisco Webex Android SDK (message)",
"type": "maven-dependency",
"coordinates": "com.ciscowebex:webexsdk-message",
"version": "3.16.3",
"registry": "webex-artifactory",
"source_file": "app/build.gradle"
}
],
"tests": {
"unit": { "command_ref": "unit-test", "dir": "app/src/test", "framework": "JUnit 4" },
"e2e": { "command_ref": "instrumented-test", "dir": "app/src/androidTest", "framework": "AndroidX Test + Espresso" }
},
"quality_gates": {
"code_coverage": {
"origin": "none",
"declared_by": "repo config (gradle.properties enableCodeCoverage=OFF); no enforced repo coverage gate"
}
},
"coverage_status_definitions": {
"specced": ">=80% public surface specced, drift <5% — spec is authoritative",
"partial": "40-80% specced — spec is a hint, cross-check code",
"untracked": "<40% specced — code is the source of truth"
},
"modules": [
{
"path": "app/",
"coverage_status": "Partial",
"coverage_evidence": "First SDD onboarding (assess-only). Draft canonical spec generated from source; module-boundary and coverage baseline were resolved by the automated config-fallback default and are not human-verified. No prior spec existed; coverage will be measured by the host-owned first coverage review.",
"canonical_spec": "app/ai-docs/app-spec.md",
"contracts": {
"provides": ["Android launcher entry: .auth.LoginActivity (exported=true, intent-filter action=android.intent.action.MAIN / category=android.intent.category.LAUNCHER)", "Exported Android Activity: .calling.CallActivity (exported=true, launchMode=singleTask, no intent-filter; externally startable call UI, supports lock-screen display and picture-in-picture)", "Exported Android Service: .CallRejectService (exported=true; externally invocable Service that on action Constants.Action.WEBEX_CALL_REJECT_ACTION with String extra Constants.Intent.CALL_ID and int extra Constants.Intent.CALLING_ACTIVITY_ID cancels the call notification and rejects the identified call via WebexRepository)"],
"requires": ["com.ciscowebex:webexsdk* 3.16.3 (auth, phone, messaging, spaces, calendarMeetings)", "Firebase Cloud Messaging + Analytics + Crashlytics", "Koin DI", "RxJava/RxAndroid", "local.properties CLIENT_ID/CLIENT_SECRET/REDIRECT_URI/WEBHOOK_URL"]
},
"last_assessed": "2026-08-06",
"section_profile": {
"has_ui": true,
"crosses_service_boundaries": true,
"enforces_domain_rules": false,
"is_concurrent_async": true,
"owns_persistence": false,
"returns_caller_errors": false,
"has_design_tradeoff": null,
"stateful_transitions": true,
"exposes_wire_protocol": false,
"ui_multi_screen": true,
"large_data_model": false,
"has_tiers": false,
"module_specific_conventions": false,
"published_package": false,
"embedded_in_host": false,
"holds_client_state": true,
"has_submodules": false,
"resolved_by": "claude-cli (bootstrap questionnaire, assess-only; module-tree computed for has_submodules)",
"resolved_at": "2026-08-06T00:00:00Z"
}
}
],
"spec_policy": {
"delta_grammar": {
"added": "## ADDED Requirements",
"modified": "## MODIFIED Requirements",
"removed": "## REMOVED Requirements"
},
"require_what_and_why": true,
"require_provenance": true,
"protected_specs": [],
"required_sections_by_change_class": {
"core_always": ["Intent (WHAT)", "Rationale (WHY)", "Scope/Out-of-scope", "Acceptance criteria", "Contracts delta"],
"security_or_contract_or_perf_critical": ["Data", "Error Matrix", "Resilience", "Observability", "Operations"]
}
},
"validation": {
"generator_runtime": "claude-cli",
"generator_model": "us.anthropic.claude-opus-4-8",
"generator_runtime_source": "invocation-input",
"minimum_independence": "different-runtime",
"blocking_severities": ["Blocking"],
"generator_run_id": "c7f4b6b8-eeda-44a3-9a9b-27d8a549279b"
},
"layout": {
"sdd_root": ".sdd",
"docs_root": "ai-docs",
"standing_docs_root": "ai-docs",
"agent_entry_path": "AGENTS.md",
"spec_index_path": "ai-docs/SPEC_INDEX.md",
"module_docs_strategy": "source-local",
"module_docs_folder_name": "ai-docs",
"template_roots": {
"canonical": ".sdd/templates",
"extensions": [".sdd/templates/extensions"]
},
"repo_skills_root": ".sdd/skills",
"contracts_strategy": "root-index-module-detail"
},
"substrate": {
"source": "the repo's own build/standard files",
"consumed": ["Gradle build config (build.gradle, app/build.gradle, buildSrc)", "standard files (README.md)", "gradle.properties"],
"compliance_tier": "baseline"
},
"section_profiles": {
"repo": {
"owns_datastore": false,
"holds_client_state": true,
"components_interact": true,
"domain_data_across_components": false,
"caches_data": false,
"observability_convention": true,
"deploys_to_infra": true,
"shared_base_libs": false,
"is_monorepo": false,
"multi_platform": false,
"published_package": false,
"embedded_in_host": false,
"cross_repo_deps_material": false,
"security_arch_warranted": true
},
"resolved_by": "claude-cli (bootstrap questionnaire, assess-only)",
"resolved_at": "2026-08-06T00:00:00Z"
}
}
93 changes: 93 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<!-- sdd-generated-metadata
doc_kind: agent-entry
generated_from: agents@0.2.2
generated_by: claude-cli
approved_by: pending
updated_at: 2026-08-06T00: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. Draft artifact from an assess-only
> onboarding: code remains the source of truth; unresolved confirmations are marked
> `[NEEDS HUMAN INPUT]`.

## Repo Overview
**kitchenSink** is a sample ("Kitchen Sink") Android application that demonstrates how to call and use the Cisco Webex Android SDK — authentication, calling/meetings, messaging, spaces/teams, and webhooks — as reference code developers can copy (`README.md`, `app/src/main/`).

**What it is:**
- A single-module Android demo app (`app/`) with a minimum of Android 9 / API 28 (`app/build.gradle` delegates `minSdk` to `Versions.minSdk`, declared `const val minSdk = 28` in `buildSrc/src/main/java/com/ciscowebex/androidsdk/build/Dependencies.kt`).
- A working harness exercising `com.ciscowebex:webexsdk*` 3.16.3 across four build flavors (`full`, `meeting`, `wxc`, `message`) (`app/build.gradle`).
**What it is NOT:**
- ❌ The Webex SDK itself (it is a consumer of that SDK, pulled from `devhub.cisco.com`).
- ❌ A published/reusable library — it is an application (`applicationId "com.cisco.sdk_android"`).
- ❌ An owner of a backend/datastore — all domain data comes from Webex services via the SDK.

## Tech Stack
- Kotlin (Android), Gradle 8.9, Android Gradle Plugin 8.7.3 (`gradle/wrapper/gradle-wrapper.properties`, `build.gradle`).
- Koin (DI), RxJava/RxAndroid, AndroidX + Material + data-binding, Firebase (FCM/Analytics/Crashlytics), Glide, OkHttp.
- Tests: JUnit 4 (JVM unit) + AndroidX Test/Espresso (instrumented) (`app/build.gradle`).

## Architecture
```
Activities/Fragments (UI, data-binding)
│ observe LiveData
WebexViewModel (BaseViewModel) ──► Webex SDK (direct: phone.dial, connectPhoneServices, setAdvancedSetting, authenticator.deauthorize)
│ └──► WebexRepository ──► Webex SDK (observers/state; auth, phone, messages, spaces, calendarMeetings)
▲ │ observers / CompletionHandler
Koin DI (per login type) ▼
Webex cloud services + Firebase (FCM)
```
→ Full repo architecture & component responsibilities: **[ARCHITECTURE.md](./ai-docs/ARCHITECTURE.md)**

## Module / Package Structure
```
app/ # the single Android application module
src/main/java/.../kitchensink/
KitchenSinkApp.kt # Application; Koin bootstrap per login type
WebexRepository.kt # SDK facade + in-memory call/space/message state (LiveData)
WebexViewModel.kt # UI-facing view model over the repository
auth/ calling/ messaging/ search/ webhooks/ cucm/ extras/ firebase/ utils/ # feature UI packages
buildSrc/ # Gradle build logic (Versions/Dependencies)
```
→ 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.** Never invent an API, path, event, flag, or constant — read the real file. This is an assess-only draft.
2. **Ask before coding.** Present a plan / Spec Summary; wait for confirmation.
3. **Never commit secrets (one known violation exists — do not add more).** `CLIENT_ID`, `CLIENT_SECRET`, `REDIRECT_URI`, `WEBHOOK_URL` come from `local.properties`; `SCOPE` from `gradle.properties`. Keep them out of source and logs (`app/build.gradle`). ⚠️ Existing exception: `Constants.Keys.PushRestEncryptionKey` in `app/src/main/java/com/ciscowebex/androidsdk/kitchensink/utils/Constants.kt` is a hardcoded 256-bit AES key (per its own source comment) committed to source — this rule is currently NOT satisfied there. Treat it as a known gap to externalize, not a pattern to copy.
4. **Only one Webex SDK flavor at a time.** `fullImplementation`/`meetingImplementation`/`wxcImplementation`/`messageImplementation` are mutually exclusive (`app/build.gradle`).

## Essential Commands
| Role | Command |
|---|---|
| Install | `./gradlew` (wrapper self-provisions Gradle 8.9) |
| Build | `./gradlew build` |
| Unit test | `./gradlew testFullDebugUnitTest` |
| Lint/format | none — no lint/format task (ktlint/spotless/detekt) is configured in `build.gradle`/`app/build.gradle`, and the manifest `commands` define no lint role |
→ 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. Missing `local.properties` keys silently fall back to empty strings (`""`) — auth then fails at runtime, not build time (`app/build.gradle`).
2. Firebase requires a valid `google-services.json`; the `com.google.gms.google-services` plugin fails the build without it (`app/build.gradle`).
3. Selecting more than one `*Implementation` Webex SDK flavor causes native-lib/class conflicts — build one flavor variant only.

## Pre-Commit Checklist
- [ ] Tests pass (`./gradlew testFullDebugUnitTest`)
- [ ] Spec/docs updated in the same change (spec-currency)
- [ ] No hardcoded secrets; `local.properties`/`gradle.properties` values not committed
- [ ] Only one Webex SDK flavor dependency is active for the built variant

## External Source Access
| Provider class | Source / host pattern | Preferred access | If unavailable |
|---|---|---|---|
| Artifact registry | `devhub.cisco.com/artifactory/webexsdk/` | maven (build) | STOP and ask — SDK resolution fails |
| Push/analytics | Firebase (Google Services) | google-services.json | STOP and ask — build fails without config |

---
**SDD coverage:** this repo's per-module coverage state lives in `.sdd/manifest.json` (mirror in
`ai-docs/SPEC_INDEX.md`). Use that state to decide whether the spec is authoritative or code must be cross-checked.
Loading