# Sheetward App Specification — reference for AI assistants

Version 1.0 · 2026-09-29 · https://sheetward.com/app-specification.md

Sheetward turns a **specification workbook** (Excel or Google Sheets) into a
hosted, multi-user web app: forms, records, dropdowns, validation, calculated
fields, dashboards and translations. The same workbook always produces the same
app. This page tells an AI assistant exactly how to write one.

**Your job:** write the workbook. The user uploads it in Sheetward
(**New App → upload a workbook**), where it is checked, shown for review, and
built only when the user approves. You never create the app yourself.

## 1. How to hand the workbook over

- If you can create files, produce an **.xlsx** file with the sheets below.
- If you can't, output **each sheet as a table**, headed by the sheet's exact
  name, so the user can paste it into Excel or Google Sheets. Row 1 of each
  table is row 1 of the sheet.
- Name the file after the app, for example `Purchase Orders.xlsx`.
- Use **generic sample values** only (one or two rows per form). Never include
  real customer data, names or anything sensitive: a specification is a
  blueprint, not a data store.

## 2. Ground rules

- Write field names, titles, list values and samples in **English** — every
  app's base language. Sheet prefixes (`Form_`, `Rules_` …), section markers
  (`HEADER`, `LINE ITEMS`) and rule keywords are always English. Other display
  languages go on a `Translation_` sheet (section 11).
