Skip to content

Fix 500 error when creating applications#102

Merged
JoshuaAFerguson merged 30 commits into
mainfrom
claude/fix-application-creation-error-01HNaKiTGxp3EMvwMu33siKf
Nov 19, 2025
Merged

Fix 500 error when creating applications#102
JoshuaAFerguson merged 30 commits into
mainfrom
claude/fix-application-creation-error-01HNaKiTGxp3EMvwMu33siKf

Conversation

@JoshuaAFerguson

Copy link
Copy Markdown
Member

No description provided.

When the ApplicationInstall CRD is not registered in the Kubernetes
cluster, the InstallApplication handler now logs a warning and
continues with the database record creation instead of returning a
500 error.

This change:
- Allows the API to work in development without the full K8s CRD setup
- Provides a helpful message showing how to install the missing CRD
- Still creates the database record so the UI can display applications
- Maintains existing error handling for other K8s errors

The user should install the CRD for full functionality:
kubectl apply -f manifests/crds/applicationinstall.yaml
Planning documents for removing direct K8s dependencies from API:
- K8S_CLIENT_REFACTORING_ANALYSIS.md - Technical analysis
- K8S_CLIENT_REFACTORING_ROADMAP.md - Implementation plan
- K8S_CLIENT_OPERATIONS_CHECKLIST.md - Operations checklist
- README_K8S_CLIENT_ANALYSIS.md - Navigation guide

These support the architectural change to make the API platform-agnostic
so controllers can run sessions on K8s, Docker, Hyper-V, vCenter, etc.
This commit establishes the foundational infrastructure for removing
direct Kubernetes dependencies from the API, enabling multi-platform
support (Kubernetes, Docker, Hyper-V, vCenter).

Changes:
- Add NATS event architecture design document
- Create events package with types, subjects, and publisher
- Add NATS dependency to go.mod (v1.37.0)
- Add database tables: platform_controllers, event_log
- Add platform fields to installed_applications and sessions tables

The API will publish events to NATS subjects, and platform-specific
controllers will subscribe and perform the actual operations. This
decouples the API from Kubernetes and allows multiple platform
controllers to run simultaneously.

Next steps:
- Update API handlers to publish NATS events instead of direct K8s calls
- Update controller to subscribe to NATS events
- Add NATS to docker-compose for development
This commit updates the ApplicationHandler to use NATS event publishing
instead of direct Kubernetes API calls, enabling multi-platform support.

Changes:
- ApplicationHandler now uses events.Publisher instead of k8s.Client
- InstallApplication publishes AppInstallEvent to NATS
- DeleteApplication publishes AppUninstallEvent to NATS
- Added updateInstallStatus helper for tracking installation state
- Initialize NATS publisher in main.go with config from environment
- Platform is now configurable (kubernetes, docker, hyperv, vcenter)

Environment variables:
- NATS_URL: NATS server URL (optional, disables events if not set)
- NATS_USER: NATS username for authentication
- NATS_PASSWORD: NATS password for authentication
- PLATFORM: Target platform (default: kubernetes)

The API now publishes events that controllers subscribe to, completely
decoupling the API from Kubernetes-specific operations.
Update API handlers to publish NATS events for platform-agnostic
operation. This enables controllers to subscribe to events and perform
platform-specific operations (Kubernetes, Docker, Hyper-V, vCenter).

Changes:
- Add NATS publisher and platform to Handler struct
- Update CreateSession to publish SessionCreateEvent
- Update UpdateSession to publish SessionHibernateEvent/SessionWakeEvent
- Update DeleteSession to publish SessionDeleteEvent
- Update CreateTemplate to publish TemplateCreateEvent
- Update DeleteTemplate to publish TemplateDeleteEvent
- Initialize NATS publisher in main.go with environment config

This completes the API-side NATS integration for the event-driven
architecture, moving Kubernetes operations toward the controller.
Update NodeHandler to publish NATS events for cordon, uncordon, and
drain operations. This enables platform-specific controllers to handle
node management operations.

Changes:
- Add NodeUncordonEvent type to events package
- Add PublishNodeUncordon method to publisher
- Update TemplateCreateEvent to use TemplateID field
- Add publisher and platform to NodeHandler struct
- Update CordonNode to publish NodeCordonEvent
- Update UncordonNode to publish NodeUncordonEvent
- Update DrainNode to publish NodeDrainEvent
- Update main.go to pass publisher and platform to NodeHandler

This continues the migration toward a platform-agnostic API that
communicates with controllers via NATS events.
Update activity tracker to publish NATS events when auto-hibernating
idle sessions. This ensures platform controllers are notified of
hibernation events triggered by the idle monitor.

Changes:
- Add publisher and platform to activity.Tracker struct
- Update NewTracker to accept publisher and platform parameters
- Publish SessionHibernateEvent when auto-hibernating idle sessions
- Update main.go to pass eventPublisher and platform to NewTracker

