Repository navigation
feat(courses): other courses under every course and post, footer advert, utm on shares, sign-in after Telegram - #1634
Conversation
…rt, utm on shares, sign-in after joining in Telegram - More courses shelf at the foot of every course page and (lazy) every blog post; a course advert in the site footer. - Internal shelf links carry ?from=<placement>; the first placement of a session and the arrival utm_source ride on to the checkout order. - Share links (course + blog) carry utm_source/medium/campaign/content; static course pages forward an arrival's utm_* into the app link. - The catalog accepts ?unlock=<key>, so a reader who joined the club in the bot signs in on the site; a "Sign in via Telegram" link on the catalog and on the paid gate. - The words say it plainly: three courses free with no sign-up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary by t27-beesThis PR adds a "More courses" shelf under course pages and blog posts, a footer advert, UTM tracking on share links, placement tracking ( Worth a look
Read: 300 files, +308 -3, the whole diff up to 60000 characters (the rest was not read). Head |
What
Owner, 2026-10-13: other courses at the foot of every course page, a course advert in the footer and on every blog post, utm tags to track traffic, a way to sign in on the site after joining the club in Telegram, and three courses free with no sign-up.
?from=<placement>on internal links (not utm: an internal utm overwrites the real channel); placement + arrival source go with the checkout order?unlock=<key>from the bot; Sign in via Telegram linksBot side (deeplink after paying): gHashTag/999-multibots-telegraf, separate PR.
{ "version": 1, "head_sha": "bcf926f4ebf36f1d4c71cbce2ef519e9a4d7d748", "summary": "Sell courses where readers already are: a More courses shelf under every course page and blog post, a footer advert, utm tags on share links, placements carried to the order, and sign-in on the site for readers who joined the club in Telegram. The words now say plainly that three courses are free with no sign-up.", "changes": [ "src/components/CourseShelf.tsx and src/lib/useLadderView.ts: course cards and a More courses shelf, unopened courses first", "src/pages/Course.tsx and src/pages/Blog.tsx: the shelf at the foot of every course page and (lazy-loaded) every blog post", "src/components/Footer.tsx: a course advert in the footer, off on course pages", "src/lib/courseLadder.ts: ?from=<placement> on internal links; first placement and arrival utm_source sent with the checkout order", "src/lib/shareTags.ts: utm tags on course and blog share links; scripts/course-pages.mjs forwards arrival utm_* into the app link", "src/pages/Courses.tsx: the catalog accepts ?unlock=<key> (sign-in after joining in the bot) and links to sign in via Telegram", "specs/ladder/course-ladder.t27 + i18n/course-ladder.ru.json: six new words, and no sign-up said plainly" ], "tests": [ { "command": "npm run check:course-ladder && npm run test:course-ladder", "result": "49 words in 2 languages, up to date; tests pass", "status": "passed", "evidence": "local run of both npm scripts in apps/website on head bcf926f4e" }, { "command": "npm run check:course && npm run test:course && npm run check:course-pages", "result": "pass; 504 static course pages regenerated", "status": "passed", "evidence": "local run of the three npm scripts in apps/website on head bcf926f4e" }, { "command": "npx vite build", "result": "built in 14.47s; CourseShelf is its own lazy chunk", "status": "passed", "evidence": "local vite build in apps/website; dist written with no errors" }, { "command": "browser on vite dev: clean localStorage, open #/courses then a course", "result": "course opens with one press, no key and no email; shelf shown; from=catalog kept in sessionStorage", "status": "passed", "evidence": "BrowserOS neo on the vite dev server, localStorage cleared before the check" } ], "limitations": [ "Static blog pages at t27.ai/blog/<slug>/ are generated outside this repo and load no app JS; their share utm counts only once a reader reaches the app.", "The on-site rouble checkout needs gHashTag/999-multibots-telegraf#4001 deployed with Robokassa env set; until then the gate keeps the bot button." ], "tags": [ "courses", "sales", "utm", "ux" ], "blog": { "title": "Selling courses where readers already are", "summary": "Every course page and blog post now ends with other courses, the footer carries an advert, shares are utm-tagged, and a club member signs in on the site with one bot button.", "outline": [ "A reader who finishes a lesson used to reach the end of the page and find nothing next, so the foot of every course page now shows three other courses, unopened first.", "Blog posts bring most of the traffic but sold nothing, so every post now ends with the same shelf, loaded lazily so the blog stays fast for readers.", "Internal links carry a from placement instead of utm tags, because an internal utm tag would overwrite the channel the reader really arrived from.", "The first placement of a session and the arrival source ride on to the checkout order, so each payment names the shelf that sold it and the channel.", "A member who paid for the club in Telegram had no way back to the site; the catalog now accepts the bot key and a sign in via Telegram link sits on it." ] } }🤖 Generated with Claude Code