Commit Graph

457 Commits

Author SHA1 Message Date
Jakub Zych
a9a7bbef73 fix(10.2): revise plans based on checker feedback 2026-09-28 01:56:53 +02:00
Jakub Zych
039cfeddfd docs(10.2): create phase plan 2026-09-28 01:46:23 +02:00
Jakub Zych
195bf2ce75 docs(state): record phase 12 context session 2026-09-28 01:28:26 +02:00
Jakub Zych
4f2358e26c docs(12): capture phase context 2026-09-28 01:28:25 +02:00
Jakub Zych
a64d5aaaa7 docs: capture exploration — backend-deployment 2026-09-28 01:27:19 +02:00
Jakub Zych
cbb5a516ef docs(state): record phase 10.1 context session 2026-09-28 00:55:00 +02:00
Jakub Zych
17250cfbd6 docs(10.1): capture phase context 2026-09-28 00:54:55 +02:00
Jakub Zych
547bd0fc17 docs(state): record phase 11 context session 2026-09-28 00:54:38 +02:00
Jakub Zych
be8bfccf98 docs(11): capture phase context 2026-09-28 00:54:36 +02:00
Jakub Zych
df45520dd8 docs: capture exploration — apparatus dissolved into framework 2026-09-28 00:39:43 +02:00
Jakub Zych
7ac75b918d test(09): persist human verification items as UAT 2026-09-28 00:03:21 +02:00
Jakub Zych
2ad19bda21 docs(09): record code review disposition 2026-09-27 23:52:18 +02:00
Jakub Zych
ee79c7f2c9 docs(09): add code review report 2026-09-27 23:51:58 +02:00
Jakub Zych
57f2204ece docs(phase-10): complete phase execution 2026-09-27 20:45:17 +02:00
Jakub Zych
35f55c733d docs(10): re-verify phase after CR-01 fix 2026-09-27 20:45:11 +02:00
Jakub Zych
c7487f6799 docs(10): re-review CR-01 fix and record approved UAT 2026-09-27 20:38:18 +02:00
Jakub Zych
7e015638f7 docs: log full-width admin forms fast task 2026-09-27 20:32:03 +02:00
Jakub Zych
25856710c7 fix(admin): render record and settings forms full width 2026-09-27 20:32:02 +02:00
Jakub Zych
a405b1b7ff docs(quick-260927-q23): fix CR-01: /auth/refresh must enforce tokens_valid_after and is_activated 2026-09-27 19:12:05 +02:00
Jakub Zych
a13a1214cb test(bouncer,cabana): cover admin refresh subject checks without a database
Quick 260927-q23 (CR-01), unit coverage that runs under -short.

- bouncer: TestRefreshAudienceForSubject covers active, pre/post cutoff,
  missing, nil provider, non-numeric sub, provider error, and proves
  token-only refusals never reach the provider
- bouncer: TestJWTGuardTokensValidAfter pins the unchanged "User not found"
  message and errors.Is(err, ErrSubjectRejected)
- cabana: TestPhase10Coverage subtest pins cookie expiry on subject
  refusals, no cookies over Bearer or on a provider error, and the
  post-cutoff success path
2026-09-27 19:00:12 +02:00
Jakub Zych
be4a923f36 fix(cabana): enforce tokens_valid_after and is_activated on admin refresh
Fixes review finding CR-01 (quick 260927-q23): POST {prefix}/api/v1/auth/refresh
minted a new token without loading the admin, so a session kept alive by the
SPA's refresh-on-401 survived admin:reset-password, deactivation and deletion.
This broke Phase 9 truth T-09-04.

- bouncer: extract the JWT guard's subject lookup into subjectPrincipal and
  issuedBeforeCutoff (same order and messages), add ErrSubjectRejected
- bouncer: add RefreshAudienceFor, which runs the guard's subject checks
  after the token-only checks and before minting; Refresh and
  RefreshAudience are unchanged (nil hook)
- cabana: share one lazyBackendUsers provider between the backend guard and
  refresh; a cookie refresh refused for its subject expires summer_admin
