# SkillVibe — Freelance Marketplace MVP

Plain PHP 8 + MySQL + PayPal (Orders v2 + Payouts). No framework, no Composer.

## Flow
1. Client posts project → freelancers bid → client accepts a bid (milestone created)
2. Client pays milestone via PayPal → platform holds funds (append-only `ledger` table)
3. Freelancer delivers → client approves → freelancer balance credited (minus 15% commission)
4. Freelancer requests withdrawal → cron sends PayPal Payout batch

## Deploy on your server (210.99.174.227)

```bash
# 1. Folder (same www-data group setup as your other sites)
sudo mkdir -p /var/www/html/svb
sudo chown administrator:www-data /var/www/html/svb
sudo chmod 2775 /var/www/html/svb
# upload files here via Cyberduck, keeping the folder structure

# 2. Database
sudo mysql
  CREATE DATABASE freelance CHARACTER SET utf8mb4;
  CREATE USER 'freelance_user'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD';
  GRANT ALL ON freelance.* TO 'freelance_user'@'localhost';
  exit
mysql -u freelance_user -p freelance < /var/www/html/svb/schema.sql

# 3. Edit config.php  (DB password, BASE_URL, PayPal sandbox keys)

# 4. Apache vhost — DocumentRoot must point at public/, NOT the flc root
#    (config.php / lib / cron stay outside the web root)
sudo nano /etc/apache2/sites-available/svb.conf
```

```apache
<VirtualHost *:80>
    ServerName skillvibe.yourdomain.com
    DocumentRoot /var/www/html/svb/public
    <Directory /var/www/html/svb/public>
        AllowOverride All
        Require all granted
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/svb_error.log
</VirtualHost>
```

```bash
sudo a2ensite svb && sudo systemctl reload apache2
sudo certbot --apache -d skillvibe.yourdomain.com     # SSL, same as your other vhosts

# 5. Payout cron (every 30 min)
crontab -e
  */30 * * * * php /var/www/html/svb/cron/payouts.php >> /var/log/svb_payouts.log 2>&1
sudo touch /var/log/svb_payouts.log && sudo chown administrator /var/log/svb_payouts.log
```

## PayPal setup
1. https://developer.paypal.com → My Apps → Create App → copy sandbox Client ID + Secret into config.php
2. Same page → Add Webhook → URL: `https://skillvibe.yourdomain.com/paypal_webhook.php`
   → events: `PAYMENT.CAPTURE.COMPLETED`, `PAYMENT.CAPTURE.REFUNDED` → copy Webhook ID into config.php
3. Test with sandbox buyer account (Sandbox → Accounts). Payouts in sandbox need
   the Payouts feature enabled on your app (checkbox in app settings).
4. Go live: switch `PAYPAL_ENV` to `'live'`, create a live app with your real
   PayPal Business account, create the live webhook, replace keys.

## Before real money
- Replace terms.php / refunds.php placeholder text (PayPal reviews these)
- Set MIN_WITHDRAWAL_CENTS / COMMISSION_PCT to taste in config.php
- Confirm the reseller-vs-escrow legal framing with a Korean lawyer (전자금융업 question)
- Consider delaying withdrawal availability D+7 after approval as chargeback buffer

## Money rules baked in
- All amounts are integer USD cents — never floats
- `ledger` is append-only: balances are SUM(amount_cents), never stored columns
- Capture is processed by BOTH the return URL and the webhook, guarded by
  `SELECT ... FOR UPDATE` + status check, so double-processing is impossible
- Failed payouts automatically refund the user's balance
