addashboard-cli 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/ads.js +32 -3
- package/dist/commands/ads.js.map +1 -1
- package/dist/commands/submission.js +64 -19
- package/dist/commands/submission.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/apiClient.js +11 -0
- package/dist/lib/apiClient.js.map +1 -1
- package/dist/schemas/submit-plan.js +133 -0
- package/dist/schemas/submit-plan.js.map +1 -0
- package/package.json +4 -2
- package/skills/ad-ops/README.md +1 -0
- package/skills/ad-ops/SKILL.md +76 -62
- package/skills/ad-ops/ad-planner.html +718 -150
- package/skills/ad-ops//343/202/265/343/203/263/343/203/227/343/203/253/343/203/227/343/203/251/343/203/263.json +0 -4
- package/skills/ad-ops//343/202/265/343/203/263/343/203/227/343/203/253/343/203/227/343/203/251/343/203/263_meta.json +3 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitPlanSchema = exports.metaSubmitPlanSchema = exports.ydaSubmitPlanSchema = exports.planProgressSchema = void 0;
|
|
4
|
+
exports.formatPlanIssues = formatPlanIssues;
|
|
5
|
+
exports.parseSubmitPlan = parseSubmitPlan;
|
|
6
|
+
/**
|
|
7
|
+
* 入稿計画 JSON (planVersion:1) のスキーマ。
|
|
8
|
+
*
|
|
9
|
+
* プランナー (`skills/ad-ops/ad-planner.html` の `buildSubmitPlanWithStats`) が書き出し、
|
|
10
|
+
* `webgram submit-plan` が読む JSON の**唯一の契約**。型はここから `z.infer` で導出する。
|
|
11
|
+
*
|
|
12
|
+
* ⚠ backend の `backend/src/schemas/meta.ts` とは別リポジトリ扱い (cli は独立した npm パッケージで
|
|
13
|
+
* backend を import できない)。**backend 側の入稿スキーマを変えたらここも直す**。
|
|
14
|
+
*
|
|
15
|
+
* 厳しさの方針:
|
|
16
|
+
* - エンベロープ (planVersion / platform / accountId / campaigns) と**階層キー**は strict。
|
|
17
|
+
* ここがズレると「Meta なのに adGroups が入っている」類の事故になり、dry-run まで気づけない。
|
|
18
|
+
* - キャンペーン / 広告セット / 広告の**中身は passthrough**。backend がフィールドを足したときに
|
|
19
|
+
* CLI 側が古いだけで入稿できなくなるのを避ける (検証の主戦場は backend の zod)。
|
|
20
|
+
* - ただし「これが無いと入稿が必ず失敗する」キーだけは required にして手前で落とす。
|
|
21
|
+
*/
|
|
22
|
+
const zod_1 = require("zod");
|
|
23
|
+
/** 広告 (媒体共通の最低限)。媒体固有のキーは passthrough で素通しする。 */
|
|
24
|
+
const adSchema = zod_1.z
|
|
25
|
+
.object({
|
|
26
|
+
adName: zod_1.z.string().min(1, '広告名が空です'),
|
|
27
|
+
finalUrl: zod_1.z.string().min(1, '最終リンク先URLが空です'),
|
|
28
|
+
})
|
|
29
|
+
.passthrough();
|
|
30
|
+
/** YDA: campaigns[].adGroups[].ads[] */
|
|
31
|
+
const ydaAdGroupSchema = zod_1.z
|
|
32
|
+
.object({
|
|
33
|
+
name: zod_1.z.string().min(1, '広告グループ名が空です'),
|
|
34
|
+
ads: zod_1.z.array(adSchema),
|
|
35
|
+
})
|
|
36
|
+
.passthrough();
|
|
37
|
+
const ydaCampaignSchema = zod_1.z
|
|
38
|
+
.object({
|
|
39
|
+
name: zod_1.z.string().min(1, 'キャンペーン名が空です'),
|
|
40
|
+
adGroups: zod_1.z.array(ydaAdGroupSchema),
|
|
41
|
+
})
|
|
42
|
+
.passthrough();
|
|
43
|
+
/** Meta: campaigns[].adSets[].ads[] */
|
|
44
|
+
const metaAdSetSchema = zod_1.z
|
|
45
|
+
.object({
|
|
46
|
+
name: zod_1.z.string().min(1, '広告セット名が空です'),
|
|
47
|
+
ads: zod_1.z.array(adSchema),
|
|
48
|
+
})
|
|
49
|
+
.passthrough();
|
|
50
|
+
const metaCampaignSchema = zod_1.z
|
|
51
|
+
.object({
|
|
52
|
+
name: zod_1.z.string().min(1, 'キャンペーン名が空です'),
|
|
53
|
+
adSets: zod_1.z.array(metaAdSetSchema),
|
|
54
|
+
})
|
|
55
|
+
.passthrough();
|
|
56
|
+
/** 1 キャンペーンの入稿進捗 (計画ファイルに書き戻して再開可能にする)。 */
|
|
57
|
+
exports.planProgressSchema = zod_1.z.object({
|
|
58
|
+
index: zod_1.z.number().int(),
|
|
59
|
+
name: zod_1.z.string(),
|
|
60
|
+
/**
|
|
61
|
+
* `unknown` は「リクエストがタイムアウトして成否が判定できない」状態。
|
|
62
|
+
* **failed にしてはいけない**(再実行で同じキャンペーンをもう一度作る)。
|
|
63
|
+
*/
|
|
64
|
+
status: zod_1.z.enum(['pending', 'submitted', 'failed', 'unknown']),
|
|
65
|
+
campaignId: zod_1.z.string().nullable(),
|
|
66
|
+
error: zod_1.z.string().nullable(),
|
|
67
|
+
submittedAt: zod_1.z.string().nullable(),
|
|
68
|
+
targetErrors: zod_1.z.array(zod_1.z.string()).optional(),
|
|
69
|
+
});
|
|
70
|
+
const envelope = {
|
|
71
|
+
planVersion: zod_1.z.number().int(),
|
|
72
|
+
accountId: zod_1.z.string().min(1, 'accountId が空です'),
|
|
73
|
+
progress: zod_1.z.array(exports.planProgressSchema).optional(),
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* platform 未記載は yda 扱い (platform 導入前に書き出された計画ファイルとの後方互換)。
|
|
77
|
+
* 判別に使うのは platform であって階層キーではない — キーの取り違えを検出したいので、
|
|
78
|
+
* 「adSets が入っている yda プラン」はここで落ちるのが正しい。
|
|
79
|
+
*/
|
|
80
|
+
exports.ydaSubmitPlanSchema = zod_1.z.object({
|
|
81
|
+
...envelope,
|
|
82
|
+
platform: zod_1.z.literal('yda').optional(),
|
|
83
|
+
campaigns: zod_1.z.array(ydaCampaignSchema).min(1, '計画に campaigns がありません'),
|
|
84
|
+
});
|
|
85
|
+
exports.metaSubmitPlanSchema = zod_1.z.object({
|
|
86
|
+
...envelope,
|
|
87
|
+
platform: zod_1.z.literal('meta'),
|
|
88
|
+
campaigns: zod_1.z.array(metaCampaignSchema).min(1, '計画に campaigns がありません'),
|
|
89
|
+
});
|
|
90
|
+
exports.submitPlanSchema = zod_1.z.union([exports.metaSubmitPlanSchema, exports.ydaSubmitPlanSchema]);
|
|
91
|
+
/**
|
|
92
|
+
* zod のエラーを「どのキャンペーン・どの広告が壊れているか」が分かる1行に畳む。
|
|
93
|
+
* path をそのまま出すと `campaigns.0.adSets.1.ads.3.finalUrl` になり、
|
|
94
|
+
* 入稿計画を開いて数えないと当該行に辿り着けないため、日本語の位置に直す。
|
|
95
|
+
*/
|
|
96
|
+
function formatPlanIssues(error) {
|
|
97
|
+
return error.issues.slice(0, 20).map((i) => {
|
|
98
|
+
const where = i.path
|
|
99
|
+
.reduce((acc, seg, idx, arr) => {
|
|
100
|
+
if (typeof seg === 'number')
|
|
101
|
+
return acc;
|
|
102
|
+
const next = arr[idx + 1];
|
|
103
|
+
const label = seg === 'campaigns'
|
|
104
|
+
? 'キャンペーン'
|
|
105
|
+
: seg === 'adGroups'
|
|
106
|
+
? '広告グループ'
|
|
107
|
+
: seg === 'adSets'
|
|
108
|
+
? '広告セット'
|
|
109
|
+
: seg === 'ads'
|
|
110
|
+
? '広告'
|
|
111
|
+
: String(seg);
|
|
112
|
+
acc.push(typeof next === 'number' ? `${label}[${next + 1}]` : label);
|
|
113
|
+
return acc;
|
|
114
|
+
}, [])
|
|
115
|
+
.join(' > ');
|
|
116
|
+
return where ? `${where}: ${i.message}` : i.message;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 計画ファイルを検証する。失敗時は人が読める複数行のエラーを返す。
|
|
121
|
+
* union のエラーはそのままだと「どちらの媒体としても不正」が2重に出て読めないので、
|
|
122
|
+
* platform を先に見て単一スキーマで検証する。
|
|
123
|
+
*/
|
|
124
|
+
function parseSubmitPlan(raw) {
|
|
125
|
+
const platform = raw?.platform ?? 'yda';
|
|
126
|
+
if (platform !== 'yda' && platform !== 'meta') {
|
|
127
|
+
return { ok: false, errors: [`submit-plan は yda / meta のみ対応です (指定: ${String(platform)})`] };
|
|
128
|
+
}
|
|
129
|
+
const schema = platform === 'meta' ? exports.metaSubmitPlanSchema : exports.ydaSubmitPlanSchema;
|
|
130
|
+
const r = schema.safeParse(raw);
|
|
131
|
+
return r.success ? { ok: true, plan: r.data } : { ok: false, errors: formatPlanIssues(r.error) };
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=submit-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit-plan.js","sourceRoot":"","sources":["../../src/schemas/submit-plan.ts"],"names":[],"mappings":";;;AA2GA,4CAsBC;AAOD,0CAUC;AAlJD;;;;;;;;;;;;;;;GAeG;AACH,6BAAwB;AAExB,iDAAiD;AACjD,MAAM,QAAQ,GAAG,OAAC;KACf,MAAM,CAAC;IACN,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC;IACpC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC;CAC7C,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,wCAAwC;AACxC,MAAM,gBAAgB,GAAG,OAAC;KACvB,MAAM,CAAC;IACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC;IACtC,GAAG,EAAE,OAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;CACvB,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,MAAM,iBAAiB,GAAG,OAAC;KACxB,MAAM,CAAC;IACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC;IACtC,QAAQ,EAAE,OAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;CACpC,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,uCAAuC;AACvC,MAAM,eAAe,GAAG,OAAC;KACtB,MAAM,CAAC;IACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC;IACrC,GAAG,EAAE,OAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;CACvB,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,MAAM,kBAAkB,GAAG,OAAC;KACzB,MAAM,CAAC;IACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC;IACtC,MAAM,EAAE,OAAC,CAAC,KAAK,CAAC,eAAe,CAAC;CACjC,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,2CAA2C;AAC9B,QAAA,kBAAkB,GAAG,OAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;IAChB;;;OAGG;IACH,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC7D,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,YAAY,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC7C,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG;IACf,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC7B,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC;IAC9C,QAAQ,EAAE,OAAC,CAAC,KAAK,CAAC,0BAAkB,CAAC,CAAC,QAAQ,EAAE;CACjD,CAAC;AAEF;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1C,GAAG,QAAQ;IACX,QAAQ,EAAE,OAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACrC,SAAS,EAAE,OAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;CACrE,CAAC,CAAC;AAEU,QAAA,oBAAoB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,GAAG,QAAQ;IACX,QAAQ,EAAE,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC3B,SAAS,EAAE,OAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;CACtE,CAAC,CAAC;AAEU,QAAA,gBAAgB,GAAG,OAAC,CAAC,KAAK,CAAC,CAAC,4BAAoB,EAAE,2BAAmB,CAAC,CAAC,CAAC;AAQrF;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,KAAiB;IAChD,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACzC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI;aACjB,MAAM,CAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YACvC,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,OAAO,GAAG,CAAC;YACxC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YAC1B,MAAM,KAAK,GACT,GAAG,KAAK,WAAW;gBACjB,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,GAAG,KAAK,UAAU;oBAClB,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,GAAG,KAAK,QAAQ;wBAChB,CAAC,CAAC,OAAO;wBACT,CAAC,CAAC,GAAG,KAAK,KAAK;4BACb,CAAC,CAAC,IAAI;4BACN,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrE,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC;aACL,IAAI,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAC7B,GAAY;IAEZ,MAAM,QAAQ,GAAI,GAAqC,EAAE,QAAQ,IAAI,KAAK,CAAC;IAC3E,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC9C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,wCAAwC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9F,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,4BAAoB,CAAC,CAAC,CAAC,2BAAmB,CAAC;IAChF,MAAM,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;AACnG,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "addashboard-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "webgram CLI — ad-dashboard (https://macchiato.site) を Claude Code / Codex CLI から操作するための CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"webgram": "./dist/index.js"
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc",
|
|
38
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
38
39
|
"dev": "tsx src/index.ts",
|
|
39
40
|
"start": "node dist/index.js",
|
|
40
41
|
"test": "vitest run",
|
|
@@ -46,7 +47,8 @@
|
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"axios": "^1.7.7",
|
|
49
|
-
"commander": "^12.1.0"
|
|
50
|
+
"commander": "^12.1.0",
|
|
51
|
+
"zod": "4.4.3"
|
|
50
52
|
},
|
|
51
53
|
"devDependencies": {
|
|
52
54
|
"@playwright/test": "1.61.1",
|
package/skills/ad-ops/README.md
CHANGED
|
@@ -24,6 +24,7 @@ ad-dashboard (`https://macchiato.site`) の webgram CLI を Claude Code / Codex
|
|
|
24
24
|
|
|
25
25
|
- アカウント参照データ: `アカウント/<platform>/<名前>.json`(`アカウント/yda/` / `アカウント/meta/`)
|
|
26
26
|
- Meta は入稿前に **accountId(`act_` 付き) / FBページID / pixelId / CVイベント** が必須(未入力は書き出しブロック)
|
|
27
|
+
- この ID は `list --platform meta --resource pixels --account-id act_<ID>` / `--resource pages` / `--resource instagram-accounts` で取得する(`pages` は `--account-id` 不要 / `instagram-accounts` は任意だが原則指定する)
|
|
27
28
|
- **Meta の本番入稿 PoC は未実施** — 初回は配信オフ (`PAUSED`)・1 キャンペーン・最小予算から
|
|
28
29
|
|
|
29
30
|
## 利用者の初回セットアップ
|
package/skills/ad-ops/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ad-ops
|
|
3
|
-
description: ad-dashboard (https://macchiato.site) の webgram CLI 経由で広告を YDA / Meta に半自動入稿する (TikTok は将来対応予定)
|
|
3
|
+
description: ad-dashboard (https://macchiato.site) の webgram CLI 経由で広告を YDA / Meta に半自動入稿する (TikTok は将来対応予定)。発火したら「入稿先アカウント&媒体」→「今回の方式 (HTMLプランナーで手動指定=既定 / 前回の入稿計画を参考にする / チャットで1つずつ聞く)」の順に確定させる。入稿の実体は 2 系統 — 動画・ローカル画像の API 入稿フロー (固定デフォルト + URL 空き番号自動割当 + 一覧 OK 確認、現状 YDA) と、入稿プランナー `ad-planner.html` (YDA / Meta を案件×媒体の統合プルダウンで切替する GUI → 入稿計画JSON → `submit-plan` で dry-run → 本実行)。「広告運用」「広告入稿」「動画入稿」「まとめ入稿」「ASC 入稿」「YDA 入稿」「Meta 入稿」「入稿プランナー」「YDA入稿プランナー」「Meta入稿プランナー」「入稿シート」「TikTok 入稿」「webgram」「ad-dashboard」と言われたら使用。Node.js が入っていれば追加インストール不要 (`npx` 経由)。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# ad-ops skill (広告運用スキル)
|
|
@@ -55,19 +55,39 @@ skills/ad-ops/scripts/adops.sh preflight yda <accountId>
|
|
|
55
55
|
> 全件パスしたが、`list accounts` が返す 17 件に含まれておらず本実行で 401。
|
|
56
56
|
> フェーズ1〜3 の作業がすべて無駄になった。
|
|
57
57
|
|
|
58
|
-
##
|
|
58
|
+
## 【必須】入口: アカウント&媒体 → 今回の方式
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
**本スキルは広告入稿の専用スキル**。発火したら `preflight` → **入稿先アカウント&媒体** → **今回の方式** の順で確定させ、対応するフローへ入る。用途を4択で聞く旧メニューは廃止した(実運用がほぼ入稿なので毎回の無駄だった)。
|
|
61
|
+
|
|
62
|
+
### 入口ステップ1: 入稿先アカウント & 媒体の決定
|
|
63
|
+
|
|
64
|
+
* **`preflight` は全分岐の共通の前提**。落ちたら分岐せずその場で止めて報告する
|
|
65
|
+
* `AskUserQuestion` で **案件 × 媒体**を選ばせる。選択肢は `アカウント/<platform>/index.json`(プランナーのヘッダー統合プルダウン `#accSelect` と同じ母集団)から作り、`webgram list accounts` の結果と突き合わせる
|
|
66
|
+
* **【必須】`list accounts` に無い ID は本実行で 401 になり、dry-run は通ってしまう**(冒頭の失敗例を参照)。**ここで弾いて先に進ませない**
|
|
67
|
+
* ユーザーの依頼にアカウント名・媒体が明示されていれば、確認を省いて既定として提示してよい
|
|
68
|
+
* ここで決まった `platform` / アカウント名は**以降の全分岐で使い回す。下流で再度聞かない**(旧 Step 3 の「入稿先アカウント名」はこのステップに前倒しした)
|
|
69
|
+
|
|
70
|
+
### 入口ステップ2: 今回の方式(3択)
|
|
71
|
+
|
|
72
|
+
* **提示条件**: ユーザーの発話に入稿パラメータ(予算・CTA・tCPA・配信開始日時・キャンペーン名など)も方式の明示も無いときだけ `AskUserQuestion` を出す。明示があればスキップして該当フローへ直行する
|
|
61
73
|
|
|
62
74
|
| 選択肢 | 遷移先 |
|
|
63
75
|
|---|---|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
76
|
+
| **HTMLプランナーで手動指定(既定)** | ステップ1の結果を渡して `adops.sh planner --platform <pf> --account "<名前>"` を起動 → 「入稿プランナー」起点フロー(4フェーズ)。以降のパラメータは GUI で決めるので個別に聞かない |
|
|
77
|
+
| 前回の入稿計画を参考にする | 下の「直近プラン採用ロジック」→ 引き継ぎ値を提示して差分だけ確認 → 動画/画像入稿フロー Step 4(一覧提示+OK 確認)へ |
|
|
78
|
+
| チャットで1つずつ聞く | 動画入稿フロー Step 1〜6 / 画像入稿フロー Step 1〜6 |
|
|
79
|
+
|
|
80
|
+
* 「チャットで1つずつ聞く」の**動画/画像の振り分けは素材パスの拡張子で判定する**(`.mp4` 等 → 動画 / `.jpg` `.jpeg` `.png` `.gif` → 画像)。素材が未提示なら `AskUserQuestion` でパス提示を促す(Step 1 の手順をそのまま使う)
|
|
68
81
|
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
### 直近プラン採用ロジック(「前回の入稿計画を参考にする」を選んだとき)
|
|
83
|
+
|
|
84
|
+
1. `入稿計画/` 配下を、**ステップ1で決めた案件×媒体アカウント**で絞り込む。判定は JSON 内の `platform` と `campaigns[].accountId`(Meta は `act_` 付き)を正とし、ファイル名は候補の絞り込み補助にとどめる
|
|
85
|
+
2. タイムスタンプ降順で **最新1件を自動採用**し、**採用したファイルパスをユーザーに提示する**
|
|
86
|
+
3. 該当が 0 件なら、その旨を伝えて「チャットで1つずつ聞く」にフォールバックする
|
|
87
|
+
4. **引き継ぐのは入稿パラメータだけ**(予算 / CTA / アトリビューション / tCPA・入札戦略 / ターゲティング / 配信日時)。**クリエイティブ(mediaId・画像/動画パス)・キャンペーン名・URL 末尾番号は引き継がない** — 毎回新規なので、URL 空き番号の自動割当と CP 名の自動生成(Step 3 のルール)で採り直す
|
|
88
|
+
5. 引き継いだ値を一覧で提示し、**変更点を 1 問で聞く**。以降は Step 4(一覧提示 → OK 確認・必須)へ合流する
|
|
89
|
+
|
|
90
|
+
* **【必須】これはパラメータの初期値として読むだけ。** 過去の入稿計画JSONの存在を**入稿済み・フェーズ完了の根拠にしてはならない**(後述の同名ガードを参照)
|
|
71
91
|
|
|
72
92
|
## 動画入稿フロー (メイン用途)
|
|
73
93
|
|
|
@@ -114,14 +134,32 @@ npx -y addashboard-cli@latest auth whoami
|
|
|
114
134
|
|
|
115
135
|
* **スマートターゲティング: 常時 ON** (backend 側の既定も `true`。明示的に OFF にしたい場合だけユーザーに確認する)
|
|
116
136
|
|
|
137
|
+
* **配信開始日時: 翌日 05:00** (プランナーで空欄のときの既定。**YDA は Yahoo Ads API の `startDate` が日付のみなので実際に効くのは「翌日」まで**で、05:00 は載らない)
|
|
138
|
+
|
|
117
139
|
**必ずユーザー確認 or 自動生成が必要な項目**:
|
|
118
140
|
|
|
119
|
-
* **入稿先アカウント名**:
|
|
141
|
+
* **入稿先アカウント名**: **入口ステップ1 で確定済み**。ここで再度聞かない (アカウント名で指定可。アカウント ID は不要、CLI 側で名前 → ID 解決)
|
|
120
142
|
|
|
121
143
|
* **入稿リンク (URL 末尾番号)**: 既存アカウントの入稿履歴から使用済み番号を取得し、**未使用の空き番号を自動割当**
|
|
122
144
|
|
|
123
145
|
* 連番でなくて OK。被らないことだけ守る (例: 1〜50 が使用中なら 51 以降、または途中の 7 が未使用なら 7)
|
|
124
146
|
|
|
147
|
+
* **【必須】「使用済み」は媒体側で配信中 (ACTIVE) のものだけ。配信停止 (PAUSED / 配信オフ) のキャンペーン・広告が使っている番号は「未使用」として扱い、再利用の候補に入れる**
|
|
148
|
+
|
|
149
|
+
* 判定材料は `webgram list --platform <媒体> --resource campaigns` が返す `status` (アカウントJSONの `refs.campaigns[].status` にも入る)
|
|
150
|
+
* **status が取れなかった媒体・アカウントでは従来どおり全件を使用済みとして扱い、「オフ判定ができなかった」ことをユーザーに明示する。** 勝手に空き扱いにしない
|
|
151
|
+
* **番号の持ち主 (キャンペーン名 / 広告名) と配信状態をセットで確認してから再利用する。** オフでも再開予定のものがあり得る
|
|
152
|
+
|
|
153
|
+
* **【必須】番号を決める前に AskUserQuestion で採番方針を選ばせる**(既定は「オフの中での MAX」)
|
|
154
|
+
|
|
155
|
+
| 選択肢 | 挙動 |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| オフの中での MAX (既定) | 配信停止番号のうち最大のものを再利用する |
|
|
158
|
+
| オフの中での MIN | 配信停止番号のうち最小のものを再利用する |
|
|
159
|
+
| オフを含めた未使用番号全体の MIN | 欠番 + 配信停止番号をすべて未使用とみなし、その最小を使う |
|
|
160
|
+
|
|
161
|
+
* 選択後、判定に使った **使用済み (ACTIVE) 番号一覧 / オフ番号一覧 / 割り当てた番号** を Step 4 の確認表の直前に提示する
|
|
162
|
+
|
|
125
163
|
* ベース URL は案件ごとに固定 (Bit.ly 系ドメイン等)。末尾パラメータ番号のみ可変
|
|
126
164
|
|
|
127
165
|
* 案件ごとの URL 一覧はシート管理されているので、そこから引く運用も可
|
|
@@ -139,6 +177,9 @@ npx -y addashboard-cli@latest auth whoami
|
|
|
139
177
|
| 1 | YDA | video\_A.mp4 | 07\_video\_A\_2026-07-16 | <https://.../?p=07> | 12,000 | tCPA 8,500 |
|
|
140
178
|
| 2 | YDA | video\_B.mp4 | 08\_video\_B\_2026-07-16 | <https://.../?p=08> | 12,000 | tCPA 8,500 |
|
|
141
179
|
|
|
180
|
+
**表の直前に、URL 末尾番号の根拠を出す**: 採番方針 / 使用済み (ACTIVE) 番号 / オフ (PAUSED) 番号 / 割り当てた番号。
|
|
181
|
+
オフ判定ができなかった場合はその旨も書く。
|
|
182
|
+
|
|
142
183
|
URL 番号・予算・配信戦略に不満があれば Step 3 に戻ってパラメータを差し替える。
|
|
143
184
|
|
|
144
185
|
### Step 5: 順次実行
|
|
@@ -278,7 +319,8 @@ skills/ad-ops/scripts/adops.sh open yda <accountId> campaigns
|
|
|
278
319
|
| 汎用入稿 (JSON) 実入稿 | `npx -y addashboard-cli@latest submit --platform <媒体> --json-file <path> --no-dry-run --yes` |
|
|
279
320
|
| 入稿計画 順次入稿 dry-run | `npx -y addashboard-cli@latest submit-plan --plan-file <入稿計画.json>`(yda / meta。`plan.platform` 未記載は yda 扱い) |
|
|
280
321
|
| 入稿計画 順次入稿 実入稿 | `npx -y addashboard-cli@latest submit-plan --plan-file <入稿計画.json> --no-dry-run --yes`(1CPずつ・再開可能) |
|
|
281
|
-
|
|
322
|
+
|
|
323
|
+
**【重要】本実行がタイムアウトしたら「失敗」と決めつけない。** CLI の進捗は `unknown`(成否不明)になる。backend は入稿を続けており、**キャンペーンと広告が作成済みのことがある**(実測あり)。この状態で再実行すると二重入稿になるため `unknown` は自動でスキップされる。媒体の管理画面を確認し、作成済みなら計画ファイルの `status` を `"submitted"`、未作成なら `"pending"` に直してから再実行する(exit code は 3)。
|
|
282
324
|
| 「予実」「予実管理」「今月の予実」「着地予測」「予実サマリ」 | `npx -y addashboard-cli@latest pl summary`(月指定は `pl summary --month YYYY-MM`) |
|
|
283
325
|
| 「案件別の予実」「案件ごとの損益」 | `npx -y addashboard-cli@latest pl projects`(`--month` / `--status` / `--platform` で絞り込み可) |
|
|
284
326
|
|
|
@@ -288,47 +330,6 @@ skills/ad-ops/scripts/adops.sh open yda <accountId> campaigns
|
|
|
288
330
|
|
|
289
331
|
***
|
|
290
332
|
|
|
291
|
-
## チーム週次レビュー取得(review コマンド)
|
|
292
|
-
|
|
293
|
-
チーム × 週で **全案件の週次レビュー(課題・今週のアクションプラン)を 1 回でまとめて取得** し、LLM(このセッション)が案件ごとに要約するためのコマンド。CLI の役割は JSON 取得までで、要約は LLM が行う。
|
|
294
|
-
|
|
295
|
-
### 自然言語 → コマンド マッピング
|
|
296
|
-
|
|
297
|
-
以下のような依頼で発火する:
|
|
298
|
-
|
|
299
|
-
- 「伊藤T(松井T)の先週の課題とアクションプラン(を案件ごとに要約して)」
|
|
300
|
-
- 「チームの週次レビュー(を見せて/まとめて)」
|
|
301
|
-
- 「先週の課題まとめ」「先週のアクションプランまとめ」
|
|
302
|
-
|
|
303
|
-
→ 実行するコマンド(**先週がデフォルト**):
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
npx -y addashboard-cli@latest review --team 伊藤T
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
特定週を指定する場合は、その週の月曜(JST)を `--week` で渡す:
|
|
310
|
-
|
|
311
|
-
```bash
|
|
312
|
-
npx -y addashboard-cli@latest review --team 松井T --week 2026-07-13
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
- `--team` は `伊藤T` または `松井T` のいずれか(必須)
|
|
316
|
-
- `--week` 省略時は **先週の月曜(JST)** を自動採用(例: 実行日が 2026-07-23(水) なら 2026-07-13)
|
|
317
|
-
- 出力は JSON(`team` / `weekStart` / `teamProjectCount` / `reviewCount` / `reviews[]`)
|
|
318
|
-
|
|
319
|
-
### 結果の要約(LLM 側の必須整形)
|
|
320
|
-
|
|
321
|
-
`review` の JSON は **そのまま貼らない**。案件ごとに次の形で要約する:
|
|
322
|
-
|
|
323
|
-
- **案件名(clientName / platform があれば併記)**
|
|
324
|
-
- 課題: `issue` を要約
|
|
325
|
-
- 今週のアクションプラン: `thisWeekPlan` を要約
|
|
326
|
-
- 数値実績(`actualCpa` / `actualCtr` / `actualCvr` 等)があれば補足。目標(`goalCpa` 等)と併記できると良い
|
|
327
|
-
|
|
328
|
-
冒頭または末尾で **`reviewCount`(レビュー記入のあった案件数)/ `teamProjectCount`(チームの総案件数)** に触れ、「N 件中 M 件にレビュー記入あり」といった全体像を示す。`reviews` が空(`reviewCount: 0`)の場合は「該当週の週次レビュー記入はありませんでした」と伝える。
|
|
329
|
-
|
|
330
|
-
***
|
|
331
|
-
|
|
332
333
|
## 入稿プランナー(YDA / Meta 媒体切替・JSON入稿)
|
|
333
334
|
|
|
334
335
|
動画の API 入稿とは別に、**一括入稿を計画・確認する**ためのシングルHTMLツール。2026-07-16 / 07-21 定例フィードバックを反映。**2026-07-23 に CSV 書き出しを廃止し、保存・入稿受け渡しを JSON に統一**。**2026-07-30 に媒体スキーマ駆動化(`PLATFORMS` レジストリ)して Meta に対応**。
|
|
@@ -350,10 +351,10 @@ npx -y addashboard-cli@latest review --team 松井T --week 2026-07-13
|
|
|
350
351
|
| クリエイティブ形式 | 画像のみ(Card 1200 / SQ 1080 の mediaID) | **画像(imageHash)/動画(videoId + サムネ imageHash)両対応**(広告行の形式列 IMAGE / VIDEO) |
|
|
351
352
|
| 参照データ (`refs.media`) | `{card, sq}` | `{image, video, thumb}` |
|
|
352
353
|
| プロジェクト必須項目 | accountId / 目的(goal) / 配信開始日 / 入札 | accountId(`act_`) / **FBページID** / **pixelId**(`OFFSITE_CONVERSIONS`/`VALUE` 時) / CVイベント / 最適化 / 課金 / 入札戦略 / 配信開始日(配信終了日は任意) |
|
|
353
|
-
| 配信期間の指定階層 | 案件設定チップのみ(配信開始日) | **広告セット行の列 → 案件設定チップ →
|
|
354
|
+
| 配信期間の指定階層 | 案件設定チップのみ(配信開始日) | **広告セット行の列 → 案件設定チップ → 既定(翌日 05:00)** の順で解決。**時刻も指定可**(`YYYY-MM-DD [HH:mm[:ss]]`・JST) |
|
|
354
355
|
| 入札 | 最大配信 / tCPA(`MAXIMIZE_CONVERSIONS`+targetCpa) | `LOWEST_COST_WITHOUT_CAP` / `LOWEST_COST_WITH_BID_CAP` / `COST_CAP` / `LOWEST_COST_WITH_MIN_ROAS`(後2者は `bidAmount` 必須) |
|
|
355
356
|
| ターゲティング列 | 年齢 / 性別 / デバイス / 曜日時間帯 / **オーディエンス(含む・除外)** / **配置(含む・除外)** / 地域・サーチKW。**オーディエンス・配置は参照表の実IDで入稿JSONに載り、本番の配信ターゲティングに反映される**(数値IDでない値は落として警告)。**入稿JSONに載らないのは 地域 と サーチKW だけ** | 年齢(ageMin/ageMax) / 性別 / デバイス / 配置(Facebook / Instagram / Audience Network / Messenger、既定は自動配置) |
|
|
356
|
-
| 命名規則 | `{番号}{c\|s}-{見出し}L{本文}-{paramCode}` / `?ad=&creative=` | **同形式を踏襲**(形式記号は `i`(画像) / `v`(動画)
|
|
357
|
+
| 命名規則 | `{番号}{c\|s}-{見出し}L{本文}-{paramCode}` / `?ad=&creative=` | **同形式を踏襲**(形式記号は `i`(画像) / `v`(動画))。**最終URLは `{記事URL}?ad={paramCode}` のみ**(`creative=` もパス連結もしない)。paramCode は**広告行 > 広告セット**の実効値 |
|
|
357
358
|
| 手入稿の除外 | バナー(固定サイズ)は API 未対応 → `手入稿` フラグで入稿JSONから除外 | 手入稿フラグの区分は無し(未解決の広告のみ除外) |
|
|
358
359
|
| 管理画面 | `https://ads.yahoo.co.jp/manager/#/{mccId}/{accountId}/list/campaigns`(**CP詳細への直リンクは不可**) | `adsmanager.facebook.com/adsmanager/manage/campaigns?act=<数値>` |
|
|
359
360
|
|
|
@@ -488,14 +489,27 @@ npx -y addashboard-cli@latest list --platform yda --resource ads \
|
|
|
488
489
|
|
|
489
490
|
#### Meta の初回セットアップ(`アカウント/meta/<名前>.json`)
|
|
490
491
|
|
|
491
|
-
1. アカウントを特定: `webgram list --platform meta --resource accounts` → 対象の **accountId(`act_` 付き)**
|
|
492
|
-
2.
|
|
492
|
+
1. アカウントを特定: `webgram list --platform meta --resource accounts` → 対象の **accountId(`act_` 付き)** を確定。
|
|
493
|
+
2. **入稿アセットID(FBページID / pixelId / IGユーザーID)を取得する**:
|
|
494
|
+
```bash
|
|
495
|
+
npx -y addashboard-cli@latest list --platform meta --resource pixels --account-id act_<ID> # pixelId(アカウント配下)
|
|
496
|
+
npx -y addashboard-cli@latest list --platform meta --resource pages # FBページID
|
|
497
|
+
npx -y addashboard-cli@latest list --platform meta --resource instagram-accounts --account-id act_<ID> # IGユーザーID
|
|
498
|
+
```
|
|
499
|
+
* **`pages` は `--account-id` を取らない**。`act_<ID>/promote_pages` は 200 を返すが常に 0 件で、ページはビジネスマネージャ配下でしか引けないため、トークンから見える全ページを返す。
|
|
500
|
+
* **【最重要】一覧に出る ≠ そのページで入稿できる。** 各行の **`canAdvertise`**(`tasks` に `ADVERTISE` を含むか)を見て、**`true` のページだけを使う**。`false` のページを指定すると入稿の広告作成で `code 10 / subcode 3858749`「ページに投稿するには広告主の役割以上のアクセス許可が必要」で落ちる(キャンペーンと広告セットだけ作られて残る)。
|
|
501
|
+
実測(2026-08-16)では 62 件中 `canAdvertise: true` は **`source` に `me` を含む 9 件だけ**で、`owned` / `client` 由来の 53 件はすべて false だった。使いたいページが false のときは、Meta Business でそのページへ広告主以上の役割を付与してもらう必要がある。
|
|
502
|
+
* **`instagram-accounts` の `--account-id` は任意**。指定すると広告アカウント配下(`act_<ID>/instagram_accounts`)も併せて引く。**アカウントによって「act_ 配下にだけ出る / business 配下にだけ出る」が分かれる**ので、原則は指定する。
|
|
503
|
+
* **ページ紐付け型の IG は現状どの経路でも引けない**(トークンに `pages_read_engagement` が無いため)。既存広告が使っている IG が一覧に出ない場合はこれ。既存キャンペーンを `campaign-import` して実際の `instagramUserId` を写すか、管理画面から拾う。
|
|
504
|
+
* `pages` の各行の `source` は取得経路(`me` = トークン所有ユーザーが管理 / `owned` = BM所有 / `client` = BMのクライアント)。どれを使うかは案件で決める。
|
|
505
|
+
* 一覧が多い場合は名前で絞り込んで対象を特定する。判断がつかない場合のみ Meta Business 管理画面で照合する。
|
|
506
|
+
3. クリエイティブ参照を取り込む:
|
|
493
507
|
```bash
|
|
494
508
|
npx -y addashboard-cli@latest list --platform meta --resource image-library --account-id act_<ID> # imageHash
|
|
495
509
|
npx -y addashboard-cli@latest list --platform meta --resource video-library --account-id act_<ID> # videoId
|
|
496
510
|
npx -y addashboard-cli@latest list --platform meta --resource campaigns --account-id act_<ID> # 既存CP/広告セット
|
|
497
511
|
```
|
|
498
|
-
|
|
512
|
+
4. 取得結果を下記スキーマに整形して `アカウント/meta/<アカウント名>.json` へ保存する(雛形は同梱の `アカウント/meta/sample_account.json`):
|
|
499
513
|
```json
|
|
500
514
|
{
|
|
501
515
|
"accountJsonVersion": 1,
|
|
@@ -515,7 +529,7 @@ npx -y addashboard-cli@latest list --platform yda --resource ads \
|
|
|
515
529
|
}
|
|
516
530
|
}
|
|
517
531
|
```
|
|
518
|
-
|
|
532
|
+
5. プランナーの「+新規追加 → 📄 ファイルから追加」または「📁 フォルダ」再接続で一覧に出る。
|
|
519
533
|
|
|
520
534
|
**プランナー内の「❓使い方」ボタンから、この取込プロンプト(媒体別の文言)をコピーできる**ので、AI に貼るだけでも進められる。
|
|
521
535
|
|
|
@@ -528,7 +542,7 @@ npx -y addashboard-cli@latest list --platform yda --resource ads \
|
|
|
528
542
|
| **pixelId** | `optimizationGoal` が **`OFFSITE_CONVERSIONS` / `VALUE`** の場合は公式必須(`promoted_object`)。未入力は書き出しブロック(backend 側も 400 を返す) |
|
|
529
543
|
| **customEventType(CVイベント)** | `promoted_object` の CV イベント(既定 `PURCHASE`) |
|
|
530
544
|
| `bidAmount` | 入札戦略が `COST_CAP` / `LOWEST_COST_WITH_BID_CAP` のときのみ必須 |
|
|
531
|
-
| `instagramUserId` | 任意(Instagram
|
|
545
|
+
| `instagramUserId` | 任意(Instagram 配置を使う場合に指定)。`list --resource instagram-accounts --account-id act_<ID>` で取得できる(ページ紐付け型は引けないので既存CPのインポート値を使う) |
|
|
532
546
|
|
|
533
547
|
### 入稿手順(YDA):未知の画像・キャンペーン/広告グループは先に登録
|
|
534
548
|
|
|
@@ -544,7 +558,7 @@ npx -y addashboard-cli@latest list --platform yda --resource ads \
|
|
|
544
558
|
|
|
545
559
|
### 入稿手順(Meta)
|
|
546
560
|
|
|
547
|
-
1. **プランナーで計画**: ヘッダーの統合プルダウンで **`<案件名> Meta`** を選ぶ(`アカウント/meta/<名前>.json` 未整備なら先に上記セットアップ)。キャンペーン > 広告セット > 広告を作り、共通設定チップで FBページID / pixelId / CVイベント / 最適化 / 課金 / 入札戦略 / 配信開始日 / 配信終了日(任意・空欄なら無期限)を確定する。**配信日時は広告セット行の列でも個別に上書きできる**(優先順位: 広告セット行 > 案件設定チップ >
|
|
561
|
+
1. **プランナーで計画**: ヘッダーの統合プルダウンで **`<案件名> Meta`** を選ぶ(`アカウント/meta/<名前>.json` 未整備なら先に上記セットアップ)。キャンペーン > 広告セット > 広告を作り、共通設定チップで FBページID / pixelId / CVイベント / 最適化 / 課金 / 入札戦略 / 配信開始日 / 配信終了日(任意・空欄なら無期限)を確定する。**配信日時は広告セット行の列でも個別に上書きできる**(優先順位: 広告セット行 > 案件設定チップ > 既定=翌日05:00)。書式は `YYYY-MM-DD` または `YYYY-MM-DD HH:mm[:ss]`(**JST**)で、時刻を省くと開始は `00:00:00` / 終了は `23:59:59` になる。
|
|
548
562
|
- **既知の制約**: 解決は「行が空ならチップを継承」なので、**チップに終了日が入っているとき、特定の広告セットだけを無期限にすることはできない**。混在させたい場合はチップの終了日を空にし、期限を付けたい広告セット行だけに終了日時を入れる。
|
|
549
563
|
2. **入稿JSON書き出し**: ワンクリックで `<案件名>_Meta入稿計画_<日時>.json`(`planVersion:1`、`platform:"meta"`)を出力。`act_` 形式違反・FBページID 未入力・(`OFFSITE_CONVERSIONS`/`VALUE` 時の)pixelId 未入力・0件 は**書き出しをブロック**する。
|
|
550
564
|
3. **dry-run で一括検証**:
|
|
@@ -569,7 +583,7 @@ npx -y addashboard-cli@latest list --platform yda --resource ads \
|
|
|
569
583
|
- **入稿JSON書き出し**: 設定ダイアログなしの**ワンクリック**。参照未解決の広告は自動除外、accountId 未入力・0件なら書き出し中止(空入稿防止)。媒体別の中身:
|
|
570
584
|
- **YDA(見出し・本文の空欄許容)**: **タイトル番号 / 説明文番号は空欄でよい**(見出し・本文を使わない広告のケース)。空欄の広告はエラーにならず、`headlines` / `descriptions` は**空配列**で書き出され、backend も空を受理する。**空を許容するのはこの2フィールドのみ**(画像番号 `imageNo`・`paramCode`・principal・finalUrl は従来どおり必須)。**番号を入れたのに参照表(refs.titles / refs.descriptions)に無い場合は従来どおり「未解決」エラー**で、その広告は書き出しから除外される(別の障害なので緩めない)。Meta は従来どおり見出し・本文とも必須。
|
|
571
585
|
- **YDA**: アカウントID・目的(goal)・配信開始日は案件設定チップ、入札はキャンペーン行(tCPA→`MAXIMIZE_CONVERSIONS`+targetCpa)、ターゲティングは広告グループ行の列(日本語ラベル→API enum 自動変換)から `*_入稿計画_*.json`(planVersion:1、広告は IMAGE 形式: mediaIds/headlines/descriptions/principal)を生成。手入稿バナーも自動除外。
|
|
572
|
-
- **Meta**: 予算は広告セット行(CBO は使わない)、目的は `objective`、最適化/課金/入札戦略/pixel/CVイベント/FBページID は案件設定チップ、ターゲティング(年齢・性別・デバイス・配置)は広告セット行の列から `*_Meta入稿計画_*.json`(planVersion:1、`platform:"meta"`、`campaigns[].adSets[]`、広告は IMAGE / VIDEO)を生成。`act_` 形式違反・FBページID 未入力・pixelId 必須ケースの未入力でブロック。 **配信日時(`startTime` / `endTime`)は広告セットごとに解決される(広告セット行 > 案件設定チップ >
|
|
586
|
+
- **Meta**: 予算は広告セット行(CBO は使わない)、目的は `objective`、最適化/課金/入札戦略/pixel/CVイベント/FBページID は案件設定チップ、ターゲティング(年齢・性別・デバイス・配置)は広告セット行の列から `*_Meta入稿計画_*.json`(planVersion:1、`platform:"meta"`、`campaigns[].adSets[]`、広告は IMAGE / VIDEO)を生成。`act_` 形式違反・FBページID 未入力・pixelId 必須ケースの未入力でブロック。 **配信日時(`startTime` / `endTime`)は広告セットごとに解決される(広告セット行 > 案件設定チップ > 既定=翌日05:00)。入力は `YYYY-MM-DD [HH:mm[:ss]]`・JST 前提で、書き出し時に `+0900` 付き ISO8601 に正規化される(時刻を明示した場合は 23:59:59 に丸めずその時刻を尊重)。`startTime` は常に送り、配信終了日が空欄なら `endTime` キー自体を送らない(無期限配信)。`lifetimeBudget` 指定時に限り backend が配信開始日+30日を補完する。**
|
|
573
587
|
|
|
574
588
|
### 量産構造(媒体要件の核)
|
|
575
589
|
|
|
@@ -587,7 +601,7 @@ npx -y addashboard-cli@latest list --platform yda --resource ads \
|
|
|
587
601
|
|
|
588
602
|
- 「**ローカル画像で入稿**」「**この画像で入稿して**」「画像パスを渡された(ドラッグ&ドロップされた)」ときは、**入口メニューの『ローカル画像で入稿する』へ分岐**し、「画像入稿フロー(ローカル画像・YDA)」を Step 0 から進める。プランナーは開かない。
|
|
589
603
|
- 「入稿プランナー」「YDA入稿プランナー」「入稿シート」「タイトル/画像一覧」「まとめ入稿の確認用シート」等を求められたら、**`adops.sh planner` で開く**(`open <path>` は使わない。`file://` だとプランが読み込まれず空の画面になる)。**媒体が明示されていなければどちらの媒体か確認**し、開いたあとヘッダーの統合プルダウン(案件 × 媒体)で切替えるよう伝える。
|
|
590
|
-
- 「**Meta入稿プランナー**」「Meta のまとめ入稿」等と言われたら、同じ `ad-planner.html` を `adops.sh planner` で開いて **統合プルダウンで `<案件名> Meta` に切替**するよう案内する。アカウント参照データ(`アカウント/meta/<名前>.json`)が無ければ**先に初回セットアップ**(`list --platform meta --resource image-library|video-library|campaigns` で取り込み)へ誘導する。**FBページID / pixelId / CV
|
|
604
|
+
- 「**Meta入稿プランナー**」「Meta のまとめ入稿」等と言われたら、同じ `ad-planner.html` を `adops.sh planner` で開いて **統合プルダウンで `<案件名> Meta` に切替**するよう案内する。アカウント参照データ(`アカウント/meta/<名前>.json`)が無ければ**先に初回セットアップ**(`list --platform meta --resource pixels|pages|instagram-accounts|image-library|video-library|campaigns` で取り込み)へ誘導する。**FBページID / pixelId / CVイベント**が未確定なら、`list --resource pages|pixels` で候補を出して確定させる(IG は `--resource instagram-accounts --account-id act_<ID>`)(書き出しがブロックされる旨も先に伝える)。
|
|
591
605
|
- 入稿計画JSONは書き出し後 `webgram submit-plan --plan-file <入稿計画.json>` で **dry-run一括検証 → `--no-dry-run --yes` 本実行** にかける(1CPずつ・進捗書き戻しで途中失敗後も再開可、`submitted` 済みはスキップ)。`plan.platform` で YDA / Meta が自動判別される(未記載は yda 扱い)。
|
|
592
606
|
- **Meta は本番PoC 未実施**なので、実入稿を頼まれたら「配信オフ(PAUSED)・1キャンペーン・最小予算から」を必ず提案してから進める。
|
|
593
607
|
|