Build https://christitus.com/ as a fast, durable Astro publication and
creator hub. The redesign should make articles, downloads, live streams,
newsletter signup, topics, and YouTube immediately discoverable while
preserving the archive, integrations, and public URLs accumulated by the Hugo
site.
- Readers find current and historical technology guides through the homepage, categories, tags, archive, search, feeds, and existing inbound links.
- Viewers browse livestream recordings and play a selected YouTube video with synchronized Twitch chat when replay data exists.
- Customers reach digital downloads, troubleshooting, and recommendations.
- Subscribers use the newsletter form and its existing reCAPTCHA-backed service.
- Maintainers publish Markdown and refresh livestream/chat data through the existing Python and GitHub Actions automation.
- Use a modern tech-editorial design that retains the existing Chris Titus Tech
logo and cyan
#47c4f1accent. - Provide polished dark and light themes using custom CSS, strong typography, restrained effects, responsive cards, and consistent spacing tokens.
- Use Astro components and vanilla JavaScript. No Bootstrap, Tailwind, React, Vue, or other client UI runtime is required.
- Header destinations are Articles, Downloads, Live, Newsletter, and Topics, with search, theme toggle, and a YouTube action. The logo links home.
- Forums, Recommendations, Archive, RSS, legal pages, and social destinations remain available through secondary/footer navigation.
/videos/redirects to the public YouTube channel because the source page is empty.- The homepage contains one primary and two secondary featured articles, creator action cards, topic discovery, recent livestreams, latest articles, and newsletter/YouTube promotion.
featuredOrderaccepts only 1, 2, or 3 and is globally unique; each value selects its matching homepage slot only when that post is production-eligible. A draft or future curated post does not render and leaves the slot for fallback. Remaining slots use production-eligible unselected posts sorted by publication key descending, then case-sensitive canonical URL ascending. Offset timestamps normalize to UTC for that key; date-only values map to midnight inAmerica/Chicagoon their stated date.
- Article pages include title, publish date, reading time, categories, tags, featured media, reading progress, responsive table of contents, sharing, related posts, lazy ads, and lazy Utterances comments.
- List, category, and tag pages use ten posts per page and retain Hugo-compatible pagination routes. Page-one aliases redirect to the canonical list URL.
- Search accepts
/search/?s=<query>, fetches/index.jsonon demand, searches title/content/tags/categories, and exposes loading, results, empty, and error states accessibly. - Archive, RSS directory, downloads, newsletter, recommendations, privacy, refund, terms, and 404 pages use the shared redesigned shell.
npm run new:post -- "<title>" [--date YYYY-MM-DD] [--category "<name>" ...]provides the Astro replacement for Hugo archetypes. The date defaults to the current calendar day inAmerica/Chicago; explicit dates use strictYYYY-MM-DD. The date determines both front matter and thesrc/content/posts/<year>/directory.- Slugs are deterministic: trim the title, apply Unicode NFKD normalization,
remove combining marks, lowercase it, replace each maximal run outside ASCII
[a-z0-9]with one hyphen, trim leading/trailing hyphens, and reject an empty result. The scaffolder writes<slug>.md, emits/<slug>/as the explicit URL, and sets the image toimages/<year>-thumbs/<slug>.webp. - The template includes the title, date, URL, image, selected categories, empty
tags,
draft: true, and a<!--more-->summary boundary. The command refuses to overwrite an existing destination file. It serializes the title as a JSON-compatible double-quoted YAML scalar, parses the generated front matter, and requires the parsed title to equal the input exactly before writing. --categoryis repeatable. When it is omitted, an interactive terminal prompts for one or more choices; non-interactive use fails instead of guessing. Canonical choices are Android, ChromeOS, Development, FreeBSD, Hardware, Linux, MacOS, Misc, Networking, Software Dev, Titus, Virtualization, Windows, Windows Server, and YouTube. Values outside this exact set fail validation.- New posts use the canonical
MacOSspelling, while migratedmacOSandmacosvalues remain unchanged. The canonical-set check applies to--categoryinput; it rejects those historical variants for new posts. The loader accepts only these exact URL/value pairs:/2020-buyers-guide/+macOS,/change-wallpaper/+macOS,/macos-sysadmin-tips/+macos,/opencore-mac/+macOS, and/zed-editor/+macOS. Only content loading and schema validation apply this pair allowlist to manually authored content and migrated fixtures; scaffolder input always rejects both historical spellings. The opposite legacy spelling fails at each allowlisted URL.Software Devgenerates the normalized taxonomy route/categories/software-dev/. - Generated posts use the same content schema and validation path as manually
authored Markdown. Before writing, the scaffolder virtually inserts the
candidate and builds the complete resulting public route inventory using the
same route-contract code as validation: explicit post URLs, derived standalone
page and collection/taxonomy routes, aliases, pagination, feeds and utility
endpoints, redirect sources, and static public endpoints. This includes new
pagination, taxonomy, and feed outputs caused by the candidate.
Collision keys enforce one leading and trailing slash and collapse repeated
slashes without changing character case. Thus
/Post/and/post/remain distinct, while/post,post/, and/post//collide with/post/. A second key maps routes to emitted paths, so/foo/collides with static/foo/index.htmland/collides with/index.html. Candidate URLs also collide with a file/directory conflict: no emitted file path may be a strict ancestor of another emitted file path. Redirect patterns are separate from emitted-route entries. Every candidate-induced route, including new taxonomy, pagination, feed, alias, and collection routes, is matched against each exact, wildcard, or parameterized redirect source under the deployed grammar. Redirect patterns are never compared with themselves; existing pattern-to- pattern behavior remains governed by the ordered redirect contract and is not a scaffolder collision. Comparison never rewrites historical front matter. Invalid categories, dates, route/output collisions, and existing destination files fail with actionable errors.
.github/workflows/update-livestreams.ymlis the scheduled workflow for both livestream metadata and chat replays. Its chained jobs use the same managed data branch, and a concurrency group withcancel-in-progress: falseserializes every accepted run. Each run resets the managed branch to its exactmasterbase and performs a full current-state source reconciliation. Each job checks out its predecessor's emitted SHA and verifies the branch has not moved. After both data jobs, the workflow builds the generated site and validates its routes. The final publisher proves both the capturedmasterbase and managed-branch final SHA are unchanged, proves the candidate changes only allowlisted generated data, and fast-forwards that exact SHA directly tomasterwithout a pull request. Drift fails closed and the next accepted run refetches current data. A separate scheduled/workflow-run watchdog usesactions: readandissues: writeto detect queue-limit cancellation or rejection through the Actions API and open/update a durable tracking issue. The watchdog closes the alert only after every required job succeeds and the managed data branch equalsmaster.data/livestreams.jsonretainsupdatedanditems. Items requirevideoId,title,description,thumbnail,date, andpublishedAt;twitchVodIdandhasChatReplayremain optional. The Python automation continues to usepublishedAtwhen matching unmatched Twitch VODs.- The archive features the newest valid stream and paginates remaining streams at 24 items per static page. Deleted/private entries are not rendered.
/live-streams/player/?v=<videoId>validates the ID, redirects invalid values to the archive, loads YouTube playback, and displays metadata for known IDs.- Chat JSON is requested only when present. Missing chat keeps video full width. Loaded chat supports embedded badges/emotes, seek resynchronization, play/ pause synchronization, automatic scrolling, and manual resume. Chat scrolls independently without moving the page. The player and chat remain side by side when both are usable at that width; on narrow portrait screens, the video stays directly above the viewport-bounded chat so both are visible together when the player section is brought into view.
- Astro loads post Markdown from
src/content/posts/and standalone page Markdown from the repository's existingsrc/content/tree. - Content with Hugo
build.render: never, including the duplicatesrc/content/live-streams.mdsource, remains excluded from Astro routes. The renderablesrc/content/live-streams/_index.mdowns/live-streams/. - Published posts require valid
title,date, andurl. New posts require at least one category, but the loader accepts the existing published posts with empty category lists only for/2022-recap/,/worst-tech-of-2022/, and/youtube-telegram-scams/, and renders those posts without category links. The allowlist is explicit in source and tests; any other uncategorized post fails validation. Draft defaults to false: an omitted field is published, and only explicitdraft: trueis excluded. Duplicate normalized URLs fail the build. - Production captures one build instant and reuses it for every content query.
Front matter with an explicit offset is parsed as an instant and is eligible
at or before that instant. A date-only
YYYY-MM-DDvalue is eligible for the entire matching day: compare it to theAmerica/Chicagocalendar date that contains the build instant, inclusively. Timestamp values without an explicit offset fail schema validation. Production excludesdraft: trueand later content with this shared predicate. npm run dev:contentstarts Astro in a local-onlycontent-previewmode that includes drafts and future content. Standardnpm run devuses production filtering.npm run buildignores/rejects content-preview mode and always produces the production route contract; a Cloudflare preview is annpm run buildartifact indist/, not the local content-preview mode.- Preserve historical front-matter extensions. In particular, the
tablesobject on/bad-windows-defender/supplies both table shortcodes and must survive typed parsing; a test asserts its existing headers and values render. - Historical raw HTML remains renderable.
<!--more-->defines the preferred summary boundary; otherwise a plain-text excerpt is generated. - The compatibility renderer supports the only Hugo shortcodes present in
published content:
youtube,x,notice,table, andshopify. Unsupported active shortcode syntax is a build error. Hugo examples inside inline or fenced code remain escaped literal content and are excluded from this gate. - YouTube embeds use privacy-enhanced URLs and descriptive titles. X embeds have a usable link fallback. Notice and table output is semantic and accessible.
- Static images, fonts, downloads, chat JSON, and custom files remain under
public/. Move or copy the trackedsrc/content/posts/2023/english.pnginto the Astro public asset tree so/posts/2023/english.pngremains byte-identical and routable. The site may use Cloudflare image transforms with direct fallback.
- Canonical published
urlvalues are immutable unless a task explicitly includes redirects and migration approval. - Preserve
/,/page/N/, categories, tags, category/tag pagination, top-level utility pages, all post URLs, legacy source-path aliases, and curated rules in_redirects. - Preserve
/index.jsonwith entries shaped astitle,tags,categories,contents, and absolutepermalink. - Preserve
/index.xml, category/tag RSS endpoints,/rss/, and/sitemap.xml. Drafts and sitemap-disabled pages are excluded where expected. - Canonical, previous/next pagination links, Open Graph, Twitter cards, WebSite/WebPage/BlogPosting/Breadcrumb JSON-LD, favicons, and feed discovery must remain valid.
- Move supported path rules from the tracked root
_redirectsfile into Astro's copied public tree. Pages file redirects must use relative sources. Configure HTTP/HTTPSwww.christitus.com/*canonicalization as a Cloudflare Single Redirect wildcard rule matchinghttp*://www.christitus.com/*and targetinghttps://christitus.com/${2}with query preservation;${1}is the optional schemes, while${2}is the path capture. These are zone-rule wildcard captures, not the Pages_redirects:splatplaceholder. - Replace the unsupported external
/winget200proxy with a supported/wingetexternal redirect tohttps://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1. Clients following redirects must receive the release script successfully; no Worker/Function proxy is introduced. - Preserve
public/_headerssecurity and feed caching behavior, but replace the Hugo/css/*and/js/*immutable rules. Only fingerprinted/_astro/*assets receive one-year immutable caching; copied CSS and JavaScript use a revalidating or bounded non-immutable policy.
- Retain Cloudflare Web Analytics, Google ads, Utterances, a first-party CTT Store handoff, YouTube, Twitch chat data, newsletter reCAPTCHA, and configured social links. The downloads page links to canonical CTT Store product, account, support, and contact routes rather than loading the Shopify Buy Button SDK, so product details, localization, checkout, and fulfillment stay on the store's maintained customer experience.
- Cloudflare Web Analytics loads with
deferon every page so no-interaction pageviews remain counted. Ads, comments, media APIs, and search data load lazily or after user intent where practical. - Never commit or log YouTube API keys, Twitch credentials, access tokens, private keys, or environment files.
- CI runs on pull requests and pushes. Repository rules require type checks,
unit tests, production build, route validation, and browser tests to pass for
ordinary code changes, including for administrators. The livestream workflow
does not rely on token-suppressed push or pull-request events: after both data
jobs it installs the pinned Node dependencies, builds the production site,
and validates generated routes on the exact candidate SHA. Publication then
rechecks the captured
masterbase, managed-branch head, and generated-data path allowlist before a non-force fast-forward push of that SHA tomaster. The workflow token has no broader publication path and no GitHub App or reserved tag is required. - Repository rules require pull-request branches to be current with
masterso checks cannot be reused against a newer base. Merge queue is excluded from the cutover contract. - CodeQL, dependency review, Dependabot, and npm audit cover the new JavaScript supply chain. High and critical findings must be resolved or explicitly waived before merge.
- Target WCAG 2.2 AA. All controls are keyboard operable, have visible focus, and expose correct labels/states. Navigation, search, dialogs, pagination, media, tables, and forms use semantic markup.
- Support current stable Chrome, Firefox, Safari, and Edge plus current mobile Safari and Chrome. Automated browser tests run Chromium, Firefox, and WebKit projects; manual release evidence covers real Safari, Edge, mobile Safari, and mobile Chrome where Playwright engines are not identical to the shipped browser. Core content remains readable without JavaScript.
- Respect
prefers-reduced-motionand avoid layout-dependent animation. - Lighthouse CI runs against a local production server using its pinned mobile
preset and Chromium dependency. It measures
/,/my-ai-workflow/,/categories/linux/, and/live-streams/three times and gates on the median run. Each representative route must score at least 90 for performance, accessibility, best practices, and SEO, with LCP under 3 seconds and CLS under 0.1. Tool versions and profile settings are committed with the lockfile so local and CI runs are reproducible. - Local fonts, responsive images, lazy third-party scripts, and minimal client JavaScript are required performance boundaries.
- Server-side rendering, Cloudflare Workers application logic, accounts, a CMS, comments hosted by this repository, or a JavaScript single-page application.
- Rewriting historical article prose or normalizing all historical taxonomy spelling during the framework migration.
- Replacing the Python livestream/chat data automation or changing its secret contract.
- Redesigning the logo or introducing a new brand identity.
npm ciandnpm run validatepass from a clean checkout using Node 24.- All non-draft, non-future content builds; draft and scheduled fixtures are
absent from production routes, search, feeds, and sitemap; every supported
shortcode has tested output; and no unresolved Hugo template syntax appears
outside literal code or
precontent in generated pages. - The generated route/redirect contract covers the Hugo baseline, including mixed-case URLs, feeds, pagination, aliases, and static files.
- The production artifact contains
_headersand supported_redirects; tests assert/_astro/*is immutable, copied CSS/JS are not immutable, and security/feed rules remain present. Preview/production request tests verify thewwwcanonical redirect, legacy path redirect, and followed/wingetresponse rather than relying on file presence alone. - Automated browser tests cover home, post, taxonomy, search, downloads, newsletter, livestream archive/player states, redirects, and 404 behavior in Chromium, Firefox, and WebKit projects.
- Content validation fixtures prove the three legacy category exceptions pass
and a newly added uncategorized post fails. A homepage-selection fixture
proves that a future-dated, non-draft post cannot fill a featured slot. A
published fixture without a
draftfield remains present in routes, search, feeds, sitemap, and homepage selection. - Content fixtures prove that only the five exact legacy URLs accept
macOSormacosin their current URL/value pairs; the opposite spelling at each URL and manually authored content using either value elsewhere fail. Homepage fixtures reject duplicate and out-of-rangefeaturedOrdervalues, exclude draft and future curated posts, and resolve equal-date fallbacks by case-sensitive canonical URL. - Fixed-clock tests cover offset-bearing timestamps immediately before, equal
to, and after the build instant; date-only values before, equal to, and after
the
America/Chicagobuild date; and consistent filtering across homepage, routes, search, feeds, and sitemap. Localnpm run dev:contentincludes draft and future fixtures, while standard development and production builds exclude them; Cloudflare-preview artifacts never include them. An offsetless timestamp fixture fails schema validation. - Scaffolder fixtures verify template output under a fixed
America/Chicagoclock, explicit dates, slug edge cases, every canonical category, repeatable category flags, non-interactive failures, draft defaults, rejection ofmacOSandmacosas new category inputs, acceptance of both in migrated fixtures, case-sensitive URL preservation, trailing-slash collision variants, emitted output paths, derived standalone and collection/taxonomy routes, pagination, aliases, feeds, utility endpoints, exact and wildcard/ parameterized redirects, static endpoints, file/directory ancestor conflicts, YAML metacharacters, colons,#, quotes, backslashes, newlines, exact parsed- title round trips, and overwrite protection. Fixtures virtually insert candidates and cover newly induced pagination, taxonomy, feed, alias, and collection outputs in exact and wildcard/parameterized redirect-overlap checks without redirect self-comparisons. The three empty-category URL exceptions remain covered separately by the content-validation fixtures. - The pinned Lighthouse CI profile passes all representative routes for three runs using the median thresholds defined above.
- Manual desktop/mobile and light/dark review is recorded with screenshots; keyboard navigation and third-party fallbacks are exercised.
- Cloudflare production uses Node 24,
npm run build, anddist; preview deployments use the same build contract. - The retained data workflow remains enabled. Its data, chat, generated-site
validation, and exact fast-forward publication jobs must all succeed, and the
managed data branch must equal
masterafter publication. - CI, security checks, local review, independent review, and all actionable review threads are clean before merge.