diff --git a/next.config.js b/next.config.js
index ee7c56a9..6e2bcea0 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,6 +1,8 @@
-// GEM Build: 2026-06-06 10:54 UTC
+// GEM Build: 2026-07-09 production-readiness hardening
/** @type {import('next').NextConfig} */
const nextConfig = {
+ poweredByHeader: false,
+
experimental: {
optimizePackageImports: [
'@radix-ui/react-accordion',
@@ -44,20 +46,35 @@ const nextConfig = {
},
async headers() {
+ const contentSecurityPolicy = [
+ "default-src 'self'",
+ "script-src 'self' 'unsafe-inline' https://va.vercel-scripts.com https://vitals.vercel-insights.com",
+ "style-src 'self' 'unsafe-inline'",
+ "img-src 'self' data: blob: https:",
+ "font-src 'self' data:",
+ "connect-src 'self' https:",
+ "frame-src 'self' https:",
+ "worker-src 'self' blob:",
+ "object-src 'none'",
+ "base-uri 'self'",
+ "form-action 'self'",
+ "frame-ancestors 'none'",
+ "upgrade-insecure-requests",
+ ].join('; ');
+
return [
{
source: '/:path*',
headers: [
{ key: 'X-DNS-Prefetch-Control', value: 'on' },
- { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
+ { key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), browsing-topics=()' },
- {
- key: 'Content-Security-Policy-Report-Only',
- value: "default-src 'self'; script-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https://vitals.vercel-insights.com https://*.vercel-insights.com; frame-ancestors 'self'; base-uri 'self'; form-action 'self'",
- },
+ { key: 'Content-Security-Policy', value: contentSecurityPolicy },
+ { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
+ { key: 'Cross-Origin-Resource-Policy', value: 'same-site' },
],
},
{
diff --git a/src/app/api/contact/route.ts b/src/app/api/contact/route.ts
index d4145c0b..954fd0ff 100644
--- a/src/app/api/contact/route.ts
+++ b/src/app/api/contact/route.ts
@@ -5,21 +5,19 @@ import { getSession } from "@/lib/auth";
import { emitAuditLog } from "@/lib/audit";
import { getRequestContext, badRequest } from "@/lib/api/auth-helpers";
import { rateLimit, rateLimitedResponse } from "@/lib/api/rate-limit";
+import { sendMail } from "@/lib/mail/send";
const schema = z.object({
name: z.string().trim().min(2, "Name must be at least 2 characters").max(120),
email: z.string().trim().toLowerCase().email("Invalid email address").max(254),
message: z.string().trim().min(10, "Message must be at least 10 characters").max(5_000),
subject: z.string().trim().max(200).optional(),
- // Optional honeypot field — bots tend to fill every input. If populated we
- // accept (200 OK) but silently drop the submission.
website: z.string().optional(),
});
export async function POST(req: NextRequest) {
const { ipAddress, userAgent } = getRequestContext(req);
- // Hard rate-limit per IP: 5 contact submissions / hour.
const limit = rateLimit(ipAddress, {
key: "contact:submit",
windowMs: 60 * 60_000,
@@ -41,75 +39,124 @@ export async function POST(req: NextRequest) {
const { name, email, message, subject, website } = parsed.data;
- // Honeypot — return 200 OK to avoid signaling rejection to the bot.
+ // Honeypot submissions receive a generic success response but are not stored.
if (website && website.trim().length > 0) {
return NextResponse.json({ ok: true });
}
- // Capture the inbound contact as a SupportTicket only when the sender is
- // already authenticated. Otherwise we never write to the database — the
- // ticket model requires a real userId FK and we will not synthesize one
- // (which previously caused FK violations and lost messages).
const session = await getSession();
- let ticketId: string | null = null;
+ const normalizedSubject = subject?.trim() || `Contact from ${name}`;
+ const baseNotes = [
+ `Website contact enquiry`,
+ `From: ${name} <${email}>`,
+ `Authenticated: ${session ? `yes (${session.email})` : "no"}`,
+ "",
+ message,
+ ].join("\n");
+
+ try {
+ // Persist every genuine public enquiry before reporting success. SupportBooking
+ // is intentionally used here because it accepts unauthenticated contacts and is
+ // already part of the production schema. Email is only a notification channel;
+ // it is not the system of record.
+ const submission = await db.supportBooking.create({
+ data: {
+ userId: session?.userId,
+ name,
+ email,
+ subject: normalizedSubject,
+ status: "pending",
+ notes: `${baseNotes}\n\nNotification delivery: pending`,
+ },
+ select: { id: true },
+ });
+
+ let ticketId: string | null = null;
+ if (session) {
+ try {
+ const ticket = await db.supportTicket.create({
+ data: {
+ userId: session.userId,
+ subject: normalizedSubject,
+ description: `From: ${name} <${email}>\n\n${message}`,
+ status: "open",
+ priority: "medium",
+ },
+ select: { id: true },
+ });
+ ticketId = ticket.id;
+ } catch (error) {
+ console.error("[contact] failed to create authenticated support ticket", error);
+ }
+ }
+
+ let delivery = "not_configured";
+ const recipient =
+ process.env.ADMIN_EMAIL ||
+ process.env.SUPPORT_EMAIL ||
+ process.env.GEM_OWNER_EMAIL;
+
+ if (recipient) {
+ try {
+ const result = await sendMail({
+ to: recipient,
+ replyTo: email,
+ subject: `[GEM Contact] ${normalizedSubject}`,
+ text: `Submission ID: ${submission.id}\nName: ${name}\nEmail: ${email}\nAuth: ${session ? `yes (${session.email})` : "no"}\nIP: ${ipAddress}\n\n${message}`,
+ });
+ delivery = result.sent
+ ? "sent"
+ : "reason" in result
+ ? result.reason
+ : "skipped";
+ } catch (error) {
+ delivery = "failed";
+ console.error("[contact] failed to send notification email", error);
+ }
+ }
- if (session) {
try {
- const ticket = await db.supportTicket.create({
+ await db.supportBooking.update({
+ where: { id: submission.id },
data: {
- userId: session.userId,
- subject: subject?.trim() || `Contact from ${name}`,
- description: `From: ${name} <${email}>\n\n${message}`,
- status: "open",
- priority: "medium",
+ notes: `${baseNotes}\n\nNotification delivery: ${delivery}`,
},
- select: { id: true },
});
- ticketId = ticket.id;
} catch (error) {
- console.error("[contact] failed to persist ticket", error);
- // non-fatal — fall through and still email + audit
+ console.error("[contact] failed to record notification status", error);
}
- }
- await emitAuditLog({
- userId: session?.userId,
- action: "admin_action",
- resource: "contact_message",
- resourceId: ticketId ?? undefined,
- metadata: {
- authenticated: Boolean(session),
- email,
- name,
- subject: subject ?? null,
- ticketId,
- },
- ipAddress,
- userAgent,
- });
+ await emitAuditLog({
+ userId: session?.userId,
+ action: "admin_action",
+ resource: "contact_message",
+ resourceId: submission.id,
+ metadata: {
+ authenticated: Boolean(session),
+ email,
+ name,
+ subject: normalizedSubject,
+ submissionId: submission.id,
+ ticketId,
+ notificationDelivery: delivery,
+ },
+ ipAddress,
+ userAgent,
+ });
- // Send notification email if SMTP is configured. We isolate the import in
- // the conditional so deployments without nodemailer wired don't pay the
- // bundle cost on the cold path.
- if (process.env.SMTP_HOST && process.env.ADMIN_EMAIL) {
- try {
- const nodemailer = await import("nodemailer");
- const transporter = nodemailer.default.createTransport({
- host: process.env.SMTP_HOST,
- port: Number(process.env.SMTP_PORT ?? 587),
- auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
- });
- await transporter.sendMail({
- from: process.env.EMAIL_FROM ?? process.env.SMTP_USER,
- to: process.env.ADMIN_EMAIL,
- replyTo: email,
- subject: `[GEM Contact] ${subject?.trim() || `Message from ${name}`}`,
- text: `Name: ${name}\nEmail: ${email}\nAuth: ${session ? `yes (${session.email})` : "no"}\nIP: ${ipAddress}\n\n${message}`,
- });
- } catch (error) {
- console.error("[contact] failed to send notification email", error);
- }
+ return NextResponse.json({
+ ok: true,
+ submissionId: submission.id,
+ ticketId,
+ });
+ } catch (error) {
+ console.error("[contact] failed to persist public enquiry", error);
+ return NextResponse.json(
+ {
+ ok: false,
+ error: "Your message could not be stored. Please use the published support email.",
+ },
+ { status: 503 },
+ );
}
-
- return NextResponse.json({ ok: true, ticketId });
}
diff --git a/src/app/api/kyc/documents/route.ts b/src/app/api/kyc/documents/route.ts
index 055598b9..7dd412c5 100644
--- a/src/app/api/kyc/documents/route.ts
+++ b/src/app/api/kyc/documents/route.ts
@@ -1,136 +1,37 @@
-import { NextRequest, NextResponse } from "next/server";
-import { z } from "zod";
-import { db } from "@/lib/db";
-import { emitAuditLog } from "@/lib/audit";
-import {
- requireSession,
- getRequestContext,
- badRequest,
- serverError,
-} from "@/lib/api/auth-helpers";
-
-// Storage path is generated server-side from the application ID; the client
-// only supplies metadata. This prevents an authenticated user from writing
-// document rows that point at someone else's storage prefix.
-
-const ALLOWED_MIME = [
- "application/pdf",
- "image/jpeg",
- "image/png",
- "image/webp",
- "image/heic",
-];
-const MAX_FILE_SIZE = 25 * 1024 * 1024; // 25 MB
-
-const createDocumentSchema = z.object({
- applicationId: z.string().min(1, "applicationId is required"),
- documentType: z
- .string()
- .trim()
- .min(2)
- .max(64)
- .regex(/^[a-z0-9_-]+$/i, "documentType must be alphanumeric/underscore"),
- fileName: z
- .string()
- .trim()
- .min(1)
- .max(255)
- // Block path traversal characters at the filename level.
- .regex(/^[^/\\]+$/, "fileName must not contain path separators"),
- fileSize: z
- .number()
- .int()
- .nonnegative()
- .max(MAX_FILE_SIZE, `File exceeds ${MAX_FILE_SIZE} bytes`)
- .optional(),
- mimeType: z.string().trim().min(1).max(127).optional(),
-});
-
-export async function POST(req: NextRequest) {
+import { NextResponse } from "next/server";
+import { requireSession } from "@/lib/api/auth-helpers";
+
+/**
+ * Production document intake is intentionally disabled until a complete private
+ * object-storage flow is available. The previous implementation created only a
+ * database metadata row and did not store, scan, or verify the actual file. That
+ * could make an application appear to contain documents when no document existed.
+ */
+export async function POST() {
const gate = await requireSession();
- if (!gate.ok) return (gate as { ok: false; response: any }).response;
- const session = gate.session;
- const { ipAddress, userAgent } = getRequestContext(req);
-
- let body: unknown;
- try {
- body = await req.json();
- } catch {
- return badRequest("Invalid JSON");
- }
-
- const parsed = createDocumentSchema.safeParse(body);
- if (!parsed.success) {
- return badRequest("Validation failed", parsed.error.flatten().fieldErrors);
- }
-
- const { applicationId, documentType, fileName, fileSize, mimeType } = parsed.data;
- const safeMime = mimeType && ALLOWED_MIME.includes(mimeType)
- ? mimeType
- : "application/octet-stream";
-
- try {
- // Ownership check: only allow attaching documents to the caller's own
- // application, and only while the application is still editable.
- const application = await db.kYCApplication.findFirst({
- where: { id: applicationId, userId: session.userId },
- select: { id: true, status: true },
- });
- if (!application) {
- return NextResponse.json({ error: "Application not found" }, { status: 404 });
- }
- if (
- application.status === "approved" ||
- application.status === "rejected" ||
- application.status === "expired"
- ) {
- return NextResponse.json(
- { error: "Cannot attach documents to a finalized application" },
- { status: 409 },
- );
- }
-
- const document = await db.kycDocument.create({
- data: {
- applicationId: application.id,
- documentType,
- fileName,
- fileSize: fileSize ?? 0,
- mimeType: safeMime,
- // Server-controlled storage prefix scoped by application id.
- storagePath: `kyc/${application.id}/${Date.now()}-${fileName}`,
- status: "pending",
- },
- });
-
- // Bump the application status forward if it's still in early stages so
- // the dashboard reflects upload progress.
- if (application.status === "not_started" || application.status === "started") {
- await db.kYCApplication.update({
- where: { id: application.id },
- data: { status: "documents_uploaded" },
- });
- }
-
- await emitAuditLog({
- userId: session.userId,
- action: "document_upload",
- resource: "kyc_document",
- resourceId: document.id,
- metadata: {
- applicationId: application.id,
- documentType,
- fileName,
- fileSize: fileSize ?? 0,
- mimeType: safeMime,
+ if (!gate.ok) return (gate as { ok: false; response: NextResponse }).response;
+
+ return NextResponse.json(
+ {
+ ok: false,
+ code: "SECURE_DOCUMENT_UPLOAD_NOT_ACTIVE",
+ error:
+ "Secure document upload is not active. Do not transmit identity or financial documents through this endpoint.",
+ requirements: [
+ "private object storage",
+ "short-lived upload authorization",
+ "file-signature and size validation",
+ "malware scanning and quarantine",
+ "reviewer access controls and audit logging",
+ "retention and deletion enforcement",
+ ],
+ },
+ {
+ status: 503,
+ headers: {
+ "Cache-Control": "no-store",
+ "Retry-After": "86400",
},
- ipAddress,
- userAgent,
- });
-
- return NextResponse.json({ ok: true, document });
- } catch (error) {
- console.error("[POST /api/kyc/documents]", error);
- return serverError();
- }
+ },
+ );
}
diff --git a/src/app/community-hub/layout.tsx b/src/app/community-hub/layout.tsx
index de48d874..dcca27f2 100644
--- a/src/app/community-hub/layout.tsx
+++ b/src/app/community-hub/layout.tsx
@@ -1,16 +1,41 @@
import type { Metadata } from "next";
import type { ReactNode } from "react";
+import { AlertTriangle } from "lucide-react";
import { HubShell } from "@/components/hub/HubShell";
export const metadata: Metadata = {
title: {
- default: "Community Hub",
- template: "%s | GEM Community Hub",
+ default: "Community Preview",
+ template: "%s | GEM Community Preview",
},
description:
- "GEM Community Hub — a private, verified network for partners, operators, investors, clients, and advisors executing across jurisdictions.",
+ "Preview of planned GEM Enterprise community capabilities. Sample profiles, organizations, events, statistics, and opportunities are demonstration data.",
+ robots: {
+ index: false,
+ follow: false,
+ nocache: true,
+ },
};
export default function CommunityHubLayout({ children }: { children: ReactNode }) {
- return {children};
+ return (
+
+
+ {children}
+
+ );
}
diff --git a/src/app/intel/news/page.tsx b/src/app/intel/news/page.tsx
index 15794921..3e68c09d 100644
--- a/src/app/intel/news/page.tsx
+++ b/src/app/intel/news/page.tsx
@@ -1,30 +1,14 @@
"use client";
-import { useState } from "react";
import Link from "next/link";
-import {
- ArrowRight,
- ExternalLink,
- Maximize2,
- Minimize2,
- RefreshCw,
- Rss,
- Shield,
- Sparkles,
-} from "lucide-react";
+import { AlertTriangle, ArrowRight, ExternalLink, Rss } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
-import { Card, CardContent } from "@/components/ui/card";
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
CuratedNewsFeed,
type CuratedCategory,
} from "@/components/intel/CuratedNewsFeed";
-// Base44-hosted fallback kept while the native feed is warming up.
-const GEM_INTEL_FEED_URL =
- "https://gem-intel-copy-769950ea.base44.app/news/category/crypto";
-
const CATEGORIES: CuratedCategory[] = [
{ label: "Crypto & Digital Assets", slug: "crypto" },
{ label: "Cybersecurity", slug: "cybersecurity" },
@@ -35,279 +19,68 @@ const CATEGORIES: CuratedCategory[] = [
];
export default function IntelNewsPage() {
- const [expanded, setExpanded] = useState(false);
- const [iframeKey, setIframeKey] = useState(0);
- const [activeCategory, setActiveCategory] = useState("crypto");
-
- const iframeSrc = `https://gem-intel-copy-769950ea.base44.app/news/category/${activeCategory}`;
-
return (
- {/* ══ HERO ══════════════════════════════════════════════════════════════ */}
-
-
-
+
+
+
+
+ News aggregation preview: articles may be imported from external
+ sources and can be delayed, incomplete, duplicated, or unavailable. Publication on
+ this page does not mean GEM independently verified, endorsed, or authored a story.
+ Always open the original publisher before relying on the information.
+
- Continuous intelligence across crypto, cybersecurity, markets,
- geopolitics, policy, and alternatives — ingested every three
- hours and curated by the GEM analyst team.
+
+ A category view of externally sourced articles. Feed status, source coverage,
+ retrieval time, and editorial review must be confirmed before this service is
+ described as continuous or analyst-curated.
- Every headline is filtered, scored, and tagged by the GEM
- research team before it reaches members.
-
-
-
-
-
-
-
-
-
- Push to Newsletters
-
-
- The most signal-dense stories are republished into the GEM
- Threat Wire and Financial Security Monitor each cycle.
-
-
-
-
-
-
-
-
-
- Member Briefings
-
-
- Community Hub members receive private commentary and context on
- high-impact stories through the{" "}
-
- Knowledge
- {" "}
- channel.
-
-
-
-
-
-
- Managing this feed?{" "}
-
- Open the admin console
- {" "}
- to trigger ingestion, toggle sources, and review run history.
+
+
+
+
Reliance notice
+
+ News content is informational and may become stale. It is not a security alert,
+ investment recommendation, legal opinion, incident notification, or substitute
+ for an authoritative advisory. Source links should open the original publisher in
+ a separate context before any operational decision is made.
+
+
+ Return to the intelligence preview
+
+
);
}
-
-// Silence unused-import warning for fallback URL kept as documentation.
-void GEM_INTEL_FEED_URL;
diff --git a/src/app/intel/page.tsx b/src/app/intel/page.tsx
index fe1eff50..4f8d45e3 100644
--- a/src/app/intel/page.tsx
+++ b/src/app/intel/page.tsx
@@ -1,94 +1,136 @@
import Image from "next/image";
import Link from "next/link";
-import { Shield, AlertTriangle, Globe, Eye, Zap, ArrowRight, Activity } from "lucide-react";
+import {
+ Shield,
+ AlertTriangle,
+ Globe,
+ Eye,
+ ArrowRight,
+ BookOpenCheck,
+} from "lucide-react";
import { Badge } from "@/components/ui/badge";
export const metadata = {
- title: "Threat Intelligence | GEM Enterprise",
- description: "Live threat intelligence, CVE advisories, dark web monitoring reports, and security bulletins from GEM Enterprise.",
+ title: "Threat Intelligence Preview",
+ description:
+ "A clearly labelled preview of GEM Enterprise threat-intelligence reporting and advisory presentation.",
};
const categories = [
- { icon: Shield, label: "Cyber Threats", color: "cyan", count: 14 },
- { icon: AlertTriangle, label: "Critical CVEs", color: "red", count: 3 },
- { icon: Eye, label: "Dark Web Alerts", color: "purple", count: 7 },
- { icon: Globe, label: "Geopolitical", color: "amber", count: 5 },
+ { icon: Shield, label: "Cyber examples", color: "cyan", count: 14 },
+ { icon: AlertTriangle, label: "CVE examples", color: "red", count: 3 },
+ { icon: Eye, label: "Exposure examples", color: "purple", count: 7 },
+ { icon: Globe, label: "Risk examples", color: "amber", count: 5 },
];
-const featuredThreats = [
+const exampleBriefs = [
{
severity: "CRITICAL",
- title: "Active Exploitation of Palo Alto PAN-OS Authentication Bypass",
- summary: "CVE-2025-0108 actively exploited in the wild. Unauthenticated attackers gaining management interface access. GEM clients on affected firmware versions have been individually notified.",
+ title: "Example advisory: PAN-OS authentication bypass",
+ summary:
+ "Demonstration of how a verified vendor advisory and exploited-vulnerability notice could be summarized for an authorized client. This card is not a current alert and must not be used for security decisions.",
category: "Infrastructure",
- timestamp: "2 hours ago",
- affected: "Network Perimeter",
+ referenceDate: "Reference advisory: February 2025",
+ affected: "Network perimeter",
},
{
severity: "HIGH",
- title: "Credential Stuffing Campaign Targeting Financial Institution Portals",
- summary: "Large-scale automated credential stuffing operation detected against major US and UK banking portals. 2.3M validated credential pairs circulating on dark web markets. Wire fraud risk elevated.",
+ title: "Example scenario: credential-stuffing activity",
+ summary:
+ "Demonstration content showing how account-takeover indicators, affected services, recommended controls, and escalation guidance may be presented after source verification.",
category: "Financial",
- timestamp: "6 hours ago",
- affected: "Financial Services",
+ referenceDate: "Demonstration scenario",
+ affected: "Identity and access",
},
{
severity: "HIGH",
- title: "Real Estate Wire Fraud: Title Company Email Compromise Campaign",
- summary: "Organized BEC campaign targeting real estate title companies in California, Texas, and New York. Attacker pattern: compromise title agent email, redirect closing wire instructions 24-48 hours before close.",
+ title: "Example scenario: real-estate payment diversion",
+ summary:
+ "Demonstration content showing a business-email-compromise pattern and the verification steps that may be included in a client briefing. No active campaign is asserted by this page.",
category: "Real Estate",
- timestamp: "1 day ago",
- affected: "Property Transactions",
+ referenceDate: "Demonstration scenario",
+ affected: "Property transactions",
},
{
severity: "MEDIUM",
- title: "QakBot Variant with New C2 Infrastructure Detected",
- summary: "Updated QakBot variant using fast-flux DNS and TLS-encrypted C2 beaconing to evade detection. Delivered via malicious OneNote documents in targeted spear-phishing campaigns.",
+ title: "Example scenario: malware command-and-control changes",
+ summary:
+ "Demonstration content showing how malware infrastructure changes, detection guidance, and source confidence may be communicated in a future verified feed.",
category: "Malware",
- timestamp: "2 days ago",
- affected: "Enterprise Endpoints",
+ referenceDate: "Demonstration scenario",
+ affected: "Enterprise endpoints",
},
];
const severityColors = {
- "CRITICAL": "text-red-400 border-red-500/30 bg-red-500/10",
- "HIGH": "text-orange-400 border-orange-500/30 bg-orange-500/10",
- "MEDIUM": "text-amber-400 border-amber-500/30 bg-amber-500/10",
- "LOW": "text-green-400 border-green-500/30 bg-green-500/10",
+ CRITICAL: "text-red-400 border-red-500/30 bg-red-500/10",
+ HIGH: "text-orange-400 border-orange-500/30 bg-orange-500/10",
+ MEDIUM: "text-amber-400 border-amber-500/30 bg-amber-500/10",
+ LOW: "text-green-400 border-green-500/30 bg-green-500/10",
};
export default function IntelPage() {
return (
+
+
+
+
+ Intelligence preview: this page contains static demonstration
+ material that illustrates a planned reporting format. It is not a live threat
+ feed, monitoring console, emergency notification channel, or substitute for
+ authoritative vendor and government advisories.
+
+
+
- {/* HERO */}
-
+
-
+
-
-
-
- 3 CRITICAL Threats Active
+
+
+
+
+ Demonstration reporting format
+
-
Threat Intelligence
-
Live advisories, CVE tracking, dark web monitoring, and geopolitical risk from GEM's 24/7 intelligence operations.
+
+ Threat Intelligence Preview
+
+
+ A transparent preview of how sourced advisories, exposure findings, and
+ risk briefings may be presented after a verified data pipeline is activated.
+
@@ -100,61 +142,90 @@ export default function IntelPage() {
- {/* DARK WEB MONITORING FEATURE */}
-
-
-
-
+
+
+
+
-
- Dark Web Active
+
+
+ Illustrative image
+
- Dark Web Monitoring
-
Your Exposure, Found Before Attackers Act
-
GEM continuously monitors dark web forums, paste sites, credential markets, and breach databases — scanning specifically for your organization's domain, email patterns, credential pairs, and sensitive data signatures.
-
When a match is found, you receive an immediate alert with context: what was exposed, where it appeared, and what action to take — before attackers can weaponize it.
-
- Learn About Cyber Fund
+
+ Planned exposure reporting
+
+
+ Source verification before publication
+
+
+ Production intelligence must identify its source, publication time, retrieval
+ time, confidence, affected products, and expiry or review state. Stale data must
+ be visibly marked and must never receive automatically changing relative-time labels.
+
+
+ Client-specific exposure monitoring will be described as active only after an
+ authorized monitoring provider, alert-delivery path, escalation process, and
+ service agreement have been verified.
+
+
+ Discuss intelligence services
- {/* FEATURED THREATS */}
-
-
-
-
-
Active Threat Advisories
-
Updated continuously by GEM intelligence analysts
-
-
-
- Live Feed
-
+
+
+
+
Example advisory cards
+
+ Static examples only. Each card is deliberately labelled and uses an absolute
+ reference date or demonstration status.
+
- Upload the documents listed below. Required documents must be provided to complete your
- application. All files are encrypted in transit and at rest.
-
-
-
- {DOCUMENT_SLOTS.map((slot) => (
-
-
+
+
+
+
+
+
+
+ Secure upload not yet activated
+
+
+ Do not send identity or financial documents through this website yet
+
- ))}
-
-
- {error && (
-
- {error}
- )}
-
+
+
+
+ The production private-storage, malware-scanning, access-audit, retention, and
+ authorized-review pipeline has not been fully activated. To protect applicants,
+ this page is intentionally fail-closed and does not accept files.
+
+
- {/* Disclosure */}
-
- Document Upload Disclosure
- All documents submitted are treated as confidential and used solely for identity verification
- and regulatory compliance purposes. Files are encrypted using AES-256 at rest and TLS 1.3
- in transit. GEM Enterprise retains documents for the duration required by applicable
- anti-money laundering (AML) and know-your-customer (KYC) regulations, typically 5–7 years.
- Documents will not be shared with third parties except as required by law or with your
- explicit consent.
+
+ GEM will enable document submission only after the storage provider, encryption,
+ short-lived upload authorization, file-signature validation, malware scanning,
+ reviewer permissions, deletion controls, and retention policy have been tested
+ end to end.
+
- GEM Enterprise delivers institutional-grade cybersecurity, financial security, and real estate protection for qualified clients. Built around KYC-gated access, compliance review, entitlement control, and audit-ready operations.
+
+ GEM Enterprise is an access-controlled platform for cybersecurity, compliance,
+ financial-security coordination, and property-risk services. Sensitive and
+ high-impact services are activated only after eligibility, scope, provider,
+ jurisdiction, and contractual checks are complete.
-
-
- {/* ── CREDIBILITY BAR ── */}
-
-
-
- {stats.map((stat, i) => (
-
-
{stat.value}
-
{stat.label}
+
+
+
+ {stats.map((stat, index) => (
+
+
{stat.value}
+
{stat.label}
))}
- {/* ── THREE PILLARS with card images ── */}
-
-
- Our Services
-
Three Pillars of Protection
-
Each pillar is independently powerful. Together, they form GEM Enterprise's complete institutional security framework.
+
+
+
+ Service areas
+
+
+ Clear scope before activation
+
+
+ Public descriptions explain possible capabilities. Actual availability,
+ coverage, staffing, deliverables, response targets, fees, and limitations are
+ defined in an approved proposal and signed agreement.
+
GEM's Security Operations Center operates on a follow-the-sun model — certified analysts across North America, EMEA, and Asia-Pacific monitoring threats in real time, every hour of every day.
-
-
+
+
+
+
+ Controlled activation
+
+
Built to fail closed
+
+ Features that depend on unverified storage, providers, staffing, or external
+ integrations remain restricted instead of pretending to be operational. For
+ example, identity-document upload is disabled until private storage and malware
+ scanning are verified end to end.
+
-
-
-
- {/* ── PLATFORM FEATURES ── */}
-
-
-
-
Built for Institutional Operations
-
Every component of the GEM platform is designed for qualified operators managing high-value assets and sensitive compliance requirements.
Our team carries decades of experience across enterprise security, regulatory compliance, and high-value asset protection. We built GEM because we couldn't find a platform that met our own institutional standards.
- Meet the Team
-
-
+
+
+
+ Review platform architecture
+
+
- {/* ── OPERATING MODEL ── */}
-
-
-
How Clients Gain Access
-
Every GEM client passes through a structured onboarding path designed for institutional integrity.
GEM Enterprise is an invitation and application-based platform. Access is granted after KYC verification, entity review, and compliance approval.
-
-
- Begin Application
+
+
+
Start with the right service path
+
+ General information and selected products are broadly available. Sensitive,
+ institutional, financial, monitoring, and jurisdiction-restricted services
+ require additional review before activation.
+
+
+
+
+ Begin an enquiry
+
-
- Contact Us
+
+ Contact GEM
diff --git a/src/app/services/[slug]/page.tsx b/src/app/services/[slug]/page.tsx
new file mode 100644
index 00000000..0a9d79e4
--- /dev/null
+++ b/src/app/services/[slug]/page.tsx
@@ -0,0 +1,242 @@
+import type { Metadata } from "next";
+import Link from "next/link";
+import { notFound } from "next/navigation";
+import {
+ AlertTriangle,
+ ArrowRight,
+ Building2,
+ Eye,
+ Globe,
+ Lock,
+ Shield,
+ Zap,
+} from "lucide-react";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+
+const services = {
+ "threat-monitoring": {
+ icon: Shield,
+ title: "Managed Threat Monitoring",
+ summary:
+ "Monitoring, triage, and escalation support for eligible client environments under a documented statement of work.",
+ capabilities: [
+ "Approved telemetry and alert-source onboarding",
+ "Triage criteria and escalation routing",
+ "Periodic reporting and control review",
+ "Named operational contacts and support windows",
+ ],
+ requirements: [
+ "Verified authority over the monitored environment",
+ "Approved data sources and retention terms",
+ "Confirmed staffing or provider coverage",
+ "Signed scope, exclusions, and response targets",
+ ],
+ },
+ "incident-response": {
+ icon: Zap,
+ title: "Incident Response Coordination",
+ summary:
+ "Structured triage, containment planning, evidence-preservation guidance, and recovery coordination according to contracted coverage.",
+ capabilities: [
+ "Initial incident intake and severity assessment",
+ "Containment and recovery coordination",
+ "Evidence-handling and decision documentation",
+ "Post-incident review and remediation planning",
+ ],
+ requirements: [
+ "Authorized incident contact and decision-maker",
+ "Defined systems and jurisdictions in scope",
+ "Available technical access and evidence sources",
+ "Contracted activation and escalation terms",
+ ],
+ },
+ "dark-web": {
+ icon: Eye,
+ title: "Exposure & Dark-Web Monitoring",
+ summary:
+ "Authorized exposure monitoring using approved providers and sources, with documented limitations and escalation routes.",
+ capabilities: [
+ "Domain and credential-exposure monitoring",
+ "Source confidence and evidence review",
+ "Alert validation and recommended next steps",
+ "Periodic exposure summaries",
+ ],
+ requirements: [
+ "Confirmed ownership or authority for monitored identifiers",
+ "Approved provider and lawful data source",
+ "Documented alert recipients",
+ "Defined false-positive and escalation process",
+ ],
+ },
+ "red-team": {
+ icon: Lock,
+ title: "Security Assessment & Testing",
+ summary:
+ "Authorized assessment of applications, infrastructure, configuration, and selected business processes within explicit rules of engagement.",
+ capabilities: [
+ "Scope and attack-surface review",
+ "Application and infrastructure testing",
+ "Control validation and evidence collection",
+ "Prioritized remediation reporting",
+ ],
+ requirements: [
+ "Written authorization from the asset owner",
+ "Approved targets, timing, and exclusions",
+ "Emergency contact and stop conditions",
+ "Data-handling and evidence-retention plan",
+ ],
+ },
+ "asset-recovery": {
+ icon: Building2,
+ title: "Asset & Property Risk Coordination",
+ summary:
+ "Risk review, documentation support, and specialist coordination where ownership, authority, jurisdiction, and provider capability are verified.",
+ capabilities: [
+ "Ownership and documentation review",
+ "Risk and fraud-indicator assessment",
+ "Qualified specialist and provider referrals",
+ "Case coordination and evidence tracking",
+ ],
+ requirements: [
+ "Verified identity and legal authority",
+ "Supporting ownership and transaction records",
+ "Jurisdiction and legal-scope review",
+ "Signed engagement and provider acceptance",
+ ],
+ },
+ "federal-compliance": {
+ icon: Globe,
+ title: "Compliance Readiness Support",
+ summary:
+ "Gap assessment, control mapping, policy support, and remediation planning for selected frameworks. Readiness support is not certification.",
+ capabilities: [
+ "Current-state gap assessment",
+ "Control and evidence mapping",
+ "Policy and procedure support",
+ "Remediation tracking and audit preparation",
+ ],
+ requirements: [
+ "Confirmed framework and organizational scope",
+ "Access to relevant policies and evidence",
+ "Named control owners",
+ "Independent legal or accredited audit advice where required",
+ ],
+ },
+} as const;
+
+type ServiceSlug = keyof typeof services;
+
+export function generateStaticParams() {
+ return Object.keys(services).map((slug) => ({ slug }));
+}
+
+export async function generateMetadata({
+ params,
+}: {
+ params: Promise<{ slug: string }>;
+}): Promise {
+ const { slug } = await params;
+ const service = services[slug as ServiceSlug];
+ if (!service) return {};
+
+ return {
+ title: service.title,
+ description: service.summary,
+ };
+}
+
+export default async function ServiceDetailPage({
+ params,
+}: {
+ params: Promise<{ slug: string }>;
+}) {
+ const { slug } = await params;
+ const service = services[slug as ServiceSlug];
+ if (!service) notFound();
+
+ const Icon = service.icon;
+
+ return (
+
+
+
+
+ Service scope
+
+
+
+
+
+
+
{service.title}
+
+ {service.summary}
+
+
+
+
+
+
+
+
+
Potential capabilities
+
+ {service.capabilities.map((item) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+
Activation requirements
+
+ {service.requirements.map((item) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
Public description, not a service-level agreement
+
+ Availability, coverage hours, personnel, providers, response times, deliverables,
+ exclusions, data handling, and fees are established only by an approved proposal
+ and signed agreement. This page does not promise continuous monitoring, a fixed
+ activation time, certification, recovery success, or a particular outcome.
+
+
+
+
+
+
+
+
+
+
Request a scoped assessment
+
+ Tell us the environment, objective, jurisdiction, timeline, and current constraints.
+ The team will confirm whether the service can be offered and under what conditions.
+
+
+
+
+ Contact GEM
+
+
+
+
+
+ );
+}
diff --git a/src/app/services/page.tsx b/src/app/services/page.tsx
index 15cbed12..81fdab34 100644
--- a/src/app/services/page.tsx
+++ b/src/app/services/page.tsx
@@ -1,79 +1,88 @@
import Link from "next/link";
import Image from "next/image";
-import { Shield, Zap, Lock, Eye, Building2, ArrowRight, Globe, Users } from "lucide-react";
+import {
+ Shield,
+ Zap,
+ Lock,
+ Eye,
+ Building2,
+ ArrowRight,
+ Globe,
+} from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
export const metadata = {
- title: "Services | GEM Enterprise",
- description: "Institutional-grade cybersecurity, financial security, and real estate protection services for qualified clients.",
+ title: "Services",
+ description:
+ "Cybersecurity, compliance, financial-security coordination, and property-risk services, subject to scope, eligibility, provider availability, and signed agreements.",
};
const services = [
{
icon: Shield,
- title: "24/7 Threat Monitoring & SOC",
+ title: "Managed Threat Monitoring",
slug: "threat-monitoring",
- desc: "Continuous AI-powered surveillance with certified analysts operating on a follow-the-sun model. Sub-6-minute mean time to acknowledge (MTTA) with zero coverage gaps across North America, EMEA, and APAC.",
+ desc: "Monitoring, triage, and escalation services can be arranged for eligible clients through an approved service scope. Coverage hours, tooling, staffing, response targets, and data sources are defined in the signed agreement.",
img: "https://media.base44.com/images/public/69d42975b7b1794c3dc01661/5c6e6baaf_generated_image.png",
- imgAlt: "GEM Enterprise Security Operations Center — analysts at curved 6-monitor workstations monitoring live SIEM dashboards, global attack maps, and threat feeds around the clock",
- tags: ["SIEM", "Log Correlation", "Real-Time Alerts"],
- tier: "Enterprise",
+ imgAlt: "Illustrative managed security monitoring interface",
+ tags: ["Monitoring", "Triage", "Escalation"],
+ tier: "Contracted service",
color: "cyan",
},
{
icon: Zap,
- title: "Incident Response",
+ title: "Incident Response Coordination",
slug: "incident-response",
- desc: "Guaranteed 4-hour activation SLA. Rapid containment, eradication, and recovery. Full digital forensics, chain-of-custody evidence management, and post-incident executive briefing.",
+ desc: "Incident triage, containment planning, evidence-preservation guidance, and recovery coordination are available according to contracted coverage. Activation windows are service-specific and are not guaranteed by this public page.",
img: "https://media.base44.com/images/public/69d42975b7b1794c3dc01661/c974a8817_generated_image.png",
- imgAlt: "GEM incident response war room — 8 cybersecurity analysts at circular workstation formation with large wall screens showing attack timeline, affected systems heatmap, and live network anomaly graphs",
- tags: ["4hr SLA", "Digital Forensics", "Evidence Preservation"],
- tier: "All Tiers",
+ imgAlt: "Illustrative incident response coordination room",
+ tags: ["Triage", "Evidence", "Recovery"],
+ tier: "Scope required",
color: "red",
},
{
icon: Eye,
- title: "Dark Web Monitoring",
+ title: "Exposure & Dark-Web Monitoring",
slug: "dark-web",
- desc: "Continuous surveillance of dark web forums, paste sites, credential markets, and breach databases. Instant alerts on exposed credentials, IP ranges, and organizational data.",
+ desc: "Authorized exposure monitoring may include approved breach-data, credential, domain, and public-risk sources. Data coverage, provider limitations, alert timing, and escalation routes are defined before activation.",
img: "https://media.base44.com/images/public/69d42975b7b1794c3dc01661/86e283cd8_generated_image.png",
- imgAlt: "GEM dark web monitoring analyst in a dark room illuminated only by monitor glow, reviewing credential leak databases and dark web forum activity on behalf of enterprise clients",
- tags: ["Credential Leaks", "IP Monitoring", "Breach Alerts"],
- tier: "Enterprise",
+ imgAlt: "Illustrative exposure-monitoring interface",
+ tags: ["Exposure", "Credentials", "Alerts"],
+ tier: "Provider dependent",
color: "purple",
},
{
icon: Lock,
- title: "Red Team & Penetration Testing",
+ title: "Security Assessment & Testing",
slug: "red-team",
- desc: "Full-scope adversarial simulations covering network penetration, web application security, social engineering, and physical security. Board-level debrief and remediation roadmap included.",
+ desc: "Authorized security assessments may cover applications, infrastructure, configuration, and selected human-process controls. Testing requires written scope, ownership verification, rules of engagement, and approved timing.",
img: "https://media.base44.com/images/public/69d42975b7b1794c3dc01661/ca12688fe_generated_image.png",
- imgAlt: "GEM red team penetration tester at dual-monitor workstation running vulnerability scanner with color-coded risk ratings and terminal commands — professional offensive security setup",
- tags: ["Pentest", "Social Engineering", "Kill Chain Simulation"],
- tier: "Enterprise",
+ imgAlt: "Illustrative authorized security testing workstation",
+ tags: ["Assessment", "Validation", "Remediation"],
+ tier: "Written authorization",
color: "orange",
},
{
icon: Building2,
- title: "Asset Recovery & Physical Security",
+ title: "Asset & Property Risk Coordination",
slug: "asset-recovery",
- desc: "High-value physical and digital asset protection and global recovery operations. Coordinated with Alliance Trust Realty for cross-jurisdiction property and financial asset recovery.",
+ desc: "GEM can coordinate risk review, documentation, specialist referrals, and authorized recovery support where appropriate. Legal authority, ownership, jurisdiction, provider capability, and engagement limits are verified before action.",
img: "https://media.base44.com/images/public/69d42975b7b1794c3dc01661/1f7e5fb1b_generated_image.png",
- imgAlt: "Alliance Trust Realty institutional real estate and asset recovery — luxury commercial property tower at dusk representing the physical asset management and recovery operations division of GEM Enterprise",
- tags: ["Physical Security", "Cross-Jurisdiction", "Asset Recovery"],
- tier: "Elite",
+ imgAlt: "Illustrative property and asset-risk management image",
+ tags: ["Risk Review", "Referrals", "Documentation"],
+ tier: "Eligibility review",
color: "amber",
},
{
icon: Globe,
- title: "Federal Compliance & Regulatory",
+ title: "Compliance Readiness Support",
slug: "federal-compliance",
- desc: "Specialized regulatory navigation for NIST SP 800-171, CMMC 2.0, SOC 2, ISO 27001, HIPAA, GDPR, and sector-specific mandates. Gap analysis, policy development, and audit readiness.",
+ desc: "Readiness support may include gap assessment, control mapping, policy development, evidence planning, and remediation tracking. Framework alignment is not certification and does not replace legal or accredited audit advice.",
img: "https://media.base44.com/images/public/69d42975b7b1794c3dc01661/2e5c40e81_generated_image.png",
- imgAlt: "GEM compliance officer at executive desk reviewing multi-screen compliance dashboard showing SOC 2 Type II, ISO 27001, NIST CSF, and HIPAA compliance scorecards with green and amber indicators",
- tags: ["NIST 800-171", "CMMC 2.0", "ISO 27001"],
- tier: "Enterprise",
+ imgAlt: "Illustrative compliance readiness dashboard",
+ tags: ["NIST", "SOC 2", "ISO 27001"],
+ tier: "Readiness support",
color: "blue",
},
];
@@ -81,72 +90,114 @@ const services = [
export default function ServicesPage() {
return (
-
- {/* HERO */}
-
+
-
+
-
- Our Services
-
Enterprise Service Suite
-
- Six interconnected disciplines forming a complete institutional security framework — from proactive threat hunting and dark web surveillance to regulatory compliance and physical asset recovery.
+
+
+ Service capabilities
+
+
+ Enterprise Service Suite
+
+
+ Services are activated only after scope, eligibility, staffing, provider,
+ jurisdiction, security, and contractual requirements have been confirmed.
+ Public descriptions do not create an SLA or guarantee availability.
All GEM services are delivered under a KYC-gated, compliance-reviewed engagement model. Begin your application to access the full service suite.
-
-
- Request Access
+
+
+
Start with a documented scope
+
+ Public information is available broadly. Services involving sensitive data,
+ regulated activities, high-value assets, monitoring, or incident response require
+ eligibility review and a signed statement of work before activation.
+
+
+
+
+ Request an assessment
+
-
- Talk to a Specialist
+
+ Talk to a specialist
diff --git a/src/app/sitemap.xml/route.ts b/src/app/sitemap.xml/route.ts
index 95772da2..81d6b509 100644
--- a/src/app/sitemap.xml/route.ts
+++ b/src/app/sitemap.xml/route.ts
@@ -3,7 +3,21 @@ const DEFAULT_APP_URL = "https://www.gemcybersecurityassist.com";
const routes = [
"/",
"/services",
+ "/services/threat-monitoring",
+ "/services/incident-response",
+ "/services/dark-web",
+ "/services/red-team",
+ "/services/asset-recovery",
+ "/services/federal-compliance",
"/intel",
+ "/intel/news",
+ "/store",
+ "/store/main",
+ "/store/campaign-hub",
+ "/store/tiktok",
+ "/store/shopify",
+ "/store/google",
+ "/store/wix",
"/resources",
"/company",
"/about",
diff --git a/src/app/store/[slug]/page.tsx b/src/app/store/[slug]/page.tsx
index 6fe1fec8..4c9e90a0 100644
--- a/src/app/store/[slug]/page.tsx
+++ b/src/app/store/[slug]/page.tsx
@@ -3,19 +3,29 @@ import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import {
+ AlertTriangle,
ArrowLeft,
ArrowRight,
CheckCircle2,
Clock3,
- ExternalLink,
LockKeyhole,
ShieldCheck,
- Sparkles,
} from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { getStoreProduct, storeProducts } from "@/lib/storeCatalog";
+const publicDescriptions = {
+ Monitoring:
+ "Proposed monitoring engagement. Coverage hours, telemetry, staffing, alert delivery, escalation, response targets, providers, and reporting are confirmed only through a signed service scope.",
+ Assessments:
+ "Proposed assessment engagement. Authorization, systems in scope, testing limits, evidence handling, deliverables, timing, and final price require written confirmation.",
+ Compliance:
+ "Proposed readiness-support engagement. Framework scope, evidence access, deliverables, limitations, and qualified legal or accredited audit support are confirmed before acceptance.",
+ Consultations:
+ "Proposed advisory engagement. Advisor availability, subject matter, duration, deliverables, limitations, and final price require written confirmation.",
+} as const;
+
type ProductPageProps = {
params: Promise<{ slug: string }>;
};
@@ -28,30 +38,38 @@ export async function generateMetadata({ params }: ProductPageProps): Promise
+
+
+
+
+ Request-only catalogue item: this page does not confirm current
+ availability, provider coverage, licensing, checkout readiness, price, fulfillment,
+ subscription activation, inventory, SLA, refund terms, or a guaranteed outcome.
+
+
+
+
- Back to GEM Security Store
+ Back to GEM catalogue
- {product.checkoutUrl ? (
-
-
- Continue to Secure Checkout
-
-
- ) : (
-
-
- Request This Service
-
-
- )}
+
+
+ Request Availability Review
+
+
- Speak With an Advisor
+ Review Service Limitations
- Final scope, access requirements, and delivery terms are confirmed during secure onboarding.
+ No payment or external checkout should be used until GEM confirms the seller,
+ provider, final price, scope, terms, and fulfillment path in writing.
- {product.suitableFor.map((item) => (
+ {[
+ "Contact details and the intended business outcome",
+ "Evidence of authority over systems, accounts, or assets in scope",
+ "Relevant jurisdiction, timing, environment, and current constraints",
+ "Acceptance of the final written proposal and service terms",
+ ].map((item) => (
- Start with this solution or speak with GEM to confirm the best service path for your organization.
+ GEM will confirm whether the requested offering can be delivered and provide the
+ applicable terms before any payment, sensitive-data transfer, or activation.
- {product.checkoutUrl ? (
-
-
- Open Shopify Checkout
-
-
- ) : (
-
- Request This Service
-
- )}
+
+ Submit Product Enquiry
+
- Browse Other Solutions
+ Browse Other Catalogue Items
diff --git a/src/app/store/page.tsx b/src/app/store/page.tsx
index 42e83ed3..4793cc5a 100644
--- a/src/app/store/page.tsx
+++ b/src/app/store/page.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import Link from "next/link";
import {
+ AlertTriangle,
ArrowRight,
BadgeCheck,
ExternalLink,
@@ -15,11 +16,15 @@ import { Button } from "@/components/ui/button";
import { StorefrontProductGrid } from "@/components/store/StorefrontProductGrid";
import { storefrontDefinitions, storefrontProducts } from "@/lib/storefrontCatalog";
import { TIKTOK_MAIN_STORE_URL } from "@/lib/storefrontDestinations";
+import {
+ catalogueRelianceNotice,
+ publicStorefrontStatus,
+} from "@/lib/storefrontPresentation";
export const metadata: Metadata = {
- title: "GEM Store | All Products and Store Channels",
+ title: "GEM Product & Service Catalogue",
description:
- "Browse all GEM Enterprise products and navigate the Main Store, Campaign Hub, TikTok Shop, Shopify, Google Merchant, and Wix Store subpages.",
+ "Browse proposed GEM Enterprise products and service packages and submit an enquiry for availability, scope, price, licensing, and fulfillment review.",
};
const categories = [
@@ -28,35 +33,64 @@ const categories = [
];
const trustItems = [
- { icon: Truck, title: "Flexible delivery", text: "Physical, digital, and service products are clearly identified." },
- { icon: ShieldCheck, title: "Secure routing", text: "External checkout appears only for approved connected destinations." },
- { icon: RefreshCcw, title: "Channel-ready", text: "Products can be organized across Shopify, TikTok, Google, Wix, and Campaign Hub." },
- { icon: BadgeCheck, title: "GEM supported", text: "Customer requests continue into GEM onboarding and support." },
+ {
+ icon: Truck,
+ title: "Delivery confirmed in writing",
+ text: "Physical, digital, and service delivery terms are confirmed before an order or engagement is accepted.",
+ },
+ {
+ icon: ShieldCheck,
+ title: "No assumed activation",
+ text: "A catalogue entry or external link does not activate monitoring, software, support, or an SLA.",
+ },
+ {
+ icon: RefreshCcw,
+ title: "Channels require verification",
+ text: "Shopify, TikTok, Google, Wix, Facebook, and campaign destinations are used only after ownership and fulfillment checks.",
+ },
+ {
+ icon: BadgeCheck,
+ title: "Scope before payment",
+ text: "GEM confirms provider capability, licensing, final price, taxes, refunds, and fulfillment before acceptance.",
+ },
];
export default function StorePage() {
return (
+
+
- All products in one store,
- organized into clear subpages.
+ Explore products and services,
+ then request written confirmation.
- Browse the combined GEM catalog here, then open the Main Store, Campaign Hub, TikTok Shop, Shopify, Google Merchant, or Wix Store page for channel-specific products and actions.
+ Review proposed offerings and channel pages. GEM confirms whether an item is
+ operationally available, who provides it, what is included, the final price,
+ delivery terms, refund terms, and any eligibility requirements before acceptance.
- Browse All Products
+
+ Browse Catalogue
+
- Open Main Store
+ Submit an Enquiry
@@ -66,7 +100,7 @@ export default function StorePage() {
{trustItems.map(({ icon: Icon, title, text }) => (
-
+
{title}
{text}
@@ -77,11 +111,15 @@ export default function StorePage() {
- Store pages
+ Catalogue channels
-
Choose the correct store subpage
+
+ Review each channel before leaving GEM
+
- Every store now has its own page, product selection, status, and external destination where one is approved.
+ An external destination is shown only as a channel reference. Confirm the domain,
+ seller identity, product terms, payment amount, refund policy, and fulfillment
+ process before submitting payment or personal information.
- Search the combined catalog by product name, category, description, or SKU. Add unconnected products to a GEM order request or open an approved checkout where available.
+ Search by product name, category, description, or SKU. Add items to an enquiry;
+ this interface does not create a cart, charge a payment method, reserve inventory,
+ start a subscription, or activate a service.
diff --git a/src/components/ProductionDisclosure.tsx b/src/components/ProductionDisclosure.tsx
new file mode 100644
index 00000000..bf444384
--- /dev/null
+++ b/src/components/ProductionDisclosure.tsx
@@ -0,0 +1,25 @@
+import Link from "next/link";
+import { ShieldAlert } from "lucide-react";
+
+export function ProductionDisclosure() {
+ return (
+
+ );
+}
diff --git a/src/components/store/HomeStoreShowcase.tsx b/src/components/store/HomeStoreShowcase.tsx
index 0e402c79..510d772c 100644
--- a/src/components/store/HomeStoreShowcase.tsx
+++ b/src/components/store/HomeStoreShowcase.tsx
@@ -3,13 +3,12 @@ import { ArrowRight, Package, ShieldCheck, ShoppingBag } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { storefrontDefinitions, storefrontProducts } from "@/lib/storefrontCatalog";
-
-function formatMoney(value: number) {
- return new Intl.NumberFormat("en-US", {
- style: "currency",
- currency: "USD",
- }).format(value);
-}
+import {
+ catalogueRelianceNotice,
+ formatCataloguePrice,
+ publicAvailabilityLabel,
+ publicProductDescription,
+} from "@/lib/storefrontPresentation";
export function HomeStoreShowcase() {
const featuredProducts = storefrontProducts.slice(0, 3);
@@ -25,13 +24,15 @@ export function HomeStoreShowcase() {
- GEM Enterprise Store
+ Request-only catalogue
- All products, organized into dedicated store pages
+ Explore proposed products and service packages
- Enter the Main Store for the complete catalog, or use Campaign Hub, TikTok Shop, Shopify, Google Merchant, and Wix Store as focused subpages inside the GEM website.
+ Browse catalogue pages, then submit an enquiry. A displayed item, price, or
+ channel does not mean that payment, inventory, licensing, fulfillment, or service
+ activation has been approved.
@@ -62,58 +81,94 @@ export function StorefrontPage({
{activeEyebrow}
{activeTitle}
-
{activeDescription}
+
+ {activeDescription} This page is a catalogue and planning surface, not proof that
+ the external channel, checkout, inventory, licensing, or fulfillment is active.
+