- Sheet names: at most 31 characters, unique, none of `[ ] : * ? / \`.
- Only the prefixes below are recognized. Other sheets produce a warning.
- Keep forms focused: **at most 6 sections and 50 fields per form**; a typical
  form has 4–12 fields. Split distinct record types into separate `Form_`
  sheets (2–4 is typical for a business domain).
- The user's plan limits how many forms and dashboards one app may have.
  Sheetward reports it at upload if a workbook exceeds them.

## 3. Sheets

| Sheet | How many | Purpose | Also accepted |
|---|---|---|---|
| `Form_<Name>` | one or more | One form each (a record type). **Required** — unless the workbook is a survey. | |
| `Survey_<Name>` | exactly one | A questionnaire instead of forms (section 12). Never mix with `Form_` sheets or add `Rules_`/`Formula_` to a survey. | |
| `List_<Name>` | any | Master data for dropdowns (section 8). | `Master_`, `LOV_` |
| `Rules_` | at most one | Validation, keys, defaults, explicit data types (section 6). | `Rule_`, `Validation_` |
| `Formula_` | at most one | Calculated fields (section 9). | `Formulas_`, `Logic_` |
| `Report_<Name>` | any | One dashboard page each (section 10). Only when asked for. | `Analytics_` |
| `Info_` | at most one | App help text and regional hints (section 13). | |
| `Translation_App` | at most one | Display labels in other languages (section 11). | any `Translation_` name |

## 4. Form sheets

Cell **A1** holds the form's display title, row 2 is **empty**, and the fields
start on row 3. Pick **one** layout per form:

1. **Columns** (register-style forms): a row of field names, then 1–2 sample
   rows directly below.
2. **Pairs** (one-record documents): one field per row — the name in column A,
   a sample value in column B.
3. **Header + lines** (invoices, orders, expense reports): a `HEADER` marker
   row, the header fields as pairs, an empty row, a `LINE ITEMS` marker row,
   then the line table as a row of field names plus sample rows.

A form may have **several line tables** only when the user clearly describes
separate row collections (a work order with parts *and* labor). Each table's
marker is then an ALL-CAPS title ending in `LINES` or `LINE ITEMS`
(`PART LINES`, `LABOR LINE ITEMS`), each unique, all after the header.

These block the upload — never do them:

- a line table before the header, or more than one `HEADER` section;
- two line tables with the same title, or an extra table whose title doesn't end in `LINES` / `LINE ITEMS`;
- the same form defined twice (as columns and as pairs);
- a sample value with no field name beside or above it;
- a `Form_` sheet with a title but no fields;
- more than one `Rules_` or `Formula_` sheet;
- `Form_` and `Survey_` sheets in the same workbook.

## 5. How field types are decided

Highest wins:

1. an explicit **Data Type** on a `Rules_` row;
2. the **field name** — `date` → date; `price`, `amount`, `total`, `cost`, `fee` → currency; `quantity`/`qty` → quantity; `email`, `phone`, `url`; `photo`/`picture`/`avatar` → image; `rating`/`stars` → rating;
3. the **sample value** — whole number → integer, decimals → number, a cell formatted as money → currency, a real date cell → date;
4. otherwise text.

So make sample values typical, format money cells as currency, and write dates
as `YYYY-MM-DD`. Declare a Data Type only when the name and sample can't
convey it.

## 6. `Rules_` sheet

Row 1 is the header; one rule per row after it:

| Field | Rule Type | Data Type | Value | Message | Section | Form |
|---|---|---|---|---|---|---|

- **Field** — the field name as written on the form. **Section** — `HEADER`,
  `LINE ITEMS` (or the line table's title); blank for single-section forms.
  **Form** — the form's sheet name without `Form_` (`Purchase_Order`); always
  fill it when there are several forms. **Message** — optional custom error.
- One field may carry several rules: one row each.
- **Data Type** only: leave Rule Type **empty** to declare a type without a
  rule. Never write a column name (such as "Data Type") into the Rule Type cell.

| Rule Type | Meaning |
|---|---|
| `required` | Can't be blank. |
| `optional` | Explicitly optional; also a harmless row for declaring a Data Type. |
| `key` | The record's business key (at most one per form); imports match on it. |
| `subkey` | Second key part; at most one, only together with a key. |
| `auto` | Numbered automatically on create, starting at 1 (or at the number in Value — only if the user asked). An auto field is the key: add a separate `key` row on the same field, and give that section no other key. |
| `min` / `max` | Lowest / highest value: a number, a date (`2026-07-01`) or another field's name. |
| `min length` / `max length` | Text length bounds. |
| `between` | `between 0 and 100`, or `between start_date and end_date from HEADER` for a line field bounded by header fields; bounds may be `today`. |
| `pattern` | Value is a regular expression. |
| `conditional` | `required if status is 'Active'` or `(total > 100) then required`; conditions use `= != > >= < <=`, `AND` / `OR` / `XOR`, quoted strings and field names. |
| `display` | Shown read-only, never typed; pair with a default. |
| `sensitive` | Personal or confidential (national IDs, bank details, salary): masked in the UI and exports, encrypted at rest. A rule type, never a Data Type. |
| `public` | Only fields marked `public` appear on the app's published public page. |
| `derived` | Looked up, never typed: `from Products` (a whole record) or `Product.UOM` / `UOM from Product` (one column of a master list). |
| `calc` | Computed and stored by a currency or unit conversion (see the conversions guide linked below). |

**Defaults** ride any rule's Value: `default value "Active"`, `default = 0`,
`default = HEADER.currency_code`, or `system date` / `today` / `now` for the
creation date.

Start/end date pairs (`start_date`/`end_date`, `from_date`/`to_date`) are
checked automatically — no rule needed.

## 7. Data types

For the Data Type column (lower-case):

| Type | Use |
|---|---|
| `text`, `textarea` | Text; cap length with `text(50)`. |
| `integer`, `number`, `percent` | Whole numbers; decimals (`decimal(4)` for more places); percentages. |
| `currency`, `quantity` | Money with a currency picker; an amount with a unit-of-measure picker. |
| `date`, `datetime`, `time`, `month`, `year` | Calendar values (`YYYY-MM-DD`, `HH:MM`, `YYYY-MM`, `2026`). |
| `boolean` | Yes/no checkbox. |
| `dropdown`, `multi` | One / several values from a `List_` sheet or a built-in standard list. |
| `rating` | 1–5 stars (`rating(10)` for a longer scale). Don't add min/max rules for its range. |
| `email`, `phone`, `url` | Validated contact fields. |
| `image`, `video`, `audio`, `doc`, `file` | Uploads; images, video, audio, safe documents, any file. |
| `relation` | Picks a record from another form of the same app. |
| `ulid`, `nanoid` | Generated identifiers (use with `auto`). |
| `ssn`, `national_id`, `bank_id`, `credit_card`, `routing_number`, `upc`, `zip`, `postal_code` | Checked identifiers; the sensitive ones are masked. Card numbers keep only the last 4 digits. |

## 8. `List_` sheets (dropdowns and master data)

- Row 1: column names; then one row per value. A form field whose name
  matches the list's **first column** becomes a dropdown (`List_Status` with
  first column `Status` → the `Status` field).
- Extra columns auto-fill form fields with the same names when a value is
  picked (choose a product → its price and unit arrive with it).
- Give every category / status / type / priority field a list of 4–8
  realistic values.
- Model a thing **either** as a `Form_` (records the team maintains) **or** as
  a `List_` (a short, stable set to pick from) — never both.
- Countries, US states, currencies, units of measure, languages and time zones
  are **built in**: declare the field's type or name it plainly (Country,
  Currency, Unit) instead of shipping your own copy. A `List_` sheet that
  duplicates a built-in list is ignored with a warning.
- Translated values: add `<column>_<code>` columns (`status_de`, `status_ja`)
  beside the values.

## 9. `Formula_` sheet (calculated fields)

| Output Field | Formula | Description | Section | Form |
|---|---|---|---|---|

- The output field is read-only and computed live; also put it on the form
  with a sample of the right type.
- Refer to fields in **snake_case** (`Unit Price` → `unit_price`). Use
  `+ - * / ( )`, comparisons, `IF(condition, then, else)`, `AND` / `OR` /
  `NOT`, `abs`, `round`, `min`, `max`, `sum`.
- A header total over the lines: `sum of amount` (also `total of`,
  `count of`, `average of`). A line formula reads a header value as
  `rate from HEADER`.
- Formulas work **within one record** only. A figure across many records
  (an average over all reviews) belongs on a dashboard instead.

## 10. `Report_` sheets (dashboards — only when the user asks)

| Widget | Title | Form | Section | Measure | Aggregate | Rows | Columns | Chart | Width |
|---|---|---|---|---|---|---|---|---|---|

- **Widget**: `title`, `kpi`, `chart`, `pivot`, `table` or `filter`.
- **Form** / **Section**: the records the widget reads (`HEADER` or the line
  table). **Measure**: the field to total, or `*` to count. **Aggregate**:
  `sum`, `average`, `count`, `min`, `max`.
- **Rows**: group-by fields, comma-separated; dates can bucket
  (`order_date by month` / `quarter` / `year`). **Chart**: `bar`, `line`,
  `area`, `pie`, `donut`. **Width**: columns out of 12.
- Start with a `title` row; keep a dashboard to 3–6 widgets.

## 11. `Translation_App` sheet (other display languages)

Additional languages: `de` (German), `ja` (Japanese), `ar` (Arabic). Add the
sheet only when the user wants them.

| Object Type | Object | Section | Form | de | ja |
|---|---|---|---|---|---|

- Object types: `app`, `form`, `section`, `field`, `message`, `list`,
  `widget`, `measure`, and for surveys `question` and `choices`
  (`report` and `dashboard` are accepted spellings of `widget`).
- **Object** is the English name exactly as written elsewhere. Fill Section and
  Form on field rows.
- Translate every form title, section title, field label, custom message and
  widget title into every requested language. Field names, sheet names,
  samples and formulas stay English.
- The workspace must have the language enabled, or the upload is refused with
  a message saying which one.

## 12. `Survey_` sheet (questionnaires)

One `Survey_` sheet, no `Form_`, `Rules_` or `Formula_` sheets. Row 1:

| Section | Question | Response | Choices | Required | Default |
|---|---|---|---|---|---|

- Section carries down — write it only when it changes. End with a
  `SUBMISSION` section holding Name (text, required) and Email (email).
- **Response**: any data type, or `rating` / `rating(10)`, `choice` (radio
  buttons), `dropdown` (a select, usually bound to a `List_`), `multi`.
- **Choices**: options separated by `|` (`Excellent | Good | Poor`), a
  `List_` sheet name, or for a rating the two end labels
  (`Very unlikely | Very likely`). Add `Other (please specify)` for a
  free-text alternative — the specify box is added automatically.
- **Required**: `Yes`, or `key` for the one answer that blocks duplicate
  submissions (typically Email). Don't number questions.

## 13. `Info_` sheet

- Regional defaults, one per row: `Country`, `Currency` or `Locale` in
  column A and the code in column B (`Currency` | `USD`), or both in one cell
  (`Currency: USD`). Codes: ISO country (`US`), ISO currency (`USD`), BCP-47
  locale (`en-US`).
- Any other rows are plain text that becomes the app's "about" help; blank
  rows separate paragraphs, and simple markdown (`## heading`, `- bullet`)
  works.

## 14. Complete example

A purchase-order app with a dashboard. Each table is one sheet; the **Row**
column is the sheet's row number and letters are columns.

### `Form_Purchase_Order`

| Row | A | B | C | D |
|---|---|---|---|---|
| 1 | Purchase Orders | | | |
| 2 | | | | |
| 3 | HEADER | | | |
| 4 | PO Number | PO-100 | | |
| 5 | Supplier | Acme Supplies | | |
| 6 | Order Date | 2026-02-01 | | |
| 7 | Status | Draft | | |
| 8 | Total | 137.50 | | |
| 9 | | | | |
| 10 | LINE ITEMS | | | |
| 11 | Item | Quantity | Unit Price | Amount |
| 12 | Copy paper A4 | 5 | 12.50 | 62.50 |
| 13 | Toner cartridge | 1 | 75.00 | 75.00 |

### `List_Supplier`

| Row | A |
|---|---|
| 1 | Supplier |
| 2 | Acme Supplies |
| 3 | Globex Trading |
| 4 | Initech Ltd |

### `List_Status`

| Row | A |
|---|---|
| 1 | Status |
| 2 | Draft |
| 3 | Sent |
| 4 | Received |

### `Rules_`

| Row | A | B | C | D | E | F | G |
|---|---|---|---|---|---|---|---|
| 1 | Field | Rule Type | Data Type | Value | Message | Section | Form |
| 2 | PO Number | key | | | | HEADER | Purchase_Order |
| 3 | PO Number | auto | | | | HEADER | Purchase_Order |
| 4 | Supplier | required | | | | HEADER | Purchase_Order |
| 5 | Order Date | required | date | system date | | HEADER | Purchase_Order |
| 6 | Status | required | | default value "Draft" | | HEADER | Purchase_Order |
| 7 | Quantity | min | | 1 | Order at least one | LINE ITEMS | Purchase_Order |

