Build your family tree, save stories, and explore where your family came from on a 3D globe.
index.html, style.css, script.js (vanilla JS + Globe.gl).
Open index.html directly or serve the folder statically.backend/
(in progress — see below).Prerequisites:
backend/venv was created with Python 3.14.6).backend/db.sqlite3, created automatically, git-ignored).Create and activate the virtual environment (already present as
backend/venv; to recreate: python -m venv backend\venv):
backend\venv\Scripts\Activate.ps1
If PowerShell blocks activation scripts, do not weaken the global
execution policy. Instead call the venv Python directly, e.g.
backend\venv\Scripts\python.exe -m pip ....
Install dependencies:
backend\venv\Scripts\python.exe -m pip install -r backend\requirements.txt
Create the local environment file (already present as backend/.env;
to recreate: copy backend/.env.example to backend/.env).
backend/.env is git-ignored — never commit it. No database
credentials are needed for the default SQLite setup.
Run Django checks:
backend\venv\Scripts\python.exe backend\manage.py check
Apply migrations (creates backend/db.sqlite3 on first run):
backend\venv\Scripts\python.exe backend\manage.py migrate
Start the development server:
backend\venv\Scripts\python.exe backend\manage.py runserver
Health check: GET http://127.0.0.1:8000/api/health/ should return
{"status": "ok", "service": "mycelium-backend", "version": "0.1.0"}.
It needs no database and exposes no configuration or secrets.
Run the backend tests (87 tests, real project settings) with:
backend\venv\Scripts\python.exe backend\manage.py test
SQLite is the default and is all local development needs. For production:
DB_ENGINE=postgresql
plus POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD,
POSTGRES_HOST, POSTGRES_PORT, along with DJANGO_SECRET_KEY,
DJANGO_DEBUG=False, DJANGO_ALLOWED_HOSTS (your domain),
FRONTEND_ORIGIN (your frontend URL), and DJANGO_SECURE=1.python manage.py migrate).CLOUDINARY_URL so uploads persist; email: set the
EMAIL_* values for Gmail SMTP delivery.PostgreSQL compatibility has only been statically checked here
(sqlmigrate rendering); no live PostgreSQL server was available, so a
live integration test is still required before relying on it.
render.yaml. It creates a free backend Web Service
and a separate paid PostgreSQL database, generates DJANGO_SECRET_KEY,
and wires the database credentials and allowed host automatically.
Review Render’s current database price before approving. The frontend
and API share the backend origin. The start command applies database
migrations before launching the backend.CLOUDINARY_URL in the Render
dashboard. Without it, uploads use the web service’s ephemeral
filesystem and can disappear after a restart or redeploy.GROQ_API_KEY there to enable the AI story helper; configure
EMAIL_* only if real email delivery is needed.GROQ_API_KEY in the
Render dashboard (locally: backend/.env, never committed).openai/gpt-oss-20b (a currently supported Groq
model; override with GROQ_MODEL if Groq retires it). The helper is
rate-limited to 20 requests/hour per account.DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend,
EMAIL_HOST=smtp.gmail.com, EMAIL_PORT=587,
EMAIL_HOST_USER=<address>,
EMAIL_HOST_PASSWORD=<16-char app password>,
DEFAULT_FROM_EMAIL=Mycelium <<address>> in the Render dashboard.backend/media/ is git-ignored and stays on this machine — it is not
deployed. After launch, either re-upload photos (they land in Cloudinary
once CLOUDINARY_URL is set) or copy the files into Cloudinary manually.
Do not make the local media directory public.
Done (foundation + family API):
config + app family, environment-variable
configuration, DRF, CORS limited to FRONTEND_ORIGIN, media uploads
directory, and optional GROQ_API_KEY (app starts without it).GET /api/health/ liveness endpoint + tests.FamilyMember (canonical parents/partners links, derived
siblings, photo upload, bio), FamilyEvent (timeline), FamilyStory
(archive). Migration family/migrations/0001_initial.py included.GET/POST /api/members/, GET/PUT/PATCH/DELETE /api/members/<id>/,
same shapes for /api/events/ and /api/stories/,
GET /api/places/ (birth/lived places resolved through a local
gazetteer of ~35 cities and ~30 countries; unknown places stay null
and are listed, never plotted), POST /api/storyhelper/ (Groq-powered;
honest 503 when no key is configured, key never leaves the backend).Parent/Child/Spouse / partner/Sibling/
Grandparent hints derive canonical links idempotently (no duplicates,
no self-links); ambiguous labels keep the entry hint only.DB_ENGINE=postgresql) but has not had a live integration run here.Done (accounts and private trees):
/api/auth/register,
/api/auth/login, /api/auth/logout, /api/auth/me,
/api/auth/csrf/); frontend serves login/register views from the
existing design with CSRF protection and narrow CORS.owner);
all endpoints are owner-scoped on the backend (cross-account reads
404, anonymous access 403). A client-supplied owner is always ignored.FamilyTree (auto-created) with a designatable
center person (GET/POST /api/center/; “Make this the center of my
tree” button in member profiles).GET /api/photos/<id>/; no public media URLs are served.GET/POST /api/connections/,
approve/reject/revoke) between exact usernames: no directory, no
auto-merge. The recipient may grant read-only tree viewing
(grants_view); the requester can then open the shared tree from the
Connections view (GET /api/shared/<username>/members|events|stories|places/,
viewer-checked photo downloads). Grants never propagate, revoking ends
access, and records always stay owned by their own accounts./accounts/password_reset/ (Django views + email;
console backend locally, Gmail SMTP in production).seed_sample_family --username <name> seeds a demo family owned by
that existing account (idempotent, per user). Records created before
ownership are ownerless and hidden; the owner can explicitly run
assign_legacy_records --username <name> once to claim them
(documented; never automatic).Frontend integration (all live, verified against the API):
EMAIL_HOST etc. and a
real DJANGO_EMAIL_BACKEND before any password-reset feature./accounts/password_reset/); real
delivery needs Gmail SMTP credentials (App Password, 2-Step Verification
on) — unverified here, no key configured.MEDIA_ROOT publicly.install.cmd (Claude Code bootstrap script) sits untracked
in the repo root; it is not part of this project.test-key.js reads GROQ_API_KEY from the environment and contains no
hardcoded secret.