yadflow 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +4 -7
  2. package/README.md +23 -2
  3. package/bin/yad.mjs +22 -1
  4. package/cli/docs.mjs +298 -0
  5. package/cli/manifest.mjs +6 -1
  6. package/docs/index.html +4 -4
  7. package/package.json +2 -2
  8. package/skills/sdlc/config.yaml +19 -0
  9. package/skills/sdlc/install.sh +1 -1
  10. package/skills/sdlc/module-help.csv +4 -0
  11. package/skills/yad-connect-docs/SKILL.md +132 -0
  12. package/skills/yad-connect-docs/references/docs-registry.md +74 -0
  13. package/skills/yad-docs/SKILL.md +159 -0
  14. package/skills/yad-docs/references/data-mapping.md +75 -0
  15. package/skills/yad-docs/references/theme-map.md +69 -0
  16. package/skills/yad-docs/templates/app/README.md +31 -0
  17. package/skills/yad-docs/templates/app/eslint.config.js +23 -0
  18. package/skills/yad-docs/templates/app/index.html +17 -0
  19. package/skills/yad-docs/templates/app/package-lock.json +4030 -0
  20. package/skills/yad-docs/templates/app/package.json +35 -0
  21. package/skills/yad-docs/templates/app/public/favicon.svg +28 -0
  22. package/skills/yad-docs/templates/app/public/logo.svg +39 -0
  23. package/skills/yad-docs/templates/app/public/vite.svg +1 -0
  24. package/skills/yad-docs/templates/app/src/App.tsx +98 -0
  25. package/skills/yad-docs/templates/app/src/components/Auth/LoginPage.tsx +101 -0
  26. package/skills/yad-docs/templates/app/src/components/Canvas/AnimatedMessage.tsx +101 -0
  27. package/skills/yad-docs/templates/app/src/components/Canvas/ConnectionLine.tsx +90 -0
  28. package/skills/yad-docs/templates/app/src/components/Canvas/FlowCanvas.tsx +216 -0
  29. package/skills/yad-docs/templates/app/src/components/Canvas/SystemComponent.tsx +153 -0
  30. package/skills/yad-docs/templates/app/src/components/Controls/PlaybackBar.tsx +284 -0
  31. package/skills/yad-docs/templates/app/src/components/Controls/StepDetail.tsx +167 -0
  32. package/skills/yad-docs/templates/app/src/components/DetailPanel/HandlerLogicSnippet.tsx +41 -0
  33. package/skills/yad-docs/templates/app/src/components/DetailPanel/RequestPayloadPreview.tsx +46 -0
  34. package/skills/yad-docs/templates/app/src/components/DetailPanel/RightPanel.tsx +88 -0
  35. package/skills/yad-docs/templates/app/src/components/DetailPanel/StatusCard.tsx +76 -0
  36. package/skills/yad-docs/templates/app/src/components/DetailPanel/TriggerEventCard.tsx +45 -0
  37. package/skills/yad-docs/templates/app/src/components/DocLayout/DocPageShell.tsx +80 -0
  38. package/skills/yad-docs/templates/app/src/components/DocLayout/DocSectionCard.tsx +55 -0
  39. package/skills/yad-docs/templates/app/src/components/DocLayout/DocTableOfContents.tsx +79 -0
  40. package/skills/yad-docs/templates/app/src/components/DocLayout/RoleCard.tsx +67 -0
  41. package/skills/yad-docs/templates/app/src/components/DocSections/ApiReferenceSection.tsx +108 -0
  42. package/skills/yad-docs/templates/app/src/components/DocSections/CancelabilitySection.tsx +73 -0
  43. package/skills/yad-docs/templates/app/src/components/DocSections/CriticalRunbookSection.tsx +177 -0
  44. package/skills/yad-docs/templates/app/src/components/DocSections/DataMigrationSection.tsx +102 -0
  45. package/skills/yad-docs/templates/app/src/components/DocSections/DbSchemaSection.tsx +98 -0
  46. package/skills/yad-docs/templates/app/src/components/DocSections/DeploymentGuideSection.tsx +104 -0
  47. package/skills/yad-docs/templates/app/src/components/DocSections/DriverIntegrationSection.tsx +127 -0
  48. package/skills/yad-docs/templates/app/src/components/DocSections/ExecutiveSummarySection.tsx +69 -0
  49. package/skills/yad-docs/templates/app/src/components/DocSections/FlowOverviewSection.tsx +73 -0
  50. package/skills/yad-docs/templates/app/src/components/DocSections/FlowPathsChecklistSection.tsx +96 -0
  51. package/skills/yad-docs/templates/app/src/components/DocSections/MiddlewareChainSection.tsx +107 -0
  52. package/skills/yad-docs/templates/app/src/components/DocSections/MonitoringAlertingSection.tsx +106 -0
  53. package/skills/yad-docs/templates/app/src/components/DocSections/NotificationLocalizationSection.tsx +102 -0
  54. package/skills/yad-docs/templates/app/src/components/DocSections/PMRoadmapSection.tsx +133 -0
  55. package/skills/yad-docs/templates/app/src/components/DocSections/PerformanceTestingSection.tsx +91 -0
  56. package/skills/yad-docs/templates/app/src/components/DocSections/RiderIntegrationSection.tsx +99 -0
  57. package/skills/yad-docs/templates/app/src/components/DocSections/SecuritySection.tsx +74 -0
  58. package/skills/yad-docs/templates/app/src/components/DocSections/StatusMachineSection.tsx +90 -0
  59. package/skills/yad-docs/templates/app/src/components/DocSections/TestPlanSection.tsx +163 -0
  60. package/skills/yad-docs/templates/app/src/components/Logs/SystemLogsTerminal.tsx +126 -0
  61. package/skills/yad-docs/templates/app/src/components/Navigation/TopNavBar.tsx +90 -0
  62. package/skills/yad-docs/templates/app/src/components/Reference/BullMQJobsList.tsx +60 -0
  63. package/skills/yad-docs/templates/app/src/components/Reference/DecisionTreeView.tsx +49 -0
  64. package/skills/yad-docs/templates/app/src/components/Reference/DeeplinkActionsChips.tsx +69 -0
  65. package/skills/yad-docs/templates/app/src/components/Reference/DriverUIStatesTable.tsx +61 -0
  66. package/skills/yad-docs/templates/app/src/components/Reference/FeatureFlagMatrix.tsx +73 -0
  67. package/skills/yad-docs/templates/app/src/components/Reference/RiderUIStatesTable.tsx +61 -0
  68. package/skills/yad-docs/templates/app/src/components/Reference/RulesLegendPanel.tsx +217 -0
  69. package/skills/yad-docs/templates/app/src/components/Reference/StakeholderToggle.tsx +41 -0
  70. package/skills/yad-docs/templates/app/src/components/Reference/TroubleshootingSection.tsx +93 -0
  71. package/skills/yad-docs/templates/app/src/components/Sidebar/PathSelector.tsx +148 -0
  72. package/skills/yad-docs/templates/app/src/components/Sidebar/SidebarFooter.tsx +40 -0
  73. package/skills/yad-docs/templates/app/src/components/Sidebar/StepList.tsx +234 -0
  74. package/skills/yad-docs/templates/app/src/components/shared/Badge.tsx +28 -0
  75. package/skills/yad-docs/templates/app/src/components/shared/CommandPalette.tsx +213 -0
  76. package/skills/yad-docs/templates/app/src/components/shared/Icon.tsx +21 -0
  77. package/skills/yad-docs/templates/app/src/components/shared/Tooltip.tsx +42 -0
  78. package/skills/yad-docs/templates/app/src/data/components.ts +74 -0
  79. package/skills/yad-docs/templates/app/src/data/docSections.ts +231 -0
  80. package/skills/yad-docs/templates/app/src/data/paths.ts +2319 -0
  81. package/skills/yad-docs/templates/app/src/data/referenceData.ts +392 -0
  82. package/skills/yad-docs/templates/app/src/data/roles.ts +145 -0
  83. package/skills/yad-docs/templates/app/src/data/types.ts +79 -0
  84. package/skills/yad-docs/templates/app/src/hooks/useAnimationQueue.ts +41 -0
  85. package/skills/yad-docs/templates/app/src/hooks/usePlayback.ts +100 -0
  86. package/skills/yad-docs/templates/app/src/hooks/useStakeholderFilter.ts +10 -0
  87. package/skills/yad-docs/templates/app/src/index.css +121 -0
  88. package/skills/yad-docs/templates/app/src/main.tsx +13 -0
  89. package/skills/yad-docs/templates/app/src/pages/RoleSelectPage.tsx +34 -0
  90. package/skills/yad-docs/templates/app/src/pages/StakeholderDocPage.tsx +98 -0
  91. package/skills/yad-docs/templates/app/src/pages/SubPathDetailPage.tsx +282 -0
  92. package/skills/yad-docs/templates/app/src/store/useAuthStore.ts +42 -0
  93. package/skills/yad-docs/templates/app/src/store/useFlowStore.ts +197 -0
  94. package/skills/yad-docs/templates/app/src/utils/iconMap.ts +46 -0
  95. package/skills/yad-docs/templates/app/tsconfig.app.json +28 -0
  96. package/skills/yad-docs/templates/app/tsconfig.json +7 -0
  97. package/skills/yad-docs/templates/app/tsconfig.node.json +26 -0
  98. package/skills/yad-docs/templates/app/vite.config.ts +10 -0
  99. package/skills/yad-docs-overview/SKILL.md +129 -0
  100. package/skills/yad-docs-overview/references/pipeline-model.md +102 -0
  101. package/skills/yad-docs-sync/SKILL.md +99 -0
  102. package/skills/yad-docs-sync/references/staleness.md +81 -0
