Commit Graph

746 Commits

Author SHA1 Message Date
Jakub Zych
8818d7b023 feat(12.2-01): add deferred:purge, its daily framework schedule and relation child hooks
- deferred:purge [--days] in lagoon.RuntimeCommands (purge_days, default 5)
- lagoon.FrameworkSchedule entry at purge_at (default 03:00, empty disables)
- conga prepends framework entries as summercms.lagoon[i]:<command>
- pact.Relation{Before,After}{Create,Update,Delete} optional hooks
- lagoon, conga and pact READMEs, scheduling and setup docs
2026-10-02 17:45:41 +02:00
Jakub Zych
f48a886f94 feat(12.2-01): add lagoon.Date and lagoon.TimeOfDay with Fill and required support
- Date (DATE) and TimeOfDay (TIME) with Scanner, Valuer, JSON and text forms
- Fill falls back to encoding.TextUnmarshaler for string sources after
  every existing conversion, so time.Time and the new types fill from JSON
- required treats a zero time.Time, Date or TimeOfDay as empty
- lagoon README, models and casts-and-validation docs
2026-10-02 17:40:48 +02:00
Jakub Zych
19f4cf8232 feat(12.2-01): add deferred bindings, guarded upload store and purge
- deferred_bindings migration set under summercms.deferred with backend_user_id
- lagoon.DeferredBind/Unbind/Bindings/Forget/Slaves scoped by DeferredKey
- lagoon.PurgeDeferred with SKIP LOCKED batches and after-commit blob deletes
- attach.Store with the ported image guard, extension and MIME limits
- attach.Relation, attach.HasRelations, attach.BlobKeys, File.ThumbKey
- lagoon README and attachments docs
2026-10-02 17:36:43 +02:00
Jakub Zych
79e2a43095 test(12): persist human verification items as UAT 2026-10-02 17:08:58 +02:00
Jakub Zych
1ea63ef1ee docs(12): record code review disposition 2026-10-02 17:08:31 +02:00
Jakub Zych
44a25dd380 docs(12): add code review report 2026-10-02 17:08:18 +02:00
Jakub Zych
560a16983c docs(12-05): update state and roadmap progress after plan 12-05 2026-10-02 16:57:41 +02:00
Jakub Zych
c97cc094d5 docs(12-05): complete the Phase 12 security proof, coverage and gate plan 2026-10-02 16:56:55 +02:00
Jakub Zych
1f4e1e01c4 docs(12-05): sign off the Phase 12 security review, validation and API-01/API-02
- 12-SECURITY-REVIEW.md maps T-12-01..T-12-34 and T-12-SC to a named test
  and 25 removal checks, all seen failing with the protection removed
- 12-VALIDATION.md validated with the final per-task map, nyquist_compliant
- REQUIREMENTS.md: API-01 and API-02 complete
2026-10-02 16:55:29 +02:00
Jakub Zych
f4ec94531f docs(12.2): create phase plan
Five sequential plans: foundations (deferred_bindings, attach.Store,
lagoon.Date/TimeOfDay, purge), cabana datepicker and fileupload, relation
child CRUD with deferral, admin SPA, and unit and security tests.
Adds D-22..D-24 from the plan-count checkpoint and the pattern map.
2026-10-02 16:53:42 +02:00
Jakub Zych
6f4386c2f9 chore(12-05): add the fail-closed Phase 12 gate
scripts/check-phase12.sh, modelled on check-phase11.sh:
- --go: vet and test both repositories, golang.org/x/image pinned at v0.46.0
- --parity: 99 ported routes in the manifest, TestParityCorpus with its
  coverage subtest, all four broadcast goldens, both Nuxt flows,
  check_corpus --require-recorded --check-secrets and a secret scan of the
  fuzz seed corpus
- --named: every test 12-VALIDATION.md names, by exact name, the fonoteka
  plugin's under -race
- --removal: 25 anchor-exact mutations behind 12-SECURITY-REVIEW.md, each
  required to fail its named test on an assertion; a dirty file is
  refused and every file is restored and compared with cmp
- --coverage: an 80% floor per Phase 12 package in both repositories
- --evidence: one review row per T-12 threat, a removal row per high
  mitigated threat, a green validation file naming only tests the gate runs
- --self-test: every detector, plant and harness branch fails closed
2026-10-02 16:39:03 +02:00
Jakub Zych
6e30624ece test(12-05): bring the Phase 12 framework packages to full unit coverage
- lagoon: Go-typed request values (typed slices and maps, sized integers,
  floats, file pointers, typed path lookups), regex delimiters, mimes
  sniffing (jpg/jpeg, SVG, PHP names, unreadable content),
  UploadedFileFromHeader, the rule builders, custom catalog lines with
  :input/:index/:position, and exists: against Postgres (text compare,
  inferred and NULL columns, arrays, unsafe identifiers, missing tables)
