@scribe-platform/cli 0.7.0 → 0.9.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/README.md +28 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +15 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/proof.d.ts +5 -0
- package/dist/commands/proof.d.ts.map +1 -0
- package/dist/commands/proof.js +440 -0
- package/dist/commands/proof.js.map +1 -0
- package/dist/commands/prospect.d.ts +27 -0
- package/dist/commands/prospect.d.ts.map +1 -0
- package/dist/commands/prospect.js +222 -0
- package/dist/commands/prospect.js.map +1 -0
- package/dist/commands/request.d.ts +38 -0
- package/dist/commands/request.d.ts.map +1 -0
- package/dist/commands/request.js +214 -0
- package/dist/commands/request.js.map +1 -0
- package/dist/commands/site.d.ts +11 -0
- package/dist/commands/site.d.ts.map +1 -1
- package/dist/commands/site.js +41 -3
- package/dist/commands/site.js.map +1 -1
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +128 -31
- package/dist/commands/update.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/claude-hook.d.ts +74 -0
- package/dist/lib/claude-hook.d.ts.map +1 -0
- package/dist/lib/claude-hook.js +108 -0
- package/dist/lib/claude-hook.js.map +1 -0
- package/dist/lib/client.d.ts +351 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +159 -0
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/proof-folder.d.ts +86 -0
- package/dist/lib/proof-folder.d.ts.map +1 -0
- package/dist/lib/proof-folder.js +226 -0
- package/dist/lib/proof-folder.js.map +1 -0
- package/dist/lib/proof-preview.d.ts +39 -0
- package/dist/lib/proof-preview.d.ts.map +1 -0
- package/dist/lib/proof-preview.js +318 -0
- package/dist/lib/proof-preview.js.map +1 -0
- package/dist/lib/proof-push.d.ts +42 -0
- package/dist/lib/proof-push.d.ts.map +1 -0
- package/dist/lib/proof-push.js +91 -0
- package/dist/lib/proof-push.js.map +1 -0
- package/dist/lib/skill.d.ts +13 -0
- package/dist/lib/skill.d.ts.map +1 -1
- package/dist/lib/skill.js +33 -2
- package/dist/lib/skill.js.map +1 -1
- package/dist/lib/update-check.d.ts +46 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +103 -0
- package/dist/lib/update-check.js.map +1 -0
- package/package.json +5 -3
- package/runtime/proof.js +139 -0
- package/skills/scribe-site-builder/SKILL.md +175 -33
- package/skills/scribe-site-builder/recipes/README.md +11 -3
- package/skills/scribe-site-builder/recipes/domains.md +151 -0
- package/skills/scribe-site-builder/recipes/forms.md +5 -2
- package/skills/scribe-site-builder/recipes/proofs.md +311 -0
- package/skills/scribe-site-builder/recipes/prospects.md +192 -0
- package/skills/scribe-site-builder/recipes/requests.md +145 -0
- package/skills/scribe-site-builder/recipes/schema.md +24 -0
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: scribe-site-builder
|
|
3
|
-
description: Guides building a website on Scribe CMS end to end — designing the Astro site freely against Scribe as its backend, editing the `.scribe.yml` schema, adding one or many forms, the local dev loop, pushing content, and deploying — using the `scribe` CLI and the recipes in `recipes/`. Also the reference for working an existing Scribe site (adding fields/collections, publishing content, triaging form submissions, archiving, restoring or deleting a site). Use whenever the user wants to build/create/start a new website or site with Scribe, add a form to a site, work on an existing Scribe site, or asks about the `scribe` CLI.
|
|
3
|
+
description: Guides building a website on Scribe CMS end to end — designing the Astro site freely against Scribe as its backend, editing the `.scribe.yml` schema, adding one or many forms, the local dev loop, pushing content, and deploying — using the `scribe` CLI and the recipes in `recipes/`. Also the reference for working an existing Scribe site (adding fields/collections, publishing content, triaging form submissions and inquiries, renaming, archiving, restoring or deleting a site), for taking a site live on a custom domain — checking whether a client has a domain, buying one, DNS/CNAME setup, GitHub Pages domain config, HTTPS — for the queue of requests clients have sent the agency (triaging, claiming, replying, closing), for the agency's prospect pipeline (logging calls, follow-ups, won/lost), and for proofs — sending a client work to review (logo boards, mockups, colour schemes), reading what they said, and sending the next version. Use whenever the user wants to build/create/start a new website or site with Scribe, add a form to a site, work on an existing Scribe site, publish/launch/go live with a site, point a site at a domain, set up or fix a custom domain or DNS for a Scribe site, work the inquiries a site has received, triage or reply to a client's request for work, log a call or follow-up with a prospect or client, wants to send a client something to look at or approve (logo ideas, mockups, options, a proof), asks what a client said about work they were sent, wants to do another round or version of something a client reviewed, or asks about the `scribe` CLI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Building a site with Scribe
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
**This file and the `recipes/` beside it are the whole reference.** They ship
|
|
9
|
+
inside the `@scribe-platform/cli` npm package and are installed with it, so
|
|
10
|
+
everything needed to drive Scribe is here or in `scribe <command> --help`.
|
|
11
|
+
There is no repo to consult and no wiki to look up — if something seems to be
|
|
12
|
+
missing, it is a gap worth telling Dave about, not a file to go hunting for.
|
|
13
|
+
|
|
14
|
+
(It is generated from `docs/BUILDER-GUIDE.md` and `docs/AGENT-GUIDE.md` in the
|
|
15
|
+
Scribe repo. That matters only to whoever edits it there; those paths do not
|
|
16
|
+
exist on a machine that installed the CLI from npm.)
|
|
12
17
|
|
|
13
18
|
## Recipes — read the one you need
|
|
14
19
|
|
|
@@ -22,16 +27,49 @@ instead of reading all of them:
|
|
|
22
27
|
| [`recipes/collections.md`](./recipes/collections.md) | rendering editor-managed content |
|
|
23
28
|
| [`recipes/forms.md`](./recipes/forms.md) | adding one or more forms |
|
|
24
29
|
| [`recipes/deploy.md`](./recipes/deploy.md) | build/deploy setup or debugging |
|
|
30
|
+
| [`recipes/domains.md`](./recipes/domains.md) | anything about a domain — whether the client has one, getting them one, the DNS, taking a site live on it, fixing one |
|
|
31
|
+
| [`recipes/requests.md`](./recipes/requests.md) | working the queue of jobs clients have asked the agency for |
|
|
32
|
+
| [`recipes/prospects.md`](./recipes/prospects.md) | logging calls and follow-ups on prospects (not site-building) |
|
|
33
|
+
| [`recipes/proofs.md`](./recipes/proofs.md) | sending a client work to review — logo boards, mockups, options — and working the rounds |
|
|
25
34
|
|
|
26
35
|
[`recipes/README.md`](./recipes/README.md) lists the five things that are a hard
|
|
27
36
|
contract (because Scribe writes into the repo) as opposed to advice.
|
|
28
37
|
|
|
38
|
+
## Sending a client work to look at: it's a Proof, never an artifact
|
|
39
|
+
|
|
40
|
+
If the ask is "send them some logo ideas", "show the client these options",
|
|
41
|
+
"get her to approve the mockup" or anything else where a **client looks at
|
|
42
|
+
work and reacts to it**, that is a Proof: read
|
|
43
|
+
[`recipes/proofs.md`](./recipes/proofs.md).
|
|
44
|
+
|
|
45
|
+
Three rules, in full, because getting them wrong is expensive:
|
|
46
|
+
|
|
47
|
+
1. **Never run `scribe proof send` without an explicit yes to that send.** It
|
|
48
|
+
emails a real person and freezes a version permanently. Everything else in
|
|
49
|
+
the proof workflow is reversible.
|
|
50
|
+
2. **Never use the Artifact tool for client review work**, even when the word
|
|
51
|
+
"artifact" is used. A claude.ai artifact needs an account to open, is
|
|
52
|
+
branded Claude rather than the agency, and nothing a client says on it
|
|
53
|
+
reaches their record — the three problems Proofs exist to fix.
|
|
54
|
+
3. **A Proof needs a client to belong to.** No prospect yet? Offer to create
|
|
55
|
+
one first.
|
|
56
|
+
|
|
29
57
|
## Mental model
|
|
30
58
|
|
|
31
59
|
- **A site = a GitHub repo.** Schema, content, and the Astro source all live in one
|
|
32
60
|
repo. The admin app and the `scribe` CLI are both just clients that read/write
|
|
33
61
|
files in it via the GitHub API; a local `git clone` is a third client reading/writing
|
|
34
62
|
the same files via git.
|
|
63
|
+
- **Scribe owns the repo's GitHub Pages settings — never set them by hand.** The
|
|
64
|
+
custom domain, `public/CNAME`, HTTPS enforcement and the build's base path are
|
|
65
|
+
all written by `scribe site promote`, in one idempotent run. Do **not** reach for
|
|
66
|
+
`gh api .../pages`, the GitHub web UI, or a hand-written `public/CNAME`: setting
|
|
67
|
+
one without the others leaves the site 404ing, and the Pages call needs repo
|
|
68
|
+
admin that a site user doesn't have. The CLI doesn't need it — the admin app
|
|
69
|
+
makes that call with Scribe's own org token, so a write-scoped API key is enough.
|
|
70
|
+
If something about a domain looks like it needs a GitHub permission you lack,
|
|
71
|
+
that's the signal you're on the wrong path, not that you need Dave.
|
|
72
|
+
See [`recipes/domains.md`](./recipes/domains.md).
|
|
35
73
|
- **Form submissions are the exception — they live in MongoDB, not the repo** (RFC
|
|
36
74
|
0004). A Visitor's name, email and message used to be committed as a YAML file into
|
|
37
75
|
the site's public repo, which published them to the open internet. Nothing writes
|
|
@@ -60,41 +98,61 @@ contract (because Scribe writes into the repo) as opposed to advice.
|
|
|
60
98
|
|
|
61
99
|
## Setup (once)
|
|
62
100
|
|
|
63
|
-
- **CLI**: confirm `scribe --help` works. If it's not found
|
|
64
|
-
`
|
|
101
|
+
- **CLI**: confirm `scribe --help` works. If it's not found:
|
|
102
|
+
`npm install -g @scribe-platform/cli`. (Working inside a clone of the Scribe
|
|
103
|
+
repo itself? `npm link` from `packages/cli` instead — but that is a
|
|
104
|
+
maintainer's setup, not a user's.)
|
|
65
105
|
- **Login**: `scribe login --token <key>` — mint the key from the
|
|
66
|
-
admin UI (sign in → account menu → **API Tokens** → New token).
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
106
|
+
admin UI (sign in → account menu → **API Tokens** → New token). This is the
|
|
107
|
+
whole machine setup: it writes `~/.scribe/config.json`, installs this skill,
|
|
108
|
+
and turns on auto-updates. Defaults to the hosted admin at
|
|
109
|
+
`https://scribe.weaverdigital.io`; add `--api-url <url>` only to point at a
|
|
110
|
+
different instance (a local dev/Docker admin). Every other command reads that
|
|
111
|
+
config, no per-invocation `--token` flag. If a command fails with a raw `fetch failed`, that's not an API
|
|
71
112
|
error — it means `apiUrl` in that config doesn't point at anything listening;
|
|
72
113
|
re-run `scribe login` with the right URL.
|
|
73
114
|
|
|
74
115
|
## Keeping Scribe up to date
|
|
75
116
|
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
**This normally happens by itself and needs no attention.** `scribe login`
|
|
118
|
+
installs this skill and registers a Claude Code `SessionStart` hook that checks npm for
|
|
119
|
+
a newer `@scribe-platform/cli` at the start of **every** session and installs
|
|
120
|
+
it — CLI and this skill together — *before* the session's skills are scanned.
|
|
121
|
+
So a session either started on the current version or was brought to it before
|
|
122
|
+
anyone typed. That is the whole reason the check runs at session start rather
|
|
123
|
+
than mid-conversation: there is never a new skill sitting on disk that the
|
|
124
|
+
running session can't see.
|
|
125
|
+
|
|
126
|
+
If an update did install, the hook says so in this session's context. Don't
|
|
127
|
+
relay it; it's already done.
|
|
128
|
+
|
|
129
|
+
If the hook reports that an update **failed** to install, that is for Dave, not
|
|
130
|
+
for the user — it will be an npm permissions or registry problem. Say so plainly
|
|
131
|
+
and carry on; the old version still works.
|
|
132
|
+
|
|
133
|
+
`scribe update` also runs the whole thing by hand:
|
|
78
134
|
|
|
79
135
|
```
|
|
80
|
-
scribe update
|
|
136
|
+
scribe update # update the CLI + this skill now
|
|
137
|
+
scribe update --check # just report whether a newer version exists
|
|
138
|
+
scribe update --install-hook # repair the auto-update hook if it went missing
|
|
81
139
|
```
|
|
82
140
|
|
|
83
|
-
|
|
141
|
+
One caveat: this **only works for a global npm install** (`npm install -g
|
|
142
|
+
@scribe-platform/cli`). In a dev checkout of the scribe repo it refuses, and if
|
|
143
|
+
`~/.claude/skills/scribe-site-builder` is a symlink into a checkout it leaves it
|
|
144
|
+
alone — that's an author editing the skill in place.
|
|
84
145
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
for a restart.
|
|
90
|
-
- **It only works for a global npm install** (`npm install -g
|
|
91
|
-
@scribe-platform/cli`). In a dev checkout of the scribe repo it refuses, and if
|
|
92
|
-
`~/.claude/skills/scribe-site-builder` is a symlink into a checkout it leaves it
|
|
93
|
-
alone — that's an author editing the skill in place.
|
|
146
|
+
Run it by hand when the user says there's a new version, or when a CLI command
|
|
147
|
+
fails in a way that suggests this skill is behind the API (an option the CLI
|
|
148
|
+
doesn't recognise, a command that no longer exists) — the session-start check
|
|
149
|
+
runs before the session, so anything published since then is not here yet.
|
|
94
150
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
151
|
+
**If a hand-run update installs a new version mid-session**, tell the user in one
|
|
152
|
+
sentence, in their words: *"I've updated Scribe — close this chat and start a new
|
|
153
|
+
one so I pick up the new instructions."* Then stop relying on anything in this
|
|
154
|
+
file that the update might have changed; if you need the new text now, read
|
|
155
|
+
`~/.claude/skills/scribe-site-builder/SKILL.md` from disk.
|
|
98
156
|
|
|
99
157
|
## Workflow: building a new site
|
|
100
158
|
|
|
@@ -168,6 +226,11 @@ recognise, a command that no longer exists).
|
|
|
168
226
|
8. **Domain cutover — only when a customer's own hostname is ready.** Skip this
|
|
169
227
|
entirely for demo sites; the GitHub Pages default already works.
|
|
170
228
|
|
|
229
|
+
If it *isn't* ready — the client may not own a domain, may not know who holds
|
|
230
|
+
it, or may have mail on it — that part is the bulk of the work and is in
|
|
231
|
+
[`recipes/domains.md`](./recipes/domains.md) under "Before the cutover". The
|
|
232
|
+
client buys their own domain, at their own registrar, in their own name.
|
|
233
|
+
|
|
171
234
|
Check what DNS the domain needs first. This changes nothing:
|
|
172
235
|
```
|
|
173
236
|
scribe site promote my-site --domain example.com --dns-only
|
|
@@ -201,12 +264,22 @@ recognise, a command that no longer exists).
|
|
|
201
264
|
sync — fix it in the Cloudflare dashboard, or the contact form silently rejects
|
|
202
265
|
real visitors on that domain.
|
|
203
266
|
|
|
267
|
+
**You do not need GitHub repo admin rights for any of this.** The Pages API call
|
|
268
|
+
is made by the admin app using Scribe's org token, so a write-scoped API key is
|
|
269
|
+
enough. If you find yourself checking whether the user can administer the repo,
|
|
270
|
+
you've left the supported path.
|
|
271
|
+
|
|
204
272
|
`scribe site update my-site --domain example.com` only edits the stored record
|
|
205
|
-
and the Turnstile widget. Use it to correct a domain, never to cut a site over
|
|
273
|
+
and the Turnstile widget. Use it to correct a domain, never to cut a site over —
|
|
274
|
+
the CLI now refuses that and points at `promote`. Deeper reference, including how
|
|
275
|
+
to repair a half-finished cutover: [`recipes/domains.md`](./recipes/domains.md).
|
|
206
276
|
|
|
207
277
|
## Working an existing site
|
|
208
278
|
|
|
209
279
|
```
|
|
280
|
+
scribe site promote <site> --domain <domain> [--dns-only] # take it live on a real domain
|
|
281
|
+
scribe site update <site> --turnstile-key <key> # correct stored settings only
|
|
282
|
+
|
|
210
283
|
scribe content list <site> [--collection <name>] [--json]
|
|
211
284
|
scribe content read <site> <path> [--json]
|
|
212
285
|
scribe content publish <site> <file> # validates against schema
|
|
@@ -223,8 +296,19 @@ scribe submission list <site> <collection> [--status <status>] [--page <n>] [--j
|
|
|
223
296
|
scribe submission update <site> <collection> <id> [--status <s>] [--note <n>]
|
|
224
297
|
scribe submission export <site> <collection> [--format csv|json] [--status <s>] [--out <file>]
|
|
225
298
|
scribe submission delete <site> <collection> <id> [--yes] # staff only
|
|
299
|
+
|
|
300
|
+
scribe request list [--site <slug>] [--status <s>] [--type <t>] [--mine|--unassigned] [--all] [--page <n>]
|
|
301
|
+
scribe request show <id> # the ask + the whole thread, internal notes included
|
|
302
|
+
scribe request claim <id> [--release]
|
|
303
|
+
scribe request reply <id> --message <text> [--internal]
|
|
304
|
+
scribe request status <id> <open|in-progress|waiting-on-you|done|cancelled>
|
|
226
305
|
```
|
|
227
306
|
|
|
307
|
+
- **"Publish/launch the site at example.com" means `scribe site promote`** — the full
|
|
308
|
+
domain cutover in one command — step 8 of the build workflow above, and in full in
|
|
309
|
+
[`recipes/domains.md`](./recipes/domains.md). It is not `content publish`, and
|
|
310
|
+
it is not `site update --domain` (which only rewrites the stored record and would
|
|
311
|
+
leave the site 404ing on the new host — the CLI refuses that now and tells you so).
|
|
228
312
|
- `scribe schema apply` is the way to add a form (or any collection with fields): it
|
|
229
313
|
takes a YAML/JSON file describing **one whole collection**, upserts it by `name`,
|
|
230
314
|
and validates through the admin's own parser first — so a reserved `status` field,
|
|
@@ -254,6 +338,53 @@ scribe submission delete <site> <collection> <id> [--yes] # staff only
|
|
|
254
338
|
**staff** role — a site user's API key gets a 403. It prompts for the id unless
|
|
255
339
|
`--yes` is passed. There is deliberately no equivalent in the admin UI, so don't go
|
|
256
340
|
looking for a delete button on the inbox.
|
|
341
|
+
- **`scribe request` is the other queue, and the opposite direction.** A submission is
|
|
342
|
+
a Visitor contacting the *client*; a Request is the **client contacting the agency**
|
|
343
|
+
to ask for work. One cross-site queue, staff-only, nothing in any repo. Three things
|
|
344
|
+
to know before touching it, with the rest in
|
|
345
|
+
[`recipes/requests.md`](./recipes/requests.md):
|
|
346
|
+
- **`waiting-on-you` means waiting on the _client_** — every status is phrased for
|
|
347
|
+
the Client's own dashboard. Read as an instruction to the agency it means the
|
|
348
|
+
opposite of what it says.
|
|
349
|
+
- **A visible `reply` is an email to the client**, sent immediately and permanently.
|
|
350
|
+
Show the user the text before sending unless they've said not to bother.
|
|
351
|
+
`--internal` is the Agency-only note: no email, invisible to the client, moves no
|
|
352
|
+
status.
|
|
353
|
+
- **There is no `create`.** A Request comes from the Client; filing one for them
|
|
354
|
+
would put words in their mouth. Say so rather than hunting for a flag.
|
|
355
|
+
|
|
356
|
+
## A site's two names, and the jobs only the admin UI can do
|
|
357
|
+
|
|
358
|
+
A site has a **slug** and a **display name**, and only one of them moves.
|
|
359
|
+
|
|
360
|
+
- The **slug** (`riverside-dental`) is the site's identity: the repo name, the
|
|
361
|
+
Pages URL, `?site=` on the submissions endpoint, and the argument to every
|
|
362
|
+
`scribe` command. **There is no rename** — not in the CLI, not in the admin.
|
|
363
|
+
Moving a site to a different slug means provisioning a new site. So when
|
|
364
|
+
someone is choosing a slug, it is worth one sentence of care up front.
|
|
365
|
+
- The **display name** is a label, and is editable any time: in the Staff console,
|
|
366
|
+
**Sites → the site → the Name field** at the top of the Details card, saved on
|
|
367
|
+
blur. It is allowed on archived sites too. `scribe site add --name` sets it at
|
|
368
|
+
creation; nothing in the CLI changes it afterwards.
|
|
369
|
+
|
|
370
|
+
A rename reaches the consoles and notification subjects and **nothing a Visitor
|
|
371
|
+
sees** — not the URL, and not `.scribe.yml`'s `siteName`, which is the website's
|
|
372
|
+
own copy of its name in a repo the rename doesn't write to. If the name is wrong
|
|
373
|
+
on the published pages too, that's a separate content edit in the repo.
|
|
374
|
+
|
|
375
|
+
Three other things live only in the Staff console, so route the user there rather
|
|
376
|
+
than hunting for a flag:
|
|
377
|
+
|
|
378
|
+
| Job | Where |
|
|
379
|
+
|---|---|
|
|
380
|
+
| Rename (display name) | Sites → the site → Name |
|
|
381
|
+
| Attach a site to a Client, or detach it | Sites → the site → **Client** |
|
|
382
|
+
| Star a site (sorts it to the top of the Sites list, and is what the staff Home page's Sites card shows) | Sites → the star |
|
|
383
|
+
|
|
384
|
+
And one that isn't available at all: **creating a login for a client's own
|
|
385
|
+
people**. There is no `scribe` command for it and no self-serve invite — user
|
|
386
|
+
management is super-admin only. "Give the client access to edit their content" is
|
|
387
|
+
a request to hand to Dave, with the site slug and who needs the login.
|
|
257
388
|
|
|
258
389
|
## Images — never hotlink, always commit the file
|
|
259
390
|
|
|
@@ -383,10 +514,21 @@ On a **form collection** specifically, since RFC 0004 moved submissions into Mon
|
|
|
383
514
|
- **An `image` field is rejected** on a form collection. The old path uploaded a
|
|
384
515
|
Visitor's file straight into the public repo, and a Mongo document is the wrong place
|
|
385
516
|
for a blob. Deferred to RFC 0007 (object storage).
|
|
386
|
-
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
517
|
+
- **New submissions are emailed** (RFC 0009, on RFC 0021's mailer), and
|
|
518
|
+
`notify:` is no longer how a *person* subscribes. Who gets one:
|
|
519
|
+
- **Site users on that Site are subscribed by default** — a lead nobody hears
|
|
520
|
+
about is the bug this closes, so the people whose business it is are opted in
|
|
521
|
+
unless they opt out.
|
|
522
|
+
- **Agency admins are not**, because they can reach every Site. They opt in per
|
|
523
|
+
Site per collection, under **Your Profile → Email notifications** in the admin.
|
|
524
|
+
- **`notify: [...]` now means addresses with no Scribe account** — a shared
|
|
525
|
+
`office@` inbox. Don't put a Scribe user's address in it; they manage their own.
|
|
526
|
+
|
|
527
|
+
The mail is best-effort and never fails the Visitor's POST, and `Reply-To` is
|
|
528
|
+
the Visitor's own address when the form has a field named `email` — that exact
|
|
529
|
+
name is the only signal, so a form whose address field is called something else
|
|
530
|
+
gets no `Reply-To`. So a client *can* be promised email on a new submission. The
|
|
531
|
+
inbox and its `needs-you` badge remain the thing of record.
|
|
390
532
|
|
|
391
533
|
Per field: `name`, `type`, `label`, `required`, `default`, `pattern`, `hidden`,
|
|
392
534
|
`readonly`, `isBody` (this field is the markdown body, not frontmatter), `list`
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Recipes
|
|
2
2
|
|
|
3
|
-
Patterns for building an Astro site against Scribe as the backend. Per
|
|
4
|
-
|
|
5
|
-
**advice, not enforcement** — read the one you need, adapt it to the site you're
|
|
3
|
+
Patterns for building an Astro site against Scribe as the backend. Per RFC
|
|
4
|
+
0010 these are **advice, not enforcement** — read the one you need, adapt it to the site you're
|
|
6
5
|
building, and ignore the rest. There is no template to conform to and no
|
|
7
6
|
generated config to keep in sync.
|
|
8
7
|
|
|
@@ -12,6 +11,15 @@ generated config to keep in sync.
|
|
|
12
11
|
| [`collections.md`](./collections.md) | rendering content (posts, products, events) that editors manage in Scribe |
|
|
13
12
|
| [`forms.md`](./forms.md) | putting one or more forms on the Site |
|
|
14
13
|
| [`deploy.md`](./deploy.md) | setting up or debugging the build and deploy |
|
|
14
|
+
| [`domains.md`](./domains.md) | finding out whether a client has a domain, getting them one, the DNS, taking a Site live on it, or repairing one |
|
|
15
|
+
| [`requests.md`](./requests.md) | working the queue of jobs clients have asked the agency for |
|
|
16
|
+
| [`prospects.md`](./prospects.md) | recording and nurturing prospects in the calling pipeline |
|
|
17
|
+
| [`proofs.md`](./proofs.md) | sending a client work to review (logo boards, mockups) and working the rounds |
|
|
18
|
+
|
|
19
|
+
`requests.md`, `prospects.md` and `proofs.md` are the odd ones out — they're
|
|
20
|
+
about the agency's own work (its queue, its sales pipeline, and the work it
|
|
21
|
+
sends clients to review) rather than anything in a Site's repo, and they live
|
|
22
|
+
here because the `scribe` CLI is the interface for all of it.
|
|
15
23
|
|
|
16
24
|
## The part that isn't advice
|
|
17
25
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Taking a site live on a custom domain
|
|
2
|
+
|
|
3
|
+
One command does all of it. Reach for `scribe site promote` whenever the ask is
|
|
4
|
+
"publish the site at example.com", "point the domain at the site", "take it
|
|
5
|
+
live", or "set up the custom domain".
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
scribe site promote <site> --domain example.com --dns-only # check DNS, change nothing
|
|
9
|
+
scribe site promote <site> --domain example.com # cut over
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Before the cutover: does the client even have a domain?
|
|
13
|
+
|
|
14
|
+
The agency user drives this whole thing themselves and is not a developer, so the
|
|
15
|
+
part that needs help is usually everything *before* `promote`. Work it in this
|
|
16
|
+
order, and say which step you're on.
|
|
17
|
+
|
|
18
|
+
**1. Find out what exists.** Don't take "we have a website" as "we have DNS we can
|
|
19
|
+
edit".
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
dig +short NS example.com # who runs the DNS — this is the one that matters
|
|
23
|
+
dig +short example.com # where the name points today, if anywhere
|
|
24
|
+
dig +short MX example.com # mail. See the warning below.
|
|
25
|
+
whois example.com | head -30 # registrar, expiry, status (may be privacy-masked)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The registrar on the invoice and the company running the DNS are often different.
|
|
29
|
+
**Follow the nameservers**, because that is where the records have to be added.
|
|
30
|
+
A `whois` that finds nothing registered is also the availability answer.
|
|
31
|
+
|
|
32
|
+
**2. If they don't own one, the client buys it.** They pay, it is registered in
|
|
33
|
+
their name, and they own it outright — never buy it on their behalf and never put
|
|
34
|
+
it in the agency's registrar. Help with the choice (business name, `.com` or the
|
|
35
|
+
local equivalent first, short, sayable on the phone, no hyphens or clever
|
|
36
|
+
spellings, nothing that pins them to one service or street), check candidates with
|
|
37
|
+
`whois`, and suggest they turn on auto-renew. Then they register it and come back
|
|
38
|
+
with access.
|
|
39
|
+
|
|
40
|
+
**3. Get DNS access.** Either their registrar login, or a call where they click
|
|
41
|
+
while you read out the records. Either is fine; the second is often faster. What
|
|
42
|
+
they're looking for is the screen listing records by type (`A`, `CNAME`, `MX`,
|
|
43
|
+
`TXT`) with an "Add record" button — every registrar names that screen
|
|
44
|
+
differently ("DNS", "Advanced DNS", "Manage DNS", "Nameservers").
|
|
45
|
+
|
|
46
|
+
Teach the shape of the task, not one provider's clicks. There is no supported
|
|
47
|
+
registrar; the client uses whatever they already have.
|
|
48
|
+
|
|
49
|
+
**4. Protect their email before you touch anything.** If `dig MX` returns records,
|
|
50
|
+
that domain carries their mail. The cutover only needs `A`/`CNAME` records for
|
|
51
|
+
the website — **say out loud that the `MX` and mail-related `TXT` records stay
|
|
52
|
+
exactly as they are**, and then make sure that is true. Breaking a client's email
|
|
53
|
+
is far worse than a late website, and it is the one mistake in this flow with no
|
|
54
|
+
quick undo from your side.
|
|
55
|
+
|
|
56
|
+
**5. Mind the old site.** If the domain currently serves a live website, the
|
|
57
|
+
switch is publicly visible. Agree a time rather than surprising them mid-trading.
|
|
58
|
+
|
|
59
|
+
Only then move on to `--dns-only` and the cutover below.
|
|
60
|
+
|
|
61
|
+
## You do not need GitHub admin rights
|
|
62
|
+
|
|
63
|
+
The Pages configuration call (`PUT /repos/<org>/<repo>/pages`) is made by the
|
|
64
|
+
**admin app**, using Scribe's org-scoped token — not by the signed-in user's
|
|
65
|
+
GitHub account. A site user with a write-scoped API key can run the whole
|
|
66
|
+
cutover. If you catch yourself checking whether someone can administer the repo,
|
|
67
|
+
you are off the supported path: go back to `scribe site promote`.
|
|
68
|
+
|
|
69
|
+
Corollary: **never** set any of this by hand — not `gh api .../pages`, not the
|
|
70
|
+
GitHub Pages settings page, not a hand-written `public/CNAME`. Each one alone
|
|
71
|
+
produces a broken site (see "Repairing a half-finished cutover" below).
|
|
72
|
+
|
|
73
|
+
## What promote actually does
|
|
74
|
+
|
|
75
|
+
In order, each step asserting current state before it writes:
|
|
76
|
+
|
|
77
|
+
1. Checks that DNS already resolves to GitHub Pages — and refuses to continue if
|
|
78
|
+
not, because step 2 kills the old project-page URL.
|
|
79
|
+
2. Commits `public/CNAME`. The deploy workflow keys off that file: present means
|
|
80
|
+
Astro builds with `base: '/'`, absent means `base: '/<repo>'`.
|
|
81
|
+
3. Registers the domain with GitHub Pages via the API. **Both step 2 and step 3
|
|
82
|
+
are required.** The repo's workflow uses `build_type: workflow`, and Pages
|
|
83
|
+
does not read `CNAME` out of a build artifact — so the file alone changes the
|
|
84
|
+
base path without ever requesting a certificate, and the API call alone
|
|
85
|
+
serves the site from the root with every asset still pointing at `/<repo>/`.
|
|
86
|
+
4. Sets `PUBLIC_SCRIBE_API_URL` so the contact form reaches the admin app, and
|
|
87
|
+
clears `PUBLIC_BASE_PATH`.
|
|
88
|
+
5. Updates the `Site` record — this is the hostname the public submissions
|
|
89
|
+
endpoint accepts CORS from.
|
|
90
|
+
6. Adds the domain to the Turnstile widget's allowed-domain list.
|
|
91
|
+
7. Re-enforces HTTPS, and dispatches a deploy.
|
|
92
|
+
|
|
93
|
+
## DNS
|
|
94
|
+
|
|
95
|
+
`--dns-only` prints the exact records. In short:
|
|
96
|
+
|
|
97
|
+
| Hostname | Records |
|
|
98
|
+
|---|---|
|
|
99
|
+
| Bare domain (`example.com`) | all four GitHub Pages **A** records |
|
|
100
|
+
| Subdomain (`www.example.com`) | one **CNAME** → `<org>.github.io` |
|
|
101
|
+
|
|
102
|
+
**In Cloudflare the record must be DNS-only (grey cloud), not proxied.** The
|
|
103
|
+
orange-cloud proxy blocks the ACME challenge GitHub uses to issue the
|
|
104
|
+
certificate, and promote will refuse with a `cloudflare-proxied` message.
|
|
105
|
+
|
|
106
|
+
`www` is not automatic. If a bare domain is the target and the client also wants
|
|
107
|
+
`www.example.com` to work, add a `www` CNAME → `<org>.github.io` at the
|
|
108
|
+
registrar; GitHub then redirects it to the apex on its own. Nothing in Scribe
|
|
109
|
+
needs to change for that.
|
|
110
|
+
|
|
111
|
+
## Re-running is the fix
|
|
112
|
+
|
|
113
|
+
Promotion is idempotent and there is deliberately no `site demote`. If a run
|
|
114
|
+
fails partway it prints which steps completed; fix the cause and run the same
|
|
115
|
+
command again.
|
|
116
|
+
|
|
117
|
+
The most common "failure" isn't one: setting a custom domain clears
|
|
118
|
+
`https_enforced`, and GitHub refuses to turn it back on until the certificate
|
|
119
|
+
exists. Promote retries at the end and warns if it isn't ready. Wait a few
|
|
120
|
+
minutes, re-run, done. Until then `http://` won't serve the site.
|
|
121
|
+
|
|
122
|
+
## Repairing a half-finished cutover
|
|
123
|
+
|
|
124
|
+
The three pieces of state — the `Site` record's domain, the Pages custom domain,
|
|
125
|
+
and `public/CNAME` — can each be set independently, and nothing in
|
|
126
|
+
`scribe site verify` currently compares them. A half-state looks healthy and
|
|
127
|
+
serves nothing.
|
|
128
|
+
|
|
129
|
+
| Symptom | What's missing |
|
|
130
|
+
|---|---|
|
|
131
|
+
| Domain 404s, no certificate ever issued | Pages custom domain not registered |
|
|
132
|
+
| Page loads but every asset/link 404s | `public/CNAME` missing, so the build still uses `base=/<repo>` |
|
|
133
|
+
| Old `github.io/<repo>` URL broke and the new domain isn't up | `public/CNAME` landed before the Pages domain was set |
|
|
134
|
+
| Form rejected with a CORS error on the new host | `Site` record still names the old domain |
|
|
135
|
+
|
|
136
|
+
The fix for all four is the same: `scribe site promote <site> --domain
|
|
137
|
+
example.com`. It reconciles whatever is already correct and writes the rest.
|
|
138
|
+
|
|
139
|
+
## `site update --domain` is not this
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
scribe site update <site> --domain example.com # record + Turnstile ONLY
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
It rewrites the stored hostname and syncs the Turnstile widget. It does not
|
|
146
|
+
touch DNS, `public/CNAME`, or Pages. Using it to go live leaves a site that
|
|
147
|
+
claims a domain serving nothing — the exact half-state above. The CLI now
|
|
148
|
+
refuses when it detects a cutover (a site still on `<org>.github.io` being moved
|
|
149
|
+
to a real hostname) and points at `promote`; `--record-only` overrides it.
|
|
150
|
+
|
|
151
|
+
Legitimate use: correcting a typo in a domain that is already live.
|
|
@@ -310,8 +310,11 @@ inbox already saying so.
|
|
|
310
310
|
|
|
311
311
|
- **Two forms, one page:** fine, as long as element ids are unique. The snippet
|
|
312
312
|
above scopes everything to `scribe-form-<collection>`.
|
|
313
|
-
-
|
|
314
|
-
|
|
313
|
+
- **New submissions are emailed** (RFC 0009), but `notify:` is only for addresses
|
|
314
|
+
with **no Scribe account** — a shared `office@` inbox. Site users on the Site are
|
|
315
|
+
subscribed by default and manage it themselves under Your Profile → Email
|
|
316
|
+
notifications; agency admins are opted out by default and opt in per Site. Adding
|
|
317
|
+
a Scribe user's address to `notify:` is redundant, not helpful.
|
|
315
318
|
- **Rate limiting is per Site and IP, not per form**, so hammering one form while
|
|
316
319
|
testing will also throttle the others.
|
|
317
320
|
- **An unchecked checkbox in `FormData` is absent, not `false`.** The payload
|