### `Formula_`

| Row | A | B | C | D | E |
|---|---|---|---|---|---|
| 1 | Output Field | Formula | Description | Section | Form |
| 2 | Amount | quantity * unit_price | Line amount | LINE ITEMS | Purchase_Order |
| 3 | Total | sum of amount | Order total | HEADER | Purchase_Order |

### `Report_Purchasing`

| Row | A | B | C | D | E | F | G | H | I | J |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | Widget | Title | Form | Section | Measure | Aggregate | Rows | Columns | Chart | Width |
| 2 | title | Purchasing overview | | | | | | | | |
| 3 | kpi | Orders | Purchase_Order | HEADER | * | count | | | | 6 |
| 4 | kpi | Total spend | Purchase_Order | HEADER | total | sum | | | | 6 |
| 5 | chart | Spend by month | Purchase_Order | HEADER | total | sum | order_date by month | | bar | 12 |

### `Info_`

| Row | A | B |
|---|---|---|
| 1 | Currency | USD |
| 2 | Track purchase orders from draft to received. | |

In Excel, format the Total, Unit Price and Amount cells as currency and the
Order Date cell as a date.

## 15. Before you hand it over

- Every form has a title in A1, an empty row 2, and one layout.
- Every status/category field has a `List_` sheet; each form has a key (or auto + key).
- Totals and amounts have `Formula_` rows, and those fields also appear on the form.
- Names in `Rules_`, `Formula_` and `Report_` match the form exactly.
- Sample data is fictional.
- Tell the user any assumptions you made, and that Sheetward will list any
  problems when they upload. Its **Reshape with AI** button can fix a workbook
  that doesn't pass.

## More

- Full human guide: https://sheetward.com/help/workbook/ ·
  forms https://sheetward.com/help/workbook-forms/ ·
  rules https://sheetward.com/help/rules/ (and /help/rules-reference/) ·
  types https://sheetward.com/help/types/ ·
  formulas https://sheetward.com/help/formulas/ ·
  dashboards https://sheetward.com/help/dashboards/ ·
  surveys https://sheetward.com/help/surveys/ ·
  languages https://sheetward.com/help/multi-language/
- Complete example workbooks: https://sheetward.com/templates/
- Sheetward can also draft a specification itself: **New App → Create with AI**.
