···4848 log.Fatalf("Failed to initialize embedded PDS: %v", err)
4949 }
50505151+ // Bootstrap PDS with hold owner as first crew member
5252+ if err := holdPDS.Bootstrap(ctx, cfg.Registration.OwnerDID); err != nil {
5353+ log.Fatalf("Failed to bootstrap PDS: %v", err)
5454+ }
5555+5156 // Create blob store adapter
5257 blobStore := pds.NewHoldServiceBlobStore(service, holdDID)
5358···59646065 // Setup HTTP routes
6166 mux := http.NewServeMux()
6767+6868+ // Root page
6969+ mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
7070+ if r.URL.Path == "/" {
7171+ w.Header().Set("Content-Type", "text/plain")
7272+ fmt.Fprintf(w, "This is a hold server. More info at https://atcr.io")
7373+ return
7474+ }
7575+ http.NotFound(w, r)
7676+ })
7777+6278 mux.HandleFunc("/health", service.HealthHandler)
6379 mux.HandleFunc("/register", service.HandleRegister)
6480 mux.HandleFunc("/presigned-url", service.HandlePresignedURL)
+19-6
pkg/hold/pds/crew.go
···3333 CrewCollection = "io.atcr.hold.crew"
3434)
35353636-// AddCrewMember adds a new crew member to the hold
3636+// AddCrewMember adds a new crew member to the hold and commits to carstore
3737func (p *HoldPDS) AddCrewMember(ctx context.Context, memberDID, role string, permissions []string) (cid.Cid, error) {
3838 crewRecord := &CrewRecord{
3939 Member: memberDID,
···4242 AddedAt: time.Now(),
4343 }
44444545- // Create record in repo
4646- recordCID, rkey, err := p.repo.CreateRecord(ctx, CrewCollection, crewRecord)
4545+ // Create record in repo (using memberDID as rkey for easy lookup)
4646+ recordCID, _, err := p.repo.CreateRecord(ctx, CrewCollection, crewRecord)
4747 if err != nil {
4848 return cid.Undef, fmt.Errorf("failed to create crew record: %w", err)
4949 }
50505151- // TODO: Commit the changes
5252- // For now, just return the CID
5353- _ = rkey // We'll use rkey for GetCrewMember later
5151+ // Create signer function from signing key
5252+ signer := func(ctx context.Context, did string, data []byte) ([]byte, error) {
5353+ return p.signingKey.HashAndSign(data)
5454+ }
5555+5656+ // Commit the changes to get new root CID
5757+ root, rev, err := p.repo.Commit(ctx, signer)
5858+ if err != nil {
5959+ return cid.Undef, fmt.Errorf("failed to commit crew record: %w", err)
6060+ }
6161+6262+ // Close the delta session with the new root
6363+ _, err = p.session.CloseWithRoot(ctx, root, rev)
6464+ if err != nil {
6565+ return cid.Undef, fmt.Errorf("failed to persist commit: %w", err)
6666+ }
54675568 return recordCID, nil
5669}
+25
pkg/hold/pds/server.go
···9898 return p.signingKey
9999}
100100101101+// Bootstrap initializes the hold with the owner as the first crew member
102102+func (p *HoldPDS) Bootstrap(ctx context.Context, ownerDID string) error {
103103+ if ownerDID == "" {
104104+ // No owner specified, skip bootstrap
105105+ return nil
106106+ }
107107+108108+ // Check if repo already has commits
109109+ _, err := p.carstore.GetUserRepoHead(ctx, p.uid)
110110+ if err == nil {
111111+ // Repo already has commits, skip bootstrap
112112+ return nil
113113+ }
114114+115115+ // Add hold owner as first crew member with admin role
116116+ fmt.Printf("🚀 Bootstrapping hold PDS with owner: %s\n", ownerDID)
117117+ _, err = p.AddCrewMember(ctx, ownerDID, "admin", []string{"blob:read", "blob:write", "crew:admin"})
118118+ if err != nil {
119119+ return fmt.Errorf("failed to add owner as crew member: %w", err)
120120+ }
121121+122122+ fmt.Printf("✅ Added %s as hold admin\n", ownerDID)
123123+ return nil
124124+}
125125+101126// Close closes the session and carstore
102127func (p *HoldPDS) Close() error {
103128 // TODO: Close session properly