# SEO & Technical Audit — ria-aquaclubetavira.pt

**Date:** April 28, 2026
**Auditor:** Hermes Agent (paperclip-dev)
**Domain:** ria-aquaclubetavira.pt (→ www.ria-aquaclubetavira.pt)
**Overall Score:** 3.8 / 10

---

## Executive Summary

RIA Aqua Clube Tavira's website is a **single-page application (SPA)** built with Vite, featuring a dark modern design and solid content about swimming programs in Tavira. However, the SPA architecture is **completely opaque to search engines** — no robots.txt, no sitemap, no per-page metadata, no structured data, and broken legal links. The site looks good to human visitors but is essentially invisible to Google.

---

## Stack & Infrastructure

| Component | Details |
|-----------|---------|
| Framework | SPA (Vite-bundled, `index-DHFtw1sm.js`) |
| Routing | Client-side (buttons, not `<a>` tags) |
| Service Worker | ✅ Present (offline caching) |
| Languages | PT + EN (client-side switch, no URL change) |
| Email | ria.aquaclubetavira@gmail.com (Gmail, not domain) |
| Phone | +351 910 406 339 |
| Partners | Câmara Municipal de Tavira, Analgarve |
| TTFB | 4ms (excellent) |
| DOM Complete | 357ms (excellent) |

---

## Pages Crawled

| Page | Route | H1 |
|------|-------|-----|
| Homepage | `/` | Natação para todas as idades, em Tavira |
| Turmas (Programs) | `/turmas` | Os Nossos Programas |
| Sobre Nós | `/about` | Sobre o RIA Aqua Clube Tavira |
| Competição | `/competicao` | Competição |
| Galeria | `/galeria` | Galeria |
| FAQ | `/faq` | Perguntas Frequentes |
| Contactos | modal dialog | — |

---

## Strengths ✅

1. **Excellent performance** — 4ms TTFB, 357ms DOM complete. The site loads instantly.

2. **Service worker** — Offline caching is implemented, good for returning visitors.

3. **Dark modern design** — Professional visual quality with teal accents on dark background. Consistent brand identity.

4. **Clear pricing structure** — Programs organized by age group with transparent pricing (€13–45/mo). Easy to compare options.

5. **Single `<h1>` per page** — Correct heading hierarchy maintained across all pages.

6. **Good image alt text** — 0 missing or empty alt attributes on content images.

7. **PT/EN translation exists** — Full English translation available for all content.

8. **Portuguese legal footer** — Includes links for Política de Privacidade, Termos e Condições, RAL, and Livro de Reclamações.

9. **Rich content** — 8 FAQ items, meet calendar, club records, institutional documents, coach profiles.

10. **Mobile-friendly** — Responsive layout with proper viewport meta tag.

---

## Critical Issues ❌

### 1. No robots.txt — Search Engines Can't Crawl
**Severity:** 🔴 Critical

Navigating to `/robots.txt` returns the SPA shell (the homepage). There is no server-side file. Search engines have no crawl directives, no sitemap reference, and no way to know which paths to index or ignore.

**Fix:** Configure the web server (Nginx/Apache/Caddy) to serve a static `robots.txt` file:
```
User-agent: *
Allow: /
Sitemap: https://www.ria-aquaclubetavira.pt/sitemap.xml
```

---

### 2. No sitemap.xml — Pages Can't Be Discovered
**Severity:** 🔴 Critical

The footer has a "Sitemap" link pointing to `/sitemap.xml`, but it returns the SPA shell. Google has no way to discover or prioritize pages for crawling.

**Fix:** Generate a static `sitemap.xml` with all routes:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url><loc>https://www.ria-aquaclubetavira.pt/</loc><priority>1.0</priority></url>
  <url><loc>https://www.ria-aquaclubetavira.pt/turmas</loc><priority>0.9</priority></url>
  <url><loc>https://www.ria-aquaclubetavira.pt/about</loc><priority>0.8</priority></url>
  <url><loc>https://www.ria-aquaclubetavira.pt/competicao</loc><priority>0.8</priority></url>
  <url><loc>https://www.ria-aquaclubetavira.pt/galeria</loc><priority>0.7</priority></url>
  <url><loc>https://www.ria-aquaclubetavira.pt/faq</loc><priority>0.7</priority></url>
