# Daily Word — next steps

Ordered so each step is independently verifiable. Steps 1–3 are yours (Rock admin
+ your prototype file). Step 4 is mine.

---

## 1. Apply the M'Cheyne patch to the prototype

`mcheyne-patch.md`, delivered earlier. Replace lines 426–429 of
`Reading Plan Builder v5 polish.dc.html`; delete the now-dead `const otx` on 422.

**Verify:** open the file, pick M'Cheyne from "Start from a proven plan".
Day 1 should read **Genesis 1 · Matthew 1 · Ezra 1 · Acts 1**. If any track is
blank on day 1, the book arrays didn't paste in order.

---

## 2. Create the person attribute

Admin Tools → Person Attributes. Settings that matter:

| field | value | why |
|---|---|---|
| Key | `DailyWordPlan` | the endpoint looks this up by key |
| Field Type | **Memo** | Text caps out; Memo is nvarchar(max) |
| Category | Discipleship (or new) | keeps it off the main profile |
| Show in Grid | No | |
| Allow Search | No | |
| Security → View | the person themselves | |
| Security → Edit | **nobody** | writes go through the endpoint, not the UI |

**Size note:** the blob is small at first and grows as `checks` fills up —
roughly 25 KB by day 365 on a four-track plan (~1,460 keys). Fine for Memo, but
it is rewritten whole on every check-off, so keep the client debounce.

---

## 3. Create the save endpoint

New endpoint on the Daily Word Lava Application:

- **Slug:** `save-plan`
- **Method:** POST
- **Security Mode:** Application View (same as your Service Planner endpoints)
- **Enabled Lava Commands:** `Sql`
- **Template:** `save-plan.lava` (in this folder)

**Verify before any markup exists** — this is the point of doing it now.
Sign in to manage.goodnewsde.com in a browser, open the console, and run:

```js
await fetch("/api/v2/lava-app/1/daily-word/save-plan", {
  method: "POST",
  headers: { "Content-Type": "application/json",
             "X-Helix-CSRF-Protection": "true" },
  body: JSON.stringify({ plan: JSON.stringify({ hello: "world" }) })
}).then(r => r.json());
```

Expect `{ok: true, bytes: 17}`. Then check your own person record in Rock admin
and confirm `DailyWordPlan` holds `{"hello":"world"}`. Run it twice — the second
call must update the same row, not create a second one.

**If it fails:** a 401 with no detail is usually the missing CSRF header, not
permissions. A 500 mentioning the attribute means step 2's key doesn't match.

**No read endpoint needed.** Loading is a merge field on the page:

```
<script type="application/json" id="dw-plan">
{{ CurrentPerson | Attribute:'DailyWordPlan','RawValue' | Default:'null' }}
</script>
```

---

## 4. Then tell me, and I build the Today view

`renderVals()` → vanilla render-to-HTML functions, Today first: smallest of the
five views, the one people open daily, and the one that exercises the check-off
write path step 3 just proved.

Day reader comes last — it is the only view blocked on the Bible-proxy decision.

---

## Still parked

- **Bible proxy.** My recommendation is an Azure Function over a Rock endpoint,
  to keep chapter fetches off the 10 DTUs. Not needed until the day reader.
- **Streak semantics.** A ten-day run on a plan with rest days currently reports
  7. Correct per spec, reads wrong on a badge. Product call, not a bug.
