skills/file-upload-storage-expert/SKILL.md
S3, multipart uploads, CDN integration, and presigned URLs for file storage. Activate on: file upload, S3, presigned URL, multipart upload, CDN, blob storage, image upload, media storage. NOT for: data warehouse storage (use lakehouse-architect), database design (use dimensional-modeler).
npx skillsauth add curiositech/windags-skills file-upload-storage-expertInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Design secure, scalable file upload and storage systems with presigned URLs, multipart uploads, CDN distribution, and lifecycle management.
Activate on: "file upload", "S3", "presigned URL", "multipart upload", "CDN", "blob storage", "image upload", "R2", "media storage", "upload progress"
NOT for: Data lake storage → lakehouse-architect | Database BLOB columns → dimensional-modeler | Video processing pipelines → relevant media skill
| Domain | Technologies | |--------|-------------| | Object Storage | AWS S3, Cloudflare R2, GCS, MinIO | | Upload Libraries | @aws-sdk/client-s3, tus-js-client, Uppy 4.x | | CDN | CloudFront, Cloudflare CDN, Fastly | | Processing | Sharp (images), FFmpeg (video), ClamAV (scanning) | | Managed | Supabase Storage, Vercel Blob, Uploadthing |
Client Server S3/R2
│ │ │
├─ POST /upload/init ────→│ │
│ { filename, type } │ │
│ ├─ createPresignedPost() ─→│
│ │ │
│←── { url, fields } ────┤ │
│ │ │
├─ PUT (direct to S3) ──────────────────────────────→│
│ │ │
│ │←── S3 Event Notification│
│ ├─ Process (thumbnail, │
│ │ scan, metadata) │
│←── webhook: ready ─────┤ │
import { S3Client, CreateMultipartUploadCommand,
UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3';
const PART_SIZE = 10 * 1024 * 1024; // 10MB parts
async function multipartUpload(file: Buffer, key: string) {
const { UploadId } = await s3.send(
new CreateMultipartUploadCommand({ Bucket: BUCKET, Key: key })
);
const parts: { ETag: string; PartNumber: number }[] = [];
for (let i = 0; i < file.length; i += PART_SIZE) {
const partNumber = Math.floor(i / PART_SIZE) + 1;
const { ETag } = await s3.send(new UploadPartCommand({
Bucket: BUCKET, Key: key, UploadId,
PartNumber: partNumber,
Body: file.subarray(i, i + PART_SIZE),
}));
parts.push({ ETag: ETag!, PartNumber: partNumber });
}
await s3.send(new CompleteMultipartUploadCommand({
Bucket: BUCKET, Key: key, UploadId,
MultipartUpload: { Parts: parts },
}));
}
User Request → CDN Edge (cache hit?) ──yes──→ Serve cached
│ no
↓
Origin (S3/R2)
↓
Response + Cache-Control: public, max-age=31536000, immutable
(use content-hash in filename for cache busting)
sha256-{hash}.ext) for CDN cacheabilitydata-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.