Commit Graph

623 Commits

Author SHA1 Message Date
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
Jakub Zych
4392550e23 feat(09-12): add the phase 9 acceptance gate
- Document every D-09 admin route for the OpenAPI contract.
- Fail the gate on skipped tests, zero-test runs, and a missing admin path.
2026-09-27 03:02:00 +02:00
Jakub Zych
30bfd2d8d5 test(09-12): add the phase 9 security matrix
- Guard isolation covers audience, secret, refresh, blacklist, and reset cutoff.
- The mounted admin route table must carry the backend guard.
- Fresh PostgreSQL migrate and rollback keep framework and plugin histories apart.
2026-09-27 03:01:54 +02:00
Jakub Zych
2efe51a168 docs(10): capture phase context 2026-09-26 23:21:43 +02:00
Jakub Zych
13760e3a1a docs(09-11): complete admin metadata and settings plan 2026-09-26 23:08:06 +02:00
Jakub Zych
10ca7a02e3 feat(09-11): add permissioned admin metadata and settings 2026-09-26 23:06:22 +02:00
Jakub Zych
8b02fff028 docs(09-10): complete collections relation manager plan 2026-09-26 21:36:21 +02:00
Jakub Zych
12081c18d1 feat(09-10): add typed relation manager 2026-09-26 21:33:43 +02:00
Jakub Zych
d7d48e2fbe feat(09-10): add typed relation manager 2026-09-26 21:33:31 +02:00
Jakub Zych
53d59dbc92 docs(09-09): complete styles admin controller plan 2026-09-26 15:10:18 +02:00
Jakub Zych
e9c0722337 docs(09-08): complete genres admin controller plan 2026-09-26 11:25:00 +02:00
Jakub Zych
e6d013717f docs(09-07): complete artists admin controller plan 2026-09-25 21:57:54 +02:00
Jakub Zych
fe639ac0d3 docs(09-06): record the plan metadata commit 2026-09-24 20:22:27 +02:00
Jakub Zych
2a955d6447 docs(09-06): complete albums admin collection boundary plan 2026-09-24 20:22:07 +02:00
Jakub Zych
0caa86ec0b feat(09-06): keep relation required flags off unbound columns
- Schema JSON still reports required relations for the client
- Save validation only adds required for scalar writable fields
2026-09-24 20:19:29 +02:00
Jakub Zych
c63146accb feat(09-06): serve admin form schemas and match Winter relations
- GET schema/form localizes the compiled form after the permission check
- relation: genre resolves to the exported Go field without changing the YAML key
2026-09-24 20:10:48 +02:00
Jakub Zych
3e7738ff32 docs(09-05): complete schema-projected CRUD plan 2026-09-24 19:48:29 +02:00
Jakub Zych
50754808f6 feat(09-05): make bulk delete atomic, ordered, and retry-safe
- Reject an empty selection and dedupe ids before locking rows in pk order
- Return deleted 0 when every requested row is already gone, without hooks
- Roll back mixed, hook, and cancelled batches so no partial delete commits
2026-09-24 19:45:15 +02:00
Jakub Zych
247c3235f6 test(09-05): add failing tests for deterministic bulk delete
- Empty selections are 422 and duplicates run once in primary-key order
- A completed retry and an all-absent selection delete nothing and skip hooks
- Mixed, hook, cancel, and concurrent requests keep the batch atomic
2026-09-24 19:43:15 +02:00
Jakub Zych
e3e1c2546e feat(09-05): enforce scoped record lifecycle on admin routes
- Mount show, create, update, and delete behind the backend permission check
- Run controller and model hooks once per operation and roll back on failure
- Treat missing and out-of-scope records the same, including idempotent delete
2026-09-24 19:39:08 +02:00
Jakub Zych
94814d980b test(09-05): add failing tests for scoped record lifecycle
- Record routes must enforce permission before ids or bodies and return D-10 envelopes
- Create, update, and delete run Before and After hooks once inside the transaction
- Out-of-scope and missing records are indistinguishable, and hook failure rolls back
2026-09-24 19:38:23 +02:00
Jakub Zych
578bdc8d5d feat(09-05): project writable fields through Fill and Validate
- Bind schema fields to model columns at activation and drop protected keys
- Create and update Fill, run BeforeValidate, then Validate before persistence
- Missing Fill or Validate capability and provider errors fail closed
2026-09-24 19:28:36 +02:00
Jakub Zych
1e14da7bb5 test(09-05): add failing tests for writable fill and validate
- Create and update must Fill then Validate and return D-10 422 field errors
- Schema bindings exclude protected, cased, nested, and unknown keys
- Missing Fill or Validate capability fails closed with controller context
2026-09-24 19:25:18 +02:00
Jakub Zych
040f3ef81c docs(09-04): complete deterministic admin list queries plan 2026-09-24 19:07:01 +02:00
Jakub Zych
3efdcc1c59 fix(09-04): keep relation columns out of the default sort set
- A relation column is not sortable unless columns.yaml says so
- An explicit sortable relation orders the joined select column, then the primary key
2026-09-24 19:04:42 +02:00
Jakub Zych
6a57f63e81 feat(09-04): execute allowlisted deterministic list queries
- Search, sort, filters, and pagination use compiled selectors and bound values
- Equal sort keys break ties on the primary key so adjacent pages do not overlap
- Unknown identifiers return validation_failed before SQL
2026-09-24 19:03:44 +02:00
Jakub Zych
7f451c3572 test(09-04): add failing tests for deterministic list queries
- Search, sort, filters, and adjacent pages must return the D-11 envelope
- Empty and single results keep an array and the requested page size
- Unknown identifiers and injected values fail closed before unsafe SQL
2026-09-24 18:58:56 +02:00
Jakub Zych
d3a93073c9 feat(09-04): compile switch, date-range, and scope filters
- Filters keep typed values and only registered scope names
- Raw conditions and arbitrary methods fail activation
- Request localization copies labels and leaves identifiers unchanged
2026-09-24 18:53:52 +02:00
Jakub Zych
cb832eb70c test(09-04): add failing tests for typed list filters
- Switch, date-range, and model-scope filters must keep typed values
- Option labels localize without changing identifiers or cached keys
- Raw conditions, unknown scopes, and arbitrary methods fail activation
2026-09-24 18:50:17 +02:00
Jakub Zych
aab4398ce4 feat(09-04): compile ordered Winter list schemas
- Typed columns, actions, default sort, search term, and page sizes
- Omitted sortable defaults to true and empty collections marshal as arrays
- Unknown keys, bad defaults, and path escape fail before routes are served
2026-09-24 18:46:53 +02:00
Jakub Zych
fd591ed3a7 test(09-04): add failing tests for ordered list schemas
- Columns, actions, default sort, and page sizes must compile to typed JSON
- Empty and single declarations stay arrays and keep source order
- Unsupported keys, actions, defaults, and path escape fail activation
2026-09-24 18:43:26 +02:00
Jakub Zych
db3d7222e9 docs(09-03): complete typed winter form schema plan 2026-09-24 18:27:51 +02:00
Jakub Zych
68715fc260 feat(09-03): scaffold Winter admin controller layout
- config_form.yaml and config_list.yaml point at models/<name>/fields.yaml and columns.yaml
- Duplicate model or controller assets fail before any new file is written
2026-09-24 18:25:20 +02:00
Jakub Zych
af8e58a038 test(09-03): add failing tests for Winter admin controller scaffolding
- make:admin-controller must emit config_form and config_list beside model fields and columns
- A pre-existing model asset must fail before any controller file is written
2026-09-24 18:24:06 +02:00
Jakub Zych
da8828ef38 feat(09-03): localize form schemas and resolve dropdown options
- Cached schemas stay source-key IR and each response carries its own meta.locale
- YAML option maps keep declaration order and scalar type; method options call DropdownOptions and fail boot without a provider
2026-09-24 18:21:59 +02:00