folx-tv/replit.md
sebastjanartic 4ece9e4ccd Add exclusive photos from recordings to the gallery and improve site metadata
Integrate AdSense ads into the photo gallery, introduce SSR meta tags for the gallery page, and improve layout stability by reserving space for ads and dynamic content.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 81f3d8bc-2328-4374-a06e-57257dbb713b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/OPD8Ro3
Replit-Helium-Checkpoint-Created: true
2026-03-08 07:33:00 +00:00

200 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Folx Music Television - folx.tv
## Overview
The official website for Folx Music Television (folx.tv). Dark-themed bento grid layout with content for folk music (Volksmusik/Schlager) fans. Features articles, videos, photo gallery, horoscope widget + subpage, recipe widget + subpage, Google News feed, and integrated AdSense ads. All content is hardcoded in seed for production deployments.
## SEO
- Primary keyword: "Volksmusik" — used across all page titles, meta descriptions, OG tags, and structured data
- Dynamic canonical URLs via `usePageMeta` hook (updates `<link rel="canonical">` per page)
- SSR article pages: server-side meta tags (OG, Twitter, description, keywords, canonical) in both `server/vite.ts` (dev) and `server/static.ts` (prod)
- SSR gallery page (`/gallery`): OG meta, Twitter card, description, canonical — emphasizes exclusive backstage/concert photos from recordings
- `stripExistingMeta()` removes duplicate meta/canonical from base HTML before injecting article-specific ones
- JSON-LD structured data: WebSite (home) with SearchAction, NewsArticle + BreadcrumbList (articles)
- Sitemap at `/sitemap.xml` — includes all static pages, categories, horoscope signs, and articles
- robots.txt disallows `/api/`, `/search`, `/admin/`
- H1 tag on home page (sr-only): "FOLX TV Volksmusik & Schlager Fernsehsender"
- Logo alt text includes "Volksmusik & Schlager Fernsehsender"
## Architecture
- **Frontend**: React + Vite + TailwindCSS + shadcn/ui (dark mode)
- **Backend**: Express.js + Node.js
- **Database**: PostgreSQL with Drizzle ORM
- **Routing**: wouter (frontend), Express (backend API)
## Key Features
- MSN-style bento grid homepage with mixed article/widget layout
- FeaturedCarousel with 5 article pages (page 2 = wide layout) + gallery page
- Photo gallery widget (547 Dropbox images) with fullscreen lightbox carousel
- Horoscope widget with element colors, star ratings, full /horoskop subpage
- Recipe widget + full /rezepte subpage (21 recipes across 5 regions: Österreich, Bayern, Schwaben/Baden, Südtirol/Alpen, Norddeutschland) with AI-generated images
- Google News RSS widget (Volksmusik/Schlager news, 5 items, auto-rotate)
- Google AdSense integration (ca-pub-4465464714854276)
- Interstitial overlay ad on article pages (3s delay, shows every other article visit, sessionStorage counter)
- Parallax/reveal ad below article content (sticky background ad revealed on scroll)
- Mobile sticky banner ad at bottom of screen (2s delay, session-dismissible, mobile-only via useIsMobile hook)
- Web Push Notifications (bell icon in header, auto-send on new articles, admin panel at /admin/push)
- Article listing with featured carousel and category filtering
- HTML content supports embedded iframes (bunny.net, YouTube, Facebook, Instagram, TikTok)
- DOMPurify sanitization for safe HTML rendering
- Responsive design with mobile navigation
## Data Model
- `articles`: id (serial), title, slug (unique), excerpt, content (HTML), coverImage, category, author, featured, views, publishedAt
- `article_views`: id (serial), articleId, ipHash (sha256 truncated to 16 chars), viewedAt — tracks unique IP views per article
## Seed Behavior
- `server/seed.ts` runs on startup and **always syncs** article content from seedArticles array to the database
- Existing articles (matched by slug) are **fully updated** with latest title, excerpt, content, coverImage, category, author, featured, publishedAt
- New articles are inserted; articles not in seed list are deleted
- HTML entity &bdquo;/&ldquo; in title/excerpt are auto-replaced with „/" after seeding
- Any changes to article content in seed.ts will be reflected on next deployment
- Currently all articles are under "News" category (+ "Video" for video-only articles)
- Future subcategory plan: add subcategory field for "Porträt" label on portrait articles
- Portrait articles (for future subcategory): die-edlseer, die-pagger-buam, anita-hofmann, oeschs-die-dritten
## API Endpoints
- `GET /api/articles` - All articles
- `GET /api/articles/featured` - Featured articles
- `GET /api/articles/popular` - Popular articles by views
- `GET /api/articles/category/:category` - Filter by category
- `GET /api/articles/:slug` - Single article (increments views)
- `POST /api/articles` - Create article
- `PATCH /api/articles/:id` - Update article
- `DELETE /api/articles/:id` - Delete article
- `POST /api/upload` - Upload image file
- `GET /api/push/vapid-key` - Get VAPID public key for push subscriptions
- `POST /api/push/subscribe` - Subscribe to push notifications
- `POST /api/push/unsubscribe` - Unsubscribe from push notifications
- `GET /api/push/count` - Get push subscriber count
- `POST /api/admin/push/send` - Send push notification to all subscribers
- `GET /api/gallery` - Shuffled gallery images from Cloudinary (with artist names from filenames + overrides)
- `GET /api/gallery/focal-points` - Gallery image focal points (JSON)
- `PUT /api/gallery/focal-points/:fileName` - Set focal point for gallery image
- `DELETE /api/gallery/focal-points/:fileName` - Reset focal point for gallery image
- `GET /api/gallery/artists` - Artist name overrides (JSON)
- `PUT /api/gallery/artists/:fileName` - Set/update artist name override
- `POST /api/gallery/migrate-to-cloudinary` - Migrate remaining Dropbox images to Cloudinary
- `GET /api/gallery/thumb` - Proxy endpoint for Dropbox thumbnail resizing (sharp, 400x400, 30-min cache)
- `GET /api/news-feed` - Google News RSS feed for Volksmusik/Schlager (15-min cache, stale-while-error)
- `GET /api/breaking-news` - Google News RSS feed for general news (15-min cache, stale-while-error)
- `GET /api/videos` - BunnyCDN video list (30-min cache, stale-while-error)
- `GET /api/videos/:guid` - BunnyCDN video details
## File Structure
- `shared/schema.ts` - Drizzle schema + Zod validation
- `server/db.ts` - Database connection
- `server/storage.ts` - Storage interface + DatabaseStorage
- `server/routes.ts` - API routes + gallery + news feed
- `server/seed.ts` - Hardcoded seed data (articles)
- `server/gallery-data.json` - Fallback gallery data (used when Dropbox/Cloudinary unavailable)
- `server/cloudinary-gallery-map.json` - Cloudinary public ID map for 176 migrated images
- `server/gallery-focal-points.json` - Manual focal point overrides for gallery images
- `server/gallery-artist-overrides.json` - Manual artist name overrides for gallery images
- `server/cloudinary.ts` - Cloudinary upload, URL generation, compression logic
- `client/src/pages/home.tsx` - MSN-style bento grid homepage
- `client/src/pages/article.tsx` - Article detail page
- `client/src/pages/category.tsx` - Category listing page
- `client/src/pages/videos.tsx` - Videos page
- `client/src/pages/gallery.tsx` - Full gallery page
- `client/src/pages/horoscope.tsx` - Full horoscope page (12 signs, love/career/health, weekly/monthly)
- `client/src/pages/recipes.tsx` - Full recipes page (21 recipes, 5 regions, AI-generated images)
- `client/src/lib/horoscope-data.ts` - Shared horoscope data (signs, texts, helpers)
- `client/src/components/header.tsx` - Header with nav (Start, News, Video, Galerie, Horoskop, Rezepte)
- `client/src/components/footer.tsx` - Footer with links
- `client/src/components/photo-gallery.tsx` - Gallery widget + lightbox carousel + paginated gallery page (24/batch infinite scroll) + artist name display
- `client/src/pages/admin-gallery.tsx` - Admin page for gallery management (focal points + artist names) at /admin/gallery
- `client/src/components/horoscope-widget.tsx` - Horoscope widget with element colors
- `client/src/components/recipe-widget.tsx` - Recipe widget with modal
- `client/src/components/news-widget.tsx` - Google News RSS widget
- `client/src/components/adsense.tsx` - AdSense ad components
## Homepage Layout (MSN Bento Grid)
- Row 1: FeaturedCarousel (hero + side articles + TopStorys, page 2 = wide hero)
- Row 2: 2 articles + PhotoGalleryWidget + RecipeWidget (mixed)
- Row 3: HoroscopeWidget + 2 articles + NewsWidget (mixed)
- Row 4: 3 articles + NativeAdCard
- Row 5: 3 articles + NativeAdCard
## Branding
- Dark theme (class="dark" on html)
- Primary/brand color: crimson/red (RGB 218,35,77)
- Background: 0 0% 5%, Card: 0 0% 9%
- Font: Poppins
- Logo: folx_MT_poz_b_1772296729169.png
## External Services
- Bunny.net: Library 476412, CDN vz-7982dfc4-cc8.b-cdn.net (NO autoplay)
- Google AdSense: ca-pub-4465464714854276
- Cloudinary: Gallery images (cloud_name: djqxt0pf3, 176 images migrated from Dropbox, face-aware cropping)
- Dropbox: Original gallery source (fallback if Cloudinary map empty)
- Google News RSS: Volksmusik/Schlager news feed
## Publishing Workflow
### Adding or Updating Articles
1. **Edit seed data**: Update `server/seed.ts` with new article data
- Add new articles to the `articlesData` array
- Update existing articles as needed
- Use unique slugs for SEO-friendly URLs
2. **Run seed locally** (for development testing):
- Execute: `npm run seed`
- This populates the development database with article data
3. **Commit changes**: Push code changes to the repository
4. **Deploy to production**:
- Deployment is configured as "autoscale" type in `.replit`
- Build command: `npm run build`
- Run command: `node ./dist/index.cjs`
- The production database is separate from the development database
- **Important**: Seed must run on every deploy to ensure the production database is updated with new/modified articles
- To run seed on deploy, add seed execution to the deployment process or manually trigger seed after deployment
### Database Management
- **Development**: Local PostgreSQL database (populated by `npm run seed`)
- **Production**: Separate PostgreSQL database on Replit deployment
- All article content is hardcoded in `server/seed.ts` for reproducible deployments
- The `DATABASE_URL` environment variable automatically points to the correct database (local for dev, production for deploy)
### Deployment Checklist
- [ ] Update `server/seed.ts` with new article data
- [ ] Test locally: run `npm run seed` and verify articles appear in dev
- [ ] Run `npm run build` to ensure no build errors
- [ ] Commit all changes
- [ ] Deploy via Replit deployment interface
- [ ] After deployment, ensure seed runs on the production database (may require manual trigger or additional setup)
- [ ] Verify live site at https://www.folx.tv shows updated content
## Adding Articles Workflow
When adding new articles:
1. **Always optimize images first**: Resize to max 1200px wide, quality 85%, target <300KB. Use `convert` command:
```
convert input.jpg -resize 1200x -quality 85 output.jpg
```
For OG/social sharing images, use 1200x630 crop:
```
convert input.jpg -resize 1200x630^ -gravity center -extent 1200x630 -quality 85 output.jpg
```
2. Copy optimized image to `client/public/uploads/`
3. Add article to `seedArticles` array in `server/seed.ts`
4. Add UPDATE migration at bottom of `seedDatabase()` function to update existing articles in production DB
5. If article already exists in DB, seed won't update it must add explicit UPDATE SQL migration
6. Featured articles appear in homepage carousel; set `featured: false` for items that should not appear there
7. Videos use category "Video", news uses category "News"
8. Bunny CDN embeds: use `https://player.mediadelivery.net/embed/476412/{video-id}` do NOT take text/title from Bunny, use user-provided text only
9. Facebook embeds: copy the iframe code as-is from user
10. After deploy, go to Facebook Sharing Debugger and click "Scrape Again" to refresh cache
## Article Page Layout
- Outer wrapper: `max-w-7xl` (for PageSideAds), inner content: `max-w-4xl mx-auto`
- Cover image: `max-h-[420px]` with object-cover
- Title: `text-2xl md:text-3xl` font-bold
- Meta (author/date/views): `text-xs` with `w-3.5 h-3.5` icons
- Body text: `prose-base` with `prose-p:text-[15px]` and `prose-headings:text-lg`
- In-article ad splits content at midpoint
## Important Notes
- Tailwind `object-[center_25%]` does NOT work must use inline `style={{ objectPosition: "center 25%" }}`
- Horoscope widget navigates to /horoskop on click (no modal)
- News widget external links open in new tab (target="_blank")
- FeaturedCarousel: page 1 = wide (5 cols, no side cards), last page = gallery
- All images use `objectPosition: "center 25%"` for better face cropping