4 Commits
Author SHA1 Message Date
Juan DenisandClaude Fable 5 f34969eaac fix(models): close all 26 dangling-on-delete FKs + orphan sweep migration
Every NOT NULL FK from the KNOWN_DANGLING_ON_DELETE audit now declares
its parent-side relationship, so the delete-cascade policy door covers
it: AI conversations/pending actions, API keys, dashboards, event
subscriptions, login links, sent invitations, resource grants (users);
env vars + history, previews + settings, WAF policy (applications);
surveys, doctor results, proxy stack, tunnels (servers); manifests
(projects); DDNS hosts (zones); exposed services (tunnels); drills
(backup policies); rollouts (agent versions); site plugin installs
(WordPress sites); queue messages (groups). The ratchet set is now
EMPTY and stays that way.

One new deliberate exception: Workspace.projects — projects carry
environments and app groupings, so delete_workspace now refuses (409)
while any remain instead of silently destroying them (previously it
crashed with IntegrityError).

Migration 095 sweeps rows already orphaned on existing installs by
pre-fix hard-deletes — including an application's leftover env-var
secrets, which a reused SQLite row id could have attached to a future
app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:25:29 -04:00
Juan DenisandClaude Fable 5 2e3a735d5a refactor(models): SerializableMixin — mechanical to_dicts become introspection (plan 77 B2)
Opt-in to_dict over __table__.columns: auto-isoformat datetimes,
*_encrypted always dropped, __serialize_exclude__ for redacted columns,
serialize_extra() for computed fields (named to dodge ServerMetrics'
literal 'extra' column). 20 purely-mechanical to_dicts across 15 files
convert; genuinely custom shapes keep their hand-written methods (plan
75 §F's ruling stands). Field selection stays api/_query.py's job.
Gate: key-for-key parity against the pre-conversion key sets frozen
from git HEAD (only the Timestamp pair may be additive).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 05:33:17 -04:00
Juan DenisandClaude Fable 5 4919ff1cfe refactor(models): TimestampMixin + uuid_pk() one-door shapes (plan 77 B1/B3)
TimestampMixin (byte-identical to the hand-written pair — zero schema
migrations) adopted by 52 classes across 44 model files; the utcnow
tz-aware migration is now a one-file edit. uuid_pk() replaces the 13
pasted String(36) uuid4 lambdas across 7 files (ai.py's hex variant
stays grandfathered, documented). Deviant shapes (indexed created_at,
sanitization_profile's default-less updated_at, created-only models)
deliberately keep their own columns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 01:59:10 -04:00
Juan DenisandClaude Opus 4.8 6b35bb996d feat(wordpress): global plugin library for operator-owned plugins
Register WordPress plugins from GitHub repos or local paths in a global
library, then install or update them across any managed WP site from one
place. The per-site Plugins tab gains a "managed" badge and an
"update from library" action.

- models: WordPressCustomPlugin (library) + WordPressSitePlugin (installs)
- service: WordPressPluginLibraryService - sync, install, update, scan,
  with a per-slug cache dir under paths.SERVERKIT_CACHE_DIR
- api: /plugins/library CRUD + sync/install/bulk-update on wordpress_bp
- migration 041_wordpress_plugin_library
- frontend: WordPressPluginLibrary page + "Plugin Library" tab; managed
  badges and library-update action in PluginsTab
- tests: test_wp_plugin_library

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:08:42 -04:00