From df45520dd862a6269ec46782cb05151cf2e20c06 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Mon, 28 Sep 2026 00:39:43 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20capture=20exploration=20=E2=80=94=20app?= =?UTF-8?q?aratus=20dissolved=20into=20framework?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apparatus-dissolved-into-framework.md | 46 +++++++++++++++++++ .../todos/pending/backend-admin-api-tokens.md | 10 ++++ .../pending/fetchguard-guarded-http-client.md | 12 +++++ .../todos/pending/redacting-slog-handler.md | 12 +++++ 4 files changed, 80 insertions(+) create mode 100644 .planning/notes/apparatus-dissolved-into-framework.md create mode 100644 .planning/todos/pending/backend-admin-api-tokens.md create mode 100644 .planning/todos/pending/fetchguard-guarded-http-client.md create mode 100644 .planning/todos/pending/redacting-slog-handler.md diff --git a/.planning/notes/apparatus-dissolved-into-framework.md b/.planning/notes/apparatus-dissolved-into-framework.md new file mode 100644 index 0000000..5a54710 --- /dev/null +++ b/.planning/notes/apparatus-dissolved-into-framework.md @@ -0,0 +1,46 @@ +--- +title: "Decision: Apparatus is dissolved into the framework, not ported as a plugin" +date: 2026-09-28 +context: /gsd-explore during Phase 11 discuss (job manager gray area) +--- + +# Decision: Apparatus Is Dissolved Into the Framework + +**Date:** 2026-09-28 +**Status:** Accepted for Phase 11 onward + +## Decision + +`Golem15\Apparatus` is not ported as a plugin. The few pieces the ported plugins depend on move into `summercms.go` as framework packages; the rest is dropped or deferred. No `apparatus` plugin exists in `fonoteka.go`. + +## Job record: `summer_jobs` + +The PHP `JobManager` (`golem15_apparatus_jobs`, `JobStatus`, `ApparatusQueueJob`) becomes a framework job package over River. + +- Table name is **`summer_jobs`** (framework-owned, no Golem15 plugin prefix). +- Columns and semantics are kept from PHP: integer auto-increment `id`, `label`, `status`, `progress`, `progress_max`, `user_id`, `is_admin`, `is_canceled`, `metadata`, timestamps. +- `JobStatus` integers are kept: `IN_QUEUE=0`, `IN_PROGRESS=1`, `COMPLETE=2`, `ERROR=3`, `STOPPED=4`. +- Integer ids stay the public contract: the CSV import API exposes them as `import_job_id` / `match_job_id`. +- At cutover, rows from `golem15_apparatus_jobs` are copied into `summer_jobs` with ids preserved (same approach as Phase 9's `backend_users`). +- River executes the work; the `summer_jobs` row is the record that API responses, progress and cooperative cancellation (`is_canceled`) read. +- A `queue:clear` command (River bulk delete) belongs with this package. A Jobs admin screen can later be plain admin YAML. + +## Triage of the rest of Apparatus + +| Apparatus piece | Consumers in ported plugins | Disposition | +|---|---|---| +| JobManager, JobStatus, ApparatusQueueJob, jobs table | fonoteka CSV import/match, wishlist digest | **Framework** job package over River, `summer_jobs` (above) | +| RequestSender (curl wrapper, bearer, multipart, private-IP guard) | feedback `G15OfficeClient`, golem `AIService` | **Do not port the class.** Extend `fetchguard` into a guarded `http.Client` (POST/PUT/multipart/bearer). fetchguard checks the IP at dial time, which closes RequestSender's resolve-then-connect DNS-rebind gap | +| RedactCredentialsTap (log scrubbing) | logging config | **Framework** `slog` handler with the same sensitive keys and patterns | +| SafeExceptionResponse (generic 500 message outside debug) | user `ApiController`, golem `AIService` | Verify `surf` already covers it; otherwise a small framework helper | +| DependencyInjector, BackendInjector, NeedsDependencies, Resolver facade, DatabaseManager, Pipeline/Pipe | internal | **Drop**: the `backpack` service registry, constructor injection and Go middleware chains replace them | +| RouteResolver, Messaging/ConfirmModal/InfiniteScroll components, HumanDateExtension, TranslApiController, theme scanner hook, BlogUrlValidationMiddleware | CMS pages / Twig | **Drop**: v1 is headless | +| KnobWidget, Sensitive, ListToggle form widgets; BackgroundImportExport behavior | Winter backend | **Drop for now**; Sensitive may return as an admin SPA field type (Phase 10.1) | +| PersonalApiToken for backend admins, TokenAuthenticate, ForceJsonResponse | none in Płytarium | **Defer** (todo: backend admin API tokens) | +| Mail import/export/reset, SaneGitModules, Optimize, FakeJob, BrowserGeneration, generic CsvImportJob, HtmlSanitizer | none (fonoteka documents it does not use the generic CsvImportJob; HtmlSanitizer is used only inside Apparatus) | **Drop** | + +## Consequences + +- Phase 11's job manager service (JOBS-01) is the framework `summer_jobs` package; its migration ships with the framework. +- Phase 14 plugins (feedback, AI recognition, Discogs) use the extended fetchguard client instead of a RequestSender port. +- The Phase 15 cutover runbook must include the `golem15_apparatus_jobs` → `summer_jobs` copy. diff --git a/.planning/todos/pending/backend-admin-api-tokens.md b/.planning/todos/pending/backend-admin-api-tokens.md new file mode 100644 index 0000000..5ecf145 --- /dev/null +++ b/.planning/todos/pending/backend-admin-api-tokens.md @@ -0,0 +1,10 @@ +--- +title: Backend admin personal API tokens (deferred Apparatus PersonalApiToken) +date: 2026-09-28 +priority: low +area: summercms.go admin auth +--- + +Apparatus provides personal API tokens for backend admins (`PersonalApiToken` model, `TokenAuthenticate` + `ForceJsonResponse` middleware, token create/revoke on the backend user form). Nothing in Płytarium calls it, so it is deferred past v1. The Phase 9 `backend` guard already accepts `Authorization: Bearer` for CLI and tests. + +Revisit when a Golem15 project needs scripted access to the admin API. See `.planning/notes/apparatus-dissolved-into-framework.md`. diff --git a/.planning/todos/pending/fetchguard-guarded-http-client.md b/.planning/todos/pending/fetchguard-guarded-http-client.md new file mode 100644 index 0000000..e467011 --- /dev/null +++ b/.planning/todos/pending/fetchguard-guarded-http-client.md @@ -0,0 +1,12 @@ +--- +title: Extend fetchguard into a guarded outbound http.Client (replaces Apparatus RequestSender) +date: 2026-09-28 +priority: high +area: summercms.go/fetchguard +--- + +fetchguard today is a guarded HTTPS GET fetcher. Extend it into a guarded `http.Client` (or a client constructor) that supports POST, PUT, multipart file upload and bearer auth, keeping the dial-time private/reserved IP rejection. + +- Replaces `Golem15\Apparatus\Classes\RequestSender` (see `.planning/notes/apparatus-dissolved-into-framework.md`). +- Consumers: feedback `G15OfficeClient` (JSON POST + multipart), golem `AIService`-style adapters (Anthropic/OpenAI-compatible) and the Discogs client. +- Needed before Phase 14 (INTG-01, INTG-02, feedback). diff --git a/.planning/todos/pending/redacting-slog-handler.md b/.planning/todos/pending/redacting-slog-handler.md new file mode 100644 index 0000000..840886a --- /dev/null +++ b/.planning/todos/pending/redacting-slog-handler.md @@ -0,0 +1,12 @@ +--- +title: Framework slog handler that redacts credentials (port RedactCredentialsTap) +date: 2026-09-28 +priority: medium +area: summercms.go logging +--- + +Port `Golem15\Apparatus\Classes\Logging\RedactCredentialsTap` as a framework `slog.Handler` wrapper: redact attribute keys `api_key`, `apikey`, `authorization`, `bearer`, `password`, `secret`, `token`, `webhook_secret`, `admin_password` (case-insensitive, nested groups), and scrub its message regex patterns. + +Also verify whether `surf`'s error path already gives `SafeExceptionResponse` behaviour (generic "Internal server error" outside debug, real message logged); add a small helper only if it does not. + +See `.planning/notes/apparatus-dissolved-into-framework.md`.