</urlset>
```

---

### 3. Same `<title>` on Every Page
**Severity:** 🔴 Critical

Every single page has the identical title: `"Swim Club Manager | RIA Aqua Clube Tavira"`. This also **leaks the software platform name** ("Swim Club Manager") which shouldn't be visible to end users.

| Page | Current Title | Recommended Title |
|------|---------------|-------------------|
| Homepage | Swim Club Manager \| RIA Aqua Clube Tavira | RIA Aqua Clube Tavira — Natação em Tavira |
| Turmas | Swim Club Manager \| RIA Aqua Clube Tavira | Programas e Preços — RIA Aqua Clube Tavira |
| About | Swim Club Manager \| RIA Aqua Clube Tavira | Sobre Nós — RIA Aqua Clube Tavira |
| Competição | Swim Club Manager \| RIA Aqua Clube Tavira | Competição — RIA Aqua Clube Tavira |
| Galeria | Swim Club Manager \| RIA Aqua Clube Tavira | Galeria — RIA Aqua Clube Tavira |
| FAQ | Swim Club Manager \| RIA Aqua Clube Tavira | Perguntas Frequentes — RIA Aqua Clube Tavira |

---

### 4. Same `<meta description>` on Every Page
**Severity:** 🔴 Critical

All pages: `"RIA Aqua Clube Tavira Management System"`. This is a generic system description, not a user-facing marketing description. Google will likely ignore it and generate its own snippet.

**Fix:** Write unique, compelling descriptions per page (120–160 chars).

---

### 5. Broken Legal Links — Privacy Policy, Terms, RAL
**Severity:** 🔴 Critical (Legal Compliance)

Three footer links are **broken** — they point to `#` (same-page anchor with no target):

| Link | Expected | Actual |
|------|----------|--------|
| Política de Privacidade | `/privacy` or `/privacidade` | `href="#"` ❌ |
| Termos e Condições | `/terms` or `/termos` | `href="#"` ❌ |
| RAL | `/ral` or external dispute resolution link | `href="#"` ❌ |

This is a **legal liability** under Portuguese and EU law. A privacy policy is mandatory under GDPR. The Complaints Book link (livroreclamacoes.pt) works correctly.

**Fix:** Create dedicated pages for Privacy Policy and Terms & Conditions. Link RAL to the appropriate Portuguese dispute resolution platform.

---

### 6. No Cookie Consent Banner — GDPR Violation
**Severity:** 🔴 Critical

The site uses a service worker (which may set cookies/localStorage) but has **no cookie consent mechanism**. Under GDPR and the ePrivacy Directive, non-essential cookies require explicit user consent before being set.

**Fix:** Implement a cookie consent banner that blocks non-essential cookies until consent is given.

---

### 7. No OG Tags — Social Shares Are Broken
**Severity:** 🔴 Critical

Zero Open Graph tags on any page. When someone shares `ria-aquaclubetavira.pt` on Facebook, WhatsApp, Instagram, or LinkedIn, the preview will show:
- No image
- Generic or missing title
- Generic or missing description

**Fix:** Add OG tags to every page:
```html
<meta property="og:title" content="RIA Aqua Clube Tavira — Natação em Tavira">
<meta property="og:description" content="Natação para todas as idades em Tavira. Escola de natação, hidroginástica, competição e natação para adultos.">
<meta property="og:image" content="https://www.ria-aquaclubetavira.pt/og-home.jpg">
<meta property="og:type" content="website">
<meta property="og:url" content="https://www.ria-aquaclubetavira.pt/">
```

---

### 8. No Structured Data (JSON-LD) — Zero Rich Snippets
**Severity:** 🔴 Critical

