- Restore src/scrapers/tjing.js with AbortController timeout (8s),
error-object returns, and verbatim GraphQL queries
- Add getOrCreateLayout() to src/models/course.js
- New /api/tjing/search and /api/tjing/import/:tjingId routes;
course-table route now includes layoutCount/activeLayoutCount via
LEFT JOIN aggregation
- Rewrite courses.ejs: action-card with Find/Import tabs, results bar,
HTMX course-table-region with body:refresh trigger
- Rewrite course-table.ejs: CSS-grid div structure replacing <table>,
lazy-load expanded layouts via JS htmx.ajax
- Rewrite course-layouts.ejs: layout-card chips with rating tier colouring,
collapsible inactive layouts section
- Rewrite courses.js: tab switching, live client-side filter, count display,
Tjing search/import using DOM API (no innerHTML with untrusted data)
- Rewrite courses.css: full new design system using project tokens
Tour functionality has moved to its own project (HyzrTour).
Removes all tour-related code, Tjing integration, and associated
views/styles/scripts. Keeps the saveCourseToDB ON CONFLICT fix.
Search and import courses with layouts from Tjing's GraphQL API.
Total par is calculated from individual hole data. Courses are saved
with a tjing.se link as unique identifier to prevent duplicates.
- Switch from Alpine to Debian slim for correct Chromium architecture
(fixes ARM/Apple Silicon support)
- Upgrade Puppeteer 21 to 24, use system Chromium via PUPPETEER_EXECUTABLE_PATH
- Replace removed page.waitForTimeout() with setTimeout
- Set NODE_ENV=production in Dockerfile to prevent pino-pretty import
- Improve error logging with Pino's { err: error } pattern
- Add build: . to docker-compose for local development builds
Replace all console.log/error with Pino logger (info/warn/error/debug/fatal)
for structured JSON logging in production and pretty-print in development.
Remove redundant header dumps and consolidate rate-limit logging.
Add GitHub Actions workflow with release-please for automated semver releases
and Docker build/push to GHCR on new releases.
- Add HTMX CDN to layout
- Replace client-side table rendering (displayRatings, displayCourses)
with server-rendered EJS partials via hx-get
- Add server-side course search with debounced hx-trigger
- Lazy-load player history and course layouts via htmx.ajax()
- Render rating chart via htmx:afterSwap with data attributes
- Add partial routes: ratings-table, course-table, player-history,
course-layouts