the owner pointed a project at the platform's repo root — an easy mistake, since
`todo/` sits inside one — and got "the todo board is owner-only, and this account
was refused". three things were wrong and only one of them was the path.
A THEME IS NOW A DIRECTORY WITH AN `_index.md`. readTree assumed every subdirectory
was one, which was safe when the only possible root was the platform's own todo
folder and is not safe now. against a repo root it read `src/_index.md`, threw
ENOENT, and the route 500'd. skipping non-themes is also just correct for a real
todo folder, which may hold a README beside its themes.
THE ERROR MESSAGE WAS A LIE IT INHERITED. "owner-only, and this account was
refused" was true of `/todos` in the platform, where the permission was
`kind: 'admin'`. here it is grantable and there is no such gate — so the sentence
survived the extraction describing a rule that no longer exists, and the first real
failure it met was reported as a permission problem. it shows the actual error now.
a wrong explanation is worse than none: it sent the owner to check their own
account when the answer was in the panel beside them.
AND AN EMPTY FOLDER SAYS SO. no themes at all is almost always this same mistake,
so it names it — a theme is a directory with an `_index.md`, and if you pointed at
a repository the folder you want is usually `todo/` inside it. an empty board
otherwise reads as "no work outstanding", which is the opposite of the truth.
verified: repo root now 200 with 0 themes and the explanation; the real folder
reads 38 themes and 139 items.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
the project form asked for a path and gave a text field, while fofos-admin — built
hours earlier — had a directory picker for exactly the same question. that picker
is now shared from the officerdev barrel, so this uses it.
browse OR type: the picker fills the field and the FIELD is what saves, so the path
stays visible and editable before it is stored. a folder outside home is still
reachable by typing, and the server refuses it with a reason rather than the picker
silently making it unreachable.
picking a folder offers its last two segments as the name when the name is empty —
`thing/todo` — because that is what somebody would have typed. left editable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
was `/todos` in the platform: a board, an API and a tree reader pointed at
`resolve(process.cwd(), 'todo')`. that is not a setting — it is the belief that
there is one project and it is the one the server happens to have been started in.
THE READER CAME ACROSS UNCHANGED except for that one line. the frontmatter parser
that never rewrites a body, the ordering, the index writer — all of it as it was,
and its 8 tests came too and still pass. everything that changed is that the
directory is now a parameter.
`writeIndex` no longer writes to `process.cwd()` either. that was the same
assumption wearing a different hat, and with two projects it would have had every
board overwriting one file. the map goes beside the folder it describes.
A PROJECT IS A NAME AND A PATH, and paths are confined to the owner's home by the
same three checks av-club uses — absolute, realpath BEFORE the containment test,
and `root` or `root + sep` rather than a bare startsWith. spelled out again rather
than cross-referenced, because the next person to add a path-taking route reads the
file they are in.
it stores NO ITEMS. one table, a list of folders. uninstalling with "delete its
data" ticked loses the list and never a line of anybody's work — which is the
property the markdown format was chosen for.
`/projects` is owner-only: pointing this at a directory is a statement about the
filesystem. moving a card is not, so a member granted `kanban` can work any board
they can see.
removing a project removes the ROW. the route says so in its response and the
button says so in its tooltip, because "delete" beside a folder full of somebody's
work should not be ambiguous.
README records the seam honestly: the platform keeps its own todo/ and its CLI, so
there are two copies of the reader and they will drift. the alternative was making
the platform's own backlog depend on a plugin being installed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>