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:
co-authored by
Cursor
parent
6cd0b009ef
commit
92601ae729
@@ -12,7 +12,11 @@ import { Prisma } from '@prisma/client';
|
||||
import { ArvanDnsService } from '../arvan-dns/arvan-dns.service';
|
||||
import { AuthUser } from '../auth/auth.types';
|
||||
import { PermissionsService } from '../auth/permissions.service';
|
||||
import { probeTlsHost } from '../common/tls-probe';
|
||||
import {
|
||||
earliestTlsExpiry,
|
||||
probeTlsHost,
|
||||
probeTlsHostDetailed,
|
||||
} from '../common/tls-probe';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { WebsiteDeployAgentService } from '../website-deploy/website-deploy-agent.service';
|
||||
import { DisableDomainDto } from './dto/disable-domain.dto';
|
||||
@@ -26,6 +30,7 @@ type DomainRow = {
|
||||
businessId: bigint;
|
||||
businessName: string;
|
||||
sslEnabled: boolean;
|
||||
sslExpiresAt: Date | null;
|
||||
isActive: boolean;
|
||||
expiresAt: Date | null;
|
||||
createdAt: Date;
|
||||
@@ -71,6 +76,7 @@ export class DomainAdminService {
|
||||
d.business_id AS "businessId",
|
||||
b.name AS "businessName",
|
||||
d.ssl_enabled AS "sslEnabled",
|
||||
d.ssl_expires_at AS "sslExpiresAt",
|
||||
d.is_active AS "isActive",
|
||||
d.expires_at AS "expiresAt",
|
||||
d.created_at AS "createdAt",
|
||||
@@ -90,7 +96,19 @@ export class DomainAdminService {
|
||||
`),
|
||||
]);
|
||||
|
||||
return { items: rows, total: totalRow[0]?.total ?? 0, page, pageSize };
|
||||
const now = Date.now();
|
||||
const items = rows.map((row) => {
|
||||
const certStillValid =
|
||||
!row.sslExpiresAt || row.sslExpiresAt.getTime() > now;
|
||||
return {
|
||||
...row,
|
||||
// List badge: issued/probed OK and cert not past notAfter.
|
||||
sslEnabled: row.sslEnabled && certStillValid,
|
||||
sslExpiresAt: row.sslExpiresAt,
|
||||
};
|
||||
});
|
||||
|
||||
return { items, total: totalRow[0]?.total ?? 0, page, pageSize };
|
||||
}
|
||||
|
||||
async syncSsl(actor: AuthUser) {
|
||||
@@ -185,26 +203,28 @@ export class DomainAdminService {
|
||||
const targets: Array<{ id: bigint; host: string; deploySlug: string | null }> = [];
|
||||
|
||||
for (const domain of candidates) {
|
||||
const apexOk = await probeTlsHost(domain.host);
|
||||
const apexProbe = await probeTlsHostDetailed(domain.host);
|
||||
const wwwHost = domain.host.startsWith('www.')
|
||||
? domain.host
|
||||
: `www.${domain.host}`;
|
||||
const wwwOk = await probeTlsHost(wwwHost);
|
||||
const ok = apexOk && wwwOk;
|
||||
const wwwProbe = await probeTlsHostDetailed(wwwHost);
|
||||
const ok = apexProbe.ok && wwwProbe.ok;
|
||||
if (ok) {
|
||||
if (!domain.sslEnabled) {
|
||||
await this.prisma.domain.update({
|
||||
where: { id: domain.id },
|
||||
data: { sslEnabled: true },
|
||||
});
|
||||
}
|
||||
const sslExpiresAt = earliestTlsExpiry(apexProbe, wwwProbe);
|
||||
await this.prisma.domain.update({
|
||||
where: { id: domain.id },
|
||||
data: {
|
||||
sslEnabled: true,
|
||||
...(sslExpiresAt ? { sslExpiresAt } : {}),
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (domain.sslEnabled) {
|
||||
await this.prisma.domain.update({
|
||||
where: { id: domain.id },
|
||||
data: { sslEnabled: false },
|
||||
data: { sslEnabled: false, sslExpiresAt: null },
|
||||
});
|
||||
}
|
||||
targets.push(domain);
|
||||
@@ -228,14 +248,21 @@ export class DomainAdminService {
|
||||
host: domain.host,
|
||||
slug: domain.deploySlug,
|
||||
});
|
||||
const ok = await probeTlsHost(domain.host);
|
||||
const apexProbe = await probeTlsHostDetailed(domain.host);
|
||||
const wwwHost = domain.host.startsWith('www.')
|
||||
? domain.host
|
||||
: `www.${domain.host}`;
|
||||
const wwwOk = ok && (await probeTlsHost(wwwHost));
|
||||
const wwwProbe = await probeTlsHostDetailed(wwwHost);
|
||||
const wwwOk = apexProbe.ok && wwwProbe.ok;
|
||||
const sslExpiresAt = wwwOk
|
||||
? earliestTlsExpiry(apexProbe, wwwProbe)
|
||||
: null;
|
||||
await this.prisma.domain.update({
|
||||
where: { id: domain.id },
|
||||
data: { sslEnabled: wwwOk },
|
||||
data: {
|
||||
sslEnabled: wwwOk,
|
||||
sslExpiresAt,
|
||||
},
|
||||
});
|
||||
if (wwwOk) {
|
||||
issued.push(domain.host);
|
||||
@@ -297,10 +324,12 @@ export class DomainAdminService {
|
||||
customer: { host: customerHost, status: 'ok' },
|
||||
};
|
||||
|
||||
let apexOk = await probeTlsHost(apex);
|
||||
let wwwOk = await probeTlsHost(wwwHost);
|
||||
let apexProbe = await probeTlsHostDetailed(apex);
|
||||
let wwwProbe = await probeTlsHostDetailed(wwwHost);
|
||||
let businessOk = await probeTlsHost(businessHost);
|
||||
let customerOk = await probeTlsHost(customerHost);
|
||||
let apexOk = apexProbe.ok;
|
||||
let wwwOk = wwwProbe.ok;
|
||||
|
||||
const storefrontNeedsIssue = !apexOk || !wwwOk;
|
||||
|
||||
@@ -325,8 +354,10 @@ export class DomainAdminService {
|
||||
} else {
|
||||
try {
|
||||
await this.websiteDeployAgent.issueSsl({ host: apex, slug });
|
||||
apexOk = await probeTlsHost(apex);
|
||||
wwwOk = await probeTlsHost(wwwHost);
|
||||
apexProbe = await probeTlsHostDetailed(apex);
|
||||
wwwProbe = await probeTlsHostDetailed(wwwHost);
|
||||
apexOk = apexProbe.ok;
|
||||
wwwOk = wwwProbe.ok;
|
||||
hosts.apex = apexOk
|
||||
? {
|
||||
host: apex,
|
||||
@@ -416,9 +447,22 @@ export class DomainAdminService {
|
||||
}
|
||||
|
||||
const storefrontOk = apexOk && wwwOk;
|
||||
// Re-probe apex/www once more when already-ok so we persist current cert expiry.
|
||||
if (storefrontOk && (!apexProbe.expiresAt || !wwwProbe.expiresAt)) {
|
||||
apexProbe = await probeTlsHostDetailed(apex);
|
||||
wwwProbe = await probeTlsHostDetailed(wwwHost);
|
||||
apexOk = apexProbe.ok;
|
||||
wwwOk = wwwProbe.ok;
|
||||
}
|
||||
const sslExpiresAt =
|
||||
apexOk && wwwOk ? earliestTlsExpiry(apexProbe, wwwProbe) : null;
|
||||
|
||||
const updated = await this.prisma.domain.update({
|
||||
where: { id: domainId },
|
||||
data: { sslEnabled: storefrontOk },
|
||||
data: {
|
||||
sslEnabled: storefrontOk && apexOk && wwwOk,
|
||||
sslExpiresAt: storefrontOk && apexOk && wwwOk ? sslExpiresAt : null,
|
||||
},
|
||||
});
|
||||
|
||||
const parts = [hosts.apex, hosts.www, hosts.business, hosts.customer];
|
||||
@@ -434,6 +478,7 @@ export class DomainAdminService {
|
||||
status: failed.length === 0 ? ('ok' as const) : ('partial' as const),
|
||||
host: apex,
|
||||
sslEnabled: updated.sslEnabled,
|
||||
sslExpiresAt: updated.sslExpiresAt?.toISOString() ?? null,
|
||||
hosts,
|
||||
issued: issued.map((p) => p.host),
|
||||
failed: failed.map((p) => ({ host: p.host, error: p.detail || 'failed' })),
|
||||
@@ -579,7 +624,10 @@ export class DomainAdminService {
|
||||
|
||||
return this.prisma.domain.update({
|
||||
where: { id: domainId },
|
||||
data: { sslEnabled: dto.sslEnabled },
|
||||
data: {
|
||||
sslEnabled: dto.sslEnabled,
|
||||
...(dto.sslEnabled ? {} : { sslExpiresAt: null }),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user