# Nextcloud File Upload Diagnostics

When files appear visible in the Nextcloud web UI but `find` on the container filesystem returns nothing, use this diagnostic sequence.

## Step 1: Check physical filesystem
```bash
docker exec <container> find '<nc_data_path>/<dir>' -type f -exec ls -la {} \;
```
Look for `.part` and `.ocTransferId*` files — these are incomplete upload fragments.

## Step 2: Rescan
```bash
docker exec -u www-data <container> php occ files:scan admin --path='<path>'
```

## Step 3: Check Nextcloud logs
```bash
docker exec <container> tail -20 /var/www/html/data/nextcloud.log | python3 -c "
import sys, json
for line in sys.stdin:
    try:
        d = json.loads(line.strip())
        if d.get('level', 0) >= 2:
            print(f'[{d.get(\"time\",\"?\")}] {d.get(\"message\",\"\")[:300]}')
    except: pass
"
```
Upload failures show: "预期文件大小为 X字节，实际...写入...Y字节"

## Step 4: Query MariaDB directly
Find the DB password first:
```bash
docker exec <container> grep dbpassword /var/www/html/config/config.php
```

Then query (use `mariadb` client, not `mysql`):
```bash
docker exec nextcloud-db-1 mariadb -u nextcloud -p<DB_PASSWORD_FROM_CONFIG> nextcloud -e "
SELECT f.fileid, f.path, f.name, f.size, FROM_UNIXTIME(f.mtime) as modified
FROM oc_filecache f 
WHERE f.path LIKE '%<search_term>%'
ORDER BY f.path;
"
```

To find children of a directory (by parent fileid):
```bash
... -e "SELECT f.fileid, f.parent, f.path, f.name, f.size
FROM oc_filecache f WHERE f.parent IN (<parent_id1>, <parent_id2>);"
```

## Step 5: Clean up fragments
```bash
docker exec <container> find '<path>' -name '*.part' -delete
docker exec <container> find '<path>' -name '*.ocTransferId*' -delete
```

## Common root cause
Cloudflare Tunnel (free tier) truncates large file uploads. The Nextcloud chunked upload protocol partially writes, then the connection drops. Repeated retries produce the same result.

**Solution**: Receive files via alternate channel (WeChat private message → `~/.hermes/cache/documents/`) and `docker cp` into Nextcloud.

## Quirk: docker cp'd file present + md5 correct, but `files:scan` returns 0 and DB row missing (2026-06-17)

After `docker cp` + `chown www-data` a new xlsx, `php occ files:scan admin --path='小Maggie协作区/.../世茂'` returned all-zeros (`Folders 0 Files 0`) and `oc_filecache` had **no row** for the file — so it was invisible in the web UI despite physically existing with a correct md5.

**Root cause**: `files:scan` keys off directory mtime; a fresh `docker cp` into an existing dir doesn't always bump the parent mtime, so the scanner skips it.

**Fix** (verified):
```bash
# 1. touch the parent dir to force an mtime change
docker exec <container> bash -c "touch '/var/www/html/data/admin/files/<REL_PATH>'"
# 2. rescan using the admin/files/ prefixed --path form (not the bare share path)
docker exec -u www-data <container> php occ files:scan --path="admin/files/<REL_PATH>"
```
This returns `Updated N` and registers the file. **Always verify after upload** by querying `oc_filecache` for the filename (Step 4) — md5 match alone does NOT prove the file is indexed/visible. Don't tell the user "uploaded" until the DB row exists.
