Files
solution-erp/fe-admin/src/lib/realtime.ts
pqhuy1987 66c1a5c170
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m52s
[CLAUDE] Rebrand: 3 domain huypham.vn → solutions.com.vn + migrate script
User request: anh trỏ 3 subdomain mới về VPS IP 103.124.94.38:
  - api.huypham.vn        → api.solutions.com.vn
  - admin.huypham.vn      → admin.solutions.com.vn
  - user.huypham.vn       → eoffice.solutions.com.vn

Verified DNS: cả 3 resolve 103.124.94.38 ✓

Update 17 file repo:
FE (4): fe-admin/.env.production + fe-user/.env.production
        (VITE_API_BASE_URL → https://api.solutions.com.vn)
        fe-admin/src/lib/{api,realtime}.ts + fe-user equivalents (comment)
BE (1): appsettings.Production.json.example — CORS AllowedOrigins
CI/CD (1): .gitea/workflows/deploy.yml — smoke test URL
Scripts (3): setup-iis-sites (DomainApi/Admin/User), setup-ssl (3 host),
             deploy-all (verify curls)
Docs (5): STATUS, HANDOFF, PROJECT-MAP, vps-setup, gotchas
Skill (1): iis-deploy-runbook — 3 site table + description
Email admin@huypham.vn giữ nguyên (Let's Encrypt contact — không phải
domain serve).

Thêm scripts/migrate-domains.ps1 — 1-shot VPS migration:
  1. Pre-flight: resolve DNS 3 domain → verify IP VPS khớp
  2. Add HTTP binding mới cho 3 IIS site (giữ binding cũ làm fallback)
  3. Run win-acme xin 3 cert Let's Encrypt qua HTTP-01 challenge
     (auto add HTTPS binding + http→https redirect)
  4. Verify /health/live + /health/ready + 2 FE endpoint
  5. (Optional -RemoveOld) xóa binding huypham.vn sau verify OK
Rollback: nếu fail, binding cũ vẫn active → site serve qua huypham.vn.

Anh chạy trên VPS:
  cd C:\solution-erp\scripts  ;  .\migrate-domains.ps1
  # Sau 1-2 ngày verify stable:
  .\migrate-domains.ps1 -RemoveOld -SkipCert
2026-04-24 09:43:05 +07:00

49 lines
1.6 KiB
TypeScript

import { HubConnection, HubConnectionBuilder, HubConnectionState, LogLevel } from '@microsoft/signalr'
import { TOKEN_KEY } from '@/lib/api'
// Hub URL resolution:
// - Dev: Vite proxy forwards /api → :5443 but SignalR bypasses axios, so we
// hit the API origin directly from the browser.
// - Prod: VITE_API_BASE_URL (https://api.solutions.com.vn)
const HUB_URL = (import.meta.env.VITE_API_BASE_URL ?? window.location.origin) + '/hubs/notifications'
let connection: HubConnection | null = null
let startPromise: Promise<void> | null = null
/** Lazily starts (or reuses) a single hub connection. Token read on connect. */
export async function ensureConnection(): Promise<HubConnection> {
if (connection && connection.state === HubConnectionState.Connected) return connection
if (!connection) {
connection = new HubConnectionBuilder()
.withUrl(HUB_URL, {
accessTokenFactory: () => localStorage.getItem(TOKEN_KEY) ?? '',
})
.withAutomaticReconnect([0, 2_000, 5_000, 10_000, 15_000]) // exponential-ish backoff
.configureLogging(LogLevel.Warning)
.build()
}
if (connection.state === HubConnectionState.Disconnected) {
startPromise ??= connection.start().catch(err => {
startPromise = null
throw err
})
await startPromise
startPromise = null
}
return connection
}
/** Stops + forgets the connection. Call on logout. */
export async function stopConnection(): Promise<void> {
if (!connection) return
try {
await connection.stop()
} catch {
/* ignore */
}
connection = null
startPromise = null
}