This ensures consistent event publishing for all hibernation events,
whether triggered by user action or automatic idle detection.
Update connection tracker to publish NATS events when auto-starting
hibernated sessions and auto-hibernating idle sessions. This ensures
platform controllers are notified of state changes triggered by the
connection tracker.

Changes:
- Add publisher and platform to ConnectionTracker struct
- Update NewConnectionTracker to accept publisher and platform
- Publish SessionWakeEvent when auto-starting hibernated sessions
- Publish SessionHibernateEvent when auto-hibernating idle sessions
- Update main.go to pass eventPublisher and platform to tracker

This provides consistent event publishing for all session state changes,
whether triggered by user action or automatic connection tracking.
Implement NATS event subscription in the controller to receive events
from the API and perform Kubernetes operations. This enables the
event-driven architecture for multi-platform support.

New files:
- controller/pkg/events/subscriber.go - NATS connection and subscription
- controller/pkg/events/types.go - Event type definitions matching API
- controller/pkg/events/handlers.go - Event handlers for K8s operations

Controller changes:
- Add NATS configuration flags (--nats-url, --nats-user, --nats-password)
- Add namespace and controller-id flags for event routing
- Initialize NATS subscriber after manager creation
- Start subscriber in background goroutine

Event handlers implemented:
- Session: create, delete, hibernate, wake
- Application: install, uninstall
- Template: create, delete (passthrough for now)
- Node: cordon, uncordon, drain

The controller now can receive events via NATS in addition to watching
CRDs directly, enabling future migration to pure event-driven operation.
- Add NATS with JetStream to docker-compose for local development
- Create complete Docker platform controller with container lifecycle management
- Add JetStream streams for durable event delivery (sessions, apps, templates, nodes, controllers)
- Docker controller subscribes to platform-specific NATS subjects
- Support for session create, delete, hibernate, and wake operations via Docker API
- Create subscriber.go to receive session and app status events
- Update main.go to initialize and start the subscriber
- API now updates database when controllers publish status changes
- Completes the event-driven feedback loop for multi-platform support
- Create SessionDB with comprehensive session management methods
- Add database migrations for new session fields (pod_name, memory, cpu, etc.)
- Update ListSessions and GetSession to use database with k8s fallback
- Add conversion functions for database sessions to API response format
- Update cacheSessionInDB to use SessionDB for consistency

This enables platform-agnostic session queries from the database,
with automatic fallback to Kubernetes for backward compatibility.
…ecture

Add comprehensive development scripts for the new NATS-based multi-platform
architecture:

New scripts:
- docker-dev.sh: Start Docker Compose environment with NATS/PostgreSQL
- docker-dev-stop.sh: Stop development environment with cleanup options
- build-docker-controller.sh: Build Docker platform controller image
- test-nats.sh: Test NATS connectivity, publish/subscribe events

Updated scripts:
- local-build.sh: Add Docker controller image build
- local-teardown.sh: Add Docker controller image cleanup
- local-port-forward.sh: Add NATS port forwarding support
- README.md: Document new Docker Compose development workflow
…orm clarity

Rename the Kubernetes controller to explicitly reflect its platform-specific
role in the new multi-platform NATS architecture:

- Image: streamspace/streamspace-controller → streamspace/streamspace-kubernetes-controller
- Controller ID: streamspace-controller-1 → streamspace-kubernetes-controller-1
- NATS client name: streamspace-controller → streamspace-kubernetes-controller

Updates across:
- chart/values.yaml: Controller image repository and documentation
- controller/cmd/main.go: Default controller ID
- controller/pkg/events/subscriber.go: NATS connection name
- scripts/local-build.sh: Build function and image names
- scripts/local-deploy.sh: Image check list
- scripts/local-teardown.sh: Image cleanup list

This change distinguishes the Kubernetes platform controller from the
Docker platform controller (docker-controller/) in the event-driven
architecture.
Rename the Kubernetes controller directory to explicitly identify it as
the Kubernetes-specific platform controller in the multi-platform architecture.

Directory change:
- controller/ → k8s-controller/

Updated references in:
- CLAUDE.md: Repository structure documentation
- DEPLOYMENT.md: Deployment instructions
- MIGRATION_SUMMARY.md: Directory structure
- scripts/local-build.sh: Build context paths

This change complements the image rename (streamspace-kubernetes-controller)
and clearly distinguishes the Kubernetes controller from the Docker controller
(docker-controller/) in the NATS-based multi-platform architecture.
…roller image name

