DEV Community

goldct
goldct

Posted on

---

description: "How I built a privacy-first iOS app for BJD doll enthusiasts using SwiftUI, CoreData, and local notifications."
published: false
tags: swiftui, ios, indiedev, appdev

cover_image: /assets/bjd-cover.jpg

As an iOS developer and BJD (Ball-Jointed Doll) collector, I found myself managing my growing doll collection with spreadsheets, random notes, and calendar reminders. It was messy.

So I built BJD Doll Archive — a dedicated app that understands the specific needs of BJD collectors.

The Problem

BJD collecting involves a lot of tracking:

  • Doll details: brand, sculpt, model, face-up artist, purchase date
  • Care schedules: MSC coating refreshes, stain checks, light protection
  • Vendor experiences: which face-up artists deliver quality work, which shops are reliable
  • Photos: documenting customization progress

Generic inventory apps don't understand BJD-specific concepts like "face-up refresh cycle" or "resin yellowing prevention."

The Solution: SwiftUI + Local-First Architecture

SwiftUI for Rapid UI Development

SwiftUI made it straightforward to build the kind of detail-oriented forms BJD collectors need:

struct DollProfile: View {
    @State private var doll: Doll

    var body: some View {
        Form {
            Section("Basic Info") {
                TextField("Name", text: $doll.name)
                Picker("Brand", selection: $doll.brand) {
                    ForEach(Brand.allCases) { Text($0.rawValue) }
                }
            }
            Section("Face-up") {
                TextField("Artist", text: $doll.faceUpArtist)
                DatePicker("Last Refresh", selection: $doll.lastFaceUp)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Privacy-First: No Backend

BJD collections can be valuable and personal. I made a deliberate choice to keep all data on-device:

  • CoreData for local persistence
  • No user accounts
  • No cloud sync
  • No analytics tracking

This means the app works offline and your collection data never leaves your phone.

Local Notifications for Care Reminders

The care reminder system uses UNUserNotificationCenter with custom repeat intervals:

func scheduleCareReminder(for doll: Doll, type: CareType) {
    let content = UNMutableNotificationContent()
    content.title = "Care Reminder"
    content.body = "Time to \(type.action) for \(doll.name)"

    let trigger = UNCalendarNotificationTrigger(
        dateMatching: type.nextDateComponents(from: doll),
        repeats: true
    )

    let request = UNNotificationRequest(
        identifier: "\(doll.id)-\(type)",
        content: content,
        trigger: trigger
    )

    UNUserNotificationCenter.current().add(request)
}
Enter fullscreen mode Exit fullscreen mode

Lessons Learned

  1. Niche apps have loyal users — The BJD community is passionate and underserved by mainstream apps
  2. Privacy matters more than you think — Collectors appreciate that their data stays local
  3. Simple > Feature-rich — Resistance to feature creep kept the app focused
  4. One-time purchase > Subscription — For niche tools, users prefer paying once

What's Next

  • Japanese and Korean localization (BJD is huge in these markets)
  • iPad support for larger photo viewing
  • Export/import for backup

BJD Doll Archive is available on the App Store.

If you're interested in indie iOS development or BJD collecting, let's connect!

Download BJD Doll Archive →

Top comments (0)