Skip to content

Latest commit

 

History

92 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Import To Planner

CI Staging Deploy .NET 10 Licence MIT

Import To Planner is a single-purpose Blazor application for importing CSV task lists into Microsoft Planner through a safe, operator-led workflow.

Quick links:

Project Name and Description

Import To Planner converts CSV task lists into Planner tasks using a controlled workflow that separates validation, preview, and execution.

Primary purpose:

  • Provide a controlled CSV-to-Planner import workflow with validation, preview, and explicit execution confirmation.
  • Support hosted and self-hosted authority configurations through AzureAd:HomeTenantId while keeping one Graph-backed runtime path.
  • Preserve self-hosting as a permanent supported delivery mode even when hosted or commercial capabilities are added.

The workflow preserves operational safeguards:

  1. Select container.
  2. Select plan.
  3. Upload CSV and import options.
  4. Validate and preview.
  5. Confirm execution and review results.

The app now has one supported runtime path:

  • Microsoft Graph planner operations with table-backed tenant metadata and blob-backed Data Protection persistence.
  • Authentication remains authority-driven through AzureAd:HomeTenantId (multiple or a specific tenant value).

Documentation

Public end-user documentation is available at https://docs.importplanner.app.

This site covers onboarding, CSV format, import workflow, troubleshooting, FAQ, privacy and security, plus secondary self-hosted guidance.

Repository policy keeps self-hosting as a first-class supported path. Hosted or commercial features are expected to be additive rather than prerequisites for running the software from your own tenant and infrastructure.

Documentation split:

  • docs/: public end-user and operator guidance published via GitHub Pages
  • docs-internal/: internal contributor, engineering, and operational guidance

Key Features

  • Row-level and file-level CSV validation before write actions.
  • Dry-run preview separated from execution.
  • Explicit confirm-and-execute flow with stale-preview protection.
  • Existing-task matching by task name (already exists outcome).
  • Partial-success execution handling with a single retry for transient row failures.
  • Execution reporting for created items, skipped or reused items, manual actions, and errors.
  • Searchable container and plan selectors for larger tenants.
  • Clearer step-state guidance, CSV field expectations, and concise manual follow-up messaging.
  • Regression coverage for startup validation, authority handling, and single-path planner registration.
  • Optional commercial account mode with first sign-in account creation, profile page, delete-and-restore lifecycle, and retention sweep support.

Primary feature sources:

Technology Stack

  • Platform and language:
    • .NET SDK 10.0.100
    • C# 14
    • ASP.NET Core Blazor Web App
  • UI:
    • MudBlazor 9.5.0
  • Core libraries:
    • CsvHelper 33.1.0
    • Microsoft.Graph 6.1.0
    • Microsoft.Kiota.Abstractions 2.0.0
    • Microsoft.Identity.Web 4.10.0
    • Microsoft.Identity.Web.UI 4.10.0
  • Hosting and observability:
    • Aspire AppHost SDK 13.5.3
    • OpenTelemetry 1.15.x packages
    • Shared service defaults for resilience and telemetry
  • Testing:
    • xUnit v3 4.0.0
    • NSubstitute
    • bUnit 2.9.0
    • Microsoft.NET.Test.Sdk 18.9.0

Primary version sources:

Project Architecture

The solution follows layered Clean Architecture. Domain and Application own policy, Infrastructure provides adapters, and Web owns presentation and workflow state.

flowchart LR
    Web[ImportToPlanner.Web\nBlazor UI, presenters, workflow coordination] --> App[ImportToPlanner.Application\nUse cases and contracts]
    Infra[ImportToPlanner.Infrastructure.Graph\nCSV parser and planner gateways] --> App
    App --> Domain[ImportToPlanner.Domain\nBusiness concepts]
    Web --> Defaults[ImportToPlanner.ServiceDefaults\nTelemetry and resilience defaults]
    AppHost[ImportToPlanner.AppHost\nAspire AppHost] --> Web
Loading

Projects in solution:

  • src/ImportToPlanner.Domain: domain entities and business concepts.
  • src/ImportToPlanner.Application: use-case orchestration and boundary contracts.
  • src/ImportToPlanner.Infrastructure.Graph: CSV parsing and planner gateway implementations.
  • src/ImportToPlanner.Web: Blazor UI, authentication entry behaviour, and stepped workflow.
  • src/ImportToPlanner.ServiceDefaults: shared service defaults for resilience and telemetry.

