docs(07): create phase plan - 8 plans across 5 waves
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
232
.planning/phases/07-user-access-audit/07-01-PLAN.md
Normal file
232
.planning/phases/07-user-access-audit/07-01-PLAN.md
Normal file
@@ -0,0 +1,232 @@
|
||||
---
|
||||
phase: 07-user-access-audit
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- SharepointToolbox/Core/Models/UserAccessEntry.cs
|
||||
- SharepointToolbox/Services/IUserAccessAuditService.cs
|
||||
- SharepointToolbox/Services/IGraphUserSearchService.cs
|
||||
autonomous: true
|
||||
requirements:
|
||||
- UACC-01
|
||||
- UACC-02
|
||||
must_haves:
|
||||
truths:
|
||||
- "UserAccessEntry record exists with all fields needed for audit results display and export"
|
||||
- "IUserAccessAuditService interface defines the contract for scanning permissions filtered by user"
|
||||
- "IGraphUserSearchService interface defines the contract for Graph API people-picker autocomplete"
|
||||
- "AccessType enum distinguishes Direct, Group, and Inherited access"
|
||||
artifacts:
|
||||
- path: "SharepointToolbox/Core/Models/UserAccessEntry.cs"
|
||||
provides: "Data model for user-centric audit results"
|
||||
contains: "record UserAccessEntry"
|
||||
- path: "SharepointToolbox/Services/IUserAccessAuditService.cs"
|
||||
provides: "Service contract for user access auditing"
|
||||
contains: "interface IUserAccessAuditService"
|
||||
- path: "SharepointToolbox/Services/IGraphUserSearchService.cs"
|
||||
provides: "Service contract for Graph API user search"
|
||||
contains: "interface IGraphUserSearchService"
|
||||
key_links: []
|
||||
---
|
||||
|
||||
<objective>
|
||||
Define the data models and service interfaces that all subsequent plans depend on. This is the Wave 0 contract layer: UserAccessEntry record, AccessType enum, IUserAccessAuditService, and IGraphUserSearchService.
|
||||
|
||||
Purpose: Every other plan in this phase imports these types. Defining them first prevents circular dependencies and gives executors concrete contracts.
|
||||
Output: UserAccessEntry.cs, IUserAccessAuditService.cs, IGraphUserSearchService.cs
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@C:/Users/dev/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/07-user-access-audit/07-CONTEXT.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Existing models this builds alongside -->
|
||||
From SharepointToolbox/Core/Models/PermissionEntry.cs:
|
||||
```csharp
|
||||
namespace SharepointToolbox.Core.Models;
|
||||
|
||||
public record PermissionEntry(
|
||||
string ObjectType, // "Site Collection" | "Site" | "List" | "Folder"
|
||||
string Title,
|
||||
string Url,
|
||||
bool HasUniquePermissions,
|
||||
string Users, // Semicolon-joined display names
|
||||
string UserLogins, // Semicolon-joined login names
|
||||
string PermissionLevels, // Semicolon-joined role names
|
||||
string GrantedThrough, // "Direct Permissions" | "SharePoint Group: <name>"
|
||||
string PrincipalType // "SharePointGroup" | "User" | "External User"
|
||||
);
|
||||
```
|
||||
|
||||
From SharepointToolbox/Core/Models/SiteInfo.cs:
|
||||
```csharp
|
||||
namespace SharepointToolbox.Core.Models;
|
||||
public record SiteInfo(string Url, string Title);
|
||||
```
|
||||
|
||||
From SharepointToolbox/Core/Models/ScanOptions.cs (inferred from usage):
|
||||
```csharp
|
||||
public record ScanOptions(bool IncludeInherited, bool ScanFolders, int FolderDepth, bool IncludeSubsites);
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create UserAccessEntry model and AccessType enum</name>
|
||||
<files>SharepointToolbox/Core/Models/UserAccessEntry.cs</files>
|
||||
<action>
|
||||
Create `SharepointToolbox/Core/Models/UserAccessEntry.cs` with:
|
||||
|
||||
```csharp
|
||||
namespace SharepointToolbox.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Classifies how a user received a permission assignment.
|
||||
/// </summary>
|
||||
public enum AccessType
|
||||
{
|
||||
/// <summary>User is directly assigned a role on the object.</summary>
|
||||
Direct,
|
||||
/// <summary>User is a member of a SharePoint group that has the role.</summary>
|
||||
Group,
|
||||
/// <summary>Permission is inherited from a parent object (not unique).</summary>
|
||||
Inherited
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One row in the User Access Audit results grid.
|
||||
/// Represents a single permission that a specific user holds on a specific object.
|
||||
/// </summary>
|
||||
public record UserAccessEntry(
|
||||
string UserDisplayName, // e.g. "Alice Smith"
|
||||
string UserLogin, // e.g. "alice@contoso.com" or "i:0#.f|membership|alice@contoso.com"
|
||||
string SiteUrl, // The site collection URL where this permission exists
|
||||
string SiteTitle, // The site collection title
|
||||
string ObjectType, // "Site Collection" | "Site" | "List" | "Folder"
|
||||
string ObjectTitle, // Name of the list/folder/site
|
||||
string ObjectUrl, // URL of the specific object
|
||||
string PermissionLevel, // e.g. "Full Control", "Contribute"
|
||||
AccessType AccessType, // Direct | Group | Inherited
|
||||
string GrantedThrough, // "Direct Permissions" | "SharePoint Group: Members" etc.
|
||||
bool IsHighPrivilege, // True for Full Control, Site Collection Administrator
|
||||
bool IsExternalUser // True if login contains #EXT#
|
||||
);
|
||||
```
|
||||
|
||||
Design notes:
|
||||
- Each row is one user + one object + one permission level (fully denormalized for DataGrid binding)
|
||||
- IsHighPrivilege pre-computed during scan for warning icon display without re-evaluation
|
||||
- IsExternalUser pre-computed using PermissionEntryHelper.IsExternalUser pattern
|
||||
- SiteUrl + SiteTitle included so results can group by site across multi-site scans
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>UserAccessEntry.cs and AccessType enum exist in Core/Models/, compile without errors, contain all 12 fields.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Create IUserAccessAuditService and IGraphUserSearchService interfaces</name>
|
||||
<files>SharepointToolbox/Services/IUserAccessAuditService.cs, SharepointToolbox/Services/IGraphUserSearchService.cs</files>
|
||||
<action>
|
||||
Create `SharepointToolbox/Services/IUserAccessAuditService.cs`:
|
||||
|
||||
```csharp
|
||||
using SharepointToolbox.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Scans permissions across selected sites and filters results to show
|
||||
/// only what specific user(s) can access.
|
||||
/// </summary>
|
||||
public interface IUserAccessAuditService
|
||||
{
|
||||
/// <summary>
|
||||
/// Scans all selected sites for permissions, then filters results to entries
|
||||
/// matching the specified user logins. Returns a flat list of UserAccessEntry
|
||||
/// records suitable for DataGrid binding and export.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">Session manager for creating authenticated contexts.</param>
|
||||
/// <param name="targetUserLogins">Login names (emails) of users to audit.</param>
|
||||
/// <param name="sites">Sites to scan.</param>
|
||||
/// <param name="options">Scan depth options (inherited, folders, subsites).</param>
|
||||
/// <param name="progress">Progress reporter.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Flat list of access entries for the target users.</returns>
|
||||
Task<IReadOnlyList<UserAccessEntry>> AuditUsersAsync(
|
||||
ISessionManager sessionManager,
|
||||
IReadOnlyList<string> targetUserLogins,
|
||||
IReadOnlyList<SiteInfo> sites,
|
||||
ScanOptions options,
|
||||
IProgress<OperationProgress> progress,
|
||||
CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
Create `SharepointToolbox/Services/IGraphUserSearchService.cs`:
|
||||
|
||||
```csharp
|
||||
namespace SharepointToolbox.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Searches tenant users via Microsoft Graph API for the people-picker autocomplete.
|
||||
/// </summary>
|
||||
public interface IGraphUserSearchService
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches for users in the tenant whose display name or email matches the query.
|
||||
/// Returns up to <paramref name="maxResults"/> matches.
|
||||
/// </summary>
|
||||
/// <param name="clientId">The Azure AD app client ID for Graph authentication.</param>
|
||||
/// <param name="query">Partial name or email to search for.</param>
|
||||
/// <param name="maxResults">Maximum number of results to return (default 10).</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>List of (DisplayName, Email/UPN) tuples.</returns>
|
||||
Task<IReadOnlyList<GraphUserResult>> SearchUsersAsync(
|
||||
string clientId,
|
||||
string query,
|
||||
int maxResults = 10,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a user returned by the Graph API people search.
|
||||
/// </summary>
|
||||
public record GraphUserResult(string DisplayName, string UserPrincipalName, string? Mail);
|
||||
```
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>Both interface files exist in Services/, compile without errors, IUserAccessAuditService.AuditUsersAsync and IGraphUserSearchService.SearchUsersAsync are defined with correct signatures.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `dotnet build SharepointToolbox/SharepointToolbox.csproj` succeeds with 0 errors
|
||||
- UserAccessEntry.cs contains record with 12 fields and AccessType enum
|
||||
- IUserAccessAuditService.cs contains AuditUsersAsync method signature
|
||||
- IGraphUserSearchService.cs contains SearchUsersAsync method signature and GraphUserResult record
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
All three files compile cleanly. The contracts are established: downstream plans (07-02 through 07-08) can import UserAccessEntry, AccessType, IUserAccessAuditService, IGraphUserSearchService, and GraphUserResult without ambiguity.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/07-user-access-audit/07-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user