從 edge-ai-platform POC 轉為正式產品的雲端後端,含以下整合階段:
- Phase 0:雛形骨架 — `cmd/api-server` (REST :3721) + `cmd/remote-proxy`
(tunnel :3800 / internal :3801) 雙 binary 共用 internal/,沿用 POC 的
WebSocket+yamux tunnel 協定但解耦 relay 與 API
- Phase 0.6:OIDC BFF 接 Innovedus Member Center
- internal/oidc package(coreos/go-oidc + PKCE S256 + state + nonce)
- internal/usersession package(HMAC-SHA256 cookie + RotateSessionID
防 session fixation, OWASP ASVS V3.2.1)
- 4 個 OIDC handler(/api/auth/login|callback|me|logout)+ AuthMiddleware
- 完全拔除 StaticAuthProvider,OIDC 是唯一認證路徑
- 9 個 ADR(含 ADR-010 BFF / ADR-011 取代 static auth /
ADR-012 pending session shared cookie / ADR-013 PKCE-only public client)
- Phase 0.7:A1 改造 + security audit 修復
- OIDC ClientSecret 變選填,支援 stage MC 的 public PKCE-only client
(AuthStyleInParams 強制 token endpoint 不送 client_secret)
- 預留 ServiceClient* 欄位給未來 client_credentials grant
- 移除 13+ 處 resolveUserID(uc, StaticUserID) fallback 改 strict mode
(Audit C1:multi-tenant 隔離破口)
- Pairing exchange MarkUsed 失敗 abort + revoke session token(Audit M3)
- 新增 all_endpoints_require_auth_test 整合測試(51 endpoint × 401)
驗證:go test -race -count=3 ./... 17 packages 全綠 / go vet 0 warning
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
3.0 KiB
Go
82 lines
3.0 KiB
Go
// Package converter 定義與 kneron_model_converter 服務互動的 client 介面。
|
||
//
|
||
// 對齊 TDD §2.7 與 api/api-converter-contract.md。
|
||
// 雛形以 StubClient 實作所有方法回 ErrNotImplemented(部分關鍵方法可給假資料讓前端走通 UI);
|
||
// Phase 2 以 HTTPClient 實作同 interface 呼叫真實 converter。
|
||
package converter
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"io"
|
||
"time"
|
||
)
|
||
|
||
// ==========================================================================
|
||
// Errors
|
||
// ==========================================================================
|
||
|
||
var (
|
||
// ErrNotImplemented 表示雛形尚未實作此方法。
|
||
ErrNotImplemented = errors.New("converter: not implemented in phase 0")
|
||
|
||
// ErrJobNotFound 表示指定 jobID 不存在。
|
||
ErrJobNotFound = errors.New("converter: job not found")
|
||
)
|
||
|
||
// ==========================================================================
|
||
// Domain types(對齊 database.md §2.6)
|
||
// ==========================================================================
|
||
|
||
// Job 是轉檔任務的狀態快照。
|
||
type Job struct {
|
||
ID string `json:"id"`
|
||
OwnerUserID string `json:"ownerUserId"`
|
||
Status string `json:"status"` // queued / running / succeeded / failed
|
||
SourceKey string `json:"sourceKey"`
|
||
ResultKey string `json:"resultKey,omitempty"`
|
||
TargetChip string `json:"targetChip"`
|
||
Params map[string]any `json:"params,omitempty"`
|
||
|
||
ErrorCode string `json:"errorCode,omitempty"`
|
||
ErrorMsg string `json:"errorMsg,omitempty"`
|
||
|
||
CreatedAt time.Time `json:"createdAt"`
|
||
UpdatedAt time.Time `json:"updatedAt"`
|
||
StartedAt *time.Time `json:"startedAt,omitempty"`
|
||
CompletedAt *time.Time `json:"completedAt,omitempty"`
|
||
}
|
||
|
||
// ConvertRequest 是提交轉檔任務時的輸入參數。
|
||
type ConvertRequest struct {
|
||
OwnerUserID string `json:"ownerUserId"`
|
||
SourceKey string `json:"sourceKey"` // 已上傳到 Storage 的來源檔 key
|
||
TargetChip string `json:"targetChip"`
|
||
Params map[string]any `json:"params,omitempty"`
|
||
}
|
||
|
||
// ==========================================================================
|
||
// Client interface
|
||
// ==========================================================================
|
||
|
||
// Client 抽象 converter 服務。
|
||
//
|
||
// 對齊 PRD interface-contracts.md §8.5 與 api-converter-contract.md。
|
||
type Client interface {
|
||
// SubmitConvert 提交一個新的轉檔任務;回傳 jobID。
|
||
SubmitConvert(ctx context.Context, req *ConvertRequest) (jobID string, err error)
|
||
|
||
// GetJob 查詢任務狀態;不存在回 ErrJobNotFound。
|
||
GetJob(ctx context.Context, jobID string) (*Job, error)
|
||
|
||
// ListJobs 列出使用者的所有轉檔任務。
|
||
ListJobs(ctx context.Context, userID string) ([]*Job, error)
|
||
|
||
// DownloadResult 下載任務產物(.nef)。
|
||
// 未完成或失敗時回錯;caller 必須 Close reader。
|
||
DownloadResult(ctx context.Context, jobID string) (io.ReadCloser, error)
|
||
|
||
// CancelJob 取消任務。
|
||
CancelJob(ctx context.Context, jobID string) error
|
||
}
|