Not a single page has structured data. This means:
- No rich snippets in Google search results
- No knowledge panel for the club
- No FAQ rich results (despite having 8 FAQ items!)
- No local business listing
- No sports organization schema

**Recommended schemas:**

| Page | Schema Type |
|------|-------------|
| Homepage | `LocalBusiness` + `SportsActivityCenter` |
| FAQ | `FAQPage` with all 8 Q&A pairs |
| Turmas | `Product` or `Service` with pricing |
| About | `Organization` with member entities |
| Competição | `SportsEvent` for upcoming meets |

---

### 9. EN Version Invisible to Search Engines
**Severity:** 🔴 Critical

The PT/EN toggle switches content client-side but **doesn't change the URL**. Search engines can only see the default PT version. The English content is completely invisible to Google.

**Fix:** Implement URL-based language routing:
- `https://www.ria-aquaclubetavira.pt/` (PT)
- `https://www.ria-aquaclubetavira.pt/en/` (EN)

Add `hreflang` tags:
```html
<link rel="alternate" hreflang="pt" href="https://www.ria-aquaclubetavira.pt/">
<link rel="alternate" hreflang="en" href="https://www.ria-aquaclubetavira.pt/en/">
<link rel="alternate" hreflang="x-default" href="https://www.ria-aquaclubetavira.pt/">
```

---

### 10. Contact Form Uses `method="get"`
**Severity:** 🟠 High

The contact form modal sends data via GET, exposing form data (name, email, message) in the URL query string. This is visible in browser history, server logs, and referrer headers.

**Fix:** Change to `method="post"`.

---

## Moderate Issues 🟡

### 11. Gallery Page Has No Actual Photos
The gallery page (`/galeria`) shows two album placeholders ("Training 2024/2025" and "Algarve Regional Championship 2025") but **zero actual photographs** — just camera icons. For a swimming club, visual content is essential for attracting new members.

### 12. No Canonical URLs
No `<link rel="canonical">` on any page. The SPA can potentially serve the same content at multiple URLs (with/without trailing slash, with/without www).