- Update all path references from controller/ to k8s-controller/
- Rename image from streamspace-controller to streamspace-kubernetes-controller
- Update matrix components in security-scan.yml to use k8s-controller
- Update build contexts, cache keys, and artifact names
- Add multi-platform support as core feature (Kubernetes, Docker)
- Update architecture diagrams to show NATS JetStream messaging
- Add Docker controller documentation and development instructions
- Update all controller references from controller/ to k8s-controller/
- Add new development scripts (docker-dev.sh, test-nats.sh)
- Update Troubleshooting to reference kubernetes-controller deployment
Add DeepCopyInto, DeepCopy, and DeepCopyObject methods for
ApplicationInstall, ApplicationInstallList, ApplicationInstallSpec,
and ApplicationInstallStatus types to fix build error where
ApplicationInstall did not implement runtime.Object interface.
- Replace undefined streamv1alpha1.ResourceSpec with corev1.ResourceRequirements
- Use proper resource.MustParse for memory and CPU values
- Change IconURL field to Icon to match ApplicationInstallSpec
- Use TemplateName instead of TemplateID in TemplateDeleteEvent
  (API's event type uses TemplateName, not TemplateID)
- Remove unused fmt import from applications.go
The docker-controller was missing go.sum file causing build failures.
Updated Dockerfile to copy source first then run go mod tidy to
generate the missing go.sum before building.
- Add types and volume package imports
- Use string "unless-stopped" for RestartPolicy (not constant)
- Use types.ContainerStartOptions instead of container.StartOptions
- Use types.ContainerRemoveOptions instead of container.RemoveOptions
- Use types.ContainerListOptions instead of container.ListOptions
- Use volume.CreateOptions from proper import
- Remove dummy volume struct
Cache middleware was generating cache keys using only the request URI,
causing all users to receive the same cached response for user-specific
endpoints like /applications/user.

Now includes userID from auth context in cache key generation, ensuring
each user gets their own cached response for endpoints that return
user-specific data.
Ensure configuration JSON is passed as string instead of []byte
to PostgreSQL JSONB columns to prevent "invalid syntax for type json"
errors.
Prevent caching of X-CSRF-Token, Set-Cookie, Authorization, and
X-Request-Id headers to avoid CSRF token mismatches and other
security issues when serving cached responses.

This fixes 403 Forbidden errors caused by stale CSRF tokens being
returned from cached responses.
Use sql.NullInt64 to properly handle NULL catalog_template_id values
when scanning from the database. This fixes false 404 errors when
deleting or getting applications that have NULL foreign key references.
Add server-side session management to address security concern where
JWT tokens persist after application restart.

Changes:
- Create SessionStore for tracking active sessions in Redis
- Modify JWT generation to include session ID (jti claim)
- Store session metadata (user, IP, user-agent) on token creation
- Validate sessions against Redis store in auth middleware
- Invalidate sessions on logout (DELETE from Redis)
- Clear all sessions on application startup (force re-login)

This enables:
- True logout (immediate session invalidation)
- Forced re-authentication after server restart
- Ability to revoke all sessions for a user
- Session audit trail (IP, user-agent tracking)

The implementation gracefully degrades when Redis is unavailable.
Add user-specific endpoints to the no-cache list in CacheControl
middleware to prevent stale browser-cached responses.

Added endpoints:
- /api/v1/applications/user - User's installed applications
- /api/v1/dashboard/me - User dashboard
- /api/v1/notifications - User notifications
- /api/v1/preferences - User preferences

These endpoints return user-specific data that should not be cached
by the browser as it can lead to stale data being displayed.
Add more specific error messages that include the app ID and
wrap database errors to help diagnose the DELETE 404 issue.
The pq driver for PostgreSQL requires JSONB columns to be scanned
into string types, not []byte. Changed configJSON from []byte to
sql.NullString to properly handle the configuration column and
NULL values.

This fixes the "pq: invalid input syntax for type json" error
when retrieving applications for DELETE operations.
@JoshuaAFerguson JoshuaAFerguson merged commit 2a57598 into main Nov 19, 2025
9 of 23 checks passed
@JoshuaAFerguson JoshuaAFerguson deleted the claude/fix-application-creation-error-01HNaKiTGxp3EMvwMu33siKf branch November 19, 2025 04:37
Comment thread docker-compose.yml
- streamspace

# NATS message broker for event-driven architecture
nats:

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.docker-compose.security.no-new-privileges.no-new-privileges Warning

Service 'nats' allows for privilege escalation via setuid or setgid binaries. Add 'no-new-privileges:true' in 'security_opt' to prevent this.
Comment thread docker-compose.yml
- streamspace

# NATS message broker for event-driven architecture
nats:

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.docker-compose.security.writable-filesystem-service.writable-filesystem-service Warning

Service 'nats' is running with a writable root filesystem. This may allow malicious applications to download and run additional payloads, or modify container files. If an application inside a container has to save something temporarily consider using a tmpfs. Add 'read_only: true' to this service to prevent this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants