# felhom.eu

Website, manifests, and infrastructure for **Felhőm.eu** — a managed home-server service for Hungarian households.

## Overview

This repository contains:
- **Website** (`website/`) — Static HTML pages served at [felhom.eu](https://felhom.eu)
- **Kubernetes manifests** (`manifests/`) — All k3s deployments for the felhom.eu ecosystem
- **Assets** (`website/assets/`) — Logo, images, OG images

The website runs on a single-node k3s cluster alongside the rest of the Felhőm management infrastructure (Healthchecks, Umami analytics, contact mailer).

## Branding

| Aspect | Value |
|--------|-------|
| **Brand name** | Felhőm.eu (with accent: ő) |
| **Domain** | felhom.eu (without accent — domain limitation) |
| **Tagline** | „Saját felhőd, saját szabályaid" |
| **Controller product** | Felhő Felügyelő (customer-facing name) |
| **Controller code name** | felhom-controller (backend/repo/container) |
| **Language** | Hungarian throughout all customer-facing content |
| **Contact email** | info@felhom.eu |
| **Admin email** | admin@felhom.eu |

### Why "Felhőm"?
"Felhő" means "cloud" in Hungarian. The "m" suffix makes it possessive — "my cloud" (felhőm). The `.eu` domain is part of the brand identity and appears in the logo. The double meaning of "felhő" (tech cloud + weather cloud) is intentional and used in product naming (e.g., Felhő Felügyelő = "Cloud Supervisor/Inspector").

## Website Pages

| File | URL | Purpose |
|------|-----|---------|
| `index.html` | `/` | Landing page — hero, services, app preview, backup intro, contact |
| `alkalmazasok.html` | `/alkalmazasok` | Full application catalog (45+ apps with categories) |
| `technologiak.html` | `/technologiak` | Technology stack explanation (Docker, Felhő Felügyelő, Proxmox, Kubernetes) |
| `biztonsagimentes.html` | `/biztonsagimentes` | Backup strategy — 3-2-1 rule, monitoring, restore procedures |
| `gyik.html` | `/gyik` | FAQ — structured Q&A with JSON-LD schema |
| `kapcsolat.html` | `/kapcsolat` | Contact form + email, sends via contact-mailer API |
| `szolgaltatasok-nonpublic.html` | `/szolgaltatasok-nonpublic` | Pricing/services page (not linked in nav, robots disallowed) |

All pages use:
- **Clean URLs** — nginx serves `.html` files without extension (`/gyik` → `gyik.html`)
- **Unified CSS** — each page contains the full CSS (no external stylesheet, for simplicity)
- **Responsive design** — mobile hamburger menu, responsive grids
- **UTF-8 with BOM** — all HTML files are saved as UTF-8-BOM for Hungarian character support
- **Umami analytics** — privacy-friendly tracking script on every page

## Infrastructure

### Architecture

```
Internet
    │
    ▼
Cloudflare (DNS only, no proxy)
    │
    ▼ CNAME → dooplex.hopto.org
    │
Home network (dynamic IP via No-IP DynDNS)
    │
    ▼ Port forward 80/443
    │
k3s cluster (single node)
    ├── nginx-ingress (TLS termination via cert-manager + Let's Encrypt)
    │
    ├── felhom-system namespace:
    │   ├── felhom-webpage    (nginx + git-sync sidecar)
    │   ├── filebrowser       (files.felhom.eu — website file management)
    │   ├── contact-mailer    (Go app — /api/contact endpoint)
    │   ├── umami + umami-db  (stats.felhom.eu — web analytics)
    │   └── healthchecks      (status.felhom.eu — monitoring)
    │
    └── cert-manager (letsencrypt-prod cluster issuer)
```

### Kubernetes Manifests

| Manifest | Services | Subdomains |
|----------|----------|------------|
| `webpage.yaml` | nginx (website), FileBrowser, git-sync | felhom.eu, www.felhom.eu, files.felhom.eu |
| `contact-mailer.yaml` | Go HTTP server for contact form | felhom.eu/api/* (path-based routing) |
| `umami.yaml` | Umami v3 + PostgreSQL | stats.felhom.eu |
| `healthchecks.yaml` | Healthchecks | status.felhom.eu |

### Website Deployment

The website uses a **git-sync sidecar** pattern:

1. `git-sync` container polls this repository (sparse checkout: `/website/` only)
2. Syncs to a shared `emptyDir` volume
3. `nginx` container serves from the synced content
4. Changes pushed to this repo are live within minutes (no manual deployment)

**FileBrowser** at `files.felhom.eu` provides a web UI for quick edits to website files (emergency fixes, asset uploads) without needing git. It writes to a Longhorn PVC that the website nginx also reads from.

### Storage

All persistent data uses **Longhorn** distributed storage:
- `filebrowser-files` (1Gi, ReadWriteMany) — website files
- `filebrowser-db` (100Mi) — FileBrowser SQLite database
- `umami-db-data` (2Gi) — Umami PostgreSQL data
- `healthchecks-data` (1Gi) — Healthchecks SQLite data

## DNS Configuration (Cloudflare)

Domain: `felhom.eu` — Cloudflare DNS (free plan), **DNS only mode** (no proxy/orange cloud).

### Records

| Type | Name | Content | Notes |
|------|------|---------|-------|
| CNAME | `felhom.eu` | dooplex.hopto.org | Main website |
| CNAME | `www` | dooplex.hopto.org | www redirect |
| CNAME | `files` | dooplex.hopto.org | FileBrowser |
| CNAME | `stats` | dooplex.hopto.org | Umami analytics |
| CNAME | `status` | dooplex.hopto.org | Healthchecks |
| CNAME | `ntfy` | dooplex.hopto.org | Push notifications |
| MX | `felhom.eu` | route{1,2,3}.mx.cloudflare.net | Incoming email → Cloudflare Email Routing |
| MX | `send` | feedback-smtp.eu-west-1.amazonses.com | Resend sending domain |
| TXT | `felhom.eu` | `v=spf1 include:_spf.mx.clo...` | SPF for Cloudflare |
| TXT | `send` | `v=spf1 include:amazonses...` | SPF for Resend |
| TXT | `cf2024-1._domainkey` | DKIM for Cloudflare Email Routing | |
| TXT | `resend._domainkey` | DKIM for Resend | |
| TXT | `_dmarc` | `v=DMARC1; p=none;` | DMARC policy |
| TXT | `felhom.eu` | `google-site-verification=...` | Google Search Console |

## Email

### Incoming Email

**Cloudflare Email Routing** (free) handles all incoming mail:
- `info@felhom.eu` → forwarded to personal Gmail
- `admin@felhom.eu` → forwarded to personal Gmail
- Catch-all → not configured

### Outgoing Email (Transactional)

**Resend** (free tier) handles outgoing email via API:
- Contact form submissions → sends formatted email to `info@felhom.eu`
- Healthchecks alerts → sends to `admin@felhom.eu`
- Sending domain: `send.felhom.eu` (verified with SPF, DKIM)
- From address: `Felhom.eu <info@felhom.eu>`

### Contact Form Flow

1. User fills form on `/kapcsolat`
2. JavaScript POST to `/api/contact`
3. `contact-mailer` (Go, in k3s) validates + calls Resend API
4. Email delivered to `info@felhom.eu` via Resend → Cloudflare Email Routing → Gmail

## SEO

### Google Search Console

- Property: `https://felhom.eu`
- Verified via DNS TXT record
- Sitemap submitted: `https://felhom.eu/sitemap.xml`
- 7 pages indexed (all public pages)

### On-Page SEO

Every page includes:
- `<title>` with Hungarian keywords + brand
- `<meta name="description">` with unique content per page
- `<meta name="keywords">` with relevant Hungarian terms
- `<link rel="canonical">` to prevent duplicate content
- **Open Graph** tags (og:title, og:description, og:image, og:locale=hu_HU)
- **Twitter Card** tags (summary_large_image)
- **JSON-LD** structured data (LocalBusiness on index, Article on technologiak, FAQPage on gyik)

### Technical SEO

- `robots.txt` — allows all, disallows `/szolgaltatasok-nonpublic`, includes sitemap URL
- `sitemap.xml` — lists all 6 public pages with priority + changefreq
- Clean URLs (no `.html` extensions)
- Static asset caching (7 day expiry for CSS/JS/images)
- Security headers (X-Frame-Options, X-Content-Type-Options)

## Analytics

**Umami v3** (self-hosted, privacy-focused):
- Dashboard: `https://stats.felhom.eu`
- Tracking script: `<script defer src="https://stats.felhom.eu/script.js" data-website-id="d419db57-...">`
- Cookie-free, GDPR compliant — no consent banner needed
- Backend: dedicated PostgreSQL instance in k3s

## Monitoring

**Healthchecks** (self-hosted):
- Dashboard: `https://status.felhom.eu`
- Monitors backup jobs, service health
- Sends email alerts via Resend when checks fail

## Development Workflow

### Quick content edits
1. Log into FileBrowser at `https://files.felhom.eu`
2. Edit HTML files directly
3. Changes are live immediately

### Standard workflow
1. Clone this repo from Gitea (`gitea.dooplex.hu`)
2. Edit files locally
3. Push to `main` branch
4. `git-sync` sidecar picks up changes automatically (~1-2 min)

### Adding a new page
1. Create `website/newpage.html` (copy structure from existing page)
2. Add to navigation in all pages' `<nav>` section
3. Add to `sitemap.xml` with appropriate priority
4. Push — clean URLs handle `/newpage` automatically

## Related Repositories

| Repository | Purpose |
|------------|---------|
| [app-catalog-felhom.eu](https://gitea.dooplex.hu/admin/app-catalog-felhom.eu) | Docker Compose templates + .felhom.yml metadata for 45+ apps |
| [felhom-controller](https://gitea.dooplex.hu/admin/felhom-controller) | felhom-controller Go app + customer deploy scripts |
| [deploy-portainer](https://gitea.dooplex.hu/admin/deploy-portainer) | Legacy — Portainer-based deploy scripts (deprecated) |
| [homelab-manifests](https://gitea.dooplex.hu/admin/homelab-manifests) | k3s cluster manifests for dooplex.hu services |
| [misc-scripts](https://gitea.dooplex.hu/admin/misc-scripts) | Utility scripts (collect-repos.sh, etc.) |

## File Encoding

All HTML files in `website/` are **UTF-8 with BOM** (byte order mark). This ensures proper Hungarian character rendering (á, é, í, ó, ö, ő, ú, ü, ű) across all tools and platforms. The BOM is the 3-byte sequence `EF BB BF` at the start of each file.

When editing files, ensure your editor preserves UTF-8-BOM encoding. VS Code: check "UTF-8 with BOM" in the bottom status bar.