- test: TestAdminRefreshRevocation (Postgres, real admin:reset-password)
2026-09-27 18:58:15 +02:00
Jakub Zych
815cb903c6 test(10): persist human verification items as UAT 2026-09-27 18:44:38 +02:00
Jakub Zych
f47a560cc8 docs(10): add phase verification report 2026-09-27 18:44:23 +02:00
Jakub Zych
6918ec5998 docs(10): add code review report and disposition 2026-09-27 18:36:06 +02:00
Jakub Zych
473a454c29 docs(10-05): record plan 05 progress, decisions and ADMIN-06 in state, roadmap and requirements 2026-09-27 18:24:07 +02:00
Jakub Zych
3bdf6c9301 docs(10-05): complete unit tests, assembled acceptance and phase gate plan 2026-09-27 18:23:44 +02:00
Jakub Zych
074fc52e5e docs(10-05): Phase 10 security review and final validation map
- 10-SECURITY-REVIEW.md: T-10-01..T-10-25 and T-10-SC with mitigation,
  test or gate stage, observed result, residual risk and the removal
  (mutation) checks behind every high threat
- 10-VALIDATION.md: executed task commands, gate statuses, Wave 0 done,
  nyquist_compliant after scripts/check-phase10.sh --all passed
2026-09-27 18:22:01 +02:00
Jakub Zych
fbef773a24 test(10-05): hygiene confines browser storage and self-tests each rule
- --hygiene refuses localStorage, sessionStorage, indexedDB or document.cookie
  outside admin/src/state/useSidebar.ts (T-10-22)
- --self-test plants each violation with a scratch test import, so the
  refusal must come from that rule and not from the untested-module check
2026-09-27 18:15:05 +02:00
Jakub Zych
07edc6ca29 test(10-05): fail-closed Phase 10 gate script
- scripts/check-phase10.sh with --self-test, --go, --security, --postgres,
  --spa, --openapi, --dist, --hygiene, --evidence and --all
- phase10_detect refuses failed, skipped, zero-test, non-JSON and build-failed
  go test runs and named tests that did not pass
- the two known fonoteka parity failures are the only allow-listed ones and
  refuse the gate once they pass again
- hygiene enforces the framework/app boundary, SC-4 alias-only API types,
  typed-client-only HTTP, no raw HTML, same-origin dist, named lucide imports,
  no retired admin prefix routes and a test import for every SPA module
2026-09-27 18:10:59 +02:00
Jakub Zych
ef448da1cc test(10-05): cover every Phase 10 Go change with branch-level tests
- bouncer TestPhase10CookieGuard: cookie read without Bearer, Bearer wins,
  empty cookie, frontend audience and blacklisted jti rejected
- boardwalk TestPhase10BoardwalkServing: HEAD, query strings, encoded
  traversal, index by name, nested prefix, MIME fallback, constructor errors
- cabana TestPhase10Coverage: mounted unsafe routes vs the CSRF walk, option
  and filter edges, read-only labels, relation message defaults, bundle
  fallback locale, cookie refresh of an expired token in the refresh window
- phrasebook override precedence, new locale, Bundle merge order, Forms shapes
- surf prefix collision for deeper paths and the default /backend prefix
- swagger2openapi TestUnionRewrite and converter branch tests
- framework tests no longer name the application (acme fixtures instead)
2026-09-27 18:05:28 +02:00
Jakub Zych
1c2a66df45 test(10-05): bring every SPA module, composable and component under Vitest
- 41 unit and component suites under admin/tests/{app,state,shell,list,form,relation,views,ui}
  covering states and a11y roles; every src module is imported by a test
- typed fixture helper assigns each JSON fixture to its generated OpenAPI type
- fix: iconFor ignores inherited object members such as "constructor"
- fix: field controls import ./control instead of the registry (import cycle
  left a renderer unregistered depending on module load order)
