All source files · Workbench

backend-notes.md

# Deadline Loom — Sanity integration

The backend contains six Sanity document types: competitions, evidence sources, source claims, proposed evidence revisions, review decisions, and project notes. It separates accepted source facts from scheduling assumptions. The 28-document seed contains three real DEV competitions checked on October 2, 2026 at 17:14 UTC. One earlier-deadline example is explicitly simulated; the 4/6/8 build-hour and 20/25/45 human-minute values are illustrative estimates.

The public Sanity project is `2mflxxa8`, dataset `production`. The seed import succeeded. Actual anonymous queries and `getProofboardData()` returned all 28 seed documents in `mode: "live"`; all three competition references and deadlines were checked. An authenticated Studio rehearsal subsequently added one approved simulated decision. No write token is used by the reader. If configuration or public access is unavailable, the frontend returns `mode: "sample"` with a visible notice.

## Free project without a payment method

Sanity's current [Understanding the Growth plan trial](https://www.sanity.io/docs/platform-management/growth-plan-trial) documentation (updated July 27, 2026) says new projects receive a free trial automatically; charges begin only if the user upgrades. Adding payment details is part of upgrading. Without an upgrade/payment details, the project moves to Free when the trial ends.

[Plans and payments](https://www.sanity.io/docs/platform-management/plans-and-payments) (updated September 23, 2026) says Free and Growth Trial have hard caps and no overages. [Pricing](https://www.sanity.io/pricing) lists Free at $0 with two public datasets, 10,000 documents, and free Studio hosting. The model uses ordinary public Content Lake documents and custom Studio actions; it does not depend on paid Comments, Tasks, scheduled drafts, or Content Releases.

The demo uses a public dataset and a free trial that returns to Free without a paid upgrade. It contains ordinary content documents and custom Studio actions.

## Configuration

The Astro public reader uses only these public routing values:

```dotenv
PUBLIC_SANITY_PROJECT_ID=2mflxxa8
PUBLIC_SANITY_DATASET=production
```

The standalone Studio uses its standard public environment names:

```dotenv
SANITY_STUDIO_PROJECT_ID=2mflxxa8
SANITY_STUDIO_DATASET=production
```

The local seed process reads `SANITY_PROJECT_ID`, `SANITY_DATASET`, and `SANITY_API_WRITE_TOKEN` from its process environment. The write token must never have a `PUBLIC_` prefix, enter source control, or be sent to the frontend. Studio uses its normal signed-in user session rather than that seed token. Node 24 can load a private, ignored `.env` with `node --env-file=.env scripts/seed-sanity.mjs --apply`; never print the file contents.

For browser-side public fetching, allow the deployed origin in Sanity CORS without credentials. The Astro build uses a fixture without making network requests; the browser replaces it with published content when a public query succeeds. The source is the [Query API / HTTP API](https://www.sanity.io/docs/http-reference) with a fixed API version and `perspective=published`.

## Seed and verification

From the project directory:

```sh
node scripts/seed-sanity.mjs
```

This validates IDs, types, references, date ordering, and simulation/estimate labels without a network request or mutation. It passed for all 28 seed documents. The authorized `--apply` import also succeeded against `2mflxxa8/production`, and a live public-read check found 3 competitions, 12 sources, 7 claims, 1 revision, 1 pending review, and 4 notes. To validate a configured target remotely without committing data, use `--apply --dry-run`. By default seeding uses `createIfNotExists`, preserving existing documents. Add `--replace` only when intentionally replacing documents with these stable seed IDs.

The seed does not create a dataset or account. API mutations bypass Studio schema validation, so the local script performs relevant checks first; see [Sanity's import guidance](https://www.sanity.io/docs/content-lake/importing-data).

The deployed browser reader was verified against `https://deadline-loom-jaye-2026.netlify.app` with the exact origin allowed by CORS and credentials disabled. The dataset now contains 29 documents: the 28 seed documents plus one persisted simulated review. The verification note was updated separately, preserving the approved revision and review history. Review decisions are displayed newest first.

Hosted responsive checks passed at 1440×1000 and 390×844 with no page overflow. Selecting the simulated source version reduced estimated slack by seven hours; checking a prerequisite changed the remaining count; modifying a recorded local plan marked its decision stale. UTC conversion, scenario reset, and the connected public review display also passed. Actual hosted screenshots are saved as `public/desktop.png` and `public/mobile.png`, with original JPEG captures alongside them.

## Review workflow

In Studio, open an `evidenceRevision`, check linked sources, and publish its proposed values. The document actions include **Approve evidence revision** and **Reject evidence revision**. Each asks for a public review reason, creates a decision record, and changes revision status in one transaction. A real approval also applies the proposed accepted field; rejection keeps it unchanged. Optimistic revision guards reject a stale review if the underlying documents changed. A simulated approval records the rehearsal but never changes a real competition's accepted deadline.

`createReviewDecision()` in `src/lib/sanity.ts` prepares a `localOnly: true` record for an interactive preview. It makes no network request. The Astro reader contains no write API. A local preview choice is not a Studio approval or persisted decision.

The workflow is implemented with [Sanity's Document Actions API](https://www.sanity.io/docs/studio/document-actions-api). The schema and action modules imported successfully with the actual SDK. The loader passed sample, mocked-live, network-failure fallback, local-only review, and actual token-free public-read checks. On October 2 at 17:39:34 UTC, an authorized agent operated the signed-in Studio and approved the simulated revision with an explicit simulation reason. An anonymous query confirmed the new decision and approved revision while the real competition deadline remained `2026-10-05T06:59:00Z`. Rejection is implemented but was not independently rehearsed in the live dataset.

## Source facts used in the seed

| Competition | Closing instant (UTC) | Chicago time | Winner announcement | Official source |
| --- | --- | --- | --- | --- |
| Hacktoberfest Weekend: Build for a Friend | 2026-10-05 06:59 | October 5, 1:59 AM CDT | Week of October 5 | [Contest rules](https://dev.to/page/hacktoberfest-weekend-challenge-26-10-01-contest-rules) |
| Sanity Challenge | 2026-10-05 06:59 | October 5, 1:59 AM CDT | October 22 | [Contest rules](https://dev.to/page/sanity-challenge-v26-09-16-contest-rules) |
| Kaggle Benchmarking Challenge | 2026-10-12 06:59 | October 12, 1:59 AM CDT | November 5 | [Contest rules](https://dev.to/page/kaggle-2026-09-23-contest-rules) |

AI assistance is permitted by each challenge's FAQ. Each requires new work during its entry window. DEV's [general rules](https://dev.to/page/official-hackathon-rules) retain entrant ownership with a sponsor license for contest/promotion. Prize eligibility/release/tax information may be required within seven business days of notice; delivery may take two to four weeks after accepted paperwork. The payment rail is not published. These events do not promise payment by October 4.

Sanity Path Two specifically asks for an AI-native IDE, Next.js or Astro, and Sanity. A DEV template post with `#sanitychallenge` needs the Sanity project ID or public dataset URL, with testing instructions if login is required. Its judging criteria are honest build-process write-up, functioning app, schema thoughtfulness, and originality. See the [Sanity Challenge](https://dev.to/challenges/sanity-2026-09-16).

The dataset intentionally contains no personal friend stories, account email addresses, identity documents, tax IDs, credentials, or financial records. Public editor role labels are generic. Only public rules, source URLs, planning assumptions, and explicitly simulated examples belong here.