Architecture and governance references:

Getting Started

Deployment modes

  • Self-hosted single-tenant mode: recommended when you want to run the app for your own organisation.
  • Hosted shared multi-tenant mode: supported for shared-service deployments across approved work or school tenants.

Self-hosting remains a permanent supported delivery path for this repository.

Commercial mode notes

  • Commercial mode is controlled by Features:CommercialMode:Enabled.
  • When enabled, the app shows a commercial sign-in gate for signed-out visitors and creates an account keyed by TenantId + UserId on first sign-in.
  • Profile management is available at /profile, including delete and restore behaviour during the retention period.
  • When commercial mode is disabled, self-hosted sign-in behaviour remains unchanged and commercial persistence is bypassed.

Choose your path

  • Run with AzureAd:HomeTenantId=multiple when you need shared-organisations authority behaviour.
  • Run with AzureAd:HomeTenantId=<tenant-id-or-domain> when you need single-tenant authority behaviour.
  • Use Aspire for both paths so storage wiring remains consistent with production.

Recommended Entra setup:

  • Hosted shared mode: use a dedicated multitenant app registration, set AzureAd:TenantId to the registration's home tenant, and set AzureAd:HomeTenantId=multiple.
  • Self-hosted mode: use a tenant-owned single-tenant app registration, set AzureAd:TenantId to that registration tenant, and set AzureAd:HomeTenantId to that same tenant.
  • Do not treat the Azure deployment tenant ID as the hosted runtime authority toggle. Runtime authority is controlled by AzureAd:HomeTenantId.

For the full internal setup guide, including the recommended separate-registration strategy and troubleshooting for the "Selected user account does not exist in tenant" error, see docs-internal/entra-app-registration-setup.md.

Prerequisites

  • .NET 10 SDK.
  • Microsoft 365 account with Planner access.
  • Entra ID app registration with required delegated permissions.
  • Local configuration for AzureAd and Graph settings.
  • Container runtime for local Azurite emulation when using Aspire.
  • Optional local tooling:
    • Aspire CLI for developer workflows and local orchestration.
    • Node.js (LTS) for local JavaScript syntax checks used in CI.
    • GitHub CLI for issue and pull request workflows.

If you prefer a containerised setup, GitHub Codespaces is supported through .devcontainer/devcontainer.json.

Restore, format, build, test

dotnet restore ImportToPlanner.slnx
dotnet format ImportToPlanner.slnx --no-restore --verify-no-changes --verbosity minimal
dotnet build ImportToPlanner.slnx
dotnet test ImportToPlanner.slnx
git ls-files '*.js' | xargs -n1 node --check

First run in VS Code

The repository includes ready-made Aspire launch profiles in .vscode/launch.json:

  • Aspire: Run (Single Tenant - In Memory) - recommended first run for contributors and local evaluation.
  • Aspire: Run (Single Tenant + Graph) - self-hosted single-tenant sign-in and real Planner calls.
  • Aspire: Run (Multi Tenant + Hosted Storage) - hosted shared multi-tenant verification with local hosted-storage emulation.

The first profile is deliberately ordered first so a new VS Code user lands on the simplest path. Profile names are historical labels; all supported paths now use Graph plus storage-backed services.

If you prefer the CLI, run the baseline validation commands above and then start the AppHost with aspire run.

Run locally without Aspire

Aspire is the recommended path because it wires storage, blobs, and tables automatically. If you need to run the Web project directly, provide equivalent connection settings and AzureAd secrets first:

dotnet user-secrets set "AzureAd:TenantId" "<app-registration-tenant-id-or-domain>" --project src/ImportToPlanner.Web
dotnet user-secrets set "AzureAd:HomeTenantId" "multiple" --project src/ImportToPlanner.Web
dotnet user-secrets set "AzureAd:ClientId" "<client-id>" --project src/ImportToPlanner.Web
dotnet run --project src/ImportToPlanner.Web/ImportToPlanner.Web.csproj

Expected behaviour:

  • Unauthenticated users are challenged through Microsoft Identity.
  • Planner data comes from Microsoft Graph.
  • Storage-backed services use the configured connection settings.

Run with a specific tenant authority

Use this path when you want sign-in constrained to one tenant:

