{"id":50811964,"url":"https://github.com/kiquetal/quarks-tigris","last_synced_at":"2026-06-13T05:33:37.086Z","repository":{"id":334388213,"uuid":"1140742402","full_name":"kiquetal/quarks-tigris","owner":"kiquetal","description":"🎙️ Full-stack MP3 upload application with Angular 19 + Quarkus 3.30.7. Features passphrase authentication, S3/Tigris storage integration, and LocalStack development environment. Built with RESTful API, hot-reload dev mode, and Docker Compose orchestration.","archived":false,"fork":false,"pushed_at":"2026-02-13T16:37:58.000Z","size":1514,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-14T00:43:19.798Z","etag":null,"topics":["java21","nats-messaging","quarkus","tigris","typescript"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kiquetal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-23T17:41:26.000Z","updated_at":"2026-02-13T16:38:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kiquetal/quarks-tigris","commit_stats":null,"previous_names":["kiquetal/quarks-tigris"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kiquetal/quarks-tigris","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Fquarks-tigris","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Fquarks-tigris/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Fquarks-tigris/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Fquarks-tigris/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kiquetal","download_url":"https://codeload.github.com/kiquetal/quarks-tigris/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Fquarks-tigris/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34273788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java21","nats-messaging","quarkus","tigris","typescript"],"created_at":"2026-06-13T05:33:36.093Z","updated_at":"2026-06-13T05:33:37.079Z","avatar_url":"https://github.com/kiquetal.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Quarks-Tigris: Secure File Upload Service\n\nA Quarkus-based secure file upload service with Angular frontend, featuring envelope encryption and S3/Tigris storage.\n\n## Features\n\n✅ **Client-Side Encryption** - Files encrypted in browser with AES-GCM  \n✅ **Envelope Encryption** - Server-side re-encryption with random DEK + master key  \n✅ **Streaming Processing** - Memory-efficient handling of large files  \n✅ **S3/Tigris Storage** - Scalable object storage  \n✅ **NATS JetStream** - Event-driven architecture with message streaming  \n✅ **Angular Frontend** - Modern SPA with authentication  \n✅ **OpenAPI Documentation** - Auto-generated API docs  \n\n## Screenshots\n\n### User Interface Walkthrough\n\n**1. Passphrase Authentication**\n\n![Passphrase Screen](docs/screenshot/passphrase-screen.png)\n\nUsers authenticate with a secure passphrase before accessing the file upload functionality.\n\n**2. File Upload \u0026 Encryption**\n\n![Encrypting and Uploading](docs/screenshot/encrypting-uploading-screen.png)\n\nThe application encrypts files client-side before uploading to the server for additional envelope encryption.\n\n**3. Upload Complete**\n\n![Upload Complete](docs/screenshot/uploaded-screen.png)\n\nSuccessful upload confirmation with file details and verification status.\n\n**4. File List \u0026 Management**\n\n![My Files Screen](docs/screenshot/my-files-screen.png)\n\nView all uploaded files with metadata including original filename, file size, upload timestamp, verification status, and options to download or delete each file.\n\n**5. S3 Storage Structure**\n\n![S3 File Storage](docs/screenshot/s3-files.png)\n\nFiles are stored in S3/Tigris with organized folder structure: `uploads/{email}/{uuid}/{filename}.enc` plus `metadata.json`\n\n### File Management Operations\n\nThe application supports complete file lifecycle management:\n\n- ✅ **Upload**: Client-side encryption → Server-side envelope encryption → S3 storage\n- ✅ **List**: View all uploaded files with metadata (size, timestamp, verification status)\n- ✅ **Delete**: Remove files with both encrypted data and metadata cleanup\n- ✅ **Download**: Decrypt and download original files (via decrypt API)\n\nEach file operation is authenticated and tracked, with comprehensive logging and error handling.\n\n## Quick Start\n\n### Prerequisites\n- Java 21+\n- Maven 3.9+\n- Node.js 20+ (for frontend)\n- Docker (optional, for LocalStack/NATS)\n- NATS Server with JetStream (for message consumers - F#/.NET/Python/Go)\n\n### Run in Development Mode\n\n**Option 1: With Quarkus DevServices (Automatic)**\n```bash\n# Start with hot reload (backend + frontend)\n# NATS and S3 will be started automatically via DevServices\n./mvnw quarkus:dev\n\n# Or use the convenience script\n./dev-mode.sh\n```\n\n**Option 2: With Docker Compose (Manual)**\n```bash\n# Start NATS JetStream + LocalStack S3\ndocker-compose up -d\n\n# Start Quarkus application\nexport USE_DEVSERVICES=false\nexport S3_ENDPOINT_URL=http://localhost:4566\n./mvnw quarkus:dev\n```\n\n**Option 3: Quick Docker Setup**\n```bash\n# Automated setup script\n./setup-docker.sh\n\n# Then start Quarkus\n./dev-mode.sh\n```\n\nAccess the application:\n- **Web UI**: http://localhost:8080/whisper\n- **API Docs**: http://localhost:8080/whisper/swagger-ui\n- **Health Check**: http://localhost:8080/whisper/q/health\n\nNATS JetStream (if using docker-compose):\n- **NATS Client**: nats://localhost:4222 (credentials: guest/guest)\n- **NATS Monitoring**: http://localhost:8222\n\n### Default Passphrase\n```\nyour-secret-passphrase\n```\n(Change in `application.properties`)\n\n## Project Structure\n\n```\nquarks-tigris/\n├── src/main/java/me/cresterida/\n│   ├── FileUploadResource.java      # REST endpoints\n│   ├── dto/                          # Request/Response DTOs\n│   │   ├── ErrorResponse.java\n│   │   ├── PassphraseRequest.java\n│   │   ├── PassphraseResponse.java\n│   │   └── UploadResponse.java\n│   ├── model/                        # Data models\n│   │   └── EnvelopeMetadata.java\n│   ├── service/                      # Business logic\n│   │   └── CryptoService.java       # Encryption service\n│   └── util/                         # Utilities\n│       └── S3StorageService.java    # S3 operations\n├── src/main/webui/                  # Angular frontend\n│   └── src/app/\n│       ├── passphrase/              # Authentication\n│       ├── mp3-upload/              # File upload\n│       └── auth.guard.ts            # Route protection\n└── docs/                            # Additional documentation\n    └── archive/                     # Historical docs\n```\n\n## Architecture\n\n### System Overview\n\n```ascii\n┌──────────────────────────────────────────────────────────────────┐\n│                         User's Browser                           │\n└──────────────────────────────────────────────────────────────────┘\n                               │\n                               │ 1. Access Web UI\n                               │    http://localhost:8080/whisper\n                               ▼\n┌──────────────────────────────────────────────────────────────────┐\n│                      Angular Frontend (SPA)                      │\n│  ┌────────────────┐  ┌────────────────┐  ┌───────────────────┐  │\n│  │   Passphrase   │  │   Auth Guard   │  │   MP3 Upload      │  │\n│  │   Component    │  │   \u0026 Service    │  │   Component       │  │\n│  └────────────────┘  └────────────────┘  └───────────────────┘  │\n│         │                                          │              │\n│         │ 2. Validate Passphrase                  │              │\n│         │    (AES-GCM client-side encryption)     │              │\n│         └──────────────────┬───────────────────────┘              │\n│                            │ 3. Upload Encrypted File             │\n└────────────────────────────┼──────────────────────────────────────┘\n                             │\n                             │ Quinoa Integration\n                             ▼\n┌──────────────────────────────────────────────────────────────────┐\n│                      Quarkus Backend                             │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │              FileUploadResource                            │  │\n│  │  • POST /api/validate-passphrase                          │  │\n│  │  • POST /api/upload (100MB limit)                         │  │\n│  └────────────────────────────────────────────────────────────┘  │\n│                            │                                      │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │              CryptoService (service/)                      │  │\n│  │  • Verify \u0026 decrypt from Angular                          │  │\n│  │  • Encrypt with random DEK (streaming)                    │  │\n│  │  • Create envelope (encrypt DEK with master key)          │  │\n│  └────────────────────────────────────────────────────────────┘  │\n│                            │                                      │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │           S3StorageService (util/)                         │  │\n│  │  • Generate S3 keys                                        │  │\n│  │  • Upload encrypted file                                   │  │\n│  │  • Upload envelope metadata                                │  │\n│  └────────────────────────────────────────────────────────────┘  │\n│                            │                                      │\n│                            │ 4. Store Encrypted Data              │\n└────────────────────────────┼──────────────────────────────────────┘\n                             │\n                             │ S3 Client\n                             ▼\n┌──────────────────────────────────────────────────────────────────┐\n│                    S3/Tigris Object Storage                      │\n│  • uploads/{email}/{uuid}/file.enc    (encrypted data)          │\n│  • uploads/{email}/{uuid}/metadata.json (encrypted DEK)         │\n│                                                                  │\n│  Dev:  LocalStack (Docker container)                            │\n│  Prod: Tigris or AWS S3                                         │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n### Encryption Flow\n\n```\nUser Browser\n    ↓ (Client encrypts with passphrase: AES-256-GCM + PBKDF2)\nEncrypted File → Quarkus Backend\n    ↓ (Verify passphrase \u0026 decrypt: streaming)\nPlaintext Data → CryptoService\n    ↓ (Encrypt with random DEK: streaming)\nDEK-Encrypted Data\n    ↓ (Encrypt DEK with master key: envelope)\nS3/Tigris Storage\n    ├─ Encrypted File Data\n    └─ Metadata (with encrypted DEK)\n```\n\n### Security Layers\n\n1. **Client-Side**: AES-256-GCM with PBKDF2 (100k iterations)\n2. **Server-Side**: Random DEK per file for data encryption\n3. **Envelope**: DEK encrypted with master key for secure storage\n4. **Streaming**: Memory-efficient processing (8KB buffers)\n\n## Data Formats\n\n### Envelope Encryption Format\n\nThe envelope metadata is stored as JSON in S3 alongside the encrypted file:\n\n**S3 Storage Structure:**\n```\nuploads/{email}/{uuid}/\n├── {filename}.enc          # Encrypted file data (binary)\n└── metadata.json           # Envelope metadata (JSON)\n```\n\n**Envelope Metadata JSON Schema:**\n\n```json\n{\n  \"version\": \"1.0\",\n  \"kek\": \"base64-encoded-encrypted-dek-with-iv-and-tag\",\n  \"algorithm\": \"AES-GCM-256\",\n  \"original_filename\": \"audio.mp3\",\n  \"original_size\": 1048576,\n  \"encrypted_size\": 1048604,\n  \"verification_status\": \"VERIFIED\",\n  \"timestamp\": 1706140800000\n}\n```\n\n**Field Descriptions:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `version` | String | Metadata format version (currently \"1.0\") |\n| `kek` | String (Base64) | The KEK (Key Encryption Key) - contains the DEK encrypted with master key. Format: `[12 bytes IV][encrypted DEK][16 bytes GCM tag]` (base64-encoded) |\n| `algorithm` | String | Encryption algorithm used (\"AES-GCM-256\") |\n| `original_filename` | String | Original file name before encryption |\n| `original_size` | Long | Original file size in bytes |\n| `encrypted_size` | Long | Encrypted file size in bytes (includes IV + GCM tag) |\n| `verification_status` | String | Verification status: \"VERIFIED\" or \"NOT_VERIFIED\" |\n| `timestamp` | Long | Unix timestamp in milliseconds (epoch time) when file was uploaded |\n\n**Encryption Process:**\n\n1. Generate random 256-bit DEK (Data Encryption Key)\n2. Encrypt file data with DEK using AES-256-GCM (streaming)\n   - Format: `[12 bytes IV][encrypted data][16 bytes GCM tag]`\n3. Encrypt DEK with master key using AES-256-GCM to create KEK\n   - Format: `[12 bytes IV][encrypted DEK][16 bytes GCM tag]` (stored as base64 in `kek` field)\n4. Store encrypted file and metadata separately in S3\n\n**Decryption Process:**\n\n1. Retrieve envelope metadata from S3\n2. Decrypt KEK (which is the encrypted DEK) using master key\n3. Use decrypted DEK to decrypt file data\n4. Return original file\n\n**Important Notes:**\n- The `kek` field contains **both** the IV and encrypted DEK in a single base64 string\n- The encrypted file contains **its own** IV at the beginning (12 bytes)\n- Each encryption operation uses a unique, randomly generated IV\n- The DEK is never stored in plaintext - only as encrypted KEK\n\n### NATS JetStream Message Format\n\nAfter successful file upload, a message is published to the `FILE_UPLOADS` stream on subject `file.uploads`.\n\n**NATS Message JSON Schema:**\n\n```json\n{\n  \"event_id\": \"4820c1bd-2753-4d70-bcae-43aa36a04889\",\n  \"email\": \"kiquetal@gmail.com\",\n  \"file_uuid\": \"8af4a599-089a-431a-833c-0c9a2fca372a\",\n  \"s3_data_key\": \"uploads/kiquetal@gmail.com/8af4a599-089a-431a-833c-0c9a2fca372a/zeno.mp3.enc\",\n  \"s3_metadata_key\": \"uploads/kiquetal@gmail.com/8af4a599-089a-431a-833c-0c9a2fca372a/metadata.json\",\n  \"bucket_name\": \"whispers-bucket-dev\",\n  \"timestamp\": 1769394113840\n}\n```\n\n**Field Descriptions:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `event_id` | String (UUID) | Unique identifier for this upload event |\n| `email` | String | Email address of the uploader |\n| `file_uuid` | String (UUID) | Unique identifier for the uploaded file |\n| `s3_data_key` | String | Full S3 object key for the encrypted file (`.enc`) |\n| `s3_metadata_key` | String | Full S3 object key for the envelope metadata JSON |\n| `bucket_name` | String | S3 bucket name where files are stored |\n| `timestamp` | Long | Unix timestamp in milliseconds (epoch time) |\n\n**NATS Stream Configuration:**\n\n| Setting | Value |\n|---------|-------|\n| **Stream Name** | `FILE_UPLOADS` |\n| **Subject** | `file.uploads` |\n| **Storage** | File-based (persistent) |\n| **Retention** | 7 days (limits policy) |\n| **Max Age** | 168 hours |\n| **Replicas** | 1 (default) |\n\n**Consumer Configuration (.NET Client):**\n\n```bash\nnats consumer add FILE_UPLOADS file_processor \\\n  --filter \"file.uploads\" \\\n  --ack explicit \\\n  --pull \\\n  --deliver all \\\n  --max-deliver=-1 \\\n  --max-pending=100 \\\n  --wait=30s\n```\n\n**Message Flow:**\n\n```\nFile Upload → CryptoService → S3 Storage → NatsService → JetStream\n                                                            ↓\n                                              .NET Consumer (Pull)\n```\n\n**Use Cases for NATS Messages:**\n\n1. **Asynchronous Processing**: Trigger background jobs (transcoding, analysis)\n2. **Notifications**: Send email/webhook notifications on upload\n3. **Audit Logging**: Track all file upload events\n4. **Integration**: Connect to .NET/Python/Go consumers for downstream processing\n5. **Monitoring**: Track upload metrics and statistics\n\n**Related Documentation:**\n- [NATS_COMMANDS.md](NATS_COMMANDS.md) - NATS CLI commands and consumer setup\n- [DOTNET_CONSUMER_SETUP.md](DOTNET_CONSUMER_SETUP.md) - Complete .NET consumer guide with code examples\n- [NATS_INTEGRATION.md](docs/NATS_INTEGRATION.md) - NATS integration architecture\n\n### Complete Example: File Upload Flow\n\n**Step 1: User Uploads File**\n- File: `my-audio.mp3` (1 MB)\n- User: `alice@example.com`\n- Client encrypts with passphrase before upload\n\n**Step 2: Server Processes Upload**\n\nGenerated UUID: `550e8400-e29b-41d4-a716-446655440000`\n\nS3 Keys created:\n```\nuploads/alice@example.com/550e8400-e29b-41d4-a716-446655440000/my-audio.mp3.enc\nuploads/alice@example.com/550e8400-e29b-41d4-a716-446655440000/metadata.json\n```\n\n**Step 3: Envelope Metadata Stored**\n\n`metadata.json`:\n```json\n{\n  \"version\": \"1.0\",\n  \"kek\": \"a1b2c3d4e5f6g7h8i9j0k1l2kL8vN2mR5tY9wB3xF6jP1qS4uH7zC0eI+GCMTag==\",\n  \"algorithm\": \"AES-GCM-256\",\n  \"original_filename\": \"my-audio.mp3\",\n  \"original_size\": 1048576,\n  \"encrypted_size\": 1048604,\n  \"verification_status\": \"VERIFIED\",\n  \"timestamp\": 1737904200000\n}\n```\n\n**Note**: The `kek` field contains `[12 bytes IV][encrypted DEK][16 bytes GCM tag]` as a single base64 string.\n\n**Step 4: NATS Message Published**\n\nPublished to: `FILE_UPLOADS` stream, subject `file.uploads`\n\n```json\n{\n  \"event_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"email\": \"alice@example.com\",\n  \"file_uuid\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"s3_data_key\": \"uploads/alice@example.com/550e8400-e29b-41d4-a716-446655440000/my-audio.mp3.enc\",\n  \"s3_metadata_key\": \"uploads/alice@example.com/550e8400-e29b-41d4-a716-446655440000/metadata.json\",\n  \"bucket_name\": \"whisper-uploads\",\n  \"timestamp\": 1737904200123\n}\n```\n\n**Step 5: .NET Consumer Processes Message**\n\nYour .NET consumer receives the message and can:\n1. Parse the NATS message to get `s3_data_key` and `s3_metadata_key`\n2. Download encrypted file from S3: `bucket_name` + `s3_data_key`\n3. Download envelope metadata from S3: `bucket_name` + `s3_metadata_key`\n4. Decrypt file using the envelope (requires master key)\n5. Process the original file (transcoding, analysis, etc.)\n6. Acknowledge message to NATS\n\n**Example .NET Code:**\n\n```csharp\nvar message = JsonSerializer.Deserialize\u003cFileUploadEvent\u003e(msgData);\n\n// Download encrypted file\nvar encryptedFile = await s3Client.GetObjectAsync(\n    message.bucket_name, \n    message.s3_data_key\n);\n\n// Download envelope metadata\nvar metadata = await s3Client.GetObjectAsync(\n    message.bucket_name, \n    message.s3_metadata_key\n);\n\n// Decrypt and process file...\n```\n\n**Security Notes:**\n- File is **double-encrypted**: once by client, once by server\n- DEK is randomly generated per file (never reused)\n- Master key never stored with the data\n- Each encryption layer uses unique IVs\n- .NET consumer needs master key to decrypt files\n\n## NATS Consumer Integration\n\nThe application publishes file upload events to NATS JetStream, enabling asynchronous processing in any language (F#, C#, Python, Go, Node.js, Rust).\n\nFor complete setup instructions and code examples, see:\n- **[DOTNET_CONSUMER_SETUP.md](DOTNET_CONSUMER_SETUP.md)** - Complete F#/.NET consumer guide with code examples\n- **[NATS_COMMANDS.md](NATS_COMMANDS.md)** - NATS CLI commands and consumer setup\n- **[NATS_INTEGRATION.md](docs/NATS_INTEGRATION.md)** - Architecture and integration details\n\n## Configuration\n\n### Environment Variables\n\n```bash\n# S3/Tigris Configuration\nAWS_ACCESS_KEY_ID=your-access-key\nAWS_SECRET_ACCESS_KEY=your-secret-key\nAWS_REGION=auto\nS3_ENDPOINT_URL=https://fly.storage.tigris.dev\nS3_BUCKET_NAME=your-bucket-name\n\n# Encryption\nAPP_PASSPHRASE=your-secret-passphrase\nENCRYPTION_MASTER_KEY=base64-encoded-master-key\n\n# NATS Configuration\nNATS_SERVERS=nats://localhost:4222\n```\n\n### Generate Master Key\n\n```bash\nopenssl rand -base64 32\n```\n\n## API Endpoints\n\nThe application provides a RESTful API for passphrase validation and file upload.\n\n**Interactive API Documentation:**\n- **Swagger UI**: http://localhost:8080/whisper/swagger-ui\n- **OpenAPI Spec**: http://localhost:8080/whisper/swagger\n\nUse the Swagger UI to explore and test all available endpoints with interactive documentation.\n\n## File Operations\n\n### Upload File\n\n**Endpoint**: `POST /whisper/api/upload`\n\n**Process Flow**:\n1. User selects file in Angular frontend (see [passphrase-screen.png](docs/screenshot/passphrase-screen.png))\n2. Client-side encryption with AES-256-GCM (see [encrypting-uploading-screen.png](docs/screenshot/encrypting-uploading-screen.png))\n3. Upload encrypted file to backend\n4. Backend verifies and re-encrypts with random DEK\n5. Create envelope metadata with encrypted DEK\n6. Store both encrypted file and metadata in S3 (see [s3-files.png](docs/screenshot/s3-files.png))\n7. Publish event to NATS JetStream\n8. Return success response (see [uploaded-screen.png](docs/screenshot/uploaded-screen.png))\n\nSee [API_TESTING.md](API_TESTING.md) for detailed request/response examples and testing instructions.\n\n### List Files\n\n**Endpoint**: `GET /whisper/api/files`\n\n**Headers**: `X-Session-Token: {session-token}`\n\nLists all files for the authenticated user with metadata including original filename, file ID (UUID), file sizes, verification status, upload timestamp, and encryption algorithm details.\n\nSee [API_TESTING.md](API_TESTING.md) for detailed request/response examples and testing instructions.\n\n### Delete File\n\n**Endpoint**: `DELETE /whisper/api/files`\n\n**Headers**: `X-Session-Token: {session-token}`\n\n**Query Parameters**:\n- `fileId`: UUID of the file (from list response)\n- `fileName`: Original filename (e.g., `audio.mp3`)\n\nDeletes both the encrypted file (`uploads/{email}/{fileId}/{fileName}.enc`) and metadata (`metadata.json`) from S3 storage.\n\n**Important Notes**:\n- Frontend sends original filename (e.g., `audio.mp3`)\n- Backend automatically handles `.encrypted` and `.enc` extension normalization\n- Both encrypted data and metadata are removed for complete cleanup\n- Operation requires valid session token\n- Deletion is immediate and cannot be undone\n\n**Frontend Integration**: The Angular frontend provides a user-friendly delete button for each file. On successful deletion, the file immediately disappears from the list with no page refresh required.\n\nSee [API_TESTING.md](API_TESTING.md) for request/response examples.\n\n## Documentation\n\n### Getting Started\n- **[GETTING_STARTED.md](GETTING_STARTED.md)** - Detailed setup guide\n- **[API_TESTING.md](API_TESTING.md)** - API testing guide with examples\n- **[ENVELOPE_ENCRYPTION_ARCHITECTURE.md](docs/archive/ENVELOPE_ENCRYPTION.md)** - Encryption architecture details\n\n### NATS JetStream Integration (F#/.NET/Python/Go Consumers)\n- **[NATS_COMMANDS.md](NATS_COMMANDS.md)** - NATS CLI commands and durable consumer setup\n- **[DOTNET_CONSUMER_SETUP.md](DOTNET_CONSUMER_SETUP.md)** - Complete .NET/F# consumer guide with code examples\n- **[NATS_INTEGRATION.md](docs/NATS_INTEGRATION.md)** - NATS integration architecture\n\n### Additional Documentation\n- **[docs/archive/](docs/archive/)** - Historical documentation\n\n## Development\n\n### Hot Reload\nBoth backend and frontend support hot reload in dev mode:\n- **Backend**: Automatic recompilation on Java changes\n- **Frontend**: Automatic rebuild on TypeScript/HTML/CSS changes\n\n### Project Packages\n\n**Backend Packages:**\n- `me.cresterida` - REST resources\n- `me.cresterida.dto` - Data Transfer Objects\n- `me.cresterida.model` - Domain models\n- `me.cresterida.service` - Business logic (encryption)\n- `me.cresterida.util` - Utilities (S3 storage)\n\n**Frontend Structure:**\n- `passphrase/` - Authentication component\n- `mp3-upload/` - File upload component\n- `auth.guard.ts` - Route protection\n- `encryption.service.ts` - Client-side encryption\n\n### Build for Production\n\n```bash\n# Build JVM-based JAR\n./mvnw package\n\n# Build native executable (requires GraalVM)\n./mvnw package -Dnative\n\n# Build container\ndocker build -f src/main/docker/Dockerfile.jvm -t quarks-tigris .\n```\n\n\n### S3 Connection Issues\nCheck your endpoint configuration in `application.properties`:\n```properties\nquarkus.s3.endpoint-override=${S3_ENDPOINT_URL}\nquarkus.s3.path-style-access=true\n```\n\n### Frontend Build Errors\n```bash\ncd src/main/webui\nnpm install\nnpm run build\n```\n\n## Technology Stack\n\n- **Backend**: Quarkus 3.30.7, Java 21\n- **Frontend**: Angular 19, TypeScript\n- **Storage**: S3-compatible (Tigris, AWS S3, LocalStack)\n- **Messaging**: NATS JetStream (message streaming \u0026 pub/sub)\n- **Encryption**: AES-256-GCM, PBKDF2\n- **API Docs**: OpenAPI/Swagger\n- **Build**: Maven, npm\n\n## License\n\nApache 2.0\n\n---\n\n**Built with ❤️ using Quarkus and Angular**\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiquetal%2Fquarks-tigris","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkiquetal%2Fquarks-tigris","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiquetal%2Fquarks-tigris/lists"}