diff --git a/app/(control)/admin/fleet/page.tsx b/app/(control)/admin/fleet/page.tsx index 288d750..2552953 100644 --- a/app/(control)/admin/fleet/page.tsx +++ b/app/(control)/admin/fleet/page.tsx @@ -139,9 +139,15 @@ export default async function AdminFleetPage() { ); } + // Scope the reads to the tenants we'll actually render (the registry), so orphaned/decommissioned + // rows don't get loaded as the fleet grows (Gemini review on #71). + const tenantSlugs = registry.tenants.map((t) => t.slug); const [devices, summaries] = await Promise.all([ - db.fleetDevice.findMany({ orderBy: [{ tenantSlug: "asc" }, { label: "asc" }] }), - db.fleetSummary.findMany(), + db.fleetDevice.findMany({ + where: { tenantSlug: { in: tenantSlugs } }, + orderBy: [{ tenantSlug: "asc" }, { label: "asc" }], + }), + db.fleetSummary.findMany({ where: { tenantSlug: { in: tenantSlugs } } }), ]); const devicesBySlug = new Map(); diff --git a/app/(control)/billing/thanks/page.tsx b/app/(control)/billing/thanks/page.tsx index b658b3c..58e0511 100644 --- a/app/(control)/billing/thanks/page.tsx +++ b/app/(control)/billing/thanks/page.tsx @@ -12,7 +12,7 @@ export default async function BillingThanksPage() { return (
- Sofra + SofraPiwas

{t("title")}

{t("body")}

