# TaskFlow — Deployment Guide (IIS & Ubuntu, with SSL)

This guide covers hosting the **TaskManagement.Api** app (ASP.NET Core **.NET 9**, Blazor Server +
REST API, MySQL) on:

1. **Windows / IIS** with HTTPS
2. **Ubuntu** with **nginx** reverse proxy + **systemd** + **Let's Encrypt** SSL

> The app serves both the Blazor web UI and the `/api/*` endpoints consumed by the Android & iOS
> apps. Mobile clients use PUT/DELETE and Bearer tokens — both deployments must allow those.

---

## 0. Prerequisites (both platforms)

- **.NET 9 SDK** on your build machine (to publish) and the **ASP.NET Core 9 Runtime** on the server.
- A reachable **MySQL** server (the app auto-applies EF migrations on startup).
- A **domain name** pointing at the server's public IP (needed for SSL), e.g. `taskflow.example.com`.

### Required configuration

The app reads these (via `appsettings.json` or environment variables). **Never commit real secrets.**

| Setting | Purpose |
|---|---|
| `ConnectionStrings:TaskManagementDatabase` | MySQL connection string |
| `Jwt:Secret` | ≥ 32-char secret for signing mobile JWTs |
| `Jwt:Issuer` / `Jwt:Audience` | JWT issuer/audience (default `TaskManagement`) |

Example `appsettings.Production.json`:

```json
{
  "ConnectionStrings": {
    "TaskManagementDatabase": "server=localhost;port=3306;database=taskmanagementdb;user=tmuser;password=CHANGE_ME;"
  },
  "Jwt": {
    "Secret": "CHANGE_ME_TO_A_LONG_RANDOM_32PLUS_CHAR_STRING",
    "Issuer": "TaskManagement",
    "Audience": "TaskManagement"
  }
}
```

### Publish the app (run on your build machine)

```bash
cd Web/src/TaskManagement.Api
dotnet publish -c Release -o ./publish
```

The `./publish` folder is what you copy to the server. It already contains the project `web.config`
(with the **WebDAV module removed** so mobile PUT/DELETE reach the API).

---

## 1. Windows / IIS + SSL

### 1.1 Install the hosting bundle

On the Windows server install the **.NET 9 Hosting Bundle** (ASP.NET Core Module v2 + runtime):
<https://dotnet.microsoft.com/download/dotnet/9.0> → "Hosting Bundle". Then:

```powershell
net stop was /y
net start w3svc
```

### 1.2 Create the site

1. Copy the `publish` folder to e.g. `C:\inetpub\taskflow`.
2. In **IIS Manager** → **Application Pools** → add pool `TaskFlowPool`, **.NET CLR version = No Managed Code**.
3. **Sites** → **Add Website**:
   - Site name: `TaskFlow`
   - Physical path: `C:\inetpub\taskflow`
   - Application pool: `TaskFlowPool`
   - Binding: https, host name `taskflow.example.com`
4. Give the app pool identity read access to the folder, and write access to
   `App_Data` (releases/attachments) and `logs`.

### 1.3 web.config / WebDAV (already handled)

The published `web.config` removes the WebDAV module so **PUT** and **DELETE** verbs reach the app
(required for mobile comment edit/delete). Confirm it contains:

```xml
<modules runAllManagedModulesForAllRequests="false">
  <remove name="WebDAVModule" />
</modules>
<handlers>
  <remove name="WebDAV" />
  <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
```

### 1.4 SSL certificate

**Option A — Let's Encrypt (free, auto-renew):** install **win-acme** (<https://www.win-acme.com/>):

```powershell
.\wacs.exe
# choose: N (new cert) → pick the IIS site → it installs + binds the cert and schedules renewal
```

**Option B — Commercial / existing PFX:**
1. IIS Manager → server node → **Server Certificates** → **Import** your `.pfx`.
2. Site → **Bindings** → edit the **https** binding → select the certificate.

Force HTTP→HTTPS: the app already calls `UseHttpsRedirection()` + HSTS in production, so an http
binding will redirect. (Optionally add the IIS **URL Rewrite** module for an edge redirect.)

### 1.5 Environment / secrets on IIS

Put production secrets in `appsettings.Production.json` next to the DLL, and set the environment in
`web.config` (inside `<aspNetCore>`):

