Minimal scaffold to view and edit a GEDCOM-based genealogical tree using Next.js (frontend), a GraphQL Yoga API, and MongoDB for persistence.
Quick start
-
Copy
.env.exampleto.env.localand setMONGODB_URI. -
For Google authentication, also configure:
AUTH_SECRET=replace-with-a-long-random-string
AUTH_GOOGLE_ID=your-google-oauth-client-id
AUTH_GOOGLE_SECRET=your-google-oauth-client-secretIn Google Cloud Console, add this authorized redirect URI:
http://localhost:3000/api/auth/callback/google- Install and run:
npm install
npm run devImport process
The import flow is split into two steps executed by a single script:
- Parse the GEDCOM file
gene.ged - Generate an intermediate JSON file in
data/gedcom.json - Upsert people and families into MongoDB
- Resolve GEDCOM family references (
FAMS,FAMC) into MongoDB document references
The import script automatically reads .env.local and .env, so if MONGODB_URI is set there you can run:
npm run import:gedIf you want to import a specific GEDCOM file, run:
npm run import:ged -- ./path/to/file.gedYou can also pass a custom GEDCOM file path:
node ./scripts/importGedcom.js ./path/to/file.gedIf the app is running in Docker Compose, copy the GEDCOM file into the app container and run the import there:
docker cp ./gene.ged <container-name>:/tmp/gene.ged
docker compose exec app npm run import:ged -- /tmp/gene.gedWhat the script does:
- Reads the GEDCOM records and extracts
INDIandFAM - Fails if it finds unsupported GEDCOM lines in
INDIorFAMrecords - Validates relationship consistency between
INDI.FAMS/INDI.FAMCandFAM.HUSB/FAM.WIFE/FAM.CHIL - Writes a parsed JSON snapshot to
data/gedcom.json - Imports
INDIrecords into thePersoncollection - Imports
FAMrecords into theFamilycollection - Rewrites family links on each person using MongoDB object references
Validation rules:
- Every
FAMSreference must point to an existing family and that family must list the person asHUSBorWIFE - Every
FAMCreference must point to an existing family and that family must list the person inCHIL - Every
HUSB,WIFE, andCHILreference in a family must point to an existing individual - Family references must be bidirectionally consistent; otherwise the import aborts
Expected output:
- A log line for the generated JSON file
- MongoDB connection logs
- A final summary like
Imported 705 persons and 226 families.
If validation fails, the script exits with code 1 and prints the first inconsistencies or unrecognized lines it found.
If MONGODB_URI is not configured, the script still generates data/gedcom.json and skips the database import.
Notes
- API endpoint:
POST /api/graphql - All API calls under
/api/*are logged to console and, when MongoDB is configured, also persisted in theapirequestlogscollection with method, path, status, duration, user, and route-specific metadata. - The project contains a simple
Personmodel and GraphQL queries/mutations to list and create persons. - Google authentication is handled with Auth.js for Next.js (
next-auth) and persists signed-in users in MongoDB. - Genealogical data is private: unauthenticated users are redirected to sign-in pages and GraphQL genealogy queries require an authenticated session.
- Authentication alone is not sufficient: users must also have an explicit role (
guest,editor, oradmin) to access genealogy data. - Admin users can generate one-time or reusable invitation links that assign a predefined role when redeemed, and can disable them later from the admin UI.
- If no admin exists anymore, you can bootstrap a new invitation from the command line with
npm run invite:user -- admin. - The
addPersonGraphQL mutation now requires an authenticated session.
Database migrations
The repository uses migrate-mongo for explicit MongoDB migrations. The configuration lives in migrate-mongo-config.js and reads .env.local and .env to resolve MONGODB_URI.
Create a new migration:
npm run migrate:create -- add-invitation-flagsApply pending migrations:
npm run migrate:upRollback the last migration:
npm run migrate:downShow migration status:
npm run migrate:statusMigration files are stored in the migrations/ directory and tracked through the migrations_changelog collection in MongoDB.
The repository already includes an initial migration to normalize legacy UserInvitation documents with the newer invitation fields.
Invitation bootstrap from CLI
The invite creation script reads .env.local and .env, connects to MongoDB, and prints an invitation URL.
This is the recovery path when the users collection is empty, the previous admin was deleted, or no application admin can access the UI anymore.
Create an admin invitation using the configured NEXTAUTH_URL:
npm run invite:user -- adminCreate an invitation for a different role:
npm run invite:user -- guest
npm run invite:user -- editorCreate a reusable invitation link:
npm run invite:user -- admin --reusableOverride the base URL printed in the invitation link:
npm run invite:user -- --role admin --base-url https://gene.example.comIf you are running in Docker Compose, you can create the invitation inside the app container:
docker compose exec app npm run invite:user -- admin
docker compose exec app npm run invite:user -- admin --reusableTypical recovery flow:
- Generate an admin invitation from the shell.
- Open the printed URL in the browser.
- Sign in with Google using the account that should become admin.
- The role is assigned when the invitation page is redeemed.
Invitation behavior:
- One-time links stop working after the first successful redemption.
- Reusable links can be redeemed any number of times by different pending accounts.
- Any invitation link can be disabled or re-enabled from the Manage users page.
Docker deployment
Build the image:
docker build -t gene-tree .Run the container:
docker run --rm -p 3000:3000 \
-e MONGODB_URI=mongodb://host.docker.internal:27017/gene \
-e AUTH_SECRET=replace-with-a-long-random-string \
-e AUTH_GOOGLE_ID=your-google-oauth-client-id \
-e AUTH_GOOGLE_SECRET=your-google-oauth-client-secret \
gene-treeApply pending migrations in the running container before using the app after a deploy that changes database structure or data shape:
docker exec <container-name> npm run migrate:upIf you use Docker Compose, the equivalent command is:
docker compose exec app npm run migrate:upIf deploying behind a public URL, also set NEXTAUTH_URL to the external base URL of the app.