# Configuration Guide

#### API Keys

**OpenRouter API Key Setup**

1. **Obtain Key**:
   * Visit [openrouter.ai](https://openrouter.ai/)
   * Sign up or log in
   * Navigate to "API Keys"
   * Click "Create API Key"
   * Copy the key (starts with `sk-or-v1-...`)
2. **Add to Project**:
   * Open/create `local.properties` in project root
   * Add line: `OPENROUTER_API_KEY=sk-or-v1-your-actual-key-here`
   * Save file
3. **Verify**:
   * Build project
   * Check `BuildConfig.OPENROUTER_API_KEY` is accessible
   * Test by starting a voice session

**Security Best Practices**

* **Never commit** `local.properties` to version control
* **Never hardcode** API keys in source files
* **Use BuildConfig** to access keys at runtime
* **Consider ProGuard** obfuscation for release builds
* **Monitor usage** on OpenRouter dashboard
* **Rotate keys** periodically

#### Build Configuration

**App-Level build.gradle.kts**

Key configurations:

```kotlin
android {
    namespace = "com.fouwaz.Pebbl"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.fouwaz.Pebbl"
        minSdk = 24
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        // Load API key from local.properties
        val properties = Properties()
        properties.load(project.rootProject.file("local.properties").inputStream())
        buildConfigField(
            "String",
            "OPENROUTER_API_KEY",
            "\"${properties.getProperty("OPENROUTER_API_KEY", "")}\""
        )
    }

    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        debug {
            isMinifyEnabled = false
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }

    kotlinOptions {
        jvmTarget = "11"
    }

    buildFeatures {
        compose = true
        buildConfig = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "2.0.0"
    }
}
```

**Dependency Management**

Using Gradle Version Catalog (`gradle/libs.versions.toml`):

```toml
[versions]
kotlin = "2.0.21"
compose-bom = "2024.09.00"
room = "2.6.1"
retrofit = "2.9.0"
vosk = "0.3.38"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version = "1.15.0" }
androidx-lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version = "2.8.0" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version = "4.12.0" }
vosk = { group = "com.alphacephei", name = "vosk-android", version.ref = "vosk" }

[plugins]
android-application = { id = "com.android.application", version = "8.5.1" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version = "2.0.21-1.0.29" }
```

**ProGuard Rules**

For release builds (`proguard-rules.pro`):

```proguard
# Keep Room entities
-keep class com.fouwaz.Pebbl.data.local.entity.** { *; }

# Keep Retrofit models
-keep class com.fouwaz.Pebbl.data.remote.model.** { *; }

# Keep Gson annotations
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.google.gson.** { *; }

# Keep Vosk
-keep class org.vosk.** { *; }

# Preserve line numbers for debugging
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
```

#### Permissions

**AndroidManifest.xml Permissions**

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Required for voice recording -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <!-- Required for AI API calls -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Android 13+ media permissions -->
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

    <!-- Legacy file access (Android 12 and below) -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="32" />
    <uses-permission
        android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="32" />

    <application
        android:name=".VoiceStreamApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:usesCleartextTraffic="false"
        android:theme="@style/Theme.Pebbl">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:theme="@style/Theme.Pebbl">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
```

**Runtime Permission Requests**

Implemented in `MainActivity.kt`:

```kotlin
class MainActivity : ComponentActivity() {

    private val requestPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        if (isGranted) {
            // Permission granted, proceed
        } else {
            // Permission denied, show explanation
            showPermissionRationale()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Check and request microphone permission
        when {
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.RECORD_AUDIO
            ) == PackageManager.PERMISSION_GRANTED -> {
                // Permission already granted
                setupApp()
            }

            shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO) -> {
                // Show rationale then request
                showPermissionRationale()
            }

            else -> {
                // Request permission
                requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
            }
        }
    }

    private fun showPermissionRationale() {
        AlertDialog.Builder(this)
            .setTitle("Microphone Permission Required")
            .setMessage("Pebbl needs microphone access to record your voice for transcription.")
            .setPositiveButton("Grant") { _, _ ->
                requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }
}
```
