Skip to content

feat(backend-sep12): GCS StorageProvider, UploadRecord schema, MIME validation & mock SMTP tests#667

Open
vic-Gray wants to merge 2 commits into
ceejaylaboratory:mainfrom
vic-Gray:feature/issue-545-547-550-541-sep12-gcs-storage-upload-record-mime-validation-smtp
Open

feat(backend-sep12): GCS StorageProvider, UploadRecord schema, MIME validation & mock SMTP tests#667
vic-Gray wants to merge 2 commits into
ceejaylaboratory:mainfrom
vic-Gray:feature/issue-545-547-550-541-sep12-gcs-storage-upload-record-mime-validation-smtp

Conversation

@vic-Gray

Copy link
Copy Markdown
Contributor

Summary

This PR implements four related backend issues in the backend-sep12 and backend-tests component scopes.


Changes

#545 — [SEP-12] Implement GCS StorageProvider (closes #545)

  • Added @google-cloud/storage: ^7.9.0 to backend/package.json
  • Created StorageProvider interface (src/services/storage/storage.provider.ts)
    • Single method: getSignedUploadUrl(key, mimeType, expiresIn?): Promise<string>
  • Created GcsStorageProvider implementing the interface (src/services/storage/gcs.storage.provider.ts)
    • Uses GCS v4 signed URLs with action: 'write', default TTL 900 s
    • Storage client injectable for easy unit-testing
  • Barrel export via src/services/storage/index.ts

#547 — [SEP-12] Add UploadRecord Schema to Prisma (closes #547)

  • Added UploadStatus enum (PENDING | COMPLETED | EXPIRED) to backend/prisma/schema.prisma
  • Added UploadRecord model with fields:
    • id, account, fieldName, storageKey, status, expiresAt, createdAt, updatedAt
    • Indexes on account and status

#550 — [SEP-12] Add Content-Type Allowlist Validation (closes #550)

  • Exported ALLOWED_MIME_TYPES set from src/api/routes/sep12.route.ts:
    image/jpeg, image/png, image/webp, application/pdf
  • Added Multer fileFilter — rejects disallowed types via MulterError
  • Added Express error-handler middleware returning HTTP 400 with a descriptive message listing allowed types

#541 — Add Mock SMTP Server for Local Backend Testing (closes #541)

  • Added nodemailer-mock: ^2.0.5 to devDependencies
  • Created src/services/admin-email.service.test.ts with 7 unit tests:
    • Sends exactly one email per call
    • Correct to and from addresses
    • Reset token present in plain-text body
    • Reset URL and token present in HTML body
    • Expiry timestamp present in body
    • Independent second send (models withdrawal confirmation pattern)

Testing

# Prisma schema validation
npx prisma validate

# Backend unit tests (includes new SMTP mock tests)
npm run test:backend

Files Changed

File Change
backend/package.json Add @google-cloud/storage dep, nodemailer-mock devDep
backend/prisma/schema.prisma Add UploadStatus enum + UploadRecord model
backend/src/api/routes/sep12.route.ts MIME allowlist + fileFilter + 400 error handler
backend/src/services/storage/storage.provider.ts NEW — StorageProvider interface
backend/src/services/storage/gcs.storage.provider.ts NEW — GcsStorageProvider
backend/src/services/storage/index.ts NEW — barrel export
backend/src/services/admin-email.service.test.ts NEW — 7 SMTP mock tests

vic-Gray added 2 commits June 26, 2026 14:17
…e validation & mock SMTP tests

- feat(backend-sep12): [sep-12] implement gcs storageprovider (closes ceejaylaboratory#545)
- feat(backend-sep12): [sep-12] add upload_record schema to prisma (closes ceejaylaboratory#547)
- feat(backend-sep12): [sep-12] add content type allowlist validation for upload requests (closes ceejaylaboratory#550)
- feat(backend-tests): add mock smtp server for local backend testing (closes ceejaylaboratory#541)
@drips-wave

drips-wave Bot commented Jun 26, 2026

Copy link
Copy Markdown

@vic-Gray Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant