What this is
A small FastAPI service wrapping this course's capstone_companies/capstone_people graph in three endpoints: add a person, get everything directly connected to a person, and find how two people are connected. This is the shape of thing pggraph's own docs point at directly, an AI agent's "give me relevant context around this entity" endpoint, backed by ordinary Postgres tables and a compiled graph instead of a hand-rolled recursive query or a separate graph database.
What it does
lifespan() builds the graph once at startup (same shape as Lesson 10's schema, works_at/reports_to), the same pattern FastAPI's lifespan handler has used throughout this repo's courses, setup that runs once, not per-request. The tables are named capstone_companies/ capstone_people, not companies/people, deliberately, so this capstone doesn't collide with whatever state earlier lessons left in the shared graph database (the same reason pgvector's own capstone uses a dedicated capstone_notes collection name). Three endpoints:
POST /people- inserts (or updates) a person row. No explicit sync call afterward, on purpose.GET /context/{person_id}-graph.get_node()for the person plusgraph.get_neighbors(direction := 'any')for everything one hop away, company and manager/reports together.GET /connection?from_name=X&to_name=Y-graph.connection(), searching both people by name and returning the path between them as one readable string.
Where each piece came from
- Schema, table/edge registration,
graph.build()- Lesson 10's setup, trimmed tocapstone_companies/capstone_peopleonly (noprojects/subsidiary_of, this capstone didn't need them). POST /peoplewriting straight to the table, with nograph.apply_sync()call, andGET /contextseeing the new person immediately anyway - Lesson 18's sync overlay, writes are visible to queries before you explicitly sync anything.graph.get_node()/graph.get_neighbors()- Lessons 6-7.graph.connection()- Lesson 15.
Try this yourself
- Add a
GET /people/{person_id}/search?q=...endpoint usinggraph.search()(Lesson 8) to find people by partial name match. - Extend
/contextto accept adepthquery parameter and usegraph.expand()(Lesson 14) instead ofget_neighbors(), returning more than one hop. - Add a
DELETE /people/{person_id}endpoint, then checkgraph.status()'spending_sync_rows(Lesson 18) immediately after, to see the delete queued the same way an insert or update would. - This is the last lesson in the course, go back to the project root README and skim the other six courses, this one's
capstone_companies/capstone_peoplegraph would slot naturally into alanggraphagent's memory layer or apydantic_aitool.