Replace the landing with the artifact design and rebuild the admin in Ant Design.

Adds consultation leads, section editors, and the one-time content reset for this release.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-01 20:36:06 +03:30
co-authored by Cursor
parent 5147c661f0
commit b0088c35d1
130 changed files with 8024 additions and 2801 deletions
+62 -185
View File
@@ -1,133 +1,56 @@
import { PrismaClient } from "@prisma/client";
import * as bcrypt from "bcryptjs";
import { DEFAULT_SECTIONS, LEGACY_SECTION_KEYS } from "@montech/shared";
const prisma = new PrismaClient();
const defaultSections: Record<string, unknown> = {
hero: {
eyebrow: "گروه توسعه نرم‌افزار",
location: "[ تأسیس ۱۴۰۰ — تهران / دورکاری ]",
loaderTitle: "هوش‌افزار منتک",
lines: [
"در هوش‌افزار منتک",
"بهترین نرم‌افزارها و خدمات",
"متناسب با کسب‌وکار شما پیشنهاد می‌شود",
],
highlightWord: "هوش‌افزار منتک",
highlightWords: ["هوش‌افزار منتک"],
body: "منتک یک تیم مهندسی ارشد است که پلتفرم‌های وب، اپلیکیشن موبایل و زیرساخت ابری را برای کسب‌وکارهایی می‌سازد که نمی‌خواهند معمولی باشند.",
cta: "مشاهده نمونه‌کارها",
badge: "مهندسی منتک • از ۱۴۰۰ •",
coords: "تهران، ایران",
projectsLabel: "بیش از ۱۲۰ پروژه تحویل‌شده",
},
marquee: {
items: [
"پلتفرم وب",
"اپلیکیشن موبایل",
"ابرو DevOps",
"هوش مصنوعی",
"سیستم طراحی",
"معماری API",
],
},
manifesto: {
tag: "ما که هستیم",
words: [
{ text: "ما" },
{ text: "نرم‌افزاری" },
{ text: "می‌سازیم", volt: true },
{ text: "که" },
{ text: "تفاوت" },
{ text: "ایجاد" },
{ text: "کند." },
{ text: "منتک", volt: true },
],
body: "استراتژی، طراحی و مهندسی زیر یک سقف — با دقت وسواس‌گونه نسبت به کیفیت و عملکرد.",
},
services: {
tag: "چه می‌کنیم",
items: [
{
n: "۰۱",
title: "استراتژی محصول",
desc: "ایده‌های مبهم را به نقشه راه معتبر تبدیل می‌کنیم. اسپرینت کشف، پژوهش کاربر و نمونه‌سازی سریع قبل از نوشتن کد.",
tags: ["کشف محصول", "پژوهش کاربر", "نقشه راه", "MVP"],
},
{
n: "۰۲",
title: "مهندسی وب",
desc: "پلتفرم‌های وب سریع و مقیاس‌پذیر — از سایت‌های بازاریابی تا داشبوردهای پیچیده SaaS.",
tags: ["Nuxt", "NestJS", "Node.js", "React"],
},
{
n: "۰۳",
title: "اپلیکیشن موبایل",
desc: "تجربهٔ بومی‌گونه روی iOS و Android از یک کدبیس مشترک — یا کاملاً نیتیو وقتی لازم باشد.",
tags: ["React Native", "Flutter", "Swift", "Kotlin"],
},
{
n: "۰۴",
title: "ابرو DevOps",
desc: "زیرساختی که با رشد شما مقیاس می‌شود؛ استقرار خودکار، امنیت و مانیتورینگ.",
tags: ["AWS / GCP", "کوبرنتیز", "CI/CD", "Terraform"],
},
{
n: "۰۵",
title: "هوش مصنوعی و داده",
desc: "هوش مصنوعی کاربردی؛ اتصال LLM، اتوماسیون هوشمند و خطوط لوله داده.",
tags: ["LLM", "اتوماسیون", "مهندسی داده", "تحلیل"],
},
],
},
work: {
tag: "نمونه کارها",
items: [
{ n: "۰۱", title: "پالس‌بورد", cat: "پلتفرم تحلیلی فین‌تک", year: "۱۴۰۳" },
{ n: "۰۲", title: "ایرو‌لوپ", cat: "نرم‌افزار لجستیک", year: "۱۴۰۳" },
{ n: "۰۳", title: "مد‌سینک", cat: "پلتفرم هلث‌تک", year: "۱۴۰۲" },
{ n: "۰۴", title: "نوواپی", cat: "زیرساخت پرداخت", year: "۱۴۰۲" },
],
},
process: {
tag: "چگونه کار می‌کنیم",
steps: [
{ n: "۰۱", title: "کشف", desc: "کارگاه، پژوهش و هم‌راستایی روی نتایجی که واقعاً مهم‌اند." },
{ n: "۰۲", title: "طراحی", desc: "سیستم‌ها، جریان‌ها و رابط‌هایی که ساده و قابل‌اعتماد به نظر می‌رسند." },
{ n: "۰۳", title: "توسعه", desc: "مهندسان ارشد که نرم‌افزار آمادهٔ تولید تحویل می‌دهند." },
{ n: "۰۴", title: "استقرار و مقیاس", desc: "CI/CD، مانیتورینگ و زیرساختی که با شما رشد می‌کند." },
],
},
stats: {
items: [
{ value: 120, suffix: "+", label: "پروژه تحویل‌شده" },
{ value: 40, suffix: "+", label: "مشتری" },
{ value: 15, suffix: "", label: "مهندس و طراح" },
{ value: 98, suffix: "%", label: "ماندگاری مشتری" },
],
},
team: {
tag: "تیم",
headline: "با جمع ما آشنا شوید",
body: "تیمی جمع‌وجور از متخصصان محصول، طراحی و مهندسی.",
members: [
{ name: "علی رضایی", role: "مدیرعامل و هم‌بنیان‌گذار" },
{ name: "سارا محمدی", role: "مدیر فنی و هم‌بنیان‌گذار" },
{ name: "مریم حسینی", role: "سرپرست طراحی" },
{ name: "رضا کریمی", role: "مهندس ارشد" },
],
},
footer: {
tag: "تماس",
marquee: ["پروژه‌ای در ذهن دارید؟", "سلام کنید", "با هم کار کنیم"],
cta: "شروع همکاری",
email: "hello@montech.ir",
phone: "+98 21 0000 0000",
address: ["تهران", "ایران"],
socials: ["لینکدین", "گیت‌هاب", "اینستاگرام"],
},
const contactDefaults = {
brandName: "منتک",
tagline: "هوش‌افزار منظر",
email: "info@montech.ir",
phone: "۰۹۱۲ ۳۴۵ ۶۷۸۹",
address: "تهران، ایران",
socials: [
{ label: "تلگرام", url: "#" },
{ label: "لینکدین", url: "#" },
{ label: "اینستاگرام", url: "#" },
],
};
const pages = [
{
key: "home",
title: "خانه",
seo: {
title: "منتک | هوش‌افزار منظر - پلتفرم راهکارهای نرم‌افزاری و هوش مصنوعی",
description:
"با کمک هوش مصنوعی منتک، بهترین نرم‌افزارها و خدمات متناسب با کسب‌وکار شما پیشنهاد می‌شود. نرم‌افزار اختصاصی، حسابداری، CRM، فروشگاه آنلاین و نرم‌افزار طلا و جواهر.",
canonical: "https://montech.ir/",
},
},
{
key: "blog",
title: "بلاگ",
seo: {
title: "بلاگ — منتک",
description: "یادداشت‌هایی درباره محصول، مهندسی و ساخت نرم‌افزار.",
canonical: "https://montech.ir/blog",
},
},
{
key: "gallery",
title: "گالری",
seo: {
title: "گالری — منتک",
description: "تصاویر منتخب از پروژه‌ها و فضای استودیو منتک.",
canonical: "https://montech.ir/gallery",
},
},
];
/** Set SEED_RESET_CONTENT=1 to overwrite existing settings/sections/SEO with the defaults. */
const resetContent = process.env.SEED_RESET_CONTENT === "1";
async function main() {
const mobile = process.env.ADMIN_MOBILE || "09121234567";
const password = process.env.ADMIN_PASSWORD || "change-me-strong";
@@ -142,57 +65,10 @@ async function main() {
await prisma.siteSettings.upsert({
where: { id: "default" },
create: {
id: "default",
brandName: "منتک",
tagline: "گروه توسعه نرم‌افزار",
email: "hello@montech.ir",
phone: "+98 21 0000 0000",
address: "تهران، ایران",
timezone: "Asia/Tehran",
socials: [
{ label: "لینکدین", url: "https://linkedin.com" },
{ label: "گیت‌هاب", url: "https://github.com" },
],
},
update: {
brandName: "منتک",
tagline: "گروه توسعه نرم‌افزار",
address: "تهران، ایران",
},
create: { id: "default", timezone: "Asia/Tehran", ...contactDefaults },
update: resetContent ? contactDefaults : {},
});
const pages = [
{
key: "home",
title: "خانه",
seo: {
title: "منتک — گروه توسعه نرم‌افزار",
description:
"منتک پلتفرم‌های وب، اپلیکیشن موبایل و زیرساخت ابری با عملکرد بالا می‌سازد. مستقر در تهران، فعال در سراسر ایران.",
canonical: "https://montech.ir/",
},
},
{
key: "blog",
title: "بلاگ",
seo: {
title: "بلاگ — منتک",
description: "یادداشت‌هایی درباره محصول، مهندسی و ساخت نرم‌افزار.",
canonical: "https://montech.ir/blog",
},
},
{
key: "gallery",
title: "گالری",
seo: {
title: "گالری — منتک",
description: "تصاویر منتخب از پروژه‌ها و فضای استودیو منتک.",
canonical: "https://montech.ir/gallery",
},
},
];
for (const p of pages) {
const page = await prisma.page.upsert({
where: { key: p.key },
@@ -202,15 +78,23 @@ async function main() {
await prisma.pageSeo.upsert({
where: { pageId: page.id },
create: { pageId: page.id, ...p.seo },
update: { ...p.seo },
update: resetContent ? { ...p.seo } : {},
});
}
for (const [key, data] of Object.entries(defaultSections)) {
await prisma.sectionContent.deleteMany({ where: { key: { in: [...LEGACY_SECTION_KEYS] } } });
for (const [key, data] of Object.entries(DEFAULT_SECTIONS)) {
const json = {
...data,
...(key === "footer"
? { email: contactDefaults.email, phone: contactDefaults.phone, address: contactDefaults.address }
: {}),
} as object;
await prisma.sectionContent.upsert({
where: { key },
create: { key, data: data as object },
update: { data: data as object },
create: { key, data: json },
update: resetContent ? { data: json } : {},
});
}
@@ -227,17 +111,10 @@ async function main() {
seoTitle: "به منتک خوش آمدید — بلاگ",
seoDesc: "معرفی منتک و نحوه ساخت نرم‌افزار در تیم ما.",
},
update: {
title: "به منتک خوش آمدید",
excerpt: "ما نرم‌افزاری می‌سازیم که واقعاً کار می‌کند — و اینجا درباره‌اش می‌نویسیم.",
content:
"منتک یک گروه توسعه نرم‌افزار است که پلتفرم وب، اپلیکیشن موبایل و زیرساخت ابری می‌سازد.\n\nدر این بلاگ درباره ساخت محصول، مهندسی و درس‌آموخته‌های استودیو می‌نویسیم.",
seoTitle: "به منتک خوش آمدید — بلاگ",
seoDesc: "معرفی منتک و نحوه ساخت نرم‌افزار در تیم ما.",
},
update: {},
});
console.log("Seed complete. Admin:", mobile);
console.log(`Seed complete (${resetContent ? "content reset" : "missing rows only"}). Admin:`, mobile);
}
main()