- lagoon/attach: thumbnails in every mode from PNG, GIF and JPEG originals,
  bucket URL normalisation, OpenBucket/Publish refusals, URL helpers and
  static prefix stripping
- tide: part validation and encoding edges, symlinks out of the fixture
  directory, Content-Type handling, every response mask and the coverage
  report helpers

Coverage: lagoon 84.4%, lagoon/attach 87.7%, tide 81.4%, beachcomber
84.3%, beachcomber/typesense 95.9%.
2026-10-02 15:54:44 +02:00
Jakub Zych
d1650e8213 docs(12.2): UI design contract 2026-10-02 15:52:22 +02:00
Jakub Zych
3ac1d64ab4 fix(12-05): cast floats to strings with PHP's 14-digit precision in request validation
PHP 8's (string) cast of a float formats with the precision ini (14
significant digits, %.14G), not the shortest round-trip form: 1/3 is
0.33333333333333, 1e14 is 1.0E+14 and 5e-324 is 4.9406564584125E-324.
phpFloatString, used for the string form of JSON floats in size, in, regex
and integer checks, printed up to 17 digits and switched to the exponent
form only from 1e15. TestPHPFloatStringMatchesPHPCast pins 27 values to
php -r output.
2026-10-02 15:46:24 +02:00
Jakub Zych
36983bc87e fix(12-05): match Laravel's in and not_in rules on array values
A 162-case truth table recorded from WinterCMS's validator (the vendored
winter/storm Factory, Laravel 9) found three divergences, all on arrays:

- in compared array elements loosely; Laravel uses array_diff, an exact
  string comparison, so ["1.0"] is not in 1,2;
- not_in failed when any element was listed; Laravel's validateNotIn is
  !validateIn, so an array passes unless every element is listed;
- not_in failed an array without the array rule; Laravel passes it.

validate_rules_test.go keeps the whole table (accepted, array keys,
boolean, numeric, integer, in/not_in, sizes by type, regex, dates and
comparisons, url, presence, nested and map wildcards, bail and order).
2026-10-02 15:42:47 +02:00
Jakub Zych
92b12fee4c docs(phase-12.2): add validation strategy 2026-10-02 15:24:48 +02:00
Jakub Zych
1c476d243f docs(12.2): research phase domain 2026-10-02 15:24:00 +02:00
Jakub Zych
1307060e15 fix(12-05): store WinterCMS's broken-image thumbnail for an unusable original (T-12-16)
A photo whose original is missing, does not decode or declares more than
4096x4096 pixels made attach.File.Thumb return an error, and every listing
that shows the photo answered 500 from then on: one 100-byte PNG uploaded
by any household member broke GET collections and the album for everyone.

Thumb now follows WinterCMS's File::makeThumb catch branch: it logs the
reason at warn level, stores WinterCMS's BrokenImage picture (exported as
attach.BrokenImagePNG) under the thumbnail key and returns its URL. Invalid
arguments, storage errors and encode failures are still errors.
2026-10-02 15:15:26 +02:00
Jakub Zych
2f71aeb534 docs(state): record phase 12.2 context session 2026-10-02 15:01:26 +02:00
Jakub Zych
4712e94a12 docs(12.2): capture phase context 2026-10-02 15:01:25 +02:00
Jakub Zych
37595fb6b2 docs(12-04): update state and roadmap progress after plan 12-04 2026-10-02 14:44:17 +02:00
Jakub Zych
3cf2b38a8c docs(12-04): complete albums, search and lookups plan 2026-10-02 14:43:34 +02:00
Jakub Zych
44526f0bca docs: insert Phase 12.2 admin form fields with deferred binding (v0.1.1) 2026-10-02 14:36:41 +02:00
Jakub Zych
6649763590 chore(12-04): require every album broadcast golden to pass
All four goldens run through the album handlers now: no pending skip is expected
and the named check requires created and updated to pass.
2026-10-02 14:30:13 +02:00
Jakub Zych
7ac6c05ab3 chore(12-04): expect only the updated broadcast golden to skip
The album store handler asserts the created golden now; updated stays pending
until the update handler lands.
2026-10-02 14:01:32 +02:00
Jakub Zych
18ead668ec docs(12-03): update state and roadmap progress after plan 12-03 2026-10-02 13:18:30 +02:00
Jakub Zych
6f37a3782f docs(12-03): complete household invitations and members plan 2026-10-02 13:17:47 +02:00
Jakub Zych
62863cf0ae docs(12-02): update state and roadmap progress after plan 12-02 2026-10-02 12:39:18 +02:00
Jakub Zych
85a45dbc80 docs(12-02): complete collections, me/context and share link plan 2026-10-02 12:38:40 +02:00
Jakub Zych
d7388af564 docs(12-01): update state and roadmap progress after plan 12-01 2026-10-02 11:50:43 +02:00
Jakub Zych
ce72e60491 docs(12-01): complete framework gaps and user groups plan 2026-10-02 11:50:05 +02:00
Jakub Zych
1bdbdf041b docs(12-01): reword the Phase 12-14 scope and requirements
- Phase 12 criteria 1-3 and goal: realtime/channels, owner-only share,
  cover import, re-gated search total (D-03, D-04, D-06, D-19, D-20)
