From ea8a9ca0c34d8eeeaf472382aca800c3613b2502 Mon Sep 17 00:00:00 2001 From: Elias Kohout Date: Thu, 2 Apr 2026 05:31:04 +0200 Subject: [PATCH] feat: add global user namespace for shared access Create a special _global namespace that every new user automatically gets can_create_rel access to (inclusive of can_read). This provides a shared space where all users can see and interact with published nodes. - ensureGlobalNamespace creates _global on first use with self-ownership - ensureUser grants can_create_rel to each new user on the global namespace - User visibility still relies on existing post-BFS global readability Co-Authored-By: Claude Haiku 4.5 --- src/service/node_service_impl.go | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/service/node_service_impl.go b/src/service/node_service_impl.go index bd3b7e4..20ce1f4 100644 --- a/src/service/node_service_impl.go +++ b/src/service/node_service_impl.go @@ -810,6 +810,37 @@ func (s *nodeServiceImpl) resolveUserRef(st store.GraphStore, ref string) (strin return s.ensureUser(st, ref) } +const globalNamespace = "_global" + +func (s *nodeServiceImpl) ensureGlobalNamespace(st store.GraphStore) (string, error) { + nsID, err := s.resolveIDByNameAndType(st, globalNamespace, "namespace") + if err != nil { + return "", err + } + if nsID != "" { + return nsID, nil + } + id, err := st.GenerateID() + if err != nil { + return "", err + } + now := time.Now().UTC().Format(time.RFC3339) + if err := st.AddNode(id, globalNamespace, "", nil, now, now); err != nil { + return "", err + } + if err := st.AddRel(id, "_type::namespace", ""); err != nil { + return "", err + } + if err := st.AddRel(id, string(models.RelInNamespace), id); err != nil { + return "", err + } + // Self-owned so no single user controls it. + if err := st.AddRel(id, string(models.RelHasOwnership), id); err != nil { + return "", err + } + return id, nil +} + func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (string, error) { userID, err := s.resolveIDByNameAndType(st, username, "user") if err != nil { @@ -833,6 +864,17 @@ func (s *nodeServiceImpl) ensureUser(st store.GraphStore, username string) (stri if err := st.AddRel(id, string(models.RelHasOwnership), id); err != nil { return "", err } + // Every user gets can_create_rel access to the global namespace (inclusive + // of can_read), providing a shared space where all users can see and interact with + // nodes that are published there. User nodes themselves are already + // globally readable via the post-BFS identity override in getPermContext. + globalNsID, err := s.ensureGlobalNamespace(st) + if err != nil { + return "", err + } + if err := st.AddRel(id, string(models.RelCanCreateRel), globalNsID); err != nil { + return "", err + } return id, nil }