WFDASH-WEBAPP/pb_quote_attachments.schema.json
SJCoetz a18ab0f19f feat: add quote email tracking, user color coding, and improved attachments
Add comprehensive quote management and UI improvements:
- Add `email_received_at` field to quotes collection, TypeScript types, and setup script
- Update quote attachments schema to mark `kind` optional for legacy attachments, add `uploaded_at` field, and improve documentation comments
- Create `/api/v1/users/lookup` server endpoint to resolve user IDs to display names
- Add stable user ID → color mapping for visual grouping of claimed quotes
- Enhance quotes list page: reorder tab filters, show claimer names, color-code rows per claimant
- Update quote detail page to display claimer info with user icon
- Expand DataTable component to support per-row custom class and style props
- Overhaul QuoteEmailCard: add proper HTML/plain text body sanitization/linkification, inline PDF/image previews, improved metadata display, and fixed auth-aware attachment previews via blob URLs
2026-06-22 15:15:00 +02:00

177 lines
6.6 KiB
JSON

{
"_comment_top": "WFDASH — PocketBase schema snippet for the quote_attachments collection. This collection backs the v5 Catch and Create attachment upload pipeline. Import via Settings → Import collections in the PB admin UI. The collection id (pbc_quote_attachments_NEW) is a placeholder — PB will assign its own 15-char id on import; if you need to pin it, replace it after import and update all workflow HTTP URLs that reference /api/collections/quote_attachments/records/.",
"collections": [
{
"_comment": "quote_attachments — one row per uploaded file. quote is OPTIONAL so the Catch and Create pipeline can POST the file BEFORE the quote record exists; a downstream PATCH links them.",
"id": "pbc_quote_attachments_NEW",
"name": "quote_attachments",
"type": "base",
"listRule": "@request.auth.id != ''",
"viewRule": "@request.auth.id != ''",
"createRule": "@request.auth.id != ''",
"updateRule": "@request.auth.id != ''",
"deleteRule": "@request.auth.id != ''",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text_qa_id",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"hidden": false,
"id": "autodate_qa_created",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": true,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate_qa_updated",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": true,
"type": "autodate"
},
{
"_comment": "The actual file. multipart upload via PocketBase's standard file field. Allowed mime types omitted — set them to whatever your RFQ vendors send (pdf, png, jpg, docx, csv, xlsx, etc).",
"hidden": false,
"id": "file_qa_file",
"maxSelect": 1,
"maxSize": 52428800,
"mimeTypes": ["application/pdf", "image/png", "image/jpeg", "image/webp", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "text/csv", "text/plain", "application/json", "application/octet-stream"],
"name": "file",
"presentable": false,
"protected": false,
"required": false,
"system": false,
"thumbs": null,
"type": "file"
},
{
"_comment": "Link to the quote this attachment belongs to. Optional — populated AFTER the quote record is created, via the PATCH Attachment (set quote) step in v5.",
"cascadeDelete": false,
"collectionId": "pbc_2527524235",
"hidden": false,
"id": "relation_qa_quote",
"maxSelect": 1,
"minSelect": 0,
"name": "quote",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
},
{
"_comment": "Email Message-ID. Part of the unique composite index so re-firing the workflow on the same email (e.g. retry, IMAP re-poll) doesn't upload duplicates.",
"autogeneratePattern": "",
"hidden": false,
"id": "text_qa_message_id",
"max": 0,
"min": 0,
"name": "email_message_id",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text_qa_filename",
"max": 0,
"min": 0,
"name": "filename",
"pattern": "",
"presentable": true,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text_qa_content_type",
"max": 0,
"min": 0,
"name": "content_type",
"pattern": "",
"presentable": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "number_qa_size",
"max": null,
"min": null,
"name": "size_bytes",
"onlyInt": true,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"_comment": "pdf / image / doc / other — convenience classification so the dashboard can render appropriate previews without sniffing the file. Required by docs/pocketbase/quote_attachments.collection.json but treated as optional here because attachments uploaded before the v7 multi-attachment workflow wrote `kind` (none of them have it). The v7 workflow now writes `kind`; old rows can be backfilled via the dashboard or a one-shot PB rule.",
"hidden": false,
"id": "select_qa_kind",
"maxSelect": 0,
"name": "kind",
"presentable": false,
"required": false,
"system": false,
"type": "select",
"values": ["pdf", "image", "doc", "other"]
},
{
"hidden": false,
"id": "date_qa_uploaded",
"max": "",
"min": "",
"name": "uploaded_at",
"presentable": false,
"required": false,
"system": false,
"type": "date"
},
{
"_comment": "Provenance. Which n8n workflow uploaded this. Lets you tell apart v4 / v5 / manual uploads in the dashboard.",
"autogeneratePattern": "",
"hidden": false,
"id": "text_qa_uploaded_by",
"max": 0,
"min": 0,
"name": "uploaded_by",
"pattern": "",
"presentable": false,
"required": false,
"system": false,
"type": "text"
}
],
"indexes": [
"CREATE UNIQUE INDEX `idx_qa_msg_filename` ON `quote_attachments` (`email_message_id`, `filename`) WHERE `email_message_id` != '' AND `filename` != ''",
"CREATE INDEX `idx_qa_quote` ON `quote_attachments` (`quote`)"
],
"system": false
}
]
}