// Path: Backend/internal/posixproj/projector_classify.go package posixproj import ( "path/filepath" "strings" ) func deriveScope(relPath string, rootScope Scope) Scope { scope := rootScope parts := strings.Split(relPath, "/") for _, part := range parts { switch { case strings.HasPrefix(part, "department-"): scope.DepartmentSlug = strings.TrimPrefix(part, "department-") case strings.HasPrefix(part, "team-"): scope.TeamSlug = strings.TrimPrefix(part, "team-") case strings.HasPrefix(part, "project-"): scope.ProjectSlug = strings.TrimPrefix(part, "project-") case strings.HasPrefix(part, "personal-"): scope.PersonalSlug = strings.TrimPrefix(part, "personal-") } } return scope } func classifyPath(relPath string, isDir bool) (logicalType, fileRole string) { parts := strings.Split(relPath, "/") name := parts[len(parts)-1] ext := strings.ToLower(filepath.Ext(name)) structuredRole := strings.TrimSuffix(name, filepath.Ext(name)) if !isDir { fileRole = structuredRole } hasChildrenAncestor := pathContainsSegment(parts, "children") hasTreeAncestor := pathContainsSegment(parts, "tree") parentName := "" if len(parts) >= 2 { parentName = parts[len(parts)-2] } switch { case !isDir && structuredRole == "settings" && len(parts) == 1 && ext == ".cbor": return "tenant", "settings" case !isDir && structuredRole == "layout" && len(parts) == 1 && ext == ".cbor": return "tenant", "layout" case len(parts) >= 1 && parts[0] == "catalog": if isDir { if len(parts) == 1 { return "catalog", "" } if len(parts) >= 2 && parts[1] == "packs" { if len(parts) == 2 { return "catalog_packs", "" } if len(parts) == 3 { return "catalog_pack", "" } if len(parts) >= 4 && parts[3] == "entries" { return "catalog_pack_entries", "" } return "catalog_entry", "" } if len(parts) >= 2 && parts[1] == "standalone" { if len(parts) == 2 { return "catalog_standalone", "" } return "catalog_entry", "" } } return "catalog", fileRole case len(parts) >= 2 && parts[0] == "departments" && strings.HasPrefix(parts[1], "department-"): if isDir { if len(parts) == 2 { return "department", "" } if len(parts) == 3 && parts[2] == "teams" { return "department_teams", "" } if len(parts) >= 4 && strings.HasPrefix(parts[3], "team-") { return "team", "" } } if len(parts) >= 4 && strings.HasPrefix(parts[3], "team-") { return "team", fileRole } return "department", fileRole case len(parts) >= 2 && parts[0] == "projects" && strings.HasPrefix(parts[1], "project-"): if isDir { if strings.HasPrefix(name, "project-") { return "project", "" } if name == "children" { return "project_children", "" } if name == "tree" { return "project_tree", "" } if hasChildrenAncestor && strings.HasPrefix(name, "folder-") { return "hierarchy_folder", "" } if hasTreeAncestor && strings.HasPrefix(name, "folder-") { return "hierarchy_folder", "" } if hasTreeAncestor && strings.HasPrefix(name, "item-") { return "item", "" } } if hasChildrenAncestor && strings.HasPrefix(parentName, "folder-") { return "hierarchy_folder", fileRole } if hasTreeAncestor { if strings.HasPrefix(parentName, "item-") { return "item", fileRole } if strings.HasPrefix(parentName, "folder-") { return "hierarchy_folder", fileRole } } return "project", fileRole case len(parts) >= 1 && parts[0] == "users": if isDir { if len(parts) == 1 { return "users", "" } if len(parts) == 2 && parts[1] == "personals" { return "personals", "" } if len(parts) >= 3 && parts[1] == "personals" && strings.HasPrefix(parts[2], "personal-") { return "personal", "" } if strings.Contains(relPath, "/tree/") || strings.HasSuffix(relPath, "/tree") { if strings.HasPrefix(name, "folder-") { return "folder", "" } if strings.HasPrefix(name, "item-") { return "item", "" } } } if len(parts) >= 3 && parts[1] == "personals" && strings.HasPrefix(parts[2], "personal-") { if strings.Contains(relPath, "/tree/") { if strings.HasPrefix(parts[len(parts)-2], "item-") { return "item", fileRole } if strings.HasPrefix(parts[len(parts)-2], "folder-") { return "folder", fileRole } } return "personal", fileRole } return "users", fileRole default: if isDir { return "directory", "" } return "file", fileRole } } func pathContainsSegment(parts []string, target string) bool { for _, part := range parts { if part == target { return true } } return false } func projectionParentPath(relPath string) *string { if relPath == "" || relPath == rootProjectionPath { return nil } parent := filepath.ToSlash(filepath.Dir(relPath)) if parent == "." || parent == "" { root := rootProjectionPath return &root } return &parent } func inferredResourceSlug(logicalType string, scope Scope) string { switch logicalType { case "department": return scope.DepartmentSlug case "team": return scope.TeamSlug case "project": return scope.ProjectSlug case "personal": return scope.PersonalSlug default: return "" } } func parentEntityName(logicalType string, scope Scope) string { switch logicalType { case "department": return scope.DepartmentSlug case "team": return scope.TeamSlug case "project": return scope.ProjectSlug case "personal": return scope.PersonalSlug default: return "" } } func stringValue(value any) string { stringValue, _ := value.(string) return strings.TrimSpace(stringValue) } func firstNonEmpty(values ...string) string { for _, value := range values { trimmed := strings.TrimSpace(value) if trimmed != "" { return trimmed } } return "" }