diff --git a/development/backend/job-queue.mdx b/development/backend/job-queue.mdx index 7dfe2e2..596d9ab 100644 --- a/development/backend/job-queue.mdx +++ b/development/backend/job-queue.mdx @@ -30,7 +30,7 @@ Background worker loop that polls the database every second, processes jobs sequ Plugin-style pattern where each worker implements the `Worker` interface. Workers are registered by type (e.g., `send_email`, `process_csv`, `sync_registry`) and execute specific job types. ### Database Tables -Two tables provide persistence: `queueJobs` stores individual jobs with payload and status, while `queueJobBatches` tracks groups of related jobs for progress monitoring. +Two tables provide persistence: `queueJobs` stores individual jobs with payload, status, and result data, while `queueJobBatches` tracks groups of related jobs for progress monitoring. ## Core Concepts @@ -92,10 +92,12 @@ interface Worker { interface WorkerResult { success: boolean; message?: string; - data?: any; + data?: any; // Persisted to database on job completion } ``` +The `data` field in `WorkerResult` is automatically stored in the database when a job completes successfully. This allows you to inspect job results through the admin UI or database queries. + ### Basic Worker Pattern ```typescript @@ -136,7 +138,8 @@ export class EmailWorker implements Worker { return { success: true, - message: 'Email sent successfully' + message: 'Email sent successfully', + data: { sentAt: new Date().toISOString(), recipient: emailPayload.to } }; } catch (error) { this.logger.error({ @@ -365,25 +368,25 @@ Jobs transition through these states: ### Database Queries -Check job status: +Check job status and result: ```sql -SELECT id, type, status, created_at, started_at, completed_at, attempts -FROM queue_jobs +SELECT id, type, status, payload, result, error, created_at, completed_at, attempts +FROM "queueJobs" WHERE id = ?; ``` Monitor batch progress: ```sql -SELECT +SELECT b.id, b.total_jobs, COUNT(CASE WHEN j.status = 'completed' THEN 1 END) as completed, COUNT(CASE WHEN j.status = 'failed' THEN 1 END) as failed, COUNT(CASE WHEN j.status = 'processing' THEN 1 END) as processing -FROM queue_job_batches b -LEFT JOIN queue_jobs j ON j.batch_id = b.id +FROM "queueJobBatches" b +LEFT JOIN "queueJobs" j ON j.batch_id = b.id WHERE b.id = ? GROUP BY b.id; ``` @@ -414,32 +417,42 @@ For the complete database schema, see [schema.ts](https://github.com/deploystack ### Jobs Table ```sql -CREATE TABLE queue_jobs ( +CREATE TABLE "queueJobs" ( id TEXT PRIMARY KEY, type TEXT NOT NULL, - payload TEXT, + payload TEXT NOT NULL, status TEXT DEFAULT 'pending', + scheduled_for TIMESTAMP WITH TIME ZONE DEFAULT NOW(), attempts INTEGER DEFAULT 0, max_attempts INTEGER DEFAULT 3, - scheduled_for INTEGER, - created_at INTEGER DEFAULT (unixepoch()), - started_at INTEGER, - completed_at INTEGER, - last_error TEXT, - batch_id TEXT, - FOREIGN KEY (batch_id) REFERENCES queue_job_batches(id) + error TEXT, + result TEXT, + batch_id TEXT REFERENCES "queueJobBatches"(id) ON DELETE CASCADE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + completed_at TIMESTAMP WITH TIME ZONE ); ``` +| Column | Description | +|--------|-------------| +| `payload` | JSON input data passed to the worker | +| `error` | Error message if job failed | +| `result` | JSON output data returned by the worker on success | + ### Batches Table ```sql -CREATE TABLE queue_job_batches ( +CREATE TABLE "queueJobBatches" ( id TEXT PRIMARY KEY, - name TEXT NOT NULL, + type TEXT NOT NULL, total_jobs INTEGER NOT NULL, - created_at INTEGER DEFAULT (unixepoch()), - metadata TEXT + completed_jobs INTEGER DEFAULT 0, + failed_jobs INTEGER DEFAULT 0, + status TEXT DEFAULT 'pending', + metadata TEXT, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + completed_at TIMESTAMP WITH TIME ZONE ); ``` @@ -451,8 +464,8 @@ CREATE TABLE queue_job_batches ( 2. Check if job's `scheduled_for` time has passed 3. Lock job by setting status to `processing` 4. Execute worker for job type -5. Update status based on result -6. Implement exponential backoff for retries (1s, 2s, 4s, etc.) +5. On success: store worker's `data` in `result` column, set status to `completed` +6. On failure: implement exponential backoff for retries (1s, 2s, 4s, etc.) ### Resource Usage @@ -486,9 +499,12 @@ Balance between responsiveness and database load. Adequate latency for backgroun - Not suitable for sub-second latency requirements - Single-server deployment (no distributed workers) -- No built-in job scheduling (cron-like patterns) - Sequential processing limits throughput + +For recurring scheduled tasks, see the [Cron Job Scheduling](/development/backend/cron) documentation which integrates with this job queue system. + + ## Migration Path If scaling beyond single-server becomes necessary, clear upgrade paths exist: @@ -501,10 +517,10 @@ Worker interface remains compatible, simplifying migration. ## Related Documentation +- [Cron Job Scheduling](/development/backend/cron) - Schedule recurring tasks using cron expressions - [Database Management](/development/backend/database/) - Database configuration and schema - [Global Event Bus](/development/backend/events) - Event system for real-time notifications - [Logging](/development/backend/logging) - Logging best practices and patterns -- [API Documentation](/development/backend/api/) - REST API endpoints and patterns ## Common Use Cases diff --git a/development/frontend/ui/design-button-loading.mdx b/development/frontend/ui/design-button-loading.mdx index 111de18..62ebd3d 100644 --- a/development/frontend/ui/design-button-loading.mdx +++ b/development/frontend/ui/design-button-loading.mdx @@ -1,43 +1,32 @@ --- title: Button with Loading States -description: Guide for using the enhanced Button component with built-in loading states. +description: Guide for implementing loading states in buttons using the Spinner component. --- -The Button component includes built-in loading state functionality for async operations. +Use the shadcn-vue Spinner component inside buttons to show loading states during async operations. -## Component Location +## Component Locations ``` services/frontend/src/components/ui/button/ -├── Button.vue # Enhanced button component with loading states +├── Button.vue # Standard shadcn-vue button └── index.ts # Button variants and exports -``` - -## Features - -- **Automatic spinner** with `Loader2` icon from lucide-vue-next -- **Auto-disable** during loading to prevent double submissions -- **Optional loading text** to display custom messages -- **Size-aware spinner** that scales with button size -- **Works with all variants** (default, destructive, outline, etc.) -## Props +services/frontend/src/components/ui/spinner/ +├── Spinner.vue # Animated loading spinner +└── index.ts # Spinner exports +``` -| Prop | Type | Default | Description | -|------|------|---------|-------------| -| `loading` | `boolean` | `false` | Shows spinner and disables button | -| `loadingText` | `string` | `undefined` | Optional text during loading | -| `disabled` | `boolean` | `false` | Disable independent of loading | -| `variant` | `string` | `'default'` | Button style variant | -| `size` | `string` | `'default'` | Button size (sm, default, lg, icon) | +## Usage -## Usage Example +Import both Button and Spinner, then conditionally render the Spinner inside the button: ```vue ``` -## Implementation Details +## Pattern + +The loading button pattern consists of three parts: + +1. **Disable the button** - Add `:disabled="isLoading"` to prevent double clicks +2. **Show the spinner** - Add `` before the text +3. **Keep the text visible** - The button text remains visible during loading + +## Spinner Customization + +The Spinner component accepts a `class` prop for styling: + +```vue + + + + + +``` -The component automatically: -- Displays a spinning `Loader2` icon when `loading` is true -- Hides the original slot content during loading -- Shows `loadingText` alongside the spinner (if provided) -- Disables the button to prevent multiple clicks -- Adjusts spinner size based on button size prop +## Examples -For implementation details, see the source code at `services/frontend/src/components/ui/button/Button.vue`. +### Form Submit Button + +```vue + +``` + +### Delete Button + +```vue + +``` + +### With Validation + +```vue + +``` ## Related Documentation diff --git a/development/frontend/ui/design-settings-menu.mdx b/development/frontend/ui/design-settings-menu.mdx new file mode 100644 index 0000000..31949e3 Binary files /dev/null and b/development/frontend/ui/design-settings-menu.mdx differ diff --git a/docs.json b/docs.json index 9833c6a..82be3e2 100644 --- a/docs.json +++ b/docs.json @@ -100,7 +100,8 @@ "/development/frontend/ui/design-system-structured-data", "/development/frontend/ui/design-system-table", "/development/frontend/ui/custom-ui-components", - "/development/frontend/ui/siteHeader-with-breadcrumbs" + "/development/frontend/ui/siteHeader-with-breadcrumbs", + "/development/frontend/ui/design-settings-menu" ] } ]