Files
server-26/drb-frontend/app/privacy/page.tsx
T
Logan CusanoandClaude Opus 5.5 bf206334e3 fix(frontend): finish the token migration — raw grey classes -> theme tokens
UI_REDESIGN chunk 4 was never finished: 39 app/component files still used
raw Tailwind greys, kept readable in light mode only by the !important
override sheet. In dark mode text-gray-600 is ~2.3:1 on surface, and the
light override maps it to #94a3b8 (~2.6:1 on white) — unreadable in both.

Mechanical mapping (886 classes): gray-100/200 -> ink, 300/400 -> ink-2,
500/600/700 -> ink-muted, bg 950/900/800 -> page/surface/raised,
border 800 -> line, 700/600 -> line-strong, plus hover/divide/placeholder.
Alpha suffixes kept (tokens are color-mix, so /60 works). bg-gray-700,
text-white and marketing pages left alone. text-[9px] -> text-[10px].

Frontend unverified: no Node on the authoring box (#207).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:29:13 -04:00

84 lines
4.7 KiB
TypeScript

import Link from "next/link";
/**
* SAAS_PLAN.md B5: page structure only — see app/terms/page.tsx for why the
* agent building this did not write real legal text. Privacy Policy needs
* the same jurisdiction-aware legal review as Terms, plus specifics this
* agent cannot respond for on the owner's behalf: what a real DPA/CCPA/GDPR
* posture looks like, and what third-party processors (OpenAI, Gemini,
* Google Maps, Firebase/GCP, Stripe once chosen) actually receive and why.
*/
const SECTIONS: { heading: string; note: string }[] = [
{
heading: "1. What data this collects",
note: "TODO(legal): account data (email, org membership), field node telemetry (location, status), radio call audio and AI-generated transcripts/entities/incident data, and usage/session logs (drb-c2-core's audit_log and user_sessions collections already exist and hold some of this today).",
},
{
heading: "2. Third parties this data is sent to, and why",
note: "TODO(legal): OpenAI (Whisper transcription), Google Gemini (incident extraction/summarization/embeddings), Google Maps (geocoding location strings extracted from transcripts), Google Cloud (Firestore + GCS storage, Firebase Auth), and — once a payment processor is chosen (SAAS_PLAN.md section 6.5, not yet decided) — that processor. Each of these is a real, already-integrated dependency, not a hypothetical one; this section needs to name them accurately, not generically.",
},
{
heading: "3. Recorded radio traffic specifically",
note: "TODO(legal): this product's core function is recording, transcribing, and storing monitored radio audio — including public-safety traffic that may name individuals, locations, and in-progress incidents. This needs explicit treatment distinct from generic 'we collect usage data' privacy boilerplate, and needs to be read alongside the same legal review flagged in Terms section 3.",
},
{
heading: "4. How long data is kept",
note: "TODO(legal): no retention enforcement exists in the product yet (no TTL, no sweep, no deletion job — see DEFERRED.md) — this section cannot promise a retention/deletion window the system doesn't actually implement.",
},
{
heading: "5. Customer and end-user rights",
note: "TODO(legal): access/export/deletion requests, and who they're directed to — org owner vs. platform operator.",
},
{
heading: "6. Cookies and session data",
note: "TODO(legal): drb_session is a client-set, non-httpOnly cookie used only for UI redirect logic (not an auth boundary — see CLAUDE.md); Firebase Auth sets its own session storage. No analytics/tracking cookies are set today.",
},
{
heading: "7. Security practices",
note: "TODO(legal): at a level appropriate for public disclosure — Firestore security rules, per-node credentials, encrypted transport. Should be reviewed against SAAS_PLAN.md's actual findings before publishing any specific claim.",
},
{
heading: "8. Changes to this policy",
note: "TODO(legal): how customers are notified.",
},
{
heading: "9. Contact",
note: "TODO(legal): real company legal identity and contact address — not yet decided (SAAS_PLAN.md section 6.6).",
},
];
export default function PrivacyPage() {
return (
<div className="max-w-screen-md mx-auto px-4 md:px-6 py-16 md:py-20">
<div className="bg-yellow-900/30 border border-yellow-700/50 rounded-lg px-4 py-3 mb-10">
<p className="text-yellow-200 text-sm font-mono font-semibold">
Draft — not yet in force
</p>
<p className="text-yellow-200/80 text-xs mt-1 leading-relaxed">
This page is a structural placeholder, not a real Privacy Policy. Every section below is a{" "}
<code className="text-yellow-100">TODO(legal)</code> marker, not actual legal text. Nothing on this page
describes a binding commitment about how data is handled.
</p>
</div>
<h1 className="text-display-sm text-white">Privacy Policy</h1>
<p className="text-ink-muted text-sm mt-2 font-mono">Draft — last structured {new Date().getFullYear()}</p>
<div className="mt-10 space-y-8">
{SECTIONS.map((s) => (
<section key={s.heading}>
<h2 className="text-white font-semibold">{s.heading}</h2>
<p className="text-ink-muted text-sm mt-2 leading-relaxed italic">{s.note}</p>
</section>
))}
</div>
<p className="text-ink-muted text-xs font-mono mt-16">
Questions in the meantime? <Link href="/faq" className="text-indigo-400 hover:text-indigo-300 transition-colors">Check the FAQ</Link> or{" "}
<Link href="/login" className="text-indigo-400 hover:text-indigo-300 transition-colors">sign in to reach us directly</Link>.
</p>
</div>
);
}