- fix: dropdown shows the placeholder for an unknown stored value next to an emptyOption
- fix: list announces a failed schema load even when the rows arrive after it
- tailwind no longer scans admin/tests; boardwalk/dist rebuilt
2026-09-27 17:53:57 +02:00
Jakub Zych
8259a456bb docs(10-04): complete relation manager and shell polish plan 2026-09-27 17:29:15 +02:00
Jakub Zych
445404e394 feat(10-04): collapsible panel with flyout, user menu with logout, breadcrumbs and dark mode
- useSidebar: collapsed below 1100px (matchMedia) or by the admin's choice,
  persisted as a boolean under summer-admin.sidebar; the viewport never
  overwrites the stored choice
- SectionPanel collapse and rail expand buttons; SectionFlyout (role menu)
  opens on hover, focus, Enter or ArrowDown on a rail item, closes on Esc or
  about 200 ms after leaving and returns focus to the rail item
- Breadcrumbs with plugin, controller and record crumbs; UserMenu (Reka
  DropdownMenu) with initials, name, role and Wyloguj
- useAuth.logout POSTs /auth/logout, clears user, navigation and settings
  and routes to login even when the call fails
- applyColorScheme toggles .dark from prefers-color-scheme (no toggle, A6)
- newest toast first, 200 ms fade and scale for dialogs and toasts
- one relation-manager type constant in the registry
- shell smoke tests; tests default to a desktop, light matchMedia
2026-09-27 17:26:44 +02:00
Jakub Zych
f4e97cccad feat(10-04): search, link and unlink related records through the relation manager
- relation-manager registered in the field registry; renders only on an
  existing record, never on create, and is never part of the save body
- RelationManager: relation schema label and comment, debounced search,
  selectable linked list (DataTable relation variant), toolbar buttons in
  declared order, confirmed unlink with plural messages and toasts
- RelationPickerModal: Reka Dialog (aria-modal, focus trap, Esc) over the
  candidates endpoint five per page, selection kept across pages, Dodaj (N)
  POSTs link, focus returns to the opener
- admin OpenAPI documents search, sort, dir, page and per_page on the linked
  and candidate relation routes so the SPA sends them typed
- neutral acme.demo.widgets members fixtures and relation smoke tests
2026-09-27 17:18:14 +02:00
Jakub Zych
6e1b6dd5bf docs(10-03): record plan 03 progress in state and roadmap 2026-09-27 17:02:50 +02:00
Jakub Zych
1964844eb9 docs(10-03): complete admin lists, forms, filters and settings plan 2026-09-27 17:02:31 +02:00
Jakub Zych
8f32416f4f feat(10-03): tabs, toggles, relation fields, form lifecycle and settings pages
- FormTabs groups fields by tab (untabbed fields in the default tab) as a
  segmented tablist; a tab holding invalid fields after a 422 shows a
  count badge and the form switches to the first invalid field
- switch, checkbox and relation join the renderer registry: toggle cards
  (role=switch, 20px checkbox) keep a numeric value numeric; relation
  fields are read-only labels from meta.labels, a searchable single
  select over fields/{field}/options with emptyOption first, or ordered
  removable chips with an appending search (300 ms debounce, 20 per
  page, more on scroll or the more action)
- FormView gets the back button, record title and update subtitle, a
  sticky footer (Usuń with deleteConfirm then DELETE, Anuluj, Zapisz i
  zamknij to the mapped redirectClose, Zapisz), and asks before leaving a
  dirty form on any route change plus a beforeunload guard
- Settings: the rail pins Ustawienia to the bottom when /settings is
  non-empty; /settings lists pages by category; /settings/:code renders
  the settings schema through FormGrid and the registry, PUTs the values
  and maps a 422 like the record form
- New backend::lang keys (form.more_options, tab_default, discard,
  settings.back); form and settings smoke tests; boardwalk/dist rebuilt
2026-09-27 17:00:18 +02:00
Jakub Zych
8b5f85603f feat(10-03): search, sort, filter, page and bulk-delete any list
- List state (search, sort, dir, page, per_page, filter[<name>]) lives in
  the URL query through parseListQuery/toListQuery; every change is a
  router replace and clears the selection; search is debounced 300 ms and
  resets the page
