Feature: 055 — Bulk Content Importer
Created: 2026-05-29
Status: Draft
Reference spec: spec.md
IA Foundation: Platform Authoring App + Admin Portal patterns
The Bulk Content Importer is an authoring workflow action — Authors use it from the same context where they create individual Objects. It belongs in the Author View as an elevated action, not as a separate sidebar destination or AI Tool card.
Rationale:
/ws/:workspaceId/authoring
└── import/ → Import Jobs list
├── new → New Import Wizard
├── :jobId → Import Job detail / progress
│ └── report → Import Report view
└── configurations → Saved configurations
Note: The import wizard opens as a full-page flow (not a modal dialog) because it is a multi-step process with file uploads, validation, duplicate resolution, and configuration that would be cramped in a dialog.
The existing [+ Create] button in the Author View page header becomes a split button / dropdown:
┌────────────────────────────────────────────────────────────────────────┐
│ [Page header: "Authoring" Perspectives ▾ [+ Create ▾] ] │
│ │ │
│ ┌─────┴───────────────┐ │
│ │ New Object │ │
│ │ ───────────────── │ │
│ │ Bulk Import... │ │
│ │ From Configuration…│ │
│ └─────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
/ws/:workspaceId/authoring/import/newRoute: /ws/:workspaceId/authoring/import/new
A full-page stepper with 5 steps. The user can navigate back to previous steps. The progress indicator shows completed / current / upcoming steps.
┌─────────────────────────────────────────────────────────────────────────────┐
│ [← Back to Authoring] │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ① Upload ── ② Configure ── ③ Validate ── ④ Resolve ── ⑤ Submit│
│ │ ● ○ ○ ○ ○ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ [Step Content Area] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ [Cancel] [← Previous] [Next →] │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
#### Step 1: Upload
┌─────────────────────────────────────────────────────────────────────┐
│ Upload Files │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌───────────────────────────────────┐ │ │
│ │ │ 📂 │ │ │
│ │ │ Drag & drop a .zip archive here │ │ │
│ │ │ or click to browse │ │ │
│ │ │ │ │ │
│ │ │ Accepted: .zip │ │ │
│ │ │ Max batch: 2 GB · Max files: 1000│ │ │
│ │ └───────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ── Manifest (optional) ── │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 📄 Upload manifest.json or manifest.csv │ │
│ │ [Browse...] │ │
│ │ ⓘ Manifests provide per-file metadata overrides │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ── Upload Progress (after file selected) ── │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ content-batch.zip (148 MB) │ │
│ │ ████████████████████░░░░ 78% Uploading... │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ── Archive Contents Preview (after upload) ── │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 📁 content-batch.zip — 47 files detected │ │
│ │ ├── 📄 procedure-oil-change.dita (DITA Task) │ │
│ │ ├── 📄 concept-filters.dita (DITA Concept) │ │
│ │ ├── 📄 overview.md (Markdown) │ │
│ │ ├── 🖼 diagram.svg (Graphics) │ │
│ │ ├── 📄 parts-list.xlsx (Excel) │ │
│ │ └── ... 42 more files │ │
│ │ │ │
│ │ Summary: 32 DITA · 5 Markdown · 4 Graphics · 6 Other │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
States:
#### Step 2: Configure
┌─────────────────────────────────────────────────────────────────────┐
│ Configure Import │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌── Saved Configuration ──────────────────────────────────────┐ │
│ │ [Load from saved ▾] OR configure manually below │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Destination ──────────────────────────────────────────────┐ │
│ │ │ │
│ │ Target Workspace: [Current workspace — locked] │ │
│ │ │ │
│ │ Destination Folder: │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ [None (loose Objects)] ▾ │ │ │
│ │ │ ────────────────────── │ │ │
│ │ │ ▸ Folder A │ │ │
│ │ │ ▾ Folder B │ │ │
│ │ │ ▸ Folder B1 │ │ │
│ │ │ ▸ Folder C │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ☐ Create subfolders from archive directory structure │ │
│ │ ⓘ Mirrors the .zip folder hierarchy under the │ │
│ │ selected destination folder │ │
│ │ (disabled when no destination folder is selected) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Initial Status ──────────────────────────────────────────┐ │
│ │ │ │
│ │ ○ Pre-Draft (recommended) │ │
│ │ Objects require review before entering editorial workflow │ │
│ │ │ │
│ │ ○ Draft │ │
│ │ Objects enter editorial workflow immediately │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Work Package (optional) ──────────────────────────────────┐ │
│ │ │ │
│ │ Associate with Work Package: │ │
│ │ [🔍 Search work packages... ▾] │ │
│ │ │ │
│ │ ⓘ Improves AI metadata suggestion accuracy by providing │ │
│ │ product and release context │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── AI Metadata ──────────────────────────────────────────────┐ │
│ │ │ │
│ │ ☑ Enable AI metadata suggestion for files without │ │
│ │ manifest entries │ │
│ │ │ │
│ │ ⓘ The AI will suggest values from active MetadataDomain │ │
│ │ definitions. All suggestions are clearly marked in the │ │
│ │ import report. │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Save Configuration ───────────────────────────────────────┐ │
│ │ ☐ Save this configuration for reuse │ │
│ │ Name: [________________________________] │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Interactions:
#### Step 3: Validate (Auto Dry-Run)
After clicking "Next" from Configure, the system automatically runs a dry-run validation. This step shows results.
┌─────────────────────────────────────────────────────────────────────┐
│ Validation Results │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌── Summary ─────────────────────────────────────────────────┐ │
│ │ ✅ 42 files ready to import │ │
│ │ ⚠️ 3 files with warnings │ │
│ │ ❌ 2 files will be skipped (errors) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Issues ───────────────────────────────────────────────────┐ │
│ │ [Filter: All ▾ | Errors only | Warnings only] │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ❌ legacy-proc.dita │ │
│ │ Error: Invalid DITA schema — missing <title> element │ │
│ │ │ │
│ │ ❌ broken.xml │ │
│ │ Error: Not valid XML — parse error at line 14 │ │
│ │ │ │
│ │ ⚠️ overview.md │ │
│ │ Warning: Missing required metadata "product-line" │ │
│ │ (will be AI-suggested or flagged as gap) │ │
│ │ │ │
│ │ ⚠️ readme.txt │ │
│ │ Warning: Template "plain-text" not enabled in │ │
│ │ workspace — file will be skipped │ │
│ │ │ │
│ │ ⚠️ manifest references "missing-file.dita" │ │
│ │ Warning: File not found in archive — entry ignored │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ [Download validation report (CSV)] │
│ │
│ ───────────────────────────────────────────────────────────────── │
│ ⓘ No Objects have been created. Review issues above. │
│ You can go back to fix your archive or proceed to duplicate │
│ detection. │
│ │
└─────────────────────────────────────────────────────────────────────┘
States:
#### Step 4: Resolve Duplicates
This step only appears if duplicates are detected. If none are found, the wizard skips from ③ directly to ⑤.
┌─────────────────────────────────────────────────────────────────────┐
│ Duplicate Detection │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ⚠️ 3 files match existing Objects in this workspace. │
│ You must resolve each match before the import can proceed. │
│ │
│ ┌── Match 1 of 3 ────────────────────────────────────────────┐ │
│ │ │ │
│ │ 📄 procedure-oil-change.dita │ │
│ │ ──────────────────────────── │ │
│ │ Matches: "Oil Change Procedure" (Object ID: obj-abc123) │ │
│ │ Match type: Title + Content hash (98% similar) │ │
│ │ │ │
│ │ Resolution: │ │
│ │ ○ Skip — do not import this file │ │
│ │ ○ Create new Object — import as a separate Object │ │
│ │ ○ Create new Subversion — add as a new Subversion of │ │
│ │ the existing Object │ │
│ │ ⓘ Only available if no editable Subversion exists │ │
│ │ ✅ Available — Version 2 has no editable Subversion │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Match 2 of 3 ────────────────────────────────────────────┐ │
│ │ 📄 concept-filters.dita │ │
│ │ Matches: "Filter Types Overview" (obj-def456) │ │
│ │ Match type: Title match (content differs) │ │
│ │ │ │
│ │ Resolution: │ │
│ │ ○ Skip │ │
│ │ ● Create new Object ← selected │ │
│ │ ○ Create new Subversion │ │
│ │ ⚠️ Unavailable — Version 1 has an editable Subversion │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Match 3 of 3 ────────────────────────────────────────────┐ │
│ │ ... (same pattern) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ───────────────────────────────────────────────────────────────── │
│ Resolved: 2 / 3 [Next →] ← disabled until all resolved │
│ │
└─────────────────────────────────────────────────────────────────────┘
Key rule: "Next" is disabled until every detected match has a resolution selected. This enforces the blocking gate from FR-013.
#### Step 5: Submit (Confirmation)
┌─────────────────────────────────────────────────────────────────────┐
│ Review & Submit │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌── Import Summary ───────────────────────────────────────────┐ │
│ │ │ │
│ │ Files to import: 45 │ │
│ │ Files to skip: 2 (validation errors) │ │
│ │ Duplicates resolved: 3 (1 skip · 1 new · 1 subver.) │ │
│ │ │ │
│ │ Destination: Folder B / (subfolders enabled) │ │
│ │ Initial status: Pre-Draft │ │
│ │ Work Package: WP-Migration-Q3 │ │
│ │ AI metadata: Enabled │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Estimated Duration ───────────────────────────────────────┐ │
│ │ ⏱ Approximately 8–12 minutes for 45 files │ │
│ │ You will receive a notification when the import completes. │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ [Cancel] [← Back] [Start Import] │
│ │
└─────────────────────────────────────────────────────────────────────┘
Clicking [Start Import] triggers a Radix AlertDialog confirmation:
┌─────────────────────────────────────────────┐
│ Start bulk import? │
│ │
│ This will create up to 45 Objects in │
│ workspace "Production". │
│ │
│ You can monitor progress or navigate away. │
│ │
│ [Cancel] [Start Import] │
└─────────────────────────────────────────────┘
Route: /ws/:workspaceId/authoring/import/:jobId
After submission the user is navigated here automatically. They can also return at any time.
┌─────────────────────────────────────────────────────────────────────┐
│ [← Back to Authoring] [Cancel Import] │
│ │
│ Import Job: imp-789xyz │
│ Submitted: May 29, 2026 at 14:32 by John Doe │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌── Progress ─────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Status: ⏳ Processing │ │
│ │ │ │
│ │ ████████████████████████░░░░░░░░░░ 62% │ │
│ │ 28 / 45 files processed │ │
│ │ │ │
│ │ Current file: maintenance-schedule.dita │ │
│ │ │ │
│ │ ✅ 26 created · ⚠️ 1 warning · ❌ 1 skipped │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Live Activity Feed ───────────────────────────────────────┐ │
│ │ │ │
│ │ 14:34:12 ✅ Created "Oil Change Procedure" (obj-abc...) │ │
│ │ 14:34:10 ✅ Created "Filter Concept" (obj-def...) │ │
│ │ 14:34:08 ⚠️ "overview.md" — metadata gap: product-line │ │
│ │ 14:34:05 ❌ "broken.xml" — skipped: parse error │ │
│ │ 14:34:02 ✅ Created "Parts List" (obj-ghi...) │ │
│ │ ... │ │
│ │ [Auto-scrolling ↓] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Real-time updates: Delivered via SignalR through PlatformHub. Progress bar, counters, and activity feed update without page refresh.
Job status states:
On completion:
┌─────────────────────────────────────────────────────────────────────┐
│ Import Job: imp-789xyz │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌── Result ───────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ✅ Completed with warnings │ │
│ │ │ │
│ │ Duration: 9 minutes 42 seconds │ │
│ │ Objects created: 43 │ │
│ │ Files skipped: 2 │ │
│ │ Warnings: 4 │ │
│ │ │ │
│ │ [View Import Report] [Download Report (CSV)] │ │
│ │ [View Created Objects in Authoring] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Route: /ws/:workspaceId/authoring/import/:jobId/report
┌─────────────────────────────────────────────────────────────────────────────┐
│ [← Back to Job] [Download CSV] │
│ │
│ Import Report — imp-789xyz │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ ┌── Summary Bar ─────────────────────────────────────────────────────┐ │
│ │ Total: 47 │ ✅ Created: 43 │ ⚠️ Warnings: 4 │ ❌ Skipped: 2 │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ [Filter: All ▾ | Created | Warnings | Skipped] [🔍 Search filename...] │
│ │
│ ┌── Report Table ─────────────────────────────────────────────────────┐ │
│ │ Source File │ Outcome │ Object ID │ Title │ Status │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ procedure-oil.dita │ ✅ │ obj-abc123 │ Oil Change │ Pre-D │ │
│ │ concept-filters.dita │ ✅ │ obj-def456 │ Filter Types │ Pre-D │ │
│ │ overview.md │ ✅ ⚠️ │ obj-ghi789 │ Overview │ Pre-D │ │
│ │ broken.xml │ ❌ │ — │ — │ — │ │
│ │ ... │ │ │ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ── Expanded Row Detail (click row to expand) ── │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 📄 overview.md → Object "Overview" (obj-ghi789) │ │
│ │ │ │
│ │ Metadata Applied: │ │
│ │ ┌────────────────────────────────────────────────────────────┐ │ │
│ │ │ Field │ Value │ Source │ │ │
│ │ │ product-line │ Hydraulic Systems │ 🤖 AI-suggested │ │ │
│ │ │ language │ EN │ 📋 Manifest │ │ │
│ │ │ department │ (gap) │ ⚠️ Unavailable │ │ │
│ │ └────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Warning: Required metadata "department" could not be suggested │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Key details:
📋 Manifest / 🤖 AI-suggested / 🔧 System-derivedRoute: /ws/:workspaceId/authoring/import/
Accessible from a persistent Import Jobs link in the Author View page header (small badge shows active job count).
┌─────────────────────────────────────────────────────────────────────┐
│ [← Back to Authoring] [+ New Import] │
│ │
│ Import Jobs │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ [Filter: All ▾ | Active | Completed | Failed] │
│ │
│ ┌── Jobs Table ───────────────────────────────────────────────┐ │
│ │ Job ID │ Files │ Status │ Submitted │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ imp-789xyz │ 47 │ ⏳ Processing (62%) │ 14:32 today │ │
│ │ imp-456abc │ 120 │ ✅ Completed │ Yesterday │ │
│ │ imp-123def │ 8 │ ⚠️ Partial │ May 27 │ │
│ │ imp-999ghi │ 200 │ ❌ Failed │ May 25 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Click a row to view job details and report. │
│ │
└─────────────────────────────────────────────────────────────────────┘
Delivered via PlatformHub SignalR push and shown in the existing notification tray:
┌────────────────────────────────────────────────────┐
│ 📥 Bulk Import Complete │
│ ────────────────────────────────── │
│ Your import (47 files) completed with warnings. │
│ 43 Objects created · 2 skipped · 4 warnings │
│ │
│ [View Report] │
│ │
│ 2 minutes ago │
└────────────────────────────────────────────────────┘
Route: /ws/:workspaceId/authoring/import/configurations
Accessible from the Configure step "Load from saved" dropdown and from the Import Jobs list header.
┌─────────────────────────────────────────────────────────────────────┐
│ [← Back] │
│ │
│ Import Configurations │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ ┌── Configurations Table ─────────────────────────────────────┐ │
│ │ Name │ Folder │ Status │ Actions │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ Migration Q3 │ /docs/manuals │ Pre-Draft │ ▶ ✏ 🗑 │ │
│ │ Weekly content drop │ /incoming │ Draft │ ▶ ✏ 🗑 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ▶ = Start new import with this configuration │
│ ✏ = Edit configuration │
│ 🗑 = Delete (Radix AlertDialog confirmation required) │
│ │
└─────────────────────────────────────────────────────────────────────┘
Author is in /authoring
→ clicks [+ Create ▾] → "Bulk Import..."
→ navigates to /authoring/import/new
Step 1: Upload
→ drags .zip onto drop zone → upload progress → archive preview shown
→ optionally uploads manifest.json
→ clicks [Next →]
Step 2: Configure
→ selects destination folder from tree
→ enables subfolder mirroring
→ keeps Pre-Draft status (default)
→ optionally associates Work Package
→ clicks [Next →]
Step 3: Validate (auto dry-run)
→ spinner: "Validating 47 files..."
→ results shown: 45 ready, 2 errors
→ reviews errors → acceptable, will be skipped
→ clicks [Next →]
Step 4: Resolve Duplicates (3 found)
→ reviews each match → selects resolution
→ all 3 resolved → Next enabled
→ clicks [Next →]
Step 5: Submit
→ reviews summary → clicks [Start Import]
→ AlertDialog confirmation → confirms
→ navigated to /authoring/import/{jobId}
→ progress bar + live feed updates via SignalR
→ Author navigates away to other work
→ platform notification arrives: "Import complete"
→ clicks [View Report] → import report page
→ clicks [View Created Objects in Authoring]
→ /authoring with destination folder selected
Author right-clicks "Manuals" folder in Folder Explorer
→ context menu → "Import files here..."
→ navigates to /authoring/import/new?folder={folderId}
→ Step 2: Configure — destination folder pre-selected to "Manuals"
→ (continues as Flow 1)
Author clicks [+ Create ▾] → "From Configuration..."
→ config picker dialog opens
→ selects "Migration Q3"
→ navigates to /authoring/import/new?config={configId}
→ Step 1: Upload (normal — config doesn't include files)
→ Step 2: Configure — all settings pre-populated
→ (continues as Flow 1)
Author completes Steps 1–3 of the wizard
→ on Step 3 (Validate), reviews the report
→ decides too many errors to proceed
→ clicks [Download validation report (CSV)]
→ downloads offline report
→ clicks [Cancel] or [← Back to Authoring]
→ wizard state cleared
→ no Objects created
Author navigated away during import
→ sees orange badge "1" on Import Jobs indicator in Authoring page header
→ clicks badge → /authoring/import/
→ active job at top with live progress
→ clicks job row → /authoring/import/{jobId}
→ current progress shown (restored from server state)
→ SignalR reconnects for live updates
Author is on /authoring/import/{jobId}
→ clicks [Cancel Import]
→ AlertDialog: "Cancel this import? Objects already created will not be removed."
→ confirms
→ job status → Cancelled
→ partial results remain accessible in report
External system:
POST /api/workspaces/{id}/import-jobs
Body: multipart archive + configuration JSON
Headers: Authorization: Bearer {token}
→ API validates: auth, bulk-import capability, workspace exists
→ 202 Accepted + { jobId: "imp-xyz" }
→ integrator polls GET /api/import-jobs/{jobId}/status
→ on completion: GET /api/import-jobs/{jobId}/report
Author without bulk-import capability opens [+ Create ▾]
→ "Bulk Import..." shown disabled
→ tooltip: "You need the 'bulk-import' capability to import content"
→ no navigation occurs
If the user navigates away mid-wizard the upload is retained in blob storage for 24h but wizard state is not restored — the user must restart the wizard.
Until the Action Tray (batch operations Phase 2) is available, import job progress surfaces in the existing Status Bar background task slot:
┌──────────────────────────────────────────────────────────────────────┐
│ [workflow state] [Import: 28/45 ████████░░ 62%] [other tasks] │
└──────────────────────────────────────────────────────────────────────┘
Once the Action Tray is available (see batch-operations-and-agent-interaction-ux-research.md §5.2), import job progress moves to the collapsed Tray strip — the canonical location for all background task progress — rather than the Status Bar directly. This avoids the two surfaces competing for the same vertical slot.
├──────────────────────────────────────────────────────────────────────┤
│ ▲ Tray [Import: 28/45 ██████████░░ 62%] [View ▶] [✕] │
├──────────────────────────────────────────────────────────────────────┤
│ [Status bar] │
└──────────────────────────────────────────────────────────────────────┘
The wizard is a desktop-primary experience. Mobile use is supported at a reduced fidelity.
UI visibility rules:
bulk-import: "Bulk Import..." menu item disabled with tooltipfolder.write: Destination folder picker disabled; only "loose Objects" option availableobject.read: Import report pages redirect to access-denied stateThe Admin Portal has no dedicated Bulk Import page, but is affected in two places:
Added under /c/:customerId/ws/:workspaceId/settings:
┌── Import Limits ──────────────────────────────────────────────┐
│ Max file size (MB): [50] │
│ Max batch size (MB): [2048] │
│ Max file count: [1000] │
│ [Save] │
└────────────────────────────────────────────────────────────────┘
The bulk-import capability appears in the capability list when creating or editing a custom role.
Per IA convention (§11 and §A8):
/ws/:workspaceId/authoring/import/* — workspace-scoped, no new sidebar entry[+ Create ▾] dropdown in Author View page header<ErrorState> component with retry on all data-fetch pagesbulk-import via ProtectedRoute; object.read on report routesuseWorkspacePath() for all internal links; buildWorkspacePath() for programmatic navigateuseFetch / useMutate — never raw fetch() or axiosPlatformHub workspace group for job progress events on job detail pagelazyComponents.tslocales/en/import namespace