Introduction
Welcome to ProposalTrack — thank you for your purchase!
ProposalTrack is a modern, self-hosted web application for sharing business proposals, quotes, and documents with clients and tracking exactly how they're viewed in real time. Upload a PDF or Word document, generate a private share link, and instantly see when it was opened, how long it was read, where the visitor is located, and what device and browser they used.
Built on Laravel 11 and PHP 8.2+, the script is lightweight, easy to install on any standard LAMP/LEMP stack (including cPanel shared hosting), and ships with a powerful admin dashboard, complete email workflow, and a clean responsive front-end.
Features Overview
Everything you need to share, track, and manage proposals — in one self-hosted package.
Core Features
↑ Drag-and-Drop Upload
Upload PDF, DOC, or DOCX files with a simple, mobile-friendly form. No account needed.
↗ Private Share Links
Each proposal gets a secure, randomly-generated share token — no sequential IDs, no scraping.
⏱ Real-Time View Tracking
Every open is logged with timestamp, IP, country, city, device, browser, OS, and exact view duration.
★ Visitor Analytics
See unique visitors, total views, average time on document, and per-view breakdowns.
✉ Client Replies
Viewers can reply directly from the proposal page — name, email and message, no signup required.
⚙ Self-Manage Dashboard
Uploaders get a private manage link to toggle, edit, replace files, and download analytics.
⌕ Find My Proposals
OTP-verified email recovery — users retrieve all their past uploads with a one-time code.
$ Ad Slots
Configurable pre- and post-document ad placements with timed delay — monetize your traffic.
Admin Features
- Beautiful, responsive admin dashboard with charts and KPIs
- Total proposals, views, replies, unique visitors with week-over-week trends
- Top-performing proposals leaderboard
- Active / inactive toggle per proposal — disable any link instantly
- Storage usage monitor
- Full SMTP email configuration (with test email button)
- Site branding: logo, favicon, colors, meta tags, contact email
- Custom HTML injection (head, body, footer) — perfect for analytics, chat widgets, pixels
- Built-in editor for Privacy Policy and Terms of Service pages
- Admin password and profile management
- One-time installer wizard (auto-locks after install)
Technical Highlights
- Laravel 11.31 — modern, secure, well-maintained framework
- Tailwind CSS 3.4 + Vite 6 — fast, beautiful, customizable UI
- MySQL, MariaDB, PostgreSQL, or SQLite supported
- Rate limiting on uploads, OTP requests, and OTP verification
- CSRF, CSP headers, XSS sanitization, MIME validation
- Private file storage — files never directly accessible by URL
- cPanel-friendly: pre-configured root
index.php+.htaccess - IP geolocation via free
ip-api.comservice (cached 30 days) - Built-in user-agent parser (no external dependency)
Server Requirements
ProposalTrack runs on any standard PHP hosting environment, including most shared hosts.
| Component | Minimum | Recommended |
|---|---|---|
| PHP | 8.2 | 8.3+ |
| Database | MySQL 5.7 / MariaDB 10.3 / PostgreSQL 10 / SQLite | MySQL 8.0 or MariaDB 10.6+ |
| Web Server | Apache (mod_rewrite) or Nginx | Apache 2.4 / Nginx 1.20+ |
| Memory | 128 MB PHP memory_limit | 256 MB+ |
| Storage | 200 MB free + space for uploads | 1 GB+ depending on usage |
| SSL | Optional (recommended) | HTTPS via Let's Encrypt |
Required PHP Extensions
Most hosts have these enabled by default. The web installer will check them for you.
pdo_mysql(orpdo_pgsql/pdo_sqlite)opensslmbstringtokenizerxml&ctypejsonbcmathfileinfo
Web Installer (Recommended)
The fastest way to get ProposalTrack running. Works on most shared hosts and VPS environments.
-
Upload the files
Extract the ZIP archive and upload the contents of the
proposaltrack/folder to your web root (e.g.public_html,www, or your domain's document root). - Create a database In your hosting control panel (cPanel, Plesk, etc.), create a new MySQL/MariaDB database and a user with full privileges on it. Note down the database name, username, and password.
-
Set folder permissions
Make sure these folders are writable by the web server (chmod 755 or 775):
storage/ storage/app/ storage/framework/ storage/logs/ bootstrap/cache/ -
Open the installer
Visit your domain in the browser — e.g.
https://yourdomain.com/. You'll be redirected automatically to the installer at/install. - Step 1 — Requirements check The installer verifies PHP version, extensions, and folder permissions. Fix any red items before continuing.
-
Step 2 — Database
Enter your database host (usually
localhost), database name, username, and password. The installer will test the connection and run all migrations automatically. - Step 3 — Admin account Set the email, name, and password for your admin user. You'll use these to log in to the admin panel.
- Step 4 — Site settings Enter the site name and contact email. You can change these later.
-
Step 5 — Done!
The installer locks itself automatically. You can now log in at
/admin/login.
/install route returns a 404 automatically. There is no need to
delete the installer files manually.
Manual Installation
For advanced users with SSH/CLI access who prefer command-line setup.
-
Upload & extract
Upload the archive to your server and extract it.
unzip proposaltrack.zip cd proposaltrack -
Copy environment file
cp .env.example .env php artisan key:generate -
Edit
.envSet your database credentials and app URL:APP_NAME=ProposalTrack APP_URL=https://yourdomain.com DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=proposaltrack DB_USERNAME=your_db_user DB_PASSWORD=your_db_pass -
Run migrations
php artisan migrate --force php artisan storage:link -
Create the admin user
php artisan tinker >>> \App\Models\AdminUser::create([ 'email' => 'admin@example.com', 'name' => 'Administrator', 'password' => bcrypt('YourStrongPassword'), ]); >>> exit -
Mark installer as complete
php artisan tinker >>> \App\Models\Setting::set('installed', '1'); >>> exit -
(Optional) Cache config for production
php artisan config:cache php artisan route:cache php artisan view:cache
cPanel / Shared Hosting Notes
ProposalTrack is pre-configured to work seamlessly on cPanel-based hosting.
Unlike a standard Laravel app where you need to point your domain to the public/ folder,
ProposalTrack ships with a root-level index.php and .htaccess that
transparently delegate requests into the public folder. This means you can:
- Upload everything directly to
public_html(or a subdomain folder) - Skip any document-root configuration
- Run the web installer immediately by visiting your domain
PHP Version
In cPanel, find Select PHP Version (or MultiPHP Manager) and ensure PHP 8.2 or higher is selected for the domain. Then enable the required extensions listed in Server Requirements.
File Permissions
Use the cPanel File Manager or an FTP client to set:
- All directories:
755 - All files:
644 - Make sure
storage/andbootstrap/cache/are writable.
After Installation
A short checklist to make sure your installation is production-ready.
- Log in to
/admin/loginusing the admin credentials you set during installation. - Visit Settings → Email and configure your SMTP server (see Email Setup).
- Send a test email to confirm SMTP is working.
- Upload your logo and favicon under Settings → Branding.
- Edit your Privacy Policy and Terms of Service from the Legal Pages section.
- Set
APP_DEBUG=falsein your.envfile before going live. - Set up the cron entry for OTP cleanup (see Cron / Scheduler).
- Install an SSL certificate (Let's Encrypt is free and works fine).
Admin Login
The admin login page is available at:
https://yourdomain.com/admin/login
Enter the email and password you created during installation. After three failed attempts, login is rate-limited for one minute to prevent brute-force attacks.
php artisan tinker
>>> $u = \App\Models\AdminUser::first();
>>> $u->password = bcrypt('NewPassword123');
>>> $u->save();
Admin Dashboard
Your home base for monitoring proposal activity at a glance.
The dashboard shows:
- KPI cards — total proposals, total views, total replies, unique visitors
- Trend indicators — week-over-week change for each metric
- Active vs Inactive proposal counts
- Storage usage — total disk space used by uploaded files
- Recent uploads — the latest proposals submitted
- Top performers — most-viewed proposals leaderboard
- Charts — visualization of uploads and views over time
Manage Proposals
View, deactivate, and inspect every proposal uploaded to your platform.
Navigate to Admin → Proposals to see the full list.
Available actions
- View details — opens a detail page with full visitor analytics, all views and replies
- Toggle active/inactive — instantly disable or re-enable any share link
- Delete — permanently removes the proposal, its file, and all tracking data
- Filter & search — by title, uploader email, date, or status
On the proposal detail page you'll see a complete view log with timestamps, IP addresses, geolocation, device/browser, and time spent on each view. You can also see and manage client replies.
Settings
All site-wide configuration lives under Admin → Settings.
Settings are organized into clear tabs — each tab is documented in the Configuration section below.
Legal Pages
Edit and publish your Privacy Policy and Terms of Service.
Navigate to Admin → Legal Pages. Default templates are pre-loaded — customize them with your business name, jurisdiction, and any specific terms. Pages are published automatically at:
https://yourdomain.com/page/privacyhttps://yourdomain.com/page/terms
Links to these pages are automatically displayed in the site footer and on the upload form.
Email (SMTP) Configuration
ProposalTrack sends emails for share confirmations, client reply notifications, and OTP verification.
Navigate to Settings → Email and fill in:
| Field | Description | Example |
|---|---|---|
| SMTP Host | Your provider's SMTP server | smtp.gmail.com |
| SMTP Port | 587 (TLS) or 465 (SSL) | 587 |
| Encryption | tls / ssl / none | tls |
| Username | Your SMTP login | noreply@yourdomain.com |
| Password | Your SMTP password / app password | •••••••• |
| From Address | Sender email shown to recipients | noreply@yourdomain.com |
| From Name | Sender display name | ProposalTrack |
After saving, click Send Test Email to verify everything works. The test will be sent to your admin email address.
Site & Branding
Customize the look and meta information of your installation.
Under Settings → Site and Settings → Branding you can configure:
- Site name — shown in the header, emails, and meta titles
- Contact email — public-facing support email
- Logo — PNG/SVG/JPG, ideally 200×60px
- Favicon — ICO or PNG, 32×32px or 64×64px
- Meta title, description, keywords — for SEO
- Custom HTML — inject code into
<head>, after<body>, or in the footer
Custom HTML injection is great for adding chat widgets (Tawk.to, Crisp, Intercom), Facebook Pixel, Hotjar, or any other third-party script.
File Upload Settings
Control what users can upload and how large files can be.
Under Settings → Uploads:
- Maximum file size — in megabytes (default: 10 MB)
- Allowed file types — comma-separated list (default:
pdf,doc,docx)
php.ini values for upload_max_filesize,
post_max_size, and memory_limit are equal to or larger than the limit you set
in the admin panel. On Nginx, also check client_max_body_size.
Ads & Monetization
Built-in ad slots for Google AdSense, banner ads, or any custom HTML.
Under Settings → Ads, two ad slots are available on every public proposal page:
- Pre-document ad — shown before the proposal renders, with a configurable countdown delay
- Post-document ad — shown below the proposal after the user finishes reading
- Ad delay — the number of seconds to wait before showing the proposal (forces users to see the pre-ad)
Paste any valid HTML — AdSense unit, banner image, affiliate link, etc.
Google Analytics
Under Settings → Analytics, paste your Google Analytics Measurement ID
(e.g. G-XXXXXXXXXX). The tracking snippet is automatically injected on every public page.
For more advanced tracking (GTM, Plausible, Fathom, custom pixels), use the Custom HTML — head field instead.
Uploading a Proposal
No account required — anyone can upload from the homepage.
- Visit the homepage at
https://yourdomain.com/ - Drag & drop a PDF, DOC, or DOCX file (or click to browse)
- Enter a proposal title, optional description, and your email address
- Click Upload — the system stores the file and emails you the share & manage links
After upload, the user sees a confirmation page with the share link (to send to clients) and the manage link (to track activity later). Both links are also emailed to the uploader.
Managing Proposals
The manage link looks like:
https://yourdomain.com/manage/xyz789...
From the manage page, the uploader can:
- See all views, replies, and analytics
- Toggle the proposal active/inactive (disabling the share link)
- Edit the title and description
- Replace the uploaded file
- Delete the proposal entirely
- Delete individual replies
- Download the original file
Finding Lost Proposals
If a user loses their manage link, they can recover all their uploads via OTP.
- Visit
https://yourdomain.com/find-proposals - Enter the email address used during upload
- Receive a 6-digit OTP code by email
- Enter the code to retrieve a list of all proposals uploaded with that email
OTPs expire after 15 minutes. Rate limits prevent abuse: 3 send requests and 5 verification attempts per email per 15 minutes.
Security
ProposalTrack is built with security as a first-class concern.
- CSRF protection on all forms via Laravel's built-in middleware
- Rate limiting on uploads (10/IP/hour), OTP send (3/email/15min), OTP verify (5/email/15min), and admin login (3 attempts/min)
- Content Security Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy headers on all responses
- Input sanitization — all user input is stripped of HTML tags and validated
- MIME validation on uploads — file type checked from actual content, not just extension
- SQL injection protection via Eloquent ORM and parameterized queries
- Private file storage — uploaded files are stored outside the public web root and served only via token-protected routes
- Bcrypt password hashing for admin accounts
- Secure random tokens for share and manage links (64 chars, cryptographically random)
- Installer auto-locks after first run, preventing accidental re-installation
APP_DEBUG=false, install an SSL certificate, use a strong admin
password, and configure regular backups for your database and storage/ folder.
Cron / Scheduler
Optional but recommended for keeping the database tidy.
ProposalTrack ships a single scheduled command that cleans up expired OTP records once per day. To enable it, add the following entry to your server's crontab:
* * * * * cd /path/to/proposaltrack && php artisan schedule:run >> /dev/null 2>&1
On cPanel, add this entry under Cron Jobs → Add New Cron Job with the schedule set to "every minute".
You can also run the cleanup manually:
php artisan proposaltrack:cleanup
Troubleshooting
"500 Internal Server Error" after install
- Check that
storage/andbootstrap/cache/are writable (chmod 755 or 775) - Confirm PHP 8.2+ is selected for the domain
- Check the
.envfile exists and has a validAPP_KEY - Look at
storage/logs/laravel.logfor the actual error
"No application encryption key has been specified"
Run from CLI: php artisan key:generate — or copy the value from .env.example and re-run the installer.
404 on every page except homepage
Your web server is missing rewrite rules. On Apache, ensure mod_rewrite is enabled and the bundled .htaccess file is present. On Nginx, add the standard Laravel rewrite block:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
Email is not being sent
- Verify SMTP credentials in Settings → Email
- Click Send Test Email — the error message will tell you exactly what's wrong
- For Gmail, generate an App Password (regular password will not work with 2FA)
- Check your hosting provider hasn't blocked outbound SMTP ports (587/465)
File uploads fail silently
- Increase
upload_max_filesizeandpost_max_sizeinphp.ini - On Nginx, increase
client_max_body_size - Check the limit in Settings → Uploads matches or is below the PHP limit
- Ensure
storage/app/public/uploadsis writable
Geolocation shows "Unknown"
The script uses the free ip-api.com service. If your server is firewalled or rate-limited, results may be empty. Geolocation is purely cosmetic and does not affect functionality.
Forgot admin password
See the Admin Login section for a CLI reset using Tinker.
I want to re-run the installer
Connect to your database, open the settings table, and delete the row where key = 'installed'. The installer will be available again.
Changelog
Version 1.0.0 — Initial release
- Core upload, share, view, and tracking workflow
- Admin dashboard with analytics, charts, and KPI cards
- Admin proposal management (list, view, toggle, delete)
- SMTP-based email with test sending
- OTP-verified "Find My Proposals" recovery flow
- Configurable ads, branding, meta tags, and custom HTML injection
- Built-in editor for Privacy Policy and Terms of Service
- 5-step web installer wizard
- cPanel-friendly file structure
- Rate limiting, CSRF, CSP, and input sanitization throughout
- IP geolocation and user-agent parsing
Support & Credits
Need help? We're here for you.
Getting support
Please use the support channel on the Codester product page. Include the following information when you submit a ticket:
- Your Codester purchase ID
- PHP version (run
php -vor check cPanel) - Hosting environment (cPanel, Plesk, VPS, etc.)
- A clear description of the issue
- Any error messages from
storage/logs/laravel.log - Screenshots if relevant
Built with
- Laravel 11 — laravel.com
- Tailwind CSS 3.4 — tailwindcss.com
- Vite 6 — vitejs.dev
- ip-api.com — IP geolocation (free tier)