Files
hub/README.md
T
nmemmertandClaude Sonnet 5.5 5466506ffb
build-container / build (push) Successful in 1m55s
Calendar: add events (NE Hub calendar + iCloud) and a Podcast tab
- Add, edit and delete events; month/agenda views open them on tap
- NE Hub calendar stored on the server and published as a private ICS subscribe link
- iCloud CalDAV read/write with an app-specific password (encrypted at rest,
  only *.icloud.com contacted, event addresses checked against the calendar)
- Edits patch the existing entry so alarms/attendees survive; writes use If-Match / If-None-Match
- Time zone definitions (VTIMEZONE) generated so other apps read times correctly
- Podcast tab (PODCAST_URL) alongside Podcast Admin

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 15:08:41 -04:00

3.7 KiB

NE Hub

One installable web app (PWA) for Seafile, OnlyOffice and your four webmail accounts. Mobile-first; bottom tabs on phones, side rail on iPad and desktop (tuned for 12.9" at 1024 and 1366 wide).

Configure

cp .env.example .env     # set ONLYOFFICE_JWT_SECRET (same value as the Document Server) and PUBLIC_URL

PUBLIC_URL must be an address the OnlyOffice server can reach (not localhost): it posts saved edits back there.

Run

docker compose up -d --build     # http://localhost:8080
# or: node server.js

Put it behind your reverse proxy with HTTPS (needed for "Add to Home Screen" and the service worker), e.g. hub.necloud.us. Settings: SEAFILE_URL, ONLYOFFICE_URL env vars in docker-compose.yml.

What each part does

  • Files: signs in with your Seafile account, browses libraries, uploads, creates folders, downloads, deletes. The server proxies /sf/* to Seafile because Seafile sends no CORS headers. Token lives in the browser only. Office files open in Seafile's own OnlyOffice integration.
  • Edit here: opens docs inside the app via OnlyOffice. The server signs each editor config with the JWT secret and saves edits back to Seafile.
  • Sign-in: the whole app sits behind a passkey (WebAuthn). First run: open the site and enter the setup code (HUB_SETUP_CODE, or the one printed in the server log) to create a passkey; add more devices from Settings. Passkeys and the session secret live in /data (a Docker volume).
  • Files: also rename, move, share links, image/PDF/video/audio preview, and New document/spreadsheet/presentation.
  • Calendar: month grid and agenda. Add, edit and delete events:
    • NE Hub calendar: events you create are stored in /data/events.json and published as a private subscribe link (Manage calendars -> copy link) so Outlook, Google or Apple Calendar can show them (read-only there).
    • iCloud (two-way): connect with an Apple ID and an app-specific password (appleid.apple.com). Credentials are encrypted in /data/icloud.json; only *.icloud.com is contacted. Edits keep alarms and attendees intact.
    • ICS links (Google secret address, Outlook/M365 published calendar) are read-only.
  • Search: libraries, file names (scans libraries if Seafile has no search index) and Plex artists/albums/tracks.
  • Music: Plex player. Sign in goes through plex.tv (no password handled), the server proxies your Plex server and adds the token itself, and a mini player keeps playing as you move between tabs; the queue (play next / add to queue) and position are remembered.
  • Audio: embeds audiobooks.necloud.us; sign-in details saved in Settings can be copied with one tap.
  • Podcast and Podcast Admin: launchers that open PODCAST_URL (a home-network address) and VERSE_URL in their own tabs.
  • Office: embeds onlyoffice.necloud.us in a frame, with an "open in new tab" fallback if it blocks framing.
  • Mail: deep links to Gmail, Outlook.com, Microsoft 365 and iCloud webmail (inbox + compose). Providers forbid framing, and a real unified inbox would need Google/Azure app registrations.

Build and deploy with Gitea

.gitea/workflows/build.yml builds the container on every push to main (and v* tags) and pushes it to git.necloud.us/nate/hub (tags: latest, short commit sha, git tag). amd64 (x86) only.

One-time setup in Gitea: create an access token with the write:package scope, then add it to the repo under Settings -> Actions -> Secrets as REGISTRY_TOKEN (optionally REGISTRY_USER). The runner needs Docker.

On the server:

cp .env.example .env                # fill in secrets, PUBLIC_URL, etc.
docker compose pull && docker compose up -d
docker compose logs hub | grep "Setup code"   # first sign-in: create your passkey