feat(schedule-tasks): support auto-publish via media accounts
Replace the legacy target_platform string on schedule tasks with a workspace-aware auto-publish payload (auto_publish + publish_account_ids JSONB + cover_asset_url + cover_image_asset_id) and migrate the schema, sqlc queries, generated models, domain struct, ScheduleTaskService DTOs, and dispatch worker to round-trip the new fields. PromptRuleGeneration gains a WithPublishJobService hook so executeGeneration can enqueue an auto-publish job once the article is ready, and worker-generate wires the publish-job service in. On the admin-web side, extract PublishArticleModal's account-card builders into a shared publish-account-cards module, rebuild GenerateTaskDrawer's schedule mode around account selection plus a CoverPickerModal, and surface the new "auto publish" column on ScheduleTaskTab. Shared types and i18n strings cover the new fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,24 +34,30 @@ func (q *Queries) CountScheduleTasks(ctx context.Context, arg CountScheduleTasks
|
||||
}
|
||||
|
||||
const createScheduleTask = `-- name: CreateScheduleTask :one
|
||||
INSERT INTO schedule_tasks (tenant_id, prompt_rule_id, brand_id, name, cron_expr,
|
||||
target_platform, start_at, end_at, next_run_at)
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, $7, $8,
|
||||
$9)
|
||||
INSERT INTO schedule_tasks (tenant_id, workspace_id, prompt_rule_id, brand_id, name, cron_expr,
|
||||
auto_publish, publish_account_ids, cover_asset_url, cover_image_asset_id,
|
||||
start_at, end_at, next_run_at)
|
||||
VALUES ($1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12,
|
||||
$13)
|
||||
RETURNING id, created_at
|
||||
`
|
||||
|
||||
type CreateScheduleTaskParams struct {
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
WorkspaceID pgtype.Int8 `json:"workspace_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
AutoPublish bool `json:"auto_publish"`
|
||||
PublishAccountIds []byte `json:"publish_account_ids"`
|
||||
CoverAssetUrl pgtype.Text `json:"cover_asset_url"`
|
||||
CoverImageAssetID pgtype.Int8 `json:"cover_image_asset_id"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
}
|
||||
|
||||
type CreateScheduleTaskRow struct {
|
||||
@@ -62,11 +68,15 @@ type CreateScheduleTaskRow struct {
|
||||
func (q *Queries) CreateScheduleTask(ctx context.Context, arg CreateScheduleTaskParams) (CreateScheduleTaskRow, error) {
|
||||
row := q.db.QueryRow(ctx, createScheduleTask,
|
||||
arg.TenantID,
|
||||
arg.WorkspaceID,
|
||||
arg.PromptRuleID,
|
||||
arg.BrandID,
|
||||
arg.Name,
|
||||
arg.CronExpr,
|
||||
arg.TargetPlatform,
|
||||
arg.AutoPublish,
|
||||
arg.PublishAccountIds,
|
||||
arg.CoverAssetUrl,
|
||||
arg.CoverImageAssetID,
|
||||
arg.StartAt,
|
||||
arg.EndAt,
|
||||
arg.NextRunAt,
|
||||
@@ -77,8 +87,9 @@ func (q *Queries) CreateScheduleTask(ctx context.Context, arg CreateScheduleTask
|
||||
}
|
||||
|
||||
const getScheduleTaskByID = `-- name: GetScheduleTaskByID :one
|
||||
SELECT st.id, st.tenant_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.target_platform, st.start_at, st.end_at,
|
||||
SELECT st.id, st.tenant_id, st.workspace_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.auto_publish, st.publish_account_ids, st.cover_asset_url, st.cover_image_asset_id,
|
||||
st.start_at, st.end_at,
|
||||
st.next_run_at, st.status, st.created_at, st.updated_at,
|
||||
pr.name AS prompt_rule_name,
|
||||
b.name AS brand_name
|
||||
@@ -94,21 +105,25 @@ type GetScheduleTaskByIDParams struct {
|
||||
}
|
||||
|
||||
type GetScheduleTaskByIDRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
PromptRuleName pgtype.Text `json:"prompt_rule_name"`
|
||||
BrandName pgtype.Text `json:"brand_name"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
WorkspaceID pgtype.Int8 `json:"workspace_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
AutoPublish bool `json:"auto_publish"`
|
||||
PublishAccountIds []byte `json:"publish_account_ids"`
|
||||
CoverAssetUrl pgtype.Text `json:"cover_asset_url"`
|
||||
CoverImageAssetID pgtype.Int8 `json:"cover_image_asset_id"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
PromptRuleName pgtype.Text `json:"prompt_rule_name"`
|
||||
BrandName pgtype.Text `json:"brand_name"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetScheduleTaskByID(ctx context.Context, arg GetScheduleTaskByIDParams) (GetScheduleTaskByIDRow, error) {
|
||||
@@ -117,11 +132,15 @@ func (q *Queries) GetScheduleTaskByID(ctx context.Context, arg GetScheduleTaskBy
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.WorkspaceID,
|
||||
&i.PromptRuleID,
|
||||
&i.BrandID,
|
||||
&i.Name,
|
||||
&i.CronExpr,
|
||||
&i.TargetPlatform,
|
||||
&i.AutoPublish,
|
||||
&i.PublishAccountIds,
|
||||
&i.CoverAssetUrl,
|
||||
&i.CoverImageAssetID,
|
||||
&i.StartAt,
|
||||
&i.EndAt,
|
||||
&i.NextRunAt,
|
||||
@@ -135,8 +154,9 @@ func (q *Queries) GetScheduleTaskByID(ctx context.Context, arg GetScheduleTaskBy
|
||||
}
|
||||
|
||||
const listScheduleTasks = `-- name: ListScheduleTasks :many
|
||||
SELECT st.id, st.tenant_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.target_platform, st.start_at, st.end_at,
|
||||
SELECT st.id, st.tenant_id, st.workspace_id, st.prompt_rule_id, st.brand_id, st.name,
|
||||
st.cron_expr, st.auto_publish, st.publish_account_ids, st.cover_asset_url, st.cover_image_asset_id,
|
||||
st.start_at, st.end_at,
|
||||
st.next_run_at, st.status, st.created_at, st.updated_at,
|
||||
pr.name AS prompt_rule_name,
|
||||
b.name AS brand_name
|
||||
@@ -160,21 +180,25 @@ type ListScheduleTasksParams struct {
|
||||
}
|
||||
|
||||
type ListScheduleTasksRow struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
PromptRuleName pgtype.Text `json:"prompt_rule_name"`
|
||||
BrandName pgtype.Text `json:"brand_name"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
WorkspaceID pgtype.Int8 `json:"workspace_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
AutoPublish bool `json:"auto_publish"`
|
||||
PublishAccountIds []byte `json:"publish_account_ids"`
|
||||
CoverAssetUrl pgtype.Text `json:"cover_asset_url"`
|
||||
CoverImageAssetID pgtype.Int8 `json:"cover_image_asset_id"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
PromptRuleName pgtype.Text `json:"prompt_rule_name"`
|
||||
BrandName pgtype.Text `json:"brand_name"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListScheduleTasks(ctx context.Context, arg ListScheduleTasksParams) ([]ListScheduleTasksRow, error) {
|
||||
@@ -195,11 +219,15 @@ func (q *Queries) ListScheduleTasks(ctx context.Context, arg ListScheduleTasksPa
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.TenantID,
|
||||
&i.WorkspaceID,
|
||||
&i.PromptRuleID,
|
||||
&i.BrandID,
|
||||
&i.Name,
|
||||
&i.CronExpr,
|
||||
&i.TargetPlatform,
|
||||
&i.AutoPublish,
|
||||
&i.PublishAccountIds,
|
||||
&i.CoverAssetUrl,
|
||||
&i.CoverImageAssetID,
|
||||
&i.StartAt,
|
||||
&i.EndAt,
|
||||
&i.NextRunAt,
|
||||
@@ -238,23 +266,31 @@ const updateScheduleTask = `-- name: UpdateScheduleTask :exec
|
||||
UPDATE schedule_tasks
|
||||
SET prompt_rule_id = $1, brand_id = $2,
|
||||
name = $3, cron_expr = $4,
|
||||
target_platform = $5,
|
||||
start_at = $6, end_at = $7,
|
||||
next_run_at = $8, updated_at = NOW()
|
||||
WHERE id = $9 AND tenant_id = $10 AND deleted_at IS NULL
|
||||
workspace_id = $5,
|
||||
auto_publish = $6,
|
||||
publish_account_ids = $7,
|
||||
cover_asset_url = $8,
|
||||
cover_image_asset_id = $9,
|
||||
start_at = $10, end_at = $11,
|
||||
next_run_at = $12, updated_at = NOW()
|
||||
WHERE id = $13 AND tenant_id = $14 AND deleted_at IS NULL
|
||||
`
|
||||
|
||||
type UpdateScheduleTaskParams struct {
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
TargetPlatform pgtype.Text `json:"target_platform"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
PromptRuleID int64 `json:"prompt_rule_id"`
|
||||
BrandID pgtype.Int8 `json:"brand_id"`
|
||||
Name string `json:"name"`
|
||||
CronExpr string `json:"cron_expr"`
|
||||
WorkspaceID pgtype.Int8 `json:"workspace_id"`
|
||||
AutoPublish bool `json:"auto_publish"`
|
||||
PublishAccountIds []byte `json:"publish_account_ids"`
|
||||
CoverAssetUrl pgtype.Text `json:"cover_asset_url"`
|
||||
CoverImageAssetID pgtype.Int8 `json:"cover_image_asset_id"`
|
||||
StartAt pgtype.Timestamptz `json:"start_at"`
|
||||
EndAt pgtype.Timestamptz `json:"end_at"`
|
||||
NextRunAt pgtype.Timestamptz `json:"next_run_at"`
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error {
|
||||
@@ -263,7 +299,11 @@ func (q *Queries) UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTask
|
||||
arg.BrandID,
|
||||
arg.Name,
|
||||
arg.CronExpr,
|
||||
arg.TargetPlatform,
|
||||
arg.WorkspaceID,
|
||||
arg.AutoPublish,
|
||||
arg.PublishAccountIds,
|
||||
arg.CoverAssetUrl,
|
||||
arg.CoverImageAssetID,
|
||||
arg.StartAt,
|
||||
arg.EndAt,
|
||||
arg.NextRunAt,
|
||||
|
||||
Reference in New Issue
Block a user