Follow-ups from a mount-point audit of the SERVER /mnt/fusionio/spikersoft share vs our docker-stack files.
1. Blog media should be served by nginx, not the API
Blog media currently gets a /blog-pictures/{username}/{file} URL, which the SPA prefixes with https://api.spikersoft.com, so every image/video request goes through the API's static-files middleware. The Angular nginx container already bind-mounts the whole share at /usr/share/nginx/html/spikersoft, so the final blogs folder is directly servable at https://learn.spikersoft.com/spikersoft/blogs/... with zero API involvement.
Change:BlogMediaMoveConsumer now builds the public URL from a BlogMedia:PublicUrlPrefix config value. Production sets it to https://learn.spikersoft.com/spikersoft/blogs (absolute URL — the SPA passes absolute URLs through untouched). The default stays /blog-pictures so Development (no nginx in front) and existing posts with legacy relative URLs keep being served by the API's /blog-pictures static route, which remains in place.
2. Typo broke the UploadCoordinator's ebooks final directory in Production
SpikerSoft.EventHandlers.UploadCoordinator/appsettings.Production.json had "Ebooks": "yes/app/ebooks" — a relative path that would resolve against the container CWD instead of the /app/ebooks bind mount. Fixed to /app/ebooks.
3. Stale duplicate stack file removed
spikersoft-backend/deploy/docker-stack.yml was an out-of-date copy of spikersoft-infrastructure/spikersoft-backend/docker-stack.yml (missing the lesson-videos mount, among other drift). CI deploys from /mnt/infrastructure/spikersoft-backend, and nothing referenced the copy, so it's deleted.
Ops prerequisites (already done)
uploads/assets created on SERVER (was missing; the coordinator's WatchDirectories.Assets points at it).
Known remaining item (separate ticket-worthy)
The code bind mounts in file-movement/upload-coordinator point /app/code at host uploads/code, making the watch dir and final dir the same host directory (move-to-final is a no-op). The top-level /mnt/fusionio/spikersoft/code folder is mounted by nothing and looks like the intended final target.
nginx serves the entire share publicly, including quarantine/ and unscanned uploads/ — should be narrowed or deny-ruled.
Follow-ups from a mount-point audit of the SERVER `/mnt/fusionio/spikersoft` share vs our docker-stack files.
## 1. Blog media should be served by nginx, not the API
Blog media currently gets a `/blog-pictures/{username}/{file}` URL, which the SPA prefixes with `https://api.spikersoft.com`, so every image/video request goes through the API's static-files middleware. The Angular nginx container already bind-mounts the whole share at `/usr/share/nginx/html/spikersoft`, so the final blogs folder is directly servable at `https://learn.spikersoft.com/spikersoft/blogs/...` with zero API involvement.
**Change:** `BlogMediaMoveConsumer` now builds the public URL from a `BlogMedia:PublicUrlPrefix` config value. Production sets it to `https://learn.spikersoft.com/spikersoft/blogs` (absolute URL — the SPA passes absolute URLs through untouched). The default stays `/blog-pictures` so Development (no nginx in front) and existing posts with legacy relative URLs keep being served by the API's `/blog-pictures` static route, which remains in place.
## 2. Typo broke the UploadCoordinator's ebooks final directory in Production
`SpikerSoft.EventHandlers.UploadCoordinator/appsettings.Production.json` had `"Ebooks": "yes/app/ebooks"` — a relative path that would resolve against the container CWD instead of the `/app/ebooks` bind mount. Fixed to `/app/ebooks`.
## 3. Stale duplicate stack file removed
`spikersoft-backend/deploy/docker-stack.yml` was an out-of-date copy of `spikersoft-infrastructure/spikersoft-backend/docker-stack.yml` (missing the `lesson-videos` mount, among other drift). CI deploys from `/mnt/infrastructure/spikersoft-backend`, and nothing referenced the copy, so it's deleted.
## Ops prerequisites (already done)
- `uploads/assets` created on SERVER (was missing; the coordinator's `WatchDirectories.Assets` points at it).
## Known remaining item (separate ticket-worthy)
- The `code` bind mounts in file-movement/upload-coordinator point `/app/code` at host `uploads/code`, making the watch dir and final dir the same host directory (move-to-final is a no-op). The top-level `/mnt/fusionio/spikersoft/code` folder is mounted by nothing and looks like the intended final target.
- nginx serves the entire share publicly, including `quarantine/` and unscanned `uploads/` — should be narrowed or deny-ruled.
Resolved in spikersoft-backend PR #201 (merged): blog media served via nginx static path, UploadCoordinator ebooks final-directory typo fixed, stale duplicate stack file removed; plus spikersoft-infrastructure commit e28e968 (blog-media-processor joins the clamav overlay). The 'known remaining item' flagged in the ticket (code bind-mount target + nginx serving quarantine/ publicly) was called separate-ticket-worthy — file it separately if still wanted. Closing.
Resolved in spikersoft-backend PR #201 (merged): blog media served via nginx static path, UploadCoordinator ebooks final-directory typo fixed, stale duplicate stack file removed; plus spikersoft-infrastructure commit e28e968 (blog-media-processor joins the clamav overlay). The 'known remaining item' flagged in the ticket (code bind-mount target + nginx serving quarantine/ publicly) was called separate-ticket-worthy — file it separately if still wanted. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Follow-ups from a mount-point audit of the SERVER
/mnt/fusionio/spikersoftshare vs our docker-stack files.1. Blog media should be served by nginx, not the API
Blog media currently gets a
/blog-pictures/{username}/{file}URL, which the SPA prefixes withhttps://api.spikersoft.com, so every image/video request goes through the API's static-files middleware. The Angular nginx container already bind-mounts the whole share at/usr/share/nginx/html/spikersoft, so the final blogs folder is directly servable athttps://learn.spikersoft.com/spikersoft/blogs/...with zero API involvement.Change:
BlogMediaMoveConsumernow builds the public URL from aBlogMedia:PublicUrlPrefixconfig value. Production sets it tohttps://learn.spikersoft.com/spikersoft/blogs(absolute URL — the SPA passes absolute URLs through untouched). The default stays/blog-picturesso Development (no nginx in front) and existing posts with legacy relative URLs keep being served by the API's/blog-picturesstatic route, which remains in place.2. Typo broke the UploadCoordinator's ebooks final directory in Production
SpikerSoft.EventHandlers.UploadCoordinator/appsettings.Production.jsonhad"Ebooks": "yes/app/ebooks"— a relative path that would resolve against the container CWD instead of the/app/ebooksbind mount. Fixed to/app/ebooks.3. Stale duplicate stack file removed
spikersoft-backend/deploy/docker-stack.ymlwas an out-of-date copy ofspikersoft-infrastructure/spikersoft-backend/docker-stack.yml(missing thelesson-videosmount, among other drift). CI deploys from/mnt/infrastructure/spikersoft-backend, and nothing referenced the copy, so it's deleted.Ops prerequisites (already done)
uploads/assetscreated on SERVER (was missing; the coordinator'sWatchDirectories.Assetspoints at it).Known remaining item (separate ticket-worthy)
codebind mounts in file-movement/upload-coordinator point/app/codeat hostuploads/code, making the watch dir and final dir the same host directory (move-to-final is a no-op). The top-level/mnt/fusionio/spikersoft/codefolder is mounted by nothing and looks like the intended final target.quarantine/and unscanneduploads/— should be narrowed or deny-ruled.Resolved in spikersoft-backend PR #201 (merged): blog media served via nginx static path, UploadCoordinator ebooks final-directory typo fixed, stale duplicate stack file removed; plus spikersoft-infrastructure commit e28e968 (blog-media-processor joins the clamav overlay). The 'known remaining item' flagged in the ticket (code bind-mount target + nginx serving quarantine/ publicly) was called separate-ticket-worthy — file it separately if still wanted. Closing.