Lovable SEO run: Bakkerij Testdeeg Gent (fictional test site), 14 November 2026
1. Baseline on the published site (17:51 UTC)
$ curl -s -o /dev/null -w '%{http_code}\n' https://testdeeg-ghent-bakery-guide.lovable.app/robots.txt
200
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/robots.txt
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
User-agent: Twitterbot
Allow: /
User-agent: facebookexternalhit
Allow: /
User-agent: *
Allow: /
$ curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://testdeeg-ghent-bakery-guide.lovable.app/sitemap.xml
404 text/html; charset=utf-8
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/ | grep -aoE '<title>[^<]*</title>|<link rel="canonical"[^>]*>|<meta property="og:(url|image)"[^>]*>|<script type="application/ld\+json"' | sort -u
<meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/lovp_3567wc0ej48688dn01q34xq2y1/9ef38d3505d2f78cf2880196af525d4c_1794677350525.png">
<title>Bakkerij Testdeeg – Ambachtelijke bakker in Gent</title>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/over-ons | grep -aoE '<title>[^<]*</title>|<link rel="canonical"[^>]*>|<meta property="og:(url|image)"[^>]*>|<script type="application/ld\+json"' | sort -u
<meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/lovp_3567wc0ej48688dn01q34xq2y1/9ef38d3505d2f78cf2880196af525d4c_1794677350525.png">
<title>Over ons – Bakkerij Testdeeg Gent</title>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/contact | grep -aoE '<title>[^<]*</title>|<link rel="canonical"[^>]*>|<meta property="og:(url|image)"[^>]*>|<script type="application/ld\+json"' | sort -u
<meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/lovp_3567wc0ej48688dn01q34xq2y1/9ef38d3505d2f78cf2880196af525d4c_1794677350525.png">
<title>Contact – Bakkerij Testdeeg, Teststraat 1 Gent</title>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/ | grep -ao '<h1[^>]*>[^<]*</h1>'
<h1 class="text-4xl font-bold leading-tight md:text-5xl">Vers gebakken in het hart van Gent</h1>
2. One message to Lovable via the Lovable MCP server (send_message)
SEO fixes for the published site https://testdeeg-ghent-bakery-guide.lovable.app. Keep the design, layout and visible copy unchanged. Make only these five changes:
1. Add /sitemap.xml that lists the three routes (/, /over-ons, /contact) with absolute URLs on https://testdeeg-ghent-bakery-guide.lovable.app. It must be served as valid XML with an XML content type.
2. Add the line "Sitemap: https://testdeeg-ghent-bakery-guide.lovable.app/sitemap.xml" to public/robots.txt. Keep the existing rules.
3. Give every route a self-referencing canonical link and a matching og:url, with absolute URLs on the same host (home = https://testdeeg-ghent-bakery-guide.lovable.app/, other routes without a trailing slash).
4. Add JSON-LD of type Bakery on the home page only: name, url, address (Teststraat 1, 9000 Gent, BE) and openingHoursSpecification that matches the opening hours table on the home page exactly (closed on Monday). Do not add any fact that is not visible on the site, such as a phone number, rating or price range.
5. Do not touch og:image, the contact form or the routing.
When you are done, list the files you changed.
Final answer from Lovable (commit 7f6300a, 1.3 credits):
Implemented and verified; design, visible copy, og:image, contact form, and existing page paths remain unchanged—publish to update the live site.
**Files changed:**
- `public/robots.txt`
- `src/routes/index.tsx`
- `src/routes/over-ons.tsx`
- `src/routes/contact.tsx`
- `src/routes/__root.tsx`
- `src/routes/sitemap[.]xml.ts` (new)
- `src/lib/sitemap.ts` (new)
- `src/test/seo.test.ts` (new)
- `src/routeTree.gen.ts` (automatically regenerated)
- `AGENTS.md`
- `roadmap.md` (new)
3. What changed in the code (get_diff)
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -28,3 +28,5 @@
own key and store it in Secrets.
- **Secrets.** Lovable manages them. Do not put secret values in the repo.
<!-- LOVABLE:END -->
+
+- Derive sitemap entries from the router's required `staticData.sitemap` decisions so public page additions stay discoverable without maintaining a duplicate URL list; omit lastmod unless backed by a page-specific content timestamp.
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -12,3 +12,5 @@
User-agent: *
Allow: /
+
+Sitemap: https://testdeeg-ghent-bakery-guide.lovable.app/sitemap.xml
--- /dev/null
+++ b/roadmap.md
@@ -0,0 +1,3 @@
+- [x] Add the XML sitemap and preserve crawler rules.
+- [x] Add self-referencing canonical URLs and homepage Bakery data without visible changes.
+- [x] Verify requested SEO values and list changed files; live updates require publication.
--- /dev/null
+++ b/src/lib/sitemap.ts
@@ -0,0 +1,80 @@
+import type { AnyRoute, AnyRouter, ParsedLocation } from "@tanstack/react-router";
+
+declare module "@tanstack/react-router" {
+ interface StaticDataRouteOption {
+ sitemap: boolean | "exclude-subtree";
+ }
+}
+
+export const sitemapRouteInventoryVersion = 1;
+
+type RouteMatch =
+ | { routeParams: Record<string, unknown>; foundRoute?: AnyRoute; parseError?: unknown }
+ | [AnyRoute[], Record<string, unknown>, AnyRoute | undefined];
+
+export function isSitemapRouteIncluded(route: AnyRoute | undefined): boolean {
+ if (!route || route.isRoot || route.options.staticData?.sitemap !== true) return false;
+ for (let ancestor = route.parentRoute; ancestor; ancestor = ancestor.parentRoute) {
+ if (ancestor.options.staticData?.sitemap === "exclude-subtree") return false;
+ }
+ return true;
+}
+
+export function sitemapStaticPaths(router: AnyRouter): string[] {
+ const paths = new Set<string>();
+ for (const route of Object.values(router.routesById) as AnyRoute[]) {
+ if (!isSitemapRouteIncluded(route) || /[$*]/.test(route.fullPath)) continue;
+ const location = router.buildLocation({ to: route.fullPath });
+ const path = sitemapPathForLocation(router, location, route.id);
+ if (path !== undefined) paths.add(path);
+ }
+ return [...paths].sort();
+}
+
+export function sitemapPathForLocation(
+ router: AnyRouter,
+ location: Pick<ParsedLocation, "pathname" | "publicHref">,
+ routeId: string,
+): string | undefined {
+ if (!isSafeSitemapPath(location.pathname) || !isSafeSitemapPath(location.publicHref)) return undefined;
+ const result = router.getMatchedRoutes(location.pathname) as RouteMatch;
+ const [params, foundRoute] = Array.isArray(result)
+ ? [result[1], result[2]]
+ : [result.routeParams, result.parseError ? undefined : result.foundRoute];
+ return params["**"] === undefined && foundRoute?.id === routeId && isSitemapRouteIncluded(foundRoute)
+ ? location.publicHref
+ : undefined;
+}
+
+export interface SitemapEntry {
+ path: string;
+ lastmod?: string;
+}
+
+function isSafeSitemapPath(pathname: string): boolean {
+ if (!pathname.startsWith("/") || pathname.startsWith("//") || /[?#\\]/.test(pathname)) return false;
+ try {
+ return decodeURI(new URL(pathname, "https://sitemap.invalid").pathname) === decodeURI(pathname);
+ } catch {
+ return false;
+ }
+}
+
+export function sitemapXML(baseURL: string, entries: SitemapEntry[]): string {
+ const origin = new URL(baseURL);
+ if (!/^https?:$/.test(origin.protocol) || origin.username || origin.password || origin.pathname !== "/" || origin.search || origin.hash) {
+ throw new Error("The sitemap base URL must be the public site origin");
+ }
+ const entities: Record<string, string> = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
+ const escape = (value: string) => value.replace(/[&<>"']/g, (character) => entities[character] ?? character);
+ const seen = new Set<string>();
+ const urls: string[] = [];
+ for (const entry of entries) {
+ if (!isSafeSitemapPath(entry.path)) throw new Error("Invalid sitemap path");
+ const url = new URL(entry.path, origin);
+ if (seen.has(url.href)) continue;
+ seen.add(url.href);
+ urls.push(`<url><loc>${escape(url.href)}</loc>${entry.lastmod ? `<lastmod>${escape(entry.lastmod)}</lastmod>` : ""}</url>`);
+ }
+ return `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${urls.join("")}</urlset>`;
+}
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -12,6 +12,7 @@
import { Route as IndexRouteImport } from './routes/index'
import { Route as ContactRouteImport } from './routes/contact'
import { Route as OverOnsRouteImport } from './routes/over-ons'
+import { Route as SitemapDotxmlRouteImport } from './routes/sitemap[.]xml'
const IndexRoute = IndexRouteImport.update({
id: '/',
@@ -28,35 +29,44 @@
path: '/over-ons',
getParentRoute: () => rootRouteImport,
} as any)
+const SitemapDotxmlRoute = SitemapDotxmlRouteImport.update({
+ id: '/sitemap.xml',
+ path: '/sitemap.xml',
+ getParentRoute: () => rootRouteImport,
+} as any)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/contact': typeof ContactRoute
'/over-ons': typeof OverOnsRoute
+ '/sitemap.xml': typeof SitemapDotxmlRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/contact': typeof ContactRoute
'/over-ons': typeof OverOnsRoute
+ '/sitemap.xml': typeof SitemapDotxmlRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/contact': typeof ContactRoute
'/over-ons': typeof OverOnsRoute
+ '/sitemap.xml': typeof SitemapDotxmlRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/contact' | '/over-ons'
+ fullPaths: '/' | '/contact' | '/over-ons' | '/sitemap.xml'
fileRoutesByTo: FileRoutesByTo
- to: '/' | '/contact' | '/over-ons'
- id: '__root__' | '/' | '/contact' | '/over-ons'
+ to: '/' | '/contact' | '/over-ons' | '/sitemap.xml'
+ id: '__root__' | '/' | '/contact' | '/over-ons' | '/sitemap.xml'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
ContactRoute: typeof ContactRoute
OverOnsRoute: typeof OverOnsRoute
+ SitemapDotxmlRoute: typeof SitemapDotxmlRoute
}
declare module '@tanstack/react-router' {
@@ -82,6 +92,13 @@
preLoaderRoute: typeof OverOnsRouteImport
parentRoute: typeof rootRouteImport
}
+ '/sitemap.xml': {
+ id: '/sitemap.xml'
+ path: '/sitemap.xml'
+ fullPath: '/sitemap.xml'
+ preLoaderRoute: typeof SitemapDotxmlRouteImport
+ parentRoute: typeof rootRouteImport
+ }
}
}
@@ -89,6 +106,7 @@
IndexRoute: IndexRoute,
ContactRoute: ContactRoute,
OverOnsRoute: OverOnsRoute,
+ SitemapDotxmlRoute: SitemapDotxmlRoute,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
--- a/src/routes/__root.tsx
+++ b/src/routes/__root.tsx
@@ -75,6 +75,7 @@
}
export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
+ staticData: { sitemap: false },
head: () => ({
// Replace these placeholders with the app's name and description when first building the app.
// Each content route, / included, must still set its own head(). Never add og:image or
--- a/src/routes/contact.tsx
+++ b/src/routes/contact.tsx
@@ -2,13 +2,18 @@
import { useState, type FormEvent } from "react";
export const Route = createFileRoute("/contact")({
+ staticData: { sitemap: true },
head: () => ({
meta: [
{ title: "Contact – Bakkerij Testdeeg, Teststraat 1 Gent" },
{ name: "description", content: "Contacteer Bakkerij Testdeeg, Teststraat 1, 9000 Gent. Stuur ons een bericht via het formulier." },
{ property: "og:title", content: "Contact – Bakkerij Testdeeg" },
{ property: "og:description", content: "Teststraat 1, 9000 Gent. Stuur ons een bericht." },
+ { property: "og:url", content: "https://testdeeg-ghent-bakery-guide.lovable.app/contact" },
+ { property: "og:type", content: "website" },
+ { name: "twitter:card", content: "summary_large_image" },
],
+ links: [{ rel: "canonical", href: "https://testdeeg-ghent-bakery-guide.lovable.app/contact" }],
}),
component: Contact,
});
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -1,13 +1,40 @@
import { createFileRoute, Link } from "@tanstack/react-router";
export const Route = createFileRoute("/")({
+ staticData: { sitemap: true },
head: () => ({
meta: [
{ title: "Bakkerij Testdeeg – Ambachtelijke bakker in Gent" },
{ name: "description", content: "Vers brood, koffiekoeken en taarten bij Bakkerij Testdeeg in Gent. Bekijk ons aanbod en onze openingsuren." },
{ property: "og:title", content: "Bakkerij Testdeeg – Ambachtelijke bakker in Gent" },
{ property: "og:description", content: "Vers brood, koffiekoeken en taarten in Gent. Aanbod en openingsuren." },
+ { property: "og:url", content: "https://testdeeg-ghent-bakery-guide.lovable.app/" },
+ { property: "og:type", content: "website" },
+ { name: "twitter:card", content: "summary_large_image" },
],
+ links: [{ rel: "canonical", href: "https://testdeeg-ghent-bakery-guide.lovable.app/" }],
+ scripts: [{
+ type: "application/ld+json",
+ children: JSON.stringify({
+ "@context": "https://schema.org",
+ "@type": "Bakery",
+ name: "Bakkerij Testdeeg",
+ url: "https://testdeeg-ghent-bakery-guide.lovable.app/",
+ address: {
+ "@type": "PostalAddress",
+ streetAddress: "Teststraat 1",
+ postalCode: "9000",
+ addressLocality: "Gent",
+ addressCountry: "BE",
+ },
+ openingHoursSpecification: [
+ { "@type": "OpeningHoursSpecification", dayOfWeek: "Monday", opens: "00:00", closes: "00:00" },
+ { "@type": "OpeningHoursSpecification", dayOfWeek: ["Tuesday", "Wednesday", "Thursday", "Friday"], opens: "07:00", closes: "18:00" },
+ { "@type": "OpeningHoursSpecification", dayOfWeek: "Saturday", opens: "07:00", closes: "17:00" },
+ { "@type": "OpeningHoursSpecification", dayOfWeek: "Sunday", opens: "07:00", closes: "13:00" },
+ ],
+ }),
+ }],
}),
component: Index,
});
--- a/src/routes/over-ons.tsx
+++ b/src/routes/over-ons.tsx
@@ -1,13 +1,18 @@
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/over-ons")({
+ staticData: { sitemap: true },
head: () => ({
meta: [
{ title: "Over ons – Bakkerij Testdeeg Gent" },
{ name: "description", content: "Leer Bakkerij Testdeeg kennen: een familiebakkerij in Gent met passie voor ambachtelijk brood." },
{ property: "og:title", content: "Over ons – Bakkerij Testdeeg Gent" },
{ property: "og:description", content: "Een familiebakkerij in Gent met passie voor ambachtelijk brood." },
+ { property: "og:url", content: "https://testdeeg-ghent-bakery-guide.lovable.app/over-ons" },
+ { property: "og:type", content: "website" },
+ { name: "twitter:card", content: "summary_large_image" },
],
+ links: [{ rel: "canonical", href: "https://testdeeg-ghent-bakery-guide.lovable.app/over-ons" }],
}),
component: OverOns,
});
--- /dev/null
+++ b/src/routes/sitemap[.]xml.ts
@@ -0,0 +1,26 @@
+import { createFileRoute } from "@tanstack/react-router";
+import { getRouterInstance } from "@tanstack/react-start";
+import { sitemapStaticPaths, sitemapXML } from "@/lib/sitemap";
+
+const BASE_URL = "https://testdeeg-ghent-bakery-guide.lovable.app";
+
+export const Route = createFileRoute("/sitemap.xml")({
+ staticData: { sitemap: false },
+ server: {
+ handlers: {
+ GET: async () => {
+ const router = await getRouterInstance();
+ const entries = sitemapStaticPaths(router).map((path) => ({ path }));
+ if (entries.length === 0) {
+ return new Response("No pages are included in this sitemap.", {
+ status: 404,
+ headers: { "Cache-Control": "no-store" },
+ });
+ }
+ return new Response(sitemapXML(BASE_URL, entries), {
+ headers: { "Content-Type": "application/xml; charset=utf-8", "Cache-Control": "public, max-age=3600" },
+ });
+ },
+ },
+ },
+});
--- /dev/null
+++ b/src/test/seo.test.ts
@@ -0,0 +1,44 @@
+import { QueryClient } from "@tanstack/react-query";
+import { createRouter } from "@tanstack/react-router";
+import { describe, expect, it } from "vitest";
+import { routeTree } from "@/routeTree.gen";
+import { sitemapStaticPaths, sitemapXML } from "@/lib/sitemap";
+import { Route as HomeRoute } from "@/routes/index";
+
+const origin = "https://testdeeg-ghent-bakery-guide.lovable.app";
+
+function bakeryData() {
+ const head = HomeRoute.options.head?.({} as Parameters<NonNullable<typeof HomeRoute.options.head>>[0]);
+ if (!head || head instanceof Promise) throw new Error("Expected synchronous homepage metadata");
+ const script = head.scripts?.find((entry) => entry?.type === "application/ld+json");
+ if (typeof script?.children !== "string") throw new Error("Missing Bakery JSON-LD");
+ return JSON.parse(script.children);
+}
+
+describe("SEO rules", () => {
+ it("includes exactly the three public pages with absolute URLs and no generated lastmod", () => {
+ const router = createRouter({ routeTree, context: { queryClient: new QueryClient() } });
+ const paths = sitemapStaticPaths(router);
+ expect(paths).toEqual(["/", "/contact", "/over-ons"]);
+ const document = new DOMParser().parseFromString(sitemapXML(origin, paths.map((path) => ({ path }))), "application/xml");
+ expect(document.querySelector("parsererror")).toBeNull();
+ expect([...document.querySelectorAll("loc")].map((node) => node.textContent)).toEqual([`${origin}/`, `${origin}/contact`, `${origin}/over-ons`]);
+ expect(document.querySelector("lastmod")).toBeNull();
+ });
+
+ it("reports Monday as closed", () => {
+ expect(bakeryData().openingHoursSpecification[0]).toEqual({ "@type": "OpeningHoursSpecification", dayOfWeek: "Monday", opens: "00:00", closes: "00:00" });
+ });
+
+ it("reports Tuesday through Friday as 07:00–18:00", () => {
+ expect(bakeryData().openingHoursSpecification[1]).toEqual({ "@type": "OpeningHoursSpecification", dayOfWeek: ["Tuesday", "Wednesday", "Thursday", "Friday"], opens: "07:00", closes: "18:00" });
+ });
+
+ it("reports Saturday as 07:00–17:00", () => {
+ expect(bakeryData().openingHoursSpecification[2]).toEqual({ "@type": "OpeningHoursSpecification", dayOfWeek: "Saturday", opens: "07:00", closes: "17:00" });
+ });
+
+ it("reports Sunday as 07:00–13:00", () => {
+ expect(bakeryData().openingHoursSpecification[3]).toEqual({ "@type": "OpeningHoursSpecification", dayOfWeek: "Sunday", opens: "07:00", closes: "13:00" });
+ });
+});
4. Published again (deploy_project), live check at 17:55 UTC
$ curl -s -o /dev/null -w '%{http_code}\n' https://testdeeg-ghent-bakery-guide.lovable.app/robots.txt
200
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/robots.txt
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
User-agent: Twitterbot
Allow: /
User-agent: facebookexternalhit
Allow: /
User-agent: *
Allow: /
Sitemap: https://testdeeg-ghent-bakery-guide.lovable.app/sitemap.xml
$ curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://testdeeg-ghent-bakery-guide.lovable.app/sitemap.xml
200 application/xml; charset=utf-8
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/ | grep -aoE '<title>[^<]*</title>|<link rel="canonical"[^>]*>|<meta property="og:(url|image)"[^>]*>|<script type="application/ld\+json"' | sort -u
<link rel="canonical" href="https://testdeeg-ghent-bakery-guide.lovable.app/"/>
<meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/lovp_3567wc0ej48688dn01q34xq2y1/34cded5e0e62b1ce0d5d8d1a60d08a06_1794678850715.png">
<meta property="og:url" content="https://testdeeg-ghent-bakery-guide.lovable.app/"/>
<script type="application/ld+json"
<title>Bakkerij Testdeeg – Ambachtelijke bakker in Gent</title>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/over-ons | grep -aoE '<title>[^<]*</title>|<link rel="canonical"[^>]*>|<meta property="og:(url|image)"[^>]*>|<script type="application/ld\+json"' | sort -u
<link rel="canonical" href="https://testdeeg-ghent-bakery-guide.lovable.app/over-ons"/>
<meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/lovp_3567wc0ej48688dn01q34xq2y1/34cded5e0e62b1ce0d5d8d1a60d08a06_1794678850715.png">
<meta property="og:url" content="https://testdeeg-ghent-bakery-guide.lovable.app/over-ons"/>
<title>Over ons – Bakkerij Testdeeg Gent</title>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/contact | grep -aoE '<title>[^<]*</title>|<link rel="canonical"[^>]*>|<meta property="og:(url|image)"[^>]*>|<script type="application/ld\+json"' | sort -u
<link rel="canonical" href="https://testdeeg-ghent-bakery-guide.lovable.app/contact"/>
<meta property="og:image" content="https://pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev/lovp_3567wc0ej48688dn01q34xq2y1/34cded5e0e62b1ce0d5d8d1a60d08a06_1794678850715.png">
<meta property="og:url" content="https://testdeeg-ghent-bakery-guide.lovable.app/contact"/>
<title>Contact – Bakkerij Testdeeg, Teststraat 1 Gent</title>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/ | grep -ao '<h1[^>]*>[^<]*</h1>'
<h1 class="text-4xl font-bold leading-tight md:text-5xl">Vers gebakken in het hart van Gent</h1>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/sitemap.xml; echo
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>https://testdeeg-ghent-bakery-guide.lovable.app/</loc></url><url><loc>https://testdeeg-ghent-bakery-guide.lovable.app/contact</loc></url><url><loc>https://testdeeg-ghent-bakery-guide.lovable.app/over-ons</loc></url></urlset>
$ curl -s https://testdeeg-ghent-bakery-guide.lovable.app/ | grep -ao '<script type="application/ld+json">[^<]*</script>'
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Bakery","name":"Bakkerij Testdeeg","url":"https://testdeeg-ghent-bakery-guide.lovable.app/","address":{"@type":"PostalAddress","streetAddress":"Teststraat 1","postalCode":"9000","addressLocality":"Gent","addressCountry":"BE"},"openingHoursSpecification":[{"@type":"OpeningHoursSpecification","dayOfWeek":"Monday","opens":"00:00","closes":"00:00"},{"@type":"OpeningHoursSpecification","dayOfWeek":["Tuesday","Wednesday","Thursday","Friday"],"opens":"07:00","closes":"18:00"},{"@type":"OpeningHoursSpecification","dayOfWeek":"Saturday","opens":"07:00","closes":"17:00"},{"@type":"OpeningHoursSpecification","dayOfWeek":"Sunday","opens":"07:00","closes":"13:00"}]}</script>