# Data Export

> Generates data export/import infrastructure for JSON, CSV, PDF formats with GDPR data portability, share sheet integration, and file import. Use when user wants data export functionality, CSV/JSON/PDF export, GDPR compliance data portability, import from files, or share sheet for data.

- **Type:** Skill
- **Install:** `agentstack add skill-rshankras-claude-code-apple-skills-data-export`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [rshankras](https://agentstack.voostack.com/s/rshankras)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [rshankras](https://github.com/rshankras)
- **Source:** https://github.com/rshankras/claude-code-apple-skills/tree/main/skills/generators/data-export

## Install

```sh
agentstack add skill-rshankras-claude-code-apple-skills-data-export
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Data Export Generator

Generate production data export and import infrastructure -- JSON export via Codable, CSV generation with proper escaping, PDF report rendering with UIGraphicsPDFRenderer, GDPR-compliant full data export, file import with UTType-based picker, and share sheet integration. No third-party dependencies.

## When This Skill Activates

Use this skill when the user:
- Asks to "add data export" or "export user data"
- Wants "CSV export" or "JSON export" or "PDF export"
- Mentions "GDPR data portability" or "right to data portability"
- Asks about "exporting all user data" for compliance
- Wants to "import data" from files or competitor apps
- Mentions "share sheet" for exporting data
- Asks about "data backup" or "data download"

## Pre-Generation Checks

### 1. Project Context Detection
- [ ] Check deployment target (iOS 16+ / macOS 13+)
- [ ] Check Swift version (requires Swift 5.9+)
- [ ] Identify data model layer (SwiftData, Core Data, custom structs)
- [ ] Identify source file locations

### 2. Existing Export Detection
Search for existing export code:
```
Glob: **/*Export*.swift, **/*Import*.swift, **/*CSV*.swift, **/*PDF*.swift
Grep: "UIGraphicsPDFRenderer" or "CSVExport" or "UIActivityViewController" or "ShareLink" or "fileExporter"
```

If existing export code found:
- Ask if user wants to replace or add additional formats
- Identify which formats are already supported

### 3. Data Model Detection
Search for data models that need exporting:
```
Grep: "@Model" or "NSManagedObject" or "struct.*Codable" or "class.*Codable"
```

Identify the models to build export conformances for.

## Configuration Questions

Ask user via AskUserQuestion:

1. **Export formats needed?**
   - JSON (structured, machine-readable, best for GDPR)
   - CSV (tabular data, spreadsheet-compatible)
   - PDF (formatted reports with headers, tables, branding)
   - Multiple (select which combination)

2. **What data needs exporting?**
   - All user data -- GDPR compliance (every piece of stored user data)
   - Specific data types (user selects which models to export)
   - Reports/summaries (aggregated data, not raw records)

3. **Do you need import capability?**
   - No -- export only
   - Yes -- from files (JSON, CSV via file picker)
   - Yes -- from competitor apps (custom format parsing)

4. **How should users trigger export?**
   - Share sheet (system share UI with multiple destinations)
   - Settings screen (dedicated export section)
   - Export button (inline in content views)
   - Automatic backup (periodic export to iCloud/local)

## Generation Process

### Step 1: Read Templates
Read `templates.md` for production Swift code.

### Step 2: Create Core Files
Generate these files:
1. `DataExportManager.swift` -- Central export coordinator with format routing
2. `DataExportable.swift` -- Protocol for models that support export

### Step 3: Create Format-Specific Files
Based on configuration:
3. `CSVExporter.swift` -- If CSV format selected
4. `PDFExporter.swift` -- If PDF format selected

### Step 4: Create Import Files
If import capability selected:
5. `DataImporter.swift` -- File picker and format parser

### Step 5: Determine File Location
Check project structure:
- If `Sources/` exists -> `Sources/DataExport/`
- If `App/` exists -> `App/DataExport/`
- Otherwise -> `DataExport/`

## Output Format

After generation, provide:

### Files Created
```
DataExport/
├── DataExportable.swift   # Protocol for exportable models
├── DataExportManager.swift # Central export coordinator
├── CSVExporter.swift       # CSV generation (optional)
├── PDFExporter.swift       # PDF rendering (optional)
└── DataImporter.swift      # File import (optional)
```

### Integration with Data Models

**Make a model exportable:**
```swift
struct Expense: Codable, DataExportable {
    let id: UUID
    let title: String
    let amount: Double
    let date: Date
    let category: String

    // DataExportable conformance
    static var csvHeaders: [String] {
        ["ID", "Title", "Amount", "Date", "Category"]
    }

    var csvRow: [String] {
        [id.uuidString, title, String(format: "%.2f", amount),
         ISO8601DateFormatter().string(from: date), category]
    }

    var pdfDescription: String {
        "\(title) - $\(String(format: "%.2f", amount)) (\(category))"
    }
}
```

**Export from a view:**
```swift
struct ExpenseListView: View {
    let expenses: [Expense]
    @State private var exportURL: URL?
    @State private var showShareSheet = false

    var body: some View {
        List(expenses) { expense in
            ExpenseRow(expense: expense)
        }
        .toolbar {
            Menu {
                Button("Export as JSON") {
                    Task { await exportAs(.json) }
                }
                Button("Export as CSV") {
                    Task { await exportAs(.csv) }
                }
                Button("Export as PDF") {
                    Task { await exportAs(.pdf) }
                }
            } label: {
                Label("Export", systemImage: "square.and.arrow.up")
            }
        }
        .sheet(isPresented: $showShareSheet) {
            if let exportURL {
                ShareSheet(activityItems: [exportURL])
            }
        }
    }

    private func exportAs(_ format: DataExportManager.ExportFormat) async {
        do {
            exportURL = try await DataExportManager.shared.export(
                expenses, format: format, filename: "expenses"
            )
            showShareSheet = true
        } catch {
            // Handle error
        }
    }
}
```

**SwiftUI ShareLink (iOS 16+):**
```swift
if let url = exportURL {
    ShareLink(item: url) {
        Label("Share Export", systemImage: "square.and.arrow.up")
    }
}
```

**Import from file picker:**
```swift
struct ImportView: View {
    @State private var showFilePicker = false
    @State private var importedItems: [Expense] = []

    var body: some View {
        Button("Import Data") { showFilePicker = true }
            .fileImporter(
                isPresented: $showFilePicker,
                allowedContentTypes: DataImporter.supportedTypes
            ) { result in
                Task {
                    let url = try result.get()
                    importedItems = try await DataImporter.importFile(
                        from: url, as: Expense.self
                    )
                }
            }
    }
}
```

### GDPR Data Portability

For full GDPR compliance, export ALL user data:
```swift
func exportAllUserData() async throws -> URL {
    let allData = GDPRExportData(
        profile: try await fetchUserProfile(),
        expenses: try await fetchAllExpenses(),
        settings: try await fetchUserSettings(),
        exportDate: Date(),
        appVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0"
    )

    let encoder = JSONEncoder()
    encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
    encoder.dateEncodingStrategy = .iso8601
    let data = try encoder.encode(allData)

    let url = FileManager.default.temporaryDirectory
        .appendingPathComponent("user-data-export.json")
    try data.write(to: url)
    return url
}
```

### Testing

```swift
@Test
func jsonExportRoundTrip() async throws {
    let expenses = [
        Expense(id: UUID(), title: "Coffee", amount: 4.50,
                date: Date(), category: "Food")
    ]

    let url = try await DataExportManager.shared.export(
        expenses, format: .json, filename: "test"
    )
    let data = try Data(contentsOf: url)
    let decoded = try JSONDecoder().decode([Expense].self, from: data)

    #expect(decoded.count == 1)
    #expect(decoded.first?.title == "Coffee")
}

@Test
func csvExportFormatsCorrectly() {
    let expenses = [
        Expense(id: UUID(), title: "Coffee, Large", amount: 4.50,
                date: Date(), category: "Food")
    ]

    let csv = CSVExporter.generate(
        from: expenses,
        headers: Expense.csvHeaders,
        rowMapper: { $0.csvRow }
    )

    #expect(csv.contains("\"Coffee, Large\""))  // Commas escaped with quotes
    #expect(csv.hasPrefix("ID,Title,Amount,Date,Category"))
}

@Test
func importParsesCSV() async throws {
    let csvContent = "ID,Title,Amount\n1,Coffee,4.50\n2,Lunch,12.00"
    let url = FileManager.default.temporaryDirectory.appendingPathComponent("test.csv")
    try csvContent.write(to: url, atomically: true, encoding: .utf8)

    let rows = try CSVExporter.parse(from: url)
    #expect(rows.count == 2)
    #expect(rows.first?["Title"] == "Coffee")
}
```

## Common Patterns

### Export to Temporary File for Sharing
Always export to a temporary directory, then present via share sheet:
```swift
let url = FileManager.default.temporaryDirectory
    .appendingPathComponent("export.\(format.fileExtension)")
try data.write(to: url)
// Present via UIActivityViewController or ShareLink
```

### GDPR Export Should Include Everything
For GDPR Article 20 compliance, export must include:
- All personal data the user provided
- All data generated about the user
- In a structured, machine-readable format (JSON recommended)
- With clear field descriptions

### CSV Must Handle Special Characters
Commas, quotes, and newlines in field values must be properly escaped:
- Fields containing commas: wrap in double quotes
- Fields containing quotes: escape with double-double quotes
- Fields containing newlines: wrap in double quotes

## Gotchas

### Temporary Files Cleanup
Files in `FileManager.default.temporaryDirectory` are cleaned up by the system periodically, but not immediately. For large exports, delete the file after sharing completes to free disk space.

### PDF Rendering on Background Thread
`UIGraphicsPDFRenderer` must be used on the main thread if it references UIKit views. For data-only PDF generation (text, lines, rectangles), it is safe to render on a background thread.

### Large Dataset Memory
For exporting thousands of records, stream the output instead of building the entire string/data in memory. Write CSV line-by-line to a file handle. For JSON, use JSONSerialization with streams.

### ShareLink vs UIActivityViewController
SwiftUI `ShareLink` (iOS 16+) is simpler but less configurable. `UIActivityViewController` gives full control over excluded activities, completion handlers, and custom activities.

### File Import Security Scoped URLs
When using `.fileImporter`, the returned URL is security-scoped. You must call `url.startAccessingSecurityScopedResource()` before reading and `url.stopAccessingSecurityScopedResource()` after.

## References

- **templates.md** -- All production Swift templates for data export/import
- [UIGraphicsPDFRenderer](https://developer.apple.com/documentation/uikit/uigraphicspdfrenderer)
- [UIActivityViewController](https://developer.apple.com/documentation/uikit/uiactivityviewcontroller)
- [UniformTypeIdentifiers](https://developer.apple.com/documentation/uniformtypeidentifiers)
- [GDPR Article 20 - Right to Data Portability](https://gdpr-info.eu/art-20-gdpr/)
- Related: `generators/settings-screen` -- Settings screen with export button
- Related: `generators/account-deletion` -- Account deletion includes data export option

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [rshankras](https://github.com/rshankras)
- **Source:** [rshankras/claude-code-apple-skills](https://github.com/rshankras/claude-code-apple-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-rshankras-claude-code-apple-skills-data-export
- Seller: https://agentstack.voostack.com/s/rshankras
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
