# Renew360 — by My Cloud

Subscription renewal management system for [My Cloud](https://mycloud.mu). Tracks B2B software subscriptions, calculates annual renewal dates, and automatically sends tiered email + SMS reminders at 60, 30, and 3 days before each subscription's anniversary.

---

## Stack

| Layer | Tech |
|---|---|
| Backend | Laravel 11 |
| Admin Panel | Backpack for Laravel Pro + Tabler theme |
| Email | ZeptoMail API (Zoho) |
| SMS | Custom SMS Gateway |
| Queue | Database queue (`php artisan queue:work`) |
| Database | SQLite / MySQL |

---

## Setup

```bash
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
php artisan queue:work
```

Set the required variables in `.env`:

```
APP_NAME=Renew360
CRON_SECRET=your-random-secret

ZEPTOMAIL_API_KEY=
EMAIL_FROM=notifications@mycloud.mu

SMS_API_URL=
SMS_API_KEY=
```

---

## Cron Job

The daily reminder run is triggered via HTTP. Configure your server/cPanel to call this URL once per day:

```
GET https://renew360.mycloud.mu/cron-jobs?token=YOUR_CRON_SECRET
```

Reminders are sent at **60 days**, **30 days**, and **3 days** before each subscription's anniversary. The job is idempotent — re-running it on the same day will not send duplicates.

---

## Queue Worker (Supervisor)

Use `supervisor.conf` at the project root as a starting point. Update the `command` path, then:

```bash
sudo cp supervisor.conf /etc/supervisor/conf.d/renew360-worker.conf
sudo supervisorctl reread && sudo supervisorctl update
sudo supervisorctl start renew360-worker:*
```

---

## Admin Panel

`/admin` — Backpack CRUD for Subscriptions, Products, and Users.

Default login created by the seeder: `admin@mycloud.mu`

## Changelog

### 2026-06-02
- Added PDF attachment support to subscriptions (upload field, auth-gated download route — no public symlink required)
- Active status column in subscription list now renders as a green/grey chip
- Fixed activity log: removed incorrect manual route (package auto-registers it), corrected controller namespace (`app\` was spuriously included), added `LogsActivity` + `getActivitylogOptions()` to Subscription, Product, and User models; password excluded from User log
- Added `ModelActivityOperation` and `EntryActivityOperation` to all three CRUD controllers

### 2026-06-01
- Added `php artisan storage:link` requirement for attachment serving

### 2026-05-31
- Branding applied: Renew360 logo in admin panel and login page; customer-facing emails remain My Cloud branded
- Email templates redesigned with styled HTML (colour-coded urgency banners per reminder interval)
- App renamed to Renew360 (internal); customer-facing sender name and domain remain My Cloud

### 2026-05-30
- Security: `/cron-jobs` route now requires `?token=CRON_SECRET`
- Reliability: cron skips subscriptions already reminded today (idempotency); only active subscriptions processed
- Subscription list: active status column, active/product/month filters, soft delete support
- Product list: subscription count column; delete blocked if linked subscriptions exist
- User CRUD: password hashed correctly on create; blank password on update preserves existing hash; self-deletion blocked; sensitive fields hidden from list
- Activity log: route registered, models instrumented
- Supervisor config added for queue worker management