Commit Graph
100 Commits
Author SHA1 Message Date
tao.chen ca12646387 update: env error 2026-08-11 18:26:37 +08:00
tao.chen 78e83e1765 fix: migrate bug 2026-08-11 18:13:15 +08:00
tao.chen ed7a6cd858 fix: migrate bug 2026-08-11 18:05:34 +08:00
tao.chen 1b0083be47 refactor: kernel spec 2026-08-11 17:47:39 +08:00
tao.chen 6c6e7e6500 update: python script run in python intercept 2026-08-11 16:20:40 +08:00
tao.chen ec9effc254 update: npm registry 2026-08-11 16:19:34 +08:00
tao.chen b49d804718 update: upgrade base image 2026-08-11 16:12:24 +08:00
tao.chen fe7f1a744e feat: schedule node add python version 2026-08-11 15:56:05 +08:00
tao.chen e28bc39328 fix: default user 2026-08-11 15:13:26 +08:00
tao.chen 4269eed018 fix: 422 error 2026-08-11 15:13:13 +08:00
tao.chen b44d057241 feat: preview components 2026-08-11 15:02:16 +08:00
tao.chen 5969f2f749 reformatter 2026-08-11 11:13:13 +08:00
tao.chen b00a0e9ae1 fix: hook 2026-08-07 20:42:36 +08:00
tao.chen 567786215e refactor: SchedulePage.tsx 2026-08-07 20:40:41 +08:00
tao.chen 084de5b2d6 fix: storage.py 2026-08-07 20:14:29 +08:00
tao.chen a97aad3179 fix: schedule error 2026-08-07 19:59:04 +08:00
tao.chen e7bce03794 fix: storage_api.py 2026-08-07 19:58:42 +08:00
tao.chen 7b4b752109 fix: import workspace member 2026-08-07 19:25:04 +08:00
tao.chen 45808192e0 refactor: SchedulePage.tsx 2026-08-07 19:19:37 +08:00
tao.chen 6ff2127de7 update: add logger info 2026-08-07 19:19:25 +08:00
tao.chen ed517c488b Merge remote-tracking branch 'aliyun/develop' into develop 2026-08-07 18:50:57 +08:00
tao.chen 14c41a22b6 fix: runtime timeout 2026-08-07 18:50:48 +08:00
tao.chen 37d89c74d6 Merge remote-tracking branch 'aliyun/develop' into develop 2026-08-07 18:22:08 +08:00
tao.chen e2615be2e8 refactor: extract components 2026-08-07 17:38:28 +08:00
tao.chen 873a464629 fix: auth error 2026-08-07 16:14:13 +08:00
tao.chen 10347efa73 update: exclude hidden dir 2026-08-07 15:08:36 +08:00
tao.chen 2ee36b48ec update: auth
update auth api
2026-08-07 14:41:20 +08:00
tao.chen 984894d797 refactor: SchedulesPageRoute.tsx, UserManagementPage.tsx, ProjectManagementPage.tsx 2026-08-07 14:40:46 +08:00
tao.chen ec57fb6c7e update: storage
update storage base path
2026-08-07 14:37:56 +08:00
tao.chen 6b2db5c613 fix: docker-compose.yml
env var error
2026-08-07 14:03:01 +08:00
tao.chen edd560cf84 fix: docker-compose.yml
env var error
2026-08-07 14:01:17 +08:00
tao.chen 96f9a5c644 update: docker-compose.yml
add volumes
2026-08-07 13:58:04 +08:00
tao.chen ffd1db45fc fix: workspace refresh 2026-08-07 13:12:07 +08:00
tao.chen 03096a8951 feat: user permission 2026-08-07 13:00:14 +08:00
tao.chen a891f1f649 fix: db version 2026-08-07 12:59:41 +08:00
tao.chen 586d9fa645 update: API.md 2026-08-07 12:58:54 +08:00
tao.chen 2369dc3dda rollback vite 2026-08-07 12:56:52 +08:00
tao.chen e8de719523 feat: add SchedulesPageRoute.tsx 2026-08-07 12:55:25 +08:00
tao.chen 6f574073e3 fix: frontend routes 2026-08-07 12:47:37 +08:00
tao.chen d7934a42ab refactor: uiStore.ts 2026-08-07 12:23:50 +08:00
tao.chen 2272e1f390 feat: add user api 2026-08-06 19:26:57 +08:00
tao.chen 2894b1f06f fix: storage_api.py 2026-08-06 19:02:11 +08:00
tao.chen 245b522d36 feat: add seed to venv 2026-08-06 12:30:33 +08:00
tao.chen 6e6f880eb0 rollback 2026-08-06 11:00:41 +08:00
tao.chen a7963406b3 fix: default kernel 2026-08-06 10:55:12 +08:00
tao.chen e2329ea429 fix: default kernel 2026-08-06 10:46:21 +08:00
tao.chen d813508461 feat: create user api 2026-08-06 10:42:17 +08:00
tao.chen bf2cd9bd69 update: rename JUPYTER_VENV 2026-08-06 10:40:03 +08:00
tao.chen 53999cbd5b docs: add API 2026-08-06 10:26:16 +08:00
tao.chen a220afdb0b update: schedule add multi python 2026-08-06 10:26:07 +08:00
tao.chen 485d324d39 update: list users 2026-08-06 10:25:50 +08:00
tao.chen b9a028a1db update: multi python version 2026-08-06 10:03:58 +08:00
tao.chen f63ddc59b5 update: remove jupyter env install kernel /opt/venv/python3.12 2026-08-05 19:16:09 +08:00
tao.chen 90c3b5ee6f fix: save version error 2026-08-05 19:14:05 +08:00
tao.chen c4529782b5 test: Isolation jupyter env 2026-08-05 18:59:33 +08:00
tao.chenandClaude Fable 5 d5de1a63d4 fix: eager-load server defaults on StorageObjects to avoid MissingGreenlet
publish_version -> create_server_object_payload -> storage_payload reads
item.created_at on a sync helper. Without eager_defaults, server-default
columns stay unloaded after INSERT, the next sync read triggers a lazy
refresh through the async driver, and MissingGreenlet fires.

Enable mapper-level eager_defaults on StorageObjects so server-default
columns (created_at, updated_at, ...) are round-tripped into the ORM
object immediately after INSERT. No other table or session config
touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 18:36:26 +08:00
tao.chen 264faecb0d fix: python3.10 build error 2026-08-05 17:49:53 +08:00
tao.chen 450609d868 feat: support python3.10 2026-08-05 17:46:13 +08:00
tao.chen c2617da61c feat: support python3.8 2026-08-05 17:10:53 +08:00
tao.chen 8519393895 update: admin valid 2026-08-05 17:10:36 +08:00
tao.chen 5e68435dd9 Merge remote-tracking branch 'aliyun/develop' into develop 2026-08-05 16:01:34 +08:00
tao.chen e997e6cf56 fix: bucket name error 2026-08-05 16:01:28 +08:00
tao.chen d851f98581 fix: runtime error 2026-08-05 15:04:07 +08:00
tao.chen 5b88f81e4b update: alembic baseline 2026-08-05 15:00:57 +08:00
tao.chen 07d2423c13 update: remove workspace operation table and refactor 2026-08-05 14:43:48 +08:00
tao.chen c3b078a827 Merge remote-tracking branch 'aliyun/develop' into develop 2026-08-05 14:29:14 +08:00
tao.chen f4cabe6e20 update: remove storage 2026-08-05 13:41:13 +08:00
tao.chen 309b657d35 docs: align with new storage architecture (s3 + local + server-proxied PUT)
All operator- and developer-facing docs updated to reflect:

  - The unified AsyncStorageBackend abstraction (s3 + local backends).
  - The STORAGE_BACKEND toggle ("s3" default, "local" for dev /
    single-node / air-gapped deployments).
  - The 4-purpose-bucket layout (workspace / version / run_log / trash)
    in both modes — 4 separate S3 buckets in s3 mode, 4 subdirectories
    of LOCAL_STORAGE_BASE_DIR in local mode.
  - The S3_* env var naming (was RUSTFS_*).
  - The server-proxied upload flow (was browser-direct presign-PUT):
    POST /internal/v1/uploads → PUT /internal/v1/uploads/{id} with
    raw bytes → server calls backend.put().
  - The factory helpers workspaces_root() (runtime's view of the
    workspace bucket on disk) and rclone_remote_spec() (s3-mode mount
    source).
  - The "two settings describing the same thing" cleanup: the deleted
    settings.workspace_root, settings.workspaces_root, and
    settings.remote_bucket fields.

Files touched:
  - API.md (§5 data-resource upload flow, §9 storage control plane,
    §10 readiness example)
  - ARCHITECTURE.md (storage layer diagram)
  - CLAUDE.md (architecture description + volume-preservation note)
  - DEVELOP.md (settings list, Storage section, "Wire a new bucket"
    how-to, dev-export example, troubleshooting network hint)
  - README.md (architecture diagram, container table, quick-start
    credentials note, tear-down note, Storage layout section)
  - REFACTOR_NOTES.md (final container list with s3 explanation)
  - backend/README.md (storage backend description)
  - migrations/data/README.md (step 11/12 record mentioning object
    storage)

