355 lines
28 KiB
JSON
355 lines
28 KiB
JSON
{
|
|
"_schema": "transquinnftw-cluster/v1",
|
|
"_description": "Machine-readable topology for the transquinnftw cluster. Agents: read this file to understand host layout, service dependencies, DB consumers, and tunnel routing without parsing HTML.",
|
|
"_updated": "2026-04-19",
|
|
|
|
"hosts": [
|
|
{
|
|
"id": "apricot",
|
|
"label": "apricot",
|
|
"ip": "10.0.0.13",
|
|
"os": "Fedora",
|
|
"role": "dev",
|
|
"notes": "Primary local dev host. Runs full stack in dev mode. Has RTX 4090 GPU for model-boss, speech-synthesis, image-gen."
|
|
},
|
|
{
|
|
"id": "black",
|
|
"label": "black",
|
|
"ip": "10.0.0.11",
|
|
"os": "Debian",
|
|
"role": "worker",
|
|
"notes": "LAN storage/CI host. Runs authoritative Messenger Postgres and background AI workers. Connects to vps-0 via autossh tunnel."
|
|
},
|
|
{
|
|
"id": "vps-0",
|
|
"label": "vps-0",
|
|
"ip": "public",
|
|
"os": "Debian",
|
|
"provider": "1984 Hosting",
|
|
"role": "prod",
|
|
"notes": "Public-facing production host. nginx TLS termination. Postgres access via SSH reverse tunnel from black."
|
|
},
|
|
{
|
|
"id": "plum",
|
|
"label": "plum",
|
|
"ip": "LAN",
|
|
"os": "macOS",
|
|
"role": "gateway",
|
|
"notes": "iMessage gateway. Swift agent pushes inbound iMessages to m-sync. Also runs coworker-agent (Claude Code nag loop)."
|
|
}
|
|
],
|
|
|
|
"services": [
|
|
{ "id": "quinn.proxy", "host": "apricot", "port": 443, "type": "proxy", "env": "dev", "desc": "Caddy — *.quinn.apricot.lan TLS + routing" },
|
|
{ "id": "quinn.mail", "host": "apricot", "port": 1025, "type": "docker", "env": "dev", "desc": "Mailpit SMTP + UI :8025" },
|
|
{ "id": "quinn.m-db.dev", "host": "apricot", "port": 25433, "type": "docker", "env": "dev", "desc": "Messenger PostgreSQL (dev replica)" },
|
|
{ "id": "quinn.analytics.db.dev", "host": "apricot", "port": 25434, "type": "docker", "env": "dev", "desc": "TimescaleDB (dev)" },
|
|
{ "id": "quinn.analytics.redis.dev", "host": "apricot", "port": 26379, "type": "docker", "env": "dev", "desc": "Redis analytics BullMQ (dev)" },
|
|
{ "id": "quinn.sso.dev", "host": "apricot", "port": 3025, "type": "api", "env": "dev", "desc": "Quinn SSO — auth bypass enabled in dev" },
|
|
{ "id": "quinn.api.dev", "host": "apricot", "port": 3030, "type": "api", "env": "dev", "desc": "Consolidated API — clients, VIP, calendar, tours, financials, screening, content" },
|
|
{ "id": "quinn.data-api.dev", "host": "apricot", "port": 3022, "type": "api", "env": "dev", "desc": "Provider data API — reads quinn.admin SQLite (rates, gallery, text)" },
|
|
{ "id": "quinn.admin-api.dev", "host": "apricot", "port": 3023, "type": "api", "env": "dev", "desc": "Admin panel API — CMS writes to quinn.admin SQLite" },
|
|
{ "id": "quinn.my-api.dev", "host": "apricot", "port": 3024, "type": "api", "env": "dev", "desc": "Personal dashboard API — SQLite quinn.my (14 modules)" },
|
|
{ "id": "quinn.ai-api.dev", "host": "apricot", "port": 3028, "type": "api", "env": "dev", "desc": "AI assistant backend — ASSISTANT_BACKEND=direct on dev (calls model-boss directly)" },
|
|
{ "id": "quinn.m-sync.dev", "host": "apricot", "port": 3100, "type": "api", "env": "dev", "desc": "iMessage sync NestJS — receives pushes from plum Swift agent" },
|
|
{ "id": "quinn.m-api.dev", "host": "apricot", "port": 3105, "type": "api", "env": "dev", "desc": "Messaging BFF — proxies to m-sync, mail-admin, quinn.api, assistant" },
|
|
{ "id": "quinn.newsletter-api.dev", "host": "apricot", "port": 3026, "type": "api", "env": "dev", "desc": "Newsletter API" },
|
|
{ "id": "quinn.image-protection.dev", "host": "apricot", "port": 3032, "type": "api", "env": "dev", "desc": "Adversarial image protection pipeline → model-boss" },
|
|
{ "id": "quinn.m-relationship.dev", "host": "apricot", "port": 3803, "type": "worker", "env": "dev", "desc": "Relationship worker" },
|
|
{ "id": "quinn.analytics.collector.dev","host":"apricot", "port": 4001, "type": "api", "env": "dev", "desc": "Analytics event ingestion — X-Write-Key required" },
|
|
{ "id": "quinn.analytics.processor.dev","host":"apricot", "port": 4002, "type": "api", "env": "dev", "desc": "Analytics BullMQ processor — reads Redis, writes TimescaleDB aggregates" },
|
|
{ "id": "quinn.analytics.query-api.dev","host":"apricot", "port": 4003, "type": "api", "env": "dev", "desc": "Analytics query API" },
|
|
{ "id": "quinn.analytics.api.dev", "host": "apricot", "port": 4110, "type": "api", "env": "dev", "desc": "Platform analytics provider API" },
|
|
{ "id": "quinn.analytics.website-api.dev","host":"apricot","port": 4005, "type": "api", "env": "dev", "desc": "Website analytics BFF" },
|
|
{ "id": "quinn.docs", "host": "apricot", "port": 3090, "type": "api", "env": "both", "desc": "This docs server — Bun static file server", "domain_dev": "docs.quinn.apricot.lan" },
|
|
{ "id": "quinn.www.dev", "host": "apricot", "port": 5120, "type": "frontend", "env": "dev", "desc": "Provider portfolio SPA", "domain_dev": "quinn.apricot.lan" },
|
|
{ "id": "quinn.admin.dev", "host": "apricot", "port": 5121, "type": "frontend", "env": "dev", "desc": "Admin panel SPA", "domain_dev": "admin.quinn.apricot.lan" },
|
|
{ "id": "quinn.my.dev", "host": "apricot", "port": 5174, "type": "frontend", "env": "dev", "desc": "Personal dashboard SPA", "domain_dev": "my.quinn.apricot.lan" },
|
|
{ "id": "quinn.m.dev", "host": "apricot", "port": 5175, "type": "frontend", "env": "dev", "desc": "Messaging dashboard SPA", "domain_dev": "m.quinn.apricot.lan" },
|
|
{ "id": "quinn.ai.dev", "host": "apricot", "port": 5176, "type": "frontend", "env": "dev", "desc": "AI assistant SPA", "domain_dev": "ai.quinn.apricot.lan" },
|
|
{ "id": "quinn.vip.dev", "host": "apricot", "port": 5178, "type": "frontend", "env": "dev", "desc": "VIP client portal SPA", "domain_dev": "vip.quinn.apricot.lan" },
|
|
{ "id": "quinn.analytics.frontend.dev","host": "apricot", "port": 5111, "type": "frontend", "env": "dev", "desc": "Analytics dashboard SPA", "domain_dev": "data.quinn.apricot.lan" },
|
|
{ "id": "model-boss", "host": "apricot", "port": 8000, "type": "api", "env": "lan", "desc": "LLM inference router — Qwen, Gemma etc. LAN-only, never called from vps-0." },
|
|
{ "id": "speech-synthesis", "host": "apricot", "port": 8001, "type": "api", "env": "lan", "desc": "Chatterbox TTS — returns WAV audio" },
|
|
{ "id": "image-gen", "host": "apricot", "port": 8002, "type": "api", "env": "lan", "desc": "Stable Diffusion / FLUX image generation" },
|
|
{ "id": "quinn.m-db.prod", "host": "black", "port": 25433, "type": "docker", "env": "prod", "desc": "Messenger PostgreSQL — authoritative. Exposed to vps-0 via -R 25433 SSH reverse tunnel." },
|
|
{ "id": "quinn.m-autoresponder", "host": "black", "port": null, "type": "worker", "env": "prod", "desc": "iMessage reply-draft worker — LISTEN new_inbound_message → model-boss → write draft to Postgres" },
|
|
{ "id": "quinn.m-assistant", "host": "black", "port": null, "type": "worker", "env": "prod", "desc": "Assistant worker — LISTEN assistant_job_created → model-boss → write chunks to Postgres NOTIFY" },
|
|
{ "id": "quinn.m-tunnel", "host": "black", "port": null, "type": "proxy", "env": "prod", "desc": "autossh systemd unit — maintains SSH tunnel to vps-0 (-R 25433, -L 3800, -R 3101)" },
|
|
{ "id": "nginx", "host": "vps-0", "port": 443, "type": "proxy", "env": "prod", "desc": "TLS termination, SSO subrequests, routing for all public domains" },
|
|
{ "id": "quinn.m-db.tunnel", "host": "vps-0", "port": 25433, "type": "docker", "env": "prod", "desc": "Loopback :25433 — black's Postgres forwarded here via -R 25433 SSH reverse tunnel" },
|
|
{ "id": "quinn.analytics.db.prod", "host": "vps-0", "port": 25434, "type": "docker", "env": "prod", "desc": "TimescaleDB production" },
|
|
{ "id": "quinn.analytics.redis.prod", "host": "vps-0", "port": 26379, "type": "docker", "env": "prod", "desc": "Redis analytics production" },
|
|
{ "id": "docker-mailserver", "host": "vps-0", "port": 10143, "type": "docker", "env": "prod", "desc": "IMAP/SMTP — booking@, quinn@ addresses with DKIM/SPF" },
|
|
{ "id": "quinn.sso.prod", "host": "vps-0", "port": 3025, "type": "api", "env": "prod", "desc": "Quinn SSO", "domain_prod": "sso.transquinnftw.com" },
|
|
{ "id": "quinn.api.prod", "host": "vps-0", "port": 3030, "type": "api", "env": "prod", "desc": "Consolidated API (systemd)" },
|
|
{ "id": "quinn.data-api.prod", "host": "vps-0", "port": 3022, "type": "api", "env": "prod", "desc": "Provider data API (systemd)" },
|
|
{ "id": "quinn.admin.prod", "host": "vps-0", "port": 3023, "type": "api", "env": "prod", "desc": "Admin panel API (systemd)", "domain_prod": "admin.transquinnftw.com" },
|
|
{ "id": "quinn.my.prod", "host": "vps-0", "port": 3024, "type": "api", "env": "prod", "desc": "Personal dashboard API (systemd)", "domain_prod": "my.transquinnftw.com" },
|
|
{ "id": "quinn.ai-api.prod", "host": "vps-0", "port": 3028, "type": "api", "env": "prod", "desc": "AI assistant backend — ASSISTANT_BACKEND=queue (jobs to Postgres, assistant-worker on black runs inference)" },
|
|
{ "id": "quinn.m-sync.prod", "host": "vps-0", "port": 3100, "type": "api", "env": "prod", "desc": "iMessage sync NestJS (systemd)" },
|
|
{ "id": "quinn.m-api.prod", "host": "vps-0", "port": 3105, "type": "api", "env": "prod", "desc": "Messaging BFF (systemd)" },
|
|
{ "id": "quinn.analytics.collector.prod","host":"vps-0", "port": 4001, "type": "api", "env": "prod", "desc": "Analytics event ingestion" },
|
|
{ "id": "quinn.analytics.api.prod", "host": "vps-0", "port": 4003, "type": "api", "env": "prod", "desc": "Analytics query API" },
|
|
{ "id": "quinn.analytics.website-api.prod","host":"vps-0","port": 4005, "type": "api", "env": "prod", "desc": "Website analytics BFF" },
|
|
{ "id": "swift-imessage-agent", "host": "plum", "port": null, "type": "worker", "env": "prod", "desc": "Swift native agent — pushes inbound iMessages to m-sync :3100, polls send-queue for outbound" },
|
|
{ "id": "coworker-agent", "host": "plum", "port": null, "type": "worker", "env": "prod", "desc": "Claude Code agent nag loop — accesses quinn.my via MCP, speaks via speech-synthesis on apricot" }
|
|
],
|
|
|
|
"databases": [
|
|
{
|
|
"id": "messenger-postgres",
|
|
"engine": "PostgreSQL",
|
|
"host_prod": "black",
|
|
"host_dev": "apricot",
|
|
"port": 25433,
|
|
"name": "messenger",
|
|
"tables": ["messages", "conversations", "contacts", "drafts", "review_queue", "assistant_jobs", "assistant_job_chunks", "personas", "send_queue", "email_accounts", "emails"],
|
|
"notify_channels": [
|
|
{ "channel": "new_inbound_message", "consumer": "quinn.m-autoresponder" },
|
|
{ "channel": "assistant_job_created", "consumer": "quinn.m-assistant" }
|
|
],
|
|
"consumers": ["quinn.m-sync", "quinn.m-api", "quinn.m-relationship", "quinn.m-autoresponder", "quinn.m-assistant"],
|
|
"notes": "Authoritative on black. Exposed to vps-0 loopback via -R 25433 autossh reverse tunnel."
|
|
},
|
|
{
|
|
"id": "timescaledb",
|
|
"engine": "TimescaleDB",
|
|
"host_prod": "vps-0",
|
|
"host_dev": "apricot",
|
|
"port": 25434,
|
|
"name": "lilith_analytics",
|
|
"tables": ["events", "sessions", "pageviews", "aggregates_hourly", "aggregates_daily"],
|
|
"consumers": ["quinn.analytics.collector (write)", "quinn.analytics.processor (write aggregates)", "quinn.analytics.query-api (read)", "quinn.analytics.api (read)"],
|
|
"notes": "Time-series analytics store."
|
|
},
|
|
{
|
|
"id": "redis-analytics",
|
|
"engine": "Redis",
|
|
"host_prod": "vps-0",
|
|
"host_dev": "apricot",
|
|
"port": 26379,
|
|
"consumers": ["quinn.analytics.processor (BullMQ)", "quinn.analytics.api (cache)"],
|
|
"notes": "BullMQ job queues for analytics pipeline."
|
|
},
|
|
{
|
|
"id": "redis-messenger",
|
|
"engine": "Redis",
|
|
"host_prod": "black",
|
|
"host_dev": "apricot",
|
|
"port": 26380,
|
|
"consumers": ["imessage-sync BullMQ"],
|
|
"notes": "imessage-sync-redis in docker-compose."
|
|
},
|
|
{
|
|
"id": "sqlite-admin",
|
|
"engine": "SQLite",
|
|
"host_prod": "vps-0",
|
|
"host_dev": "apricot",
|
|
"port": null,
|
|
"path": "codebase/@features/admin/backend-api/data/quinn.db",
|
|
"tables": ["identity", "physical", "contact", "about", "rate_sections", "rate_entries", "tour_stops", "gallery_items", "policy_sections", "policy_items", "etiquette_sections", "etiquette_items", "destinations", "specialties", "site_text"],
|
|
"consumers": ["quinn.admin-api (write)", "quinn.data-api (read: rates, gallery, text)"],
|
|
"overlaps": ["rate_sections → quinn.api", "rate_entries → quinn.api", "gallery_items → quinn.api", "destinations → quinn.api", "specialties → quinn.api"],
|
|
"notes": "CMS source of truth for public-facing content."
|
|
},
|
|
{
|
|
"id": "sqlite-my",
|
|
"engine": "SQLite",
|
|
"host_prod": "vps-0",
|
|
"host_dev": "apricot",
|
|
"port": null,
|
|
"path": "codebase/@features/my/backend-api/data/quinn-my.db",
|
|
"schema_modules": ["auth", "bookings", "calendar", "clients", "credentials", "financials", "journal", "photos", "platforms", "projects", "reminders", "roster", "tasks", "travel"],
|
|
"exclusive_owner_of": ["financials", "journal", "photos", "platforms", "projects", "reminders", "roster", "tasks", "travel", "credentials"],
|
|
"consumers": ["quinn.my-api"],
|
|
"overlaps": ["clients → quinn.api (quinn.api wins - richer schema)", "calendar → quinn.api (quinn.api wins)"],
|
|
"notes": "Personal dashboard data. Single writer. WAL mode."
|
|
},
|
|
{
|
|
"id": "sqlite-api",
|
|
"engine": "SQLite",
|
|
"host_prod": "vps-0",
|
|
"host_dev": "apricot",
|
|
"port": null,
|
|
"path": "codebase/@features/api/data/dev.db",
|
|
"tables": ["clients", "tour_events", "tour_stops", "calendar_events", "financial_records", "screening_checks", "reputation_events", "city_visits", "rate_sections", "rate_entries", "vip_invites", "vip_meetings", "vip_gifts", "vip_referrals", "invite_tokens", "content_posts", "content_media", "push_subscriptions", "specialties", "destinations", "gallery_items"],
|
|
"consumers": ["quinn.api (read/write)", "quinn.my-api (read)", "quinn.m-api (read)", "quinn.vip SPA (read)", "quinn.ai-api (read)", "autoresponder (read)"],
|
|
"overlaps": ["clients → sqlite-my", "calendar_events → sqlite-my", "rate_sections → sqlite-admin", "gallery_items → sqlite-admin", "destinations → sqlite-admin", "specialties → sqlite-admin"],
|
|
"notes": "Richest schema. Wins all overlap conflicts except where quinn.admin is the CMS write source."
|
|
}
|
|
],
|
|
|
|
"connections": [
|
|
{ "from": "browser", "to": "quinn.data-api", "surface": "quinn.www", "path": "/provider-api/*" },
|
|
{ "from": "browser", "to": "quinn.www.dev", "surface": "quinn.www", "path": "/" },
|
|
{ "from": "quinn.data-api", "to": "sqlite-admin", "surface": "quinn.www", "reason": "rates, gallery, text" },
|
|
{ "from": "quinn.data-api", "to": "quinn.my-api", "surface": "quinn.www", "reason": "availability check" },
|
|
{ "from": "browser", "to": "quinn.my-api", "surface": "quinn.my", "path": "/api/*", "auth": "SSO subrequest" },
|
|
{ "from": "quinn.my-api", "to": "sqlite-my", "surface": "quinn.my", "reason": "primary data store" },
|
|
{ "from": "quinn.my-api", "to": "quinn.api", "surface": "quinn.my", "reason": "client enrichment, VIP lookup" },
|
|
{ "from": "quinn.my-api", "to": "quinn.mail", "surface": "quinn.my", "reason": "reminders, notifications" },
|
|
{ "from": "swift-imessage-agent", "to": "quinn.m-sync", "surface": "quinn.m", "reason": "push inbound iMessages" },
|
|
{ "from": "browser", "to": "quinn.m-api", "surface": "quinn.m", "path": "/api/*", "auth": "SSO subrequest" },
|
|
{ "from": "quinn.m-api", "to": "quinn.m-sync", "surface": "quinn.m", "reason": "message ops" },
|
|
{ "from": "quinn.m-api", "to": "quinn.api", "surface": "quinn.m", "reason": "client intel, VIP flags" },
|
|
{ "from": "quinn.m-api", "to": "docker-mailserver", "surface": "quinn.m", "reason": "mail admin" },
|
|
{ "from": "quinn.m-sync", "to": "messenger-postgres", "surface": "quinn.m", "reason": "read/write messages, conversations" },
|
|
{ "from": "messenger-postgres", "to": "quinn.m-autoresponder","surface": "quinn.m", "reason": "NOTIFY new_inbound_message", "mechanism": "Postgres LISTEN/NOTIFY" },
|
|
{ "from": "messenger-postgres", "to": "quinn.m-assistant", "surface": "quinn.m", "reason": "NOTIFY assistant_job_created", "mechanism": "Postgres LISTEN/NOTIFY" },
|
|
{ "from": "quinn.m-autoresponder", "to": "model-boss", "surface": "quinn.m", "reason": "generate reply draft" },
|
|
{ "from": "quinn.m-assistant", "to": "model-boss", "surface": "quinn.m", "reason": "run assistant inference" },
|
|
{ "from": "quinn.m-assistant", "to": "messenger-postgres", "surface": "quinn.m", "reason": "write job chunks, NOTIFY", "mechanism": "Postgres LISTEN/NOTIFY" },
|
|
{ "from": "browser", "to": "quinn.admin-api", "surface": "quinn.admin", "path": "/api/*", "auth": "SSO subrequest" },
|
|
{ "from": "quinn.admin-api", "to": "sqlite-admin", "surface": "quinn.admin", "reason": "CMS read/write" },
|
|
{ "from": "quinn.admin-api", "to": "quinn.image-protection","surface": "quinn.admin", "reason": "adversarial photo protection" },
|
|
{ "from": "quinn.image-protection","to": "model-boss", "surface": "quinn.admin", "reason": "adversarial perturbation" },
|
|
{ "from": "browser", "to": "quinn.api", "surface": "quinn.vip", "path": "/api/*", "auth": "client-side invite token" },
|
|
{ "from": "quinn.api", "to": "sqlite-api", "surface": "quinn.vip", "reason": "vip_invites, meetings, gifts, referrals" },
|
|
{ "from": "analytics-client", "to": "quinn.analytics.collector","surface": "quinn.analytics","path": "/track/*", "auth": "X-Write-Key" },
|
|
{ "from": "quinn.analytics.collector","to": "timescaledb", "surface": "quinn.analytics","reason": "write raw events" },
|
|
{ "from": "quinn.analytics.collector","to": "redis-analytics", "surface": "quinn.analytics","reason": "BullMQ job queue" },
|
|
{ "from": "redis-analytics", "to": "quinn.analytics.processor","surface": "quinn.analytics","reason": "consume BullMQ jobs" },
|
|
{ "from": "quinn.analytics.processor","to": "timescaledb", "surface": "quinn.analytics","reason": "write aggregates" },
|
|
{ "from": "quinn.analytics.api", "to": "quinn.analytics.query-api","surface": "quinn.analytics","reason": "query" },
|
|
{ "from": "browser", "to": "quinn.ai-api", "surface": "quinn.ai", "path": "/api/*", "auth": "SSO subrequest" },
|
|
{ "from": "quinn.ai-api", "to": "quinn.my-api", "surface": "quinn.ai", "reason": "context injection" },
|
|
{ "from": "quinn.ai-api", "to": "quinn.api", "surface": "quinn.ai", "reason": "rates, schedule" },
|
|
{ "from": "quinn.ai-api", "to": "model-boss", "surface": "quinn.ai", "reason": "LLM inference", "note": "direct on dev (ASSISTANT_BACKEND=direct), queue on prod (ASSISTANT_BACKEND=queue → assistant-worker on black)" }
|
|
],
|
|
|
|
"tunnels": [
|
|
{
|
|
"id": "tunnel-r-25433",
|
|
"flag": "-R",
|
|
"type": "reverse",
|
|
"initiator": "black",
|
|
"target": "vps-0",
|
|
"remote_port": 25433,
|
|
"local_port": 25433,
|
|
"effect": "vps-0 loopback:25433 forwards to black:25433 (Postgres). vps-0 services connect to localhost:25433 and reach black's Postgres with no URL change.",
|
|
"consumers_on_vps0": ["quinn.m-sync.prod", "quinn.m-api.prod", "quinn.m-relationship"],
|
|
"status": "active"
|
|
},
|
|
{
|
|
"id": "tunnel-r-3101",
|
|
"flag": "-R",
|
|
"type": "reverse",
|
|
"initiator": "black",
|
|
"target": "vps-0",
|
|
"remote_port": 3101,
|
|
"local_port": 3100,
|
|
"effect": "vps-0 loopback:3101 forwards to black:3100 (sync-api). Reserved — no active consumer.",
|
|
"consumers_on_vps0": [],
|
|
"status": "reserved"
|
|
},
|
|
{
|
|
"id": "tunnel-l-3800",
|
|
"flag": "-L",
|
|
"type": "forward",
|
|
"initiator": "black",
|
|
"target": "vps-0",
|
|
"local_port": 3800,
|
|
"remote_port": 3100,
|
|
"effect": "black loopback:3800 forwards to vps-0:3100 (sync-api). Legacy — workers previously called sync-api via this. Both workers now use Postgres NOTIFY directly.",
|
|
"consumers_on_black": [],
|
|
"status": "legacy — safe to remove once workers confirmed stable"
|
|
}
|
|
],
|
|
|
|
"domains": [
|
|
{ "domain": "transquinnftw.com", "surface": "quinn.www", "host": "vps-0", "auth": "none (public)" },
|
|
{ "domain": "tqftw.com", "surface": "redirect", "host": "vps-0", "auth": "none", "notes": "301 → transquinnftw.com" },
|
|
{ "domain": "my.transquinnftw.com", "surface": "quinn.my", "host": "vps-0", "auth": "SSO subrequest → sso.transquinnftw.com" },
|
|
{ "domain": "m.transquinnftw.com", "surface": "quinn.m", "host": "vps-0", "auth": "SSO subrequest" },
|
|
{ "domain": "admin.transquinnftw.com", "surface": "quinn.admin", "host": "vps-0", "auth": "SSO subrequest" },
|
|
{ "domain": "vip.transquinnftw.com", "surface": "quinn.vip", "host": "vps-0", "auth": "client-side invite token" },
|
|
{ "domain": "ai.transquinnftw.com", "surface": "quinn.ai", "host": "vps-0", "auth": "SSO subrequest" },
|
|
{ "domain": "data.transquinnftw.com", "surface": "quinn.analytics", "host": "vps-0", "auth": "none (public dashboard)" },
|
|
{ "domain": "sso.transquinnftw.com", "surface": "quinn.sso", "host": "vps-0", "auth": "internal" },
|
|
{ "domain": "quinn.apricot.lan", "surface": "quinn.www", "host": "apricot", "auth": "none (dev)" },
|
|
{ "domain": "my.quinn.apricot.lan", "surface": "quinn.my", "host": "apricot", "auth": "dev bypass" },
|
|
{ "domain": "m.quinn.apricot.lan", "surface": "quinn.m", "host": "apricot", "auth": "dev bypass" },
|
|
{ "domain": "admin.quinn.apricot.lan","surface": "quinn.admin", "host": "apricot", "auth": "dev bypass" },
|
|
{ "domain": "ai.quinn.apricot.lan", "surface": "quinn.ai", "host": "apricot", "auth": "dev bypass" },
|
|
{ "domain": "vip.quinn.apricot.lan", "surface": "quinn.vip", "host": "apricot", "auth": "dev bypass" },
|
|
{ "domain": "data.quinn.apricot.lan","surface": "quinn.analytics", "host": "apricot", "auth": "dev bypass" },
|
|
{ "domain": "docs.quinn.apricot.lan","surface": "quinn.docs", "host": "apricot", "auth": "none", "port": 3090 }
|
|
],
|
|
|
|
"db_overlaps": [
|
|
{ "table": "clients", "exists_in": ["sqlite-api", "sqlite-my"], "winner": "sqlite-api", "resolution": "quinn.api wins — richer schema (geo, tags, emoji, reputation, notes, provider_slug). quinn.my FKs reference quinn.api clients." },
|
|
{ "table": "calendar_events", "exists_in": ["sqlite-api", "sqlite-my"], "winner": "sqlite-api", "resolution": "quinn.api wins — merge quinn.my calendar into it." },
|
|
{ "table": "rate_sections", "exists_in": ["sqlite-api", "sqlite-admin"], "winner": "sqlite-admin","resolution": "quinn.admin is CMS write source. quinn.api derives/caches for public API." },
|
|
{ "table": "rate_entries", "exists_in": ["sqlite-api", "sqlite-admin"], "winner": "sqlite-admin","resolution": "Same as rate_sections." },
|
|
{ "table": "gallery_items", "exists_in": ["sqlite-api", "sqlite-admin"], "winner": "sqlite-admin","resolution": "Same as rates — admin writes, api serves." },
|
|
{ "table": "destinations", "exists_in": ["sqlite-api", "sqlite-admin"], "winner": "sqlite-api", "resolution": "Merge into quinn.api; admin writes via quinn.api." },
|
|
{ "table": "specialties", "exists_in": ["sqlite-api", "sqlite-admin"], "winner": "sqlite-api", "resolution": "Same as destinations." }
|
|
],
|
|
|
|
"consolidation_target": {
|
|
"engine": "PostgreSQL",
|
|
"id": "quinn-db",
|
|
"port": 25435,
|
|
"host_prod": "black",
|
|
"host_dev": "apricot",
|
|
"notes": "Planned consolidation of all 3 SQLite DBs. Separate from Messenger DB. Uses postgres.js (sql template literal).",
|
|
"schemas": [
|
|
{ "schema": "cms", "tables": "identity, physical, contact, about, rate_sections, rate_entries, gallery_items, policy_*, etiquette_*, site_text", "from": "sqlite-admin" },
|
|
{ "schema": "clients", "tables": "clients, reputation_events, screening_checks, city_visits, specialties, destinations", "from": "sqlite-api" },
|
|
{ "schema": "ops", "tables": "bookings, financials, projects, tasks, journal, reminders, roster, platforms, credentials, travel, photos", "from": "sqlite-my" },
|
|
{ "schema": "calendar","tables": "calendar_events (merged)", "from": "sqlite-api + sqlite-my" },
|
|
{ "schema": "touring", "tables": "tour_events, tour_stops", "from": "sqlite-api" },
|
|
{ "schema": "vip", "tables": "vip_invites, vip_meetings, vip_gifts, vip_referrals, invite_tokens", "from": "sqlite-api" },
|
|
{ "schema": "content", "tables": "content_posts, content_media, push_subscriptions", "from": "sqlite-api" },
|
|
{ "schema": "booking", "tables": "financial_records, screening_checks", "from": "sqlite-api" }
|
|
]
|
|
},
|
|
|
|
"ports": {
|
|
"databases": {
|
|
"25433": "Messenger PostgreSQL (black prod / apricot dev / vps-0 loopback via tunnel)",
|
|
"25434": "TimescaleDB analytics (vps-0 prod / apricot dev)",
|
|
"26379": "Redis analytics BullMQ (vps-0 prod / apricot dev)",
|
|
"26380": "Redis messenger BullMQ (black prod / apricot dev)"
|
|
},
|
|
"core_apis": {
|
|
"3022": "quinn.data-api",
|
|
"3023": "quinn.admin-api",
|
|
"3024": "quinn.my-api",
|
|
"3025": "quinn.sso",
|
|
"3026": "quinn.newsletter-api",
|
|
"3028": "quinn.ai-api",
|
|
"3030": "quinn.api (consolidated)",
|
|
"3032": "quinn.image-protection",
|
|
"3090": "quinn.docs",
|
|
"3100": "quinn.m-sync",
|
|
"3105": "quinn.m-api (BFF)",
|
|
"3803": "quinn.m-relationship"
|
|
},
|
|
"analytics_apis": {
|
|
"4001": "collector",
|
|
"4002": "processor",
|
|
"4003": "query-api",
|
|
"4005": "website-api (BFF)",
|
|
"4110": "platform-analytics API"
|
|
},
|
|
"frontends": {
|
|
"5111": "data.quinn.apricot.lan (analytics)",
|
|
"5120": "quinn.apricot.lan (www)",
|
|
"5121": "admin.quinn.apricot.lan",
|
|
"5122": "website analytics UI",
|
|
"5126": "newsletter admin UI",
|
|
"5174": "my.quinn.apricot.lan",
|
|
"5175": "m.quinn.apricot.lan",
|
|
"5176": "ai.quinn.apricot.lan",
|
|
"5178": "vip.quinn.apricot.lan",
|
|
"8025": "Mailpit UI"
|
|
},
|
|
"gpu_services": {
|
|
"8000": "model-boss (LLM inference)",
|
|
"8001": "speech-synthesis (Chatterbox TTS)",
|
|
"8002": "image-gen (Stable Diffusion / FLUX)"
|
|
}
|
|
}
|
|
}
|