Santhosh Janardhanan 65b51d573a
Some checks failed
ci / site (push) Has been cancelled
publish-image / publish (push) Has been cancelled
nginx tuning
2026-02-10 23:32:56 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 23:32:56 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 06:46:29 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 02:52:14 -05:00
2026-02-10 20:57:28 -05:00
2026-02-10 22:37:29 -05:00
2026-02-10 20:57:28 -05:00
2026-02-10 20:57:28 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 23:06:52 -05:00
2026-02-10 20:57:28 -05:00
2026-02-10 20:57:28 -05:00
2026-02-10 23:13:37 -05:00

fast-website

Lightweight, SEO-first website for SanthoshJ that aggregates YouTube + Instagram + podcast content and tracks conversion events via Umami.

Specs (OpenSpec)

This repo uses OpenSpec (schema: spec-driven) to document and ship features.

  • Active specs live in openspec/specs/<spec-name>/spec.md
  • Completed initiatives (proposal/design/tasks + delta specs) live in openspec/changes/archive/<date>-<change-name>/

Key public flags (documented in site/.env.example):

  • PUBLIC_SITE_URL: canonical URL base
  • PUBLIC_ENABLE_SW: set to "false" to disable service worker registration
  • PUBLIC_ENABLE_NAV_HOVER_LINE: set to "false" to disable decorative hover-line styling

Spec Index (Active)

Content + ingestion:

  • social-content-aggregation (openspec/specs/social-content-aggregation/spec.md): normalize YouTube/Instagram/podcast items and refresh via cached ingestion
  • homepage-content-modules (openspec/specs/homepage-content-modules/spec.md): homepage module ordering, newest feed, high-performing videos, and Instagram omission when empty
  • wordpress-content-source (openspec/specs/wordpress-content-source/spec.md): fetch WordPress posts/pages/categories via wp-json and write to build cache
  • blog-section-surface (openspec/specs/blog-section-surface/spec.md): /blog surface (index/category/detail) + Umami-instrumented navigation
  • seo-content-surface (openspec/specs/seo-content-surface/spec.md): indexable pages, canonical URLs, sitemap + robots, and JSON-LD expectations

Analytics + tracking:

  • interaction-tracking-taxonomy (openspec/specs/interaction-tracking-taxonomy/spec.md): required Umami event attributes, target_id namespaces, and modal interaction events
  • analytics-umami (openspec/specs/analytics-umami/spec.md): Umami enable/disable behavior + supported custom events
  • conversion-ctas (openspec/specs/conversion-ctas/spec.md): reusable CTA surface + UTM support + cta_click tracking

UI + UX shell:

  • wcag-responsive-ui (openspec/specs/wcag-responsive-ui/spec.md): responsive nav shell, focus-visible baseline, reduced motion, and semantic element rules
  • card-layout-system (openspec/specs/card-layout-system/spec.md): standardized card information architecture + modal-trigger behavior for video/podcast cards
  • media-modal (openspec/specs/media-modal/spec.md): <dialog>-based media preview modal requirements (focus, playback stop, crawlable CTAs)
  • image-lazy-loading (openspec/specs/image-lazy-loading/spec.md): shimmer placeholders + fade-in + failure handling + reduced-motion behavior
  • site-theming (openspec/specs/site-theming/spec.md): data-theme application, defaults, and persistence rules (localStorage + cookie fallback)
  • theme-switcher-notch (openspec/specs/theme-switcher-notch/spec.md): floating theme notch placement, interaction, and accessibility requirements
  • navbar-branding (openspec/specs/navbar-branding/spec.md): header logo + centered brand layout
  • nav-hover-line (openspec/specs/nav-hover-line/spec.md): decorative hover-line treatment for header titles + key surface titles (flagged)

Performance + deployment:

  • service-worker-performance (openspec/specs/service-worker-performance/spec.md): production SW registration + runtime caching + safe updates
  • responsive-image-delivery (openspec/specs/responsive-image-delivery/spec.md): explicit dimensions + deterministic image behavior for quality gates
  • lighthouse-quality-gate (openspec/specs/lighthouse-quality-gate/spec.md): deterministic Lighthouse runner + 100-score assertion
  • docker-content-refresh (openspec/specs/docker-content-refresh/spec.md): Docker-only host refresh/update workflow (no Node.js on server)
  • cache-layer (openspec/specs/cache-layer/spec.md): Redis-backed shared cache + TTL + manual cache clear

Quality Gates

  • Site build: npm -C site run build
  • Lighthouse gate docs: site/docs/lighthouse.md (scripts: npm -C site run lighthouse:run, npm -C site run verify:lighthouse)

Completed Initiatives (Archived)

Each archived initiative includes proposal.md, design.md, tasks.md, and any delta specs used for that change.