### 13. No Twitter Card Tags
No `<meta name="twitter:card">` or related tags. Twitter/X shares will use OG fallbacks (which also don't exist).

### 14. Render-Blocking Scripts
2 render-blocking scripts on every page (main bundle + service worker registration). Should use `defer` or `async`.

### 15. No Lazy Loading on Images
`loading="lazy"` is not used on any image. For pages with multiple images (About page has 12), this delays initial render.

### 16. SPA Routing Issues
Direct URL navigation (e.g., typing `ria-aquaclubetavira.pt/turmas` in the browser) sometimes serves the homepage content first, then client-side JS re-renders the correct page. This creates a flash of wrong content and may confuse search engine crawlers.

### 17. No `<html lang>` Dynamic Update
When switching to EN, the `lang` attribute updates to `"en"` (good), but since this is client-side only, search engines always see `lang="pt"`.

### 18. Professional Email Address
The contact email is `ria.aquaclubetavira@gmail.com` — a Gmail address. For credibility, use a domain email like `info@ria-aquaclubetavira.pt` or `geral@ria-aquaclubetavira.pt`.

---

## Minor Issues

19. **No skip link** for screen reader accessibility
20. **No `<meta name="robots">`** tag (defaults to index,follow, but explicit is better)
21. **"Ver Horários e Preços"** button text is not translated in the EN pricing cards — shows Portuguese in English context
22. **No favicon references** in `<head>` (may work via manifest, but explicit `<link rel="icon">` is best practice)

---

## Score Summary

| Category | Score | Notes |
|----------|-------|-------|
| On-Page SEO | 2/10 | Same title/description everywhere, no canonical, no OG |
| Technical SEO | 1/10 | No robots.txt, no sitemap, SPA invisible to crawlers |
| Structured Data | 1/10 | Zero JSON-LD on any page |
| Performance | 9/10 | 4ms TTFB, service worker, fast DOM |
| Accessibility | 5/10 | Good alt text, but no skip link, no lazy loading |
| GDPR/Legal | 2/10 | No cookie consent, broken privacy/terms links |
| Content | 7/10 | Good pricing, FAQ, team info — but empty gallery |
| Social/OG | 1/10 | Zero OG or Twitter Card tags |
| **Overall** | **3.8/10** | |

---

## Top 10 Fixes (Prioritized by Impact)

| Priority | Fix | Impact | Effort |
|----------|-----|--------|--------|
| 1 | Add robots.txt + sitemap.xml | Enables crawling | Low |
| 2 | Add unique `<title>` + `<meta description>` per page | SEO foundation | Low |
| 3 | Add OG tags to all pages | Social sharing | Low |
| 4 | Create Privacy Policy + Terms pages (fix broken links) | Legal compliance | Medium |
| 5 | Add cookie consent banner | GDPR compliance | Medium |
| 6 | Add FAQPage schema to FAQ page | Rich snippets | Low |
| 7 | Add LocalBusiness + SportsActivityCenter schema | Knowledge panel | Low |
| 8 | Implement URL-based EN routing + hreflang | English SEO | High |
| 9 | Fix contact form to use POST | Security | Low |
| 10 | Populate gallery with actual photos | User engagement | Medium |

---

## Detailed SEO Data Per Page

### Homepage (`/`)
```
Title: Swim Club Manager | RIA Aqua Clube Tavira
Description: RIA Aqua Clube Tavira Management System
Canonical: MISSING
OG Tags: ALL MISSING
Hreflang: NONE
Structured Data: NONE
H1: "Natação para todas as idades, em Tavira" (1×)
Images: 3 total, 0 missing alt, 1 empty alt
Render-blocking scripts: 2
```

### Turmas (`/turmas`)
```
Title: Swim Club Manager | RIA Aqua Clube Tavira
Description: RIA Aqua Clube Tavira Management System
Canonical: MISSING
Structured Data: NONE (pricing data not marked up)
H1: "Os Nossos Programas" (1×)
Images: 1 total
Pricing: 4 programs (Escola de Natação, Hidroginástica, Competição, Adultos)
```

### Sobre Nós (`/about`)
```
Title: Swim Club Manager | RIA Aqua Clube Tavira
Description: RIA Aqua Clube Tavira Management System
H1: "Sobre o RIA Aqua Clube Tavira" (1×)
Images: 12 total, 0 missing alt
Content: Coach profiles, governing bodies, institutional documents
```

### Competição (`/competicao`)
```
Title: Swim Club Manager | RIA Aqua Clube Tavira
Description: RIA Aqua Clube Tavira Management System
H1: "Competição" (1×)
Content: Meet calendar, results, club records
Upcoming meets: Regional Club Championship (Faro, Mar 2026), Tavira Swimming Open (Apr 2026)
```

### Galeria (`/galeria`)
```
Title: Swim Club Manager | RIA Aqua Clube Tavira
Description: RIA Aqua Clube Tavira Management System
H1: "Galeria" (1×)
Images: 0 actual photos (2 empty album placeholders)
```

### FAQ (`/faq`)
```
Title: Swim Club Manager | RIA Aqua Clube Tavira
Description: RIA Aqua Clube Tavira Management System
H1: "Perguntas Frequentes" (1×)
Structured Data: NONE (should have FAQPage)
FAQ items: 8 (enrollment, documents, progression, schedules, payment, trial, absence, coach contact)
```

---

## Tech Stack Details

- **Bundler**: Vite (hashed filenames: `index-DHFtw1sm.js`)
- **Service Worker**: `registerSW.js` — offline caching enabled
- **Framework**: Undetectable (no React/Vue/Svelte/Astro/Nuxt markers in DOM)
- **No analytics detected**: No Google Analytics, Matomo, or other tracking
- **No CDN detected**: Direct domain serving
- **External links**: cm-tavira.pt, analgarve.pt, livroreclamacoes.pt, Facebook, Instagram, WhatsApp

---

*Generated by Hermes Agent — Galhardo internal tooling*
