Search/Update a Go API and React SPA by Editing the OpenAPI Spec First

Update a Go API and React SPA by Editing the OpenAPI Spec First

For a repo where a Go backend and a React SPA share an OpenAPI spec. It edits the spec and regenerates code instead of hand-editing it, handles settings, errors, logins, downloads, and updates by fixed rules, and tests before reporting.

To use this AI rule
## Make the OpenAPI Spec the Single Source and Give Each Layer Its Own Job - Treat the OpenAPI specification as the source of truth for routes, request and response schemas, and shared models. - Keep the Go backend and React SPA independently buildable in development. - In production, prefer embedding the built SPA into the backend binary and serving API and UI from the same origin. - Use the development server only as a proxying convenience; do not let development-only ports or hosts leak into production code. - Preserve clear ownership: the API layer owns transport, services own domain behavior, stores own persistence, and the frontend owns presentation. - Extend existing contracts before inventing parallel routes, configuration stores, event channels, or state models. - Do not add explicitly deferred subsystems without a scoped requirement and an architecture decision. - When documentation and implementation disagree, stop the affected change and resolve the source-of-truth conflict first. ## Edit the Spec and Regenerate Code Instead of Hand-Editing Generated Files 1. Inspect the specification, generated interfaces, implementation, tests, and relevant operational documentation. 2. Edit the authoritative source: the OpenAPI files for API shape, configuration structs for settings, and message catalogs for UI text. 3. Regenerate backend and frontend artifacts with the repository commands. 4. Implement the generated interface and update only directly affected services and UI wrappers. 5. Run formatting, static analysis, focused tests, and the smallest relevant runtime check. 6. Review generated diffs to confirm that the specification produced the intended contract. - Never hand-edit generated files; fix the specification or generator configuration instead. - Never register an ad hoc route that bypasses the generated server interface. - Keep operation identifiers unique and stable because they become generated method names. ## Keep Shared Schemas in One Place and Generated Types Matching the API - Split path definitions by domain while keeping shared schemas, parameters, and responses in one canonical components section. - Reuse shared references instead of duplicating nearly identical schemas across path files. - Preserve generator-specific import mappings and pruning controls required by cross-file references. - When a schema mirrors an upstream library type, keep the machine mapping and the JSON properties synchronized. - Declare every serialized field and mark every always-present field as required for non-Go consumers. - Represent nullable references using the form required by the OpenAPI version and generator; test the generated result. - Generate frontend types from the API document actually served by the backend when runtime fidelity matters. - Commit generated API types when repository policy uses their diffs as contract review evidence. - Keep API clients behind domain wrappers so components do not depend on transport details. ## Return Structured Errors Without Leaking Internal Error Text - Implement endpoints through the generated server interface and group handler methods by domain. - Use one shared JSON response helper and one central error classifier. - Return structured errors with stable machine codes, a rendering kind, safe optional fields, and a request identifier. - Never copy raw internal or upstream error text into a client response. - Put field-validation details in a dedicated map and reserve a general key for non-field failures. - Convert upstream failures into stable reason tokens; keep raw bodies in protected logs only. - Use typed user-facing errors only when dynamic text is intentionally safe to display. - Do not construct wire-error envelopes outside the classifier. - Return status codes and JSON errors instead of using panics for control flow. - Treat panic recovery as a safety net whose output is structured and logged, not as normal behavior. ## Define Each Setting Once and Mark Which Ones Need a Restart - Define settings once in typed configuration structures; derive defaults, validation, schema metadata, and environment keys from them. - Apply precedence consistently: defaults, then settings file, then environment overrides. - Persist only values that differ from built-in defaults. - For every new setting, define its default, validation, UI category, sensitivity, visibility, and restart behavior. - A hot-reloadable setting must have a live consumer or reload hook; otherwise mark it restart-required. - Restart-required values may be persisted immediately but must remain pinned in the effective runtime view until restart. - Mask sensitive values in API responses and treat redacted placeholders as no-op on update. - Keep program-only settings read-only through the runtime API, and keep hidden settings out of the reflected UI schema. - Run the same validators at startup and before persistence so saved configuration cannot break the next boot. - Write settings atomically and anchor managed relative paths to a stable data root, not the launch directory. ## Use One Log Format and Shut Down the Server Without Leaving Work Behind - Use structured logging with one schema across HTTP requests, lifecycle events, and background workers. - Attach handler fields and errors to the current request log instead of emitting duplicate per-request events. - Keep backend logs in one operational language; UI localization belongs in the frontend. - Preserve middleware order when request IDs, real client addresses, request logging, and panic recovery depend on it. - Place new middleware inside the recovery boundary unless it must alter fields before request logging begins. - On shutdown, close long-lived event subscribers before draining the HTTP server. - Give in-flight requests a bounded drain deadline and define explicit behavior when the deadline expires. - For restart, complete service cleanup before replacing or spawning the process. - Make streaming handlers return on hub closure or request cancellation. - Register every background worker in the same shutdown sequence so no work is orphaned. ## Use Stable Query Keys and Clear Caches When the User Changes - Keep provider order explicit when later providers depend on query, locale, authentication, or event contexts. - Expose query-option factories from feature modules and keep raw API calls inside domain wrappers. - Use stable query keys that include every identity-changing parameter. - Preserve prior list data only for true page transitions; discard it when filters, users, tabs, or search identity change. - Clear account-scoped caches when the authenticated session changes. - Centralize optimistic updates, rollback snapshots, and invalidation so every cached copy of an entity stays consistent. - Treat server events as refresh hints; authoritative state still comes from queries or state endpoints. - Read localized message functions through reactive context inside render paths. - Map dynamic translation keys through explicit static resolvers, and keep placeholder shapes identical across locales. - Keep human-readable configuration labels in frontend catalogs rather than backend schemas. ## Store Login Sessions Separately and Keep Users Signed In Through Brief Failures - Store session credentials in one dedicated state file with restrictive permissions; never mix them into general settings. - Treat the refresh credential as session authority and short-lived access credentials as replaceable. - Refresh proactively near expiry and reactively once after an authentication failure, using single-flight coordination. - Preserve the session on transient failures; clear it only after a confirmed permanent rejection. - Keep authorization verifiers short-lived, capacity-bounded, and single-use. - Validate pasted callback values before sending them upstream, and return localized, actionable errors. - Strip credentials from proxy-discovery results and keep discovery read-only. - Guard unauthenticated onboarding writes so they cannot mutate settings after login. - Protect sensitive mutation endpoints with authentication and an application-specific CSRF header. - Never expose upstream authentication bodies, credentials, or internal package errors to clients. ## Save Downloads Through Temp Files and Never Delete Files the App Did Not Create - Make the job the transaction boundary and persist every meaningful state transition atomically. - Send high-frequency progress through events rather than rewriting persistent state on every tick. - Write payloads to uniquely named temporary files and rename only after success; remove partials on cancellation or failure. - Retry only retryable failures with bounded exponential backoff. - Record whether the application created each final file before cleanup; never delete a path based only on its expected name. - Resolve collisions against both disk contents and in-flight reservations, with a bounded fallback strategy. - Re-resolve paths during restart recovery unless a completed payload already owns its destination. - Parse path templates at startup and validate them again before accepting configuration changes. - Sanitize every path segment, preserve explicit roots, clamp filenames by bytes, and count user-visible truncation by characters. - Pin conversion and naming decisions per job so hot-reloaded settings cannot change work already in progress. ## Replay Missed Events on Reconnect and Resync When Replay Is Impossible - Keep persistent state authoritative and treat events as an optimization. - Give events stable IDs, timestamps, topics, types, and reconstructible payloads. - On reconnect, replay events after the client's last known ID when the buffer still contains them. - If replay is impossible, emit one resynchronization event and require clients to refetch authoritative state. - Use keepalives to prevent intermediaries from silently closing idle streams. - Let only job-level events set aggregate job status; task events update task state without recomputing server-owned rules. - Refresh affected views after reconnect and after a resynchronization signal. - Throttle progress notifications, but bypass throttling for terminal transitions and the final progress update. - Keep event transport independent from domain managers through a small publisher interface. ## Limit Proxy Targets and Verify Signed Updates Before Replacing the App - Allow proxy targets by exact host policy and recheck every redirect to prevent server-side request forgery. - Share concurrent cache misses for the same resource and reject oversized bodies before caching. - Treat the filesystem as cache truth; reconcile size periodically and after writes using oldest-accessed eviction. - Keep cache storage relocatable and separate from durable user state. - Inject update-feed locations and trusted signing keys at release build time; fail closed when trust material is absent. - Verify a signed manifest before trusting any version, URL, checksum, or release note field. - Verify the downloaded archive against the signed manifest before replacing a binary. - Single-flight update application, reject it in development builds, and require authentication plus CSRF protection. - Resolve the replacement executable deterministically and refuse ambiguous archives. - Drain services and restart only after the verified replacement is ready. ## Test the Running App and Stop Before Releases or Production Changes - Work through generation, implementation, focused tests, and direct runtime verification without skipping a failed step. - Verify the health endpoint, served OpenAPI document, affected API behavior, and the directly affected UI path. - Run format, static analysis, race-sensitive backend tests, frontend checks, and production builds when the change touches them. - Confirm atomic persistence, restart semantics, secret masking, and error non-disclosure with targeted tests. - For release work, validate strict semantic versioning, signed-feed continuity, checksums, and platform archive resolution. - Keep deferred features deferred unless the current requirement explicitly brings them into scope. - Avoid unrelated refactors, parallel state stores, duplicate error systems, and speculative infrastructure. - Stop before an external release, destructive migration, credential change, or production mutation unless it is explicitly authorized. - Report what changed, what was verified, what remains out of scope, and any unresolved contract conflict.