尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證BiblioStatus is a web app that shows the real-time opening status of Finnish public libraries on a map
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
BiblioStatus is a web app that shows the real-time opening status of Finnish public libraries on a map.檢視完整 README ↗BiblioStatus is a web app that shows the real-time opening status of Finnish public libraries on a map.
The map
Finding a library
?city=Espoo&service=Sauna&library=123), so a link restores a view and a reload keeps itA library's details
Reliability
GET /health for uptime monitoring, with a Cloud Monitoring check and an e-mail alertfetch_library_data.R # The data pipeline (Kirkanta API v4 -> Turso + SQLite backup)
check_library_urls.R # Validates all library URLs
R/ # Pipeline code the app shares or tests
├── turso.R # Turso HTTP API: reads (with timeout and retry), all-or-nothing writes
├── schedules.R # The 7-day window, parsing the API's schedules, how the window is written
├── library_write.R # Replacing the libraries and services in one transaction
├── coordinates.R # Which coordinates to believe (override > API > last good snapshot)
└── backfill_historical_data.R # Backfill historical schedules
data/ # Manual corrections and the coordinate snapshot (CSV)
├── library_url_overrides.csv, library_coordinate_overrides.csv, library_exclusions.csv
└── library_coordinates.csv # Last good coordinates of every library (kept up to date by the weekly run)
app/
├── run.R # Entry point: security headers, /health, host and port
├── global.R, server.R, ui.R
├── server/ # data (loading, reloading), filters, url (the address), map, panels
├── modules/service_stats.R # The Service Statistics tab
├── libraries.sqlite # SQLite backup (written by the pipeline)
└── www/
├── functions.R # Database queries, status calculation, map drawing, popups
├── data_layer.R # get_app_data(): never throws, shared cache, stale/backup states
├── filter_logic.R # The dropdown rules (no Shiny in it), the search box, the address
├── health.R, security.R # /health and the security headers (including the CSP)
├── strings.R # All user-facing text
├── variables.R # Colours, map settings, cache and reload times
├── app.js, mode-toggle.js, styles.css
tests/testthat/ # The test suite (about 1,500 expectations)
.github/workflows/ # tests, fetch_data, check_library_urls, deploy_shiny_app
infra/, fixes/ # Artifact Registry cleanup policy, the monitoring setup script
schema.sql, Dockerfile, docker-compose.yml, deploy.sh, renv.lock
CLAUDE.md describes how the pieces fit together (for people and for Claude Code), and bibliostatus-refactor-plan.md is the record of the 2026-10 refactor.
Daily schedule update (2:00 AM UTC; GitHub often starts the job a few hours late):
fetch_library_data.R in "schedules" modelibraries.sqlite as the backupWeekly library update (Sunday 2:00 AM UTC):
fetch_library_data.R in "both" modedata/ (100+ URL fixes, a few coordinate fixes, libraries without an address of their own left out)data/library_coordinates.csv (the API once gave 0, 0 for a library); the file is kept current by this runlibrary_services table (10,000+ records, 240+ unique services)get_app_data() reads Turso (8-second timeout, one retry) and falls back to libraries.sqlite; it never throws and says where the data came fromAll library website URLs are checked automatically every day at 3:00 AM UTC. If any is broken, an e-mail alert is sent and the URL is investigated and corrected (the fixes live in data/library_url_overrides.csv); when all are fine, nothing is sent.
GET /health answers ok, or a 503 with a short reason (no data, no opening hours for today, the nightly update lagging, only the backup available)fixes/monitoring_setup.sh)The app runs as a Docker container on Google Cloud Run. Every change goes through a pull request whose tests must pass; merging to main deploys it (the build takes about 8 minutes) through a GitHub Actions workflow with keyless Google Cloud login. See DEPLOY.md for how it works and for manual deployment.
With Docker:
docker compose up --build
# Open http://localhost:8082
Or directly with R:
renv::restore()
shiny::runApp("app/")
The app needs the Turso credentials: put TURSO_DATABASE_URL and TURSO_AUTH_TOKEN in a git-ignored .Renviron in the project folder (see CLAUDE.md). Without them it uses app/libraries.sqlite.
Tests (they never touch the real database):
Rscript tests/testthat.R
The same suite runs on every pull request and gates the deploy.
The versions are locked in renv.lock (R 4.5.2).
The basemap is Esri's World Light / Dark Gray canvas with a labels layer. It needs no API key, and the attribution ("Tiles © Esri — Esri, HERE, Garmin, © OpenStreetMap contributors, and the GIS user community") is shown on the map. The tiles are real only up to zoom 16, so tile requests are capped there and scaled up for closer views. (The app used Carto tiles with an API key until 2026-10-17.)