diff --git a/deploy/check-deploy-fail.py b/deploy/check-deploy-fail.py
new file mode 100644
index 0000000..db2791b
--- /dev/null
+++ b/deploy/check-deploy-fail.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+import paramiko
+
+c = paramiko.SSHClient()
+c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+c.connect("10.10.0.10", username="localadministrator", password="Bbt9115xty9176!", timeout=20, allow_agent=False, look_for_keys=False)
+
+def run(cmd, t=120):
+ print("$", cmd[:200])
+ _, o, e = c.exec_command(cmd, timeout=t)
+ code = o.channel.recv_exit_status()
+ out = (o.read() + e.read()).decode(errors="replace")
+ print(out[-12000:])
+ print("exit", code, "\n")
+ return out
+
+run("cd /tmp/exposedgays && git fetch origin && git reset --hard origin/main && git log -1 --oneline")
+run(
+ "docker exec coolify-db psql -U coolify -d coolify -t -c "
+ "\"SELECT id,status FROM application_deployment_queues ORDER BY id DESC LIMIT 5;\""
+)
+run(
+ "docker exec coolify-db psql -U coolify -d coolify -t -c "
+ "\"SELECT deployment_logs FROM application_deployment_queues ORDER BY id DESC LIMIT 1;\" | tail -c 8000"
+)
+run("ls -la /data/coolify/applications/ira4bw4nhbvm87o7s3fgqu6v/logs/ 2>/dev/null | tail -5")
+run("tail -80 /data/coolify/applications/ira4bw4nhbvm87o7s3fgqu6v/logs/*.log 2>/dev/null | tail -80")
+
+c.close()
\ No newline at end of file
diff --git a/deploy/check-deploy-fail2.py b/deploy/check-deploy-fail2.py
new file mode 100644
index 0000000..ddc8c32
--- /dev/null
+++ b/deploy/check-deploy-fail2.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+import paramiko
+
+c = paramiko.SSHClient()
+c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+c.connect("10.10.0.10", username="localadministrator", password="Bbt9115xty9176!", timeout=20, allow_agent=False, look_for_keys=False)
+
+def run(cmd, t=300):
+ print("$", cmd[:220])
+ _, o, e = c.exec_command(cmd, timeout=t)
+ code = o.channel.recv_exit_status()
+ out = (o.read() + e.read()).decode(errors="replace")
+ print(out[-15000:])
+ print("exit", code, "\n")
+ return out
+
+run("docker exec coolify-db psql -U coolify -d coolify -c \"\\d application_deployment_queues\"")
+run("docker exec coolify-db psql -U coolify -d coolify -t -c \"SELECT logs FROM application_deployment_queues WHERE id=1116;\" | tail -c 12000")
+run("find /data/coolify -name '*l9hjct9e8yxydqjl8okovpr5*' 2>/dev/null | head -5")
+run("find /data/coolify -path '*ira4bw4nhbvm87o7s3fgqu6v*' -name '*.log' 2>/dev/null | head -10")
+run("cd /data/coolify/applications/ira4bw4nhbvm87o7s3fgqu6v && docker compose build 2>&1 | tail -60")
+
+c.close()
\ No newline at end of file
diff --git a/deploy/redeploy-v2.py b/deploy/redeploy-v2.py
new file mode 100644
index 0000000..6d4c1ab
--- /dev/null
+++ b/deploy/redeploy-v2.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+import paramiko
+
+HOST = "10.10.0.10"
+USER = "localadministrator"
+PASS = "Bbt9115xty9176!"
+APP = "ira4bw4nhbvm87o7s3fgqu6v"
+
+c = paramiko.SSHClient()
+c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+c.connect(HOST, username=USER, password=PASS, timeout=20, allow_agent=False, look_for_keys=False)
+
+def run(cmd, t=300):
+ print("$", cmd[:180])
+ _, o, e = c.exec_command(cmd, timeout=t)
+ code = o.channel.recv_exit_status()
+ out = (o.read() + e.read()).decode(errors="replace")
+ print(out[-6000:])
+ print("exit", code, "\n")
+ return out
+
+run("cd /tmp/exposedgays && git fetch origin && git reset --hard origin/main && git log -1 --oneline")
+run(
+ "TOKEN=$(cat /home/localadministrator/.coolify-token | tail -1); "
+ f"curl -sS -X POST 'http://127.0.0.1:8000/api/v1/deploy?uuid={APP}&force_rebuild=true' "
+ '-H "Authorization: Bearer $TOKEN"'
+)
+
+for i in range(150):
+ _, out = run("docker exec coolify php artisan queue:work --queue=high,default --once --timeout=900 2>&1", t=920)
+ if "ApplicationDeploymentJob" in out:
+ if "DONE" in out or "finished" in out.lower():
+ print("=== DEPLOY SUCCESS ===")
+ break
+ if "FAIL" in out:
+ print("=== DEPLOY FAILED ===")
+ break
+
+run("docker exec coolify-db psql -U coolify -d coolify -t -c \"SELECT id,status FROM application_deployment_queues ORDER BY id DESC LIMIT 1;\"")
+run("curl -sS https://exposedgays.com/ 2>&1 | head -c 500")
+c.close()
\ No newline at end of file
diff --git a/public/partners/jtr-wordmark.svg b/public/partners/jtr-wordmark.svg
new file mode 100644
index 0000000..948bac9
--- /dev/null
+++ b/public/partners/jtr-wordmark.svg
@@ -0,0 +1,11 @@
+
+
+
diff --git a/public/partners/pinkpulse-icon.svg b/public/partners/pinkpulse-icon.svg
new file mode 100644
index 0000000..03cf624
--- /dev/null
+++ b/public/partners/pinkpulse-icon.svg
@@ -0,0 +1,56 @@
+
+
+
+
diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx
index 8d8f7c5..9494636 100644
--- a/src/app/privacy/page.tsx
+++ b/src/app/privacy/page.tsx
@@ -3,9 +3,11 @@ export default function PrivacyPage() {
Privacy Policy
- We collect minimal data. Location is used for map features and city chat auto-join.
- Anonymous browsing is supported. Cart data stays in your browser (localStorage).
- Placeholder policy — consult legal counsel before launch.
+ ExposedGays is operated by Just Two Roommates LLC. We collect minimal data.
+ Location is used for map features and city chat auto-join. Anonymous browsing
+ is supported. Cart data stays in your browser (localStorage). When you follow
+ links to our community partner The Pink Pulse, their privacy policy applies on
+ their site. Placeholder policy — consult legal counsel before launch.
);
diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx
index 2c0fbdd..3c97f7c 100644
--- a/src/app/profile/page.tsx
+++ b/src/app/profile/page.tsx
@@ -15,6 +15,7 @@ import { AuthModal } from "@/components/AuthModal";
import { PhotoGalleryManager } from "@/components/PhotoGalleryManager";
import { CannedMessagesPanel } from "@/components/CannedMessagesPanel";
import { IdVerificationModal } from "@/components/IdVerificationModal";
+import { PinkPulsePartner } from "@/components/PinkPulsePartner";
import {
US_STATES,
getUserState,
@@ -307,6 +308,8 @@ export default function ProfilePage() {
+
+
{message && (
- ExposedGays is a free adult platform. You must be 18+ to use this site.
- All content is user-generated. We reserve the right to remove illegal content.
- No paid subscriptions — ever. Placeholder terms — consult legal counsel before launch.
+ ExposedGays is a free adult platform operated by Just Two Roommates LLC. You must
+ be 18+ to use this site. All content is user-generated. We reserve the right to
+ remove illegal content. No paid subscriptions — ever. Links to our community
+ partner The Pink Pulse (thepinkpulse.com) are provided for LGBTQ+ news, events,
+ and local resources — separate editorial property, same parent company.
+ Placeholder terms — consult legal counsel before launch.
);
diff --git a/src/components/ChatPanel.tsx b/src/components/ChatPanel.tsx
index b25e829..7ec0ecf 100644
--- a/src/components/ChatPanel.tsx
+++ b/src/components/ChatPanel.tsx
@@ -8,6 +8,7 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Send, Image as ImageIcon, Users, Lock, Zap, ChevronDown, ChevronUp } from "lucide-react";
import { timeAgo } from "@/lib/utils";
import { CannedMessagesPanel } from "@/components/CannedMessagesPanel";
+import { PinkPulsePartner } from "@/components/PinkPulsePartner";
interface Message {
id: string;
@@ -148,9 +149,10 @@ export function ChatPanel({ dmUserId }: ChatPanelProps) {
-
+
Create a group room — free, no limits.
+
diff --git a/src/components/Map.tsx b/src/components/Map.tsx
index 2f0a44b..7c3d990 100644
--- a/src/components/Map.tsx
+++ b/src/components/Map.tsx
@@ -14,6 +14,7 @@ import type { Profile, CruisingSpot, MapFilters, Position } from "@/types";
import { KINK_OPTIONS, POSITION_COLORS } from "@/types";
import { MOCK_PROFILES, MOCK_SPOTS } from "@/lib/mock-data";
import { useOpenIdVerification } from "@/components/Providers";
+import { PinkPulsePartner } from "@/components/PinkPulsePartner";
import "leaflet/dist/leaflet.css";
import "leaflet.markercluster/dist/MarkerCluster.css";
@@ -279,9 +280,15 @@ export function CruisingMap({ vanillaMode, onActiveCountChange }: MapProps) {
vanillaMode={vanillaMode}
/>
))}
+
)}
+ {/* Mobile — community partner strip above bottom nav */}
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Providers.tsx b/src/components/Providers.tsx
index 8d63bd5..61a8093 100644
--- a/src/components/Providers.tsx
+++ b/src/components/Providers.tsx
@@ -5,6 +5,7 @@ import { AgeGate } from "@/components/AgeGate";
import { Nav } from "@/components/Nav";
import { MobileHeader } from "@/components/MobileHeader";
import { IdVerificationModal } from "@/components/IdVerificationModal";
+import { SiteFooter } from "@/components/SiteFooter";
import { AuthProvider, useAuth } from "@/lib/auth/context";
import {
mustBlurExplicit,
@@ -90,9 +91,10 @@ function InnerProviders({ children }: ProvidersProps) {
onVanillaToggle={handleVanillaToggle}
activeCount={activeCount}
/>
-
+
- {children}
+
{children}
+
+
+
+
+
+
+
+
+
+ Designed & operated by
+
+
+
+
+
+ ExposedGays is a free adult platform from the Just Two Roommates media
+ family — alongside{" "}
+
+ {PINK_PULSE.name}
+
+ , your queer city guide.
+