---
name: init_kotlin_app
kind: pipeline
lang: bash
domain: pipelines
version: "1.0.0"
purity: impure
signature: "init_kotlin_app(name: string, [--project <p>] [--desc <s>] [--tags <csv>] [--package <id>]) -> void"
description: "Scaffolder canonico de app Android Kotlin Compose con FnTheme + Roborazzi tests + e2e_checks declarados. Mirror exacto del patron init_cpp_app para el stack Kotlin."
tags: [android, kotlin, compose, scaffolder, launcher]
uses_functions:
  - ensure_repo_synced_bash_infra
  - gradle_run_bash_infra
  - gradle_assemble_debug_bash_infra
  - gradle_unit_test_bash_infra
  - gradle_screenshot_test_bash_infra
  - fn_theme_kt_ui
  - fn_tokens_kt_ui
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
  - name: name
    desc: "nombre de la app en snake_case. Sera el id en registry.db y el repo dataforge/<name>"
  - name: "--project"
    desc: "proyecto bajo projects/ donde crear la app (opcional). Si se omite va a apps/<name>/. El project.md debe existir"
  - name: "--desc"
    desc: "descripcion breve para el frontmatter app.md (default: 'App Android Kotlin Compose')"
  - name: "--tags"
    desc: "tags CSV adicionales para el frontmatter (siempre se anaden kotlin, compose, android)"
  - name: "--package"
    desc: "application id Android (default: com.fnregistry.<name>). Ej: com.aurgi.scanner"
output: "Stdout con pasos y archivos creados. Exit 0 = scaffold completo y ready para build. Exit !=0 si falla validacion (nombre invalido, destino existe, proyecto inexistente) o git init."
tested: false
tests: []
test_file_path: ""
file_path: "bash/functions/pipelines/init_kotlin_app.sh"
---

## Ejemplo

```bash
# App suelta en apps/<name>/
fn run init_kotlin_app my_scanner --desc "Escaner de documentos" --package "com.aurgi.scanner"

# App dentro de un proyecto
fn run init_kotlin_app expense_tracker --project budget --desc "Tracker de gastos" --tags "finance,mobile"

# Con package id personalizado
fn run init_kotlin_app pos_terminal --package "com.aurgi.pos" --desc "Terminal de punto de venta"
```

## Que genera

```
apps/<name>/                                   (o projects/<p>/apps/<name>/)
├── settings.gradle.kts                        # rootProject + include(:app) + composite build ui
├── build.gradle.kts                           # top-level (apply false)
├── app/build.gradle.kts                       # Compose + Material3 + Roborazzi + tests
├── gradle.properties
├── gradlew                                    # stub ejecutable
├── gradle/wrapper/gradle-wrapper.properties   # Gradle 8.6
├── app/
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml            # activity con LAUNCHER intent
│       │   ├── kotlin/<pkg_path>/
│       │   │   └── MainActivity.kt            # FnTheme + Surface + Text("<name> ready")
│       │   └── res/values/strings.xml
│       ├── test/kotlin/<pkg_path>/
│       │   └── ExampleScreenshotTest.kt       # Roborazzi: captura FnTheme + Surface
│       └── androidTest/kotlin/<pkg_path>/
│           └── MainActivityTest.kt            # Compose ui-test: assertIsDisplayed("<name> ready")
├── app.md                                     # frontmatter registry (lang:kt, framework:compose)
├── .gitignore
└── README.md
```

## Composite build

La app apunta via `includeBuild` a `kotlin/functions/ui` del registry (FnTheme + FnTokens).
El path relativo se calcula automaticamente:

| Ubicacion | Path al composite |
|---|---|
| `apps/<name>/` | `../../kotlin/functions/ui` |
| `projects/<p>/apps/<name>/` | `../../../../kotlin/functions/ui` |

La dependencia se declara como `implementation("fn.compose:ui")` en `app/build.gradle.kts`.

## e2e_checks generados

| id | cmd | timeout |
|---|---|---|
| `unit` | `fn run gradle_unit_test_bash_infra <dir>` | 240s |
| `screenshot` | `fn run gradle_screenshot_test_bash_infra <dir>` | 240s |
| `build` | `fn run gradle_assemble_debug_bash_infra <dir>` | 360s |
| `emu_start` | `fn run android_emulator_start_bash_infra Medium_Phone_API_35` | 240s |
| `instrumented` | `fn run gradle_instrumented_test_bash_infra <dir>` | 600s |
| `emu_stop` | `fn run android_emulator_stop_bash_infra` | 30s (warning) |

## Despues de crear

1. Completar `uses_functions` en `app.md` cuando la app consuma funciones adicionales del registry.
2. Para tests Roborazzi: los snapshots se generan en `app/src/test/snapshots/images/` (gitignored).
   Para actualizar golden images: `./gradlew recordRoborazziDebug`.
3. Para tests instrumentados se necesita un AVD creado con `avdmanager create avd -n Medium_Phone_API_35 ...`.

## Notas

- `fn_theme_kt_ui` y `fn_tokens_kt_ui` se referencian en `uses_functions` del `app.md` generado
  aunque todavia no esten indexados en registry.db — son los modulos del composite build.
- `ensure_repo_synced_bash_infra` requiere `GITEA_URL` y `GITEA_TOKEN`. Sin ellos se hace
  `git init + git commit` local y se avisa al usuario.
- Si `--project <p>` se especifica, se ejecuta `fn index` al final para registrar la nueva app.
