A music distribution platform connecting publishers, composers, and record labels. payment gateways, digital signatures, and handling 20GB WAV files. this project pushed me into areas I'd never worked with before.
The Project
PT Daya Arsana needed a platform where record labels could buy music licenses from publishers, sign contracts digitally, and upload/download large music files. three complex problems in one project.
What I Built
Payment Gateway Integration (NicePay)
- Integrated NicePay payment system for license purchases
- Record labels can buy licenses directly from publishers
- Payment status tracking and reconciliation
- Invoice generation and receipt management
Digital Signature Contracts (Privy)
- Integrated Privy for legally binding digital signatures
- Three-party contracts: publishers, composers, and record labels
- Contract lifecycle management (draft → sign → archive)
- Audit trail for all contract actions
Large File Upload System (MinIO)
- Google Drive-like file upload experience
- Chunked uploads with pause, resume, and cancel
- Support for WAV music files up to 20GB
- Progress tracking and retry logic
- MinIO for scalable object storage
Legacy Codebase Refactoring
- Refactored existing Laravel codebase using Domain-Driven Design
- Improved code organization and maintainability
- Applied DDD patterns: Value Objects, Aggregates, Repositories
- Better separation of concerns across domains
Technical Deep Dive
Chunked File Upload:
// chunked upload with pause/resume
async function uploadChunk(file: File, chunkIndex: number, totalChunks: number) {
const start = chunkIndex * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, file.size);
const chunk = file.slice(start, end);
const response = await fetch('/api/upload', {
method: 'POST',
headers: {
'X-Upload-Id': uploadId,
'X-Chunk-Index': chunkIndex.toString(),
'X-Total-Chunks': totalChunks.toString(),
},
body: chunk,
});
return response.json();
}
NicePay Integration:
// laravel payment service
class NicePayService {
public function createPayment(Order $order): PaymentResponse {
return $this->client->post('/api/v1/transaction', [
'order_id' => $order->id,
'amount' => $order->total,
'customer_details' => $order->customer,
]);
}
}
Privy Digital Signature:
// contract signing flow
class ContractService {
public function initiateSignature(Contract $contract): void {
$signers = $contract->getRequiredSigners();
foreach ($signers as $signer) {
$this->privy->createSignatureRequest(
document: $contract->document,
signer: $signer,
callback: route('webhooks.privy-signed')
);
}
}
}
Challenges
20GB file uploads This was the hardest technical challenge:
- Regular uploads would timeout or fail
- Needed chunked upload with resume capability
- MinIO configuration for large objects
- Progress tracking across unstable connections
- Memory management on both client and server
Payment + Legal compliance
- NicePay integration required careful error handling
- Privy digital signatures must be legally binding
- Three-party contract flow is complex
- Audit trail for every action
Legacy codebase
- Inherited code with no clear structure
- Applied DDD concepts incrementally
- Refactored without breaking existing functionality
- Improved DX for future developers
Features I'm Proud Of
- 20GB chunked uploads — pause, resume, cancel. works even on unstable connections
- Three-party digital contracts — publishers, composers, and labels all sign digitally
- Payment integration — seamless license purchasing flow
- DDD refactoring — turned a messy codebase into something maintainable
Tech Decisions
Why MinIO?
- S3-compatible API
- Self-hosted option
- Handles large objects well
- Great for music files
Why NicePay?
- Popular payment gateway in Indonesia
- Good API documentation
- Supports multiple payment methods
- Reliable transaction handling
Why Privy?
- Legally recognized digital signatures in Indonesia
- Good API for contract workflows
- Audit trail built-in
- Multi-party signing support
Results
- ✅ Payment gateway integrated and processing transactions
- ✅ Digital signature contracts working for all three parties
- ✅ 20GB file uploads with pause/resume/cancel
- ✅ Legacy codebase refactored with DDD principles
- ✅ Improved developer experience for future development
Lessons Learned
- Large file handling requires a completely different approach than regular uploads
- Payment integrations need careful error handling and idempotency
- Digital signatures add legal complexity — understand the requirements first
- DDD is powerful but requires buy-in from the whole team
- Refactoring legacy code is like surgery — go slow, test everything
some projects teach you new technologies. this one taught me about payments, legal compliance, and handling files at scale.
Related Articles
Kalla Property Management - Full-Stack Real Estate System
Built a comprehensive property management system for Kalla Group's real estate portfolio.
DPR RI Open Data - Making Parliament Data Accessible
Built the open data portal for Indonesian Parliament - high traffic, strict requirements, real impact.
HRIS System - Web & Mobile Application
Built an HRIS system from scratch with a scalable design system and React Native mobile app.