Skip to content

Harden the hub, polish the UX, and add Builder medals - #63

Merged
jsshin2022 merged 3 commits into
mainfrom
hub-ga-own
Oct 24, 2026
Merged

jsshin2022 merged 3 commits into
mainfrom
hub-ga-own

Conversation

@jsshin2022

@jsshin2022 jsshin2022 commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Replaces #62, which was branched from an older main and conflicted with the shared assets/js/ga.js and assets/js/track.js that landed in #61. Rebuilt on current main; no conflicts.

Four commits, reviewable one at a time.

1. GA4 and team-site links (5db79be)

  • ga.js configures only the hub property G-C5V0X2SGD3. page_location is passed so incoming campaigns are kept, then utm_* is removed from the address bar. Google signals and ad personalization are off.
  • Links to other sites on this domain (web book, causal-studio, ccwr, ...) get utm_source=hub&utm_medium=referral&utm_campaign=crosslink&utm_content=<spot>, open in the same tab unless a new tab was asked for, and send webbook_click or team_site_click (site, placement, link_url). Hub pages (game, lab, builders, badges) are excluded.
  • station_open from Use the hub's own GA4 property and track visits across team sites #62 is not added: open_repo already covers it, with source: "deeplink" for #station= links.

Pairs with CausalInferenceLab/Causal-Inference-with-Python#91 on the web book side.

