# Bulk Address Upload — Implementation Tracker ## Overview Upload CSV/XLSX to S3 (browser-direct via XHR with progress bar) → confirm in DB → redirect to upload list. Portfolio shows all uploads ordered by date. User picks which to continue. --- ## DB Migration (manual — do this first) ```sql CREATE TABLE bulk_address_uploads ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), portfolio_id TEXT NOT NULL, user_id TEXT NOT NULL, s3_bucket TEXT NOT NULL, s3_key TEXT NOT NULL, filename TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'ready_for_processing', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); ``` Status values: `ready_for_processing` | `processing` | `complete` | `failed` - [ ] Migration applied to dev - [ ] Migration applied to staging - [ ] Migration applied to prod --- ## Tasks ### 1. Drizzle Schema - [ ] Create `src/app/db/schema/bulk_address_uploads.ts` - [ ] Import + spread into `src/app/db/db.ts` ### 2. Confirm API Route - [ ] Create `src/app/api/upload/bulk-addresses/confirm/route.ts` - POST `{ fileKey, filename, portfolioId, userId }` - Inserts into `bulk_address_uploads`, `s3Bucket` from `RETROFIT_PLAN_INPUT_BUCKET_NAME` env - Returns `{ id, s3Key, s3Bucket, status }` ### 3. List API Route - [ ] Create `src/app/api/portfolio/[portfolioId]/bulk-uploads/route.ts` - GET → all uploads for portfolio ordered by `created_at DESC` - Returns array of upload records ### 4. Modal — XHR Upload + Progress + Redirect to List - [ ] Replace `fetch` PUT → `XMLHttpRequest` in `handleUpload` - [ ] Add `progress: number | null` state - [ ] Show progress bar in dropzone while uploading - [ ] After XHR load: POST confirm → `router.push(/portfolio/[id]/bulk-upload)` ### 5. Upload List Page - [ ] Create `src/app/portfolio/[portfolioId]/bulk-upload/page.tsx` - Server component - List all uploads: filename, status badge, created date, "Continue →" link - Empty state if none - Each row links to `/bulk-upload/[uploadId]` ### 6. Upload Detail Page - [ ] Create `src/app/portfolio/[portfolioId]/bulk-upload/[uploadId]/page.tsx` - Server component - Shows: filename, `s3://bucket/key`, status, created date - For now: "Your file is queued for processing" --- ## Flow ``` User drops/clicks file → validate (size, extension, headers) → GET presigned URL (/api/upload/bulk-addresses) → XHR PUT to S3 (progress bar shown) → POST confirm (/api/upload/bulk-addresses/confirm) → redirect to list (/portfolio/[id]/bulk-upload) → list page (all uploads, status badges, click to continue) → detail page (/portfolio/[id]/bulk-upload/[uploadId]) → shows s3_uri + status ``` --- ## Files Touched | File | Status | |------|--------| | `src/app/db/schema/bulk_address_uploads.ts` | not started | | `src/app/db/db.ts` | not started | | `src/app/api/upload/bulk-addresses/confirm/route.ts` | not started | | `src/app/api/portfolio/[portfolioId]/bulk-uploads/route.ts` | not started | | `src/app/components/portfolio/BulkUploadComingSoonModal.tsx` | not started | | `src/app/portfolio/[portfolioId]/bulk-upload/page.tsx` | not started | | `src/app/portfolio/[portfolioId]/bulk-upload/[uploadId]/page.tsx` | not started |