feat: add SEO fundamentals - canonical, OG, robots.txt, sitemap, JSON-LD
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

Add missing SEO elements to improve audit score from 89 to 95+:
- Canonical URL and dynamic meta description blocks in base.html
- Open Graph tags (og:title, og:description, og:image, og:url, og:locale)
- JSON-LD structured data (Organization + WebSite schemas)
- robots.txt route with proper Disallow rules
- sitemap.xml route with homepage and release-notes
- LocalBusiness JSON-LD schema on landing page for Local SEO
- Last-Modified header for freshness signals
- Preload critical image for LCP optimization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-02-21 16:23:04 +01:00
parent b0befd2973
commit 53f8d7ca1f
4 changed files with 135 additions and 2 deletions

6
app.py
View File

@ -740,6 +740,12 @@ def set_security_headers(response):
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
# Freshness signal for SEO crawlers
if response.content_type and 'text/html' in response.content_type and 'Last-Modified' not in response.headers:
from email.utils import formatdate
from time import time
response.headers['Last-Modified'] = formatdate(timeval=time(), localtime=False, usegmt=True)
# Content Security Policy
csp = (
"default-src 'self'; "

View File

@ -9,7 +9,7 @@ connections map, release notes, dashboard.
import logging
from datetime import datetime, timedelta, date
from flask import render_template, request, redirect, url_for, flash, session, current_app
from flask import render_template, request, redirect, url_for, flash, session, current_app, Response
from flask_login import login_required, current_user
from sqlalchemy import or_, func
@ -1510,3 +1510,41 @@ def release_notes():
db.close()
return render_template('release_notes.html', releases=releases, stats=stats)
@bp.route('/robots.txt')
def robots_txt():
"""Robots.txt for search engine crawlers."""
content = """User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Disallow: /chat
Disallow: /login
Disallow: /register
Disallow: /dashboard
Sitemap: https://nordabiznes.pl/sitemap.xml
"""
return Response(content, mimetype='text/plain')
@bp.route('/sitemap.xml')
def sitemap_xml():
"""Sitemap XML for search engines."""
today = date.today().isoformat()
xml = f"""<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://nordabiznes.pl/</loc>
<lastmod>{today}</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://nordabiznes.pl/release-notes</loc>
<lastmod>{today}</lastmod>
<changefreq>weekly</changefreq>
<priority>0.5</priority>
</url>
</urlset>"""
return Response(xml, mimetype='application/xml')

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Norda Biznes Partner - platforma networkingu Stowarzyszenia Norda Biznes">
<meta name="description" content="{% block meta_description %}Norda Biznes Partner - katalog firm członkowskich Izby Gospodarczej Norda Biznes z Wejherowa. Networking, współpraca biznesowa i rozwój na Kaszubach.{% endblock %}">
<meta name="author" content="Norda Biznes">
<meta name="robots" content="index, follow">
<meta name="page-view-id" content="{{ page_view_id|default('') }}">
@ -12,6 +12,9 @@
<title>{% block title %}Norda Biznes Partner{% endblock %}</title>
<!-- Canonical URL -->
<link rel="canonical" href="{% block canonical_url %}{{ request.url_root.rstrip('/') }}{{ request.path }}{% endblock %}">
<!-- Favicon - Gwiazda Nordy (kompas) -->
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='img/favicon.svg') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='img/favicon-32.png') }}">
@ -23,6 +26,9 @@
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}">
<meta name="theme-color" content="#233e6d">
<!-- Preload critical resources for LCP optimization -->
<link rel="preload" href="{{ url_for('static', filename='img/favicon-512.png') }}" as="image">
<!-- Fonts - Poppins (norda-biznes.info style) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@ -1269,6 +1275,45 @@
{% block extra_css %}{% endblock %}
</style>
<!-- Open Graph -->
<meta property="og:title" content="{% block og_title %}Norda Biznes Partner{% endblock %}">
<meta property="og:description" content="{% block og_description %}Katalog firm członkowskich Izby Gospodarczej Norda Biznes z Wejherowa. Networking i współpraca biznesowa na Kaszubach.{% endblock %}">
<meta property="og:image" content="{{ url_for('static', filename='img/favicon-512.png', _external=True) }}">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Norda Biznes Partner">
<meta property="og:locale" content="pl_PL">
<!-- JSON-LD Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Stowarzyszenie Norda Biznes",
"url": "https://nordabiznes.pl",
"logo": "{{ url_for('static', filename='img/favicon-512.png', _external=True) }}",
"address": {
"@type": "PostalAddress",
"streetAddress": "ul. Hallera 18",
"addressLocality": "Wejherowo",
"postalCode": "84-200",
"addressCountry": "PL"
},
"sameAs": [
"https://www.facebook.com/nordabiznes",
"https://norda-biznes.info"
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Norda Biznes Partner",
"url": "https://nordabiznes.pl"
}
</script>
{% block head_extra %}{% endblock %}
<!-- Analytics Tracker -->

View File

@ -2,6 +2,50 @@
{% block title %}Norda Biznes Partner - Strefa Partnera Stowarzyszenia Norda Biznes{% endblock %}
{% block meta_description %}Firmy członkowskie Izby Gospodarczej Norda Biznes z Wejherowa - katalog {{ total_companies }} firm z Kaszub. Networking, współpraca biznesowa, usługi i handel w regionie.{% endblock %}
{% block og_title %}Norda Biznes Partner - Katalog Firm Członkowskich{% endblock %}
{% block og_description %}{{ total_companies }} firm z Wejherowa i Kaszub w jednym miejscu. Izba Gospodarcza Norda Biznes - networking i współpraca biznesowa.{% endblock %}
{% block head_extra %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Stowarzyszenie Norda Biznes",
"description": "Izba Gospodarcza zrzeszająca firmy z Wejherowa i Kaszub. Networking, współpraca biznesowa i rozwój przedsiębiorczości.",
"url": "https://nordabiznes.pl",
"telephone": "+48 58 572 27 00",
"address": {
"@type": "PostalAddress",
"streetAddress": "ul. Hallera 18",
"addressLocality": "Wejherowo",
"postalCode": "84-200",
"addressRegion": "pomorskie",
"addressCountry": "PL"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 54.6059,
"longitude": 18.2356
},
"areaServed": {
"@type": "GeoCircle",
"geoMidpoint": {
"@type": "GeoCoordinates",
"latitude": 54.6059,
"longitude": 18.2356
},
"geoRadius": "50000"
},
"sameAs": [
"https://www.facebook.com/nordabiznes",
"https://norda-biznes.info"
]
}
</script>
{% endblock %}
{% block extra_css %}
<style>
/* Professional, visually rich design */