Instruction file imported from Juguitoo/JuguitoReader (
.cursor/rules/architecture.mdc). Copyright stays with the author.
Arquitectura Kotlin — JuguitoReader
Capas — respetar separación
- ui/ — Compose, ViewModels. No acceder a DAOs directamente.
- domain/ — Models, repository interfaces, use cases. Sin imports Android (salvo excepciones existentes como
@StringRes). - data/ — Room, mappers, repository impls.
ViewModel pattern
private val _internalState = MutableStateFlow<XUiState>(XUiState.Loading)
val uiState: StateFlow<XUiState> = _internalState.asStateFlow()
private val _effect = Channel<UiEffect>()
val effect = _effect.receiveAsFlow()
fun onEvent(event: XEvent) { when (event) { ... } }
- Estados sellados: Loading, Success, Error, Empty.
- Errores al usuario vía
UiText/JuguitoException.asUiText(). - Navegación y snackbars:
UiEffecten Channel, no en UiState. - Settings puede hospedar un segundo ViewModel (
ui/settings/backup) para export/import; no mezclarlo enSettingsViewModel. UiEffect.RestartApplo consume la Screen (ProcessAppRestarter); el ViewModel no mata el proceso.
Use cases
- Un archivo por operación en
domain/usecase/. - Retorno
Result<T>. Validación de negocio aquí, no en ViewModel. - ViewModels orquestan; use cases contienen reglas.
Nuevas pantallas
Seguir estructura existente: Screen.kt, ViewModel.kt, UiState.kt, Event.kt. Registrar ruta en ui/navigation/JuguitoApp.kt.
Módulo :epub-engine (TAR-30)
- Librería Android; no es una feature de
:app. - No importar
com.juguito.juguitoreader.*desde este módulo. - No añadir
implementation(project(":epub-engine"))en:apphasta sustituirEpubWebView. - El parser EPUB (
EpubParser) sigue en:apphasta v1.4.
No hacer
- Saltarse use cases llamando repositories desde ViewModels.
- Poner strings de UI hardcodeados (usar strings.xml + UiText).
- Añadir dependencias sin proponer primero.