ColeFinder es una aplicación Android nativa para ayudar a docentes a localizar centros educativos cercanos (colegios e institutos) mediante geolocalización y mapas.
- Lenguaje: Kotlin 2.0.21 (K2).
- UI: Jetpack Compose y Material 3.
- Arquitectura: MVVM con estado unidireccional (
MapState+MapViewModel). La lógica de datos pasa por repositorios; la UI no llama a Supabase directamente. - Backend: Supabase (PostgreSQL + PostGIS). Acceso vía RPC PostgREST (
nearby_colegios) y consultas directas (from("colegios")). - Cliente remoto: supabase-kt 3.0.3 (PostgREST) sobre Ktor.
- Persistencia local: DataStore Preferences (preferencias de UI, p. ej. hints de long press).
- Inyección de dependencias: Hilt.
- Mapas y ubicación: Maps Compose 6.6.0, Play Services Maps 20.0.0 y Fused Location Provider.
- Actualizaciones in-app: Google Play In-App Updates (
app-update-ktx 2.1.0). Forzado obligatorio (IMMEDIATE) o recomendado (FLEXIBLE) según configuración remota. - Configuración remota: tabla
app_configen Supabase (key/value). Controla la versión mínima requerida, el tipo de actualización forzada y el límite de POIs mostrados en el mapa, sin necesidad de publicar una nueva APK.
- Android 15 (API 35) edge-to-edge: soportado (
targetSdk36; insets en SearchBar, FAB y bottom sheet). - Permiso de ubicación: si el usuario deniega de forma permanente («No volver a preguntar»), el FAB muestra un hint inline que abre Ajustes de la app (sin depender de un diálogo del sistema que ya no aparece).
El módulo es :app, namespace es.colefinder. Organización real del código fuente:
Ruta (bajo app/src/main/java/es/colefinder/) |
Contenido |
|---|---|
ui/map/ |
MapScreen, MapViewModel, MapState, filtros (CentroFiltros), detalle en pantalla |
data/ |
Cliente Supabase (Supabase.kt), repositorios (ColegioRepository, SupabaseColegioRepository, UserPreferencesRepository) |
data/model/ |
Modelos de dominio (Colegio) y DTOs (NearbyColegioDto, ColegioSearchDto, AppConfigRowDto, AppUpdateConfig, AppConfigKeys) |
data/repository/ |
ColegioRepository, SupabaseColegioRepository, UserPreferencesRepository, AppConfigRepository |
data/network/ |
Clasificación de errores de red (ColegiosLoadError, ColegiosLoadException) |
di/ |
Módulos Hilt (NetworkModule, RepositoryModule) |
update/ |
InAppUpdateManager (gestiona una única instancia de AppUpdateManager, soporta flujos FLEXIBLE e IMMEDIATE) e InAppUpdateUiState (data class con el estado del banner, definida en el mismo archivo) |
No hay un paquete domain/ separado.
Hay dos sabores en la dimensión env:
| Flavor | applicationId |
Esquema Postgres (BuildConfig.SUPABASE_SCHEMA) |
Uso típico |
|---|---|---|---|
| pre | es.colefinder.pre |
staging |
Staging / validación contra BD de pruebas |
| prod | es.colefinder |
public |
Producción |
Las URLs y claves anon se inyectan por flavor en BuildConfig desde secretos (ver siguiente sección).
La app lee al arrancar la tabla app_config del esquema activo
(staging en PRE, public en PROD). Permite cambiar el comportamiento
de la app sin publicar una nueva versión.
| Parámetro | Cómo editarlo | Efecto |
|---|---|---|
min_version_code |
Columna value (número) |
Versión mínima de la app para funcionar. Si la instalada es menor, se lanza el flujo de actualización. |
update_type |
Columna value_enum (selector) |
FLEXIBLE: actualización recomendada con banner. IMMEDIATE: pantalla bloqueante hasta actualizar. |
nearby_colegios_limit |
Columna value (número) |
Número máximo de colegios que devuelve la RPC. Lo aplica la función SQL directamente; la app no controla este valor. |
Nota:
update_typese edita víavalue_enum(enum Postgres con selector en el panel de Supabase). Un trigger sincroniza el valor a la columnavalueautomáticamente. No editarvaluedirectamente para este parámetro.
Para forzar una actualización en producción:
UPDATE public.app_config SET value = '5' WHERE key = 'min_version_code';
UPDATE public.app_config SET value_enum = 'IMMEDIATE' WHERE key = 'update_type';- Copia
secrets.defaults.propertiescomosecrets.propertiesen la raíz del proyecto (el archivo real no se versiona; está en.gitignore). - Rellena al menos:
SUPABASE_URL_PRE=https://<tu-proyecto>.supabase.co
SUPABASE_ANON_KEY_PRE=<anon-key-staging>
SUPABASE_URL_PROD=https://<tu-proyecto-o-custom>.supabase.co
SUPABASE_ANON_KEY_PROD=<anon-key-prod>
MAPS_API_KEY=<tu-clave-maps>- Supabase: URL base del proyecto (sin sufijos
/rest/v1; el SDK los resuelve). Puedes usar el host*.supabase.coo un dominio custom si tu infraestructura lo expone así. - Google Maps: la clave se inyecta en el manifest mediante el Secrets Gradle Plugin; el placeholder en
AndroidManifest.xmles${MAPS_API_KEY}. No hace falta pegar la clave a mano en el XML sisecrets.propertiesestá bien configurado.
Necesitas un proyecto Supabase activo con el backend configurado. Ver
supabase/setup/README.md.
El backend es un proyecto Supabase con PostGIS.
La carpeta supabase/setup/ contiene scripts SQL
idempotentes para levantar el backend desde cero en cualquier proyecto
Supabase nuevo.
Para replicar el entorno: sigue las instrucciones de
supabase/setup/README.md. En resumen:
- Crea un proyecto en supabase.com y activa la extensión PostGIS (Database → Extensions).
- Si usas supabase.com (hosted), expone el esquema
stagingen INTEGRATIONS → Data API → Settings → Exposed Schemas antes de ejecutar ningún script. - Ejecuta los 8 scripts de
supabase/setup/en el SQL Editor en el orden indicado en el README de esa carpeta. - Rellena
secrets.propertiescon la URL base y la anon key del proyecto (ver sección anterior).
Datos de muestra: los scripts incluyen ~500 centros del centro de Madrid como muestra funcional. La app publicada en Google Play conecta al backend de producción con el dataset nacional completo. Los scripts de
supabase/scripts/son de mantenimiento interno (imports, promotes). No son necesarios para levantar el entorno desde cero.
Hay dos variantes de debug; el task compileDebugKotlin es ambiguo. Ejemplos:
./gradlew :app:compilePreDebugKotlin
./gradlew :app:compileProdDebugKotlin
./gradlew :app:assemblePreDebug
./gradlew :app:assembleProdDebugLas pruebas unitarias usan JUnit 4, MockK y kotlinx-coroutines-test.
# Ejecutar tests unitarios (flavor pre)
./gradlew :app:testPreDebugUnitTest
# Ejecutar con informe de cobertura Jacoco (pre + prod)
./gradlew :app:jacocoFullReportEl informe HTML se genera en:
app/build/reports/jacoco/jacocoFullReport/html/index.html
El workflow de GitHub Actions (.github/workflows/ci.yml) se ejecuta en cada push y pull request a develop y main:
| Job | Qué hace |
|---|---|
| Assemble Debug | Compila ambos flavors (pre + prod) |
| Unit Tests | Ejecuta tests y genera cobertura Jacoco |
Los artefactos de cobertura se guardan 14 días en cada ejecución de CI.
- Mapa interactivo con marcadores codificados por color (titularidad) y numerados.
- Búsqueda híbrida: la SearchBar busca simultáneamente por nombre de centro (Supabase) y por ubicación/dirección (Geocoder). Los resultados de centros aparecen primero con icono de escuela; las ubicaciones con icono de pin.
- Filtros por titularidad (Público, Concertado, Privado) y tipo de centro (Primaria, Secundaria, FP, Adultos, Especial, Otros), aplicados en servidor y con fallback en cliente.
- Detalle del centro con navegación a Google Maps y llamada.
- Long press en el mapa para explorar centros en cualquier punto.
- Ubicación: FAB «Mi ubicación»; si el permiso está bloqueado permanentemente, banner con enlace a Ajustes del sistema.
- Actualizaciones forzadas: al arrancar, la app consulta
app_configen Supabase y compara la versión instalada conmin_version_code. Si es inferior, lanza Google Play In-App Updates en modo IMMEDIATE (bloqueante) o FLEXIBLE (banner) según el valor deupdate_type.
Los fallos de carga se clasifican automáticamente (DNS, TIMEOUT, SSL, HTTP_CLIENT, HTTP_SERVER, etc.) y se registran con el tag SupabaseColegioRepo en nivel Error. El usuario ve un mensaje legible; Logcat muestra la categoría y el detalle técnico.
adb logcat -s SupabaseColegioRepo:E MapViewModel:Egit clone git@github.com:dianri/coleFinder.git
cd coleFinderCrea secrets.properties como se indica arriba antes de compilar.
La app está publicada en Google Play (flavor prod, esquema public):
La versión publicada conecta al backend de producción con el dataset nacional completo de centros educativos de toda España.
Presentación del TFM realizada con Gamma:
| Rama | Propósito |
|---|---|
main |
Código de producción estable |
develop |
Rama de integración principal |
feature/* |
Nuevas funcionalidades |
Las PRs van siempre de feature/* → develop → main.
Copyright (C) 2026 Diego Angel Fernandez Garcia
Este proyecto está licenciado bajo la GNU Affero General Public License v3.0 (AGPL-3.0).
Esto significa que:
- Puedes ver, estudiar y modificar el código libremente.
- Si distribuyes una versión modificada o la usas en un servicio, debes publicar el código fuente bajo la misma licencia.
- No está permitido publicar esta aplicación o una derivada en tiendas de apps (Google Play, etc.) sin publicar también el código fuente completo.
Ver el archivo LICENSE para el texto completo.
Gracias por contribuir o probar ColeFinder.