diff --git a/app/(control)/forgot/page.tsx b/app/(control)/forgot/page.tsx index b7649e6..0303c5d 100644 --- a/app/(control)/forgot/page.tsx +++ b/app/(control)/forgot/page.tsx @@ -10,7 +10,7 @@ export default async function ForgotPage() { return (
- Sofra + SofraPiwas

{t("forgotTitle")}

{t("forgotIntro")}

diff --git a/app/(control)/invite/[token]/page.tsx b/app/(control)/invite/[token]/page.tsx index cff324b..bb3040a 100644 --- a/app/(control)/invite/[token]/page.tsx +++ b/app/(control)/invite/[token]/page.tsx @@ -17,7 +17,7 @@ export default async function InvitePage({ return (
- Sofra + SofraPiwas

{t("inviteTitle")}

{valid ? ( diff --git a/app/(control)/layout.tsx b/app/(control)/layout.tsx index 3217050..91f7b8a 100644 --- a/app/(control)/layout.tsx +++ b/app/(control)/layout.tsx @@ -11,9 +11,9 @@ import { controlLocale } from "@/lib/control-locale"; import { fontClassNames, themeInitScript } from "@/lib/fonts"; export const metadata: Metadata = { - title: "Sofra — Partner area", + title: "SofraPiwas — Partner area", robots: { index: false, follow: false }, - icons: { icon: "/favicon.svg" }, + icons: { icon: "/favicon.svg", apple: "/apple-touch-icon.png" }, }; export default async function ControlLayout({ children }: { children: React.ReactNode }) { diff --git a/app/(control)/login/page.tsx b/app/(control)/login/page.tsx index 8a48c46..2e91796 100644 --- a/app/(control)/login/page.tsx +++ b/app/(control)/login/page.tsx @@ -22,7 +22,7 @@ export default async function LoginPage({ return (
- Sofra + SofraPiwas

{t("loginTitle")}

diff --git a/app/(control)/reset/[token]/page.tsx b/app/(control)/reset/[token]/page.tsx index 360e5b8..f55f1ea 100644 --- a/app/(control)/reset/[token]/page.tsx +++ b/app/(control)/reset/[token]/page.tsx @@ -17,7 +17,7 @@ export default async function ResetPage({ return (

- Sofra + SofraPiwas

{t("resetTitle")}

{valid ? ( diff --git a/app/[locale]/case/rumi/page.tsx b/app/[locale]/case/rumi/page.tsx index 83d741f..7d9e87c 100644 --- a/app/[locale]/case/rumi/page.tsx +++ b/app/[locale]/case/rumi/page.tsx @@ -53,8 +53,8 @@ export default async function RumiCaseStudyPage({ dateModified: PUBLISHED, inLanguage: locale, mainEntityOfPage: `${SITE_URL}/${locale}/case/rumi`, - author: { "@type": "Organization", name: "Sofra", url: SITE_URL }, - publisher: { "@type": "Organization", name: "Sofra", url: SITE_URL }, + author: { "@type": "Organization", name: "SofraPiwas", url: SITE_URL }, + publisher: { "@type": "Organization", name: "SofraPiwas", url: SITE_URL }, about: { "@type": "Restaurant", name: "RUMI Restaurant", diff --git a/app/[locale]/compare/gloriafood/page.tsx b/app/[locale]/compare/gloriafood/page.tsx index ef30959..4303e4a 100644 --- a/app/[locale]/compare/gloriafood/page.tsx +++ b/app/[locale]/compare/gloriafood/page.tsx @@ -15,7 +15,7 @@ import { } from "@/components/compare-gloriafood-data"; import { SITE_URL, marketingPageMetadata } from "@/lib/seo"; -// Honest, dated Sofra-vs-GloriaFood comparison (AEO plan §2 priority 2). +// Honest, dated SofraPiwas-vs-GloriaFood comparison (AEO plan §2 priority 2). // Every GloriaFood claim is sourced (see compare-gloriafood-data.ts) — // re-verify the sources before editing any factual cell. diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 5ee1bf0..c2f9224 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -4,7 +4,7 @@ import { NextIntlClientProvider, hasLocale } from "next-intl"; import { setRequestLocale, getTranslations } from "next-intl/server"; import "../globals.css"; import { routing } from "@/i18n/routing"; -import { SITE_URL, pageAlternates } from "@/lib/seo"; +import { SITE_URL, pageAlternates, OG_IMAGE } from "@/lib/seo"; import { fontClassNames, themeInitScript } from "@/lib/fonts"; import ThemeSync from "@/components/ThemeSync"; @@ -24,14 +24,21 @@ export async function generateMetadata({ metadataBase: new URL(SITE_URL), title: t("title"), description: t("description"), - icons: { icon: "/favicon.svg" }, + icons: { icon: "/favicon.svg", apple: "/apple-touch-icon.png" }, alternates: pageAlternates(locale, ""), openGraph: { title: t("title"), description: t("description"), - siteName: "Sofra", + siteName: "SofraPiwas", locale, type: "website", + images: [OG_IMAGE], + }, + twitter: { + card: "summary_large_image", + title: t("title"), + description: t("description"), + images: [OG_IMAGE], }, robots: { index: true, follow: true }, }; diff --git a/app/api/partner/apply/route.ts b/app/api/partner/apply/route.ts index e037dae..aa26151 100644 --- a/app/api/partner/apply/route.ts +++ b/app/api/partner/apply/route.ts @@ -38,7 +38,7 @@ export async function POST(request: Request) { await sendEmail({ to, replyTo: data.email, - subject: `Sofra — Partner application: ${data.name}`, + subject: `SofraPiwas — Partner application: ${data.name}`, html: craftEmail({ kicker: "Partner program", title: "New partner application", diff --git a/app/api/signup/route.ts b/app/api/signup/route.ts index ae6d3a1..fd36a89 100644 --- a/app/api/signup/route.ts +++ b/app/api/signup/route.ts @@ -44,7 +44,7 @@ export async function POST(request: Request) { await sendEmail({ to, replyTo: data.email, - subject: `Sofra — New signup: ${data.restaurantName}`, + subject: `SofraPiwas — New signup: ${data.restaurantName}`, html: craftEmail({ kicker: "Signups", title: "New restaurant signup", diff --git a/app/api/waitlist/route.ts b/app/api/waitlist/route.ts index 3861be1..8621eab 100644 --- a/app/api/waitlist/route.ts +++ b/app/api/waitlist/route.ts @@ -54,7 +54,7 @@ export async function POST(request: Request) { const { sent } = await sendEmail({ to, replyTo: email, - subject: `Sofra — ${meta.subject}: ${restaurant}`, + subject: `SofraPiwas — ${meta.subject}: ${restaurant}`, html: craftEmail({ kicker: meta.kicker, title: meta.title, diff --git a/components/BrandMark.tsx b/components/BrandMark.tsx new file mode 100644 index 0000000..e4d2aac --- /dev/null +++ b/components/BrandMark.tsx @@ -0,0 +1,21 @@ +type BrandMarkProps = { className?: string }; + +/** + * The SofraPiwas onion mark (piwas). Decorative in the brand lockup — the + * adjacent "SofraPiwas" wordmark carries the accessible name — so it's + * `aria-hidden` with an empty alt. A static SVG served from /public; next/image + * would add no value (no optimization for inline vector) so a plain is used. + */ +export default function BrandMark({ className }: Readonly) { + return ( + // eslint-disable-next-line @next/next/no-img-element -- static SVG logo, no next/image optimization + + ); +} diff --git a/components/Footer.tsx b/components/Footer.tsx index 100c9f9..b8e23cf 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -10,7 +10,7 @@ export default function Footer() {