- DataTable renders the schema columns with a tri-state page checkbox,
  asc/desc/none sorting with aria-sort, selected rows, a sticky header,
  eight skeleton rows while loading and an empty slot
- CellValue renders text (muted dash when empty, arrays comma-joined),
  datetime as YYYY-MM-DD HH:mm and switch as the Tak/Nie pills
- The heading shows the plural recordCount and the create button;
  delete sits in the toolbar, disabled without a selection, and confirms
  with the plural deleteConfirm in a Reka alert dialog before POSTing
  bulk-delete; a 409 shows a danger toast
- FilterBar renders switch (JSON of the option value), daterange
  (from..to) and scope filters (choices from filters/{scope}/options)
- Pagination shows the range, the per-page select over perPageOptions
  (hidden with one choice) and a pager with ellipsis
- The tracer smoke test skips the new checkbox column; new backend::lang
  list keys; boardwalk/dist rebuilt
2026-09-27 16:51:00 +02:00
Jakub Zych
126ca5b8ed feat(10-03): open, edit and save a record with toast and 422 feedback
- The SPA loads the backend::lang bundle before /auth/me, sets the
  document language from meta.locale and renders plural messages with
  Intl.PluralRules; interpolate mirrors phrasebook for :name/:Name/:NAME
- Create and record routes; mapWinterUrl maps recordUrl and redirects
  onto the controller's list, create and record routes only
- List rows open their record; FormView loads the form schema and the
  record, shows context-allowed fields in the span grid, saves values
  keyed by field name and toasts the resolved saved message
- A 422 puts each message under its field (aria-invalid,
  aria-describedby), shows the plural banner, focuses the first invalid
  field in schema order and clears a field's error on change
- The D-05 registry maps text, textarea, number and dropdown; any other
  type renders the unsupported-field box with the type in DM Mono
- The admin OpenAPI document declares the write request bodies
  (AdminRecord, AdminIDsRequest) and the list filter query as a
  deepObject, so the typed client can send them
- New backend::lang form.load_failed key; boardwalk/dist rebuilt
2026-09-27 16:43:47 +02:00
Jakub Zych
453b8ae786 docs(10-02): complete admin backend contract plan 2026-09-27 16:30:15 +02:00
Jakub Zych
9f296b0484 feat(10-02): filter choices and a fully typed admin API proven on the wire
- pact.FilterOptions on the model serves a scope filter's choices; a scope
  filter whose model lacks it fails activation (D-27)
- GET /{vendor}/{plugin}/{controller}/filters/{scope}/options answers a
  declared scope filter behind the controller permission with localized
  {value, label} choices, 404 otherwise
- Every admin route documents a typed success schema, and protected routes
  document 401, 403 and 404 (422 on writes); SuccessEnvelope is gone and
  logout writes a typed AdminLogoutData
- jsonScalar and fieldContext decode their served shapes
- TestPhase10OpenAPIConformance calls every inventoried route through the
  assembled router on PostgreSQL and decodes each body into its documented
  type with unknown fields disallowed, checking admin.json's schema ref
- The SPA aliases every new schema type; Tailwind no longer scans the
  generated API files, so API changes do not churn boardwalk/dist
2026-09-27 16:27:42 +02:00
Jakub Zych
c87148a34f feat(10-02): backend strings, controller messages and declarative toolbar
- phrasebook ships the backend::lang admin strings (pl, en) with CLDR
  plural maps, loads them as namespace backend, applies
  pact.HasLangOverrides trees (lang/<locale>/<namespace>/<group>.yaml)
  after every namespace, and fails activation when a backend key cannot
  convert to plural forms
- Translator.Forms, Bundle, Resolved and Has serve keys as CLDR form maps
- Public GET /lang returns every backend::lang key for the request
  locale over the fallback locale, Cache-Control no-cache
- config_list, config_form and config_relation accept a strict messages
  block; omitted keys take framework defaults, schemas serve every message
  as CLDR forms, and activation fails on a missing phrase key
