SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%

Site identity: author Simon-Pierre Boucher, contact@spboucher.ai, hosted on MacLustr (www.maclustr.io) in footer, About, methodology, metadata and OpenAPI contact

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 13 days ago (Sep 11, 2026) parent 15088d0

6 changed files +40 −7

modified apps/api/src/app.ts +1 −1
@@ -94,7 +94,7 @@ export async function buildApp(opts: BuildOptions = {}): Promise<FastifyInstance
94 94 version: '1.0.0',
95 95 description:
96 96 'Public read-only API of CancerIndex.io — the global index of cancer. Every response is wrapped in `{ data, sources, dataRelease, generatedAt }`; `sources` lists the upstream sources (with license and attribution) behind the returned data. Numbers are never invented: absent data is absent, not zero. Rankings carry scope, formula version and inputs hash. Not medical advice.',
97 − contact: { name: 'CancerIndex', url: 'https://www.cancerindex.io' },
97 + contact: { name: 'Simon-Pierre Boucher — CancerIndex', url: 'https://www.cancerindex.io/about', email: 'contact@spboucher.ai' },
98 98 license: { name: 'Data licensed per source; see /v1/sources' },
99 99 },
100 100 servers: [{ url: '/', description: 'This host' }],
modified apps/web/src/app/about/page.tsx +17 −0
@@ -1,5 +1,6 @@
1 1 import type { Metadata } from 'next';
2 2 import Link from 'next/link';
3 +import { CONTACT_EMAIL, AUTHOR_NAME, AUTHOR_URL, HOSTING_NAME, HOSTING_URL } from '@/lib/site';
3 4 import { PageHeader, Section } from '@/components/ui/section';
4 5
5 6 export const metadata: Metadata = { title: 'About', description: 'What CancerIndex is, who it is for, and what it refuses to do.' };
@@ -23,6 +24,22 @@ export default function AboutPage() {
23 24 <li>No AI-generated synthesis in this phase; all text is sourced or fixed methodology.</li>
24 25 </ul>
25 26 </Section>
27 + <Section id="team" kicker="Who" title="Who builds and hosts it">
28 + <p>
29 + CancerIndex is designed, built and maintained by{' '}
30 + <a className="ci-link" href={AUTHOR_URL} rel="author">
31 + {AUTHOR_NAME}
32 + </a>
33 + . Questions, corrections, licensing concerns and collaboration requests: <a className="ci-link" href={`mailto:${CONTACT_EMAIL}`}>{CONTACT_EMAIL}</a>.
34 + </p>
35 + <p className="mt-2">
36 + The platform — database, ingestion workers, API and web application — is hosted on{' '}
37 + <a className="ci-link" href={HOSTING_URL} target="_blank" rel="noopener noreferrer">
38 + {HOSTING_NAME}
39 + </a>{' '}
40 + (www.maclustr.io), a private Apple-silicon compute cluster, and published through the MacLustr Tunnel.
41 + </p>
42 + </Section>
26 43 <Section id="status" kicker="Status" title="Phase 1">
27 44 <p>
28 45 The taxonomy backbone is live; epidemiology, genomics, trial and literature connectors are being brought online one at a time, each after a license review. Follow progress on the <Link className="ci-link" href="/sources">source registry</Link> and read the <Link className="ci-link" href="/methodology">methodology</Link>.
modified apps/web/src/app/layout.tsx +3 −1
@@ -3,7 +3,7 @@ import { Newsreader, Inter, IBM_Plex_Mono } from 'next/font/google';
3 3 import './globals.css';
4 4 import { SiteHeader } from '@/components/layout/site-header';
5 5 import { SiteFooter } from '@/components/layout/site-footer';
6 −import { SITE_URL, SITE_NAME, TAGLINE } from '@/lib/site';
6 +import { SITE_URL, SITE_NAME, TAGLINE, AUTHOR_NAME, AUTHOR_URL } from '@/lib/site';
7 7
8 8 const display = Newsreader({ variable: '--font-display', subsets: ['latin'], display: 'swap', weight: ['400', '500', '600'], style: ['normal', 'italic'] });
9 9 const ui = Inter({ variable: '--font-ui', subsets: ['latin'], display: 'swap' });
@@ -14,6 +14,8 @@ export const metadata: Metadata = {
14 14 title: { default: `${SITE_NAME} — ${TAGLINE}`, template: `%s · ${SITE_NAME}` },
15 15 description: 'A provenance-first index of every recognized cancer entity: taxonomy, epidemiology, genomics, variants, therapies, clinical trials, literature and transparent rankings.',
16 16 applicationName: SITE_NAME,
17 + authors: [{ name: AUTHOR_NAME, url: AUTHOR_URL }],
18 + creator: AUTHOR_NAME,
17 19 robots: { index: true, follow: true },
18 20 openGraph: { type: 'website', siteName: SITE_NAME, url: SITE_URL, title: `${SITE_NAME} — ${TAGLINE}`, description: 'Provenance-first oncology intelligence: every number linked to its source.' },
19 21 twitter: { card: 'summary', title: SITE_NAME, description: TAGLINE },
modified apps/web/src/app/methodology/page.tsx +1 −1
@@ -297,7 +297,7 @@ export default async function MethodologyPage() {
297 297 <li>Approval records reflect the jurisdictions ingested; absence of an approval on this site is not evidence of absence.</li>
298 298 </ul>
299 299 <p className="mt-3 text-[13px] text-ink-3">
300 − Corrections: <a className="ci-link" href="mailto:corrections@cancerindex.io">corrections@cancerindex.io</a>. See also <Link className="ci-link" href="/trust">Trust &amp; policies</Link>.
300 + Corrections: <a className="ci-link" href="mailto:contact@spboucher.ai">contact@spboucher.ai</a>. See also <Link className="ci-link" href="/trust">Trust &amp; policies</Link>.
301 301 </p>
302 302 </Section>
303 303 </div>
modified apps/web/src/components/layout/site-footer.tsx +13 −3
@@ -1,5 +1,5 @@
1 1 import Link from 'next/link';
2 −import { DISCLAIMER, FOOTER_NAV, CONTACT_EMAIL } from '@/lib/site';
2 +import { DISCLAIMER, FOOTER_NAV, CONTACT_EMAIL, AUTHOR_NAME, AUTHOR_URL, HOSTING_NAME, HOSTING_URL } from '@/lib/site';
3 3
4 4 export function SiteFooter() {
5 5 return (
@@ -20,14 +20,24 @@ export function SiteFooter() {
20 20 </Link>
21 21 ))}
22 22 <a href={`mailto:${CONTACT_EMAIL}`} className="text-ink-2 no-underline hover:text-accent">
23 − Report a correction
23 + Contact · {CONTACT_EMAIL}
24 24 </a>
25 25 <Link href="/healthz" className="text-ink-2 no-underline hover:text-accent">
26 26 Status
27 27 </Link>
28 28 </nav>
29 29 </div>
30 − <p className="mt-6 text-[11.5px] text-ink-3">© {new Date().getUTCFullYear()} CancerIndex. Source data remains under the license of each provider — see /sources.</p>
30 + <p className="mt-6 text-[11.5px] text-ink-3">
31 + © {new Date().getUTCFullYear()} CancerIndex · built and maintained by{' '}
32 + <a href={AUTHOR_URL} className="text-ink-2 no-underline hover:text-accent" rel="author">
33 + {AUTHOR_NAME}
34 + </a>{' '}
35 + · contact <a href={`mailto:${CONTACT_EMAIL}`} className="text-ink-2 no-underline hover:text-accent">{CONTACT_EMAIL}</a> · hosted on{' '}
36 + <a href={HOSTING_URL} className="text-ink-2 no-underline hover:text-accent" target="_blank" rel="noopener noreferrer">
37 + {HOSTING_NAME}
38 + </a>{' '}
39 + (www.maclustr.io). Source data remains under the license of each provider — see /sources.
40 + </p>
31 41 </div>
32 42 </footer>
33 43 );
modified apps/web/src/lib/site.ts +5 −1
@@ -3,7 +3,11 @@ export const SITE_NAME = 'CancerIndex';
3 3 export const TAGLINE = 'The global index of cancer.';
4 4 export const DISCLAIMER =
5 5 'CancerIndex is a research and information platform. It is not a physician, does not diagnose, and does not recommend treatment. Population statistics do not predict individual outcomes.';
6 −export const CONTACT_EMAIL = 'corrections@cancerindex.io';
6 +export const CONTACT_EMAIL = 'contact@spboucher.ai';
7 +export const AUTHOR_NAME = 'Simon-Pierre Boucher';
8 +export const AUTHOR_URL = 'https://www.spboucher.ai';
9 +export const HOSTING_NAME = 'MacLustr';
10 +export const HOSTING_URL = 'https://www.maclustr.io';
7 11
8 12 export const NAV = [
9 13 { href: '/cancers', label: 'Cancers' },
10 14