docs: capture exploration — apparatus dissolved into framework

This commit is contained in:
Jakub Zych
2026-09-28 00:39:43 +02:00
parent 7ac75b918d
commit df45520dd8
4 changed files with 80 additions and 0 deletions

View File

@@ -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.

View File

@@ -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`.

View File

@@ -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).

View File

@@ -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`.