@getvitops/create 0.6.0 → 0.8.0-alpha.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/CHANGELOG.md +178 -5
- package/package.json +2 -2
- package/templates/emdash/.agents/skills/setup/SKILL.md +61 -0
- package/templates/emdash/.astro/types.d.ts +3 -0
- package/templates/emdash/.github/workflows/deploy-prod.yml +1 -1
- package/templates/emdash/AGENTS.md +19 -11
- package/templates/emdash/README.md +45 -42
- package/templates/emdash/SETUP.html +576 -0
- package/templates/emdash/_gitignore +3 -0
- package/templates/emdash/astro.config.mjs +33 -3
- package/templates/emdash/package.json +14 -9
- package/templates/emdash/seed/seed.json +1 -1
- package/templates/emdash/site.json +303 -0
- package/templates/emdash/src/layouts/Layout.astro +7 -1
- package/templates/emdash/src/pages/404.astro +5 -0
- package/templates/emdash/src/pages/[...slug].astro +7 -0
- package/templates/emdash/src/pages/index.astro +7 -0
- package/templates/emdash/vite.config.ts +19 -5
- package/templates/emdash/wrangler.jsonc +8 -3
- package/templates/static/.agents/skills/setup/SKILL.md +61 -0
- package/templates/static/.github/workflows/deploy-prod.yml +1 -1
- package/templates/static/AGENTS.md +14 -7
- package/templates/static/README.md +15 -20
- package/templates/static/SETUP.html +576 -0
- package/templates/static/_gitignore +3 -0
- package/templates/static/astro.config.mjs +5 -1
- package/templates/static/package.json +8 -6
- package/templates/static/site.json +228 -0
- package/templates/static/src/pages/index.astro +2 -2
- package/templates/static/wrangler.jsonc +10 -3
- package/templates/emdash/design-system.json +0 -148
- package/templates/emdash/scripts/init-github.mjs +0 -186
- package/templates/emdash/scripts/init-hosting.mjs +0 -150
- package/templates/static/scripts/init-github.mjs +0 -186
- package/templates/static/scripts/init-hosting.mjs +0 -62
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Setup</title>
|
|
7
|
+
<!--
|
|
8
|
+
Opened straight from disk (file://) before anything is deployed, which is
|
|
9
|
+
when most of these steps happen — so it links a relative, pre-generated
|
|
10
|
+
stylesheet rather than the site's own build output. Run `pnpm run sop`
|
|
11
|
+
first (it's a one-line `vitops generate -f css` into .vitops/sop/); the
|
|
12
|
+
banner below explains this if the stylesheet 404s, and the markup stays
|
|
13
|
+
legible either way — every item here is a real checkbox in a real
|
|
14
|
+
<details>, readable and tickable with JS off.
|
|
15
|
+
|
|
16
|
+
This file is template DATA copied verbatim by `vp create`, not framework
|
|
17
|
+
code — see AGENTS.md's "Client onboarding" section for why it isn't a
|
|
18
|
+
<wc-*> element. Only class names from @getvitops/core's own vocabulary
|
|
19
|
+
are used here; if you need something this page can't express, that's a
|
|
20
|
+
missing framework pattern, not a reason to hand-write CSS.
|
|
21
|
+
-->
|
|
22
|
+
<link id="sop-stylesheet" rel="stylesheet" href=".vitops/sop/styles.css" />
|
|
23
|
+
<style>
|
|
24
|
+
/* Minimal fallback so the page is still legible before `pnpm run sop`
|
|
25
|
+
has run once — intentionally not framework CSS, since it only ever
|
|
26
|
+
applies in the narrow window before the real stylesheet exists. */
|
|
27
|
+
body {
|
|
28
|
+
font-family:
|
|
29
|
+
system-ui,
|
|
30
|
+
-apple-system,
|
|
31
|
+
'Segoe UI',
|
|
32
|
+
sans-serif;
|
|
33
|
+
max-width: 64rem;
|
|
34
|
+
margin-inline: auto;
|
|
35
|
+
padding: 2rem 1.5rem 6rem;
|
|
36
|
+
line-height: 1.5;
|
|
37
|
+
}
|
|
38
|
+
</style>
|
|
39
|
+
</head>
|
|
40
|
+
<body class="centered">
|
|
41
|
+
<div class="rhythm">
|
|
42
|
+
<header class="region rhythm">
|
|
43
|
+
<h1>Client onboarding checklist</h1>
|
|
44
|
+
<p id="no-stylesheet-notice" class="banner" hidden>
|
|
45
|
+
This page isn't styled yet — run <code>pnpm run sop</code> once (it generates
|
|
46
|
+
<code>.vitops/sop/styles.css</code>), then reload.
|
|
47
|
+
</p>
|
|
48
|
+
<p>
|
|
49
|
+
A local working document — it is never deployed, never committed to a build, and nothing
|
|
50
|
+
here is read by the site itself. Work top to bottom; each stage gates the next. Every
|
|
51
|
+
command is copy-pasteable as written. Progress is saved in this browser only
|
|
52
|
+
(<code>localStorage</code>), so it won't follow you to another machine.
|
|
53
|
+
</p>
|
|
54
|
+
<p>
|
|
55
|
+
<span class="badge" id="progress-badge">0 / 0 done</span>
|
|
56
|
+
</p>
|
|
57
|
+
</header>
|
|
58
|
+
|
|
59
|
+
<main class="rhythm">
|
|
60
|
+
<details class="details" open data-sop-stage="host">
|
|
61
|
+
<summary>1. Choose the host</summary>
|
|
62
|
+
<div class="rhythm">
|
|
63
|
+
<label class="custom-check">
|
|
64
|
+
<input type="checkbox" data-sop="host.decide" />
|
|
65
|
+
<span class="custom-check__box"
|
|
66
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
67
|
+
></span>
|
|
68
|
+
<span>
|
|
69
|
+
Decide the hosting target — <strong>Cloudflare Workers</strong> is the default and
|
|
70
|
+
what the shipped deploy workflows target. A <code>node</code> target exists for the
|
|
71
|
+
EmDash template (VPS / docker-compose / k8s) but needs manual setup — see that
|
|
72
|
+
template's README "Hosting" section — and the deploy workflows here are
|
|
73
|
+
Cloudflare-specific either way.
|
|
74
|
+
</span>
|
|
75
|
+
</label>
|
|
76
|
+
</div>
|
|
77
|
+
</details>
|
|
78
|
+
|
|
79
|
+
<details class="details" data-sop-stage="repo">
|
|
80
|
+
<summary>2. GitHub repo + branch policy</summary>
|
|
81
|
+
<div class="rhythm">
|
|
82
|
+
<p>
|
|
83
|
+
<code>dev</code> is the unprotected integration branch — push and merge to it
|
|
84
|
+
directly. <code>main</code> is production: protected, gated by a
|
|
85
|
+
<code>production</code> environment that pauses for an admin's approval, and reachable
|
|
86
|
+
only through the <code>promote</code> workflow (never a direct push).
|
|
87
|
+
</p>
|
|
88
|
+
<label class="custom-check">
|
|
89
|
+
<input type="checkbox" data-sop="repo.plan" />
|
|
90
|
+
<span class="custom-check__box"
|
|
91
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
92
|
+
></span>
|
|
93
|
+
<span> Preview it: <code>npx vitops setup repo --dry</code> </span>
|
|
94
|
+
</label>
|
|
95
|
+
<label class="custom-check">
|
|
96
|
+
<input type="checkbox" data-sop="repo.run" />
|
|
97
|
+
<span class="custom-check__box"
|
|
98
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
99
|
+
></span>
|
|
100
|
+
<span>
|
|
101
|
+
Run it: <code>npx vitops setup repo</code> — creates the GitHub repo, pushes
|
|
102
|
+
<code>main</code> + <code>dev</code>, makes <code>dev</code> default, and requests
|
|
103
|
+
branch protection + the <code>production</code>/<code>dev</code>
|
|
104
|
+
environments.
|
|
105
|
+
</span>
|
|
106
|
+
</label>
|
|
107
|
+
<label class="custom-check">
|
|
108
|
+
<input type="checkbox" data-sop="repo.verify" />
|
|
109
|
+
<span class="custom-check__box"
|
|
110
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
111
|
+
></span>
|
|
112
|
+
<span>
|
|
113
|
+
Verify by hand in GitHub → Settings → Branches / Environments. Branch protection and
|
|
114
|
+
environment reviewers need GitHub Pro/Team on a private repo — if the command
|
|
115
|
+
reported that as blocked, this is where you set it up manually.
|
|
116
|
+
</span>
|
|
117
|
+
</label>
|
|
118
|
+
</div>
|
|
119
|
+
</details>
|
|
120
|
+
|
|
121
|
+
<details class="details" data-sop-stage="hosting">
|
|
122
|
+
<summary>3. Hosting resources</summary>
|
|
123
|
+
<div class="rhythm">
|
|
124
|
+
<label class="custom-check">
|
|
125
|
+
<input type="checkbox" data-sop="hosting.plan" />
|
|
126
|
+
<span class="custom-check__box"
|
|
127
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
128
|
+
></span>
|
|
129
|
+
<span> Preview it: <code>npx vitops setup hosting --dry</code> </span>
|
|
130
|
+
</label>
|
|
131
|
+
<label class="custom-check">
|
|
132
|
+
<input type="checkbox" data-sop="hosting.run" />
|
|
133
|
+
<span class="custom-check__box"
|
|
134
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
135
|
+
></span>
|
|
136
|
+
<span>
|
|
137
|
+
Run it: <code>npx vitops setup hosting</code> — provisions the isolated dev D1
|
|
138
|
+
database + R2 bucket (EmDash template) and sets the <code>DEV_D1_ID</code> /
|
|
139
|
+
<code>CLOUDFLARE_ACCOUNT_ID</code> repo secrets. Requires
|
|
140
|
+
<code>npx wrangler login</code> first.
|
|
141
|
+
</span>
|
|
142
|
+
</label>
|
|
143
|
+
<label class="custom-check">
|
|
144
|
+
<input type="checkbox" data-sop="hosting.token" />
|
|
145
|
+
<span class="custom-check__box"
|
|
146
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
147
|
+
></span>
|
|
148
|
+
<span>
|
|
149
|
+
<strong>Create a Cloudflare API token by hand</strong> — no API can mint one:
|
|
150
|
+
<a
|
|
151
|
+
class="link"
|
|
152
|
+
href="https://dash.cloudflare.com/profile/api-tokens"
|
|
153
|
+
target="_blank"
|
|
154
|
+
rel="noopener"
|
|
155
|
+
>dash.cloudflare.com/profile/api-tokens</a
|
|
156
|
+
>
|
|
157
|
+
(Workers + D1 + R2 edit), then
|
|
158
|
+
<code>gh secret set CLOUDFLARE_API_TOKEN</code>. The first workflow runs fail until
|
|
159
|
+
this exists.
|
|
160
|
+
</span>
|
|
161
|
+
</label>
|
|
162
|
+
<label class="custom-check">
|
|
163
|
+
<input type="checkbox" data-sop="hosting.emdash-fingerprint" />
|
|
164
|
+
<span class="custom-check__box"
|
|
165
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
166
|
+
></span>
|
|
167
|
+
<span>
|
|
168
|
+
<strong>(EmDash template)</strong> After the first deploy to each environment, run
|
|
169
|
+
<code>npx emdash migrate --status</code> locally against that environment's real
|
|
170
|
+
database, review the printed account/database identity, and set the reviewed
|
|
171
|
+
fingerprint:
|
|
172
|
+
<code
|
|
173
|
+
>gh variable set EMDASH_TARGET_FINGERPRINT --env dev --body <value></code
|
|
174
|
+
>
|
|
175
|
+
and again with <code>--env production</code>. No command can do this for you — it's
|
|
176
|
+
the human review the fingerprint guard exists for. Deploys fail clearly on the
|
|
177
|
+
migration-apply step until it's set for that environment.
|
|
178
|
+
</span>
|
|
179
|
+
</label>
|
|
180
|
+
<label class="custom-check">
|
|
181
|
+
<input type="checkbox" data-sop="hosting.design-system-editor-token" />
|
|
182
|
+
<span class="custom-check__box"
|
|
183
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
184
|
+
></span>
|
|
185
|
+
<span>
|
|
186
|
+
<strong>(EmDash template, only if <code>designSystemEditor</code> is on)</strong>
|
|
187
|
+
Create a fine-grained GitHub PAT scoped to this one repository,
|
|
188
|
+
<code>Contents: Read and write</code> only — no <code>admin</code> scope, no access
|
|
189
|
+
to any other repo — then <code>gh secret set VITOPS_GITHUB_TOKEN</code>. Also set
|
|
190
|
+
<code>site.deployment.repo</code> (<code>"owner/name"</code>) and
|
|
191
|
+
<code>site.deployment.branch</code> (default <code>"dev"</code>) in
|
|
192
|
+
<code>site.json</code>. Without these the live design-system editor still works —
|
|
193
|
+
only the auto-commit-to-source half is skipped, and the admin page's response says
|
|
194
|
+
so.
|
|
195
|
+
</span>
|
|
196
|
+
</label>
|
|
197
|
+
</div>
|
|
198
|
+
</details>
|
|
199
|
+
|
|
200
|
+
<details class="details" data-sop-stage="domain">
|
|
201
|
+
<summary>4. Domain strategy</summary>
|
|
202
|
+
<div class="rhythm">
|
|
203
|
+
<p>Two mutually exclusive tracks. Pick one — do not do both in the same deploy.</p>
|
|
204
|
+
|
|
205
|
+
<h3>4a. Go live on <code>*.workers.dev</code> (default, safe)</h3>
|
|
206
|
+
<p>
|
|
207
|
+
Leaves any existing live site untouched at its current domain. Do this first, always —
|
|
208
|
+
cutover is a separate, later step.
|
|
209
|
+
</p>
|
|
210
|
+
<label class="custom-check">
|
|
211
|
+
<input type="checkbox" data-sop="domain.workersdev.leave" />
|
|
212
|
+
<span class="custom-check__box"
|
|
213
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
214
|
+
></span>
|
|
215
|
+
<span>
|
|
216
|
+
Leave <code>workers_dev: true</code> and the <code>routes</code> block commented out
|
|
217
|
+
in <code>wrangler.jsonc</code> — this is the shipped default.
|
|
218
|
+
</span>
|
|
219
|
+
</label>
|
|
220
|
+
<label class="custom-check">
|
|
221
|
+
<input type="checkbox" data-sop="domain.workersdev.url" />
|
|
222
|
+
<span class="custom-check__box"
|
|
223
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
224
|
+
></span>
|
|
225
|
+
<span>
|
|
226
|
+
Deploy once (<code>pnpm deploy</code>), note the printed
|
|
227
|
+
<code>*.workers.dev</code> URL, and set
|
|
228
|
+
<code>site.environments.production.url</code> in <code>site.json</code> to it.
|
|
229
|
+
</span>
|
|
230
|
+
</label>
|
|
231
|
+
<label class="custom-check">
|
|
232
|
+
<input type="checkbox" data-sop="domain.workersdev.noindex" />
|
|
233
|
+
<span class="custom-check__box"
|
|
234
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
235
|
+
></span>
|
|
236
|
+
<span>
|
|
237
|
+
Set <code>site.environments.production.robots</code> to
|
|
238
|
+
<code>"noindex,nofollow"</code> — a workers.dev URL is indexable, and this is the
|
|
239
|
+
launch gate that stops search engines picking it up as a duplicate of the real site.
|
|
240
|
+
</span>
|
|
241
|
+
</label>
|
|
242
|
+
|
|
243
|
+
<h3>4b. Cut over to the custom domain</h3>
|
|
244
|
+
<p>
|
|
245
|
+
<strong>This step overwrites the zone's DNS record the moment you deploy</strong>
|
|
246
|
+
— it is the one irreversible-feeling moment in this whole checklist, and it takes an
|
|
247
|
+
existing live site down at that instant. Do it deliberately, not as part of a bigger
|
|
248
|
+
batch of changes. It is safe to complete stage 6 (Search Console / GCP / ads) before
|
|
249
|
+
this — <code>vitops search setup</code> only ever <em>creates</em> a verification TXT
|
|
250
|
+
record, it never touches the apex.
|
|
251
|
+
</p>
|
|
252
|
+
<label class="custom-check">
|
|
253
|
+
<input type="checkbox" data-sop="domain.cutover.ttl" />
|
|
254
|
+
<span class="custom-check__box"
|
|
255
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
256
|
+
></span>
|
|
257
|
+
<span> If replacing a live site, lower that site's DNS TTL well ahead of time. </span>
|
|
258
|
+
</label>
|
|
259
|
+
<label class="custom-check">
|
|
260
|
+
<input type="checkbox" data-sop="domain.cutover.plan" />
|
|
261
|
+
<span class="custom-check__box"
|
|
262
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
263
|
+
></span>
|
|
264
|
+
<span>
|
|
265
|
+
Preview it: <code>npx vitops setup domain --domain <apex> --dry</code> — this
|
|
266
|
+
only plans and checks; it never applies the cutover itself.
|
|
267
|
+
</span>
|
|
268
|
+
</label>
|
|
269
|
+
<label class="custom-check">
|
|
270
|
+
<input type="checkbox" data-sop="domain.cutover.uncomment" />
|
|
271
|
+
<span class="custom-check__box"
|
|
272
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
273
|
+
></span>
|
|
274
|
+
<span>
|
|
275
|
+
Uncomment the <code>routes</code> block in <code>wrangler.jsonc</code>, set your
|
|
276
|
+
apex, and deploy: <code>pnpm deploy</code>.
|
|
277
|
+
</span>
|
|
278
|
+
</label>
|
|
279
|
+
<label class="custom-check">
|
|
280
|
+
<input type="checkbox" data-sop="domain.cutover.config" />
|
|
281
|
+
<span class="custom-check__box"
|
|
282
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
283
|
+
></span>
|
|
284
|
+
<span>
|
|
285
|
+
Set <code>site.domains.canonical</code> and
|
|
286
|
+
<code>site.environments.production.url</code> to the custom domain, and flip
|
|
287
|
+
<code>environments.production.robots</code> back to <code>"index,follow"</code> (or
|
|
288
|
+
remove it).
|
|
289
|
+
</span>
|
|
290
|
+
</label>
|
|
291
|
+
<label class="custom-check">
|
|
292
|
+
<input type="checkbox" data-sop="domain.cutover.notify" />
|
|
293
|
+
<span class="custom-check__box"
|
|
294
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
295
|
+
></span>
|
|
296
|
+
<span>
|
|
297
|
+
Re-run <code>npx vitops robots</code> and <code>npx vitops search notify</code>.
|
|
298
|
+
</span>
|
|
299
|
+
</label>
|
|
300
|
+
</div>
|
|
301
|
+
</details>
|
|
302
|
+
|
|
303
|
+
<details class="details" data-sop-stage="config">
|
|
304
|
+
<summary>5. Configuration</summary>
|
|
305
|
+
<div class="rhythm">
|
|
306
|
+
<label class="custom-check">
|
|
307
|
+
<input type="checkbox" data-sop="config.fill" />
|
|
308
|
+
<span class="custom-check__box"
|
|
309
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
310
|
+
></span>
|
|
311
|
+
<span>
|
|
312
|
+
Fill in <code>site.json</code>: <code>organization</code> (name, address, contact),
|
|
313
|
+
<code>site.locales</code>, <code>site.environments</code>, <code>site.seo</code>,
|
|
314
|
+
<code>site.analytics</code>, <code>site.legal.*.enabled</code>,
|
|
315
|
+
<code>site.favicon</code>, <code>site.icons</code>.
|
|
316
|
+
</span>
|
|
317
|
+
</label>
|
|
318
|
+
<label class="custom-check">
|
|
319
|
+
<input type="checkbox" data-sop="config.validate" />
|
|
320
|
+
<span class="custom-check__box"
|
|
321
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
322
|
+
></span>
|
|
323
|
+
<span> Check it: <code>npx vitops validate site.json</code> </span>
|
|
324
|
+
</label>
|
|
325
|
+
</div>
|
|
326
|
+
</details>
|
|
327
|
+
|
|
328
|
+
<details class="details" data-sop-stage="connections">
|
|
329
|
+
<summary>6. Search Console / GCP / ads</summary>
|
|
330
|
+
<div class="rhythm">
|
|
331
|
+
<label class="custom-check">
|
|
332
|
+
<input type="checkbox" data-sop="connections.gcp" />
|
|
333
|
+
<span class="custom-check__box"
|
|
334
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
335
|
+
></span>
|
|
336
|
+
<span>
|
|
337
|
+
Set <code>site.google.project</code>, and the environment variables:
|
|
338
|
+
<code>VITOPS_GOOGLE_CLIENT_ID</code>, <code>VITOPS_GOOGLE_CLIENT_SECRET</code>,
|
|
339
|
+
<code>VITOPS_GOOGLE_REFRESH_TOKEN</code>, <code>CLOUDFLARE_API_TOKEN</code>.
|
|
340
|
+
</span>
|
|
341
|
+
</label>
|
|
342
|
+
<label class="custom-check">
|
|
343
|
+
<input type="checkbox" data-sop="connections.search" />
|
|
344
|
+
<span class="custom-check__box"
|
|
345
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
346
|
+
></span>
|
|
347
|
+
<span>
|
|
348
|
+
Preview then run: <code>npx vitops setup search --dry</code>, then
|
|
349
|
+
<code>npx vitops setup search</code>. This is a <strong>user OAuth</strong>
|
|
350
|
+
action, deliberately — verifying a site makes the caller an owner, and that should
|
|
351
|
+
be a person, not a deploy robot.
|
|
352
|
+
</span>
|
|
353
|
+
</label>
|
|
354
|
+
<label class="custom-check">
|
|
355
|
+
<input type="checkbox" data-sop="connections.ads" />
|
|
356
|
+
<span class="custom-check__box"
|
|
357
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
358
|
+
></span>
|
|
359
|
+
<span>
|
|
360
|
+
Preview then run: <code>npx vitops setup ads --dry</code>, then
|
|
361
|
+
<code>npx vitops setup ads</code>.
|
|
362
|
+
</span>
|
|
363
|
+
</label>
|
|
364
|
+
<label class="custom-check">
|
|
365
|
+
<input type="checkbox" data-sop="connections.email" />
|
|
366
|
+
<span class="custom-check__box"
|
|
367
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
368
|
+
></span>
|
|
369
|
+
<span>
|
|
370
|
+
If <code>site.notifications.email</code> sends mail, onboard its sender domain:
|
|
371
|
+
<code>npx vitops email setup --dry</code>, then <code>npx vitops email setup</code>.
|
|
372
|
+
Cloudflare onboards an exact name — usually a subdomain like
|
|
373
|
+
<code>send.<domain></code>, not the apex — so a mismatch here is silent at
|
|
374
|
+
build time and only fails when a form is actually submitted in production. Both
|
|
375
|
+
templates' <code>deploy</code> script already runs
|
|
376
|
+
<code>vitops email check</code> first as a non-blocking warning.
|
|
377
|
+
</span>
|
|
378
|
+
</label>
|
|
379
|
+
<label class="custom-check">
|
|
380
|
+
<input type="checkbox" data-sop="connections.manual" />
|
|
381
|
+
<span class="custom-check__box"
|
|
382
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
383
|
+
></span>
|
|
384
|
+
<span>
|
|
385
|
+
Two things are never automated, by design: adding a Search Console
|
|
386
|
+
<strong>Full User</strong> (via a Google Group), and clicking each platform's own
|
|
387
|
+
"Verify" button. Both are named in the command output when they apply.
|
|
388
|
+
</span>
|
|
389
|
+
</label>
|
|
390
|
+
</div>
|
|
391
|
+
</details>
|
|
392
|
+
|
|
393
|
+
<details class="details" data-sop-stage="legal">
|
|
394
|
+
<summary>7. Legal</summary>
|
|
395
|
+
<div class="rhythm">
|
|
396
|
+
<label class="custom-check">
|
|
397
|
+
<input type="checkbox" data-sop="legal.generate" />
|
|
398
|
+
<span class="custom-check__box"
|
|
399
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
400
|
+
></span>
|
|
401
|
+
<span>
|
|
402
|
+
Generate real documents from the filled-in config —
|
|
403
|
+
<code>npx vitops legal --format portable-text</code> (EmDash; paste into the admin)
|
|
404
|
+
or <code>npx vitops legal --format md</code> (static; commit the output). The seeded
|
|
405
|
+
<code>/terms</code> and <code>/privacy</code> pages are deliberately short,
|
|
406
|
+
obviously-unfinished placeholders.
|
|
407
|
+
</span>
|
|
408
|
+
</label>
|
|
409
|
+
<label class="custom-check">
|
|
410
|
+
<input type="checkbox" data-sop="legal.review" />
|
|
411
|
+
<span class="custom-check__box"
|
|
412
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
413
|
+
></span>
|
|
414
|
+
<span>
|
|
415
|
+
<strong>Have it reviewed before publishing.</strong> Every generated document opens
|
|
416
|
+
with a non-optional review banner — it is a starting point from your config, not
|
|
417
|
+
legal advice, and a plausible-looking policy shipped unread is the one failure mode
|
|
418
|
+
here with real consequences.
|
|
419
|
+
</span>
|
|
420
|
+
</label>
|
|
421
|
+
</div>
|
|
422
|
+
</details>
|
|
423
|
+
|
|
424
|
+
<details class="details" data-sop-stage="launch">
|
|
425
|
+
<summary>8. Launch gates</summary>
|
|
426
|
+
<div class="rhythm">
|
|
427
|
+
<label class="custom-check">
|
|
428
|
+
<input type="checkbox" data-sop="launch.robots" />
|
|
429
|
+
<span class="custom-check__box"
|
|
430
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
431
|
+
></span>
|
|
432
|
+
<span>
|
|
433
|
+
Robots directive matches the live origin's intent (blocked while on workers.dev,
|
|
434
|
+
open after cutover) — <code>npx vitops robots</code>.
|
|
435
|
+
</span>
|
|
436
|
+
</label>
|
|
437
|
+
<label class="custom-check">
|
|
438
|
+
<input type="checkbox" data-sop="launch.canonical" />
|
|
439
|
+
<span class="custom-check__box"
|
|
440
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
441
|
+
></span>
|
|
442
|
+
<span>
|
|
443
|
+
Canonical domain in <code>site.json</code> matches the actual live origin.
|
|
444
|
+
</span>
|
|
445
|
+
</label>
|
|
446
|
+
<label class="custom-check">
|
|
447
|
+
<input type="checkbox" data-sop="launch.favicon" />
|
|
448
|
+
<span class="custom-check__box"
|
|
449
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
450
|
+
></span>
|
|
451
|
+
<span> Favicon / PWA assets present and correct. </span>
|
|
452
|
+
</label>
|
|
453
|
+
<label class="custom-check">
|
|
454
|
+
<input type="checkbox" data-sop="launch.lint" />
|
|
455
|
+
<span class="custom-check__box"
|
|
456
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
457
|
+
></span>
|
|
458
|
+
<span>
|
|
459
|
+
<code>npx vitops lint --src</code> and <code>pnpm typecheck</code> both clean.
|
|
460
|
+
</span>
|
|
461
|
+
</label>
|
|
462
|
+
<label class="custom-check">
|
|
463
|
+
<input type="checkbox" data-sop="launch.approve" />
|
|
464
|
+
<span class="custom-check__box"
|
|
465
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
466
|
+
></span>
|
|
467
|
+
<span>
|
|
468
|
+
Prod deploy approved by an admin in the <code>production</code> GitHub Environment
|
|
469
|
+
gate.
|
|
470
|
+
</span>
|
|
471
|
+
</label>
|
|
472
|
+
<label class="custom-check">
|
|
473
|
+
<input type="checkbox" data-sop="launch.notify" />
|
|
474
|
+
<span class="custom-check__box"
|
|
475
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
476
|
+
></span>
|
|
477
|
+
<span> <code>npx vitops search notify</code> run once live. </span>
|
|
478
|
+
</label>
|
|
479
|
+
<label class="custom-check">
|
|
480
|
+
<input type="checkbox" data-sop="launch.check" />
|
|
481
|
+
<span class="custom-check__box"
|
|
482
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
483
|
+
></span>
|
|
484
|
+
<span>
|
|
485
|
+
A day or two later: <code>npx vitops search notify --check</code> confirms Google
|
|
486
|
+
actually indexed it.
|
|
487
|
+
</span>
|
|
488
|
+
</label>
|
|
489
|
+
</div>
|
|
490
|
+
</details>
|
|
491
|
+
</main>
|
|
492
|
+
|
|
493
|
+
<footer class="region rhythm">
|
|
494
|
+
<div class="card">
|
|
495
|
+
<p><strong>Working alongside an AI agent?</strong></p>
|
|
496
|
+
<p>
|
|
497
|
+
Point it at <code>.agents/skills/setup/</code> — it works this same list autonomously
|
|
498
|
+
and only stops at the steps marked above as requiring a person (the Cloudflare API
|
|
499
|
+
token, the domain cutover, and publishing any generated legal document).
|
|
500
|
+
</p>
|
|
501
|
+
</div>
|
|
502
|
+
</footer>
|
|
503
|
+
</div>
|
|
504
|
+
|
|
505
|
+
<script type="module">
|
|
506
|
+
// The whole persistence contract. An admin portal that wants this same
|
|
507
|
+
// checklist backed by shared/server storage defines
|
|
508
|
+
// `window.__vitopsSopStore` before this script runs; everything below is
|
|
509
|
+
// DOM wiring against whichever store is present. Do not add a second
|
|
510
|
+
// storage backend inline here — swap the store, not this file.
|
|
511
|
+
//
|
|
512
|
+
// { get(id): boolean, set(id, v): void|Promise<void>, all(): Record<string, boolean> }
|
|
513
|
+
function localStore(key) {
|
|
514
|
+
const read = () => {
|
|
515
|
+
try {
|
|
516
|
+
return JSON.parse(localStorage.getItem(key) ?? '{}');
|
|
517
|
+
} catch {
|
|
518
|
+
return {};
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
return {
|
|
522
|
+
get: (id) => Boolean(read()[id]),
|
|
523
|
+
set: (id, value) => {
|
|
524
|
+
const state = read();
|
|
525
|
+
state[id] = value;
|
|
526
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
527
|
+
},
|
|
528
|
+
all: () => read(),
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const store = window.__vitopsSopStore ?? localStore('vitops.sop.v1');
|
|
533
|
+
const checkboxes = Array.from(document.querySelectorAll('input[data-sop]'));
|
|
534
|
+
const badge = document.getElementById('progress-badge');
|
|
535
|
+
|
|
536
|
+
// A <link> still loading (network/disk latency) reports zero cssRules just
|
|
537
|
+
// like a 404'd one — the check has to wait for the sheet to settle rather
|
|
538
|
+
// than sampling it once at parse time, or a real stylesheet that simply
|
|
539
|
+
// hasn't finished loading yet reads as "not styled".
|
|
540
|
+
function checkStylesheet() {
|
|
541
|
+
const link = document.getElementById('sop-stylesheet');
|
|
542
|
+
try {
|
|
543
|
+
if (link.sheet && link.sheet.cssRules.length > 0) return;
|
|
544
|
+
} catch {
|
|
545
|
+
// A cross-origin or 404'd sheet throws on `.cssRules` under `file://` —
|
|
546
|
+
// that failure IS the signal the stylesheet isn't there yet.
|
|
547
|
+
}
|
|
548
|
+
document.getElementById('no-stylesheet-notice').hidden = false;
|
|
549
|
+
}
|
|
550
|
+
const sopLink = document.getElementById('sop-stylesheet');
|
|
551
|
+
if (sopLink.sheet) checkStylesheet();
|
|
552
|
+
else {
|
|
553
|
+
sopLink.addEventListener('load', checkStylesheet);
|
|
554
|
+
sopLink.addEventListener('error', checkStylesheet);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function updateBadge() {
|
|
558
|
+
const done = checkboxes.filter((c) => c.checked).length;
|
|
559
|
+
badge.textContent = `${done} / ${checkboxes.length} done`;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const saved = store.all();
|
|
563
|
+
for (const box of checkboxes) {
|
|
564
|
+
box.checked = Boolean(saved[box.dataset.sop]);
|
|
565
|
+
}
|
|
566
|
+
updateBadge();
|
|
567
|
+
|
|
568
|
+
document.addEventListener('change', (event) => {
|
|
569
|
+
const box = event.target;
|
|
570
|
+
if (!(box instanceof HTMLInputElement) || !box.dataset.sop) return;
|
|
571
|
+
store.set(box.dataset.sop, box.checked);
|
|
572
|
+
updateBadge();
|
|
573
|
+
});
|
|
574
|
+
</script>
|
|
575
|
+
</body>
|
|
576
|
+
</html>
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import react from '@astrojs/react';
|
|
2
2
|
import vitops from '@getvitops/astro';
|
|
3
|
+
import { resolveOrganizationName } from '@getvitops/astro/routes';
|
|
3
4
|
import { vitopsEmdash, vitopsHosting } from '@getvitops/emdash';
|
|
4
5
|
import { defineConfig } from 'astro/config';
|
|
5
6
|
import emdash from 'emdash/astro';
|
|
7
|
+
import config from './site.json' with { type: 'json' };
|
|
8
|
+
|
|
9
|
+
// site.json's organization.name is the one build-time-readable source for a
|
|
10
|
+
// display name — EmDash's own getSiteSettings() only resolves inside a live
|
|
11
|
+
// Worker request (AsyncLocalStorage + a DB binding), so it can't be read here
|
|
12
|
+
// even though it's what Layout.astro shows on rendered pages. See AGENTS.md's
|
|
13
|
+
// "EmDash plugin as the design-system editing surface".
|
|
14
|
+
const organizationName = resolveOrganizationName(config) ?? 'My EmDash Site';
|
|
6
15
|
|
|
7
16
|
// Hosting seam: adapter + EmDash database/storage for the configured target.
|
|
8
17
|
// Default 'cloudflare' (Workers + D1 + R2 — see wrangler.jsonc / src/worker.ts).
|
|
@@ -30,19 +39,40 @@ export default defineConfig({
|
|
|
30
39
|
// disclosure, carousel) in the editor slash menu. Default 'integration'
|
|
31
40
|
// script delivery: Layout.astro renders <Head /> from @getvitops/astro,
|
|
32
41
|
// which emits the web-component runtime tags.
|
|
33
|
-
|
|
42
|
+
//
|
|
43
|
+
// designSystemEditor mounts a live <wc-theme-editor> admin page at
|
|
44
|
+
// /design-system — edits are visible site-wide immediately (no
|
|
45
|
+
// rebuild) and auto-sync back to source once site.deployment.repo and
|
|
46
|
+
// a VITOPS_GITHUB_TOKEN secret are set (see SETUP.html) — see
|
|
47
|
+
// AGENTS.md's "EmDash plugin as the design-system editing surface".
|
|
48
|
+
// Until then the live half still works; only the sync half is skipped.
|
|
49
|
+
plugins: [vitopsEmdash({ designSystemEditor: { config } })],
|
|
50
|
+
// 1.0's runtime migration mode defaults to 'auto' (apply pending core
|
|
51
|
+
// migrations on first request) — fine for local dev, but a deploy
|
|
52
|
+
// should have already migrated before traffic arrives. 'check' 503s a
|
|
53
|
+
// request instead of migrating behind it if the explicit `emdash
|
|
54
|
+
// migrate` step in site-deploy-emdash.yml (see AGENTS.md's CI/CD
|
|
55
|
+
// section) was skipped or failed. `dev: 'auto'` keeps the convenient
|
|
56
|
+
// first-run behaviour for `pnpm dev`.
|
|
57
|
+
migrations: { runtime: 'check', dev: 'auto' },
|
|
34
58
|
}),
|
|
35
59
|
vitops({
|
|
36
60
|
favicon: {
|
|
37
61
|
source: 'src/assets/logo.svg',
|
|
38
|
-
name:
|
|
62
|
+
name: organizationName,
|
|
39
63
|
themeColor: '#2e9b73',
|
|
40
64
|
backgroundColor: '#ffffff',
|
|
41
65
|
},
|
|
42
66
|
// inject: false — Layout.astro imports the generated stylesheet, so
|
|
43
67
|
// EmDash's /_emdash/admin routes don't inherit the design system while
|
|
44
68
|
// your pages (and EmDash previews rendered through the layout) do.
|
|
45
|
-
|
|
69
|
+
//
|
|
70
|
+
// site.json is the umbrella Config — organization + site facts plus the
|
|
71
|
+
// design system at designSystem.themes.default — so css.input points
|
|
72
|
+
// there instead of a bare design-system.json. legal/fonts/search/ads/
|
|
73
|
+
// reviews all read the same file (see AGENTS.md's "Client onboarding").
|
|
74
|
+
css: { format: 'tailwind', inject: false, input: 'site.json' },
|
|
75
|
+
site: { input: 'site.json' },
|
|
46
76
|
}),
|
|
47
77
|
],
|
|
48
78
|
});
|