initial wcag-ada
This commit is contained in:
parent
042b8cb83a
commit
d52cfe7de2
112 changed files with 9069 additions and 0 deletions
89
apps/wcag-ada/config/src/schemas/features.schema.ts
Normal file
89
apps/wcag-ada/config/src/schemas/features.schema.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const featuresConfigSchema = z.object({
|
||||
// Scanner features
|
||||
screenshots: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
quality: z.number().min(0).max(100).default(80),
|
||||
fullPage: z.boolean().default(false),
|
||||
}).default({}),
|
||||
|
||||
customRules: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
maxRules: z.number().default(50),
|
||||
}).default({}),
|
||||
|
||||
multiPage: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
maxPages: z.number().default(10),
|
||||
maxDepth: z.number().default(3),
|
||||
}).default({}),
|
||||
|
||||
// API features
|
||||
apiKeys: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
maxPerUser: z.number().default(5),
|
||||
}).default({}),
|
||||
|
||||
webhooks: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
maxPerWebsite: z.number().default(3),
|
||||
retryAttempts: z.number().default(3),
|
||||
}).default({}),
|
||||
|
||||
// Report features
|
||||
reports: z.object({
|
||||
pdf: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
watermark: z.boolean().default(true),
|
||||
}).default({}),
|
||||
excel: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
}).default({}),
|
||||
scheduling: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
|
||||
// Compliance features
|
||||
compliance: z.object({
|
||||
wcag20: z.boolean().default(true),
|
||||
wcag21: z.boolean().default(true),
|
||||
wcag22: z.boolean().default(true),
|
||||
section508: z.boolean().default(false),
|
||||
ada: z.boolean().default(true),
|
||||
}).default({}),
|
||||
|
||||
// Integration features
|
||||
integrations: z.object({
|
||||
github: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
}).default({}),
|
||||
slack: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
}).default({}),
|
||||
teams: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
}).default({}),
|
||||
jira: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
|
||||
// Enterprise features
|
||||
enterprise: z.object({
|
||||
sso: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
providers: z.array(z.enum(['saml', 'oauth', 'ldap'])).default([]),
|
||||
}).default({}),
|
||||
whiteLabel: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
}).default({}),
|
||||
audit: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
retention: z.number().default(365), // days
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
});
|
||||
|
||||
export type FeaturesConfig = z.infer<typeof featuresConfigSchema>;
|
||||
84
apps/wcag-ada/config/src/schemas/providers.schema.ts
Normal file
84
apps/wcag-ada/config/src/schemas/providers.schema.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const providersConfigSchema = z.object({
|
||||
// Storage providers
|
||||
storage: z.object({
|
||||
type: z.enum(['local', 's3', 'gcs', 'azure']).default('local'),
|
||||
local: z.object({
|
||||
basePath: z.string().default('/tmp/wcag-ada'),
|
||||
reports: z.string().default('reports'),
|
||||
screenshots: z.string().default('screenshots'),
|
||||
exports: z.string().default('exports'),
|
||||
}).default({}),
|
||||
s3: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
bucket: z.string().optional(),
|
||||
region: z.string().default('us-east-1'),
|
||||
accessKeyId: z.string().optional(),
|
||||
secretAccessKey: z.string().optional(),
|
||||
endpoint: z.string().optional(),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
|
||||
// Email providers
|
||||
email: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
provider: z.enum(['smtp', 'sendgrid', 'ses', 'postmark']).default('smtp'),
|
||||
from: z.object({
|
||||
name: z.string().default('WCAG-ADA Compliance'),
|
||||
email: z.string().email().default('noreply@wcag-ada.com'),
|
||||
}).default({}),
|
||||
smtp: z.object({
|
||||
host: z.string().default('localhost'),
|
||||
port: z.number().default(587),
|
||||
secure: z.boolean().default(false),
|
||||
auth: z.object({
|
||||
user: z.string().optional(),
|
||||
pass: z.string().optional(),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
sendgrid: z.object({
|
||||
apiKey: z.string().optional(),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
|
||||
// Authentication providers
|
||||
auth: z.object({
|
||||
jwt: z.object({
|
||||
secret: z.string().default('change-me-in-production'),
|
||||
expiresIn: z.string().default('7d'),
|
||||
refreshExpiresIn: z.string().default('30d'),
|
||||
}).default({}),
|
||||
oauth: z.object({
|
||||
google: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
clientId: z.string().optional(),
|
||||
clientSecret: z.string().optional(),
|
||||
}).default({}),
|
||||
github: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
clientId: z.string().optional(),
|
||||
clientSecret: z.string().optional(),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
|
||||
// Analytics providers
|
||||
analytics: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
provider: z.enum(['posthog', 'mixpanel', 'amplitude', 'custom']).default('posthog'),
|
||||
posthog: z.object({
|
||||
apiKey: z.string().optional(),
|
||||
host: z.string().default('https://app.posthog.com'),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
|
||||
// CDN providers
|
||||
cdn: z.object({
|
||||
enabled: z.boolean().default(false),
|
||||
provider: z.enum(['cloudflare', 'cloudfront', 'fastly']).default('cloudflare'),
|
||||
baseUrl: z.string().optional(),
|
||||
}).default({}),
|
||||
});
|
||||
|
||||
export type ProvidersConfig = z.infer<typeof providersConfigSchema>;
|
||||
34
apps/wcag-ada/config/src/schemas/scanner.schema.ts
Normal file
34
apps/wcag-ada/config/src/schemas/scanner.schema.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const scannerConfigSchema = z.object({
|
||||
concurrency: z.number().min(1).max(10).default(2),
|
||||
timeout: z.number().min(30000).default(120000), // 2 minutes default
|
||||
pageLoadTimeout: z.number().min(10000).default(30000),
|
||||
headless: z.boolean().default(true),
|
||||
blockResources: z.boolean().default(true),
|
||||
viewport: z.object({
|
||||
width: z.number().default(1280),
|
||||
height: z.number().default(720),
|
||||
deviceScaleFactor: z.number().default(1),
|
||||
}).default({}),
|
||||
browsers: z.object({
|
||||
chromium: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
args: z.array(z.string()).default(['--no-sandbox', '--disable-setuid-sandbox']),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
axe: z.object({
|
||||
tags: z.array(z.string()).default(['wcag2aa', 'wcag21aa']),
|
||||
resultTypes: z.array(z.enum(['violations', 'passes', 'incomplete', 'inapplicable']))
|
||||
.default(['violations', 'passes', 'incomplete', 'inapplicable']),
|
||||
}).default({}),
|
||||
retries: z.object({
|
||||
maxAttempts: z.number().default(3),
|
||||
backoff: z.object({
|
||||
type: z.enum(['exponential', 'fixed']).default('exponential'),
|
||||
delay: z.number().default(2000),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
});
|
||||
|
||||
export type ScannerConfig = z.infer<typeof scannerConfigSchema>;
|
||||
111
apps/wcag-ada/config/src/schemas/wcag-app.schema.ts
Normal file
111
apps/wcag-ada/config/src/schemas/wcag-app.schema.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import { z } from 'zod';
|
||||
import {
|
||||
baseAppConfigSchema,
|
||||
logConfigSchema,
|
||||
databaseConfigSchema,
|
||||
serviceConfigSchema,
|
||||
} from '@stock-bot/core-config';
|
||||
import { scannerConfigSchema } from './scanner.schema';
|
||||
import { workerConfigSchema } from './worker.schema';
|
||||
import { featuresConfigSchema } from './features.schema';
|
||||
import { providersConfigSchema } from './providers.schema';
|
||||
|
||||
// Service-specific configurations
|
||||
const wcagServicesSchema = z.object({
|
||||
api: serviceConfigSchema.extend({
|
||||
port: z.number().default(3001),
|
||||
cors: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
origin: z.string().default('*'),
|
||||
credentials: z.boolean().default(true),
|
||||
}).default({}),
|
||||
rateLimit: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
windowMs: z.number().default(900000), // 15 minutes
|
||||
max: z.number().default(100),
|
||||
keyGenerator: z.enum(['ip', 'userId', 'apiKey']).default('userId'),
|
||||
}).default({}),
|
||||
pagination: z.object({
|
||||
defaultLimit: z.number().default(20),
|
||||
maxLimit: z.number().default(100),
|
||||
}).default({}),
|
||||
}),
|
||||
|
||||
dashboard: serviceConfigSchema.extend({
|
||||
port: z.number().default(3000),
|
||||
apiUrl: z.string().default('http://localhost:3001'),
|
||||
publicUrl: z.string().default('http://localhost:3000'),
|
||||
}),
|
||||
|
||||
worker: serviceConfigSchema.extend({
|
||||
port: z.number().default(3002), // For health checks
|
||||
}),
|
||||
});
|
||||
|
||||
// Main WCAG application configuration schema
|
||||
export const wcagAppConfigSchema = baseAppConfigSchema.extend({
|
||||
appName: z.literal('wcag-ada').default('wcag-ada'),
|
||||
|
||||
// Core configurations
|
||||
log: logConfigSchema,
|
||||
database: databaseConfigSchema,
|
||||
|
||||
// WCAG-specific configurations
|
||||
scanner: scannerConfigSchema,
|
||||
worker: workerConfigSchema,
|
||||
features: featuresConfigSchema,
|
||||
providers: providersConfigSchema,
|
||||
|
||||
// Service configurations
|
||||
services: wcagServicesSchema.default({}),
|
||||
|
||||
// Business logic configurations
|
||||
compliance: z.object({
|
||||
defaultLevel: z.object({
|
||||
standard: z.enum(['WCAG20', 'WCAG21', 'WCAG22']).default('WCAG21'),
|
||||
level: z.enum(['A', 'AA', 'AAA']).default('AA'),
|
||||
}).default({}),
|
||||
passingScore: z.object({
|
||||
A: z.number().min(0).max(100).default(95),
|
||||
AA: z.number().min(0).max(100).default(98),
|
||||
AAA: z.number().min(0).max(100).default(100),
|
||||
}).default({}),
|
||||
criticalCriteria: z.array(z.string()).default([
|
||||
'1.1.1', // Non-text Content
|
||||
'1.3.1', // Info and Relationships
|
||||
'1.4.3', // Contrast (Minimum)
|
||||
'2.1.1', // Keyboard
|
||||
'2.1.2', // No Keyboard Trap
|
||||
'2.4.1', // Bypass Blocks
|
||||
'2.4.2', // Page Titled
|
||||
'4.1.2', // Name, Role, Value
|
||||
]),
|
||||
}).default({}),
|
||||
|
||||
// Subscription/pricing tiers
|
||||
subscriptions: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
tiers: z.object({
|
||||
starter: z.object({
|
||||
websites: z.number().default(5),
|
||||
scansPerMonth: z.number().default(500),
|
||||
users: z.number().default(1),
|
||||
price: z.number().default(49),
|
||||
}).default({}),
|
||||
professional: z.object({
|
||||
websites: z.number().default(25),
|
||||
scansPerMonth: z.number().default(5000),
|
||||
users: z.number().default(5),
|
||||
price: z.number().default(149),
|
||||
}).default({}),
|
||||
enterprise: z.object({
|
||||
websites: z.number().default(-1), // Unlimited
|
||||
scansPerMonth: z.number().default(-1),
|
||||
users: z.number().default(-1),
|
||||
price: z.number().default(499),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
});
|
||||
|
||||
export type WcagAppConfig = z.infer<typeof wcagAppConfigSchema>;
|
||||
49
apps/wcag-ada/config/src/schemas/worker.schema.ts
Normal file
49
apps/wcag-ada/config/src/schemas/worker.schema.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const workerConfigSchema = z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
concurrency: z.number().min(1).max(10).default(2),
|
||||
queueName: z.string().default('accessibility-scans'),
|
||||
redis: z.object({
|
||||
host: z.string().default('localhost'),
|
||||
port: z.number().default(6379),
|
||||
password: z.string().optional(),
|
||||
db: z.number().default(2), // Different DB for WCAG
|
||||
maxRetriesPerRequest: z.number().nullable().default(null),
|
||||
}).default({}),
|
||||
jobs: z.object({
|
||||
scan: z.object({
|
||||
priority: z.number().default(0),
|
||||
attempts: z.number().default(3),
|
||||
backoff: z.object({
|
||||
type: z.enum(['exponential', 'fixed']).default('exponential'),
|
||||
delay: z.number().default(2000),
|
||||
}).default({}),
|
||||
timeout: z.number().default(300000), // 5 minutes
|
||||
removeOnComplete: z.object({
|
||||
age: z.number().default(86400), // 24 hours
|
||||
count: z.number().default(100),
|
||||
}).default({}),
|
||||
removeOnFail: z.object({
|
||||
age: z.number().default(604800), // 7 days
|
||||
count: z.number().default(500),
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
report: z.object({
|
||||
priority: z.number().default(1),
|
||||
attempts: z.number().default(2),
|
||||
backoff: z.object({
|
||||
type: z.enum(['exponential', 'fixed']).default('exponential'),
|
||||
delay: z.number().default(5000),
|
||||
}).default({}),
|
||||
timeout: z.number().default(600000), // 10 minutes
|
||||
}).default({}),
|
||||
}).default({}),
|
||||
scheduler: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
interval: z.number().default(60000), // Check every minute
|
||||
timezone: z.string().default('UTC'),
|
||||
}).default({}),
|
||||
});
|
||||
|
||||
export type WorkerConfig = z.infer<typeof workerConfigSchema>;
|
||||
Loading…
Add table
Add a link
Reference in a new issue