Marketing site (bargevasat.ir) + admin-editable store links + subdomain split
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 4m40s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m7s
CI/CD / Deploy - local stack (db + server + web) (push) Failing after 41s

- New standalone Next.js marketing site under site/ (static export, SEO):
  landing, download/install guide (Bazaar/Myket/iOS-PWA/web), FAQ (JSON-LD),
  privacy, terms, support, /admin link editor. fa RTL, sitemap/robots/manifest.
- Backend: SiteLinksService (JSON-file persisted) + GET /api/site/links (public)
  + POST /api/admin/site/links (X-Admin-Token). ADMIN_TOKEN + Site__DataDir via env.
- compose: hokm-site service (:1520) + hokm_data volume for links JSON.
- CI deploy job builds + deploys the site container.
- deploy/SUBDOMAIN_SPLIT.md: nginx blocks, cert reissue, DNS, ENV split.
- Exclude site/ from root tsc + web docker context.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-08 07:19:43 +03:30
parent 8d0d4dc991
commit 5d38312ef0
39 changed files with 8207 additions and 2 deletions
+81
View File
@@ -0,0 +1,81 @@
import type { Metadata, Viewport } from "next";
import "./globals.css";
import { BRAND, SITE_URL } from "@/lib/site";
import { Nav } from "@/components/Nav";
import { Footer } from "@/components/Footer";
export const metadata: Metadata = {
metadataBase: new URL(SITE_URL),
title: {
default: `${BRAND.nameFa} | بازی حکم آنلاین رایگان`,
template: `%s | ${BRAND.nameFa}`,
},
description: BRAND.descFa,
keywords: [
"حکم",
"بازی حکم",
"حکم آنلاین",
"بازی ورق ایرانی",
"برگ وسط",
"بازی کارتی آنلاین",
"حکم با دوستان",
"Hokm",
"Barg-e Vasat",
],
applicationName: BRAND.nameFa,
authors: [{ name: BRAND.nameFa }],
alternates: { canonical: "/" },
openGraph: {
type: "website",
locale: "fa_IR",
url: SITE_URL,
siteName: BRAND.nameFa,
title: `${BRAND.nameFa} | بازی حکم آنلاین رایگان`,
description: BRAND.descFa,
images: [{ url: "/og.png", width: 1200, height: 630, alt: BRAND.nameFa }],
},
twitter: {
card: "summary_large_image",
title: `${BRAND.nameFa} | بازی حکم آنلاین`,
description: BRAND.descFa,
images: ["/og.png"],
},
icons: { icon: "/icon.svg", apple: "/icon.svg" },
manifest: "/manifest.webmanifest",
};
export const viewport: Viewport = {
themeColor: "#070b18",
width: "device-width",
initialScale: 1,
};
const jsonLd = {
"@context": "https://schema.org",
"@type": "VideoGame",
name: "برگ وسط",
alternateName: "Barg-e Vasat",
description: BRAND.descFa,
url: SITE_URL,
applicationCategory: "GameApplication",
genre: "بازی کارتی",
operatingSystem: "Android, iOS, Web",
inLanguage: "fa-IR",
offers: { "@type": "Offer", price: "0", priceCurrency: "IRR" },
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="fa" dir="rtl">
<body>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<Nav />
<main>{children}</main>
<Footer />
</body>
</html>
);
}