Commit Graph

131 Commits

Author SHA1 Message Date
agent-kanban[bot] 038e23172b feat: establish unified authorization kernel (#533)
* feat: establish unified authorization kernel

Agent-Profile: https://agent-kanban.dev/agents/e0a1ce35687e48ef

* docs(v2.9): sync confirmed agent access plan

---------

Co-authored-by: Ravi Shah <ravi-shah@mails.agent-kanban.dev>
Co-authored-by: saltbo <saltbo@foxmail.com>
2026-07-28 21:34:11 -04:00
saltbo c66590a51b feat(image-hosting): gate custom domains and support origins 2026-07-28 14:48:53 -04:00
Jasper Van faea00d025 feat(image-hosting): improve custom-domain image links (#531) 2026-07-28 02:38:03 -04:00
Jasper Van 6ad1563acc feat(image-hosting): automate Cloudflare domain setup (#530) 2026-07-28 01:03:56 -04:00
Jasper Van 1d58d5b80d feat(image-hosting): add configurable custom domain providers (#529)
* feat(image-hosting): add custom domain providers

* test(image-hosting): cover custom domain provider flows
2026-07-27 22:52:18 -04:00
Jasper Van b2859ec944 refactor(storage): remove legacy custom host downloads (#528)
* refactor(storage): remove custom host downloads

* test(download): cover private signed URLs end to end
2026-07-27 20:00:43 -04:00
Jasper Van ece5f413be fix(download): force browser-downloadable files to save (#527)
* fix(download): force browser-downloadable files to save

* fix(storage): require signed upload CORS headers

* fix(storage): keep upload metadata out of signatures

* fix(storage): sign bare upload commands

* revert: keep upload metadata in signed commands
2026-07-27 18:47:52 -04:00
Jasper Van a5c281b26a refactor(api)!: make site routes RESTful (#526)
Move site configuration under settings, model analytics and licensing as resources, and isolate scheduler runs under the internal API.

BREAKING CHANGE: site email, branding, analytics, licensing, WebDAV verification, and scheduler endpoint paths have changed.

Refs #451
2026-07-27 15:22:28 -04:00
Jasper Van 5473db9be1 fix(downloads): separate list data from task details (#525)
* fix(downloads): separate list items from task details

* fix(downloads): scope task list to downloader

* fix(downloads): stabilize table data
2026-07-27 10:22:47 -04:00
Jasper Van ad0f21bb39 fix: unify list pagination and realtime updates (#524)
* fix!: unify pagination and realtime change delivery

Replace offset paging on affected unbounded collections with signed keyset tokens and infinite loading. Persist scoped resource changes so one global SSE connection can resume and invalidate query caches safely.

BREAKING CHANGE: migrated list APIs now accept pageToken and return nextPageToken instead of page and total fields.

Refs #450

* fix: keep page tokens at the HTTP boundary

Move signed page-token handling out of the pure domain layer so dependency-cruiser architecture checks pass without changing behavior.

* fix: route background job stats through usecase

Keep the HTTP boundary from reaching directly into repository ports and cover the new usecase wrapper.

* fix: align clients and checks with cursor pagination

* refactor: unify pagination boundaries and infinite loading
2026-07-27 02:02:53 -04:00
saltbo 5c3d5a71a5 chore(openapi): regenerate object list model 2026-07-26 22:09:07 -04:00
saltbo 1a61b6d9e2 fix(downloader): serialize attempt ledger updates 2026-07-26 10:39:27 -04:00
Jasper Van d6d811f41c feat(public): redesign profile and share pages (#522)
* feat(public): redesign profile and share pages

* fix(openapi): regenerate Go client

* test(share): cover README validation boundaries
2026-07-24 08:35:05 -04:00
saltbo 0550e41868 feat(shares)!: make landing shares public by default
Replace opt-in profile listings with an opt-out private flag and a unified privacy endpoint.

BREAKING CHANGE: showOnProfile, listedAt, and the profile-listing endpoints are replaced by private and PUT /api/shares/:token/privacy.
2026-07-24 01:07:01 -04:00
agent-kanban[bot] 526d237a4e feat: connect curated shares to public profiles (#519)
* feat: connect curated shares to public profiles

Agent-Profile: https://agent-kanban.dev/agents/1dc839c09b5ee5e5

* chore: retry CI after tunnel failure

Agent-Profile: https://agent-kanban.dev/agents/1dc839c09b5ee5e5

---------

Co-authored-by: Marina Zhou <marina-zhou@mails.agent-kanban.dev>
2026-07-24 00:39:25 -04:00
saltbo 2f7026b77d chore(openapi): regenerate Go client 2026-07-23 18:24:21 -04:00
saltbo a83c3ac5a7 fix(api-keys): normalize legacy scope metadata 2026-07-23 01:50:22 -04:00
saltbo 3f0531c6bd fix(webdav): sync generated OpenAPI client 2026-07-22 23:47:54 -04:00
saltbo 44198fabcb chore(openapi): regenerate Go client 2026-07-22 11:21:50 -04:00
saltbo e55ee53496 refactor(stats): unify audit and fact pipelines
Centralize request audit recording, preserve immutable download-task history, and derive hourly statistics and backfills from the same authoritative sources. Add durable user registration facts so admin deletion no longer destroys signup history.
2026-07-21 23:02:52 -04:00
saltbo e761b6aec7 feat(webdav): verify derived domains before publishing 2026-07-20 18:54:12 -04:00
saltbo 7fe16f3ed7 refactor(site): replace options with structured config APIs 2026-07-20 15:17:48 -04:00
saltbo 8cd151c798 chore(openapi): refresh generated Go client 2026-07-20 13:09:37 -04:00
agent-kanban[bot] f0292cc257 fix(events): allow org API keys to stream download tasks (#509)
* fix(events): authorize org API key task streams

Agent-Profile: https://agent-kanban.dev/agents/e0a1ce35687e48ef

* docs(events): complete verification checklist

Agent-Profile: https://agent-kanban.dev/agents/e0a1ce35687e48ef

---------

Co-authored-by: Ravi Shah <ravi-shah@mails.agent-kanban.dev>
2026-07-19 01:09:12 -04:00
saltbo 8eb388ea01 fix(admin): align dashboard stats data sources 2026-07-09 23:34:03 -04:00
saltbo ab81f138bd fix(admin): harden dashboard stats ranges 2026-07-09 23:34:03 -04:00
saltbo b7f7fa7ecd feat(admin): implement operations dashboard stats 2026-07-09 23:34:03 -04:00
saltbo 554c231536 feat(admin): redesign dashboard with pro analytics 2026-07-09 23:34:03 -04:00
agent-kanban[bot] 7ccaba2f8b feat: refine admin audit filtering (#495)
* feat: refine admin audit filtering

Agent-Profile: https://agent-kanban.dev/agents/b0abe6cd7aeba133

* test: add audit filter spec scenarios

Agent-Profile: https://agent-kanban.dev/agents/b0abe6cd7aeba133

* chore: refresh openapi client

Agent-Profile: https://agent-kanban.dev/agents/b0abe6cd7aeba133

---------

Co-authored-by: Noah Reed <noah-reed@mails.agent-kanban.dev>
2026-07-04 10:21:45 -04:00
dependabot[bot] bc15bc3617 chore(deps): bump golang.org/x/net (#496)
Bumps the go_modules group with 1 update in the /cmd directory: [golang.org/x/net](https://github.com/golang/net).


Updates `golang.org/x/net` from 0.52.0 to 0.55.0
- [Commits](https://github.com/golang/net/compare/v0.52.0...v0.55.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.55.0
  dependency-type: indirect
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 01:31:26 -04:00
saltbo 3695c80c2e feat(downloads): add task event timeline 2026-06-29 21:07:00 -04:00
saltbo 74c0d0cd75 fix(downloader): report aria2 metadata runtime 2026-06-29 20:19:46 -04:00
saltbo 979afd20e7 style(downloader): format client tests 2026-06-29 17:45:34 -04:00
saltbo 3fdc7b4ae0 refactor(downloader): reorganize cmd downloader runtime 2026-06-29 17:42:24 -04:00
saltbo 26b7a1d8a4 fix(downloader): preserve failed upload results for retry 2026-06-29 12:08:25 -04:00
saltbo 2c0cdd8a63 fix(downloader): prevent aria2 session auto-restore 2026-06-27 01:42:32 -04:00
saltbo cf7b1de112 fix(downloader): consolidate polling into heartbeat 2026-06-27 01:16:12 -04:00
saltbo c55f6f460c chore(openapi): update generated storage client 2026-06-24 17:51:19 -04:00
saltbo 3f6751d60c chore(openapi): update generated downloader client 2026-06-24 14:59:54 -04:00
saltbo fb2281f1b3 fix(downloader): clean local data only on task delete 2026-06-24 11:12:31 -04:00
agent-kanban-local[bot] f41ed27bba [codex] separate billing configuration (#479)
* feat(admin): separate billing configuration

Add dedicated storage egress and downloader credit billing contracts, usecases, RPC wrappers, drawers, generated client updates, and coverage.

Agent-Profile: https://agent-kanban.dev/agents/2673e70e0085f4e0

* fix(billing): preserve not found ordering

Check storage and downloader existence before quota_store gating in dedicated billing usecases, and cover enabled missing-resource requests at usecase and route levels.

Agent-Profile: https://agent-kanban.dev/agents/2673e70e0085f4e0

---------

Co-authored-by: Jordan Park <jordan-park@mails.agent-kanban.dev>
2026-06-24 05:57:10 -04:00
agent-kanban-local[bot] 82c5452782 feat(auth): move OAuth provider editor to drawer (#480)
Agent-Profile: https://agent-kanban.dev/agents/57ed5bcf43079e29

Co-authored-by: Jordan Park <jordan-park@mails.agent-kanban.dev>
2026-06-24 05:55:26 -04:00
agent-kanban-local[bot] 7cfbbf77b7 fix: clean downloader terminal artifacts (#477)
* fix: clean downloader terminal artifacts

Agent-Profile: https://agent-kanban.dev/agents/57ed5bcf43079e29

* test: tolerate stale cloud license cleanup

Agent-Profile: https://agent-kanban.dev/agents/57ed5bcf43079e29

* test: retry transient pairing poll failures

Agent-Profile: https://agent-kanban.dev/agents/57ed5bcf43079e29

* fix: make suspended downloader cleanup idempotent

Agent-Profile: https://agent-kanban.dev/agents/57ed5bcf43079e29

---------

Co-authored-by: Jordan Park <jordan-park@mails.agent-kanban.dev>
2026-06-24 03:14:38 -04:00
agent-kanban-local[bot] c7f3d11793 [codex] Add admin storage connection testing (#475)
* feat(storage): add admin connection testing

Agent-Profile: https://agent-kanban.dev/agents/2673e70e0085f4e0

* fix: correct storage CORS guidance

Agent-Profile: https://agent-kanban.dev/agents/2673e70e0085f4e0

---------

Co-authored-by: Jordan Park <jordan-park@mails.agent-kanban.dev>
2026-06-24 00:37:59 -04:00
Jianguo Wu f4b65e4987 feat: make forcePathStyle configurable per storage (#474)
* feat: make forcePathStyle configurable per storage

Previously hardcoded to true, which breaks S3-compatible backends that require
virtual-hosted-style addressing (e.g. Alibaba Cloud OSS). Now configurable via
admin storage settings with a toggle switch, defaulting to true for backwards
compatibility.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test: cover storage force path style

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: saltbo <saltbo@foxmail.com>
2026-06-23 20:46:33 -04:00
agent-kanban-local[bot] 00f48cf355 feat(avatars): host avatars + team logos on Cloud via SDK 2.4.0; remove public-bucket mode (#467)
* feat(avatars): host avatars + team logos on Cloud via SDK 2.4.0; remove public-bucket mode

Host user avatars and org logos on the ZPan Cloud avatar service
(zpan-cloud-sdk ^2.4.0) instead of a public S3/R2 bucket, then remove the
now-dead storages.mode / public-bucket concept entirely (#456 parts 2-3).

- image-upload gateway: upload/delete via SDK uploadAvatar/deleteAvatar against
  a bound Cloud client; validate mime (AVATAR_CONTENT_TYPES) + size
  (MAX_AVATAR_BYTES) before the call; map cloud error codes to 400/403/413/500;
  unbound instance returns 503 cloud_required (delete is a best-effort no-op).
- licensing-cloud: createAvatarUploadClient builds the client with a plain-object
  bearer header so both the image content-type and Authorization survive hono's
  per-request header merge (a Headers instance would be dropped).
- drop storages.mode (migration via drizzle-kit), StorageRepo.select() no longer
  takes a mode, remove StorageMode / Storage.mode / mode schema+audit+UI+i18n and
  the PUBLIC_IMAGES bucket + PUBLIC_IMAGES_URL wiring.

Agent-Profile: https://agent-kanban.dev/agents/f759c704c282d88a

* ci(deploy): drop dead PUBLIC_IMAGES R2 provisioning from CF deploy

The Cloud avatar migration removed the PUBLIC_IMAGES binding from
wrangler.toml, so the deploy workflow's R2 public-images steps are dead and
must go too — otherwise every CF deploy keeps re-provisioning a public-read
zpan-public-images bucket (the footgun #456 eliminates) and sets an unused
PUBLIC_IMAGES_URL secret. Removes the bucket-create, managed-public-URL, and
secret steps (steps.r2 was only consumed by the secret step). Also drops a
stale storage-modes line from the v2.0 roadmap.

Agent-Profile: https://agent-kanban.dev/agents/f759c704c282d88a

---------

Co-authored-by: Alex Chen <alex-chen@mails.agent-kanban.dev>
2026-06-20 00:16:07 -04:00
saltbo 29ec82651f fix(downloader): resume download path instead of panicking when runtime isn't complete
Final piece of the restart→download→upload→seed robustness pass. nextTaskWorkStage
can route a task to uploadExistingResult based on the server checkpoint (upload
progress / runtime phase / download totals), but the engine may not report the
download complete yet — aria2 re-checks on-disk files after a restart (showing
downloaded=0/total=nil transiently), or the download was lost. The old code
panic()'d on that mismatch, which recoverTaskPanic turned into a permanently
failed task (this is what failed Moonfall after it had fully downloaded 7.4GB).

Now uploadExistingResult falls back to downloadThenUpload when the runtime isn't
complete (or has no result). downloadThenUpload re-attaches to the session
download, waits for aria2 to finish re-checking, and uploads on completion — no
data loss, no spurious failure. Test updated to assert resume-not-fail.
2026-06-19 19:38:33 -04:00
saltbo 23ded65e6f fix(downloader): nil-safe isAria2RPCDisconnected to stop a startup panic
isAria2RPCDisconnected called err.Error() unconditionally, so a nil error
panicked (nil pointer deref). findSeed reaches it with a nil error whenever
tellStatus succeeds but the status isn't a seed — which crashed the downloader at
startup while restoring a retained seed from the ledger. Guard nil -> false.
2026-06-19 19:28:18 -04:00
saltbo a803b2d6f0 fix(downloader): don't adopt an assigned task's auto-seed before it's uploaded
Second restart bug behind the same stuck Moonfall: aria2 auto-seeds a torrent
the instant its download finishes (--seed-time), so a completed-but-not-yet-
uploaded download shows up in ListSeeds. reconcileEngineSeeds runs at startup
BEFORE the task loop marks tasks running, so 'running' was empty and it adopted
that seed as a done seed for managed expiry — skipping the upload entirely. The
task then sat at 'downloading' forever and the file would be deleted when the
seed expired.

Skip seeds whose task is still assigned/unfinished (AssignedTasks: assigned/
downloading/interrupted/uploading) — those belong to the task loop, which will
upload then seed them. Only genuinely orphaned seeds (completed tasks) are
adopted. Confirmed on prod: Moonfall finished (7.4GB on disk) with
result_object_id=null, stuck downloading.
2026-06-19 19:12:10 -04:00
saltbo 50514399d5 fix(downloader): re-attach to session download on restart so progress keeps reporting
After a downloader restart, the web UI showed a frozen download with 0 speed
even though aria2 was still downloading. Cause: on restart a task comes back as
'interrupted', but shouldAttachExistingAria2Task only attached for
downloading/uploading — so the worker RE-ADDED the magnet. aria2 had already
reloaded that download from its saved session, so the re-add hit error 12
(infohash already registered) and produced a dead duplicate gid. The worker then
polled the dead duplicate (bytes=0, speed=0) instead of the live download;
mergeTaskProgress's max() kept the stale byte count, so the UI froze. The real
download kept going, orphaned and unreported.

Fixes:
- shouldAttachExistingAria2Task also returns true for 'interrupted', so restart
  attaches to the session-restored download instead of re-adding.
- findTask skips error/removed entries so it never attaches to a dead duplicate.

Confirmed on prod: Moonfall had two aria2 gids — 29ded179 (live, 6.8GB) and
3203aca6 (error-12 duplicate) — and the server runtime was frozen at the
pre-restart snapshot.
2026-06-19 18:49:53 -04:00