A modern, full-featured file upload system built with SvelteKit, TypeScript, and PostgreSQL. This application provides a user-friendly interface for uploading, organizing, and managing various types of content files with advanced filtering, archiving, and tracking capabilities.
- File Upload with Modal Interface: Clean, intuitive popup for uploading files
- Comprehensive Metadata Collection:
- Title (max 200 characters)
- Description (max 1000 characters)
- Category selection (Leadership, Managing Complexity, etc.)
- Language selection (English, Italian, Spanish, etc.)
- Provider selection (Skilla, LinkedIn, Pack, etc.)
- Multi-select roles (Mentor/Coach, Mentee/Coachee, etc.)
- File Support: PDF, TXT, Video files, PowerPoint, Excel, Word documents
- Smart Content Filtering:
- Filter by content type (All, Videos, Documents, Lessons)
- MIME type-based intelligent categorization
- Archive Management:
- Archive/unarchive items with dedicated archive view
- Clean separation between active and archived content
- Interactive Table with Enhanced Features:
- Sortable Columns: Click any column header to sort (Title, Path, View Count, Provider, Type, Date)
- View Count Tracking: Automatic increment when items are downloaded
- Actions Menu: Right-click style menu for archive operations
- One-Click Download: Click any table row to download and track views
- Modern Tab Interface: Navigate between different content types and archive
- Icon System: Consistent, scalable icon library throughout the application
- Responsive Design: Works beautifully on desktop and mobile devices
- Frontend: SvelteKit with TypeScript
- Backend: SvelteKit API routes
- Database: PostgreSQL with Drizzle ORM
- Containerization: Docker & Docker Compose
- Styling: Custom CSS with modern design principles
- Icons: Centralized icon component system
Before you begin, ensure you have the following installed:
The project is designed to be set up with just 1-2 commands:
# Clone the repository (if not already done)
git clone <repository-url>
cd pack-assignment
# Run the automated setup command
npm run setupThis single command will:
- Install all dependencies
- Start the PostgreSQL database with Docker
- Run database migrations
- Set up the upload directory
If you prefer to run each step manually:
# 1. Install dependencies
npm install
# 2. Copy environment file and configure if needed
cp .env.example .env
# 3. Start the database
npm run docker:up
# 4. Wait a few seconds for the database to be ready, then run migrations
npm run db:migrate
# 5. Start the development server
npm run devThe application uses the following environment variables (already configured in .env.example):
DATABASE_URL=postgresql://packuser:packpass@localhost:5432/packdb
UPLOAD_DIR=uploads
MAX_FILE_SIZE=10485760DATABASE_URL: PostgreSQL connection stringUPLOAD_DIR: Directory where uploaded files are storedMAX_FILE_SIZE: Maximum file size in bytes (default: 10MB)
After setup, start the development server:
npm run devThe application will be available at http://localhost:5173
The top navigation bar provides several ways to view your content:
- All: Shows all non-archived content
- Videos: Filters to show only video files (mp4, avi, mov, etc.)
- Documents: Filters to show documents (PDF, Word, Text, etc.)
- Lessons: Filters to show presentation files (PowerPoint, slides, etc.)
- Archive: Shows all archived items (separate from active content)
- Click the "Upload" button (available in all tabs except Archive)
- Fill in all required fields:
- Title: Descriptive title (max 200 chars)
- Description: Detailed description (max 1000 chars)
- Category: Select from predefined categories
- Language: Choose the content language
- Provider: Select content provider
- Roles: Multi-select relevant roles using the dropdown
- File: Click "Select file" to choose your file
- Click "Upload" to save
- Sorting: Click any column header to sort by that field
- Click again to reverse sort order
- Visual indicators show current sort column and direction
- View Tracking: Each click on a row increments the view count
- Download: Click any row to download the file and track the view
- Click the three dots (โฎ) in the Actions column for each item
- Select "Archive" to move items to the archive
- Switch to the Archive tab to view archived items
- Click "Unarchive" to restore items to active content
The application uses a single uploads table with the following structure:
CREATE TABLE uploads (
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
description TEXT NOT NULL,
category VARCHAR(100) NOT NULL,
language VARCHAR(10) NOT NULL,
provider VARCHAR(100) NOT NULL,
roles JSON NOT NULL,
file_name VARCHAR(255) NOT NULL,
original_name VARCHAR(255) NOT NULL,
mime_type VARCHAR(100) NOT NULL,
file_size INTEGER NOT NULL,
file_path VARCHAR(500) NOT NULL,
view_count INTEGER DEFAULT 0 NOT NULL,
archived BOOLEAN DEFAULT false NOT NULL,
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP DEFAULT NOW() NOT NULL
);view_count: Tracks how many times an item has been downloadedarchived: Boolean flag for archive statusmime_type: Used for intelligent content type filtering
npm run dev # Start development server
npm run lint # Run ESLint
npm run format # Format code with Prettier
# Database scripts
npm run db:generate # Generate database migrations
npm run db:migrate # Run database migrations
# Docker scripts
npm run docker:up # Start PostgreSQL with Docker
npm run docker:down # Stop Docker containers
# Quick setup
npm run setup # Complete setup in one commandpack-assignment/
โโโ src/
โ โโโ lib/
โ โ โโโ components/ # Svelte components
โ โ โ โโโ FileUploadModal.svelte
โ โ โ โโโ UploadsTable.svelte
โ โ โ โโโ Icon.svelte # Centralized icon system
โ โ โโโ db/ # Database configuration
โ โ โ โโโ index.ts
โ โ โ โโโ schema.ts
โ โ โ โโโ migrate.ts
โ โ โโโ constants.ts # Application constants
โ โ โโโ utils.ts # Utility functions
โ โโโ routes/
โ โ โโโ api/uploads/ # API endpoints
โ โ โ โโโ +server.ts # Upload & fetch with filtering
โ โ โ โโโ [id]/
โ โ โ โโโ download/+server.ts # File download
โ โ โ โโโ view/+server.ts # View count increment
โ โ โ โโโ archive/+server.ts # Archive operations
โ โ โโโ +layout.svelte # Main layout
โ โ โโโ +page.svelte # Home page with tabs
โ โโโ app.css # Global styles
โ โโโ app.d.ts # TypeScript declarations
โ โโโ app.html # HTML template
โโโ static/ # Static assets
โโโ uploads/ # Uploaded files (auto-created)
โโโ docker-compose.yml # PostgreSQL setup
โโโ drizzle.config.ts # Database configuration
โโโ package.json # Dependencies and scripts
GET /api/uploads- Fetch uploads with filtering support- Query params:
archived=true/false,filter=videos/documents/lessons
- Query params:
POST /api/uploads- Upload new file
GET /api/uploads/[id]/download- Download file and increment view countPOST /api/uploads/[id]/view- Increment view countPOST /api/uploads/[id]/archive- Archive/unarchive item
The application includes a centralized icon component (Icon.svelte) with:
- Consistent sizing and styling
- Support for various UI, status, and content icons
- Easy-to-use props:
name,size,class_
- Mobile-optimized table layout
- Collapsible navigation on smaller screens
- Touch-friendly interaction elements
- File Type Validation: Only allows specific file types
- File Size Limits: Configurable maximum file size (10MB default)
- Input Validation: Server-side validation for all form fields
- Unique Filenames: Prevents file conflicts with timestamp and random strings
- SQL Injection Protection: Uses parameterized queries with Drizzle ORM
- Archive Protection: Archived items are logically separated from active content
If you encounter database connection problems:
# Check if PostgreSQL container is running
docker ps
# Restart the database
npm run docker:down
npm run docker:up
# Wait a few seconds, then retry migrations
npm run db:migrateIf you need to reset the database:
# Stop the database
npm run docker:down
# Remove the volume (this will delete all data)
docker volume rm pack-assignment_postgres_data
# Restart and migrate
npm run docker:up
npm run db:migrateIf port 5173 (frontend) or 5432 (database) is already in use:
- Frontend: SvelteKit will automatically try the next available port
- Database: Modify the port in
docker-compose.ymland updateDATABASE_URL
If file uploads fail:
# Ensure upload directory exists and has proper permissions
mkdir -p uploads
chmod 755 uploadsHappy coding! ๐