Skip to content

Team 3: search engine pages, categories and game pages, multiplayer rooms, and the F-series - #31

Merged
dav3exe merged 95 commits into
startnextgen:mainfrom
Cybertron-HNG:main
Oct 26, 2026
Merged

dav3exe merged 95 commits into
startnextgen:mainfrom
Cybertron-HNG:main

Conversation

@dav3exe

@dav3exe dav3exe commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

Brings startnextgen/startng-be up to date with the Cybertron-HNG fork's main: Team 3's three workstreams and the F-series. Every change went through a PR into the fork's dev with pytest and malware-scan green, then dev into main (#130) with CodeQL, Analyze, Dependency audit and review green as well.

Workstream 1, search engines and AI tools (Dave): the text of each public page for nginx to put inside the page (/pages/home, /pages/games, /pages/creators, /pages/tournament, /pages/leaderboard, and /pages/spotlight, /pages/by, /pages/shop, /pages/friends while their feature is on). A page past the last one is a 404. The sitemap lists the feature pages and every creator's /by page while their feature is on, and a creator's page links each game.

Workstream 2, categories and game pages (Chloe): tags and category pages (/categories, /categories/<name>), about, how to play, FAQ and walkthrough pages for each game written only from its own files, a short brief read from each game's repo, and About and FAQ pages for games by independent creators.

Workstream 3, multiplayer rooms (Hamzat): refereed rooms with a code, matchmaking and bots (tic-tac-toe, Connect 4, draughts, ayo, Whot, Ludo, quiz, bingo), and relay rooms for games start.ng does not referee.

F-series and fixes (Hamzat): F2 game review (a new game waits for an admin before it is listed), F8 game health, F9 private tournaments made by admins, F10 problem reports with a coin reward for real bugs, switching features on and off from the admin page, stay signed in, activity log search, Play next inside a running tournament, ratings and newest-first fixes.

Also: tournament emails with game covers (Jubril), a leagues seat fix, CONTRIBUTING.md, and fixes for every CodeQL alert raised on these changes.

To deploy:

  • Migrations 0043 to 0049 run on start (alembic upgrade head): feature switches, tags, game pages, game brief, game reviews, admin private tournaments, problem reports.
  • New features are off until switched on, in FEATURES or the admin page's Features tab: tags, game_pages, rooms, game_review, support.
  • Deploy this before startnextgen/startng-fe, which asks these routes for its page text. Until then the website shows the same pages without the text.

Checks run locally on this exact merge with upstream main: pytest 981 passed, 2 skipped.

