112 lines
7.1 KiB
Markdown
112 lines
7.1 KiB
Markdown
# todo
|
||
|
||
## Scoring
|
||
|
||
`Score = 100 * V / (2**S + 8)`
|
||
|
||
`Bar = 1`
|
||
|
||
`Next ID = 45`
|
||
|
||
## Items
|
||
|
||
| ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score |
|
||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||
| 44 | 0.4.21 | | defect | **Show which filter segment or chip is selected and focused on a browser without `:has()`.** | 1 | 2 | 2 | 3 | 2 | 4 by 4 | 23.9 |
|
||
| 13 | 0.4.21 | | | **Accept a verification code pasted with surrounding whitespace.** | 4 | 2 | 3 | 7 | 7 | 2 by 8 | 1.0 |
|
||
| 19 | 0.5.0 | | question | **Run the documented Docker commands on macOS and fix whatever misbehaves.** | 2 | 2 | 1 | 3 | 3 | 1 by 3 | 3.3 |
|
||
| 16 | 0.5.0 | | question | **Decide whether the single Keto `Resource` namespace splits into per-domain namespaces.** | 3 | 2 | 3 | 6 | 6 | 7 by 2 | 0.5 |
|
||
| 6 | 0.5.0 | | | **Warn at discovery when a route or nav node gates on a permission no plugin declares.** | 2 | 1 | 1 | 2 | 2 | 7 by 3, 9 by 3 | 8.0 |
|
||
| 23 | 0.5.0 | | | **Give list pages one view-model helper from query to pagination, instead of ~40 hand-written lines each.** | 3 | 1 | 2 | 4 | 5 | 1 by 4, 9 by 2, code health by 3 | 7.9 |
|
||
| 43 | 0.5.0 | | | **Let a plugin version the scripts and other `/public/` files its own markup links, so they are cached as immutable too.** | 2 | 2 | 1 | 3 | 3 | 8 by 3, 7 by 2 | 5.0 |
|
||
| 28 | 0.5.0 | | | **Let a plugin add entries to the profile menu through the plugin API.** | 2 | 2 | 2 | 4 | 4 | 7 by 4, 1 by 2 | 4.2 |
|
||
| 2 | 0.5.0 | | | **Rename the admin example plugin to a name that says what it administers.** | 3 | 1 | 2 | 4 | 6 | 9 by 3, code health by 2 | 2.6 |
|
||
| 5 | 0.5.0 | | | **List grants that no installed plugin declares, with a remove action.** | 2 | 2 | 2 | 4 | 4 | 2 by 3 | 2.1 |
|
||
| 41 | 0.5.0 | | | **Apply a permission save as one Keto call, so it cannot stop part-way.** | 2 | 2 | 2 | 4 | 3 | 2 by 2 | 2.1 |
|
||
| 14 | 0.5.0 | | | **Drop a double-clicked duplicate submit, with no client-side JavaScript.** | 4 | 2 | 3 | 7 | 7 | 2 by 7, 1 by 4 | 1.4 |
|
||
|
||
## Details
|
||
|
||
### 44. Show which filter segment or chip is selected and focused on a browser without `:has()`.
|
||
|
||
`.segmented input` and `.chip input` are `opacity: 0`, and only `:has(input:checked)` and
|
||
`:has(input:focus-visible)` rules mark the choice. On Firefox 115, Chromium 87–104 and Safari
|
||
15.0–15.3 a filter shows no selected state and no keyboard focus, which README → "Two browser
|
||
floors" forbids. Show the native inputs in `public/css/styles.css`'s `@supports not selector(:has(a))`
|
||
block.
|
||
|
||
### 13. Accept a verification code pasted with surrounding whitespace.
|
||
|
||
A pasted code fails the browser's `pattern` check. No zero-JS fix exists: `pattern`
|
||
cannot transform, so loosening it only lets the untrimmed value through to Kratos. **Check first:**
|
||
`kratos-admin.ts` returns a `recovery_link` alongside the code; if the stock courier mail can carry
|
||
one, a template change fixes this with no host code. Otherwise proxy the flow POST through the host:
|
||
`submitFlow` (`src/auth/kratos-public.ts`) already relays cookies and normalises a 422
|
||
`redirect_browser_to`, and has no callers outside tests. CSRF improves, since the POST becomes
|
||
same-origin and `form-action 'self'` can join the CSP. Risks: one `flow.ui.action` serves all five
|
||
flows, so this rewrites the sign-in path; and Go's nosurf checks Referer only over https, which no
|
||
test covers. Code entry has no E2E coverage today.
|
||
|
||
### 19. Run the documented Docker commands on macOS and fix whatever misbehaves.
|
||
|
||
Needs a Mac. Two suspects, both from `--user "$(id -u):$(id -g)"`: a macOS `id -g` is `20`, which is
|
||
`dialout` inside the noble image, and Docker Desktop remaps bind-mount ownership in its VM.
|
||
|
||
### 16. Decide whether the single Keto `Resource` namespace splits into per-domain namespaces.
|
||
|
||
Ory's own examples model `Shift`, `Document` and so on. One global `Resource` bucket is the
|
||
project's "no catch-all names" rule applied to namespaces.
|
||
|
||
### 6. Warn at discovery when a route or nav node gates on a permission no plugin declares.
|
||
|
||
Declaring stays optional on purpose, but the picker is built from declarations only, so such a route
|
||
is ungrantable from the GUI and answers a permanent 403. A warning, not an error.
|
||
|
||
### 23. Give list pages one view-model helper from query to pagination, instead of ~40 hand-written lines each.
|
||
|
||
Every list screen bridges `parseListQuery`/`paginate` to the partials by hand. At minimum a
|
||
`buildPaginationModel(page, hrefFor)`. Exported through the barrel, so it is contract surface.
|
||
|
||
### 43. Let a plugin version the scripts and other `/public/` files its own markup links, so they are cached as immutable too.
|
||
|
||
The host versions every `/public/` href it renders (`src/http/static.ts`): the shell's stylesheets,
|
||
favicon and logo, and a plugin's `styles`. A file a plugin's own markup links, such as fastjira's
|
||
`board-drag.js`, keeps an unversioned URL and is revalidated every five minutes. Offering a way —
|
||
`assetHref` documented as a view local, a `ctx.assetHref`, or a `scripts` slot in the shell — adds to
|
||
the plugin API, hence a minor. Pick one with the plugin authors' panel, then document it in README →
|
||
Reserved view locals.
|
||
|
||
### 28. Let a plugin add entries to the profile menu through the plugin API.
|
||
|
||
The profile dropdown stays a dropdown: Sign out is its only entry today, and it will gain more.
|
||
`views/partials/shell.ejs` hand-rolls it (AGENTS.md → UI, the dropdown rule), so the entries need a
|
||
manifest field that discovery checks, gated like a nav node.
|
||
|
||
### 2. Rename the admin example plugin to a name that says what it administers.
|
||
|
||
Candidates: `auth-admin`, `users-groups-admin`. The id is also the mount path, so the compose files,
|
||
E2E stacks and README move with it.
|
||
|
||
### 5. List grants that no installed plugin declares, with a remove action.
|
||
|
||
`grantDiff` never revokes an undeclared name, and nothing shows one either, so it can't be audited or
|
||
cleaned, and reinstalling its plugin silently reactivates access nobody remembers granting.
|
||
|
||
### 41. Apply a permission save as one Keto call, so it cannot stop part-way.
|
||
|
||
`applyGrants` writes and deletes one tuple per request and reports a partial save when one fails.
|
||
**Check first:** Keto documents `PATCH /admin/relation-tuples`, which should apply a list of inserts
|
||
and deletes in one transaction; confirm that against the Keto version `ory/` pins. If so, add the
|
||
call to `KetoClient`, which is contract surface (`@plainpages/plugin-api`) and so needs 0.5.0, and the
|
||
partial-failure path in the admin example can go.
|
||
|
||
### 14. Drop a double-clicked duplicate submit, with no client-side JavaScript.
|
||
|
||
A second identical POST is expected from a non-technical user, and today creates two
|
||
users, mints two recovery codes, or registers two OAuth2 clients. It must not break a legitimately
|
||
repeatable action. Sketch: a CSS-only affordance so the second click has nothing to hit, plus the
|
||
host recognising a duplicate (same session, route and payload within a short window), logging and
|
||
dropping it. Open: what identifies "the same submission" (a one-time token minted into each form
|
||
beats hashing the payload), the window, where the record lives given the host is stateless, and how
|
||
a plugin declares a route repeatable.
|