# todo.item
The shape of one to-do item, shared by every `todo.*` capability, and the two
checks that say whether one is acceptable. `Todo` is what is stored;
`TodoDraft` is the part a person edits (the add and edit forms, and what
todo.parse-quick-add produces); `Recurrence` says how an item repeats.
`validateDraft` is for forms: it returns `valid` and one message per field
that needs fixing, keyed by the field's name, so a form can show each message
under its input and an API can return them as a validation error. It never
throws. `validateTodo` is for stored items (read back from storage, or
imported): the same rules plus the ones only a stored item has.
## The rules
- **title**: judged after trimming, 1 to 200 characters, one line (no control
characters). In a stored todo it must already be trimmed.
- **notes**: optional, up to 2000 characters.
- **priority**: `none`, `low`, `medium` or `high`.
- **due**: optional, a real calendar date `YYYY-MM-DD`. A due date has no time
of day: a to-do is due on a day.
- **tags**: at most 10, each in the normal form todo.normalise-tags produces
(lower-case ASCII letters and digits, runs joined by single hyphens), at
most 30 characters, no duplicates. The first problem is reported.
- **recurrence**: optional; frequency `daily`, `weekdays`, `weekly`,
`monthly` or `yearly`, interval 1 to 999 (weekdays only 1), a real `anchor`
date, and it needs a due date no earlier than the anchor.
- **id** (stored): not blank. Ids are the caller's: pass one in.
- **createdAt**, **completedAt** (stored): UTC timestamps
`YYYY-MM-DDTHH:MM:SS[.fraction]Z`, as JavaScript's `toISOString` writes
them. Offsets are refused so that timestamps compare as strings.
`completedAt` is set exactly when `done` is true.
- **order** (stored): the manual position, a whole number 0 or more.
## Decisions
"Characters" are Unicode code points, which all three languages count the
same way: 200 emoji is 200 characters, not 400 UTF-16 units.
Trimming removes ASCII whitespace only (space, tab, CR, LF, VT, FF). The
three standard libraries trim different sets of Unicode spaces, so a wider
trim would store different titles in different services.
The anchor is why month ends survive: a monthly todo anchored on 31 January
is due 28 February, then 31 March, because every occurrence is counted from
the anchor (todo.next-occurrence). Without it, the 28 February copy would
drift to the 28th for ever.
Messages are full sentences written for the person at the form, and the same
in every language.