Add page-view analytics, product counters, SSL expiry, and business renewal.

Auto-count storefront page views with 6-month event retention and lifetime counters, track product visit/cart/sale stats, persist SSL cert expiry with daily probes, and support owner titles plus annual contract renewal.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-26 10:13:06 +03:30
co-authored by Cursor
parent 6cd0b009ef
commit 92601ae729
39 changed files with 1013 additions and 198 deletions
@@ -1,25 +1,59 @@
export const WEBSITE_VIEW_KINDS = [
'website',
'product',
'portfolio',
'blog',
export const WEBSITE_PAGE_KINDS = [
'home',
'portfolio_list',
'portfolio_detail',
'product_list',
'product_detail',
'store_item_list',
'store_item_detail',
'blog_list',
'blog_detail',
'video_list',
'video_detail',
] as const;
export type WebsiteViewKind = (typeof WEBSITE_VIEW_KINDS)[number];
export type WebsitePageKind = (typeof WEBSITE_PAGE_KINDS)[number];
export function isWebsiteViewKind(value: unknown): value is WebsiteViewKind {
/** @deprecated Prefer WebsitePageKind — kept for dashboard chart query aliases. */
export type WebsiteViewKind = WebsitePageKind | 'website' | 'product' | 'portfolio' | 'blog';
const DETAIL_KINDS = new Set<WebsitePageKind>([
'portfolio_detail',
'product_detail',
'store_item_detail',
'blog_detail',
'video_detail',
]);
/** Legacy chart / POST aliases → canonical page kinds. */
const KIND_ALIASES: Record<string, WebsitePageKind> = {
website: 'home',
product: 'product_detail',
portfolio: 'portfolio_detail',
blog: 'blog_detail',
};
export function isWebsitePageKind(value: unknown): value is WebsitePageKind {
return (
typeof value === 'string' &&
(WEBSITE_VIEW_KINDS as readonly string[]).includes(value)
(WEBSITE_PAGE_KINDS as readonly string[]).includes(value)
);
}
/** Maps home dashboard chart ids to analytics view kinds. */
export const HOME_CHART_VIEW_KIND: Partial<
Record<string, WebsiteViewKind>
> = {
website_views_30d: 'website',
product_views_30d: 'product',
portfolio_views_30d: 'portfolio',
blog_views_30d: 'blog',
export function normalizeWebsitePageKind(value: string): WebsitePageKind | null {
if (isWebsitePageKind(value)) return value;
const aliased = KIND_ALIASES[value];
return aliased ?? null;
}
export function pageKindRequiresEntity(kind: WebsitePageKind): boolean {
return DETAIL_KINDS.has(kind);
}
/** Maps home dashboard chart ids to analytics page kinds. */
export const HOME_CHART_VIEW_KIND: Partial<Record<string, WebsitePageKind>> = {
website_views_30d: 'home',
product_views_30d: 'product_detail',
portfolio_views_30d: 'portfolio_detail',
blog_views_30d: 'blog_detail',
};