Backend Request: Full Settlement for User Admin Bulk Transfer

Date: 2026-01-20 From: Frontend Claude To: Backend Claude Priority: High


Summary

The User Admin bulk transfer endpoint (POST /adminUsers/transfer-docs) needs to perform full RoC settlement, not just ownership transfer. Currently it only updates documents_${orgId}.user_id without settling fees or RoC credits.

Business Context

The "on behalf of" workflow is designed to help onboard new users:

  1. Admin creates queue item to upload document on behalf of non-existent user (using their email)
  2. Admin processes queue, uploading the document/chunks
  3. Admin incurs the upload fees
  4. Over time, other users query the document, generating RoC for the admin
  5. The intended user registers and gets a users.id
  6. Admin transfers ownership via User Admin bulk transfer (by email)

The intent is onboarding assistance, not revenue sharing. The original uploader should be made whole:

  • Reimbursed for upload fees they paid
  • RoC credits earned should transfer to the new owner

Current Behavior

POST /adminUsers/transfer-docs (called from dist/js/admin/users.js line 950):

const result = await callAdminApi('transfer-docs', {
  method: 'POST',
  body: { email, newOwnerId },
});

Current behavior:

  • Finds documents where metadata->>dc_creator_email matches the email
  • Updates documents_${orgId}.user_id to the new owner
  • ❌ Does NOT reimburse upload fees
  • ❌ Does NOT transfer RoC credits
  • ❌ Does NOT create audit transactions

Required Behavior

For each document transferred, perform full settlement:

  1. Reimburse Upload Fees: Find document_add transactions for this source_url and reimburse the original uploader
  2. Transfer RoC Credits: Find credit_earned transactions for this source_url and transfer to new owner
  3. Create Audit Transactions: Record the transfer with full accounting details
  4. Update Ownership: Set documents_${orgId}.user_id to new owner

Implementation Options

Option A: Reuse Queue Settlement Logic

The POST /manageQueue/transfer/:id endpoint already has settlement logic. Extract it into a shared utility that can work by source_url:

// Shared settlement utility
async function settleDocumentTransfer(
  supabase: SupabaseClient,
  sourceUrl: string,
  fromUserId: string,
  toUserId: string,
  orgId: string
): Promise<SettlementResult>

Option B: Call Queue Transfer for Each Document

If each document has a corresponding queue item, the User Admin endpoint could call the queue transfer endpoint for each document. However, this may not work for documents uploaded before the queue system existed.

Response Format (Suggested)

interface TransferResult {
  documentsTransferred: number;
  settlementSummary: {
    totalFeesReimbursed: number;
    totalRocTransferred: number;
    documentsSettled: number;
    documentsSkipped: number; // e.g., already settled or no transactions
  };
  details: Array<{
    sourceUrl: string;
    title: string;
    feesReimbursed: number;
    rocTransferred: number;
    status: 'settled' | 'skipped' | 'error';
  }>;
}

Files to Modify

File Change
supabase/functions/adminUsers/handlers/transfer-docs.ts Add settlement logic
supabase/functions/manageQueue/handlers/transfer.ts Extract shared settlement utility
supabase/functions/_shared/settlement.ts New shared utility (optional)

Testing Considerations

  1. Test with documents that have credit_earned transactions
  2. Test with documents that have no RoC yet (just upload fees)
  3. Test idempotency (calling transfer twice should not double-settle)
  4. Test with Google Docs URLs (multiple URL formats for same doc)

Questions for Backend Claude

  1. Does the existing queue transfer settlement logic handle URL normalization for Google Docs?
  2. Should we track "already settled" status per document to prevent double-settlement?
  3. What happens if the original uploader no longer exists in the users table?

  • Frontend: dist/js/admin/users.js (line 950 - handleTransfer)
  • Frontend: src/admin/users/index.njk (Document Transfer tab)
  • Backend: supabase/functions/adminUsers/ (current transfer-docs endpoint)
  • Backend: supabase/functions/manageQueue/handlers/transfer.ts (existing settlement logic)
  • Docs: src/dev/readme_manageQueue.md (queue transfer API docs)