- toolbar.buttons is an ordered [create, delete] list; the Winter string
  form, duplicates, unknown actions and delete without showCheckboxes fail
  at boot, and create is dropped when the controller has no form
- Form schema serves the raw Winter redirects; scaffold emits the list
  syntax; form and relation schema routes are typed in the admin OpenAPI
2026-09-27 16:16:32 +02:00
Jakub Zych
fe04dbc89e feat(10-02): relation field options and relation saves with labels
- FieldRelationContract/FieldRelationProvider bind every type: relation
  field to a belongsTo foreign key or a belongsToMany pivot; activation
  fails naming plugin, controller and field on a missing or broken contract
- GET /{vendor}/{plugin}/{controller}/fields/{field}/options serves
  {value, label} pages scoped by pact.RelationExtendOptionsQuery, behind
  the controller permission; read-only and non-relation fields are 404
- Saves apply present relation keys after the Before hook: ids are
  revalidated through the same scoped query (422 and full rollback
  otherwise), belongsTo sets the foreign key, belongsToMany replaces pivot
  rows in submitted order with the order column set to the index
- Show, create and update return relation values in data and meta.labels
- A belongsTo on a protected fill key is read-only (D-26)
- One six-segment GET pattern dispatches relation lists and field options,
  which ServeMux cannot register side by side
- Admin OpenAPI documents the options route and RecordEnvelope
2026-09-27 16:00:52 +02:00
Jakub Zych
e9b48d4720 docs(10-01): complete admin SPA tracer plan 2026-09-27 15:37:02 +02:00
Jakub Zych
dafdb18234 feat(10-01): harden the admin cookie session and prefix boot guards
- refresh and logout read the Bearer header first, then the summer_admin
  cookie; a cookie refresh rotates the cookie without a token in the body and
  logout always expires the cookie
- backend.cookie_secure (default true) may drop Secure outside production only
- activation rejects controller vendor segments api, assets, login, settings
- BuildRouter rejects non-cabana routes at or under the admin prefix
- SPA single-flights refresh on 401, replays once, and refreshes proactively
  at 80 percent of expires_in; dist rebuilt
- scripts/check-admin-dist.sh rebuilds the SPA and fails on dist drift
- tests: TestPhase10CookieAuth, TestPhase10CSRF, TestPhase10Prefix,
  TestPhase10AdminPrefixCollision, boardwalk serving and header tests
2026-09-27 15:34:19 +02:00
Jakub Zych
5f9353841b feat(10-01): serve the embedded admin SPA at backend.uri with cookie login
- backend.uri prefix (default /backend) mounts the admin API at {prefix}/api/v1
  and the embedded SPA shell at {prefix} with an api/ JSON 404 fallback
- cookie transport: an X-Requested-With login sets the HttpOnly summer_admin
  cookie and returns no token; the backend guard reads the cookie after Bearer
- CSRF wrapper refuses cookie-only POST/PUT/DELETE without X-Requested-With
- boardwalk package embeds boardwalk/dist, rewrites index.html once per prefix
  and sets cache and security headers
- framework admin OpenAPI pipeline (swag, swagger2openapi, openapi-typescript)
  with prefix-relative paths and typed envelopes for the tracer routes
- admin/ Vite SPA: login, plugin rail, section panel and read-only list
  through the openapi-fetch client typed by the generated schema
2026-09-27 15:21:48 +02:00
Jakub Zych
8c3e131111 docs(10): create phase plan 2026-09-27 14:11:07 +02:00
Jakub Zych
42c7216f5f docs(10): record plan-time decisions and plan count 2026-09-27 13:26:11 +02:00
Jakub Zych
ec97007637 docs(10): research admin Vue SPA phase 2026-09-27 13:23:46 +02:00
Jakub Zych
92fb6e323f docs(09-12): record the phase 9 acceptance evidence
- Security review names the test that fails if each high control is removed.
- Validation rows now point at the phase gate commands.
- Roadmap shows 12/12 plans executed.
2026-09-27 03:03:09 +02:00