2. Security hardening (35ecb8c)

  • Article pages: Markdown is rendered through DOMPurify. marked and DOMPurify are vendored under assets/vendor/ instead of loaded from a CDN.
  • Builder pages: slugs must match [a-z0-9]+(-[a-z0-9]+)* (a bad slug could write outside builders/). Every value is escaped, links must be http(s), and onerror attributes are replaced by a shared image fallback.
  • Hub data: ids, numbers and links from data/*.json are cleaned on load. Values read back from localStorage and #station= are parsed defensively.
  • scripts/check_data.py runs in the deploy workflow and stops a build on non-plain ids, non-integer counts, bad slugs, or links that are not http(s) or site paths.
  • CSP meta on every page (script-src 'self' + Google Tag Manager, object-src 'none', base-uri 'self', form-action 'self'). Pretendard is pinned with SRI.
  • Workflow: actions pinned to commit SHAs, persist-credentials: false, and the stats push uses the token explicitly. update_stats.py keeps the token on api.github.com when following redirects. Removed the empty .github/workflows/cd.

3. UX polish (b2a9d19)

  • Same five-item nav and skip link on game, lab, article, 404 and Builder pages, with the current page marked.
  • The quiz becomes the last goal chip ("잘 모르겠어요 · 3문항으로 찾기"). Game and lab links move into the daily band. Chips wrap on phones instead of scrolling sideways.
  • Picking a route hides the weekly block so the route shelf comes first. New route: 마케팅 효과를 재요, also used for marketing answers in the quiz.
  • One tenure format everywhere: "8기부터 · 3개 기수 (8·9·12기)".
  • Builder dialog: "자료 열기", and a way back to the person after opening one of their repos.
  • Data Forum: the upcoming one comes first, with "신청 링크는 곧 열립니다" when there is no sign-up link yet. Cards are compact on phones.
  • The stamp toast shows above an open dialog instead of behind it.
  • Lab: the challenge is at the top, the chart stays in view while the sliders move on phones, and "여기서 본 것" opens once the challenge is solved.
  • Game review chapters are sorted by chapter number.

4. Builder medals and academic events (abaeb8a)

  • Roster: each row shows only the cohorts that person took part in, as chips ("8기 러너 6", outlined "7기 러너"). The old strip of empty cells across every cohort is gone.
  • Medals by cohorts led as Builder: Builder (1), 다시 온 Builder (2), 베테랑 Builder (3+), 명예 Builder (5+). Special medals: 멘토 (20+ runners) and 러너에서 Builder로 (joined as a runner before leading). The rules live in TIERS/SPECIALS in hub.js and the same lists in build_builders.py.
  • Highlight: opening a Builder shows a medal panel at the top of the dialog, and that person stays marked in the top three, rail and roster.
  • Images: "메달 카드 만들기" draws a 1200×630 card to save or share. build_builders.py also writes badges/<slug>-medal.svg. Builder pages, README badges and the share images (assets/og/builders/*.jpg, regenerated) show the medal.
  • Medal ladder in the 기여 tab: the four tiers with how many people hold each, ending at "발표 무대".
  • 학회와 함께 여는 무대: a new block under 행사 and a line in the banner for the 한국경영정보학회 events (비즈니스 실험 심포지엄 2025·2026, 인과추론 여름 워크숍 2024), from data/stages.json. check_data.py validates it.
  • New events: medal_card_open (builder, tier) and click_conference (conference, placement). share also gets content: "medal_card".

Checked

  • Full regression suite plus UX and medal checks at 1440 and 390px: no console errors, no horizontal overflow on any page.
  • No CSP violations on any page. GA, fonts and the article renderer still load.
  • Injected payloads in a throwaway copy are blocked: article img onerror and javascript: links, event dates, repo cohorts, Builder LinkedIn, stored streak, #station=%E0. check_data.py rejects each of them.

After merge

  • Run Deploy site once.
  • In GA4 (hub property), register the event-scoped dimensions placement, site, chapter, control, tier, conference.
  • CODEOWNERS only applies if "Require review from Code Owners" is on in branch protection.
  • The scheduled stats job pushes straight to main. If main starts requiring PRs, that push will fail.

https://claude.ai/code/session_01HXKUXMwRWZBebGVTt4yncM


Generated by Claude Code

- ga.js configures only G-C5V0X2SGD3, passes page_location so GA keeps
  incoming campaigns, then drops utm_* from the address bar.
- Links to the team's other sites on this domain get
  utm_source=hub&utm_medium=referral&utm_campaign=crosslink and the
  spot they were clicked from, open in the same tab unless a new tab
  was asked for, and send webbook_click or team_site_click.
- Hub pages (game, lab, builders, badges) are not treated as team sites.
- Articles: markdown is rendered through DOMPurify; marked and DOMPurify
  are served from assets/vendor instead of a CDN.
- scripts/check_data.py replaces the JSON syntax check in the deploy
  workflow: plain-token ids, integer counts, valid slugs, and only
  http(s) or site-relative links.
- Builder pages: invalid slugs stop the build; every interpolated value
  is escaped; LinkedIn and record links must be http(s); no inline
  onerror on avatars.
- Hub: data is cleaned on load (links, ids, counts), dates are escaped,
  stored streak values are read as numbers, and a malformed #station=
  link no longer stops the page from starting.
- Content-Security-Policy meta on every page; Pretendard from the npm
  path with SRI.
- GA config turns off Google signals and ad personalization; privacy
  copy matches what is sent.
- Workflow: actions pinned to commits, checkout without persisted
  credentials, stats push with an explicit token; update_stats.py only
  calls api.github.com and drops Authorization on cross-host redirects.
- Remove the empty .github/workflows/cd file.
- Same five-item nav and skip link on every page, with the current page marked
- Quiz becomes the last goal chip; game and lab links move into the daily band
- Picking a route hides the weekly block so the route shelf comes first
- Add a marketing route and send marketing quiz answers to it
- One tenure format for Builders across the hub and Builder pages
- Builder dialog: '자료 열기' and a way back to the person
- Upcoming Data Forum first, with a clear note when sign-up is not open yet
- Stamp toast shows above an open dialog
- Lab: challenge on top, sticky chart on small screens, notes open once solved
- Sort chapters in the game review; small layout fixes
@jsshin2022 jsshin2022 changed the title Use the hub's own GA4 property and track visits across team sites Harden the hub, use its own GA4 property, and polish the UX Oct 24, 2026
@jsshin2022
jsshin2022 merged commit 9ce4183 into main Oct 24, 2026
@jsshin2022 jsshin2022 changed the title Harden the hub, use its own GA4 property, and polish the UX Harden the hub, polish the UX, and add Builder medals Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant