Summary

File-based Astro routing for the public site. Each .astro or .ts file becomes a URL route. All pages use export const prerender = false for on-demand SSR. Dynamic routes use bracket syntax ([slug], [isbn]). Pages cache aggressively via Cache-Control headers set in Astro.response.headers.

File Structure

pages/
├── index.astro                       - Homepage: hero search bar + curated book sections
├── 404.astro                         - Custom 404 error page
├── [slug].astro                      - Catch-all for CMS-managed static content pages
├── nyheter.astro                     - New arrivals listing
├── sok.astro                         - Full-text book search (query via ?q=)
├── annonssamarbeten.astro            - Advertising partnerships information
├── branschkollegor.astro             - Industry colleague resources page
├── forlagstjanster.astro             - Publisher services page
├── integritetspolicy.astro           - Privacy policy
├── kontakt.astro                     - Contact information page
├── om-oss.astro                      - About Smakprov.se
├── sa-gor-vi-smakprov.astro          - How PDF samples are produced
├── smakprov-express.astro            - Express publisher service page
├── sitemap-books.xml.ts              - Dynamic XML sitemap for all book pages (queries DB)
├── smakprov.php.ts                   - Legacy PHP redirect compatibility endpoint
├── admin/
│   ├── index.astro                   - Admin dashboard (auth required)
│   ├── login.astro                   - Admin login page
│   ├── analytics.astro               - Page-view analytics dashboard
│   ├── navigation.astro              - CMS navigation editor
│   ├── categories/
│   │   ├── index.astro               - Category list
│   │   ├── [id].astro                - Edit category
│   │   └── new.astro                 - Create category
│   ├── content/
│   │   ├── index.astro               - CMS content block list
│   │   └── [key].astro               - Edit content block by key
│   ├── curated/
│   │   ├── index.astro               - Curated list manager
│   │   ├── [id].astro                - Edit curated list
│   │   └── new.astro                 - Create curated list
│   ├── groups/
│   │   ├── index.astro               - Category group manager
│   │   ├── [id].astro                - Edit category group
│   │   └── new.astro                 - Create category group
│   └── partners/
│       ├── index.astro               - Partner list
│       ├── [slug].astro              - Edit partner
│       └── new.astro                 - Create partner
├── api/
│   ├── admin/
│   │   ├── analytics.ts              - Admin analytics API: reads page_views
│   │   ├── categories.ts             - CRUD API for cms_categories
│   │   ├── content.ts                - CRUD API for cms_content
│   │   ├── curated.ts                - CRUD API for cms_curated_lists
│   │   ├── groups.ts                 - CRUD API for cms_category_groups
│   │   ├── navigation.ts             - API for navigation configuration
│   │   └── partners.ts               - CRUD API for partners
│   ├── analytics/
│   │   └── collect.ts                - Endpoint that receives page view events (inserts into page_views)
│   └── auth/
│       ├── login.ts                  - Admin login endpoint (sets session cookie)
│       └── logout.ts                 - Admin logout endpoint (clears session)
├── bok/
│   └── [slug].astro                  - Book detail page (SSR, 301 redirect from ISBN URLs)
├── blogg/
│   ├── index.astro                   - Blog post listing
│   └── [...slug].astro               - Individual MDX blog post
├── forlag/
│   ├── [slug].astro                  - Publisher catalog page
│   └── [slug]/portal/
│       └── statistik.astro           - Publisher portal: statistics view
├── kategori/
│   └── [slug].astro                  - Category browse with paginated BookGrid
├── lab/
│   └── allBooksWithSmakprov_hum.php.ts - Legacy PHP feed compatibility endpoint
├── las/
│   └── [isbn].astro                  - Full-screen PDF reader (noindex, client-only React)
├── native/
│   ├── index.astro                   - Native (sponsored) content listing
│   └── [...slug].astro               - Individual native content article
└── smakprov/
    ├── index.astro                   - Smakprov landing/browse page
    └── visa/[isbn]/partner/
        └── [slug].astro              - Partner-branded smakprov reader page

Connections

Page details

/ — index.astro

Fetches curated sections from getCuratedBooks() (one Supabase query per section). Caches for 1 hour with 10 minute stale-while-revalidate.

/bok/[slug] — bok/[slug].astro

Primary book page. If the URL param looks like a 13-digit ISBN, issues a 301 redirect to the slug-based URL. Fetches the book with full join (publishers, book_contributors, book_categories). Loads similar books by shared category IDs, falling back to same publisher. Caches for 24 hours.

/las/[isbn] — las/[isbn].astro

Full-screen PDF reader. Validates the ISBN param, looks up storage_url, renders <PdfViewer client:only="react">. Marked noindex. Caches for 24 hours.

/kategori/[slug] — kategori/[slug].astro

Filters books by category slug using the filters array from lib/categories.ts. Matches against categories.name with type genre or subject. Supports pagination via ?page= query param.

/sok — sok.astro

Accepts ?q= query parameter. Searches books table using Supabase .ilike() across title, ISBN, and author name fields.

/forlag/[slug] — forlag/[slug].astro

Publisher catalog page. Lists all books by the given publisher. The portal sub-route (/forlag/[slug]/portal/statistik) shows page-view statistics for the publisher’s books, gated behind authentication.

/native/[...slug] and /blogg/[...slug]

Server-rendered MDX content pages. native/ serves sponsored/partner content; blogg/ serves editorial blog posts. Both use the Astro content collection system with MDX.

/smakprov/visa/[isbn]/partner/[slug] — smakprov/visa/[isbn]/partner/[slug].astro

Partner-branded reader page. Loads partner branding from the partners table and renders the PDF viewer with partner header. Used for affiliate/partner deep-links.

/admin/*

Admin CMS pages protected by src/middleware.ts. All admin pages import AdminLayout. The React components in components/admin/ handle interactive client-side operations (toast messages, CRUD forms, category picker). Admin API routes are in api/admin/ and use the Supabase service role key.

/api/analytics/collect — collect.ts

Receives POST requests with page view data and inserts a row into page_views. Called client-side by Analytics.astro. No auth required — uses the anon key. Rate limiting should be handled at the CDN or WAF level.

/sitemap-books.xml.ts

Generates an XML sitemap by paginating through the books table and emitting one <url> per book slug. Used alongside the @astrojs/sitemap static sitemap.

Caching conventions

// Standard content page — 1 hour TTL
Astro.response.headers.set('Cache-Control', 'public, s-maxage=3600, stale-while-revalidate=600');

// Book/reader pages — 24 hour TTL
Astro.response.headers.set('Cache-Control', 'public, s-maxage=86400, stale-while-revalidate=3600');