Cory Copeland
Back to work

KinGrove

Active

A privacy-conscious family network with opt-in profile sharing, self-hosted web deployment, and Supabase/Postgres infrastructure.

  • Family/social
  • Privacy
  • Self-hosted
  • Supabase
  • Product design

Updated 2026-05-21

KinGrove

Overview

KinGrove turns a private family network into a product design and infrastructure case study. A zoomable infinite canvas at the front, consent-first privacy in the middle, and a self-hosted Caddy + Docker + Supabase deployment at the back. Phase 1 is shipped and live at kingrove.corycopeland.dev.

The problem

Existing genealogy products — Ancestry, MyHeritage, and the rest — treat the tree owner as the only authority. Anyone they enter is fair game. That works when the product is "research dead ancestors," but it breaks down the moment the tree contains living relatives who didn't ask to be in a database.

The opportunity was a product where the tree is built with the family rather than about them: navigable as a zoomable canvas, consent-controlled on a per-member basis, and operable on infrastructure I actually own.

Audience

  • Tree owners building a living family record that includes relatives who are still around to weigh in.
  • Family members who get invited into someone else's tree and need granular control over what appears about them — not a single approve/reject button.

What I built

  • An infinite zoomable canvas as the primary navigation, not a static pedigree chart. Five zoom levels — surname clusters at the top, individual profiles at the bottom — with smooth transitions between them. The same canvas engine is designed to also power Spiceshelf character/faction trees.
  • A complete brand system: Grove/Canopy/Spring palette, Cormorant Garamond + DM Sans + Syne type stack, vectorized logo set in Affinity Designer, Tailwind v4 theme tokens — everything from logo/final/ through src/theme/kingrove.css.
  • A self-hosted backend stack on Proxmox: web LXC running Caddy + Docker, database LXC running the full 13-service Supabase compose, both behind Cloudflare Tunnels.
  • A documented deployment topology — secrets locations, build/deploy path, rollback procedure, backup runbook, restore-testing notes. Operable by one person at 2am.

Product decisions

A few decisions that defined the product:

  • The privacy model is per-member opt-in, not owner-controlled. Names stay visible (a tree with hidden people isn't a tree any more) but every other field — address, email, phone, social, job, photos, hobbies — is gated by that member's own consent. The owner can still record private notes for their own viewing, in a column distinct from the consented fields so a future "claim your profile" flow works cleanly.
  • Anything published or shared respects opt-outs. Sharing and export code paths filter through visibility flags, not just row-level account ownership. This forecloses a pure owner-edits-everything admin mode, even in Phase 1's single-user trees, so the Phase 2 visibility layer can be additive instead of a rewrite.
  • Themed canvas. Selectable visual themes (traditional, cyber, simple) so the same data can present in different aesthetics. The canvas is treated as a stage, not as the brand itself.
  • Self-host before scale. The first deployment runs on my own hardware behind Cloudflare Tunnel, not on a managed platform. That's not ideological — it forced me to design real operational discipline (backups, restores, rollbacks, secret rotation) before the product has users to disappoint.

Technical architecture

Fully self-hosted as of the 2026-05-07 cutover from Vercel + managed Supabase.

  • Source of truth: self-hosted Forgejo. No external clone of the repo.
  • Web SPA (LXC 207): Vite-built React app, served by Caddy inside a multi-stage Dockerfile (node:22-alpine for build, caddy:2-alpine for serve). Caddy listens on 127.0.0.1:3000; Cloudflare Tunnel kingrove-web fronts it at https://kingrove.corycopeland.dev.
  • Backend (LXC 206): the full official Supabase docker-compose (13 services) running with a shared overlay, fronted by a second Cloudflare Tunnel at https://kingrove-db.corycopeland.dev. The SPA talks to it directly; there is no app server in LXC 207.
  • Deploy: dev box rsync -az --delete (excluding .env, .git, node_modules, dist) into /opt/kingrove-web/ on the LXC, then remote docker compose build && up -d. Manual today; Forgejo Actions on push to main is the next iteration.
  • Secrets: .env files at 0600 on each LXC and the dev box, never in git, never logged. Canonical copies live in Vaultwarden. Vite inlines VITE_* at build time — so the service-role key and hCaptcha secret never go anywhere near a VITE_* var.
  • Backups: Supabase data is dumped nightly on LXC 206, synced to NAS (CodingTest), and snapshotted with Kopia. The web LXC itself needs no backups — it's regenerable from the repo at HEAD plus a three-line .env.
  • Rollback: check out the last-good SHA on the dev box, re-rsync, rebuild. There's no "promote previous deploy" button to lean on, and that's the point — recovery is well-understood.

Design and brand

KinGrove's identity is warm and quietly classic: Cormorant Garamond display type pairs with DM Sans body and Syne labels; the palette runs from a deep Grove green through Canopy to a soft Spring. The logo set was vectorized in Affinity Designer and lives in logo/final/ as SVG and PNG exports. The visual brand spec is committed alongside the code so design decisions don't drift across rebuilds.

Current status

  • Live: Phase 1 shipped 2026-05-07 at kingrove.corycopeland.dev, single-user trees, fully self-hosted.
  • Vercel and managed Supabase retired at the same cutover.
  • Phase 2 (per-member privacy controls) is designed; schema and invite-flow work pending.
  • Phase 3 (exports — slideshow, family-history website, PDF) is on the roadmap behind Phase 2.

What I would do next

  • Land Phase 2: per-member opt-in/opt-out invitations, visibility flags on every member-owned field, an invite UI that shows the invited member exactly what's currently recorded about them.
  • Replace the manual rsync deploy with a Forgejo Actions workflow on push to main.
  • Open Phase 3 exports once consented-vs-private filtering is provably watertight.
  • Document a public privacy page that maps the consent model to plain language, since "per-member opt-in" is the marketing story as much as the product story.

Proof

  • Live site: kingrove.corycopeland.dev
  • Screenshots and a deployment-diagram graphic are still being prepared for this page; they will land here without changing the status above.