Skip to content

VSKI v0.5.0

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 system
    • GET /api/migrations/generate - Generate a new migration file from schema diff
    • POST /api/migrations/save - Save a generated migration to a file
    • GET /api/migrations/load - Load a migration from a file
    • POST /api/migrations/upload - Upload a migration file
    • GET /api/migrations/export - Export all migrations as a ZIP file
    • POST /api/migrations/import - Import migrations from a ZIP file
    • GET /api/migrations/{version}/download - Download a specific migration file as YAML
    • POST /api/migrations/{version}/apply - Apply a migration
    • POST /api/migrations/{version}/rollback - Rollback a migration
    • DELETE /api/migrations/{version} - Delete a migration file and record
  • Complete Web Interface for Migration Management:

    • New Migrations page accessible at /migrations in the web dashboard
    • Full CRUD operations for database migrations
    • Visual status indicators (pending, applied, failed)
  • 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
  • Common App Framework:

    • Created internal/app/bootstrap.go with shared initialization logic
    • NewApp(cfg *config.Config) function returns configured *gin.Engine and a cleanup function
    • Eliminated ~90% code duplication between cmd/server and cmd/standalone
    • Both entry points now use the same initialization
  • NewApp Function Output:

    • NewApp returns (*gin.Engine, func(), error)
    • The *gin.Engine provides 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): Uses NewApp and starts the Gin server.
    • Standalone Mode (cmd/standalone/main.go): Uses NewApp, then registers an router.NoRoute() handler to serve the embedded web UI. All API routes are available in both modes.

Download binary for your platform:

Terminal window
# Linux (standalone with embedded UI)
wget https://vski.sh/x/platform/releases/download/v0.5.0/vski-standalone
chmod +x vski-standalone
./vski-standalone
# Linux (API-only)
wget https://vski.sh/x/platform/releases/download/v0.5.0/vski
chmod +x vski
./vski

Pull and run official Docker image:

Terminal window
# 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 version
docker pull vski.sh/x/vski:v0.5.0
docker pull vski.sh/x/vski:v0.5.0-standalone
# Run light version with default configuration
docker run -p 3000:3000 -v $(pwd)/data:/app/data vski.sh/x/vski:latest
# Run standalone version with embedded web UI
docker run -p 3000:3000 -v $(pwd)/data:/app/data vski.sh/x/vski:latest-standalone

Create a .env file:

DATA_DIR=./data
SERVER_PORT=3000
JWT_SECRET=your-secret-key

The complete OpenAPI 3.0 specification is available at:

GET /api/openapi.json

This includes all endpoints including the newly documented migration APIs.

Access the Migrations management page by navigating to:

  • URL: http://localhost:3000/migrations
  • Navigation: SQL → Migrations in the sidebar

Common Workflows:

  1. 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/migrations directory.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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).

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...")
}

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

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.

None.

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 status
  • GET /api/migrations/generate - Generate new migration from schema diff
  • POST /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 file
  • GET /api/migrations/export - Export all migrations as ZIP
  • POST /api/migrations/import - Import migrations from ZIP file
  • GET /api/migrations/{version}/download - Download migration YAML
  • POST /api/migrations/{version}/apply - Apply migration
  • POST /api/migrations/{version}/rollback - Rollback migration
  • DELETE /api/migrations/{version} - Delete migration

Collection Changes Model (internal/models/migrations.go):

  • Added drop_columns: []string field 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 fields
  • isEmptyCollectionChanges() filters unchanged collections
  • Empty collection changes are excluded from generated migrations

Migration Service (internal/services/migrations.go):

  • applyCollectionChanges() now handles drop_columns via metadata update only
  • Better error handling for rollback data parsing

Before (separate main.go files):

Terminal window
cmd/server/main.go # ~220 lines
cmd/standalone/main.go # ~205 lines

After (shared initialization):

Terminal window
internal/app/bootstrap.go # New file with common logic
cmd/server/main.go # ~35 lines (uses app.NewApp(cfg))
cmd/standalone/main.go # ~40 lines (uses app.NewApp(cfg) + standalone handler)
Terminal window
cd vski
make build
make e2e TEST=50_migrations_test.ts # Test migrations
make e2e # Run all E2E tests
Terminal window
# Build the server
make build
# Start the server
./bin/vski-prod
# Fetch OpenAPI spec
curl 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}"
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:

Terminal window
go run your_custom_main.go

Expected output will show “Custom route works!” if successful.

Full documentation available at: https://vski.sh/x/platform

  • Complete OpenAPI 3.0 specifications for all implemented migration endpoints.
  • internal/app/bootstrap.go with NewApp(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_columns field 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/updateRule when 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.
  • Refactored cmd/server/main.go and cmd/standalone/main.go to use app.NewApp, significantly reducing code duplication.
  • Moved RecoveryMiddleware to internal/middleware/middleware.go for shared use.
  • DownloadMigrationsZip in internal/services/migrations.go now 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.
  • 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.
  • NewApp returns (*gin.Engine, func(), error) allowing flexible router extension and proper resource cleanup.
  • Standalone mode (cmd/standalone/main.go) integrates embedded web UI via router.NoRoute().
  • Server mode (cmd/server/main.go) serves to API without embedded UI.
  • Frontend MigrationsPage uses sdk.settings.migrations API for all operations with improved user feedback.
  • Added DropColumns field to CollectionChanges struct in internal/models/migrations.go.
  • Added detectDropColumns() function in internal/services/schema_diff.go to identify removed fields.
  • Added isEmptyCollectionChanges() helper function to filter out unchanged collections.
  • Updated applyCollectionChanges() in internal/services/migrations.go to handle dropped columns via soft delete.
  • Improved GenerateMigrationWithVersion() error handling for rollback data parsing.