A handful of historical "RustFS" mentions are intentionally retained
where they name a specific S3-compatible product (e.g. as an example
in REFACTOR_NOTES.md's container list) or document the pre-2026
abstraction name (DEVELOP.md Storage section).
2026-08-05 13:13:20 +08:00
tao.chen 4e290bd80a storage: add UploadSessions columns for server-proxied upload metadata
The server-proxied upload flow (replaces presign-PUT) stores the
file-level metadata directly on the UploadSessions row at session
creation, so step 2 (PUT bytes) can build the StorageObjects row
without re-sending metadata through a separate CompleteUploadRequest.

New columns on upload_sessions:
  file_name    VARCHAR(255) NOT NULL DEFAULT ''
  usage_type   VARCHAR(32)  NOT NULL DEFAULT 'working_copy'
  visibility   VARCHAR(16)  NOT NULL DEFAULT 'private'
  is_immutable TINYINT(1)   NOT NULL DEFAULT 0

The SQLAlchemy model already declares these columns; this migration
applies the schema change to MySQL.

Migration: c3d4e5f6a7b8_upload_session_object_metadata.py
(chains off a2b3c4d5e6f7)
2026-08-05 13:11:55 +08:00
tao.chen d2bb450d30 storage: add local filesystem backend option (STORAGE_BACKEND toggle)
The factory now picks between two backends based on
settings.storage_backend ("s3" default, "local" for dev / single-node /
air-gapped deployments). The new factory helper build_storage_config()
takes one of the 4 PURPOSE_BUCKETS ("workspace" | "version" |
"run_log" | "trash") and returns the kwargs for create_storage(...).

  s3   mode: AsyncStorageBackend over an S3-compatible service
           (S3_WORKSPACE_BUCKET etc. as separate buckets).
  local mode: AsyncStorageBackend over on-disk files; the 4 buckets
           become subdirectories of LOCAL_STORAGE_BASE_DIR (default
           "/data"), so the same 4-bucket layout works in both modes.

Concretely:
  - common/config.py: add storage_backend (default "s3") +
    local_storage_base_dir (default "/data").
  - common/storage/factory.py: add PURPOSE_BUCKETS constant +
    build_storage_config(bucket_name) helper.
  - backend/main.py + backend/storage_api.py: lifespan collapses the
    4-instance construction into one dict comprehension:
      app.state.object_stores = {
        name: create_storage(build_storage_config(name))
        for name in PURPOSE_BUCKETS
      }
    (was 4x ~10-line dicts, one per bucket).
  - runtime/mount.py: when STORAGE_BACKEND=local, skip the rclone mount
    entirely (the shared docker volume at LOCAL_STORAGE_BASE_DIR is the
    store; runtime reads directly).
  - docker-compose.yml: mount the shared local-storage volume at /data
    in both backend and runtime containers.
  - .env.example: document STORAGE_BACKEND + LOCAL_STORAGE_BASE_DIR.

Dependencies added to support both backends:
  - aiofiles>=25.1.0 (local async I/O) to backend + common + runtime.
  - aioboto3>=15.5.0 (async S3) to common.
  - uv.lock regenerated.

After this commit, both modes deploy end-to-end. The s3 mode is the
production default; local mode is opt-in via STORAGE_BACKEND=local.
2026-08-05 13:10:05 +08:00
tao.chen 4b2a67ae5d storage: extract unified AsyncStorageBackend abstraction + migrate from RustFS
Replace the old RustFS-specific storage layer (common.storage.client /
RustFSObjectStore) with a minimal sync/async abstraction:

  AsyncStorageBackend: put / get / get_stream / delete / exists / stat /
                       list / get_url / copy
  StorageBackend:      same surface, sync implementations
  create_storage({"type": "s3" | "local", "mode": "async", ...})
  backends/s3.py:      S3-compatible (boto3 / aioboto3)
  backends/local.py:   on-disk filesystem (aiofiles)

Concretely:
  - Drop RustFSObjectStore + common.storage.client (deleted).
  - Drop the RustFS-specific ensure_bucket / presign_put / move_to_trash /
    rewrite_to_public_path / sha256 / put_bytes methods.
  - Migrate backend/storage_api.py + backend/main.py + backend/scripts.py
    + schedule/service.py + schedule/worker.py to the new abstraction.
  - Migrate backend/storage_client.py + schedule/storage_client.py to
    stub status (HTTP wrapper is dead code post-migration; rewrite pending).
  - Rename all RUSTFS_* env vars to S3_* across .env.example,
    docker-compose.yml, default.conf, scripts/nginx-entrypoint.sh,
    common/config.py.
  - Replace hardcoded rclone remote name "rustfs" with "s3" in
    docker-compose.yml + config.py default.
  - Rename "rustfs" SQLAlchemy column comments + table comments to
    provider-neutral wording; StorageObjects.storage_backend enum
    value moves from "rustfs" to "s3" (DB rows with the old value will
    fail the != "s3" check until a one-shot migration is applied).
  - Drop unused common/src/common/migrations/{README,env.py,script.py.mako}
    (the alembic setup lives in /migrations/, not here).

Migration of the old abstractions has been done in one pass; per-route
method calls (delete / stat / put / get_url) are now direct one-liners
against AsyncStorageBackend.

After this commit:
  - All Python imports resolve; routes compile (compileall green).
  - s3 mode is fully wired.
  - Routes that depended on removed methods (presign_put, move_to_trash,
    rewrite_to_public_path, head() metadata) raise NotImplementedError
    with a one-line TODO; rewriting these route handlers is the next step.
2026-08-05 13:08:32 +08:00
tao.chen 7c456a04ce update: update custom css 2026-08-05 11:07:54 +08:00
tao.chen fdf49a9ece Merge remote-tracking branch 'aliyun/develop' into develop 2026-08-04 18:48:24 +08:00
tao.chen bbf166f3c8 feat: front base dockerfile 2026-08-04 18:48:15 +08:00
tao.chen 00f50d4603 refactor: update frontend Dockerfile 2026-08-04 18:47:59 +08:00
tao.chen 87382d7bda refactor: update Dockerfile 2026-08-04 18:39:30 +08:00
tao.chen 7cf3a9d02a fix: runtime build failed 2026-08-04 18:00:06 +08:00
tao.chen a6692338cc fix: runtime build failed 2026-08-04 17:58:10 +08:00
tao.chen 004d7289ca update: update jupyter css 2026-08-04 17:45:23 +08:00
tao.chenandClaude Fable 5 45f0ff534f feat: workspace CRUD at platform scope + drop audit_logs
新增系统管理模块 /api/v1/platform/*:
- workspace 实体 CRUD(创建/列表/详情/更新/软删除)
- workspace 成员 CRUD(添加/列表/更新/移除)
- SystemAdminContext 依赖,仅 platform_role_id 指向 admin 角色的用户可访问
- /api/v1/auth/me 与 /auth/login 增 is_system_admin 派生字段
- 不变量:每个 workspace 至少保留一个 admin;系统管理员无法自我移除成员
- 软删除 workspace 级联软删除其成员

清理 audit_logs(无运行时写入,纯死特性):
- baseline 移除 audit_logs 建表与三索引(20 → 19 tables)
- 删除 AuditLogs 模型定义与 __init__.py 导出
- 清理 migrate_system_json / migrate_legacy_workspaces 中的 audit 写入与回填代码

API.md 增 §七系统管理,§七/§八/§九 顺延为 §八/§九/§十,附录 A/B 同步更新。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 17:20:42 +08:00
tao.chen 78e8affc94 Merge remote-tracking branch 'aliyun/develop' into develop 2026-08-04 16:06:00 +08:00
tao.chen 85eb19546e feat: add password 2026-08-04 16:05:54 +08:00
tao.chen 94a1aef7c7 fix: script not found 2026-08-04 14:24:55 +08:00
tao.chen 1cf2eecbc9 chore: frontend and schedule module 2026-08-04 13:58:19 +08:00
tao.chen e18a7a34a3 update: save version 2026-08-04 13:35:16 +08:00
tao.chen 14e84b6ce2 fix: path error 2026-08-04 13:05:18 +08:00
tao.chen 2a23030d6f fix: path error 2026-08-04 12:57:40 +08:00
tao.chen 4919fe0909 update: create file 2026-08-04 12:40:38 +08:00
tao.chen a27cda5a0c fix: jupyter start params 2026-08-04 12:03:43 +08:00
tao.chen 60b17f5bef update: jupyter start dir 2026-08-04 11:59:04 +08:00
tao.chen ddf112034d update: jupyter api payload, wire os.environ 2026-08-04 11:29:33 +08:00
tao.chen 173d562bd1 update: debug create file by jupyter 2026-08-04 11:06:52 +08:00
tao.chen d45109916a chore: update docker-compose.yml 2026-08-04 10:30:24 +08:00
tao.chen 078d8f8687 update: delete vfs refresh 2026-08-04 09:37:14 +08:00
tao.chen 1bd7da384c feat: add loguru 2026-08-03 20:45:00 +08:00
tao.chen 939a579b07 feat: rclone client 2026-08-03 20:37:56 +08:00
tao.chen 134f8ca552 feat: refresh VFS 2026-08-03 20:23:18 +08:00
tao.chen e1172a0091 update: rclone add remote control 2026-08-03 20:02:42 +08:00
tao.chen 85791ab1ea update: rclone add remote control 2026-08-03 19:57:29 +08:00
tao.chen e19340332a update: hide top-panel 2026-08-03 19:51:24 +08:00