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
+46
View File
@@ -0,0 +1,46 @@
import { API_URL, APP_URL } from "./site";
export interface SiteLinks {
bazaarUrl: string;
bazaarEnabled: boolean;
myketUrl: string;
myketEnabled: boolean;
directApkUrl: string;
directApkEnabled: boolean;
webPlayUrl: string;
iosPwaEnabled: boolean;
instagram: string;
telegram: string;
supportEmail: string;
supportPhone: string;
appVersion: string;
}
// Safe defaults used until the API responds (or if it's unreachable).
export const FALLBACK_LINKS: SiteLinks = {
bazaarUrl: "",
bazaarEnabled: false,
myketUrl: "",
myketEnabled: false,
directApkUrl: "",
directApkEnabled: false,
webPlayUrl: APP_URL,
iosPwaEnabled: true,
instagram: "",
telegram: "",
supportEmail: "support@bargevasat.ir",
supportPhone: "",
appVersion: "",
};
/** Fetch admin-editable links at runtime (client-side). Falls back gracefully. */
export async function fetchLinks(): Promise<SiteLinks> {
try {
const res = await fetch(`${API_URL}/api/site/links`, { cache: "no-store" });
if (!res.ok) return FALLBACK_LINKS;
const data = (await res.json()) as Partial<SiteLinks>;
return { ...FALLBACK_LINKS, ...data };
} catch {
return FALLBACK_LINKS;
}
}
+13
View File
@@ -0,0 +1,13 @@
// Build-time public config (baked into the static bundle).
export const API_URL = (process.env.NEXT_PUBLIC_API_URL || "https://api.bargevasat.ir").replace(/\/$/, "");
export const APP_URL = (process.env.NEXT_PUBLIC_APP_URL || "https://app.bargevasat.ir").replace(/\/$/, "");
export const SITE_URL = (process.env.NEXT_PUBLIC_SITE_URL || "https://bargevasat.ir").replace(/\/$/, "");
export const BRAND = {
nameFa: "برگ وسط",
nameEn: "Barg-e Vasat",
taglineFa: "بازی حکمِ آنلاین، رایگان و حرفه‌ای",
descFa:
"برگ وسط، بازی حکم ایرانی به‌صورت آنلاین: با دوستان یا هوش مصنوعی بازی کن، در لیگ‌ها بالا برو، سکه و دستاورد جمع کن. روی اندروید، iOS و مرورگر.",
email: "support@bargevasat.ir",
};