Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
Clima Bolivia 볼리비아 9개 주도의 7일 날씨 예보
Pronóstico del tiempo a 7 días para las nueve capitales departamentales de Bolivia: temperatura máxima y mínima, sensación térmica y viento. Datos de Open-Meteo.
라이프스타일TypeScript · CSSGitHub @MarlonTMF온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Clima Bolivia — Pronóstico de 7 días Aplicación web que muestra el pronóstico de los próximos siete días para las nueve capitales departamentales de Bolivia. Aplicación desplegada: Repositorio: ▼ Ver la vista móvil (390 px) Requisitos: Node.js 20 o superior (desarrollado con la 24.14.0) y npm. No hace falta ninguna clave de API ni archivo .env: la API elegida no pide autenticación.README 전문 보기 ↗
Aplicación web que muestra el pronóstico de los próximos siete días para las nueve capitales departamentales de Bolivia.
Aplicación desplegada: https://clima-bolivia-theta.vercel.app/ Repositorio: https://github.com/MarlonTMF/Clima_Bolivia
Requisitos: Node.js 20 o superior (desarrollado con la 24.14.0) y npm.
No hace falta ninguna clave de API ni archivo .env: la API elegida no pide
autenticación.
git clone https://github.com/MarlonTMF/Clima_Bolivia.git
cd Clima_Bolivia
npm install
npm run dev # http://localhost:5173
| Comando | Qué hace |
|---|---|
npm run dev | Servidor de desarrollo |
npm run build | Compila tipos y genera dist/ para producción |
npm run preview | Sirve el dist/ ya compilado |
npm run test | 19 pruebas con Vitest |
npm run typecheck | Comprobación de tipos |
npm run lint | oxlint |
npm run audit | Auditoría propia de fallos silenciosos (ver más abajo) |
npm run check | Los cinco anteriores en orden. Es el que se ejecuta antes de cada commit |
Una nota sobre typecheck: usa tsc -b --noEmit, no tsc --noEmit. El
tsconfig.json raíz es un archivo de referencias sin archivos propios, así
que tsc --noEmit devuelve éxito aunque haya errores de tipos. Se
descubrió introduciendo un error a propósito para comprobar que el hook de
verificación servía de algo, y no servía.
| Pieza | Elección | Por qué |
|---|---|---|
| Framework | React 19 | Componentización y tipado, y es lo más reconocible para quien evalúa. Svelte habría sido más ligero; se eligió React por familiaridad, no por superioridad técnica |
| Lenguaje | TypeScript | Tipar la respuesta de la API convierte un error de mapeo en un fallo de compilación en vez de en una pantalla en blanco |
| Build | Vite | Un comando para arrancar y para compilar, sin configuración |
| Estilos | CSS plano | Sin framework: son unas 970 líneas que se pueden explicar una a una |
| Pruebas | Vitest + Testing Library | 19 pruebas: lógica, mapeo de la API, los cinco casos de error y los cuatro estados de la interfaz |
| Linter | oxlint | Viene con la plantilla de Vite |
| Despliegue | Vercel (plan gratuito) | Sitio estático servido desde CDN |
"dependencies": { "react": "^19.2.8", "react-dom": "^19.2.8" }
Eso es todo. Sin router, sin gestor de estado, sin cliente HTTP, sin librería de CSS, sin librería de iconos, sin librería de fechas. Para una sola pantalla, cada dependencia sería una decisión más que defender y una superficie más que explicar:
useState en el
componente raíz.fetch nativo cubre el caso, incluido el timeout con
AbortController.Intl.DateTimeFormat,
que está en el navegador.Las dependencias de desarrollo sí existen —Vitest, Testing Library, jsdom, TypeScript— y no contradicen lo anterior: no entran en el paquete final ni llegan al usuario.
El resultado compilado son 99 KB comprimidos, de los que unos 68 KB son React. Ese peso es la contrapartida asumida de la decisión.
Se compararon cuatro opciones contra su documentación oficial antes de elegir, no después.
| API | 7 días diarios en plan gratuito | Clave | Peticiones para 9 ciudades | Veredicto |
|---|---|---|---|---|
| Open-Meteo | Sí | No requiere | 1 | Elegida |
| OpenWeather | Vía One Call, modelo de pago por uso con 1 000 llamadas diarias gratis | Sí | 9 | Descartada |
| WeatherAPI.com | No: sólo 3 días | Sí | 9 | Descartada por no cumplir el requisito |
| Meteosource | Sí | Sí | 9 | Descartada: 9 llamadas por carga sobre un límite de 400 diarias |
Las tres razones de la elección:
La limitación real, dicha por delante: el uso gratuito de Open-Meteo es no comercial, bajo licencia CC-BY 4.0. Si este proyecto pasara a uso comercial habría que pagar su plan o reevaluar OpenWeather — que además exigiría un backend propio para no exponer la clave en el navegador.
weatherApi.ts.src/data/cities.ts.docs/decisiones.md.cities.ts está acoplado al de la petición. Es
deliberado y está documentado, pero es una trampa real para quien lo toque
sin leer: hay una prueba que la vigila.npm run test ejecuta 19 pruebas repartidas en cinco archivos:
| Nivel | Qué cubre |
|---|---|
| Lógica de dominio | Traducción de los 28 códigos WMO documentados y su valor neutro; formato de fecha sin desfase de zona horaria |
| Mapeo de la API | La respuesta real guardada en docs/api-sample.json → el modelo propio |
| Casos de error | Red caída, HTTP 500, timeout abortado, JSON con forma inesperada y camino correcto |
| Invariante de orden | Que la petición pida las coordenadas en el mismo orden que CITIES |
| Componentes | Tarjeta de día, cambio de ciudad, y los cuatro estados de la aplicación |
Además, 12 casos manuales ejecutados sobre el despliegue en producción,
en Chromium y en Firefox, con el resultado real anotado en
docs/pruebas.md — incluidos los que hubo que
replantear porque no probaban lo que decían.
La API devuelve un array en el orden de la petición. Si ese orden se
rompiera, cada ciudad mostraría el clima de otra sin error, sin excepción y
sin pista: es el único fallo verdaderamente silencioso del proyecto. Hay una
prueba que compara los parámetros de la URL contra CITIES, y se comprobó
que sirve invirtiendo el orden a propósito — al hacerlo falla ella sola,
mientras las otras seis del archivo siguen en verde.
npm run auditCasi todos los errores reales de este proyecto fueron del mismo tipo: código
válido que no falla y no hace nada. Una regla CSS apuntando a una clase
inexistente, un contorno de foco sobre un elemento con opacity: 0, un
flex-direction en un contenedor que a ese ancho es grid. tsc y oxlint
no los ven porque comprueban sintaxis y tipos, no efecto.
scripts/audit.mjs cubre esas seis categorías. Cada una existe porque ese
error se cometió aquí, y se verificó reintroduciéndolos uno a uno en lugar de
dar la auditoría por buena por estar escrita.
Sin pruebas de extremo a extremo permanentes (Playwright se usó como
herramienta puntual, no como dependencia), sin instantáneas, sin objetivo de
cobertura porcentual, sin pruebas de carga y sin probar React ni fetch. El
razonamiento de cada exclusión está en docs/pruebas.md.
Las catorce están razonadas en docs/decisiones.md con
su contexto, alternativas y consecuencia. En resumen:
| Decisión | Por qué |
|---|---|
| Una sola petición para las nueve ciudades | Nueve habrían sido nueve formas de fallar parcialmente y nueve veces la latencia |
El orden de cities.ts es significativo | La respuesta llega en el orden pedido y las coordenadas vuelven ajustadas a la malla del modelo, así que no se pueden reemparejar. El acoplamiento es la solución correcta, y una prueba lo vigila |
La respuesta cruda no sale de weatherApi.ts | Ningún componente ve un temperature_2m_max. Cambiar de proveedor sería tocar un archivo |
| Ocho categorías de clima, no treinta códigos | Nadie necesita distinguir «llovizna helada ligera» de «densa». Los códigos desconocidos caen en un valor neutro |
| El diseño se generó con IA; su código, no | El export traía Tailwind, iconos y cientos de líneas que no se podrían explicar. Se usó como especificación visual y se implementó a mano |
| Cuatro estados, no tres | Un fallo con copia guardada no es lo mismo que uno sin ella: hay datos reales, sólo que viejos |
| Sin backend | Se diseñó un proxy con caché y se decidió no construirlo: el problema de resiliencia era real, pero la solución desproporcionada para este alcance. El diseño se conserva escrito y sólo se implementó su capa cliente, la copia en el navegador |
src/
├── data/cities.ts las 9 ciudades — el orden es significativo
├── lib/
│ ├── weatherApi.ts fetch, validación y mapeo al modelo propio
│ ├── weatherCodes.ts códigos WMO → etiqueta e icono
│ ├── forecastCache.ts copia local de la última respuesta correcta
│ └── formatDate.ts fechas sin desfase de zona horaria
├── components/ nunca ven la forma cruda de la API
├── types.ts el modelo de la aplicación
└── index.css todos los estilos
docs/
├── decisiones.md las 14 decisiones, con alternativas y consecuencias
├── pruebas.md matriz manual, navegadores y Lighthouse
├── api-sample.json respuesta real de la API, usada como fixture
└── design/ la referencia visual generada y sus tokens
scripts/audit.mjs auditoría de fallos silenciosos
AI_LOG.md bitácora de uso de IA, con las correcciones
Todo lo que sigue sale de AI_LOG.md, una bitácora con 21
entradas escritas durante el desarrollo, no reconstruidas al final. Cada
una registra qué propuso la herramienta, qué encontré al comprobarlo, cómo se
resolvió y por qué. Esta sección es un resumen; el detalle está allí.
| Herramienta | Uso |
|---|---|
| Claude Code | Asistente principal durante todo el desarrollo: código, documentación y verificación conduciendo un navegador real |
| Google Stitch | Referencia visual de las cuatro pantallas. Su código no entró al proyecto |
| Subagente revisor propio | Definido en .claude/agents/revisor.md, con permisos de sólo lectura, para revisar src/ antes de entregar |
| Búsqueda web | Verificar contra documentación oficial cada dato de API, límites y precios |
Con una regla de fondo: la IA propone, yo verifico, y lo que entra al repositorio es responsabilidad mía. En la práctica eso fue:
Para justificar la elección de API, la herramienta redactó este párrafo:
«El endpoint de 7 días de OpenWeather (One Call 3.0) exige registrar tarjeta de crédito.»
Suena plausible y tenía dos problemas. La versión vigente es One Call API 4.0, no la 3.0. Y la página oficial de precios describe un modelo pay as you call con 1 000 llamadas diarias gratuitas, sin mencionar en ningún punto la exigencia de tarjeta: la afirmación era más fuerte que la evidencia.
Un número de versión y una condición comercial son justo la clase de dato que un modelo genera por patrón en vez de consultar — suenan bien porque son lo que el dato debería ser, y además envejecen: la 3.0 fue correcta en algún momento. Ningún compilador ni prueba habría detectado ese error; habría llegado intacto al README y sólo se habría caído si alguien lo cuestionaba.
Hay un matiz que también quedó registrado: al retirar la afirmación me pasé de frenada. Retirar algo por falta de evidencia es correcto, pero no equivale a declararlo falso, y la investigación posterior mostró que apuntaba en la dirección correcta. La lección no fue «verifica más» sino distinguir tres estados —confirmado, refutado y sin evidencia— y redactar cada uno con las palabras que le corresponden.
El subagente revisor señaló que Math.round(-2.5) devuelve -2 y no -3,
porque JavaScript redondea hacia +∞. Es cierto, y lo comprobé. Aun así no
lo apliqué: el caso sólo se dispara en un empate exacto de medio grado, el
desvío es de medio grado, y corregirlo pedía una función de redondeo propia.
Añadir código para eso es exactamente la sobre-ingeniería que el enunciado
pide evitar.
Es el descarte que mejor ilustra el criterio, precisamente porque la sugerencia era técnicamente correcta: rechazarla no fue detectar un error suyo, fue decidir que el arreglo costaba más de lo que valía.
El otro descarte grande fue estructural: el código que exportó Stitch. Traía Tailwind, una librería de iconos y cientos de líneas de marcado que no podría explicar clase por clase. Se tomó el diseño como especificación visual y se implementó a mano.
La decisión del backend, que cambió tres veces. Primero se descartó, luego se revirtió al encontrar dos fallos reales en ese razonamiento —tratar la disponibilidad del proveedor como problema ajeno, y una objeción sobre arranques en frío que describía otra plataforma—, se diseñó por completo, y finalmente se decidió no construirlo: el problema de resiliencia era real, pero la solución desproporcionada para este alcance. Cada vuelta incorporó información que la anterior no tenía, y la tercera fue la propia aplicación terminada y verificada.
Y decidir qué NO probar, qué NO añadir y qué NO construir. Es donde la herramienta ayuda menos: siempre puede proponer una prueba más, una abstracción más o una capa más, y ninguna de esas propuestas viene marcada como innecesaria.
Al revisar la bitácora entera apareció que los errores del proyecto no eran
variados: eran ocho instancias del mismo tipo. Código válido que no produce
ningún error y simplemente no hace nada — una clase CSS inexistente, un
contorno de foco sobre opacity: 0, un flex-direction en un contenedor
grid, Testing Library que nunca desmontaba y hacía que las pruebas pasaran
por casualidad.
La causa común era verificar el artefacto en vez del efecto. La
consecuencia fue npm run audit, seis comprobaciones automáticas, una por
cada categoría que se dio aquí — y verificadas reintroduciendo los errores
uno a uno para comprobar que la auditoría los detecta de verdad.
Las otras tres reglas que salieron de ahí:
Tres de las cuatro pantallas del diseño estuvieron sin implementar durante
cuatro bloques y lo detecté mirando la aplicación, no ninguna verificación.
El motivo es instructivo: todas las comprobaciones esperaban a que
aparecieran los datos, así que se saltaban por construcción los estados de
carga y de error. Y el título de la pestaña estuvo diciendo scaffold —el
valor de la plantilla de Vite— hasta que lo encontró el revisor delegado, con
la aplicación ya en producción.
Ninguna de las dos cosas la encontró una herramienta automática. Las dos están en la bitácora con su fecha.