Every enrolled person gets a photo, so records look and feel realistic in the UI. No real people’s photos are ever used.

Primary source: AI-generated faces

By default, both the seed script and the enroll endpoint fetch a photo from a public AI face generator (thispersondoesnotexist.com) at the moment a person is created. Each request returns a different synthetic, photorealistic face with no identity behind it — the model that produces them doesn’t represent any real individual. This requires the machine running the server to have outbound internet access. Records created this way are stored with photo_source: "ai-generated".

Fallback: procedural SVG faces

If that request fails — no internet, the service is down, a timeout — the system falls back to generating a face procedurally: a seeded, deterministic SVG illustration (varied skin tone, face shape, eyes, hair, and occasional glasses or facial hair). This never fails and never requires network access. Records created this way are stored with photo_source: "procedural".
In fully offline environments (for example, a sandboxed CI runner), every seeded record will show photo_source: "procedural". That’s expected behavior, not a bug — the seed script always completes either way.

Manual uploads

The enroll form also accepts an uploaded image instead of generating one. Records created this way are stored with photo_source: "upload".

Where photos live

Photos are written to server/data/images/person_<id>.<ext> (.jpg for AI-generated or uploaded photos, .svg for procedural ones) and served statically at /images/person_<id>.<ext> by the API server.