- Fix saveCourseToDB returning 0 on conflict by falling back to SELECT
- Fix inactive layouts showing 'Never played' when last_played exists
- Add .icon-btn.spinning to courses.css for refresh button feedback
- Remove duplicate .btn-primary from courses.css (use shared.css version)
- Tokenize rating tier colors into --rating-tier-{high,mid,low} CSS vars
- Convert var to const/let throughout courses.js
- Fix logger.error calls to use {err} object form (pino convention)
- Extract RATING_TIER_HIGH/MID constants in course-layouts.ejs scriptlet
- Remove dead href='#' View all link from courses.ejs (deferred)
- Pass total prop explicitly from course-table.ejs to course-cards.ejs
- Remove dead #search-results-info selector from mobile.css
- Remove redundant .replace(/"/g, '"') from data attributes in course-table.ejs
- 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
- Add "Round spread" row (±stdDev, range lo–hi) to desktop accordion
(player-history.ejs) and mobile card expanded section (ratings-cards.ejs)
- Remove .std-dev-tooltip div and .std-dev-inline span from table partial
- Remove stdDevTooltipText, updateStdDevInline, initRatingsTooltips helpers
and all call sites from players.js
- Remove .std-dev-tooltip and .std-dev-inline CSS rules; drop cursor:help
from .rating-value
Previously .mobile-add-bar { margin-bottom: -80px } was hardcoded
to match .container { padding-bottom: 80px }. Now both reference
--m-container-pad-bottom so they can't drift out of sync.
- New .gitea/workflows/release.yml triggers on push to main
- Scans commits since last v* tag and bumps strict semver
- feat: -> minor, fix: -> patch, !: or BREAKING CHANGE -> major
- Updates package.json + package-lock.json, commits as <version>,
tags v<version>, pushes both
- Tag push triggers existing deploy.yml (PACKAGES_TOKEN is a PAT so
cross-workflow triggers work)
- Skips silently when no releaseable commits are found
- Updates CLAUDE.md release section to reflect automation
- Add .table-toolbar to mobile hide list (was rendering duplicate
'TRACKED PLAYERS' header above the mobile section-head)
- Change .m-card__body grid to minmax(0, 1fr) auto so the stats
column can shrink below content size
- Add min-width: 0 to .m-card__stats for proper grid shrinking
- Remove grid-row: span 2 from .m-card__sparkline (single-row grid)
- Remove overflow: visible from .m-chart-spark so the end-dot stays
within the SVG viewport
- Hide desktop .card-section on mobile, add .m-search-input with same
HTMX attrs for mobile course search (fixes horizontal overflow)
- Remove dead layoutCount var and .m-layouts-pill block in course-cards
- Remove dead 768px breakpoints from players.css (table hidden at 880px)
- Move .mobile-section-head inside else-block for empty state in both
ratings-cards and course-cards (fixes section head showing on empty)
- Add tabindex, role=button, aria-expanded, onkeydown to .m-card and
.m-course-card; toggle aria-expanded in JS toggle functions
- Fix data-history attribute to use <%= (HTML-escaped) instead of <%-
- Convert var to const/let in all new/changed JS blocks
Fix YAML indentation (on:/jobs: were nested under name:), correct
image name from shcizo/myapp to shcizo/pdga-rating, switch registry
auth from GITEA_TOKEN to PACKAGES_TOKEN (auto-injected token lacks
effective registry access), and add packages:write permission.
Remove docker-build.yml since deploy.yml now covers build + push +
deploy in one workflow — previously both triggered on tag push and
raced for the same image tags.
After the binary search converges, also simulate predicted rating at
required±1 average. Display the three rows in the modal so the user can
see how sharp the requirement is — e.g. whether averaging 1 point lower
costs them 1 point of predicted rating or 5.
When a player has rating_history (graph) but no round_history (per-round
detail), calculating a target produced a dead-end error. Now the modal
detects the NO_ROUNDS case and shows a button that triggers the existing
refresh-round-history endpoint and re-runs the calculation on success.
Handles the 24h rate-limit and other refresh errors explicitly.
The topbar showed the first Tuesday of the *next* month instead of
PDGA's actual cycle (second Tuesday of the month). Replace the
duplicated computeNextUpdate() with the central
getNextPDGAUpdateDate() from rating-calculator, keeping only the
formatter ("Tue 9 Jun") here.
- Fix runtime line (Node 22 slim, not Node 18 Alpine)
- Add Hosting line (Gitea, use tea not gh)
- Reflect new CI/CD flow (Gitea Actions, manual version bump, PACKAGES_TOKEN)
- Add PDGA Domain Notes section (rating cycle, predicted-rating algorithm,
rate limits) so future sessions don't have to re-derive domain logic
- Note absence of test framework explicitly
The auto-injected GITEA_TOKEN does not have effective write access to
the container registry on Gitea 1.26 even with `permissions: packages:
write` set. Switching to a dedicated PAT (write:package scope) stored
as the PACKAGES_TOKEN repo secret.
Bumps version to 1.2.3 to trigger a fresh tag-build.
Per Gitea Actions docs, the auto-injected token is exposed as
GITEA_TOKEN, not GITHUB_TOKEN. The latter is GitHub-Actions-specific
and not aliased on Gitea by default.
Also bumps version to 1.2.2 to trigger a fresh tag-build.
Origin moved from GitHub to Gitea. release-please-action and ghcr.io are
GitHub-specific and don't work on Gitea Actions, so the release-please
flow is dropped in favor of manual tag-trigger docker builds.
- Add .gitea/workflows/docker-build.yml: builds and pushes to
gitea.shcizo.se/shcizo/pdga-rating on tag push (v*)
- Remove release-please-config.json and .release-please-manifest.json
- Neutralize .github/workflows/release-please.yml to workflow_dispatch
(kept as reference; can't be deleted via tooling under .github/)
The thead had position: sticky; top: var(--topbar-height), pinning it
to 64px from the viewport. Inside the new .table-card with a toolbar
above, this pulled the header up out of its natural flow and overlapped
the toolbar and first data row. Let thead flow normally — design
doesn't require sticky behavior.