VSKI v0.5.0
Features
Section titled “Features”Complete OpenAPI Documentation for Migrations
Section titled “Complete OpenAPI Documentation for Migrations”-
Added OpenAPI Specs for All Migration Endpoints:
- All migration endpoints now have complete OpenAPI 3.0 specifications
- Properly documented with tags, summaries, operation IDs, and response schemas
- Security requirements (BearerAuth) properly defined for all admin endpoints
- Query parameters, request bodies, and responses fully specified
-
Endpoints Documented:
GET /api/migrations- List all migrations (applied and pending)GET /api/migrations/status- Get the current status of the migration systemGET /api/migrations/generate- Generate a new migration file from schema diffPOST /api/migrations/save- Save a generated migration to a fileGET /api/migrations/load- Load a migration from a filePOST /api/migrations/upload- Upload a migration fileGET /api/migrations/export- Export all migrations as a ZIP filePOST /api/migrations/import- Import migrations from a ZIP fileGET /api/migrations/{version}/download- Download a specific migration file as YAMLPOST /api/migrations/{version}/apply- Apply a migrationPOST /api/migrations/{version}/rollback- Rollback a migrationDELETE /api/migrations/{version}- Delete a migration file and record
New Migrations Management UI
Section titled “New Migrations Management UI”-
Complete Web Interface for Migration Management:
- New Migrations page accessible at
/migrationsin the web dashboard - Full CRUD operations for database migrations
- Visual status indicators (pending, applied, failed)
- New Migrations page accessible at
-
Key Features:
- Migration Status Overview: Shows applied and pending migration counts, last applied version
- Generate Migrations: One-click generation from schema diffs
- Apply/Rollback Migrations: Easy controls to apply or undo migrations
- View Migration Details: View migration YAML files in a modal, with loading feedback
- Download Migrations: Export individual migrations as YAML files
- Export All Migrations: Bundle all migrations as a ZIP file (includes full YAML content)
- Upload Migrations: Import migration files from local system
- Delete Migrations: Remove unwanted migrations with confirmation
-
User Experience:
- Pending migrations shown at the top with prominent Apply buttons
- Applied migrations show rollback options and expandable details view with YAML content
- Real-time status updates after actions
- Loading states for all async operations
- Confirmation dialogs for destructive actions (apply, rollback, delete)
- Error and success notifications for all operations
-
Navigation:
- Migrations link added to SQL section in sidebar navigation
- Accessible via SQL → Migrations in the dashboard menu
Code Refactoring
Section titled “Code Refactoring”Unified App Initialization
Section titled “Unified App Initialization”-
Common App Framework:
- Created
internal/app/bootstrap.gowith shared initialization logic NewApp(cfg *config.Config)function returns configured*gin.Engineand a cleanup function- Eliminated ~90% code duplication between
cmd/serverandcmd/standalone - Both entry points now use the same initialization
- Created
-
NewApp Function Output:
NewAppreturns(*gin.Engine, func(), error)- The
*gin.Engineprovides access to the Gin router for custom routes. - The
func()is a cleanup function to gracefully shut down services (e.g., cron, stats, database connections).
-
Mode-Specific Differences:
- Server Mode (
cmd/server/main.go): UsesNewAppand starts the Gin server. - Standalone Mode (
cmd/standalone/main.go): UsesNewApp, then registers anrouter.NoRoute()handler to serve the embedded web UI. All API routes are available in both modes.
- Server Mode (
Installation
Section titled “Installation”Binary
Section titled “Binary”Download binary for your platform:
# Linux (standalone with embedded UI)wget https://vski.sh/x/platform/releases/download/v0.5.0/vski-standalonechmod +x vski-standalone./vski-standalone
# Linux (API-only)wget https://vski.sh/x/platform/releases/download/v0.5.0/vskichmod +x vski./vskiDocker
Section titled “Docker”Pull and run official Docker image:
# Light version (API only, no embedded UI)docker pull vski.sh/x/vski:latest
# Standalone version (with embedded web UI)docker pull vski.sh/x/vski:latest-standalone
# Pull specific versiondocker pull vski.sh/x/vski:v0.5.0docker pull vski.sh/x/vski:v0.5.0-standalone
# Run light version with default configurationdocker run -p 3000:3000 -v $(pwd)/data:/app/data vski.sh/x/vski:latest
# Run standalone version with embedded web UIdocker run -p 3000:3000 -v $(pwd)/data:/app/data vski.sh/x/vski:latest-standaloneConfiguration
Section titled “Configuration”Create a .env file:
DATA_DIR=./dataSERVER_PORT=3000JWT_SECRET=your-secret-keyAccessing OpenAPI Documentation
Section titled “Accessing OpenAPI Documentation”The complete OpenAPI 3.0 specification is available at:
GET /api/openapi.jsonThis includes all endpoints including the newly documented migration APIs.
Managing Migrations via Web UI
Section titled “Managing Migrations via Web UI”Access the Migrations management page by navigating to:
- URL:
http://localhost:3000/migrations - Navigation: SQL → Migrations in the sidebar
Common Workflows:
-
Generate a new migration:
- Click the “Generate” button to create a migration from current schema diff.
- The new migration will appear in the “Pending Migrations” section and be saved to the
data/migrationsdirectory.
-
Apply a pending migration:
- Find the migration in the “Pending Migrations” list.
- Click the “Apply” button.
- Confirm the action when prompted.
- The migration will move to “Applied Migrations” after successful application.
-
Rollback an applied migration:
- Find the migration in the “Applied Migrations” list.
- Click the “Rollback” button.
- Confirm the rollback action.
- The migration will be reverted to its previous state.
-
View migration details:
- Click the JSON icon (view details) on any migration to display its YAML content in a modal.
- For applied migrations, click the expand chevron (>) to view the YAML content inline.
-
Export migrations:
- Single migration: Click “Download” on a specific migration to save its YAML content.
- All migrations: Click “Export All” to download all migrations as a ZIP file containing individual YAML files.
-
Import migrations:
- Click “Upload” button.
- Select a migration YAML file or a ZIP file containing multiple migration YAMLs.
- Click “Upload” to import the migration(s).
Custom Router Integration
Section titled “Custom Router Integration”You can now extend the VSKI server with custom routes using the NewApp function:
package main
import ( "fmt" "vski.sh/x/vski/internal/app" "vski.sh/x/vski/internal/config" "github.com/gin-gonic/gin" "log" "os" "os/signal" "syscall")
func main() { cfg := config.Load() router, cleanup, err := app.NewApp(cfg) if err != nil { log.Fatalf("Failed to initialize app: %v", err) } defer cleanup()
// Add custom routes router.GET("/custom", func(c *gin.Context) { c.JSON(200, gin.H{"message": "Custom endpoint"}) })
log.Printf("Starting custom server on port %s", cfg.ServerPort) go func() { if err := router.Run(fmt.Sprintf(":%s", cfg.ServerPort)); err != nil { log.Fatalf("Failed to start server: %v", err) } }()
quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit
log.Println("Shutting down server...")}Migration Notes
Section titled “Migration Notes”Database Migration Required
Section titled “Database Migration Required”Adding fieldRules Column to collections Table
Section titled “Adding fieldRules Column to collections Table”For existing deployments, you need to manually add the fieldRules column to the collections table. Run the following SQL in your database:
ALTER TABLE collections ADD COLUMN fieldRules TEXT;Note: This change is backward compatible. Existing collections will have fieldRules set to NULL, which the application treats as “no field rules defined” (default open behavior).
Adding fieldEditRules Column to collections Table
Section titled “Adding fieldEditRules Column to collections Table”For existing deployments, you need to manually add the fieldEditRules column to the collections table. Run the following SQL in your database:
ALTER TABLE collections ADD COLUMN fieldEditRules TEXT;Note: This change is backward compatible. Existing collections will have fieldEditRules set to NULL, which the application treats as “no field edit rules defined” (default open behavior).
Alternative: Automatic Schema Update
Section titled “Alternative: Automatic Schema Update”If you prefer automatic schema updates, you can restart the VSKI server which will apply any missing columns during database initialization. The fieldRules column will be automatically added on first startup.
Breaking Changes
Section titled “Breaking Changes”None.
API Changes
Section titled “API Changes”New OpenAPI Endpoints Documented
Section titled “New OpenAPI Endpoints Documented”The following migration endpoints now have complete OpenAPI specifications:
GET /api/migrations- List all migrations (applied and pending)GET /api/migrations/status- Get migration system statusGET /api/migrations/generate- Generate new migration from schema diffPOST /api/migrations/save- Save migration to file (admin utility)GET /api/migrations/load- Load migration from file path (admin utility)POST /api/migrations/upload- Upload migration YAML fileGET /api/migrations/export- Export all migrations as ZIPPOST /api/migrations/import- Import migrations from ZIP fileGET /api/migrations/{version}/download- Download migration YAMLPOST /api/migrations/{version}/apply- Apply migrationPOST /api/migrations/{version}/rollback- Rollback migrationDELETE /api/migrations/{version}- Delete migration
Migration File Format Changes
Section titled “Migration File Format Changes”Collection Changes Model (internal/models/migrations.go):
- Added
drop_columns: []stringfield to track removed columns - Supports soft delete - columns removed from metadata but kept in database
Schema Diff Service (internal/services/schema_diff.go):
detectDropColumns()function identifies removed fieldsisEmptyCollectionChanges()filters unchanged collections- Empty collection changes are excluded from generated migrations
Migration Service (internal/services/migrations.go):
applyCollectionChanges()now handlesdrop_columnsvia metadata update only- Better error handling for rollback data parsing
Code Structure Changes
Section titled “Code Structure Changes”Before (separate main.go files):
cmd/server/main.go # ~220 linescmd/standalone/main.go # ~205 linesAfter (shared initialization):
internal/app/bootstrap.go # New file with common logiccmd/server/main.go # ~35 lines (uses app.NewApp(cfg))cmd/standalone/main.go # ~40 lines (uses app.NewApp(cfg) + standalone handler)Testing
Section titled “Testing”Run E2E Tests
Section titled “Run E2E Tests”cd vskimake buildmake e2e TEST=50_migrations_test.ts # Test migrationsmake e2e # Run all E2E testsVerify OpenAPI Spec
Section titled “Verify OpenAPI Spec”# Build the servermake build
# Start the server./bin/vski-prod
# Fetch OpenAPI speccurl http://localhost:3000/api/openapi.json | jq '.paths | keys | .[] | select(contains("migrations"))'Expected output (example, actual list may vary slightly depending on other APIs):
"/api/migrations""/api/migrations/status""/api/migrations/generate""/api/migrations/save""/api/migrations/load""/api/migrations/upload""/api/migrations/export""/api/migrations/import""/api/migrations/{version}/download""/api/migrations/{version}/apply""/api/migrations/{version}/rollback""/api/migrations/{version}"Test Custom Router Integration
Section titled “Test Custom Router Integration”package main
import ( "fmt" "vski.sh/x/vski/internal/app" "vski.sh/x/vski/internal/config" "github.com/gin-gonic/gin" "log" "os" "os/signal" "syscall" "net/http" // Added for example)
func main() { cfg := config.Load() router, cleanup, err := app.NewApp(cfg) if err != nil { log.Fatalf("Failed to initialize app: %v", err) } defer cleanup()
// Add custom routes router.GET("/custom", func(c *gin.Context) { c.JSON(200, gin.H{"message": "Custom endpoint"}) })
serverPort := cfg.ServerPort // Get the configured port
log.Printf("Starting custom server on port %s", serverPort) go func() { if err := router.Run(fmt.Sprintf(":%s", serverPort)); err != nil { log.Fatalf("Failed to start server: %v", err) } }()
// Example of calling a custom route time.Sleep(2 * time.Second) // Give server time to start resp, err := http.Get(fmt.Sprintf("http://localhost:%s/custom", serverPort)) if err != nil { log.Printf("Error calling custom route: %v", err) } else { defer resp.Body.Close() if resp.StatusCode == http.StatusOK { log.Println("Custom route works!") } else { log.Printf("Custom route returned status: %d", resp.StatusCode) } }
quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit
log.Println("Shutting down server...")}Run this code:
go run your_custom_main.goExpected output will show “Custom route works!” if successful.
Documentation
Section titled “Documentation”Full documentation available at: https://vski.sh/x/platform
Changelog
Section titled “Changelog”v0.5.0 (2026-02-22)
Section titled “v0.5.0 (2026-02-22)”- Complete OpenAPI 3.0 specifications for all implemented migration endpoints.
internal/app/bootstrap.gowithNewApp(cfg *config.Config)for unified app initialization.- Full UI for migration CRUD operations (generate, apply, rollback, view, download, upload, export, delete) in
web/src/pages/Migrations.tsx. - Migration status overview, pending/applied migration counts, and last applied version in UI.
- Inline display of migration YAML content for applied migrations via expandable details.
- Loading feedback for asynchronous UI operations in migration management.
- Dropped column tracking in migrations (
drop_columnsfield in collection changes). - Soft delete for columns - dropped columns are untracked from metadata but remain in database (SQLite limitation workaround).
- Filtering of empty collection changes - generated migrations no longer include empty collection entries.
- Better error handling when parsing rollback data and generating migrations.
- Field-level view rules (
fieldRules) - Control READ visibility of individual fields by user groups. - Field-level edit rules (
fieldEditRules) - Control CREATE/UPDATE access to individual fields by user groups. - Field-level permissions override global
viewRule/createRule/updateRulewhen defined. - Split field permissions UI - Separate “View Rules” and “Edit Rules” sections in collection settings with clear visual indicators.
- Required field warnings - UI shows warnings when required fields are not in a group’s edit allowed list.
Changed
Section titled “Changed”- Refactored
cmd/server/main.goandcmd/standalone/main.goto useapp.NewApp, significantly reducing code duplication. - Moved
RecoveryMiddlewaretointernal/middleware/middleware.gofor shared use. DownloadMigrationsZipininternal/services/migrations.gonow correctly includes full YAML content of migration files in the ZIP archive and uses proper version matching.- Corrected display logic for “View” migration YAML in web UI modal.
- Removed duplicated UI buttons in
web/src/pages/Migrations.tsx.
Technical
Section titled “Technical”- Implemented backend migration APIs for
list,status,generate,save,load,upload,export,import,download,apply,rollback,delete(global operations, not collection-specific). - App initialization is centralized in
internal/app/bootstrap.go. NewAppreturns(*gin.Engine, func(), error)allowing flexible router extension and proper resource cleanup.- Standalone mode (
cmd/standalone/main.go) integrates embedded web UI viarouter.NoRoute(). - Server mode (
cmd/server/main.go) serves to API without embedded UI. - Frontend
MigrationsPageusessdk.settings.migrationsAPI for all operations with improved user feedback. - Added
DropColumnsfield toCollectionChangesstruct ininternal/models/migrations.go. - Added
detectDropColumns()function ininternal/services/schema_diff.goto identify removed fields. - Added
isEmptyCollectionChanges()helper function to filter out unchanged collections. - Updated
applyCollectionChanges()ininternal/services/migrations.goto handle dropped columns via soft delete. - Improved
GenerateMigrationWithVersion()error handling for rollback data parsing.