{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/dataverse-sharing-access-teams-escala/","result":{"data":{"markdownRemark":{"frontmatter":{"title":"Dataverse: controle de acesso com sharing e access teams em escala","description":"Entenda quando o record sharing e os access teams resolvem exceções de acesso no Dataverse sem inflar security roles, e por que o compartilhamento em massa degrada a performance.","date":"01 de novembro de 2026","thumbnail":null},"html":"<p>No modelo de segurança do Dataverse, a maioria dos times começa resolvendo tudo com <strong>security roles</strong> e <strong>business units</strong>. Mas há uma categoria de problema que roles não resolvem bem: o acesso <strong>por exceção</strong>, caso a caso, a registros específicos — aquele \"preciso que fulano veja só este projeto\", ou \"esta oportunidade foi passada para outro vendedor manter\". É aí que entram o <strong>record sharing</strong> e os <strong>access teams</strong>, duas mecânicas que compartilham acesso granular sem reescrever o desenho de roles. O problema é que ambas têm armadilhas de performance e governança que só aparecem em escala.</p>\n<p><strong>Como o sharing funciona por baixo</strong></p>\n<p>Quando você compartilha um registro (manualmente na UI, via <code>GrantAccessRequest</code> no SDK ou via Power Automate), o Dataverse cria uma linha na tabela de sistema <strong>PrincipalObjectAccess (POA)</strong>. Cada linha POA associa um principal (usuário ou team) a um registro específico, com um conjunto de direitos (Read, Write, Append, AppendTo, Assign, Share, Delete). Esse acesso é <strong>aditivo</strong> ao que a security role já concede — o sharing nunca tira acesso, só soma.</p>\n<p>O ponto crítico: a POA cresce com o número de <strong>combinações</strong> registro × principal. Compartilhar um registro com 1 team de 200 pessoas gera 1 linha POA (o acesso é resolvido via membership do team). Compartilhar o mesmo registro individualmente com 200 usuários gera 200 linhas. Em cenários de compartilhamento em massa — por exemplo, um flow que compartilha cada novo caso com meia dúzia de usuários — a POA pode chegar a milhões de linhas, e aí <strong>toda query</strong> que precisa avaliar acesso (praticamente todas) fica mais lenta, porque o engine precisa resolver a POA no plano de execução. Esse é um dos gargalos de performance mais difíceis de diagnosticar no Dataverse, justamente porque a tabela é invisível no modelo de dados.</p>\n<p><strong>Owner team, access team e o modo automático (access team template)</strong></p>\n<p>Teams no Dataverse vêm em dois sabores, e confundi-los custa caro:</p>\n<ul>\n<li><strong>Owner team</strong> — pode ser <strong>proprietário</strong> de registros. Tem security roles próprias, e o acesso dos membros vem dessas roles (nível Business Unit, por exemplo). Serve para \"este conjunto de registros pertence a um grupo\". A troca de membership é relativamente cara e a recomendação é manter o número de owner teams sob controle.</li>\n<li><strong>Access team</strong> — <strong>não</strong> pode ser proprietário e não carrega security roles. Existe só para receber <strong>compartilhamento</strong> de registros específicos. É o mecanismo pensado para o cenário de exceção: \"adicione este usuário ao time de acesso deste caso\".</li>\n</ul>\n<p>E há a variante poderosa: o <strong>access team template</strong>. Você define, por tabela, um template com um conjunto de direitos (ex.: Read + Write) e habilita um subgrid de \"team members\" no formulário. Quando um usuário é adicionado ao subgrid de um registro, o Dataverse cria <strong>sob demanda</strong> um access team invisível para aquele registro e compartilha com os direitos do template. Quando o último membro sai, o team é removido. Isso dá acesso por registro com uma UX limpa, sem explosão de teams manuais — mas cada membership ainda vira linha POA, então o volume continua importando.</p>\n<p><strong>Quando usar cada mecanismo</strong></p>\n<p>Um roteiro prático de decisão:</p>\n<ol>\n<li><strong>O acesso segue uma regra estrutural</strong> (departamento, região, hierarquia)? Resolva com <strong>security roles + business units</strong> (ou hierarchy security). Sharing aqui é antipadrão — vira dívida técnica.</li>\n<li><strong>O acesso é por exceção, pontual e feito por um humano</strong> no registro? <strong>Access team template</strong> com subgrid é o encaixe ideal: granular, autogerenciado, sem código.</li>\n<li><strong>O acesso é por exceção, mas disparado por lógica</strong> (um flow/plugin compartilha quando um status muda)? Use <code>GrantAccessRequest</code>/<code>ModifyAccessRequest</code> com <strong>cautela de volume</strong> — prefira compartilhar com um team em vez de N usuários, e <strong>revogue</strong> o acesso (<code>RevokeAccessRequest</code>) quando a condição deixa de valer, para não deixar POA órfã acumulando.</li>\n<li><strong>Grupos estáveis que precisam ser owner</strong> de registros? <strong>Owner team</strong> com roles.</li>\n</ol>\n<p><strong>Armadilhas que aparecem em produção</strong></p>\n<ul>\n<li><strong>Sharing em massa via flow sem revogação</strong> — o clássico. A POA cresce indefinidamente, ninguém mede, e seis meses depois as telas começam a demorar. Toda vez que você concede acesso programaticamente, planeje a revogação correspondente.</li>\n<li><strong>Usar sharing para contornar uma role mal desenhada</strong> — se você está compartilhando os mesmos registros com os mesmos grupos repetidamente, a resposta certa é um owner team ou um ajuste de role, não milhares de linhas POA.</li>\n<li><strong>Cascade de share em relacionamentos</strong> — relacionamentos com cascade <code>Share</code> propagam o compartilhamento para registros filhos. Em hierarquias profundas, um único share pode gerar uma cascata de linhas POA que você não contou.</li>\n<li><strong>Esquecer que o compartilhamento é aditivo</strong> — sharing não implementa negação. Se o requisito é \"este grupo NÃO pode ver\", sharing não é a ferramenta; isso é desenho de role/BU ou column security.</li>\n<li><strong>Ownership change não limpa shares</strong> — ao reatribuir um registro, os compartilhamentos existentes podem permanecer dependendo da configuração, deixando acesso residual.</li>\n</ul>\n<p><strong>Fechamento</strong></p>\n<p>Sharing e access teams são as ferramentas certas para acesso por exceção no Dataverse — desde que usados como exceção, não como arquitetura. Quando viram o mecanismo principal de autorização, a PrincipalObjectAccess silenciosamente se torna o maior gargalo de performance do ambiente. A regra de ouro: estrutura em roles e business units, exceção em access teams, e todo compartilhamento programático com revogação planejada.</p>\n<p>Se sua empresa opera model-driven apps ou Dynamics 365 em escala e já sente lentidão difícil de explicar, ou precisa redesenhar um modelo de segurança que virou uma teia de compartilhamentos, a Dynamic Soluções pode ajudar a auditar a POA, racionalizar roles e teams e definir um padrão sustentável de autorização.</p>\n<p>In the Dataverse security model, most teams start out solving everything with <strong>security roles</strong> and <strong>business units</strong>. But there's a class of problem roles don't handle well: <strong>exception-based</strong> access, case by case, to specific records — the \"I need this one person to see only this project,\" or \"this opportunity was handed off to another rep to maintain.\" That's where <strong>record sharing</strong> and <strong>access teams</strong> come in, two mechanisms that grant granular access without reworking your role design. The catch is that both carry performance and governance traps that only surface at scale.</p>\n<p><strong>How sharing works under the hood</strong></p>\n<p>When you share a record (manually in the UI, via <code>GrantAccessRequest</code> in the SDK, or through Power Automate), Dataverse creates a row in the system table <strong>PrincipalObjectAccess (POA)</strong>. Each POA row ties a principal (user or team) to a specific record, with a set of rights (Read, Write, Append, AppendTo, Assign, Share, Delete). This access is <strong>additive</strong> to what the security role already grants — sharing never removes access, it only adds.</p>\n<p>The critical point: POA grows with the number of record × principal <strong>combinations</strong>. Sharing a record with 1 team of 200 people generates 1 POA row (access is resolved through team membership). Sharing the same record individually with 200 users generates 200 rows. In mass-sharing scenarios — say, a flow that shares every new case with half a dozen users — POA can reach millions of rows, and then <strong>every query</strong> that needs to evaluate access (nearly all of them) gets slower, because the engine must resolve POA in the execution plan. This is one of the hardest Dataverse performance bottlenecks to diagnose, precisely because the table is invisible in the data model.</p>\n<p><strong>Owner team, access team, and the automatic mode (access team template)</strong></p>\n<p>Teams in Dataverse come in two flavors, and confusing them is costly:</p>\n<ul>\n<li><strong>Owner team</strong> — can <strong>own</strong> records. It has its own security roles, and members' access comes from those roles (Business Unit level, for example). It's for \"this set of records belongs to a group.\" Changing membership is relatively expensive, and the recommendation is to keep the number of owner teams under control.</li>\n<li><strong>Access team</strong> — <strong>cannot</strong> own records and carries no security roles. It exists only to receive <strong>sharing</strong> of specific records. It's the mechanism designed for the exception scenario: \"add this user to this case's access team.\"</li>\n</ul>\n<p>And there's the powerful variant: the <strong>access team template</strong>. Per table, you define a template with a set of rights (e.g., Read + Write) and enable a \"team members\" subgrid on the form. When a user is added to a record's subgrid, Dataverse creates an invisible access team <strong>on demand</strong> for that record and shares it with the template's rights. When the last member leaves, the team is removed. This gives per-record access with a clean UX, with no explosion of manual teams — but each membership still becomes a POA row, so volume still matters.</p>\n<p><strong>When to use each mechanism</strong></p>\n<p>A practical decision guide:</p>\n<ol>\n<li><strong>Access follows a structural rule</strong> (department, region, hierarchy)? Solve it with <strong>security roles + business units</strong> (or hierarchy security). Sharing here is an antipattern — it becomes tech debt.</li>\n<li><strong>Access is by exception, ad hoc, and done by a human</strong> on the record? An <strong>access team template</strong> with a subgrid is the ideal fit: granular, self-managed, no code.</li>\n<li><strong>Access is by exception but triggered by logic</strong> (a flow/plugin shares when a status changes)? Use <code>GrantAccessRequest</code>/<code>ModifyAccessRequest</code> with <strong>volume caution</strong> — prefer sharing with a team rather than N users, and <strong>revoke</strong> access (<code>RevokeAccessRequest</code>) when the condition no longer holds, so you don't leave orphaned POA accumulating.</li>\n<li><strong>Stable groups that need to own records?</strong> <strong>Owner team</strong> with roles.</li>\n</ol>\n<p><strong>Traps that show up in production</strong></p>\n<ul>\n<li><strong>Mass sharing via flow with no revocation</strong> — the classic. POA grows indefinitely, nobody measures it, and six months later screens start crawling. Every time you grant access programmatically, plan the matching revocation.</li>\n<li><strong>Using sharing to work around a poorly designed role</strong> — if you're sharing the same records with the same groups over and over, the right answer is an owner team or a role adjustment, not thousands of POA rows.</li>\n<li><strong>Share cascade on relationships</strong> — relationships with cascade <code>Share</code> propagate sharing to child records. In deep hierarchies, a single share can generate a cascade of POA rows you didn't account for.</li>\n<li><strong>Forgetting that sharing is additive</strong> — sharing implements no denial. If the requirement is \"this group must NOT see,\" sharing isn't the tool; that's role/BU design or column security.</li>\n<li><strong>Ownership change doesn't clean up shares</strong> — when reassigning a record, existing shares may remain depending on configuration, leaving residual access.</li>\n</ul>\n<p><strong>Closing</strong></p>\n<p>Sharing and access teams are the right tools for exception-based access in Dataverse — as long as they're used as the exception, not as the architecture. When they become the primary authorization mechanism, PrincipalObjectAccess silently becomes the environment's biggest performance bottleneck. The golden rule: structure in roles and business units, exceptions in access teams, and every programmatic share with a planned revocation.</p>\n<p>If your company runs model-driven apps or Dynamics 365 at scale and is already feeling unexplained slowness, or needs to redesign a security model that has turned into a web of shares, Dynamic Soluções can help audit POA, rationalize roles and teams, and define a sustainable authorization standard.</p>"}},"pageContext":{"slug":"/blog/dataverse-sharing-access-teams-escala/","previousPost":null,"nextPost":{"frontmatter":{"title":"Power Automate: concurrency control e ApplyToEach em paralelo sem corromper dados"},"fields":{"slug":"/blog/power-automate-concurrency-control-apply-to-each-paralelo/"}}}},"staticQueryHashes":["2269431855"]}