Blackburn0 and others added 30 commits October 23, 2026 22:52
nginx on the website includes it inside the homepage's #root (an SSI include),
so crawlers and AI tools read the hero, every game A to Z, how to publish,
and the About and questions without running the app. It is the same words the
React homepage shows, and leaves out hidden games and the Hangout.
nginx on the website includes it inside /games' #root, one page at a time
(?page=2), like the homepage. It is the same cards, order, count and page
links the app shows: the Hangout first, then the newest games, 20 a page,
and a page past the end shows the last one. The header and footer are now
shared with the homepage text.
GET /pages/games?page=N answers 404 when there's no such page, so nginx can
serve the site's 404 page instead of a copy of the last page.
The pages app/routers/pages.py writes for search engines must match the
React pages word for word: same data, order, counts, links and head tags,
nothing for bots only, a 404 for pages that don't exist, and a curl check
before every PR. Also how to build a feature, test and open a PR.
A new player got seat "players in the group + 1". Deleting an account
removes its league entry, so that number could already be taken: every
later join to the group clashed with it, and nobody new could be seated
for the rest of the round. Now a player gets the group's lowest free seat.
Tags (app/features/tags, flag "tags"): a game can have many tags, not one category (T1's single category is untouched).
42 tags in 6 groups, with rules that only suggest tags from a game's name and description. A person approves every tag in
the admin; only approved tags are shown. A tag gets a public page once 3 visible games have it. Four "words people search"
tags (Web games, Browser games, Free online games, HTML5 games) are on every game.

Category pages, written by the server: /pages/categories (all of them) and /pages/categories/<slug> (one, with its games,
a pager, related categories, structured data and a real 404 with noindex for a category that has no page).

The server-written /games/<name> page now links to the game's categories, so search engines can follow them.

Shared pieces: SITEMAP_PROVIDERS and GAME_PAGE_PARTS in app/routers/pages.py (small hooks a feature uses to add its own
addresses to the sitemap and a block to a game's page; a feature that is off adds nothing), and app/server_html.py with
the top bar, footer, game card and category tile that server-written pages share.

Migration 0043 (tags, game_tags). Renumber if another lands first.
…by the server

A game's own pages (app/features/game_pages, flag "game_pages"): /games/<name>/about, /how-to-play, /faq and /walkthrough,
written by the server from facts in the game's own files (startng.json, then the README, then its page). Nothing is invented
and no AI writer is used. A page is not made when the facts are not enough (a FAQ needs something the game itself said), two
near-identical pages become one, a person reads, edits and approves each page, and an edited or approved page is never
written over. Admin routes to make drafts, review, approve and list the games that have no page and why.

Approved pages are listed in the sitemap with the day they were approved, and the game's server-written page links to them
("More about this game"), using the hooks from the tags PR. If the tags feature is on, a game's categories also show on its
own pages.

Migration 0044 (game_pages). Renumber if another lands first.
start.ng can't read these games' files, so the pages say only what the creator typed when adding the game (its name and
description), who they are and where it is hosted. They don't claim the game is free, works on a phone or has nothing to
install. They are written on request (nothing to approve, nothing stored), under the same "game_pages" flag:
- GET /pages/creators/<id>/about and /faq: server-written pages with a canonical link (/creators/<id>-<name>/about),
  BreadcrumbList, VideoGame (about) and FAQPage (faq) data. A missing game is a real 404 (noindex).
- GET /indie/<id>/pages lists them, so the game's page can link to them.
- The sitemap lists them, and the server-written /creators/<id> page gets a "More about this game" block through a new
  hook, INDIE_PAGE_PARTS in app/routers/pages.py (like GAME_PAGE_PARTS).
Everything the creator typed is escaped. 7 new tests.
The pages said little more than the creator's own words. They now also use true facts we already have:
- About: an "At a glance" list (creator, on start.ng since <month>, where it plays, categories, leaderboard and its
  columns, first control) and "How scoring works" (how the game's own leaderboard columns rank players, from startng.json).
- How to play: "The goal", "Scoring and the leaderboard" and "Before you start" (where to open it, sign in to save a run,
  a pointer to the walkthrough when there is one).
- FAQ: since when it has been on start.ng, and how the leaderboard ranks.
- Read live on each page, so they are never out of date: "Top players right now" (About and How to play), "More games by
  <creator>" and "Games like <name>" (the same category, when tags is on), as cards.
Nothing is invented: a part is left out when its fact is missing, and the tests check that no claim about phones, offline,
multiplayer or "best game" appears. 9 new tests.
… be thin

- About: "What is <game> about?" now also includes more of what the game says about itself: further README paragraphs
  (not the how to play, features or tips sections) and sentences from its own page. A person still reads and approves each
  page, and a control or a one-word label is never used as "about" text.
- Publishing warns when start.ng found nothing to say about the game (thin_page): it says to add a description and a story to
  startng.json, or a README paragraph. The check lists it too (POST /games/check), so creators see it before they publish.
Same idea as the community game pages, with the facts we have for a game hosted elsewhere:
- About: an "At a glance" list (creator, on start.ng since <month>, where it is hosted, opens in a new tab).
- FAQ: two more questions, when it was added to start.ng, and whether it has a leaderboard here (no: it is hosted by its
  creator, so start.ng does not keep its scores).
- Read live on each page: "More games by <creator>" and "More games by independent creators", as cards.
Nothing is claimed that the creator did not say. 3 more tests.
Until now an admin had to press "Generate". Now, while the game_pages feature is on:
- a background job (every 2 minutes, 10 games at a time) writes draft pages for any visible game that has none, so a new
  game gets its drafts without anyone doing anything, and so does every existing game the first time the feature is on;
- when a game gets a new version (the game_updated event, including pushes from GitHub), its draft pages are remade, so a
  game that was too thin gets pages once its creator adds words.
A person still reads and approves every page before it is public, and an approved or edited page is never overwritten.
Nothing happens while the feature is off. 3 new tests.
…d the admins

- After 3 failed checks in a row, start.ng marks the game "needs fixing" itself:
  hidden everywhere until the owner says it's fixed and an admin puts it back.
  A hidden game is checked from its files only (its address shows an error page).
- The owner is emailed what failed and what to try (DEV_EMAILS, only to addresses
  Google checked); the super admins are emailed too.
- Guard: if 30% or more of a round fails (5+ checked), or more than 5 games would
  be hidden in an hour, it looks like start.ng is down: nothing is hidden and the
  super admins get one alert an hour.
- Email: send_to_user and send_to_admins, for emails about a person's own games.
- Needs fixing: marking moves into service.mark (used by admins and the health
  check); requests say if they were "automatic".
- Settings GAME_HEALTH_AUTO_HIDE and DEV_EMAILS (both on). No migration.
A round only checks the games that are due, often just a few in production, so a
round's share alone rarely showed an outage; the 5-an-hour cap would then hide good
games first. Now the share of failing checks in the last CHECK_EVERY counts too.
- app/features/game_review (flag game_review, permission games.review). A new game
  (a signed-in publish, or one claimed through its /approve link) is unlisted with
  reason "in_review": off lists, search and tournaments, but its address still
  works so the admin and its owner can open it.
- Admins approve it (listed) or reject it with a reason and a note (stays
  unlisted). A rejected game whose owner pushes a fix is back in the queue.
- Only the first publish is reviewed. No review row means approved (games already
  live, or published while the flag was off). Admins who can review skip it.
- Emails: the owner gets "we got it", "it's live" or "not approved yet, why"
  (DEV_EMAILS); super admins get "new game to review".
- The publish reply has hidden: "in_review" on a new game that waits.
- Game health also checks games in review (their address is online), so the
  review card shows if a game loads; it never hides them. "Check now" says when
  it has just hidden a game.
- Migration 0045 (game_reviews), on top of 0042: renumber before merging.
dav3exe and others added 29 commits October 25, 2026 21:56
# Conflicts:
#	README.md
#	app/features/__init__.py
feat(rooms): refereed multiplayer rooms, with tic-tac-toe
feat(rooms): more games (Connect 4, draughts, ayo, Whot, Ludo, quiz, bingo)
feat(rooms): Relay rooms for games start.ng does not referee
F8 game health: hide a game that keeps failing, and tell its owner and the admins
# Conflicts:
#	README.md
#	app/features/__init__.py
F2 game review: a new game waits for an admin before it's listed
F9 private tournaments made by admins, shared by link, for people who register
# Conflicts:
#	app/config.py
#	app/features/__init__.py
F10 problem reports: players report problems with start.ng, a real bug pays coins
Redesign tournament emails with game covers
…ure pages and creators in the sitemap

- /pages/creators?page=: the newest games by independent creators, 20 a page, 404 past the last page
- /pages/tournament: today's games, top runs, standings and past winners (times in Nigeria time)
- /pages/leaderboard?period=all|week: tournament points, all time or this week
- Sitemap lists /spotlight, /shop, /by and /friends while their feature is on, and every creator's /by page
- A creator's server-written page links each game to its /games page
- /pages/spotlight: today's challenge and the Game of the Week
- /pages/by: the top creators, each linked to their page
- /pages/shop: today's stock with prices and the featured picks
- /pages/friends: what a tournament with friends is
Each answers 404 while its feature is off, so nginx leaves the page as it is.
Server-written text for more pages, and a fuller sitemap
… fixed words in page addresses

- Pagination (/games, /creators, category pages): links and numbers from ?page= are escaped
- Category pages build their address from the stored slug; game and independent game guides use the
  page type from our own list, not the request's text
- generate.shingles: the game address regex is bounded (a name is at most 63 characters), so long runs
  of dashes can't make it slow
- test_indie_pages: check the host with a regex (CodeQL read the substring check as URL sanitizing)
Fix CodeQL alerts on the server-written pages
Fix the last CodeQL alert on category pages
Merge dev into main: workstreams 1 to 3, F-series and server-written pages
@dav3exe
dav3exe merged commit d532fd2 into startnextgen:main Oct 26, 2026
5 of 6 checks passed
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.

4 participants