BuildShip Workflow: Speaking Events Image Upload¶
Archived record
This page describes the Firebase-era platform or a migration step that has completed. It is kept as history and is not a current runbook. The current platform is described from the home page.
Last Updated: February 15, 2026 Purpose: Create a BuildShip workflow to upload event images to Firebase Cloud Storage and store download URLs in Firestore
Overview¶
This workflow enables you to:
- Upload event images via a web form
- Automatically store them in Firebase Cloud Storage (
speakerevents/folder) - Save the full download URL to Firestore
eventImageUrlfield - Maintain proper file naming and organization
Architecture¶
BuildShip Workflow (Web Form)
↓
Upload Image (Firebase Storage)
↓
Get Download URL
↓
Update Firestore speakerevents Document
↓
Display in Speaking Engagements Widget
Step-by-Step Setup¶
Step 1: Create BuildShip Workflow¶
- Go to BuildShip Dashboard
- Create a new workflow named:
Upload Speaking Event Image - Set trigger type: HTTP Request (REST API)
- HTTP Method: POST
Step 2: Configure Input Schema¶
In the HTTP trigger, define the request body schema:
{
"type": "object",
"properties": {
"eventId": {
"type": "string",
"description": "Firestore document ID (from speakerevents collection)"
},
"eventName": {
"type": "string",
"description": "Name of the speaking event"
},
"imageFile": {
"type": "string",
"description": "Base64-encoded image data or URL"
},
"imageFileName": {
"type": "string",
"description": "Original filename (e.g., 'event-photo.png')"
}
},
"required": ["eventId", "eventName", "imageFile", "imageFileName"]
}
Step 3: Add Firebase Upload Node¶
- Add Node → Search for Firebase Storage → Upload File
- Configure:
- Service Account Key: Select your HCW Firebase project
- Bucket:
hybridcloudworks-61e8d.appspot.com - File Path:
- File Content: (Connect to imageFile input)
-
Content Type:
image/pngor auto-detect from filename -
Output Variable Name:
uploadResult
Step 4: Add Get Download URL Node¶
- Add Node → Search for Firebase Storage → Get Download URL
- Configure:
- Service Account Key: Same Firebase project
- Bucket:
hybridcloudworks-61e8d.appspot.com -
File Path:
-
Output Variable Name:
downloadUrl
Step 5: Add Firestore Update Node¶
- Add Node → Search for Firebase Firestore → Update Document
- Configure:
- Service Account Key: Same Firebase project
- Collection:
speakerevents - Document ID:
{{ eventId }} - Data to Update:
- Output Variable Name:
updateResult
Step 6: Add Response Node¶
- Add Node → Return Response
- Configure response:
Step 7: Add Error Handling¶
- Add error handlers for each Firebase node
- Return appropriate error messages:
Update Firestore Storage Rules¶
Your current storage.rules needs to allow BuildShip uploads. Update it:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// ========================================================================
// Speaking Events - BuildShip Uploads
// ========================================================================
match /speakerevents/{eventId}/{allPaths=**} {
allow read: if true; // Public read
allow write: if request.auth == null; // Service account (BuildShip) can write
}
// ... rest of existing rules ...
}
}
Then deploy:
Integration with Rowy¶
Once the BuildShip workflow is set up:
In Rowy:¶
- Open the
speakereventstable - In the
eventImageUrlcolumn: - Field Type: URL (or File)
- Add Action Button: Create custom action
-
Link to your BuildShip workflow endpoint
-
Or use a Custom Component to embed an upload button
Example Rowy Action Config:¶
// Custom action in Rowy
const uploadImage = async (row) => {
const file = await selectFile(); // File picker
const formData = new FormData();
formData.append('eventId', row.id);
formData.append('eventName', row.name);
formData.append('imageFile', file);
formData.append('imageFileName', file.name);
const response = await fetch('YOUR_BUILDSHIP_WEBHOOK_URL', {
method: 'POST',
body: JSON.stringify({
eventId: row.id,
eventName: row.name,
imageFile: await fileToBase64(file),
imageFileName: file.name,
}),
});
return response.json();
};
Manual Upload Alternative¶
If you prefer not to use BuildShip, use Firebase Console directly:
- Firebase Console → Storage
- Create folder structure manually:
- Upload file
- Click file → Copy download URL (with auth token)
- Paste into Firestore
eventImageUrlfield in Rowy
Testing the Workflow¶
Using cURL:¶
curl -X POST https://your-buildship-webhook-url \
-H "Content-Type: application/json" \
-d '{
"eventId": "tprVKGxm9EWGP766l9tx",
"eventName": "Business Applications LATAM",
"imageFile": "data:image/png;base64,iVBORw0KGgo...",
"imageFileName": "latam-event.png"
}'
Expected Response:¶
{
"success": true,
"message": "Image uploaded successfully",
"downloadUrl": "https://firebasestorage.googleapis.com/v0/b/hybridcloudworks-61e8d.appspot.com/o/speakerevents%2FtprVKGxm9EWGP766l9tx%2FeventImageUrl%2Flatam-event.png?alt=media&token=...",
"eventId": "tprVKGxm9EWGP766l9tx"
}
Frontend Integration (Optional)¶
To add direct upload from your Speaking Engagements page:
const uploadEventImage = async (eventId, file) => {
const formData = new FormData();
formData.append('eventId', eventId);
formData.append('imageFile', await fileToBase64(file));
formData.append('imageFileName', file.name);
const response = await fetch(
process.env.REACT_APP_BUILDSHIP_WEBHOOK_URL,
{ method: 'POST', body: JSON.stringify({...}) }
);
if (response.ok) {
// Refresh the speaking engagements widget
// Firestore listener will auto-update
console.log('Image uploaded successfully');
}
};
Troubleshooting¶
| Issue | Solution |
|---|---|
| "Permission denied" error | Check storage.rules allows service account writes to speakerevents/* |
| Download URL not saving to Firestore | Verify Firestore document ID matches exactly in the Update Document node |
| Image shows blank in Rowy | Ensure eventImageUrl field is type URL and contains full HTTPS link |
| BuildShip webhook returns 404 | Check webhook URL is copied correctly from BuildShip dashboard |
| File uploads but URL is invalid | Verify filename doesn't contain special characters; sanitize in BuildShip node |
Security Considerations¶
- Limit file size: Set max 5-10MB in BuildShip and storage rules
- Validate image types: Only allow
image/png,image/jpeg,image/webp - Use service account: BuildShip uses service account (not user auth)
- Public read access: Images in
speakerevents/are publicly readable (OK for event photos) - CORS: If uploading from frontend, configure CORS in Firebase
Next Steps¶
- Create the BuildShip workflow following steps above
- Deploy updated
storage.rules - Test with sample event image
- Integrate upload button into Rowy (optional)
- Document in team wiki how to add new speaking events with images