This document explains how to set up Firebase Storage for firm branding assets (letterhead, signature, stamp images).
- Images stored as Base64 strings in Firestore documents
- 100KB image → ~133KB Base64 string
- 3 images per firm → ~400KB per firm document
- Firestore limit: 1MB per document → Only 2-3 firms possible!
- Images uploaded to Firebase Storage
- Firestore stores only URLs (5KB per firm)
- Unlimited firms possible
- Images served via CDN
- Automatic compression and optimization
- Go to Firebase Console
- Select your project:
auto-tender-pro - Click on Storage in the left sidebar
- Click Get Started
- Choose Start in production mode (or test mode for development)
- Select your region (e.g.,
us-central1) - Click Done
- Go to Storage → Rules tab
- Replace the default rules with the rules from
firestore.rulesfile - Click Publish
Storage Rules Summary:
- Authenticated users can read/write images
- Max file size: 2MB
- Only image files allowed (PNG, JPEG, WebP)
- Files organized by firm ID and image type
Add these to your .env file:
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=auto-tender-pro.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=1024282764045If you want to deploy rules via Firebase CLI:
# Install Firebase CLI (if not already installed)
npm install -g firebase-tools
# Login to Firebase
firebase login
# Deploy rules
firebase deploy --only storagefirms/
├── {firmId}/
│ ├── letterhead/
│ │ └── {filename}-{timestamp}.png
│ ├── signature/
│ │ └── {filename}-{timestamp}.png
│ └── stamp/
│ └── {filename}-{timestamp}.png
└── temp/
└── {userId}/
└── {filename}-{timestamp}.png
import { uploadFirmImage } from '@/services/imageUploadService';
const result = await uploadFirmImage(file, firmId, 'letterhead');
// result.url = "https://firebasestorage.googleapis.com/..."
// result.fileName = "firms/abc123/letterhead/image.png-1234567890"
// result.fileSize = 102400
// result.mimeType = "image/png"import { deleteFirmImage } from '@/services/imageUploadService';
await deleteFirmImage(imageUrl);import { deleteFirmImages } from '@/services/imageUploadService';
const deletedCount = await deleteFirmImages(firmId);
// Returns number of images deletedallow read: if isAuthenticated();- Any authenticated user can read images
allow write: if isAuthenticated() &&
isFileSizeValid() &&
isImageTypeValid() &&
isFileNameValid() &&
imageType in ['letterhead', 'signature', 'stamp'];- Must be authenticated
- File size < 2MB
- File type must be image
- File name must be alphanumeric
- Image type must be one of: letterhead, signature, stamp
- 5GB storage
- 1GB downloads per day
- Sufficient for 100+ firms
- Pay per usage
- ~$0.026/GB storage
- ~$0.12/GB downloads
- 100 firms × 3 images × 100KB = 30MB storage
- Monthly cost: ~$0.0008 (negligible)
// Run in browser console
const json = await db.exportDatabase();
downloadFile('backup-before-storage.json', json);// For each firm with Base64 images
for (const firm of firms) {
if (firm.headerImagePath?.startsWith('data:')) {
// Convert Base64 to file
const response = await fetch(firm.headerImagePath);
const blob = await response.blob();
const file = new File([blob], 'letterhead.png', { type: 'image/png' });
// Upload to storage
const url = await uploadFirmImage(file, firm.id, 'letterhead');
// Update firm with URL
await dataService.firms.update(firm.id, { headerImagePath: url });
}
}// Check that all firms have storage URLs
const firms = await dataService.firms.list();
const hasBase64 = firms.some(f => f.headerImagePath?.startsWith('data:'));
console.log('Has Base64 images:', hasBase64);- Check storage rules are deployed
- Verify user is authenticated
- Check file size and type constraints
- Verify the URL is correct
- Check if file was deleted
- Ensure storage bucket name is correct
- Check browser console for CORS errors
- Verify storage bucket is public or images have read permissions
- Check network tab for 403/404 errors
- Always validate file size (max 2MB)
- Always validate file type (images only)
- Use Firebase Authentication (don't allow anonymous uploads)
- Organize files by user/firm (prevents collisions)
- Delete old temp files (use Cloud Functions)
- Monitor storage usage (set up alerts)
# Using Firebase CLI
firebase storage:ls
# Or check in Firebase Console
# Storage → Files → Total size- Go to Firebase Console → Usage
- Click Set up billing alerts
- Configure alerts for:
- Storage usage > 80%
- Downloads > 1GB/day
- ✅ Upload images to Firebase Storage
- ✅ Store URLs in Firestore
- ✅ Delete old Base64 images
- ✅ Monitor storage usage
- ✅ Set up Cloud Functions for auto-cleanup
For issues:
- Check Firebase Console → Storage → Logs
- Check browser console for errors
- Verify storage rules are correct
- Ensure Firebase SDK is properly initialized