```xml
<environmentVariables>
  <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>
```

### 1.6 Verify

- Browse `https://taskflow.example.com` → the web UI loads over HTTPS.
- `https://taskflow.example.com/api/cards` returns 401 (expected without a token) — confirms the API + TLS work.

---

## 2. Ubuntu + nginx + systemd + Let's Encrypt SSL

### 2.1 Install the runtime

```bash
# Microsoft package feed
wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y aspnetcore-runtime-9.0
```

### 2.2 Deploy the files

```bash
sudo mkdir -p /var/www/taskflow
# copy your published output here (scp/rsync from the build machine):
#   rsync -av ./publish/ user@server:/var/www/taskflow/
sudo chown -R www-data:www-data /var/www/taskflow
```

Put production secrets in `/var/www/taskflow/appsettings.Production.json` (chmod 600, owned by www-data).

### 2.3 Run as a systemd service (Kestrel on localhost:5000)

Create `/etc/systemd/system/taskflow.service`:

```ini
[Unit]
Description=TaskFlow ASP.NET Core app
After=network.target

[Service]
WorkingDirectory=/var/www/taskflow
ExecStart=/usr/bin/dotnet /var/www/taskflow/TaskManagement.Api.dll
Restart=always
RestartSec=10
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
# Bind Kestrel to localhost only; nginx terminates TLS in front of it.
Environment=ASPNETCORE_URLS=http://127.0.0.1:5000
# So forwarded-proto/host from nginx is honoured (the app already wires UseForwardedHeaders).
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
```

```bash
sudo systemctl daemon-reload
sudo systemctl enable --now taskflow
sudo systemctl status taskflow      # confirm it's active
```

### 2.4 nginx reverse proxy

```bash
sudo apt-get install -y nginx
```

Create `/etc/nginx/sites-available/taskflow`:

```nginx
server {
    listen 80;
    server_name taskflow.example.com;

    # Increase if you upload large release files / attachments.
    client_max_body_size 50m;

    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;

        # WebSocket / Blazor Server SignalR circuit support
        proxy_set_header   Upgrade           $http_upgrade;
        proxy_set_header   Connection        $connection_upgrade;

        # Pass real host/scheme so the app builds correct URLs + secure cookies
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   X-Forwarded-Host  $host;

        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 100s;
    }
}
```

Add the WebSocket upgrade map (once) in `/etc/nginx/nginx.conf` inside the `http { }` block:

```nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
```

Enable and reload:

```bash
sudo ln -s /etc/nginx/sites-available/taskflow /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```

> No WebDAV concerns on nginx — PUT/DELETE pass through to Kestrel by default, so mobile
> comment edit/delete work without extra config.

### 2.5 SSL with Let's Encrypt (Certbot)

```bash
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d taskflow.example.com
# Certbot edits the nginx config to add the 443 server block + a 80→443 redirect,
# installs the cert, and sets up auto-renewal.
```

Verify auto-renew:

```bash
sudo certbot renew --dry-run
```

### 2.6 Firewall

```bash
sudo ufw allow 'Nginx Full'   # opens 80 + 443
sudo ufw allow OpenSSH
sudo ufw enable
```

### 2.7 Verify

- `https://taskflow.example.com` loads the web UI with a valid certificate.
- `curl -i https://taskflow.example.com/api/cards` → `401` (expected) confirms API + TLS.
- Test a mobile **PUT** (edit a comment) — should succeed (no 405).

### Updating later

```bash
# build machine
dotnet publish -c Release -o ./publish
rsync -av ./publish/ user@server:/var/www/taskflow/
# server
sudo systemctl restart taskflow
```

---

## 3. Post-deploy checklist (both platforms)

- [ ] HTTPS works with a valid cert; HTTP redirects to HTTPS.
- [ ] MySQL reachable; app started without migration errors (check logs / `journalctl -u taskflow`).
- [ ] `Jwt:Secret` set to a strong value (≥ 32 chars) and **not** the dev default.
- [ ] License public key file (`taskflow.public.pem`) present if licensing is enforced.
- [ ] Mobile app pointed at `https://taskflow.example.com`; login, comments (incl. **edit/delete**),
      archive, projects, and performance all work.
- [ ] `App_Data` (attachments/releases) is writable and included in your backups along with the DB.
```