dotnet user-secrets set "AzureAd:TenantId" "<tenant-id-or-domain>" --project src/ImportToPlanner.Web
dotnet user-secrets set "AzureAd:HomeTenantId" "<tenant-id-or-domain>" --project src/ImportToPlanner.Web
dotnet run --project src/ImportToPlanner.Web/ImportToPlanner.Web.csproj

Use a tenant-owned single-tenant app registration for this path. Keep the redirect URI aligned with the app origin you are running, always ending with /signin-oidc, and grant the delegated Graph permissions listed in src/ImportToPlanner.Web/appsettings.json.

Expected behaviour:

  • Unauthenticated sessions are redirected to sign-in.
  • Container and plan data are loaded from Microsoft Graph.
  • Sign-in remains single-tenant.

See src/ImportToPlanner.Web/appsettings.json for the full configuration shape, including AzureAd, certificate, and Graph scope placeholders, and see docs-internal/microsoft-graph-guidelines.md for implementation guidance.

Use Aspire for development workflows

Aspire is the recommended developer path because the AppHost and launch profiles keep authority and storage wiring explicit and consistent.

aspire start --isolated
aspire describe
aspire logs web
aspire stop

Notes:

  • The AppHost always starts storage, blobs, tables, and web.
  • A container runtime is needed for local Azurite emulation.
  • For deeper developer guidance, see docs-internal/developer-quickstart.md.

Project Structure

src/
  ImportToPlanner.Application/
  ImportToPlanner.Domain/
  ImportToPlanner.Infrastructure.Graph/
  ImportToPlanner.ServiceDefaults/
  ImportToPlanner.Web/
tests/
  ImportToPlanner.Tests/
  ImportToPlanner.Web.Tests/
docs/
docs-internal/
specs/
src/ImportToPlanner.AppHost/
ImportToPlanner.slnx

Repository areas:

  • src/: production projects.
  • tests/: unit, integration-style, and Blazor UI tests.
  • docs/: public-facing documentation.
  • docs-internal/: internal engineering guidance.
  • specs/: Spec Kit artefacts (specs, plans, tasks, quickstarts, contracts).

Development Workflow

This repository uses specification-led delivery and explicit governance:

Contribution flow summary:

  1. Branch from main.
  2. Keep the change focused to one logical concern.
  3. Preserve linear history (rebase or squash; no merge commits).
  4. Keep CI green before requesting review.
  5. Update tests and relevant docs with behaviour or setup changes.

See CONTRIBUTING.md for full pull request and review-thread guidance.

Coding Standards

Key standards:

  • Use UK English in user-facing and contributor-facing wording.
  • Preserve dependency direction and layer boundaries across Web, Application, Domain, and Infrastructure.
  • Keep provider-specific concepts (Graph, Kiota, transport details) in adapter layers.
  • Prefer MudBlazor components and parameters before custom CSS or HTML workarounds.
  • Use async end-to-end for I/O and avoid blocking calls.
  • Avoid exposing secrets, certificate values, or tenant-sensitive identifiers.

Standards references:

Testing

Test projects:

  • tests/ImportToPlanner.Tests: application and infrastructure tests.
  • tests/ImportToPlanner.Web.Tests: Blazor UI and workflow tests.

Run all tests:

dotnet test ImportToPlanner.slnx

Collect coverage locally:

dotnet tool install -g dotnet-coverage
dotnet-coverage collect -f cobertura -o coverage.cobertura.xml dotnet test ImportToPlanner.slnx

Testing expectations include regression coverage for changed behaviour, startup validation, and authority-specific auth handling. See tests/README.md and docs-internal/engineering-policies.md. Architecture rules that tests must satisfy live in .specify/memory/constitution.md.

Contributing

Contributions are welcome, but scope remains intentionally focused.

  • Read CONTRIBUTING.md before opening a pull request.
  • Follow CODE_OF_CONDUCT.md.
  • Keep pull requests small and focused.
  • Ensure CI checks pass before requesting review.
  • Reply to review comments in-thread.
  • Update contributor setup docs when development behaviour changes.

Recommended contributor flow:

  1. Create a branch from main.
  2. Run restore, format, build, test, and JavaScript syntax checks locally.
  3. Make the smallest change that satisfies the requirement.
  4. Update tests and documentation alongside behaviour changes.
  5. Open a PR targeting main with a clear explanation of what changed and why.

Further Reading

Licence

This project is licensed under the MIT Licence.

About

Single-use Blazor utility to import tasks from CSV into Microsoft Planner.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Sponsor this project

Used by

Contributors

Languages