- reservations and anonymous public-token views move to Phase 13
  (API-03, API-07); the Discogs cover-price route to Phase 14 (INTG-01)
- the folded lagoon-validate-min-message todo moves to done
2026-10-02 11:44:52 +02:00
Jakub Zych
3ae49bb6f4 feat(12-01): report the search engine's found count and field weights
- optional beachcomber.PageSearcher returns a page of candidate ids plus
  the engine's found count; beachcomber.SearchPage falls back to
  SearchIDs for engines without it, so Engine is unchanged
- Query.QueryByWeights is sent to Typesense as query_by_weights; a
  mismatched weight list or a page above typesense.MaxPerPage (250) is
  refused before any request
2026-10-02 11:37:01 +02:00
Jakub Zych
e06e0cc8bf feat(12-01): record multipart uploads and match Winter upload URLs
- attach.PublicURL and (*File).URL build Winter File::getPath() URLs; the
  thumbnailer decodes webp via golang.org/x/image v0.46.0 and checks the
  image size from the header before decoding
- tide requests carry multipart parts (files beside the fixture pinned by
  sha256) encoded with the fixed MultipartBoundary, so PHP and Go receive
  byte-identical bodies
- tide masks the random partition, disk name and file id of url/thumb_url
  upload URLs while still diffing prefix, size, mode and extension, and
  NormalizePublications masks Carbon dates in the published album
2026-10-02 11:33:42 +02:00
Jakub Zych
f9b7f2ea33 feat(12-01): add Laravel request validation to lagoon
- lagoon.ValidateRequest ports Laravel 9 request validation: wildcard
  expansion, implicit-rule stop, bail, sometimes/nullable/blank skipping,
  size messages split by type and character-counted string lengths
- ParseRules, In, CustomRule, UploadedFile and ErrorKeys for rule tables
- pl/en lagoon::validation catalogs ported verbatim from WinterCMS
- lagoon.Validate answers a numeric range failure with the bound that
  failed (min, max or numeric between) instead of always max
2026-10-02 11:25:36 +02:00
Jakub Zych
cfe568a214 docs(quick-261002-esz): extract golem15.user into its own repo sm-user-plugin 2026-10-02 11:04:00 +02:00
Jakub Zych
947aabee93 docs: move golem15.user to sm-user-plugin and supersede the Phase 1 extraction deferral
- new note .planning/notes/core-plugins-own-repos.md: shared core plugins live in sm-<name>-plugin repos mounted as submodules
- 01-CONTEXT deferral points to the note; PROJECT constraint and Key Decisions row
- ROADMAP Phase 12 repos and the 12-01 entry, and Phase 12 plans 12-01, 12-02, 12-05 name sm-user-plugin and the submodule commit workflow
2026-10-02 11:02:07 +02:00
Jakub Zych
b3fda9188f docs(12): create phase plan 2026-10-02 08:40:06 +02:00
Jakub Zych
d97b4292a3 docs(12): record post-research decisions and validation strategy 2026-10-02 08:04:23 +02:00
Jakub Zych
77f8b371cf docs(12): research phase domain 2026-10-02 01:08:08 +02:00
Jakub Zych
8cc7b81559 docs: defer phase 11.3 newsletter to backlog as 999.1 2026-10-02 00:49:47 +02:00
Jakub Zych
3f650ffcd4 docs(10, 10.2): regenerate verification reports for modules/ paths 2026-10-01 23:32:42 +02:00
Jakub Zych
f2f2279be9 docs(phase-9): complete phase execution 2026-10-01 23:19:21 +02:00
Jakub Zych
9692315cb5 docs(09): verification passed 2026-10-01 23:18:53 +02:00
Jakub Zych
ba1aaefa01 docs(09): record approved review decisions and close UAT 2026-10-01 23:13:02 +02:00
Jakub Zych
2da8112dbb fix(09): WR-11 enforce case-insensitive unique backend user emails
Add a backend admin migration that creates a unique index on
lower(backend_users.email). Rows copied from WinterCMS may hold emails
that differ only in case, so the migration refuses to run and names the
clashing logins instead of choosing an account to drop.
2026-10-01 23:12:29 +02:00
Jakub Zych
5d79f7d0bb docs(09): re-verify phase after code review fixes 2026-10-01 21:50:43 +02:00
Jakub Zych
2ecc85ea19 docs(09): record code review disposition 2026-10-01 21:43:15 +02:00
Jakub Zych
9d2128acc2 docs(09): add code review fix report 2026-10-01 21:43:14 +02:00
Jakub Zych
4ae272e3cc fix(09): WR-19 expose the write transaction to hooks and scopes through TxFromContext 2026-10-01 21:37:13 +02:00