CLAUDE.md

Persistent instructions for AI coding agents working in this repo. Read this before making changes.

What this is

The BookHub static site — Jekyll, hosted on GitHub Pages (mokhhtar.github.io/bookhub), auto-deploying from main on every push (no manual deploy step, no webhook to babysit — unlike the sibling API repo, see below). Plain HTML/CSS/vanilla JS throughout: no build step, no bundler, no npm for the frontend JS itself. Every page includes <script> blocks directly; shared helpers like esc()/$() are duplicated per page rather than imported from a module.

The two-repo pair — read this first

Most features touch both repos. A new field in the backend’s /summary response is invisible here until you render it in both summary.html (the dynamic, API-driven page) and _layouts/book.html (the static, pre-published page) — these are two independent templates with no shared partial between them; check both whenever the API response shape changes.

Site structure

_config.yml          # collections (books/authors/characters), site.api_url
_layouts/
  default.html          # base layout — loads header/footer/firebase.html
  book.html               # static published book page (from _books/*.md)
  author.html              # static author page
  character.html            # static character page
_includes/
  header.html               # nav, auth chip (Sign in / account menu)
  footer.html
  firebase.html              # Firebase SDK init — see below
summary.html          # the dynamic Summarizer tool (calls the API live)
account.html          # /account/ — sign-in/register + user data management
admin/comments.html   # /admin/comments/ — owner-only moderation queue
tools/*.html          # standalone tool pages (reading-list, pdf-chat, timer, …)
_books/, _authors/,
_characters/           # AUTO-PUBLISHED by the backend's github_publisher.py —
                        # don't hand-edit individual entries; the whole
                        # publishing pipeline lives in bookhub-api.
firebase/
  firestore.rules          # source of truth for Firestore security rules —
                            # NOT auto-deployed, see below
  DATA_MODEL.md              # Firestore schema + console setup checklist

Firebase integration

Loaded via _includes/firebase.html as native ES modules straight from the gstatic.com CDN — no npm install, no build step. It exposes a small global surface for every other (non-module, classic-script) page to use:

firestore.rules is the ONLY authorization layer — there’s no backend intermediary for Firestore data (comments, likes, ratings, synced library). Every collection’s read/write rules must be airtight on their own. Critical: editing firebase/firestore.rules in this repo does NOT deploy it. You must manually re-paste the file’s contents into Firebase Console → Firestore Database → Rules → Publish after every change. This has caused real bugs (a feature shipped in code but broken live because the console still had the old rules) — always tell the user explicitly when firestore.rules changed and needs re-pasting.

Similarly, new Firestore collection-group queries need a manually created index (Console → Firestore → Indexes → Exemptions, or via the error-message link Firestore prints in the browser console on first query). Code changes alone never create these.

localStorage key conventions

Don’t invent new key names ad hoc — reuse or extend these:

Design conventions

A JS bug pattern to avoid (bit us in production)

Temporal dead zone (TDZ) crashes on direct-link entry. Several pages run entry-point logic (e.g. ?q= / ?b= query-param handling) that can execute synchronously during script parsing when the page is loaded via a direct link (as opposed to in-page navigation, where the same code runs later after everything’s initialized). Any const/let referenced by that entry-point code must be declared before it in source order, not just “somewhere in the file” — a mid-script const TOOL_BASE_PATH = ... caused Cannot access 'TOOL_BASE_PATH' before initialization for every homepage-search visitor while working fine for every in-page search, because only the homepage path hit the code before the declaration ran. When adding a new top-level const a script’s entry point might touch, declare it at the very top of the <script> block.

Testing before every push

bundle exec jekyll build locally, then check the actual generated _site/ output for the page you changed (not just “build succeeded” — Liquid errors on unrelated pages can silently produce empty/broken HTML for the page you care about). For anything touching Firebase, also manually click through the flow in a browser — Firestore rule rejections and missing indexes only surface at runtime, not at build time.

Ship one commit + push per logical step; GitHub Pages rebuilds automatically within ~1-2 minutes of push — no separate deploy action needed on this side.

Sibling repo

Backend: ../bookhub-api (FastAPI on Render). Its CLAUDE.md covers the four storage layers (Render/Redis/Firebase/GitHub), cache versioning, and backend-specific infra gotchas — read it too when a change spans both repos.