@@ -0,0 +1,106 @@
1
+ import { Icon } from '../shared/Icon';
2
+
3
+ const METRICS = [
4
+ {
5
+ name: 'booking_status_update_rate',
6
+ type: 'Counter',
7
+ description: 'Number of booking status updates per minute',
8
+ alert: '> 500/min sustained → investigate traffic spike',
9
+ source: 'fnUpdateBookingStatus middleware',
10
+ },
11
+ {
12
+ name: 'optimistic_lock_failure_rate',
13
+ type: 'Counter',
14
+ description: 'Number of modifiedCount: 0 responses',
15
+ alert: '> 5% of total updates → investigate concurrent access patterns',
16
+ source: 'Trip.updateOne with booking_status guard',
17
+ },
18
+ {
19
+ name: 'bullmq_job_processing_time',
20
+ type: 'Histogram',
21
+ description: 'Time from job scheduled to job completed',
22
+ alert: 'p99 > 30s → check Redis latency and worker health',
23
+ source: 'BullMQ worker event listeners',
24
+ },
25
+ {
26
+ name: 'bullmq_queue_depth',
27
+ type: 'Gauge',
28
+ description: 'Number of waiting jobs in booking-trips queue',
29
+ alert: '> 100 waiting → workers may be stuck or undersized',
30
+ source: 'BullMQ queue.getWaitingCount()',
31
+ },
32
+ {
33
+ name: 'notification_delivery_failures',
34
+ type: 'Counter',
35
+ description: 'Failed push notification sends',
36
+ alert: '> 10% failure rate → check FCM/APNS credentials',
37
+ source: 'sendBookingNotificationWithConfig .catch()',
38
+ },
39
+ {
40
+ name: 'dac_pubsub_publish_failures',
41
+ type: 'Counter',
42
+ description: 'Failed DAC Pub/Sub publishes',
43
+ alert: 'Any sustained failures → check GCP Pub/Sub health',
44
+ source: 'publishScheduledRideDacMW',
45
+ },
46
+ ];
47
+
48
+ const DASHBOARD_PANELS = [
49
+ 'Booking status distribution (pie chart: terminal vs active)',
50
+ 'Update rate over time (time series: last 24h)',
51
+ 'Optimistic lock failure ratio (single stat + trend)',
52
+ 'BullMQ queue depth and processing rate (dual axis)',
53
+ 'Notification delivery success rate (gauge)',
54
+ 'Top error codes by frequency (bar chart)',
55
+ ];
56
+
57
+ export function MonitoringAlertingSection() {
58
+ return (
59
+ <div className="space-y-5">
60
+ <div
61
+ className="rounded-xl border overflow-hidden"
62
+ style={{ borderColor: 'var(--color-border-default)', background: 'rgba(20,17,24,0.5)' }}
63
+ >
64
+ <div className="px-4 py-3 border-b" style={{ borderColor: 'var(--color-border-default)', background: 'rgba(255,255,255,0.03)' }}>
65
+ <span className="text-sm font-bold text-slate-200">Key Metrics & Alert Thresholds</span>
66
+ </div>
67
+ <div className="divide-y" style={{ borderColor: 'var(--color-border-default)' }}>
68
+ {METRICS.map((m) => (
69
+ <div key={m.name} className="p-4 hover:bg-white/5 transition-colors" style={{ borderColor: 'var(--color-border-default)' }}>
70
+ <div className="flex items-center gap-2 mb-1">
71
+ <code className="text-xs font-mono text-cyan-400">{m.name}</code>
72
+ <span
73
+ className="text-[9px] px-1.5 py-0.5 rounded font-medium"
74
+ style={{ background: 'rgba(255,255,255,0.05)', color: 'var(--color-text-muted)' }}
75
+ >
76
+ {m.type}
77
+ </span>
78
+ </div>
79
+ <p className="text-xs text-slate-400 mb-1.5">{m.description}</p>
80
+ <div className="flex items-start gap-2">
81
+ <Icon name="notifications_active" size={12} className="text-amber-400 mt-0.5" />
82
+ <span className="text-[11px] text-amber-300">{m.alert}</span>
83
+ </div>
84
+ <div className="text-[10px] text-slate-600 mt-1">Source: {m.source}</div>
85
+ </div>
86
+ ))}
87
+ </div>
88
+ </div>
89
+
90
+ <div
91
+ className="rounded-xl border p-4"
92
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
93
+ >
94
+ <h4 className="text-sm font-bold text-slate-200 mb-3">Grafana Dashboard Panels</h4>
95
+ <div className="space-y-1.5">
96
+ {DASHBOARD_PANELS.map((panel, i) => (
97
+ <div key={i} className="flex items-center gap-2">
98
+ <Icon name="dashboard" size={14} className="text-slate-600" />
99
+ <span className="text-xs text-slate-400">{panel}</span>
100
+ </div>
101
+ ))}
102
+ </div>
103
+ </div>
104
+ </div>
105
+ );
106
+ }
@@ -0,0 +1,102 @@
1
+ import { DEEPLINK_ACTIONS } from '../../data/referenceData';
2
+
3
+ const PUSH_PAYLOAD_EXAMPLE = {
4
+ notification: {
5
+ title: '{{ localized_title }}',
6
+ body: '{{ localized_body }}',
7
+ },
8
+ data: {
9
+ action: 'confirm_booking',
10
+ trip_id: '{{ trip._id }}',
11
+ deeplink: 'yassir://booking/confirm?tripId={{ trip._id }}',
12
+ },
13
+ };
14
+
15
+ const LOCALIZATION_KEYS = [
16
+ { action: 'confirm_booking', titleKey: 'booking.confirm.title', bodyKey: 'booking.confirm.body', description: 'Asks rider to confirm their scheduled ride' },
17
+ { action: 'booking_timeout', titleKey: 'booking.timeout.title', bodyKey: 'booking.timeout.body', description: 'Warns rider their confirmation window is closing' },
18
+ { action: 'booking_cancelled', titleKey: 'booking.cancelled.title', bodyKey: 'booking.cancelled.body', description: 'Informs rider booking was cancelled' },
19
+ { action: 'confirm_driver_booking', titleKey: 'driver.booking.confirm.title', bodyKey: 'driver.booking.confirm.body', description: 'Asks driver to confirm availability' },
20
+ { action: 'booking_driver_assigned', titleKey: 'driver.booking.assigned.title', bodyKey: 'driver.booking.assigned.body', description: 'Notifies driver of new assignment' },
21
+ { action: 'booking_driver_assigned_rider', titleKey: 'booking.driver_assigned.title', bodyKey: 'booking.driver_assigned.body', description: 'Notifies rider that driver is assigned' },
22
+ { action: 'booking_driver_confirmed_rider', titleKey: 'booking.driver_confirmed.title', bodyKey: 'booking.driver_confirmed.body', description: 'Notifies rider that driver confirmed' },
23
+ ];
24
+
25
+ export function NotificationLocalizationSection() {
26
+ const riderActions = DEEPLINK_ACTIONS.filter((a) => a.target === 'rider');
27
+ const driverActions = DEEPLINK_ACTIONS.filter((a) => a.target === 'driver');
28
+
29
+ return (
30
+ <div className="space-y-5">
31
+ <div
32
+ className="rounded-xl border p-5"
33
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
34
+ >
35
+ <h4 className="text-sm font-bold text-slate-200 mb-2">Push Notification Payload Format</h4>
36
+ <p className="text-xs text-slate-400 mb-3">
37
+ All booking notifications use <code className="text-xs bg-white/5 px-1 rounded text-slate-300">sendBookingNotificationWithConfig</code> which
38
+ wraps the standard notification service. The payload follows this structure:
39
+ </p>
40
+ <pre className="text-[11px] font-mono text-emerald-400 bg-black/30 rounded-lg p-3 overflow-x-auto">
41
+ {JSON.stringify(PUSH_PAYLOAD_EXAMPLE, null, 2)}
42
+ </pre>
43
+ </div>
44
+
45
+ <div
46
+ className="rounded-xl border overflow-hidden"
47
+ style={{ borderColor: 'var(--color-border-default)', background: 'rgba(20,17,24,0.5)' }}
48
+ >
49
+ <div className="px-4 py-3 border-b" style={{ borderColor: 'var(--color-border-default)', background: 'rgba(255,255,255,0.03)' }}>
50
+ <span className="text-sm font-bold text-slate-200">Localization Keys</span>
51
+ </div>
52
+ <table className="w-full text-sm">
53
+ <thead>
54
+ <tr style={{ background: 'rgba(255,255,255,0.05)' }}>
55
+ <th className="px-4 py-2 text-left text-xs font-semibold text-slate-400">Action</th>
56
+ <th className="px-4 py-2 text-left text-xs font-semibold text-slate-400">Title Key</th>
57
+ <th className="px-4 py-2 text-left text-xs font-semibold text-slate-400">Body Key</th>
58
+ </tr>
59
+ </thead>
60
+ <tbody>
61
+ {LOCALIZATION_KEYS.map((k) => (
62
+ <tr key={k.action} className="border-t hover:bg-white/5 transition-colors" style={{ borderColor: 'var(--color-border-default)' }}>
63
+ <td className="px-4 py-2 font-mono text-[11px] text-cyan-400">{k.action}</td>
64
+ <td className="px-4 py-2 font-mono text-[11px] text-slate-400">{k.titleKey}</td>
65
+ <td className="px-4 py-2 font-mono text-[11px] text-slate-400">{k.bodyKey}</td>
66
+ </tr>
67
+ ))}
68
+ </tbody>
69
+ </table>
70
+ </div>
71
+
72
+ <div
73
+ className="rounded-xl border p-4"
74
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
75
+ >
76
+ <h4 className="text-sm font-bold text-slate-200 mb-3">Action Summary</h4>
77
+ <div className="grid grid-cols-2 gap-4">
78
+ <div>
79
+ <span className="text-[10px] uppercase tracking-wider text-slate-500 font-semibold mb-2 block">
80
+ Rider ({riderActions.length})
81
+ </span>
82
+ <div className="space-y-1">
83
+ {riderActions.map((a) => (
84
+ <div key={a.value} className="text-[11px] font-mono text-slate-400">{a.value}</div>
85
+ ))}
86
+ </div>
87
+ </div>
88
+ <div>
89
+ <span className="text-[10px] uppercase tracking-wider text-slate-500 font-semibold mb-2 block">
90
+ Driver ({driverActions.length})
91
+ </span>
92
+ <div className="space-y-1">
93
+ {driverActions.map((a) => (
94
+ <div key={a.value} className="text-[11px] font-mono text-slate-400">{a.value}</div>
95
+ ))}
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,133 @@
1
+ import { Icon } from '../shared/Icon';
2
+
3
+ const PHASES = [
4
+ {
5
+ phase: 'Phase 1 — Foundation',
6
+ status: 'completed',
7
+ color: '#22c55e',
8
+ items: [
9
+ 'booking_status field added to Trip schema',
10
+ 'TRIP_STATUS_TO_BOOKING_STATUS mapping (12 entries)',
11
+ 'fnUpdateBookingStatus middleware on internal trip updates',
12
+ 'Rider booking status endpoint (confirm/unconfirm/cancel)',
13
+ 'Driver booking status endpoint (accept/cancel)',
14
+ ],
15
+ },
16
+ {
17
+ phase: 'Phase 2 — Scheduled Jobs',
18
+ status: 'in-staging',
19
+ color: '#f59e0b',
20
+ items: [
21
+ 'BullMQ job scheduling for pre-trip confirmations',
22
+ 'Rider confirmation timeout chain (24h → 30min → 15min)',
23
+ 'Ops intervention window for unconfirmed bookings',
24
+ 'Job cleanup on cancellation/completion',
25
+ ],
26
+ },
27
+ {
28
+ phase: 'Phase 3 — Driver Confirmation',
29
+ status: 'planned',
30
+ color: '#8b5cf6',
31
+ items: [
32
+ 'ENABLE_DRIVER_CONFIRMATION flag activation',
33
+ 'Driver confirmation timeout chain (40min → 5min → 10min)',
34
+ 'Fast-track auto-confirmation for imminent rides',
35
+ 'handleBookAssigned decision tree (time threshold logic)',
36
+ ],
37
+ },
38
+ {
39
+ phase: 'Phase 4 — Enhancements',
40
+ status: 'planned',
41
+ color: '#64748b',
42
+ items: [
43
+ 'Ops dashboard for booking status monitoring',
44
+ 'Analytics events for booking funnel tracking',
45
+ 'Rider/driver app booking status history view',
46
+ 'Automated reporting for cancellation patterns',
47
+ ],
48
+ },
49
+ ];
50
+
51
+ const STATUS_COLORS: Record<string, { color: string; bg: string; label: string }> = {
52
+ completed: { color: '#22c55e', bg: 'rgba(34,197,94,0.1)', label: 'Completed' },
53
+ 'in-staging': { color: '#f59e0b', bg: 'rgba(245,158,11,0.1)', label: 'In Staging' },
54
+ planned: { color: '#8b5cf6', bg: 'rgba(139,92,246,0.1)', label: 'Planned' },
55
+ };
56
+
57
+ const RISKS = [
58
+ { risk: 'Redis downtime blocks all BullMQ jobs', mitigation: 'Redis HA setup + fallback to manual ops processing', level: 'high' },
59
+ { risk: 'Mobile app not handling new booking statuses', mitigation: 'Graceful degradation — unknown statuses treated as pending', level: 'medium' },
60
+ { risk: 'Notification service rate limiting', mitigation: 'Fire-and-forget pattern prevents blocking; add retry queue later', level: 'low' },
61
+ ];
62
+
63
+ export function PMRoadmapSection() {
64
+ return (
65
+ <div className="space-y-5">
66
+ {PHASES.map((phase) => {
67
+ const sc = STATUS_COLORS[phase.status];
68
+ return (
69
+ <div
70
+ key={phase.phase}
71
+ className="rounded-xl border overflow-hidden"
72
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
73
+ >
74
+ <div className="px-4 py-3 border-b flex items-center justify-between" style={{ borderColor: 'var(--color-border-default)', background: 'rgba(255,255,255,0.03)' }}>
75
+ <div className="flex items-center gap-2">
76
+ <div className="w-2 h-2 rounded-full" style={{ background: phase.color }} />
77
+ <span className="text-sm font-bold text-slate-200">{phase.phase}</span>
78
+ </div>
79
+ <span
80
+ className="text-[10px] font-bold px-2 py-0.5 rounded"
81
+ style={{ background: sc.bg, color: sc.color }}
82
+ >
83
+ {sc.label}
84
+ </span>
85
+ </div>
86
+ <ul className="p-4 space-y-1.5">
87
+ {phase.items.map((item, i) => (
88
+ <li key={i} className="flex items-center gap-2">
89
+ <Icon
90
+ name={phase.status === 'completed' ? 'check_circle' : 'radio_button_unchecked'}
91
+ size={14}
92
+ className={phase.status === 'completed' ? 'text-emerald-400' : 'text-slate-600'}
93
+ />
94
+ <span className="text-xs text-slate-400">{item}</span>
95
+ </li>
96
+ ))}
97
+ </ul>
98
+ </div>
99
+ );
100
+ })}
101
+
102
+ <div
103
+ className="rounded-xl border p-4"
104
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
105
+ >
106
+ <h4 className="text-sm font-bold text-slate-200 mb-3">Risk Register</h4>
107
+ <div className="space-y-2">
108
+ {RISKS.map((r, i) => (
109
+ <div
110
+ key={i}
111
+ className="flex items-start gap-3 p-2.5 rounded-lg"
112
+ style={{ background: 'rgba(255,255,255,0.02)' }}
113
+ >
114
+ <span
115
+ className="text-[9px] font-bold uppercase px-1.5 py-0.5 rounded shrink-0 mt-0.5"
116
+ style={{
117
+ color: r.level === 'high' ? '#ef4444' : r.level === 'medium' ? '#f59e0b' : '#22c55e',
118
+ background: r.level === 'high' ? 'rgba(239,68,68,0.1)' : r.level === 'medium' ? 'rgba(245,158,11,0.1)' : 'rgba(34,197,94,0.1)',
119
+ }}
120
+ >
121
+ {r.level}
122
+ </span>
123
+ <div>
124
+ <div className="text-xs text-slate-300">{r.risk}</div>
125
+ <div className="text-[11px] text-slate-500 mt-0.5">Mitigation: {r.mitigation}</div>
126
+ </div>
127
+ </div>
128
+ ))}
129
+ </div>
130
+ </div>
131
+ </div>
132
+ );
133
+ }
@@ -0,0 +1,91 @@
1
+ import { Icon } from '../shared/Icon';
2
+
3
+ const SCENARIOS = [
4
+ {
5
+ name: 'Concurrent Booking Updates',
6
+ description: 'Simulate multiple status updates hitting the same trip simultaneously',
7
+ expected: 'Only one succeeds (optimistic lock), others skip silently with modifiedCount: 0',
8
+ metric: '< 50ms p99 for updateOne with status guard',
9
+ },
10
+ {
11
+ name: 'BullMQ Job Throughput',
12
+ description: 'Schedule 1000 confirmation jobs within 1 minute',
13
+ expected: 'All jobs processed within their delay windows, no job drops',
14
+ metric: 'Queue depth returns to 0 within expected timeframe + 10% buffer',
15
+ },
16
+ {
17
+ name: 'Notification Burst',
18
+ description: 'Trigger 500 booking notifications simultaneously',
19
+ expected: 'All notifications delivered via FCM/APNS, fire-and-forget pattern prevents blocking',
20
+ metric: '< 200ms for notification dispatch (excludes delivery)',
21
+ },
22
+ {
23
+ name: 'DAC Pub/Sub Latency',
24
+ description: 'Publish/delete 100 DAC cards in rapid succession',
25
+ expected: 'All Pub/Sub messages acknowledged within timeout',
26
+ metric: '< 100ms per Pub/Sub publish',
27
+ },
28
+ {
29
+ name: 'Full Flow Path Execution',
30
+ description: 'Execute all 11 flow paths sequentially with realistic delays',
31
+ expected: 'All paths reach terminal state with correct booking_status',
32
+ metric: 'No memory leaks, no connection pool exhaustion',
33
+ },
34
+ ];
35
+
36
+ const KEY_METRICS = [
37
+ { metric: 'MongoDB updateOne (with guard)', target: '< 10ms p50, < 50ms p99', icon: 'storage' },
38
+ { metric: 'BullMQ job scheduling', target: '< 5ms per add()', icon: 'schedule' },
39
+ { metric: 'Pub/Sub publish', target: '< 100ms per message', icon: 'cloud_upload' },
40
+ { metric: 'API endpoint response', target: '< 200ms p99 (end-to-end)', icon: 'speed' },
41
+ ];
42
+
43
+ export function PerformanceTestingSection() {
44
+ return (
45
+ <div className="space-y-5">
46
+ <div className="grid grid-cols-2 gap-3">
47
+ {KEY_METRICS.map((m) => (
48
+ <div
49
+ key={m.metric}
50
+ className="rounded-lg border p-3"
51
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
52
+ >
53
+ <Icon name={m.icon} size={18} className="text-cyan-400 mb-2" />
54
+ <div className="text-xs text-slate-200 font-medium">{m.metric}</div>
55
+ <div className="text-[11px] text-emerald-400 font-mono mt-1">{m.target}</div>
56
+ </div>
57
+ ))}
58
+ </div>
59
+
60
+ <div
61
+ className="rounded-xl border overflow-hidden"
62
+ style={{ borderColor: 'var(--color-border-default)', background: 'rgba(20,17,24,0.5)' }}
63
+ >
64
+ <div className="px-4 py-3 border-b" style={{ borderColor: 'var(--color-border-default)', background: 'rgba(255,255,255,0.03)' }}>
65
+ <span className="text-sm font-bold text-slate-200">Load Test Scenarios</span>
66
+ </div>
67
+ <div className="divide-y" style={{ borderColor: 'var(--color-border-default)' }}>
68
+ {SCENARIOS.map((s) => (
69
+ <div key={s.name} className="p-4 hover:bg-white/5 transition-colors" style={{ borderColor: 'var(--color-border-default)' }}>
70
+ <div className="text-sm font-semibold text-slate-200 mb-1">{s.name}</div>
71
+ <p className="text-xs text-slate-400 mb-2">{s.description}</p>
72
+ <div className="flex flex-wrap gap-3">
73
+ <span className="text-[10px] text-slate-500">
74
+ <strong className="text-slate-400">Expected:</strong> {s.expected}
75
+ </span>
76
+ </div>
77
+ <div className="mt-1.5">
78
+ <span
79
+ className="text-[10px] font-mono px-2 py-0.5 rounded border"
80
+ style={{ background: 'rgba(34,197,94,0.1)', borderColor: 'rgba(34,197,94,0.2)', color: '#22c55e' }}
81
+ >
82
+ Target: {s.metric}
83
+ </span>
84
+ </div>
85
+ </div>
86
+ ))}
87
+ </div>
88
+ </div>
89
+ </div>
90
+ );
91
+ }
@@ -0,0 +1,99 @@
1
+ import { Icon } from '../shared/Icon';
2
+
3
+ const ENDPOINTS = [
4
+ {
5
+ method: 'PUT',
6
+ path: '/rider/trips/:tripId/booking-status',
7
+ body: '{ "booking_status": "BOOK_CONFIRMED" | "BOOK_UNCONFIRMED" | "RIDER_CANCELED" }',
8
+ description: 'Rider updates their booking status — confirm, decline, or cancel.',
9
+ },
10
+ ];
11
+
12
+ const TRANSITIONS = [
13
+ { from: 'TRIP_BOOK_PENDING', to: 'BOOK_CONFIRMED', action: 'Rider confirms the booking' },
14
+ { from: 'TRIP_BOOK_PENDING', to: 'BOOK_UNCONFIRMED', action: 'Rider declines (maps to BOOK_RIDER_CANCELED)' },
15
+ { from: 'TRIP_BOOK_PENDING', to: 'RIDER_CANCELED', action: 'Rider cancels before confirmation' },
16
+ { from: 'TRIP_BOOK_RIDER_CONFIRMED', to: 'RIDER_CANCELED', action: 'Rider cancels after confirming' },
17
+ ];
18
+
19
+ const INTEGRATION_CHECKLIST = [
20
+ 'Handle push notification with action "confirm_booking" — deep link to booking confirmation screen',
21
+ 'Handle push notification with action "booking_timeout" — show warning that confirmation window is closing',
22
+ 'Handle push notification with action "booking_cancelled" — show cancellation screen',
23
+ 'Handle push notification with action "booking_driver_assigned_rider" — show driver info',
24
+ 'Handle push notification with action "booking_driver_confirmed_rider" — show confirmed status',
25
+ 'Handle push notification with action "booking_canceled_by_driver" — show re-assignment pending',
26
+ 'Implement booking status polling or WebSocket for real-time status updates',
27
+ 'Handle HTTP 409 responses gracefully (concurrent update / invalid transition)',
28
+ 'Handle HTTP 404 for non-booked trips (is_booked: false)',
29
+ ];
30
+
31
+ export function RiderIntegrationSection() {
32
+ return (
33
+ <div className="space-y-5">
34
+ {ENDPOINTS.map((ep) => (
35
+ <div
36
+ key={ep.path}
37
+ className="rounded-xl border overflow-hidden"
38
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
39
+ >
40
+ <div className="px-4 py-3 flex items-center gap-3 border-b" style={{ borderColor: 'var(--color-border-default)' }}>
41
+ <span className="text-[10px] font-bold px-2 py-0.5 rounded" style={{ background: 'rgba(251,191,36,0.15)', color: '#fbbf24' }}>
42
+ {ep.method}
43
+ </span>
44
+ <code className="text-sm text-slate-200 font-mono">{ep.path}</code>
45
+ </div>
46
+ <div className="px-4 py-3">
47
+ <p className="text-xs text-slate-400 mb-2">{ep.description}</p>
48
+ <span className="text-[10px] uppercase tracking-wider text-slate-500 font-semibold">Request Body</span>
49
+ <pre className="mt-1 text-[11px] font-mono text-emerald-400 bg-black/30 rounded-lg px-3 py-2">{ep.body}</pre>
50
+ </div>
51
+ </div>
52
+ ))}
53
+
54
+ <div
55
+ className="rounded-xl border overflow-hidden"
56
+ style={{ borderColor: 'var(--color-border-default)', background: 'rgba(20,17,24,0.5)' }}
57
+ >
58
+ <div className="px-4 py-3 border-b" style={{ borderColor: 'var(--color-border-default)', background: 'rgba(255,255,255,0.03)' }}>
59
+ <span className="text-sm font-bold text-slate-200">Valid Rider Transitions</span>
60
+ </div>
61
+ <table className="w-full text-sm">
62
+ <thead style={{ background: 'rgba(255,255,255,0.05)' }}>
63
+ <tr>
64
+ <th className="px-4 py-2 text-left text-xs font-semibold text-slate-400">From</th>
65
+ <th className="px-4 py-2 text-center text-xs font-semibold text-slate-400"></th>
66
+ <th className="px-4 py-2 text-left text-xs font-semibold text-slate-400">To</th>
67
+ <th className="px-4 py-2 text-left text-xs font-semibold text-slate-400">Action</th>
68
+ </tr>
69
+ </thead>
70
+ <tbody>
71
+ {TRANSITIONS.map((t, i) => (
72
+ <tr key={i} className="border-t hover:bg-white/5 transition-colors" style={{ borderColor: 'var(--color-border-default)' }}>
73
+ <td className="px-4 py-2 font-mono text-[11px] text-slate-400">{t.from}</td>
74
+ <td className="px-4 py-2 text-center"><Icon name="arrow_forward" size={14} className="text-slate-600" /></td>
75
+ <td className="px-4 py-2 font-mono text-[11px] text-cyan-400">{t.to}</td>
76
+ <td className="px-4 py-2 text-xs text-slate-400">{t.action}</td>
77
+ </tr>
78
+ ))}
79
+ </tbody>
80
+ </table>
81
+ </div>
82
+
83
+ <div
84
+ className="rounded-xl border p-4"
85
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
86
+ >
87
+ <h4 className="text-sm font-bold text-slate-200 mb-3">Integration Checklist</h4>
88
+ <ul className="space-y-2">
89
+ {INTEGRATION_CHECKLIST.map((item, i) => (
90
+ <li key={i} className="flex items-start gap-2">
91
+ <Icon name="check_box_outline_blank" size={16} className="text-slate-600 mt-0.5 shrink-0" />
92
+ <span className="text-xs text-slate-400">{item}</span>
93
+ </li>
94
+ ))}
95
+ </ul>
96
+ </div>
97
+ </div>
98
+ );
99
+ }
@@ -0,0 +1,74 @@
1
+ import { Icon } from '../shared/Icon';
2
+
3
+ const SECURITY_LAYERS = [
4
+ {
5
+ layer: 'Authentication',
6
+ items: [
7
+ { control: 'JWT token validation on all endpoints', status: 'active' },
8
+ { control: 'Role-based access: rider endpoints require rider token, driver endpoints require driver token', status: 'active' },
9
+ { control: 'Trip ownership check: rider can only update their own trips', status: 'active' },
10
+ ],
11
+ },
12
+ {
13
+ layer: 'Authorization',
14
+ items: [
15
+ { control: 'VALID_RIDER_TRANSITIONS map restricts which statuses a rider can set', status: 'active' },
16
+ { control: 'VALID_DRIVER_TRANSITIONS map restricts which statuses a driver can set', status: 'active' },
17
+ { control: 'Terminal status guard prevents modifications to completed/cancelled bookings', status: 'active' },
18
+ ],
19
+ },
20
+ {
21
+ layer: 'Data Integrity',
22
+ items: [
23
+ { control: 'Optimistic locking via updateOne with booking_status guard', status: 'active' },
24
+ { control: 'booking_status_history array provides audit trail', status: 'active' },
25
+ { control: 'is_booked flag check prevents non-scheduled trips from using booking endpoints', status: 'active' },
26
+ ],
27
+ },
28
+ {
29
+ layer: 'Input Validation',
30
+ items: [
31
+ { control: 'Booking status value validated against enum (Joi/express-validator)', status: 'active' },
32
+ { control: 'Trip ID format validation (MongoDB ObjectId)', status: 'active' },
33
+ { control: 'Request body schema validation on booking status endpoints', status: 'active' },
34
+ ],
35
+ },
36
+ {
37
+ layer: 'Rate Limiting',
38
+ items: [
39
+ { control: 'API gateway rate limiting on booking endpoints', status: 'active' },
40
+ { control: 'BullMQ job deduplication prevents duplicate scheduling', status: 'active' },
41
+ { control: 'Notification throttling via sendBookingNotificationWithConfig', status: 'active' },
42
+ ],
43
+ },
44
+ ];
45
+
46
+ export function SecuritySection() {
47
+ return (
48
+ <div className="space-y-4">
49
+ {SECURITY_LAYERS.map((layer) => (
50
+ <div
51
+ key={layer.layer}
52
+ className="rounded-xl border overflow-hidden"
53
+ style={{ background: 'rgba(20,17,24,0.5)', borderColor: 'var(--color-border-default)' }}
54
+ >
55
+ <div
56
+ className="px-4 py-2.5 border-b flex items-center gap-2"
57
+ style={{ borderColor: 'var(--color-border-default)', background: 'rgba(255,255,255,0.03)' }}
58
+ >
59
+ <Icon name="shield" size={16} className="text-emerald-400" />
60
+ <span className="text-sm font-bold text-slate-200">{layer.layer}</span>
61
+ </div>
62
+ <ul className="p-3 space-y-1.5">
63
+ {layer.items.map((item) => (
64
+ <li key={item.control} className="flex items-center gap-2 px-1">
65
+ <Icon name="check_circle" size={14} className="text-emerald-400 shrink-0" />
66
+ <span className="text-xs text-slate-400">{item.control}</span>
67
+ </li>
68
+ ))}
69
+ </ul>
70
+ </div>
71
+ ))}
72
+ </div>
73
+ );
74
+ }