cuatrolabs-scm-ms / DOCUMENT_UI_QUICKREF.md
MukeshKapoor25's picture
minio doc store
9b11567
# Document Service - UI Quick Reference
## πŸš€ Quick Start (3 Steps)
### Step 1: Initialize Upload
```javascript
POST /scm/storage/upload/init
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"domain": "po",
"entity_id": "PO-2024-001",
"category": "invoice",
"file_name": "invoice.pdf",
"mime_type": "application/pdf",
"file_size": 2097152,
"visibility": "private"
}
Response:
{
"upload_id": "uuid",
"presigned_urls": ["http://minio:9000/..."],
"object_key": "tenant_001/po/PO-2024-001/invoice/invoice.pdf"
}
```
### Step 2: Upload File to MinIO (Direct)
```javascript
// ⚠️ NOT a backend endpoint - direct upload to MinIO
// Use the presigned_urls[0] from Step 1 response
PUT <presigned_urls[0]> // From Step 1 response
Content-Type: application/pdf
Body: <binary file data>
// NO Authorization header needed (presigned URL is tenant-scoped)
// Calculate checksum while uploading
const fileBuffer = await file.arrayBuffer();
const checksum = await crypto.subtle.digest('SHA-256', fileBuffer);
```
**Note**: This step bypasses the backend API and uploads directly to MinIO for performance. The presigned URL is scoped to the tenant and expires in 15 minutes.
### Step 3: Complete Upload
```javascript
POST /scm/storage/upload/complete
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"upload_id": "uuid from step 1",
"checksum_sha256": "hex_string"
}
Response:
{
"id": "object_id",
"deduplicated": false
}
```
---
## πŸ“‹ Endpoints Reference
| Method | Endpoint | Purpose | Auth Required |
|--------|----------|---------|---------------|
| POST | `/scm/storage/upload/init` | Initialize upload | βœ… |
| POST | `/scm/storage/upload/complete` | Finalize upload | βœ… |
| POST | `/scm/storage/download-url` | Get download URL | βœ… |
| GET | `/scm/storage/{object_id}` | Get metadata | βœ… |
| DELETE | `/scm/storage/{object_id}` | Delete object | βœ… |
---
## πŸ”‘ Authentication
All requests must include JWT token:
```javascript
headers: {
"Authorization": "Bearer <JWT_TOKEN>",
"Content-Type": "application/json"
}
```
**JWT Payload Requirements:**
- `user_id`: User identifier
- `username`: Username
- `role`: buyer | supplier | ops | admin
- `merchant_id`: Tenant identifier
---
## 🎯 Allowed Domains by Role
| Role | PO | GRN | Inventory | Dispatch | Returns | Promotions | Profile |
|------|----|----|-----------|----------|---------|-----------|---------|
| buyer | βœ… | βœ… | βœ… | ❌ | ❌ | ❌ | ❌ |
| supplier | ❌ | ❌ | ❌ | βœ… | βœ… | ❌ | ❌ |
| ops | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… |
| admin | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… | βœ… |
**Delete Permissions**: Only ops and admin (legal_hold can block)
---
## πŸ“¦ File Limits
| Type | Max Size | MIME Types |
|------|----------|-----------|
| Images | 10 MB | image/jpeg, image/png, image/webp, image/gif |
| Documents | 50 MB | application/pdf, application/msword, application/vnd.ms-excel, text/csv |
| Exports | 50 MB | Any (temporary) |
---
## πŸ“Š Bucket Routing (Automatic)
| Type | Bucket | Visibility |
|------|--------|-----------|
| Documents | `cutra-scm-documents` | Private only |
| Images | `cutra-scm-images` | Private |
| Images | `cutra-scm-images-public` | Public |
| Exports | `cutra-scm-exports` | Temporary |
---
## ❌ Error Codes
| Code | Meaning | Solution |
|------|---------|----------|
| 400 | Bad Request | Check request payload, verify all required fields |
| 403 | Forbidden | Check user role/domain permissions |
| 404 | Not Found | Object deleted or doesn't exist |
| 409 | Conflict | Checksum mismatch - file corrupted during upload |
| 413 | Too Large | File exceeds size limit |
| 415 | Wrong Type | MIME type not allowed |
---
## πŸ” Download File (2 Options)
### Option A: By Object ID
```javascript
POST /scm/storage/download-url
{ "object_id": "uuid" }
```
### Option B: By Composite Key
```javascript
POST /scm/storage/download-url
{
"domain": "po",
"entity_id": "PO-2024-001",
"category": "invoice",
"file_name": "invoice.pdf"
}
```
**Response:**
```javascript
{
"url": "http://minio:9000/...",
"expires_in": 900 // 15 minutes
}
```
---
## πŸ’Ύ Get Metadata
```javascript
GET /scm/storage/{object_id}
Response:
{
"id": "uuid",
"file_name": "invoice.pdf",
"mime_type": "application/pdf",
"file_size": 2097152,
"visibility": "private",
"domain": "po",
"entity_id": "PO-2024-001",
"category": "invoice",
"checksum_sha256": "hex",
"created_at": "2024-01-14T10:30:00Z",
"legal_hold": false
}
```
---
## πŸ—‘οΈ Delete Object (Soft Delete)
```javascript
DELETE /scm/storage/{object_id}
Response:
{ "status": "deleted" }
Notes:
- Object marked as deleted (not removed)
- Audit trail preserved
- Returns 404 on subsequent fetches
- Only ops/admin can delete
- Legal hold prevents deletion
```
---
## ♻️ Deduplication
Same file uploaded twice?
- **First upload**: `{id: "uuid1", deduplicated: false}`
- **Second upload**: `{id: "uuid1", deduplicated: true}`
**Benefits:**
- Saves storage
- Single copy for identical files
- Service returns existing ID
---
## πŸ” Security Features
βœ… **Tenant Isolation**
- Cross-tenant access impossible
- All queries filtered by merchant_id
βœ… **Presigned URLs**
- 15-minute expiry (900s)
- Tenant-scoped
- No auth headers in URL
βœ… **RBAC**
- Role-based domain access
- Buyer β‰  Supplier domains
- Delete restricted to ops/admin
βœ… **Soft Delete**
- Audit trail with timestamps
- Legal hold enforcement
- Compliance ready
βœ… **Checksum Validation**
- SHA-256 verification
- Detects file corruption
- Prevents tampering
---
## πŸ“± React Component Usage
```javascript
import DocumentUploadComponent from './DocumentUploadComponent';
<DocumentUploadComponent
token={jwtToken}
domain="po"
entityId="PO-2024-001"
category="invoice"
/>
```
---
## πŸ“ Common Workflows
### Upload Invoice
```javascript
POST /scm/storage/upload/init
{
"domain": "po",
"entity_id": "PO-2024-001",
"category": "invoice",
"file_name": "invoice_001.pdf",
"mime_type": "application/pdf",
"file_size": 1048576,
"visibility": "private"
}
```
### Upload Merchant Logo
```javascript
POST /scm/storage/upload/init
{
"domain": "profile",
"entity_id": "MERCHANT-001",
"category": "profile",
"file_name": "logo.png",
"mime_type": "image/png",
"file_size": 524288,
"visibility": "public"
}
```
### Share Document
```javascript
POST /scm/storage/download-url
{ "object_id": "uuid" }
// Share the returned presigned URL (expires in 900s)
```
---
## πŸ› οΈ Troubleshooting
| Issue | Solution |
|-------|----------|
| 403 Forbidden | Check user role has access to domain |
| 404 Not Found | Object deleted or wrong ID |
| 409 Checksum Error | File corrupted - retry upload |
| 413 Too Large | Reduce file size or check limits |
| Upload stuck | Check internet connection, retry |
| No download | Verify presigned URL not expired (900s max) |
---
## πŸš€ Production Checklist
- [ ] Use production JWT tokens
- [ ] Enable HTTPS for all requests
- [ ] Set up MinIO with SSL
- [ ] Configure CORS for domain
- [ ] Monitor upload bandwidth
- [ ] Set up error logging
- [ ] Test with various file types
- [ ] Verify multi-tenancy isolation
- [ ] Set legal hold for compliance docs
- [ ] Monitor presigned URL usage
---
## πŸ“š Related Files
- `UI_INTEGRATION_GUIDE.md` - Detailed integration guide
- `DocumentUploadComponent.jsx` - React component example
- `DOCUMENT_TESTING_GUIDE.md` - API testing
- `app/documents/README.md` - Backend setup
---
**Last Updated**: January 14, 2026
**API Version**: 1.0.0
**Status**: Production Ready βœ