Change Focus
2026-02-10-dynamic-homepage-social-acquisition Initial SEO-first site: content aggregation, homepage modules, CTAs, and analytics
2026-02-10-better-tracking Site-wide click tracking taxonomy aligned to Umami
2026-02-10-custom-events-umami Expand Umami custom event coverage + standardize event properties
2026-02-10-blog-umami-fix Fix and verify blog surface Umami instrumentation
2026-02-10-better-cache Add Redis cache layer + TTL + manual clear; wire into ingestion
2026-02-10-card-layout Standardize card layout across surfaces
2026-02-10-lazy-loading Add shimmer placeholders and reduced-motion-safe image loading UX
2026-02-10-blogs-section Add WordPress-backed blog section + routes + secondary nav
2026-02-10-hide-ig-if-no-data Omit Instagram module when dataset is empty
2026-02-10-reduce-bounce-rate Add in-page media modal previews for video/podcast cards
2026-02-10-service-workers Add service worker caching for repeat-visit performance
2026-02-10-deploy-without-node Docker-only host refresh/update workflow
2026-02-10-fix-sub-pages Fix static serving so /videos, /podcast, /about do not 404
2026-02-10-wcag-responsive WCAG baseline + responsive nav shell + typography/background fixes
2026-02-10-lighthouse-fixes Lighthouse cleanup + deterministic 100/100/100/100 gate
2026-02-11-dch-theming Dark/light/high-contrast themes + theme notch UI
2026-02-11-remember-theme Persist theme across visits + emit theme switch tracking
2026-02-11-final-touches Header branding polish + hover-line treatment behind env flag

Local Setup

cd site
cp .env.example .env
npm install
npm run fetch-content
npm run dev

Open http://localhost:4321.

Configuration

All configuration is via environment variables (see site/.env.example).

YouTube

  • YOUTUBE_CHANNEL_ID is required for ingestion.
  • Optional: YOUTUBE_API_KEY enables view-count ingestion for high-performing ranking.

Notes:

  • The channel ID looks like UC... and can be found by viewing the channel page source or via YouTube Studio settings.
  • If YOUTUBE_API_KEY is not set, ingestion falls back to the public channel RSS feed and metrics will be missing.

Podcast

  • PODCAST_RSS_URL is required to ingest episodes.

Instagram (Embed-First)

Edit site/content/instagram-posts.json:

{
  "posts": [
    { "url": "https://www.instagram.com/p/<id>/", "publishedAt": "2026-02-01T00:00:00Z", "title": "Movie post" }
  ]
}

Phase 2 (API ingestion) path:

  • Requires Meta developer app setup, correct account type, token issuance + refresh, and platform policy compliance.
  • Recommended approach: keep embed-first for v1, then add an optional API ingest module when constraints are clear.

If YouTube metrics are not available, curate high-performing videos in site/content/featured-videos.json:

{ "videoIds": ["abc123", "def456"] }

Analytics (Umami)

Set:

  • PUBLIC_UMAMI_SCRIPT_URL
  • PUBLIC_UMAMI_WEBSITE_ID

If either is missing, analytics is disabled and the site still functions.

Event tracking is implemented using Umami's data-umami-event and data-umami-event-* attributes.

Click Tracking Taxonomy (Umami-Compatible)

All tracked clickables MUST set:

  • data-umami-event: the event name (max 50 chars), e.g. click, cta_click, outbound_click
  • data-umami-event-target_id: stable unique identifier for the clickable element (namespaced like nav.*, cta.*, card.*)
  • data-umami-event-placement: where the clickable appears (e.g. nav, hero, section_header, home.newest)

For links, also set:

  • data-umami-event-target_url: destination URL (can be relative for internal navigation)

Common additional properties:

  • data-umami-event-domain: destination domain (for outbound links)
  • data-umami-event-source: youtube / instagram / podcast where applicable
  • data-umami-event-ui_placement: a sub-placement for UI grouping (e.g. content_card)

Instrumentation checklist:

  • Every clickable should have a unique target_id so it can be segmented in Umami.
  • Use categorical ids and placements only (no PII).

Deployment (Linode + Docker)

The production host is intentionally minimal and only needs Docker (no Node.js on the server).

Local Docker

docker compose build
docker compose up -d

The container serves the static output on port 8080 (map or proxy as needed).

Production (Docker-Only Host)

In production, CI builds and publishes a Docker image (nginx serving the static output). The server updates by pulling that image and restarting the service.

Runbook: deploy/runbook.md.

Refreshing Content (Manual, Docker-Only)

Content is fetched at build time into site/content/cache/content.json (typically in CI), then packaged into the image.

On the server host:

./scripts/refresh.sh

This:

  1. Pulls the latest published image
  2. Restarts the service (no build on the host)

Refreshing Content (Scheduled)

Install a daily cron using deploy/cron.example as a starting point.

Rollback:

  • Re-deploy a known-good image tag/digest (see deploy/runbook.md).
Description
No description provided
Readme 11 MiB
Languages
Astro 44.2%
TypeScript 33.5%
CSS 17.4%
JavaScript 3.4%
Dockerfile 1.1%
Other 0.4%