diff --git a/.planning/research/ARCHITECTURE.md b/.planning/research/ARCHITECTURE.md new file mode 100644 index 0000000..03860e4 --- /dev/null +++ b/.planning/research/ARCHITECTURE.md @@ -0,0 +1,440 @@ +# Architecture Patterns + +**Domain:** Pure frontend multi-step configuration wizard (static site, no backend) +**Project:** Ready2Blob +**Researched:** 2026-03-26 +**Confidence:** MEDIUM — rclone.conf format and Intune deployment patterns verified from training data (stable, well-documented domains); client-side download patterns are stable browser APIs; web research unavailable for cross-validation + +--- + +## Recommended Architecture + +### High-Level System Diagram + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Browser (Static App) │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │ +│ │ Wizard UI │───▶│ Wizard State│───▶│ Config Builders │ │ +│ │ (Steps/Nav) │ │ (Form Data) │ │ (rclone.conf + │ │ +│ └──────────────┘ └──────────────┘ │ PS Scripts) │ │ +│ └────────┬───────────┘ │ +│ │ │ +│ ┌────────▼───────────┐ │ +│ │ Download Manager │ │ +│ │ (individual files │ │ +│ │ or ZIP bundle) │ │ +│ └────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + (file download only) + │ + User's disk +``` + +No network requests leave the browser. All state is ephemeral (in-memory for the session lifetime). + +--- + +## Component Boundaries + +| Component | Responsibility | Inputs | Outputs | Communicates With | +|-----------|---------------|--------|---------|-------------------| +| **Wizard UI** | Render step forms, handle navigation (next/back/jump), validate per-step | User interactions | Step completion events | Wizard State | +| **Wizard State** | Single source of truth for all collected form data; tracks current step and completion status | Step form submissions | Reactive state object | Wizard UI (reads), Config Builders (reads) | +| **Backend Schema Registry** | Defines the fields required per rclone backend type (Azure Blob, S3, OneDrive, etc.) | Backend type selection | Field definitions for each step | Wizard UI (drives dynamic form rendering) | +| **rclone.conf Builder** | Transforms wizard state into a valid rclone.conf string | Wizard State snapshot | `rclone.conf` string | Download Manager | +| **PowerShell Script Builder** | Generates PS scripts (Intune Win32 or RMM) from wizard state + optional rclone install flag | Wizard State snapshot, script type selection | `.ps1` string(s) | Download Manager | +| **Download Manager** | Packages one or more text files and triggers browser download (individual or ZIP) | File content strings + filenames | Browser file download | rclone.conf Builder, PS Script Builder | + +--- + +## Data Flow + +``` +User fills wizard step N + │ + ▼ +Wizard UI validates step N inputs + │ + ▼ +Wizard State updated (merge step N data into central store) + │ + ▼ +User reaches Review/Download step + │ + ├──▶ rclone.conf Builder + │ reads: [remote_name, backend_type, ...backend-specific fields] + │ produces: rclone.conf string + │ + ├──▶ PowerShell Script Builder (Intune) + │ reads: [remote_name, mount_path, include_install_flag, install_source_url] + │ produces: deploy-intune.ps1 string + │ + └──▶ PowerShell Script Builder (RMM) + reads: [remote_name, mount_path, include_install_flag] + produces: deploy-rmm.ps1 string + + All strings → Download Manager + User selects files → individual download (Blob URL) or ZIP (JSZip) +``` + +Key invariant: builders are pure functions — same wizard state always produces the same file content. There is no side-effectful build step. + +--- + +## rclone.conf Format (INI-like) + +**Confidence: HIGH** — rclone.conf format is stable and well-documented. + +The rclone config file uses a simple INI-like format. Each remote is a named section. + +```ini +[remote-name] +type = azureblob +account = mystorageaccount +key = base64encodedaccesskey== +``` + +### Structure Rules + +- Section header: `[remote-name]` — any identifier the user chooses; appears in rclone commands as `remote-name:` +- Each key-value pair on its own line: `key = value` (spaces around `=` are conventional but optional) +- No quoting of values needed (rclone parses raw strings) +- Comments: lines starting with `#` or `;` +- Multiple remotes = multiple sections in the same file + +### Required Fields Per Backend + +| Backend | `type` value | Minimum required fields | Common optional fields | +|---------|-------------|------------------------|------------------------| +| Azure Blob | `azureblob` | `account`, then one of: `key`, `sas_url`, or `client_id`+`client_secret`+`tenant` | `endpoint`, `chunk_size`, `upload_cutoff` | +| AWS S3 | `s3` | `provider = AWS`, `access_key_id`, `secret_access_key`, `region` | `storage_class`, `server_side_encryption` | +| S3-compatible | `s3` | `provider = Other`, `access_key_id`, `secret_access_key`, `endpoint` | varies by provider | +| OneDrive | `onedrive` | `client_id`, `client_secret`, `token` (OAuth flow) | `drive_id`, `drive_type` | +| SFTP | `sftp` | `host`, `user`, then one of `pass` or `key_file` | `port`, `use_insecure_cipher` | +| Google Drive | `drive` | `client_id`, `client_secret`, `token` (OAuth flow) | `team_drive`, `shared_with_me` | + +### Example Full Config (Azure Blob + S3) + +```ini +[my-azure] +type = azureblob +account = contosostorage +key = dGhpcyBpcyBhIHBsYWNlaG9sZGVyIGtleQ== + +[my-s3] +type = s3 +provider = AWS +access_key_id = AKIAIOSFODNN7EXAMPLE +secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY +region = us-east-1 +``` + +### Generation Pattern + +The rclone.conf builder is pure string templating: + +```typescript +function buildRcloneConf(remotes: RemoteConfig[]): string { + return remotes.map(remote => { + const lines = [`[${remote.name}]`, `type = ${remote.type}`]; + for (const [key, value] of Object.entries(remote.params)) { + if (value !== undefined && value !== '') { + lines.push(`${key} = ${value}`); + } + } + return lines.join('\n'); + }).join('\n\n'); +} +``` + +No library needed — plain string concatenation is the correct approach. + +--- + +## Intune / RMM Deployment Patterns + +**Confidence: MEDIUM** — Intune Win32 app deployment is well-established; exact script conventions vary by org. + +### Intune Win32 App Approach + +Intune Win32 apps require a `.intunewin` package, but PowerShell-only deployments (Intune PowerShell scripts feature) are simpler and sufficient for this use case. + +The generated script must: + +1. (Optionally) download and install rclone — copy `rclone.exe` to a stable path (e.g., `C:\ProgramData\rclone\`) +2. Write `rclone.conf` to the user-appropriate path (`$env:APPDATA\rclone\rclone.conf` for per-user, or `C:\ProgramData\rclone\rclone.conf` for system-wide) +3. (Optionally) create a scheduled task or a startup script to mount the remote on login +4. Return exit code 0 on success; non-zero on failure (Intune reads exit codes) + +### Intune Script Deployment Constraints + +- Scripts run as SYSTEM by default, or as logged-on user (configurable) +- Script must handle the case where rclone is already installed (idempotent) +- 64-bit PowerShell is required for `rclone.exe` (32-bit PS cannot run 64-bit binaries reliably) +- Scripts have a 30-minute execution timeout in Intune +- Output directory for config must account for execution context (SYSTEM vs user) + +### RMM Script Approach (NinjaRMM, Datto, etc.) + +Simpler than Intune Win32: paste PS script, run as SYSTEM or user. Same functional requirements as above but no `.intunewin` packaging. Script should be self-contained. + +### PowerShell Script Structure + +```powershell +#Requires -RunAsAdministrator # or omit if running as user context + +$rclonePath = "C:\ProgramData\rclone" +$rcloneExe = "$rclonePath\rclone.exe" +$rcloneConf = "$rclonePath\rclone.conf" + +# --- Optional: Install rclone --- +# if ($InstallRclone) { ... download from $RcloneDownloadUrl ... } + +# --- Write config --- +$confContent = @" +[remote-name] +type = azureblob +account = REPLACE_ME +key = REPLACE_ME +"@ + +New-Item -ItemType Directory -Force -Path $rclonePath | Out-Null +Set-Content -Path $rcloneConf -Value $confContent -Encoding UTF8 + +# --- Optional: Register mount as scheduled task --- +# ... + +exit 0 +``` + +The PS script builder generates this structure by substituting values from wizard state into a template string. + +--- + +## Patterns to Follow + +### Pattern 1: Centralized Wizard State (Single Store) + +**What:** All form data lives in one top-level state object, passed down or accessed via context/store. Steps read from and write to slices of this store. + +**When:** Any multi-step form where later steps depend on earlier choices (e.g., backend type selection in step 1 drives which fields appear in step 2). + +**Why:** Avoids prop-drilling, makes "go back and edit" trivial, makes config builders pure functions with a single well-typed input. + +**Shape:** +```typescript +interface WizardState { + currentStep: number; + remote: { + name: string; + backendType: BackendType; + params: Record; // backend-specific key/value pairs + }; + deployment: { + includeInstall: boolean; + installSource: 'github' | 'custom'; + customInstallUrl?: string; + mountPath?: string; + scriptTargets: ('intune' | 'rmm')[]; + }; + outputOptions: { + includeConf: boolean; + includeIntune: boolean; + includeRmm: boolean; + bundleAsZip: boolean; + }; +} +``` + +### Pattern 2: Backend Schema Registry + +**What:** A static data structure (not code) that defines, per backend type, which fields are required, their labels, input types, placeholder text, and validation rules. + +**When:** The wizard needs to render dynamic forms based on which rclone backend the user selected. + +**Why:** Adding support for a new backend means adding one entry to the registry, not writing new UI components. Keeps UI code backend-agnostic. + +**Shape:** +```typescript +interface FieldDef { + key: string; // matches rclone config key exactly + label: string; + inputType: 'text' | 'password' | 'select' | 'toggle'; + required: boolean; + placeholder?: string; + helpText?: string; + options?: { value: string; label: string }[]; // for select +} + +type BackendSchema = Record; +``` + +### Pattern 3: Pure Builder Functions + +**What:** Config and script builders are pure functions — they receive wizard state and return a string. No side effects, no DOM access, no async. + +**When:** Always — this is the core generation logic. + +**Why:** Easily testable (unit test: given state X, output matches expected string). Deterministic. Separates concerns cleanly. + +### Pattern 4: Blob URL Download + +**What:** To trigger a file download in the browser without a server, create a `Blob` from the string content, generate an object URL, attach it to an `` element, and programmatically click it. + +**When:** Single file download. + +```typescript +function downloadTextFile(filename: string, content: string): void { + const blob = new Blob([content], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + a.click(); + URL.revokeObjectURL(url); +} +``` + +**Confidence: HIGH** — Blob URL download is a standard, well-supported browser API (all modern browsers, no library needed for single files). + +### Pattern 5: ZIP Bundle via JSZip + +**What:** When the user wants all generated files in one download, use JSZip to assemble a ZIP in-memory and trigger download. + +**When:** Multi-file download (rclone.conf + one or more .ps1 files). + +```typescript +import JSZip from 'jszip'; + +async function downloadZip(files: { name: string; content: string }[]): Promise { + const zip = new JSZip(); + files.forEach(f => zip.file(f.name, f.content)); + const blob = await zip.generateAsync({ type: 'blob' }); + downloadTextFile('ready2blob-deployment.zip', URL.createObjectURL(blob)); +} +``` + +**Confidence: HIGH** — JSZip is the established library for client-side ZIP creation. FileSaver.js is an optional companion for older browser compatibility but not required with the Blob URL pattern above. + +--- + +## Anti-Patterns to Avoid + +### Anti-Pattern 1: Per-Step Local State + +**What:** Each wizard step manages its own form state with no shared store. + +**Why bad:** When the user navigates back to step 2 from step 4, their inputs are gone. The config builder cannot access step 2 data from step 4. Breaks the "review before download" pattern. + +**Instead:** Lift all state to the wizard root. Steps only control their own UI (focus, error display), not their data. + +### Anti-Pattern 2: Generating Files Only at Download Time from DOM + +**What:** Reading form field values directly from the DOM to build the config string at download time. + +**Why bad:** Bypasses validation, couples the builder to the DOM structure, cannot unit-test without a browser. Fragile. + +**Instead:** Always read from wizard state, which is the validated, typed representation of user input. + +### Anti-Pattern 3: Hardcoding Backend Fields in Step Components + +**What:** Writing a dedicated ``, ``, `` component for every backend. + +**Why bad:** Adding a new backend requires a new component. Does not scale. Leads to duplication of validation logic. + +**Instead:** Use the Backend Schema Registry to drive a single generic `` that renders fields from schema definitions. + +### Anti-Pattern 4: Storing Secrets Beyond Session + +**What:** Persisting wizard state to `localStorage`, `sessionStorage`, or any cache. + +**Why bad:** Credentials (storage keys, SAS tokens) would persist on the machine after the browser tab is closed. Security risk explicitly called out in project constraints. + +**Instead:** Wizard state lives only in in-memory React/Vue/Svelte state. Closing the tab is the only "logout". + +### Anti-Pattern 5: Using a Backend for File Generation + +**What:** Sending form data to a server to generate files, which returns them as downloads. + +**Why bad:** Server receives credentials in plaintext. Violates the project's explicit no-backend constraint. Creates data retention risk. + +**Instead:** All generation is client-side (builders are pure TS/JS functions). + +--- + +## Suggested Build Order (Component Dependencies) + +Dependencies flow from foundational to dependent. Build in this order: + +``` +Phase 1 — Foundation + └── Wizard State shape definition (TypeScript types + store setup) + └── Backend Schema Registry (static data, no UI) + +Phase 2 — Core Generators (no UI needed yet, fully testable) + └── rclone.conf Builder (pure function, unit-testable immediately) + └── PowerShell Script Builder — Intune variant + └── PowerShell Script Builder — RMM variant + └── Download Manager (Blob URL + JSZip wrapper) + +Phase 3 — Wizard UI Shell + └── Step navigation (stepper, next/back, step completion tracking) + └── Wizard State wired to UI (reads/writes) + +Phase 4 — Dynamic Step Forms + └── Backend type selector (step 1) + └── Dynamic backend fields step (step 2, driven by Schema Registry) + └── Deployment options step (step 3) + └── Review + Download step (step 4, calls builders + download manager) + +Phase 5 — Polish + └── Per-step validation with user-visible errors + └── Security warning modal before download + └── Preview pane (show generated file content before download) +``` + +**Rationale for this order:** + +- Builders and the schema registry have zero UI dependencies — build and test them first +- The wizard UI shell (navigation only) can be built against mock/empty state +- Dynamic forms are built last because they depend on both state wiring AND the schema registry being final +- The download step can only be meaningfully built once all builders exist + +--- + +## Scalability Considerations + +| Concern | At MVP (5 backends) | At Growth (20+ backends) | Notes | +|---------|---------------------|--------------------------|-------| +| Backend support | Hardcode schema for top 5 | Schema registry makes adding trivial | Registry pattern is the key enabler | +| Bundle size | Single JS bundle is fine | Consider lazy-loading backend schemas | Each schema is tiny; not a real concern until 50+ backends | +| State complexity | Flat wizard state struct | No change needed | Wizard is inherently linear; state stays simple | +| Testing | Unit tests on builders | Add snapshot tests for generated files | Builders are pure functions — easiest thing to test | +| Localization | Not needed v1 | Field labels/help text in schema enables i18n | Plan label strings as separate keys in schema if i18n is future | + +--- + +## Key Technical Decisions + +| Decision | Recommended Choice | Rationale | +|----------|-------------------|-----------| +| State management | React Context + useReducer OR Zustand (lightweight store) | No server state; no need for React Query or Redux. Zustand reduces boilerplate vs Context for this use case. | +| ZIP library | JSZip v3 | De facto standard for browser ZIP. No alternatives with meaningful adoption. | +| File download | Native Blob URL API | No library needed. FileSaver.js unnecessary for modern browsers. | +| Config generation | Plain string templates (template literals) | rclone.conf is simple enough that a template engine adds no value. | +| Script generation | Template literal function per script type | Same reasoning. Mustache/Handlebars would be overkill. | +| Backend schema | Static TypeScript object (no database, no fetch) | Schemas are known at build time. Static data = zero loading time. | + +--- + +## Sources + +- rclone.conf format: training data (stable since rclone v1.x; format has not changed); confidence HIGH +- Azure Blob rclone backend fields: training data; confidence MEDIUM (specific field names should be cross-checked against https://rclone.org/azureblob/ before implementing the schema registry) +- Intune PowerShell script deployment: training data; confidence MEDIUM (execution context and timeout limits are well-documented but should be verified for current Intune behavior) +- JSZip client-side ZIP: training data; confidence HIGH (library API is stable) +- Blob URL download pattern: training data (standard browser API, MDN-documented); confidence HIGH +- Web search and WebFetch unavailable during this research session — claims marked MEDIUM should be verified against official docs during implementation phases diff --git a/.planning/research/FEATURES.md b/.planning/research/FEATURES.md new file mode 100644 index 0000000..8dceb14 --- /dev/null +++ b/.planning/research/FEATURES.md @@ -0,0 +1,144 @@ +# Feature Landscape + +**Domain:** rclone configuration wizard / enterprise deployment helper +**Project:** Ready2Blob +**Researched:** 2026-03-26 +**Confidence note:** External research tools (WebSearch, WebFetch, Bash) were unavailable in this session. All findings are from training data (knowledge cutoff August 2025). Confidence levels are assigned conservatively. Recommend validating against live rclone docs and community forums before finalizing. + +--- + +## Table Stakes + +Features IT admins expect. Missing any of these means the tool gets discarded immediately. + +| Feature | Why Expected | Complexity | Notes | +|---------|--------------|------------|-------| +| Multi-step backend selection wizard | rclone has 50+ backends; admins need guided selection, not raw docs | Medium | First screen should show backends sorted by popularity: Azure Blob, S3, OneDrive, SFTP, then others | +| Per-backend field forms with labels | Each backend has different required fields (account name vs access key vs OAuth token); forms must match | Medium | Source of truth is rclone's own `rclone config` flow; replicate those fields exactly | +| Valid rclone.conf output | The generated file must be parseable by rclone with no errors | Low | INI-like format: `[remote-name]`, `type = azureblob`, then key=value pairs. Pure string generation | +| Remote name customization | Admins name remotes to match org conventions (e.g., `corp-backup`, `client-files`) | Low | Single text input, validated to allow only rclone-safe characters (alphanumeric, dash, underscore) | +| Intune PowerShell deployment script | Intune Win32 app or PS script deployment is the dominant MDM workflow for Windows | High | Must handle: detection script, install script, optional rclone.exe download, config placement at correct path | +| RMM deployment script | NinjaRMM, Datto RMM, ConnectWise Automate, Syncro — MSP-dominant tools | High | Single PS script that downloads rclone if needed and drops config; simpler than Intune (no detection logic needed) | +| Optional rclone install inclusion | Some orgs already have rclone in their baseline image; others don't | Medium | Checkbox: "Include rclone installation". If checked, script downloads from rclone.org/downloads or GitHub releases | +| Security warning before download | Credentials are in plain text in generated files — legal/compliance exposure if admin doesn't understand | Low | Modal or banner: "This file contains your storage credentials in plain text. Store and transmit securely." Must be impossible to miss | +| Download individual output files | Admin may only need the .conf, or only the script, depending on their environment | Low | Separate download buttons for each generated artifact | +| No data sent to server | IT security teams will ask "where do my credentials go?" — answer must be "nowhere, browser only" | Low | Static site + client-side generation. Prominently state this in UI | + +## Differentiators + +Features that set Ready2Blob apart from "just read the rclone docs" or copy-pasting PS scripts from Reddit. + +| Feature | Value Proposition | Complexity | Notes | +|---------|-------------------|------------|-------| +| Intune-specific detection script generation | Intune Win32 apps require a separate detection script (exit 0 = installed); most admins copy-paste wrong ones | Medium | Detect by checking rclone.exe presence at install path AND config file presence. Both must exist | +| Intune packaging hints / IntuneWinAppUtil guidance | After generating scripts, show admin the exact IntuneWinAppUtil command to wrap the installer | Low | Static text block, not dynamic generation — but reduces a common stumbling point | +| RMM-specific script variants | NinjaRMM, Datto, and ConnectWise have slightly different execution contexts (SYSTEM vs user, working dir) | High | Start with a generic "SYSTEM context" PS script that works across RMMs; add named variants later | +| Rclone version pinning | MSP environments require reproducible deployments; "latest" is not acceptable for production | Low | Text input: "Pin to rclone version" (e.g., `v1.68.2`). Defaults to latest stable. Affects download URL in script | +| Config placement path options | Config can go to `%APPDATA%\rclone\rclone.conf` (user) or a machine-wide path. Intune SYSTEM context needs machine-wide | Medium | Dropdown: User profile path vs machine-wide path (`C:\ProgramData\rclone\`). Explain implications of each | +| Multiple remotes in one config | A single rclone.conf can contain multiple named remotes; some orgs need 2-3 backends on same endpoint | High | Allow "Add another remote" in wizard. Generates a single .conf with multiple sections | +| Live config preview | Admin sees the exact text of generated files before downloading — builds trust, catches errors | Low | Syntax-highlighted read-only textarea. Updates in real time as form fields change | +| Copy-to-clipboard for each output | Some RMM tools have a "run script" field — paste directly without downloading a file | Low | Copy button beside each output block | +| Field-level validation with rclone-specific rules | Azure Blob storage account names are 3-24 lowercase alphanumeric chars — catch this before the admin deploys a broken config | Medium | Per-field regex/rule validation. Reduces "why doesn't rclone connect?" support tickets | +| Explanatory tooltips on sensitive fields | "What is an SAS token vs an Access Key?" — admins often don't know which credential type to use | Low | Tooltip or inline help text per field. Reduces abandonment from confusion | +| Backend popularity ordering | Show Azure Blob, S3, OneDrive, SFTP, GCS at top — don't bury them alphabetically | Low | Simple UX decision with high impact on time-to-task-complete | + +## Anti-Features + +Features to explicitly NOT build in v1 — scope creep killers. + +| Anti-Feature | Why Avoid | What to Do Instead | +|--------------|-----------|-------------------| +| Test connection / validate credentials | Requires a backend proxy (CORS blocks direct cloud API calls from browser); breaks the "no server" constraint entirely | Show a callout: "Run `rclone lsd remote-name:` on any Windows PC after deploying to verify connectivity" | +| Save / load configurations | Requires either a backend (no-server constraint violated) or localStorage (credentials in browser storage = security incident) | Tell user to save the downloaded .conf file. That IS their save format | +| User accounts / authentication | No backend = no accounts. Would require a complete architecture rethink | Out of scope permanently for v1. Re-evaluate only if architecture changes | +| rclone mount / sync scheduling | UI for configuring rclone mount or scheduled sync jobs adds a second problem domain (task scheduler, Windows service) on top of the first | Separate product decision. Ready2Blob focuses solely on getting rclone configured and deployed | +| Auto-push to Intune via Graph API | Would require Azure AD app registration, OAuth flow, Graph API integration — massive scope increase | Generate files the admin uploads manually. Graph API is a v2+ consideration | +| Multi-OS support (macOS, Linux) | Scripts are PowerShell for Windows. macOS/Linux have different path conventions, shell scripts, MDM tools | Out of scope for v1. State clearly in UI: "Windows endpoints only" | +| rclone version auto-update logic | Keeping rclone up to date on endpoints is a separate lifecycle management problem | Point admin to rclone's own update mechanism or their RMM's patch management | +| Visual diff of old vs new config | Requires knowing what's already deployed — impossible without a backend | Not viable without persistence layer | +| Encryption of config credentials | rclone supports `rclone config` password-encrypted configs but requires interactive unlock on each use, incompatible with unattended deployment | Document the limitation; recommend Azure Key Vault or Intune-native secrets for sensitive deployments | + +--- + +## Feature Dependencies + +``` +Backend selection + → Per-backend form fields (fields depend on selected backend type) + → Remote name input + → rclone.conf generation (depends on: backend type, all field values, remote name) + → Intune script generation (depends on: config content, install option, config path choice) + → RMM script generation (depends on: config content, install option, config path choice) + → Version pin input (affects download URL inside both scripts) + → Config path option (affects file placement command inside both scripts) + +Live config preview → rclone.conf generation (real-time rendering of same output) +Download buttons → all generation outputs (nothing to download until form is valid) +Security warning → download buttons (warning must be acknowledged before download is enabled) +``` + +--- + +## MVP Recommendation + +Prioritize in this order: + +1. Backend selection + per-backend forms (Azure Blob, S3, OneDrive, SFTP as initial set — covers 80% of use cases) +2. rclone.conf generation with live preview +3. Intune PowerShell script generation (primary target audience pain point) +4. RMM PowerShell script generation +5. Security warning gate before download +6. Optional rclone install toggle +7. Config path selector (user vs machine-wide) + +Defer to post-MVP: + +- Multiple remotes in one config: adds wizard UX complexity; single remote covers the majority of deployments +- RMM-named variants (NinjaRMM-specific, Datto-specific): start with generic SYSTEM-context PS script +- Intune IntuneWinAppUtil packaging hints: valuable but can be a static docs page +- Version pinning: default to latest stable with a text field; low-effort add +- Field-level validation beyond basic required-field checks: adds significant per-backend maintenance burden + +--- + +## Backend Coverage Priority + +Based on enterprise Windows deployment prevalence (HIGH confidence from domain knowledge): + +| Tier | Backends | Rationale | +|------|----------|-----------| +| Tier 1 — Must ship in v1 | Azure Blob Storage, Amazon S3, Microsoft OneDrive | Dominant in enterprise; covers ~70% of use cases. "Ready2Blob" brand implies Azure first | +| Tier 2 — Ship in v1 if feasible | SFTP, Google Cloud Storage, Backblaze B2 | Common in MSP environments and SMB | +| Tier 3 — Post-v1 | Google Drive, Dropbox, SharePoint, S3-compatible (Wasabi, MinIO, etc.) | Consumer-origin or niche; lower enterprise priority | +| Tier 4 — Document only | All remaining rclone backends (50+) | Too many to form-ify in v1; link to rclone docs | + +**Note on S3-compatible backends:** Amazon S3 forms should include an "endpoint override" field so the same form handles Wasabi, MinIO, Cloudflare R2, etc. This is how rclone handles them natively — `provider` + optional `endpoint`. One form, many backends. (MEDIUM confidence — verify against rclone S3 docs) + +--- + +## IT Admin Expectations (Contextual) + +These are workflow expectations rather than discrete features, but they inform every feature decision: + +- **Scripts must run as SYSTEM** — Intune and most RMMs execute scripts as SYSTEM, not as the logged-in user. Config path must be machine-wide, not `%APPDATA%`. This is the single most common deployment failure mode. +- **Scripts must be idempotent** — Running the install script twice must not break anything. Check-then-act pattern: if rclone.exe already exists and config already exists, exit 0. +- **Scripts must have exit codes** — Intune uses exit codes to determine success/failure of a deployment. Script must exit 0 on success, non-zero on failure. +- **Detection scripts must be separate from install scripts** — Intune Win32 app model requires them to be distinct. Many generated scripts online conflate them. +- **No interactive prompts** — Scripts run silently. Any `Read-Host`, `Write-Host` expecting input, or UAC prompt breaks unattended deployment. +- **64-bit PowerShell** — Intune on 64-bit Windows sometimes executes PS in 32-bit mode. rclone.exe path may differ. Scripts should force 64-bit context or be path-aware. + +(Confidence: HIGH for SYSTEM context and exit codes — verified by common Intune troubleshooting canon. MEDIUM for 32/64-bit PS caveat — common but less universally documented.) + +--- + +## Sources + +- rclone official documentation (rclone.org) — not fetched in this session due to tool restrictions; referenced from training data (knowledge cutoff August 2025) +- Microsoft Intune Win32 app deployment model — training data (HIGH confidence on SYSTEM context, exit codes, detection script requirements) +- RMM deployment patterns (NinjaRMM, Datto, ConnectWise) — training data (MEDIUM confidence) +- rclone.conf INI format specification — training data (HIGH confidence; format is stable and well-documented) + +**Validation recommended before roadmap finalization:** +- Confirm current rclone backend list and required fields per backend at rclone.org/overview +- Confirm Intune Win32 app detection script requirements in current Microsoft docs +- Check if rclone has changed S3-compatible `provider`+`endpoint` pattern in recent releases diff --git a/.planning/research/PITFALLS.md b/.planning/research/PITFALLS.md new file mode 100644 index 0000000..f0fd7ce --- /dev/null +++ b/.planning/research/PITFALLS.md @@ -0,0 +1,362 @@ +# Domain Pitfalls + +**Domain:** rclone config generator / PowerShell deployment wizard (Windows/Intune/RMM) +**Researched:** 2026-03-26 +**Confidence:** HIGH (Intune/PowerShell — verified against official Microsoft docs), MEDIUM (rclone-specific — based on format spec knowledge plus training data; rclone docs were inaccessible during research) + +--- + +## Critical Pitfalls + +Mistakes that cause the generated script/config to silently fail or require a full rewrite. + +--- + +### Pitfall 1: rclone config deployed to wrong path under SYSTEM context + +**What goes wrong:** +When Intune deploys a PowerShell script with "Run as SYSTEM" (the `No` logged-on-credentials option), the script runs as `NT AUTHORITY\SYSTEM`. The default rclone config location resolves from the SYSTEM user's `%APPDATA%`, which is `C:\Windows\system32\config\systemprofile\AppData\Roaming\rclone\rclone.conf`. This path is not readable by the end user who will later run rclone interactively. The config is deposited silently with no error, but rclone launched by the user finds no config. + +**Why it happens:** +rclone resolves config location from environment variables at runtime. Under SYSTEM, `%APPDATA%` and `%USERPROFILE%` expand to the SYSTEM profile paths, not any individual user's profile. Developers test locally as themselves and never hit this path. + +**Consequences:** +- rclone runs with no configuration; all sync commands fail with "no remote" error +- Hard to debug because the config file exists on disk — just in the wrong place +- If the wizard generates a hardcoded `%APPDATA%` path string in the script, that string is evaluated at deployment time (SYSTEM), not at user runtime + +**Prevention:** +- The generated script must write the config to a machine-wide path such as `C:\ProgramData\rclone\rclone.conf` and then invoke rclone with `--config "C:\ProgramData\rclone\rclone.conf"` (or set `RCLONE_CONFIG` env var). +- Alternatively: write to each user's profile by running in user context — but SYSTEM context is common for silently deploying software. +- The wizard should make the config destination path explicit and let the IT admin choose: machine-wide vs. user-profile. Never default to a bare `%APPDATA%` expansion in a SYSTEM-context script. + +**Detection:** +- Config exists at SYSTEM profile path but rclone launched by user says "no remote configured" +- Check `rclone config file` — it will show the wrong path + +**Phase relevance:** Phase generating the PowerShell script (any phase touching script output) + +--- + +### Pitfall 2: Intune PowerShell scripts are size-limited to 200 KB (ASCII) + +**What goes wrong:** +Microsoft Intune enforces a hard 200 KB (ASCII) size limit on uploaded PowerShell scripts. Scripts that embed a large rclone installer binary (base64-encoded), or that inline multiple large config payloads, will be rejected at upload time. + +**Why it happens:** +IT developers prototype a "self-contained" script that downloads rclone, unpacks it, writes the config, and sets up a scheduled task — all in one file. Base64-encoding a ~50 MB rclone binary produces a ~67 MB string. Even base64-encoding a 400 KB installer produces a 550 KB string, well over the limit. + +**Consequences:** +- Script upload fails; IT admin gets a non-obvious error in Intune +- Workaround requires restructuring the entire script delivery approach + +**Prevention:** +- The wizard must never embed rclone binary content into the generated script +- The rclone installation step must use a network download (e.g., `Invoke-WebRequest` from the rclone GitHub releases API or a corporate file share URL) or reference a Win32 app deployment separately +- Clearly surface this constraint in the wizard: "rclone binary will be downloaded from [URL] at deployment time" — and let the admin specify an internal mirror if internet access is restricted on endpoints + +**Detection:** +- Intune admin center shows upload error "Script size exceeds limit" +- Script file is visibly large before upload + +**Phase relevance:** Phase implementing the rclone-install option in script generation + +--- + +### Pitfall 3: PowerShell script encoding mismatch causes silent config corruption + +**What goes wrong:** +The generated PowerShell script writes the rclone config file to disk using `Set-Content` or `Out-File`. The default encoding in Windows PowerShell 5.1 is UTF-16 LE with BOM for `Out-File`, and varies for `Set-Content` (system codepage/ANSI on PS 5.1, UTF-8 no-BOM on PS 7+). rclone expects its config file in UTF-8. A config with a UTF-16 BOM or ANSI-encoded special characters (common in storage keys) will be misread, causing authentication failures. + +**Why it happens:** +Developers write `Out-File $configPath` and it works in their test because all values are ASCII. The bug surfaces when a customer has a storage account key or SAS token containing characters that differ between encodings, or when the file has a BOM that confuses rclone's parser. + +**Consequences:** +- rclone silently reads a corrupt config; authentication fails with opaque errors +- Hard to reproduce because it only manifests with certain key contents + +**Prevention:** +- The generated script must always write the config with explicit UTF-8 no-BOM encoding: + ```powershell + [System.IO.File]::WriteAllText($configPath, $configContent, [System.Text.Encoding]::UTF8) + ``` + or + ```powershell + Set-Content -Path $configPath -Value $configContent -Encoding UTF8 + ``` + Note: In PowerShell 5.1, `-Encoding UTF8` writes UTF-8 *with* BOM. Use `[System.IO.File]::WriteAllText` with `new System.Text.UTF8Encoding($false)` to guarantee no BOM. +- The wizard's script template must hardcode the correct write method; never leave encoding to PS default + +**Detection:** +- Open the written config in a hex editor: UTF-16 has `FF FE` as first bytes; UTF-8 BOM has `EF BB BF` +- rclone error: "unexpected character at start of file" or authentication failures on otherwise valid credentials + +**Phase relevance:** Any phase producing the PowerShell script template + +--- + +### Pitfall 4: rclone config section names collide with rclone reserved names or contain invalid characters + +**What goes wrong:** +rclone remote names in the config are used on the command line as `remotename:path`. The name becomes part of shell arguments and rclone's internal addressing. Names with spaces, colons, forward slashes, or square brackets break the INI section header (`[remote name]` is valid INI only if the name contains no `]`). Names that match rclone built-in remote types (e.g., naming a remote "local", "union", "memory") cause confusing errors. Names starting with a dash conflict with CLI flag parsing. + +**Why it happens:** +The wizard lets IT admins freely type a remote name without validation. The name goes into `[user input]` verbatim. + +**Consequences:** +- Config is syntactically broken (rclone fails to parse) +- Or config parses but the remote cannot be referenced on the command line +- Error messages are cryptic: "Failed to create file system for remotename: didn't find section in config file" + +**Prevention:** +- Validate remote names in the wizard UI before generation: allow only `[a-zA-Z0-9_-]`, max ~40 chars, no leading dash +- Show a live preview of the section header: `[my-remote]` +- Reject reserved-looking names or warn on them + +**Detection:** +- rclone returns "didn't find section in config file" when the name contains special characters +- rclone returns parse error when name contains `]` + +**Phase relevance:** Wizard input validation phase; config generation phase + +--- + +### Pitfall 5: Secrets embedded in generated scripts are exposed in Intune admin center logs + +**What goes wrong:** +Intune logs PowerShell script output and stores it in the Azure portal (AgentExecutor.log on endpoint + reporting in Intune admin center). If the generated script echoes the config content or uses `Write-Host` with credential values for debugging, those secrets are persisted in logs accessible to any Intune admin. + +**Why it happens:** +Developers add debug output during testing ("Writing config: [content]") and forget to remove it. Or error handlers dump the config on failure. + +**Consequences:** +- Storage account keys, SAS tokens, or OAuth secrets appear in Intune reporting +- Violates least-privilege and secrets hygiene; potential audit/compliance failure + +**Prevention:** +- The wizard's generated script template must never echo credential values +- Use a sentinel like `Write-Host "Writing config to $configPath"` (path only, no content) +- Add a comment in the generated script: `# Do not add Write-Host or logging for $configContent` +- The wizard UI must display a security warning at download time (already planned per PROJECT.md) + +**Detection:** +- Audit the script template for any interpolation of credential variables into strings passed to output cmdlets + +**Phase relevance:** Script template design (early phase); security review before any release + +--- + +## Moderate Pitfalls + +--- + +### Pitfall 6: Group Policy overrides PowerShell execution policy set in the script + +**What goes wrong:** +The generated script attempts to set `Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned` or `Bypass`. In enterprise environments with Group Policy managing `MachinePolicy` or `UserPolicy` execution policy scopes, the script's `Set-ExecutionPolicy` call has no effect — Group Policy always wins. The script appears to succeed (no error from `Set-ExecutionPolicy`) but subsequent script logic may still fail if the endpoint GP enforces `AllSigned` or `Restricted`. + +**Why it happens:** +Official Microsoft docs confirm: "Set-ExecutionPolicy doesn't override a Group Policy, even if the user preference is more restrictive than the policy." Intune itself bypasses execution policy for its own scripts (IME uses `-ExecutionPolicy Bypass` internally), but any child processes spawned by the script inherit the GP-enforced policy. + +**Consequences:** +- Scripts that call `& rclone.exe` or invoke helper `.ps1` files from within the script fail with execution policy errors +- Developers test on unmanaged machines and never observe GP interference + +**Prevention:** +- The generated script should not attempt to change execution policy +- Any sub-scripts should be invoked with `-ExecutionPolicy Bypass` in the powershell.exe call, or avoided entirely (inline everything) +- Document this in the wizard's "Intune deployment" output pane + +**Detection:** +- `Get-ExecutionPolicy -List` on target machine shows `MachinePolicy = AllSigned` +- Script works in test but fails on managed fleet endpoints + +**Phase relevance:** Script generation phase; testing guidance + +--- + +### Pitfall 7: 32-bit vs 64-bit PowerShell host affects path resolution + +**What goes wrong:** +Intune's default is to run scripts in the 32-bit PowerShell host (`Run script in 64-bit PowerShell host = No`). On 64-bit Windows, 32-bit processes use File System Redirector: `System32` resolves to `SysWOW64`, and `%ProgramFiles%` resolves to `%ProgramFiles(x86)%`. If the generated script installs rclone to `$env:ProgramFiles\rclone\` under 32-bit context, the binary lands in `C:\Program Files (x86)\rclone\`, not `C:\Program Files\rclone\`. When the user runs rclone from a 64-bit shell, they look in `Program Files` and find nothing. + +**Why it happens:** +The Intune "Run in 64-bit" option defaults to `No` per Microsoft docs. Developers test in a normal 64-bit PowerShell session. + +**Consequences:** +- rclone binary installed to wrong Program Files variant +- PATH entries or shortcuts point to non-existent location + +**Prevention:** +- The generated script should use `$env:ProgramW6432` (always the native 64-bit Program Files on 64-bit Windows) or hardcode `C:\Program Files\rclone\` +- The wizard UI for Intune output should recommend enabling "Run script in 64-bit PowerShell host" and document why +- Alternatively, use `C:\ProgramData\rclone\` which is not subject to WOW64 redirection + +**Detection:** +- rclone binary absent from expected path after deployment +- `[System.Environment]::Is64BitProcess` returns `False` inside the running script + +**Phase relevance:** Script generation phase; Intune deployment option + +--- + +### Pitfall 8: OAuth-backed backends require interactive browser flow — incompatible with SYSTEM/headless deployment + +**What goes wrong:** +rclone backends that use OAuth (OneDrive, Google Drive, Dropbox, Box, etc.) require an interactive browser authorization step to generate the token. The rclone config for these backends includes an `token = {...}` JSON blob. If the IT admin generates a config without pre-populating this token, the deployment script writes a config with no token. When rclone first runs on the endpoint, it attempts an interactive browser flow — which silently fails or hangs in a SYSTEM/headless context. + +**Why it happens:** +The wizard generates the config from form inputs. For OAuth backends, the wizard cannot complete the OAuth flow on behalf of the user — there is no rclone running in the browser context to perform `rclone config`. The IT admin might not realize the token needs to be obtained separately on a reference machine. + +**Consequences:** +- Deployed rclone silently does nothing or opens a browser on the endpoint +- Most prominent with OneDrive; affects any backend requiring `rclone authorize` + +**Prevention:** +- For OAuth backends, the wizard must show a prominent notice: "This backend requires an OAuth token. You must run `rclone config` or `rclone authorize` on a reference Windows machine as the target user, then copy the resulting token value into this wizard." +- The wizard should provide a dedicated "OAuth token" input field for token-based backends, with instructions for how to extract the token from `rclone config show remotename` +- Consider warning against deploying OAuth backends via SYSTEM-context Intune scripts entirely; recommend user-context deployment instead + +**Detection:** +- Config section for OneDrive/GDrive has no `token =` line +- rclone first-run opens a browser on the endpoint or exits with "no token found" + +**Phase relevance:** Backend-specific configuration phase; wizard backend selection step + +--- + +### Pitfall 9: SAS tokens and storage keys contain characters that need escaping in INI values + +**What goes wrong:** +Azure SAS tokens contain `%`, `=`, `&`, and `+` characters. Azure storage keys contain `+` and `/` and end in `==`. In rclone's INI config format, values are read until end-of-line — no quoting needed for most characters — but if the value accidentally contains a line-break (e.g., from copy-paste in a browser field that wraps), the config is truncated silently. If the generated value is also used inside a PowerShell string interpolation (e.g., `"sas_url = $sasToken"`), PowerShell variable substitution can corrupt values containing `$`. + +**Why it happens:** +The wizard builds the config as a JavaScript template literal. Storage keys and SAS tokens pasted by users may include trailing newlines or spaces. PowerShell double-quoted strings treat `$` as variable prefix. + +**Consequences:** +- Truncated SAS token causes authentication failures with opaque Azure storage errors +- Corrupted key causes "AuthenticationFailed" from Azure + +**Prevention:** +- Trim all credential inputs in the wizard before inserting into the config (strip leading/trailing whitespace including `\n`, `\r`) +- In the PowerShell script template, use single-quoted strings for the config content (PowerShell single-quoted strings do not interpolate `$`): + ```powershell + $configContent = @' + [myremote] + type = azureblob + account = mystorageaccount + key = ABC+xyz== + '@ + ``` + (here-string with single-quote terminator) +- Validate that credential inputs do not contain newlines before generating + +**Detection:** +- Config file, when opened, shows a truncated key value +- rclone error: "failed to parse config file" or Azure "AuthenticationFailed" + +**Phase relevance:** Config generation logic (core phase) + +--- + +### Pitfall 10: Windows path length limit (MAX_PATH = 260) breaks rclone operations on deep directory trees + +**What goes wrong:** +On Windows versions before Windows 10 1607, and on any Windows where the Long Path registry key is not set, paths exceeding 260 characters cause rclone operations to fail silently or with cryptic I/O errors. rclone syncing deep SharePoint or OneDrive folder trees commonly hits this. The deployment script may also fail if it writes files to paths that are too long (e.g., user profile paths with long usernames inside long corporate folder structures). + +**Why it happens:** +Windows enforces MAX_PATH = 260 by default per `kernel32.dll`. IT admins don't control the endpoint's registry setting. The wizard generates scripts without path-length guards. + +**Consequences:** +- rclone skips or errors on files with long paths +- `New-Item` or `Set-Content` in the PowerShell script itself can fail if the config destination path is long + +**Prevention:** +- The wizard should recommend using `C:\ProgramData\rclone\` (short path) for config and binary placement, not user-profile paths +- Generated scripts should include a check and optionally enable long paths: + ```powershell + Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1 + ``` + (requires admin rights; typically available in SYSTEM context) +- Document the limitation in the wizard output pane for Intune deployments + +**Detection:** +- rclone logs show `ERROR: ... path too long` +- PowerShell script itself fails with "The specified path, file name, or both are too long" + +**Phase relevance:** Script generation; deployment documentation phase + +--- + +## Minor Pitfalls + +--- + +### Pitfall 11: Intune script runs once per device; config changes don't re-deploy unless script is modified + +**What goes wrong:** +Intune only re-runs a PowerShell script if the script content changes or is reassigned. If the IT admin generates a new config (different credentials, different remote name) and wants to update the deployed config, they must upload a new version of the script to Intune. If they upload the exact same script bytes with only a comment changed, the re-run is triggered. But if they don't know this, they think re-assigning the unchanged script will update endpoints — it won't. + +**Prevention:** +- Document this in the wizard output: "To update config on endpoints, modify and re-upload the script (e.g., bump a version comment) to trigger Intune re-execution." +- Consider auto-inserting a `# Generated: [timestamp]` comment in each script so re-generated scripts always differ + +**Phase relevance:** Documentation/UX phase + +--- + +### Pitfall 12: rclone binary download URL in the script becomes stale + +**What goes wrong:** +The generated script contains a hardcoded rclone download URL (e.g., `https://downloads.rclone.org/rclone-current-windows-amd64.zip`). rclone uses the filename `rclone-current-*` as a redirect alias. This URL is stable, but if the wizard hardcodes a specific version URL (e.g., `v1.68.0`) to ensure repeatability, that version URL remains functional but the binary may have known issues. If the wizard uses `current`, the binary silently upgrades, potentially introducing breaking changes. + +**Prevention:** +- Use the `rclone-current-windows-amd64.zip` alias for the default path (always latest stable) +- Allow an override field for IT admins who want to pin a version +- Add a comment in the generated script stating the resolved version strategy + +**Phase relevance:** Script generation (rclone install option) + +--- + +### Pitfall 13: Generated config has Windows-style line endings that cause issues on cross-platform rclone use + +**What goes wrong:** +JavaScript running in a browser on Windows may produce `\r\n` line endings when building the config string (less likely with modern JS but possible with string concatenation involving platform newlines). rclone's INI parser handles `\r\n` correctly on Windows, but if the config is later copied to a Linux/macOS system, the `\r` characters appear in values. + +**Prevention:** +- Explicitly normalize line endings to `\n` in the config generation logic before download +- Use `content.replace(/\r\n/g, '\n').replace(/\r/g, '\n')` before creating the Blob for download + +**Phase relevance:** Config generation (frontend logic) + +--- + +## Phase-Specific Warnings + +| Phase Topic | Likely Pitfall | Mitigation | +|-------------|---------------|------------| +| Script template design | SYSTEM context config path mismatch (Pitfall 1) | Use machine-wide path; document context options | +| rclone install option | 200 KB Intune script size limit (Pitfall 2) | Download-only; never embed binary | +| Script file write logic | PowerShell encoding writes UTF-16 BOM (Pitfall 3) | Use `[System.IO.File]::WriteAllText` with explicit UTF-8 no-BOM | +| Remote name input field | Invalid characters in section name (Pitfall 4) | Validate `[a-zA-Z0-9_-]` in UI before generation | +| Debug/error output in script | Secrets exposed in Intune logs (Pitfall 5) | No credential interpolation in output cmdlets | +| Execution policy in script | GP overrides any Set-ExecutionPolicy call (Pitfall 6) | Do not set policy; use `-ExecutionPolicy Bypass` on sub-processes | +| Intune script options | 32-bit host path redirection (Pitfall 7) | Use `$env:ProgramW6432` or `C:\ProgramData\rclone\` | +| OAuth backend config | Headless OAuth flow impossible (Pitfall 8) | Require pre-obtained token; prominent wizard warning | +| Credential input handling | SAS/key corruption via whitespace or `$` (Pitfall 9) | Trim inputs; single-quoted PowerShell here-strings | +| Config/binary placement | MAX_PATH exceeded on deep trees (Pitfall 10) | Short machine-wide paths; optionally enable long paths | +| Re-deployment UX | Intune won't re-run identical script (Pitfall 11) | Auto-insert timestamp comment; document update flow | +| rclone download URL | Pinned URL goes stale (Pitfall 12) | Default to `rclone-current`; allow version override | +| Config string generation | Windows CRLF in config file (Pitfall 13) | Normalize to LF before Blob creation | + +--- + +## Sources + +- Microsoft Learn — PowerShell scripts in Intune (updated 2025-10-02): https://learn.microsoft.com/en-us/intune/intune-service/apps/powershell-scripts +- Microsoft Learn — Intune Management Extension (updated 2026-03-17): https://learn.microsoft.com/en-us/intune/intune-service/apps/intune-management-extension +- Microsoft Learn — Set-ExecutionPolicy reference (updated 2025-04-15): https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy +- Microsoft Learn — Naming Files, Paths, and Namespaces (Win32): https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file +- Microsoft Learn — Code Page Identifiers: https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers +- rclone config format and Windows behavior: training data (MEDIUM confidence; rclone official docs were inaccessible during research session — verify against https://rclone.org/docs/ before finalizing) diff --git a/.planning/research/STACK.md b/.planning/research/STACK.md new file mode 100644 index 0000000..1755bb3 --- /dev/null +++ b/.planning/research/STACK.md @@ -0,0 +1,143 @@ +# Technology Stack + +**Project:** Ready2Blob +**Researched:** 2026-03-26 +**Confidence note:** External verification tools were unavailable in this session. Version numbers reflect training data (knowledge cutoff August 2025). Verify all versions against npmjs.com before scaffolding. + +--- + +## Recommended Stack + +### Core Framework + +| Technology | Version | Purpose | Why | +|------------|---------|---------|-----| +| React | 18.x | Component model, state management, rendering | Largest ecosystem, best-in-class multi-step form libraries all target React first. Hooks (useState, useReducer, useContext) provide exactly the right mental model for a wizard: local step state + shared config accumulator state. No SSR needed — this is 100% client-side rendering. | +| Vite | 5.x | Build tooling, dev server, static asset bundling | Near-zero config for a React SPA. `vite build` produces a static `dist/` folder deployable to GitHub Pages, Netlify, or any CDN with no server required. HMR makes iteration fast. Replaces CRA, which is abandoned. Replaces Webpack, which requires painful configuration for something this simple. | +| TypeScript | 5.x | Type safety | rclone config generation involves composing structured data (backend type, required fields per backend, optional flags) into string templates. TypeScript catches the inevitable "wrong field name" bugs at compile time rather than at user download time. The marginal overhead is worth it for a tool where correctness of generated output is the entire product. | + +### Styling + +| Technology | Version | Purpose | Why | +|------------|---------|---------|-----| +| Tailwind CSS | 3.x | Utility-first styling | No design system to maintain — each step of the wizard is a one-off layout. Tailwind's inline classes mean styling stays co-located with markup, avoiding CSS file sprawl. For a tool likely built by one or two developers, it eliminates the "where does this class live?" question. Avoid CSS Modules (too much file switching) and styled-components (runtime overhead, no benefit here). | + +### Form & Wizard State + +| Technology | Version | Purpose | Why | +|------------|---------|---------|-----| +| react-hook-form | 7.x | Per-step form validation and field registration | The standard for React forms. Uncontrolled inputs with ref-based validation means no re-render on every keystroke — important when some wizard steps may have 10+ fields (e.g., S3 config). Native Zod integration via `@hookform/resolvers` allows schema-driven validation that mirrors the rclone backend field spec. | +| Zod | 3.x | Schema definition and runtime validation | Per-backend field schemas (required vs optional, string format, enum values) map directly to Zod schemas. A `backends/azure.ts`, `backends/s3.ts`, etc. pattern lets each backend declare its own schema — react-hook-form validates against it per step. This is the correct abstraction: the schema IS the backend spec. | + +### File Generation & Download + +| Technology | Version | Purpose | Why | +|------------|---------|---------|-----| +| Native Blob API | — (browser built-in) | Text file download (rclone.conf, .ps1 scripts) | No library needed. `new Blob([content], { type: 'text/plain' })` + `URL.createObjectURL()` + programmatic anchor click is the standard pattern for single-file downloads. Zero dependency, works in all modern browsers. Using a library for this adds complexity without benefit. | +| JSZip | 3.x | ZIP bundling of all generated files | When the user wants to download all files at once (rclone.conf + Intune script + RMM script), a ZIP is far better UX than three separate downloads. JSZip is the de-facto standard for client-side ZIP in browsers, actively maintained, no server required. `file-saver` is often paired with it for the `saveAs()` convenience but the Blob/anchor pattern works fine without it. | + +### State Management + +| Technology | Version | Purpose | Why | +|------------|---------|---------|-----| +| React built-ins (useState / useReducer / useContext) | 18.x | Wizard state, accumulated config object | No external state library needed. The wizard has one primary data structure: the accumulating rclone config object (backend type + per-backend fields + script options). A `useReducer` at the app root with a context provider gives all steps read/write access without prop drilling. This is a solved problem at this scale — Zustand/Redux are overkill. | + +### Hosting / Deployment + +| Technology | Version | Purpose | Why | +|------------|---------|---------|-----| +| GitHub Pages or Netlify (free tier) | — | Static hosting | The output of `vite build` is a folder of HTML/CSS/JS. Any static host works. GitHub Pages is zero-cost and integrates directly with the repository. Netlify adds deploy previews for PRs, which is useful for validating config generation changes. No server needed at either. | + +--- + +## Alternatives Considered + +| Category | Recommended | Alternative | Why Not | +|----------|-------------|-------------|---------| +| Framework | React 18 | Vue 3 | Vue is a reasonable choice but the wizard library ecosystem (react-hook-form, Formik) is React-first. No strong reason to diverge. | +| Framework | React 18 | Svelte / SvelteKit | Svelte has no widely-adopted multi-step form library. Would require hand-rolling wizard state. The compile-time model is elegant but not worth the ecosystem tradeoff here. | +| Build tool | Vite | Create React App | CRA is officially deprecated by the React team. Not a valid choice for new projects in 2025. | +| Build tool | Vite | Next.js | Next.js is a server-framework. Using it for a pure static SPA adds file-based routing conventions, SSR plumbing, and deployment assumptions that are all irrelevant here. `vite + react` is simpler and more appropriate. | +| Styling | Tailwind CSS | Material UI / shadcn/ui | shadcn/ui is worth considering as a component library for accessible form elements (inputs, selects, checkboxes). It is built on Radix UI primitives and works with Tailwind. If the team wants pre-built accessible components rather than raw HTML + Tailwind, shadcn/ui is the right addition — not a replacement for Tailwind, but a layer on top. | +| Forms | react-hook-form | Formik | Formik is older and uses controlled inputs (re-render on every keystroke). react-hook-form is the current standard and has better performance and Zod integration. | +| ZIP | JSZip | fflate | fflate is faster and smaller than JSZip. Both are valid. JSZip has more documentation and community examples for the browser download pattern, making it easier to implement correctly without prior experience. If bundle size becomes a concern, swap to fflate. | +| State | useReducer + Context | Zustand | Zustand is excellent but unnecessary at this scale. No async state, no complex selectors needed. Adding a dependency for something React itself handles cleanly is not justified. | + +--- + +## Recommended shadcn/ui Addition + +**Use shadcn/ui for form components.** shadcn/ui is not a dependency — it is a code generator. Running `npx shadcn-ui@latest add button input select checkbox` copies accessible, Tailwind-styled components into your project. These components are owned by the project (not a node_module) and fully customizable. For a wizard with many form inputs, this provides: + +- Accessible labels, focus states, error message patterns out of the box +- Consistent visual design without a custom design system +- Radix UI primitives under the hood (keyboard navigation, ARIA) at no extra runtime cost + +This is the current 2025 best practice for React + Tailwind projects. + +--- + +## Installation + +```bash +# Scaffold +npm create vite@latest ready2blob -- --template react-ts +cd ready2blob + +# Tailwind CSS +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p + +# Forms and validation +npm install react-hook-form zod @hookform/resolvers + +# ZIP generation +npm install jszip + +# shadcn/ui setup (optional but recommended) +npx shadcn-ui@latest init +# Then add components as needed: +npx shadcn-ui@latest add button input select checkbox label +``` + +--- + +## What NOT to Use + +| Technology | Why Not | +|------------|---------| +| Next.js | Server framework. Adds SSR/SSG complexity with zero benefit for a pure client-side tool. | +| Create React App | Officially deprecated. Abandoned by React team. | +| Redux / Redux Toolkit | Overkill for wizard state. useReducer + Context is sufficient. | +| Formik | Superseded by react-hook-form. Controlled inputs cause unnecessary re-renders. | +| Angular | Enterprise framework, large bundle, steep learning curve, wrong tool for a simple wizard. | +| Backend of any kind | Explicitly out of scope. All generation is string manipulation in the browser. | +| LocalStorage / IndexedDB | Out of scope per PROJECT.md — no persistence. | + +--- + +## Confidence Assessment + +| Decision | Confidence | Basis | +|----------|------------|-------| +| React 18 + Vite as core | HIGH | Industry-standard since 2023, no credible challenger for this use case | +| TypeScript | HIGH | Unambiguously correct for generated-output correctness | +| react-hook-form + Zod | HIGH | De-facto standard pairing for React forms as of 2024-2025 | +| Tailwind CSS | HIGH | Dominant utility-CSS framework; strong fit for wizard UI | +| shadcn/ui | MEDIUM | Strong community adoption but version numbers evolve quickly; verify CLI syntax | +| JSZip for ZIP | MEDIUM | Stable and widely used, but fflate is a valid modern alternative — verify latest version on npm | +| Blob API for single-file download | HIGH | Native browser API, no version concern | +| Version numbers (all) | LOW | Training data cutoff August 2025; must verify on npmjs.com before scaffolding | + +--- + +## Sources + +- PROJECT.md: project requirements and constraints (pure frontend, no backend, static hosting) +- React documentation (react.dev) — training data, verify current version +- Vite documentation (vitejs.dev) — training data, verify current version +- react-hook-form documentation (react-hook-form.com) — training data, verify current version +- Zod documentation (zod.dev) — training data, verify current version +- JSZip (stuk.github.io/jszip) — training data, verify current version +- shadcn/ui (ui.shadcn.com) — training data, verify CLI commands +- MDN Web Docs: Blob API, URL.createObjectURL — browser built-in, no version concern diff --git a/.planning/research/SUMMARY.md b/.planning/research/SUMMARY.md new file mode 100644 index 0000000..4991125 --- /dev/null +++ b/.planning/research/SUMMARY.md @@ -0,0 +1,219 @@ +# Project Research Summary + +**Project:** Ready2Blob +**Domain:** Pure-frontend rclone configuration wizard / enterprise Windows deployment helper +**Researched:** 2026-03-26 +**Confidence:** MEDIUM-HIGH (stack HIGH, pitfalls HIGH, features MEDIUM, architecture MEDIUM) + +## Executive Summary + +Ready2Blob is a client-side-only static web application that guides IT administrators through configuring rclone for cloud storage backends (Azure Blob, S3, OneDrive, SFTP) and generating PowerShell deployment scripts for Intune and RMM platforms. The product has no backend, no persistence, and no server: all credential handling, config generation, and file download happen entirely in the browser. The right technology choices are well-established — React + Vite + TypeScript with react-hook-form/Zod for per-step validation, and native Blob/JSZip APIs for file generation. This is a greenfield SPA with a small, stable dependency set and no novel architecture challenges. + +The recommended approach is to build from the inside out: define types and schemas first, build pure generator functions (config builder, PS script builder) second, then add the wizard UI shell on top. This order ensures the most critical output — the generated files — is correct and testable before any UI work begins. The Backend Schema Registry pattern (one static TS object describing all backend field definitions) is the architectural keystone: it decouples form rendering from backend-specific knowledge and makes adding new backends trivial without modifying UI components. + +The single largest risk category is PowerShell deployment correctness, not frontend development. Generated scripts must handle SYSTEM-context path resolution, UTF-8 no-BOM encoding, single-quoted here-strings to prevent `$` interpolation, 32-bit vs 64-bit host differences, and Intune's 200 KB script size limit. These are operational correctness requirements that will not surface during local development — they only manifest in real enterprise Intune or RMM environments. Every script template decision must be made with these constraints in mind from the first line of code. + +--- + +## Key Findings + +### Recommended Stack + +The stack is lean by design. React 18 + Vite 5 + TypeScript 5 provides the scaffold; Tailwind CSS 3 + shadcn/ui handles styling and accessible form primitives without a maintained design system; react-hook-form 7 + Zod 3 handles per-step validation with schema-driven field definitions that map directly to rclone backend specs. File generation uses only browser-native APIs (Blob, URL.createObjectURL) for single-file downloads and JSZip 3 for ZIP bundles. No backend, no external state library, no database. + +**Core technologies:** +- React 18 + Vite 5: SPA scaffold — fast HMR, zero-config static build, no SSR overhead +- TypeScript 5: type safety for generated-output correctness — wrong field name = broken config +- react-hook-form 7 + Zod 3: per-step validation + backend schema definitions — uncontrolled inputs, schema-driven, performant +- Tailwind CSS 3 + shadcn/ui: utility styling + accessible form components — no design system maintenance +- Native Blob API: single-file download — zero dependency, browser built-in +- JSZip 3: ZIP bundle of all artifacts — de-facto browser ZIP standard +- React useReducer + Context: wizard state — sufficient at this scale, no Zustand/Redux needed + +**Critical exclusions:** No Next.js (SSR overhead irrelevant), no Create React App (deprecated), no localStorage/sessionStorage (credentials must not persist), no backend of any kind. + +### Expected Features + +IT admins evaluating this tool will immediately abandon it if any table-stakes feature is missing. The MVP must cover the full generation pipeline — backend selection through file download — for at least Azure Blob, S3, and OneDrive before any polish work begins. + +**Must have (table stakes):** +- Multi-step backend selection wizard with popular backends (Azure Blob, S3, OneDrive, SFTP) shown first +- Per-backend field forms with labels, help text, and required-field validation matching rclone's own config flow +- Valid rclone.conf output (INI format, correct key/value pairs per backend) +- Remote name input with character validation (alphanumeric, dash, underscore only) +- Intune PowerShell deployment script (handles SYSTEM context, idempotent, correct exit codes) +- RMM PowerShell deployment script (self-contained, runs as SYSTEM) +- Optional rclone install toggle (script downloads rclone binary from URL — never embeds it) +- Security warning gate before download (credentials are plaintext — must be acknowledged) +- Individual download buttons per artifact (conf, Intune script, RMM script) +- Prominent "no data sent to server" assurance + +**Should have (differentiators):** +- Live config preview (real-time generated file content visible before downloading) +- Intune detection script generation (separate from install script — Intune Win32 requirement) +- Config path selector: machine-wide `C:\ProgramData\rclone\` vs user profile (with explanation of SYSTEM context implications) +- Rclone version pinning input (defaults to `rclone-current`; override for reproducible deployments) +- Copy-to-clipboard for all output blocks (RMM tools often have a "run script" field) +- Field-level validation for backend-specific formats (Azure account name: 3-24 lowercase alphanumeric) +- Explanatory tooltips on credential fields (SAS token vs access key confusion is common) +- ZIP "download all" bundle + +**Defer to v2+:** +- Multiple remotes in one config (adds significant wizard UX complexity) +- RMM-named script variants (NinjaRMM-specific, Datto-specific execution contexts) +- IntuneWinAppUtil packaging hints (valuable but can be a static docs page) +- Test connection / credential validation (requires a proxy backend — violates no-server constraint) +- Save/load configurations (requires localStorage = credentials in browser storage = security incident) +- Graph API auto-push to Intune (massive scope; manual upload is acceptable for v1) +- Multi-OS support (macOS/Linux scripts out of scope; state clearly "Windows endpoints only") + +### Architecture Approach + +The architecture follows four clean layers: Wizard UI (React components, navigation), Wizard State (single useReducer store, shared via Context), Config Builders (pure functions: state in, file string out), and Download Manager (Blob URL or JSZip). The Backend Schema Registry is a static TypeScript object that defines all field definitions per backend type — it drives dynamic form rendering, Zod schema construction, and config key/value generation from one source of truth. All builders are pure functions with no side effects, making them immediately unit-testable without a browser. + +**Major components:** +1. Wizard UI + Navigation — step rendering, next/back/jump, step completion tracking +2. Wizard State (useReducer + Context) — single source of truth for all form data; typed WizardState interface +3. Backend Schema Registry — static TS object: BackendType → FieldDef[]; drives dynamic forms +4. rclone.conf Builder — pure function: WizardState → INI string; plain template literals +5. PowerShell Script Builder (Intune + RMM variants) — pure functions: WizardState → .ps1 string +6. Download Manager — Blob URL (single file) + JSZip (bundle); no library for single files + +**Key patterns:** +- Centralized state — all form data in one typed store; never per-step local state +- Schema Registry — one entry per backend = new backend support with zero UI changes +- Pure builders — same input always produces same output; no DOM reads; fully unit-testable +- PowerShell single-quoted here-strings — prevents `$` interpolation corrupting credentials + +### Critical Pitfalls + +These are the failure modes that cause silent deployment breakage in production enterprise environments. All five must be addressed in the initial script template — retrofitting them later risks shipping broken scripts. + +1. **SYSTEM context config path mismatch** — rclone config written to SYSTEM's `%APPDATA%` is invisible to the logged-in user. Always write to `C:\ProgramData\rclone\rclone.conf` (machine-wide path, no WOW64 redirection). Make the destination path explicit in the wizard and let the admin choose; never default to bare `%APPDATA%` expansion. + +2. **PowerShell encoding writes UTF-16 BOM** — `Out-File` in PS 5.1 defaults to UTF-16 LE with BOM; rclone cannot parse it. Always use `[System.IO.File]::WriteAllText($path, $content, [System.Text.UTF8Encoding]::new($false))` to guarantee UTF-8 no-BOM. Hardcode this in every script template from day one. + +3. **Secrets exposed in Intune script logs** — Intune logs all script output to the Azure portal. Generated scripts must never echo credential values. Use `Write-Host "Writing config to $configPath"` (path only), never `Write-Host $configContent`. No debug output containing credential variables, ever. + +4. **Intune 200 KB script size limit** — Scripts that embed or base64-encode rclone binary content are rejected at upload. The generated script must always download rclone from a URL (`Invoke-WebRequest`) at deployment time — never embed the binary. Surface the download URL in the wizard and let admins specify a corporate mirror. + +5. **SAS token / storage key corruption via `$` interpolation** — Azure credentials contain `$` characters. In double-quoted PowerShell strings, `$` triggers variable substitution, silently corrupting the credential. Always wrap the config content block in a single-quoted here-string (`@' ... '@`). Trim all credential inputs before inserting into the config to prevent newline truncation. + +**Additional moderate pitfalls to address in script templates:** +- OAuth backends (OneDrive, Google Drive) require a pre-obtained token from `rclone authorize` — the wizard cannot complete OAuth flow in the browser; show a prominent warning and a dedicated token input field +- 32-bit PowerShell host (Intune default) causes WOW64 path redirection; use `C:\ProgramData\rclone\` or `$env:ProgramW6432` — recommend enabling 64-bit PS in Intune settings +- Do not call `Set-ExecutionPolicy` in the generated script — Group Policy always overrides it; use `-ExecutionPolicy Bypass` on any sub-process calls instead +- Auto-insert a `# Generated: [timestamp]` comment in each script so re-generated scripts always have different bytes, enabling Intune re-execution on config updates + +--- + +## Implications for Roadmap + +Based on combined research, the architecture's inside-out build order maps directly to phases. The generator functions and schema registry have zero UI dependencies — build them first, test them in isolation, then layer UI on top. This order also front-loads the hardest correctness requirements (script encoding, path choices, credential handling) before any deployment to users. + +### Phase 1: Foundation — Types, Schema Registry, State Shape + +**Rationale:** All other components depend on these definitions. Building them first prevents architectural drift where UI components hardcode backend knowledge. The schema registry is the keystone — it must exist before dynamic forms, before builders, before anything. +**Delivers:** TypeScript type definitions (WizardState, BackendType, FieldDef, RemoteConfig), Backend Schema Registry (Azure Blob, S3, OneDrive, SFTP as Tier 1; GCS, Backblaze B2 as Tier 2), Zod schemas per backend derived from registry, Vite + React + TypeScript + Tailwind scaffold +**Addresses:** Foundational architecture (ARCHITECTURE.md Pattern 2 — Backend Schema Registry) +**Avoids:** Anti-Pattern 3 (hardcoding backend fields in step components) + +### Phase 2: Core Generators — rclone.conf + PowerShell Script Builders + +**Rationale:** Pure functions with no UI dependencies. Build and unit-test these before any React work. This is where all the correctness requirements from PITFALLS.md live — encoding, path choices, credential handling, no-log rules must be baked in from the first line of the template. +**Delivers:** `buildRcloneConf(remotes)` — pure function producing INI string with LF normalization; `buildIntuneScript(state)` — PS script with UTF-8 no-BOM write, single-quoted here-string, machine-wide path, download-only rclone install, timestamp comment, no credential logging; `buildRmmScript(state)` — same constraints; Download Manager (Blob URL + JSZip wrapper) +**Implements:** ARCHITECTURE.md Patterns 3, 4, 5 (pure builders, Blob URL, JSZip) +**Avoids:** Pitfalls 1, 2, 3, 5, 8 (SYSTEM path, 200 KB limit, encoding, credential corruption, OAuth warning) + +### Phase 3: Wizard Shell + State Wiring + +**Rationale:** Navigation shell and state store can be built against mock/empty step content. Getting the state shape right before forms are built prevents having to refactor form registration later. +**Delivers:** useReducer + Context store wired to WizardState shape; step navigation (stepper, next/back, URL-free step tracking); step completion state; mobile-responsive layout shell using Tailwind + shadcn/ui +**Uses:** React 18, useReducer/Context, Tailwind, shadcn/ui +**Avoids:** Anti-Pattern 1 (per-step local state losing data on back-navigation) + +### Phase 4: Wizard Step Forms — Dynamic Backend Forms + Deployment Options + +**Rationale:** Now that state, schema registry, and builders all exist, forms can be built as thin wrappers that write to the state store. The dynamic form component reads from the schema registry — one component handles all backends. +**Delivers:** Step 1 — Backend type selector (popularity-ordered: Azure Blob, S3, OneDrive, SFTP first); Step 2 — `` driven by Schema Registry (react-hook-form + Zod per backend); Step 3 — Deployment options (rclone install toggle, config path selector: machine-wide vs user profile, version pin field, script target selection); Remote name input with `[a-zA-Z0-9_-]` validation and live section header preview +**Addresses:** Table-stakes features from FEATURES.md; Pitfall 4 (remote name validation); Pitfall 8 (OAuth token field + warning for OAuth backends) + +### Phase 5: Review, Download + Security Gate + +**Rationale:** Final wizard step assembles everything. Live preview builds trust and catches errors before the admin deploys a broken config. Security warning is a hard blocker before download. +**Delivers:** Review step with live syntax-highlighted config preview (updates in real time); security warning modal (credentials in plaintext — cannot be dismissed without acknowledgment); individual download buttons (conf, Intune .ps1, RMM .ps1); "Download All as ZIP" via JSZip; copy-to-clipboard for each output block +**Addresses:** Table-stakes and differentiator features from FEATURES.md (live preview, security gate, copy-to-clipboard, ZIP bundle) +**Avoids:** Pitfall 5 (security warning gate) + +### Phase 6: Polish + Correctness Hardening + +**Rationale:** After end-to-end flow works, add the depth features that reduce support tickets and build admin trust. This phase also adds per-field validation beyond basic required-field checks and the contextual help text that reduces abandonment. +**Delivers:** Per-field backend-specific validation (Azure account name format, SAS token trimming); explanatory tooltips on credential fields; Intune detection script generation (separate from install script); config path implications documentation in the wizard output pane; 64-bit PS host recommendation in Intune output; auto-inserted `# Generated: [timestamp]` comment in scripts; LF normalization on all generated output +**Addresses:** Differentiator features from FEATURES.md; Pitfalls 6, 7, 9, 10, 11, 13 + +### Phase Ordering Rationale + +- Phases 1 and 2 have no UI dependencies and contain the highest-risk correctness requirements — building them first allows unit testing before any user-facing code exists +- The wizard shell (Phase 3) can be built with empty/mock steps while the generators are being built, if team size allows parallelism +- Dynamic forms (Phase 4) depend on both the schema registry (Phase 1) and state wiring (Phase 3) being finalized +- The download step (Phase 5) can only be meaningfully built once all builders (Phase 2) exist +- Polish (Phase 6) is deliberately last — it adds depth but does not change the architecture + +### Research Flags + +Phases likely needing deeper research during planning: + +- **Phase 2 (Script Builders):** Verify current Intune PowerShell script execution model against live Microsoft docs before writing templates. Intune behavior around 32-bit/64-bit host defaults and script re-execution triggers can change between Intune releases. High-stakes: wrong behavior is invisible until tested on a real managed device. +- **Phase 4 (Backend Forms):** Verify exact required field names for each backend against live rclone docs (rclone.org/azureblob, rclone.org/s3, etc.) before implementing the Schema Registry. Field names are the source of truth for config generation — a wrong key name produces a silently broken config. +- **Phase 4 (OAuth backends):** Confirm current `rclone authorize` token extraction flow for OneDrive before designing the OAuth token input UX. The token JSON structure may have changed. + +Phases with standard patterns (skip research-phase): + +- **Phase 1 (Foundation):** React + Vite + TypeScript scaffold is fully documented; schema registry is a static TS object; no novel decisions required +- **Phase 3 (Wizard Shell):** Multi-step form navigation with useReducer + Context is a well-documented React pattern; react-hook-form per-step validation is standard +- **Phase 5 (Download):** Blob URL download and JSZip are stable browser APIs with no version concerns; security modal is standard UI + +--- + +## Confidence Assessment + +| Area | Confidence | Notes | +|------|------------|-------| +| Stack | HIGH | React + Vite + TypeScript + react-hook-form + Zod is the industry-standard 2025 pairing; no credible alternatives for this use case. shadcn/ui CLI syntax should be verified before scaffolding. | +| Features | MEDIUM-HIGH | Table-stakes and IT admin deployment expectations are HIGH confidence from domain knowledge. Specific rclone backend field names are MEDIUM — must be cross-checked against live rclone docs before implementing schema registry. | +| Architecture | MEDIUM-HIGH | rclone.conf format is HIGH (stable since v1.x). Intune script patterns are MEDIUM (well-documented but behavior can change between releases). Blob/JSZip download patterns are HIGH (stable browser APIs). | +| Pitfalls | HIGH | SYSTEM context, encoding, execution policy, and size-limit pitfalls are verified against official Microsoft docs. rclone-specific pitfalls (section name validation, config format edge cases) are MEDIUM — verify against live rclone docs. | + +**Overall confidence:** MEDIUM-HIGH + +### Gaps to Address + +- **rclone backend field names:** Every field key in the Schema Registry must match rclone's exact config key names. Verify each Tier 1 backend against rclone.org before implementing Phase 1. Wrong keys produce silently broken configs. +- **rclone S3-compatible provider pattern:** The `provider = AWS` + optional `endpoint` field pattern for S3-compatible backends (Wasabi, MinIO, Cloudflare R2) should be confirmed against current rclone S3 docs before implementing the S3 schema entry. +- **Intune re-execution trigger:** Confirm whether Intune re-runs a modified script based on byte-level content change or requires a script version increment. This affects the timestamp-comment strategy in Phase 6. +- **OneDrive OAuth token format:** Confirm current `token = {...}` JSON structure for OneDrive to design the token input field correctly in Phase 4. +- **shadcn/ui CLI commands:** Verify current `npx shadcn-ui@latest` command syntax before Phase 3 scaffolding — the CLI interface has historically changed between major versions. + +--- + +## Sources + +### Primary (HIGH confidence) +- Microsoft Learn — PowerShell scripts in Intune (2025-10-02) — SYSTEM context, size limits, exit codes, script re-execution +- Microsoft Learn — Intune Management Extension (2026-03-17) — execution context, 32-bit/64-bit host defaults +- Microsoft Learn — Set-ExecutionPolicy reference (2025-04-15) — Group Policy override behavior +- Microsoft Learn — Naming Files, Paths, and Namespaces (Win32) — MAX_PATH constraints +- MDN Web Docs — Blob API, URL.createObjectURL — browser file download pattern +- PROJECT.md — project requirements and constraints (no backend, no persistence, static hosting) + +### Secondary (MEDIUM confidence) +- rclone.org documentation — backend field names, config format, S3 provider pattern (training data, knowledge cutoff August 2025; verify before implementation) +- rclone.conf INI format specification — training data (format is stable since v1.x; HIGH confidence on structure, MEDIUM on per-backend field names) +- RMM deployment patterns (NinjaRMM, Datto, ConnectWise) — training data; verify execution context differences before adding RMM-named variants + +### Tertiary (LOW confidence) +- Version numbers for all npm packages — training data cutoff August 2025; verify all versions against npmjs.com before scaffolding + +--- +*Research completed: 2026-03-26* +*Ready for roadmap: yes*