adserver-dashboard 1.0.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.
- package/.ci/staging.yml +191 -0
- package/.dockerignore +117 -0
- package/.env +40 -0
- package/.env.staging +38 -0
- package/.gitlab-ci.yml +16 -0
- package/DEMO_STATUS.md +579 -0
- package/Dockerfile +61 -0
- package/Influence-MW-AdServer-12-02-2026/client/index.html +17 -0
- package/Influence-MW-AdServer-12-02-2026/client/public/favicon.png +0 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/App.tsx +91 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/advanced-map-drawer.tsx +1131 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ai-recommendation-panel.tsx +379 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/app-sidebar.tsx +183 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/auto-optimize-button.tsx +184 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/availability-drawer.tsx +385 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/brand-insights-panel.tsx +87 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/create-agency-drawer.tsx +198 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/create-brand-drawer.tsx +275 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/creative-assignment.tsx +526 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/data-table-toolbar.tsx +148 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/data-table.tsx +158 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/filter-drawer.tsx +356 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/form-insights-panel.tsx +82 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/geography-selector.tsx +699 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/header-user-menu.tsx +178 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/history-drawer.tsx +313 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/inventory-availability-section.tsx +176 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/inventory-format-drawer.tsx +173 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/inventory-selector.tsx +401 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/manual-inventory-drawer.tsx +368 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/mapbox-map.tsx +368 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/market-insights-panel.tsx +202 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/media-owner-drawer.tsx +217 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/metric-card.tsx +58 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/page-header.tsx +27 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/player-status-indicator.tsx +137 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/poi-targeting-drawer.tsx +298 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/recommendation-score-badge.tsx +102 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/recommended-inventories-panel.tsx +248 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/searchable-combobox.tsx +134 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/signal-visualizations.tsx +407 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/status-badge.tsx +35 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/theme-provider.tsx +73 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/theme-toggle.tsx +37 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/traffic-slider.tsx +75 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/accordion.tsx +56 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/alert-dialog.tsx +139 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/alert.tsx +59 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/aspect-ratio.tsx +5 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/avatar.tsx +51 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/badge.tsx +38 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/breadcrumb.tsx +115 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/button.tsx +62 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/calendar.tsx +68 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/card.tsx +85 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/carousel.tsx +260 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/chart.tsx +365 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/checkbox.tsx +28 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/collapsible.tsx +11 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/command.tsx +151 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/context-menu.tsx +198 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/dialog.tsx +122 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/drawer.tsx +118 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/dropdown-menu.tsx +198 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/form.tsx +178 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/hover-card.tsx +29 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/input-otp.tsx +69 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/input.tsx +23 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/label.tsx +24 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/menubar.tsx +256 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/navigation-menu.tsx +128 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/pagination.tsx +117 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/popover.tsx +29 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/progress.tsx +28 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/radio-group.tsx +42 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/resizable.tsx +45 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/scroll-area.tsx +46 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/select.tsx +160 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/separator.tsx +29 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/sheet.tsx +140 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/sidebar.tsx +727 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/skeleton.tsx +15 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/slider.tsx +26 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/switch.tsx +27 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/table.tsx +117 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/tabs.tsx +53 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/textarea.tsx +22 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toast.tsx +127 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toaster.tsx +33 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toggle-group.tsx +61 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toggle.tsx +43 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/tooltip.tsx +30 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/vendor-stores-modal.tsx +336 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/venue-type-drawer.tsx +359 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/components/venue-type-selector.tsx +436 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/hooks/use-mobile.tsx +19 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/hooks/use-toast.ts +191 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/index.css +244 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/lib/queryClient.ts +57 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/lib/utils.ts +39 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/lib/venue-taxonomy.ts +532 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/main.tsx +5 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/assign-creative.tsx +781 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/content-hub.tsx +995 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/custom-pois.tsx +431 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/dashboard.tsx +620 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/deal-detail.tsx +1062 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/deal-form.tsx +1570 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/deals.tsx +716 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/edit-creative-assignment.tsx +1051 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/geotargeting.tsx +675 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/integrations.tsx +425 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/line-item-creatives.tsx +622 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/line-item-form.tsx +3132 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/line-items.tsx +530 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/not-found.tsx +21 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/proof-of-play-upload.tsx +479 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/proof-of-play.tsx +880 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/reports.tsx +235 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/settings.tsx +652 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/signal-form.tsx +1117 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/signals.tsx +366 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/tags.tsx +332 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/pages/venues.tsx +381 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/types/mapbox-gl-draw.d.ts +37 -0
- package/Influence-MW-AdServer-12-02-2026/client/src/types/react-simple-maps.d.ts +57 -0
- package/Influence-MW-AdServer-12-02-2026/components.json +20 -0
- package/Influence-MW-AdServer-12-02-2026/docs/PRD.md +3373 -0
- package/Influence-MW-AdServer-12-02-2026/docs/influence-feature-mapping.csv +498 -0
- package/Influence-MW-AdServer-12-02-2026/drizzle.config.ts +14 -0
- package/Influence-MW-AdServer-12-02-2026/package-lock.json +9672 -0
- package/Influence-MW-AdServer-12-02-2026/package.json +118 -0
- package/Influence-MW-AdServer-12-02-2026/postcss.config.js +6 -0
- package/Influence-MW-AdServer-12-02-2026/replit.md +91 -0
- package/Influence-MW-AdServer-12-02-2026/script/build.ts +67 -0
- package/Influence-MW-AdServer-12-02-2026/scripts/create-miro-diagrams.cjs +318 -0
- package/Influence-MW-AdServer-12-02-2026/scripts/create-remaining-diagrams.cjs +270 -0
- package/Influence-MW-AdServer-12-02-2026/server/index.ts +103 -0
- package/Influence-MW-AdServer-12-02-2026/server/recommendation-service.ts +319 -0
- package/Influence-MW-AdServer-12-02-2026/server/routes.ts +1890 -0
- package/Influence-MW-AdServer-12-02-2026/server/static.ts +19 -0
- package/Influence-MW-AdServer-12-02-2026/server/storage.ts +2058 -0
- package/Influence-MW-AdServer-12-02-2026/server/vite.ts +58 -0
- package/Influence-MW-AdServer-12-02-2026/shared/schema.ts +1595 -0
- package/Influence-MW-AdServer-12-02-2026/tailwind.config.ts +107 -0
- package/Influence-MW-AdServer-12-02-2026/tsconfig.json +23 -0
- package/Influence-MW-AdServer-12-02-2026/vite.config.ts +40 -0
- package/LINE_ITEM_BUDGET_FIELD_MAPPING.md +178 -0
- package/PCM/.env.example +92 -0
- package/PCM/README.md +558 -0
- package/PCM/docs/TEST_CASES.md +422 -0
- package/PCM/index.js +106 -0
- package/PCM/package-lock.json +3282 -0
- package/PCM/package.json +32 -0
- package/PCM/replit.md +64 -0
- package/PCM/schema.sql +495 -0
- package/PCM/scripts/export-schema.js +183 -0
- package/PCM/scripts/seed-comprehensive.js +631 -0
- package/PCM/scripts/seed-production.js +477 -0
- package/PCM/src/config/db.js +56 -0
- package/PCM/src/config/swagger.js +5975 -0
- package/PCM/src/dto/EmailRequestDTO.js +166 -0
- package/PCM/src/middleware/errorHandler.js +52 -0
- package/PCM/src/middleware/logger.js +26 -0
- package/PCM/src/migrations/001_add_campaign_mode_fields.sql +36 -0
- package/PCM/src/migrations/002_create_deal_id_counters.sql +22 -0
- package/PCM/src/migrations/003_update_publishers_column.sql +15 -0
- package/PCM/src/migrations/004_add_direct_dealtype_and_advertiser.sql +5 -0
- package/PCM/src/migrations/005_add_programmatic_fields_and_update_enums.sql +31 -0
- package/PCM/src/migrations/006_add_line_item_programmatic_fields.sql +12 -0
- package/PCM/src/migrations/007_add_line_item_direct_fields.sql +15 -0
- package/PCM/src/migrations/008_add_inventory_fields.sql +45 -0
- package/PCM/src/migrations/009_move_inventory_fields_to_metadata.sql +32 -0
- package/PCM/src/migrations/010_add_draft_status_and_line_items_count.sql +23 -0
- package/PCM/src/migrations/011_add_planning_field.sql +21 -0
- package/PCM/src/migrations/012_fix_inventory_composite_pk.sql +17 -0
- package/PCM/src/migrations/013_make_external_id_optional.sql +3 -0
- package/PCM/src/migrations/014_create_change_history.sql +38 -0
- package/PCM/src/migrations/016_create_publisher_insertion_orders.sql +33 -0
- package/PCM/src/migrations/017_fix_line_item_id_fk_reference.sql +86 -0
- package/PCM/src/migrations/018_create_approval_tables.sql +44 -0
- package/PCM/src/migrations/019_add_encrypted_token_column.sql +2 -0
- package/PCM/src/migrations/020_add_rejection_reason_to_deals.sql +10 -0
- package/PCM/src/migrations/021_add_publisher_external_id_to_inventories.sql +12 -0
- package/PCM/src/migrations/022_add_line_item_extended_fields.sql +24 -0
- package/PCM/src/migrations/023_add_base_price_fields.sql +8 -0
- package/PCM/src/migrations/run-migrations.js +46 -0
- package/PCM/src/models/ApprovalOTP.js +51 -0
- package/PCM/src/models/ApprovalToken.js +79 -0
- package/PCM/src/models/ChangeHistory.js +107 -0
- package/PCM/src/models/Deal.js +186 -0
- package/PCM/src/models/DealIdCounter.js +28 -0
- package/PCM/src/models/LineItem.js +227 -0
- package/PCM/src/models/LineItemCreative.js +89 -0
- package/PCM/src/models/LineItemInventory.js +115 -0
- package/PCM/src/models/PublisherInsertionOrder.js +93 -0
- package/PCM/src/models/TransactionHistory.js +34 -0
- package/PCM/src/models/associations.js +81 -0
- package/PCM/src/routes/approval.js +321 -0
- package/PCM/src/routes/creatives.js +437 -0
- package/PCM/src/routes/deals.js +1638 -0
- package/PCM/src/routes/digitalSignage.js +242 -0
- package/PCM/src/routes/insertionOrders.js +380 -0
- package/PCM/src/routes/lineItems.js +926 -0
- package/PCM/src/routes/system.js +384 -0
- package/PCM/src/services/ApprovalService.js +885 -0
- package/PCM/src/services/CampaignImportConverter.js +631 -0
- package/PCM/src/services/CampaignModeService.js +273 -0
- package/PCM/src/services/CampaignStatusService.js +395 -0
- package/PCM/src/services/ChangeHistoryService.js +316 -0
- package/PCM/src/services/DealIdService.js +94 -0
- package/PCM/src/services/DealResponseFormatter.js +90 -0
- package/PCM/src/services/EmailNotificationService.js +315 -0
- package/PCM/src/services/LineItemResponseFormatter.js +122 -0
- package/PCM/src/services/LineItemStatusService.js +380 -0
- package/PCM/src/tests/comprehensiveTestRunner.js +360 -0
- package/PCM/src/tests/comprehensiveTests.js +1277 -0
- package/PCM/src/tests/dealTypeUnitTests.js +1058 -0
- package/PCM/src/tests/testRunner.js +248 -0
- package/PCM/src/utils/caseConverter.js +92 -0
- package/PCM/src/utils/dealCalculations.js +206 -0
- package/PCM/src/utils/lineItemPayloadNormalizer.js +41 -0
- package/PCM/src/utils/payloadNormalizer.js +34 -0
- package/PCM/src/utils/sourceNormalizer.js +56 -0
- package/PCM/src/validators/creativeValidator.js +27 -0
- package/PCM/src/validators/dealValidator.js +203 -0
- package/PCM/src/validators/lineItemValidator.js +489 -0
- package/PCM/tests/approval-flows.test.js +238 -0
- package/PCM/tests/approval-workflow.test.js +291 -0
- package/PCM/tests/campaign-import-converter.test.js +543 -0
- package/PCM/tests/campaign-import-e2e.test.js +520 -0
- package/PCM/tests/campaign-status.test.js +539 -0
- package/PCM/tests/direct-publisher-split-reimport.test.js +460 -0
- package/PCM/tests/e2e/digital-signage.test.js +145 -0
- package/PCM/tests/e2e/search-filter-pagination.test.js +399 -0
- package/PCM/tests/e2e-comprehensive.test.js +3446 -0
- package/PCM/tests/edge-cases.test.js +340 -0
- package/PCM/tests/line-item-status.test.js +340 -0
- package/PCM/tests/seller-account-external-ids.test.js +877 -0
- package/PCM/tests/source-validation.test.js +324 -0
- package/PRD.md +3373 -0
- package/README.md +186 -0
- package/client/index.html +35 -0
- package/client/public/DEMO_STATUS.md +579 -0
- package/client/public/img/MW-logo-trans_1754045676555.png +0 -0
- package/client/public/locales/ar/approval.json +144 -0
- package/client/public/locales/ar/buyer.json +61 -0
- package/client/public/locales/ar/campaigns.json +1 -0
- package/client/public/locales/ar/common.json +218 -0
- package/client/public/locales/ar/contentHub.json +266 -0
- package/client/public/locales/ar/creatives.json +79 -0
- package/client/public/locales/ar/dashboard.json +57 -0
- package/client/public/locales/ar/deals.json +886 -0
- package/client/public/locales/ar/dsp.json +131 -0
- package/client/public/locales/ar/inventory.json +201 -0
- package/client/public/locales/ar/lineItems.json +553 -0
- package/client/public/locales/ar/navigation.json +48 -0
- package/client/public/locales/ar/wizard.json +1 -0
- package/client/public/locales/en/approval.json +144 -0
- package/client/public/locales/en/buyer.json +65 -0
- package/client/public/locales/en/campaigns.json +1 -0
- package/client/public/locales/en/common.json +218 -0
- package/client/public/locales/en/contentHub.json +266 -0
- package/client/public/locales/en/creatives.json +79 -0
- package/client/public/locales/en/dashboard.json +57 -0
- package/client/public/locales/en/deals.json +886 -0
- package/client/public/locales/en/dsp.json +131 -0
- package/client/public/locales/en/inventory.json +201 -0
- package/client/public/locales/en/lineItems.json +659 -0
- package/client/public/locales/en/navigation.json +48 -0
- package/client/public/locales/en/wizard.json +1 -0
- package/client/public/locales/ja/approval.json +144 -0
- package/client/public/locales/ja/buyer.json +61 -0
- package/client/public/locales/ja/campaigns.json +1 -0
- package/client/public/locales/ja/common.json +218 -0
- package/client/public/locales/ja/contentHub.json +266 -0
- package/client/public/locales/ja/creatives.json +79 -0
- package/client/public/locales/ja/dashboard.json +57 -0
- package/client/public/locales/ja/deals.json +886 -0
- package/client/public/locales/ja/dsp.json +131 -0
- package/client/public/locales/ja/inventory.json +201 -0
- package/client/public/locales/ja/lineItems.json +553 -0
- package/client/public/locales/ja/navigation.json +48 -0
- package/client/public/locales/ja/wizard.json +1 -0
- package/client/public/locales/zh/approval.json +144 -0
- package/client/public/locales/zh/buyer.json +61 -0
- package/client/public/locales/zh/campaigns.json +1 -0
- package/client/public/locales/zh/common.json +218 -0
- package/client/public/locales/zh/contentHub.json +266 -0
- package/client/public/locales/zh/creatives.json +79 -0
- package/client/public/locales/zh/dashboard.json +57 -0
- package/client/public/locales/zh/deals.json +886 -0
- package/client/public/locales/zh/dsp.json +131 -0
- package/client/public/locales/zh/inventory.json +201 -0
- package/client/public/locales/zh/lineItems.json +553 -0
- package/client/public/locales/zh/navigation.json +48 -0
- package/client/public/locales/zh/wizard.json +1 -0
- package/client/public/manifest.json +36 -0
- package/client/src/App.tsx +464 -0
- package/client/src/components/app-sidebar.tsx +312 -0
- package/client/src/components/approval/approval-decision-form.test.tsx +294 -0
- package/client/src/components/approval/approval-decision-form.tsx +326 -0
- package/client/src/components/approval/approval-sheet.tsx +631 -0
- package/client/src/components/approval/line-item-details-sheet.tsx +371 -0
- package/client/src/components/approval/otp-verification.test.tsx +337 -0
- package/client/src/components/approval/otp-verification.tsx +180 -0
- package/client/src/components/content-hub/bulk-transcode-dialog.tsx +379 -0
- package/client/src/components/content-hub/content-hub-manager-v2.tsx +574 -0
- package/client/src/components/content-hub/content-hub-manager.tsx +330 -0
- package/client/src/components/content-hub/creative-card.tsx +456 -0
- package/client/src/components/content-hub/creative-detail-sheet.tsx +685 -0
- package/client/src/components/content-hub/creative-filters.tsx +457 -0
- package/client/src/components/content-hub/creative-grid.tsx +329 -0
- package/client/src/components/content-hub/creative-selector.tsx +415 -0
- package/client/src/components/content-hub/creative-upload.tsx +547 -0
- package/client/src/components/content-hub/folder-dialogs.tsx +445 -0
- package/client/src/components/content-hub/folder-list.tsx +280 -0
- package/client/src/components/content-hub/review-dialogs.tsx +268 -0
- package/client/src/components/content-hub/transcode-dialog.tsx +226 -0
- package/client/src/components/creative-library/creative-details-view.tsx +446 -0
- package/client/src/components/creative-library/creative-filters-panel.tsx +203 -0
- package/client/src/components/creative-library/creative-list.tsx +360 -0
- package/client/src/components/creative-library/creative-status-badge.tsx +71 -0
- package/client/src/components/creative-library/folder-card.tsx +78 -0
- package/client/src/components/creative-library/index.ts +27 -0
- package/client/src/components/creative-library/new-creative-card.tsx +211 -0
- package/client/src/components/creative-library/upload-creative-dialog.tsx +261 -0
- package/client/src/components/dashboard-overview.tsx +109 -0
- package/client/src/components/deals/approval-history-panel.test.tsx +240 -0
- package/client/src/components/deals/approval-history-panel.tsx +156 -0
- package/client/src/components/deals/deal-status-badge.tsx +92 -0
- package/client/src/components/deals/import-from-planner-dialog.tsx +399 -0
- package/client/src/components/deals/market-insights-panel.tsx +237 -0
- package/client/src/components/deals/reopen-deal-sheet.tsx +191 -0
- package/client/src/components/deals/request-approval-sheet.test.tsx +323 -0
- package/client/src/components/deals/request-approval-sheet.tsx +136 -0
- package/client/src/components/deals/resend-approval-sheet.tsx +201 -0
- package/client/src/components/direct-campaigns/campaign-card.tsx +283 -0
- package/client/src/components/direct-campaigns/deal-filter-panel.tsx +325 -0
- package/client/src/components/inventory/advanced-filters-panel.tsx +273 -0
- package/client/src/components/inventory/csv-upload-modal.tsx +639 -0
- package/client/src/components/inventory/inventory-availability-view.tsx +486 -0
- package/client/src/components/inventory/inventory-details-sheet.tsx +376 -0
- package/client/src/components/inventory/inventory-map-view.tsx +596 -0
- package/client/src/components/inventory/inventory-settings-menu.tsx +52 -0
- package/client/src/components/language-switcher.tsx +53 -0
- package/client/src/components/line-items/campaign-forecast-panel.tsx +138 -0
- package/client/src/components/line-items/form-insights.tsx +89 -0
- package/client/src/components/line-items/geofencing/LocationCsvUploadDrawer.tsx +100 -0
- package/client/src/components/line-items/geofencing/POIDropdown.tsx +379 -0
- package/client/src/components/line-items/geofencing/SelectedLocationsSidebar.tsx +436 -0
- package/client/src/components/line-items/geofencing/ViewFileLocationDrawer.tsx +199 -0
- package/client/src/components/line-items/geofencing/components/ExistingFilesTab.tsx +268 -0
- package/client/src/components/line-items/geofencing/components/TemplateDownloadSection.tsx +59 -0
- package/client/src/components/line-items/geofencing/components/UploadTab.tsx +215 -0
- package/client/src/components/line-items/geofencing-map.tsx +1270 -0
- package/client/src/components/line-items/inventory-availability-section.tsx +178 -0
- package/client/src/components/line-items/line-item-schedule-manager.tsx +313 -0
- package/client/src/components/line-items/manual-inventory-drawer.tsx +346 -0
- package/client/src/components/line-items/planner-inventory-card.tsx +495 -0
- package/client/src/components/line-items/planner-schedule-grid.tsx +495 -0
- package/client/src/components/line-items/schedule-rule-editor.tsx +649 -0
- package/client/src/components/line-items/schedule-rule-types.ts +122 -0
- package/client/src/components/line-items/steps/creatives-step.tsx +681 -0
- package/client/src/components/line-items/steps/inventory-schedule-step.tsx +1596 -0
- package/client/src/components/line-items/steps/inventory-step.tsx +1533 -0
- package/client/src/components/line-items/steps/line-item-details-step.tsx +916 -0
- package/client/src/components/line-items/steps/schedule-step.tsx +273 -0
- package/client/src/components/line-items/steps/summary-step.tsx +680 -0
- package/client/src/components/line-items/steps/targeting-step.tsx +1708 -0
- package/client/src/components/product-switcher.tsx +105 -0
- package/client/src/components/protected-route.tsx +49 -0
- package/client/src/components/skip-link.tsx +22 -0
- package/client/src/components/stat-card.tsx +53 -0
- package/client/src/components/status-badge.tsx +96 -0
- package/client/src/components/ui/hierarchical-venue-selector.tsx +389 -0
- package/client/src/components/ui/toaster.tsx +111 -0
- package/client/src/contexts/auth-context.tsx +181 -0
- package/client/src/contexts/sidebar-state.tsx +50 -0
- package/client/src/contexts/theme-context.tsx +66 -0
- package/client/src/data/campaign-data.json +107 -0
- package/client/src/data/countries.json +22 -0
- package/client/src/hooks/use-approval.ts +366 -0
- package/client/src/hooks/use-keyboard-shortcuts.ts +74 -0
- package/client/src/hooks/use-media-query.ts +46 -0
- package/client/src/hooks/use-mobile.tsx +19 -0
- package/client/src/hooks/use-page-title.ts +21 -0
- package/client/src/hooks/use-toast.ts +195 -0
- package/client/src/index.css +694 -0
- package/client/src/lib/__tests__/accessibility.test.ts +104 -0
- package/client/src/lib/__tests__/date-utils.test.ts +199 -0
- package/client/src/lib/__tests__/dsp-buyer-api.test.ts +127 -0
- package/client/src/lib/__tests__/dsp-buyer-integration.test.ts +247 -0
- package/client/src/lib/__tests__/storage-utils.test.ts +167 -0
- package/client/src/lib/__tests__/utils.test.ts +57 -0
- package/client/src/lib/accessibility.ts +141 -0
- package/client/src/lib/api-config.ts +9 -0
- package/client/src/lib/auth-service.ts +209 -0
- package/client/src/lib/campaign-creative-api.ts +82 -0
- package/client/src/lib/company-api.ts +61 -0
- package/client/src/lib/content-hub-api.ts +407 -0
- package/client/src/lib/creative-mapper.ts +61 -0
- package/client/src/lib/date-utils.ts +119 -0
- package/client/src/lib/deal-helpers.ts +220 -0
- package/client/src/lib/dsp-buyer-api.ts +196 -0
- package/client/src/lib/geo-import-api.ts +151 -0
- package/client/src/lib/google-poi-api.ts +305 -0
- package/client/src/lib/i18n/__tests__/formatting.test.ts +202 -0
- package/client/src/lib/i18n/formatting.ts +130 -0
- package/client/src/lib/i18n/index.ts +8 -0
- package/client/src/lib/i18n-compat.ts +76 -0
- package/client/src/lib/influence-deals-api.ts +896 -0
- package/client/src/lib/inventory-api.ts +399 -0
- package/client/src/lib/oauth-service.ts +678 -0
- package/client/src/lib/poi-types.ts +75 -0
- package/client/src/lib/queryClient.ts +144 -0
- package/client/src/lib/recommendation-api.ts +380 -0
- package/client/src/lib/storage-utils.ts +104 -0
- package/client/src/lib/tolgee.ts +85 -0
- package/client/src/lib/utils.ts +0 -0
- package/client/src/main.tsx +67 -0
- package/client/src/mapbox-draw-modes.d.ts +32 -0
- package/client/src/pages/all-folders.tsx +203 -0
- package/client/src/pages/auth-callback.tsx +115 -0
- package/client/src/pages/buyer-form.tsx +339 -0
- package/client/src/pages/buyer-list.tsx +622 -0
- package/client/src/pages/content-hub.tsx +1358 -0
- package/client/src/pages/create-deal.tsx +2093 -0
- package/client/src/pages/creative-assignment-page.tsx +548 -0
- package/client/src/pages/creatives.tsx +5 -0
- package/client/src/pages/custom-pois.tsx +425 -0
- package/client/src/pages/dashboard.tsx +615 -0
- package/client/src/pages/deal-history.tsx +434 -0
- package/client/src/pages/deal-line-items.tsx +1703 -0
- package/client/src/pages/demo-status.tsx +113 -0
- package/client/src/pages/direct-campaign-details.tsx +361 -0
- package/client/src/pages/direct-campaigns-new.tsx +824 -0
- package/client/src/pages/dsp-form.tsx +803 -0
- package/client/src/pages/dsp-list.tsx +239 -0
- package/client/src/pages/folder-content.tsx +336 -0
- package/client/src/pages/integrations.tsx +429 -0
- package/client/src/pages/line-item-creatives.tsx +789 -0
- package/client/src/pages/line-item-detail-page.tsx +684 -0
- package/client/src/pages/line-item-form-page.tsx +3261 -0
- package/client/src/pages/line-item-wizard.tsx +1207 -0
- package/client/src/pages/login.tsx +154 -0
- package/client/src/pages/not-found.tsx +23 -0
- package/client/src/pages/proof-of-play.tsx +397 -0
- package/client/src/pages/public-approval.tsx +551 -0
- package/client/src/pages/reports.tsx +231 -0
- package/client/src/pages/settings.tsx +760 -0
- package/client/src/pages/signals.tsx +389 -0
- package/client/src/pages/tags.tsx +318 -0
- package/client/src/pages/test-results.tsx +328 -0
- package/client/src/store/hooks.ts +5 -0
- package/client/src/store/index.ts +15 -0
- package/client/src/store/mapMarkerLocationsSlice.ts +241 -0
- package/client/src/styles/design-tokens.css +324 -0
- package/client/src/test/setup.ts +261 -0
- package/client/src/test/test-utils.tsx +40 -0
- package/client/src/types/approval.ts +221 -0
- package/client/src/types/content-hub.ts +209 -0
- package/client/src/types/geofencing.ts +67 -0
- package/client/src/types/transcoding.ts +140 -0
- package/client/src/vite-env.d.ts +18 -0
- package/components.json +20 -0
- package/creative-api.json +1 -0
- package/docs/AI_REFERENCE.md +459 -0
- package/docs/MWDesign-Prompt.md +132 -0
- package/docs/MWDesign-System.md +344 -0
- package/docs/test-plan.md +277 -0
- package/e2e/AUTONOMOUS-TESTING.md +406 -0
- package/e2e/README.md +219 -0
- package/e2e/autonomous-flow.spec.ts +308 -0
- package/e2e/debug-sso.spec.ts +163 -0
- package/e2e/direct-campaigns.spec.ts +219 -0
- package/e2e/explore-sso.spec.ts +149 -0
- package/e2e/fixtures/auth.ts +26 -0
- package/e2e/fixtures/enhanced-test.ts +331 -0
- package/e2e/pagination.spec.ts +280 -0
- package/e2e/view-toggle.spec.ts +312 -0
- package/generated-icon.png +0 -0
- package/i18next-scanner.config.cjs +46 -0
- package/package.json +141 -0
- package/playwright.config.ts +93 -0
- package/postcss.config.js +6 -0
- package/replit.md +196 -0
- package/screenshot-after-login.png +0 -0
- package/screenshot-contenthub-grid.png +0 -0
- package/screenshot-contenthub-list-fixed.png +0 -0
- package/screenshot-contenthub-list.png +0 -0
- package/screenshot-create-deal.png +0 -0
- package/screenshot-dashboard.png +0 -0
- package/screenshot-deals.png +0 -0
- package/screenshot-login-filled.png +0 -0
- package/screenshot-login.png +0 -0
- package/screenshot.mjs +24 -0
- package/scripts/deploy-stg.sh +185 -0
- package/shared/direct-io-schema.ts +383 -0
- package/shared/schema.ts +439 -0
- package/shared/screen-types.ts +149 -0
- package/springdocDefault.json +1 -0
- package/swagger-ui-bundle.js +2 -0
- package/swagger-ui-init.js +10316 -0
- package/tailwind.config.ts +282 -0
- package/terraform/README.md +306 -0
- package/terraform/cloudfront.tf +289 -0
- package/terraform/ecs.tf +727 -0
- package/terraform/environments/dev.tfvars +59 -0
- package/terraform/environments/production.tfvars +60 -0
- package/terraform/main.tf +47 -0
- package/terraform/outputs.tf +145 -0
- package/terraform/s3.tf +192 -0
- package/terraform/variables.tf +226 -0
- package/terraform/waf.tf +165 -0
- package/terraform-frontend/.terraform.lock.hcl +25 -0
- package/terraform-frontend/README.md +85 -0
- package/terraform-frontend/cloudfront.tf +125 -0
- package/terraform-frontend/main.tf +31 -0
- package/terraform-frontend/outputs.tf +24 -0
- package/terraform-frontend/terraform.tfvars +12 -0
- package/terraform-frontend/variables.tf +53 -0
- package/tsconfig.json +23 -0
- package/vite.config.ts +226 -0
- package/vitest.config.ts +56 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rest-express",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "NODE_ENV=development tsx server/index.ts",
|
|
8
|
+
"build": "tsx script/build.ts",
|
|
9
|
+
"start": "NODE_ENV=production node dist/index.cjs",
|
|
10
|
+
"check": "tsc",
|
|
11
|
+
"db:push": "drizzle-kit push"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@hookform/resolvers": "^3.10.0",
|
|
15
|
+
"@jridgewell/trace-mapping": "^0.3.25",
|
|
16
|
+
"@mapbox/mapbox-gl-draw": "^1.5.1",
|
|
17
|
+
"@radix-ui/react-accordion": "^1.2.4",
|
|
18
|
+
"@radix-ui/react-alert-dialog": "^1.1.7",
|
|
19
|
+
"@radix-ui/react-aspect-ratio": "^1.1.3",
|
|
20
|
+
"@radix-ui/react-avatar": "^1.1.4",
|
|
21
|
+
"@radix-ui/react-checkbox": "^1.1.5",
|
|
22
|
+
"@radix-ui/react-collapsible": "^1.1.4",
|
|
23
|
+
"@radix-ui/react-context-menu": "^2.2.7",
|
|
24
|
+
"@radix-ui/react-dialog": "^1.1.7",
|
|
25
|
+
"@radix-ui/react-dropdown-menu": "^2.1.7",
|
|
26
|
+
"@radix-ui/react-hover-card": "^1.1.7",
|
|
27
|
+
"@radix-ui/react-label": "^2.1.3",
|
|
28
|
+
"@radix-ui/react-menubar": "^1.1.7",
|
|
29
|
+
"@radix-ui/react-navigation-menu": "^1.2.6",
|
|
30
|
+
"@radix-ui/react-popover": "^1.1.7",
|
|
31
|
+
"@radix-ui/react-progress": "^1.1.3",
|
|
32
|
+
"@radix-ui/react-radio-group": "^1.2.4",
|
|
33
|
+
"@radix-ui/react-scroll-area": "^1.2.4",
|
|
34
|
+
"@radix-ui/react-select": "^2.1.7",
|
|
35
|
+
"@radix-ui/react-separator": "^1.1.3",
|
|
36
|
+
"@radix-ui/react-slider": "^1.2.4",
|
|
37
|
+
"@radix-ui/react-slot": "^1.2.0",
|
|
38
|
+
"@radix-ui/react-switch": "^1.1.4",
|
|
39
|
+
"@radix-ui/react-tabs": "^1.1.4",
|
|
40
|
+
"@radix-ui/react-toast": "^1.2.7",
|
|
41
|
+
"@radix-ui/react-toggle": "^1.1.3",
|
|
42
|
+
"@radix-ui/react-toggle-group": "^1.1.3",
|
|
43
|
+
"@radix-ui/react-tooltip": "^1.2.0",
|
|
44
|
+
"@tanstack/react-query": "^5.60.5",
|
|
45
|
+
"@types/archiver": "^7.0.0",
|
|
46
|
+
"@types/mapbox__mapbox-gl-draw": "^1.4.9",
|
|
47
|
+
"@types/mapbox-gl": "^3.4.1",
|
|
48
|
+
"archiver": "^7.0.1",
|
|
49
|
+
"class-variance-authority": "^0.7.1",
|
|
50
|
+
"clsx": "^2.1.1",
|
|
51
|
+
"cmdk": "^1.1.1",
|
|
52
|
+
"connect-pg-simple": "^10.0.0",
|
|
53
|
+
"date-fns": "^3.6.0",
|
|
54
|
+
"drizzle-orm": "^0.39.3",
|
|
55
|
+
"drizzle-zod": "^0.7.0",
|
|
56
|
+
"embla-carousel-react": "^8.6.0",
|
|
57
|
+
"express": "^5.0.1",
|
|
58
|
+
"express-session": "^1.18.1",
|
|
59
|
+
"framer-motion": "^11.13.1",
|
|
60
|
+
"input-otp": "^1.4.2",
|
|
61
|
+
"lucide-react": "^0.453.0",
|
|
62
|
+
"mapbox-gl": "^3.18.1",
|
|
63
|
+
"memorystore": "^1.6.7",
|
|
64
|
+
"next-themes": "^0.4.6",
|
|
65
|
+
"passport": "^0.7.0",
|
|
66
|
+
"passport-local": "^1.0.0",
|
|
67
|
+
"pg": "^8.16.3",
|
|
68
|
+
"react": "^18.3.1",
|
|
69
|
+
"react-day-picker": "^8.10.1",
|
|
70
|
+
"react-dom": "^18.3.1",
|
|
71
|
+
"react-hook-form": "^7.55.0",
|
|
72
|
+
"react-icons": "^5.4.0",
|
|
73
|
+
"react-resizable-panels": "^2.1.7",
|
|
74
|
+
"react-simple-maps": "^3.0.0",
|
|
75
|
+
"recharts": "^2.15.2",
|
|
76
|
+
"tailwind-merge": "^2.6.0",
|
|
77
|
+
"tailwindcss-animate": "^1.0.7",
|
|
78
|
+
"tw-animate-css": "^1.2.5",
|
|
79
|
+
"vaul": "^1.1.2",
|
|
80
|
+
"wouter": "^3.3.5",
|
|
81
|
+
"ws": "^8.18.0",
|
|
82
|
+
"zod": "^3.24.2",
|
|
83
|
+
"zod-validation-error": "^3.4.0"
|
|
84
|
+
},
|
|
85
|
+
"devDependencies": {
|
|
86
|
+
"@replit/vite-plugin-cartographer": "^0.4.4",
|
|
87
|
+
"@replit/vite-plugin-dev-banner": "^0.1.1",
|
|
88
|
+
"@replit/vite-plugin-runtime-error-modal": "^0.0.3",
|
|
89
|
+
"@tailwindcss/typography": "^0.5.15",
|
|
90
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
91
|
+
"@types/connect-pg-simple": "^7.0.3",
|
|
92
|
+
"@types/express": "^5.0.0",
|
|
93
|
+
"@types/express-session": "^1.18.0",
|
|
94
|
+
"@types/node": "20.19.27",
|
|
95
|
+
"@types/passport": "^1.0.16",
|
|
96
|
+
"@types/passport-local": "^1.0.38",
|
|
97
|
+
"@types/react": "^18.3.11",
|
|
98
|
+
"@types/react-dom": "^18.3.1",
|
|
99
|
+
"@types/ws": "^8.5.13",
|
|
100
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
101
|
+
"autoprefixer": "^10.4.20",
|
|
102
|
+
"drizzle-kit": "^0.31.8",
|
|
103
|
+
"esbuild": "^0.25.0",
|
|
104
|
+
"postcss": "^8.4.47",
|
|
105
|
+
"tailwindcss": "^3.4.17",
|
|
106
|
+
"tsx": "^4.20.5",
|
|
107
|
+
"typescript": "5.6.3",
|
|
108
|
+
"vite": "^7.3.0"
|
|
109
|
+
},
|
|
110
|
+
"overrides": {
|
|
111
|
+
"drizzle-kit": {
|
|
112
|
+
"@esbuild-kit/esm-loader": "npm:tsx@^4.20.4"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"optionalDependencies": {
|
|
116
|
+
"bufferutil": "^4.0.8"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Influence - DOOH Adserver Platform
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Influence is a comprehensive Digital Out-of-Home (DOOH) adserver platform designed to manage advertising deals across digital screen networks. It integrates traditional direct-sold deals with programmatic capabilities through its built-in SSP and external integrations. The platform aims to provide a robust solution for advertisers and media owners to manage, deliver, and analyze DOOH advertising, enhancing market potential through efficient ad delivery and detailed analytics. Key capabilities include a four-level hierarchy for deal and line item management, various deal types, single-level traffic allocation, tiered creative approval workflows, and detailed performance reporting.
|
|
6
|
+
|
|
7
|
+
## User Preferences
|
|
8
|
+
|
|
9
|
+
- **PRD documentation style**: Physics textbook approach with paragraphs, narratives, examples
|
|
10
|
+
- Document structure mirrors application structure
|
|
11
|
+
- Keep documentation updated with code changes
|
|
12
|
+
|
|
13
|
+
## System Architecture
|
|
14
|
+
|
|
15
|
+
**Frontend:**
|
|
16
|
+
- **Framework**: React 18 with TypeScript, Wouter for routing, TanStack Query for state management.
|
|
17
|
+
- **UI Components**: Shadcn/UI with Radix primitives, Tailwind CSS for styling.
|
|
18
|
+
- **Forms**: React Hook Form with Zod validation.
|
|
19
|
+
|
|
20
|
+
**Backend:**
|
|
21
|
+
- **Runtime**: Node.js with Express.
|
|
22
|
+
- **Storage**: In-memory (MemStorage class).
|
|
23
|
+
- **API**: RESTful endpoints.
|
|
24
|
+
|
|
25
|
+
**Data Model & Hierarchy:**
|
|
26
|
+
- Core entities: Advertiser → Deal → Line Item → Creative Assignment.
|
|
27
|
+
- Deal Types: Traditional, Programmatic (PG, Preferred Deal, PMP, Always On, Open Auction).
|
|
28
|
+
- Creative Management: Tier 1 (Content Hub) and Tier 2 (Media Owner) approval processes.
|
|
29
|
+
|
|
30
|
+
**Traffic Control System:**
|
|
31
|
+
- Single-level allocation (0-100%) and priority system (1-10) at the Line Item level.
|
|
32
|
+
- **Frequency Cap**: Limits ad plays per inventory (screen) per time period for programmatic deal types.
|
|
33
|
+
|
|
34
|
+
**UI/UX Design:**
|
|
35
|
+
- **Theming**: Light mode, enterprise theme with blue primary color and white sidebar.
|
|
36
|
+
- **Dialog Usage**: Only for error/confirmation; forms use dedicated pages.
|
|
37
|
+
- **Forms**: Dedicated pages for create/edit with fixed footer.
|
|
38
|
+
- **Filters**: Right-side drawer with extensive filter options.
|
|
39
|
+
- **Dropdowns**: All dropdowns include search functionality.
|
|
40
|
+
- **Data Formatting**: Standardized dates (MMM DD, YYYY) and ISO 3-letter currency codes.
|
|
41
|
+
- **Lists**: Sorted by last edited first.
|
|
42
|
+
|
|
43
|
+
**Key Features:**
|
|
44
|
+
- **Dashboard**: Customizable metrics, impression progress, inventory availability summary, and status tracking.
|
|
45
|
+
- **Sidebar Navigation**: Dashboard, Deals, Content Hub, Inventory (external link), Proof of Play, Integrations, Measure (external link), Configuration (dropdown).
|
|
46
|
+
- **Drill-Down Navigation**: Structured paths for detailed views.
|
|
47
|
+
- **Creative Assignment Page**: Full-page drag-and-drop interface.
|
|
48
|
+
|
|
49
|
+
**Configuration Module:**
|
|
50
|
+
- **Custom POI Management**: Creation and management of Points of Interest for geotargeting, with bulk upload via CSV.
|
|
51
|
+
- **Tags System**: Cross-platform organization for deals, creatives, and other entities, with central storage in Admin Console.
|
|
52
|
+
- **Settings Module**: Comprehensive settings for general, notifications, traffic control, forecasting, optimization, workflow, terminology, themes, inventory whitelisting, and API.
|
|
53
|
+
|
|
54
|
+
**Line Item Form:**
|
|
55
|
+
- Comprehensive creation form with drawer-based UX covering basic details, creative, flight dates, budget, pacing, targeting, DOOH inventory, AI recommendations, day parting, billing, bid strategy, custom fees, advanced options, and signals.
|
|
56
|
+
- **Advanced Map Features**: Geography drawer includes Mapbox tooling with drawing tools (circle, polygon, line), 3D view toggle, heatmap toggle, CSV upload for coordinates, and include/exclude toggles.
|
|
57
|
+
|
|
58
|
+
**Ad Delivery Architecture (Dual-Channel):**
|
|
59
|
+
- **Channel A — Decision Engine (DE)**: Real-time microservice providing manifest-based ad delivery, utilizing Redis for pacing and budget caps.
|
|
60
|
+
- **Channel B — VAST Tag Distribution**: Manual distribution of VAST tags for third-party CMS platforms.
|
|
61
|
+
- Both channels report into the same deal-level dashboard.
|
|
62
|
+
|
|
63
|
+
**Deal Acceptance & Locking Workflow:**
|
|
64
|
+
- Deals are locked after "Request Acceptance" to maintain data integrity, restricting edits. "Reopened" status allows changes.
|
|
65
|
+
|
|
66
|
+
**Error Handling & Recovery:**
|
|
67
|
+
- Specific error messages, auto-retry, optimistic UI updates, draft/autosave, and queued operations.
|
|
68
|
+
|
|
69
|
+
**CMS Integration Plan:**
|
|
70
|
+
- Integration with various CMS platforms (e.g., Studio, Broadsign) for creative/schedule pushing, and player status/PoP data pulling.
|
|
71
|
+
|
|
72
|
+
**Proof of Play (PoP) System:**
|
|
73
|
+
- Verification of ad display with proof media, sourced from CMS or manual playlog uploads.
|
|
74
|
+
|
|
75
|
+
**Role-Based Feature Access Control:**
|
|
76
|
+
- Comprehensive RBAC system integrated with Admin Console, mapping features to roles.
|
|
77
|
+
|
|
78
|
+
**Recommendation Engine Integration:**
|
|
79
|
+
- Integrates with MW Planner's Recommendation Engine V2 for AI-driven inventory recommendations based on an 8-factor scoring system.
|
|
80
|
+
|
|
81
|
+
## External Dependencies
|
|
82
|
+
|
|
83
|
+
- **Planner**: For sending Traditional deals and managing inventory reservations.
|
|
84
|
+
- **Activate**: For sending Programmatic deals.
|
|
85
|
+
- **Booking Engine**: Separate service for inventory reservations.
|
|
86
|
+
- **Admin Console**: Source for DSP partners, seat names/IDs, and company hierarchy.
|
|
87
|
+
- **Inventory Management**: External product for screen and display management.
|
|
88
|
+
- **SSP Partners**: Supply-side platforms for programmatic integrations (default: Influence SSP).
|
|
89
|
+
- **DSP Partners**: Demand-side platforms sourced from Admin Console.
|
|
90
|
+
- **Measure**: Reporting platform for analytics, bid requests, bid responses, and proof-of-play reports.
|
|
91
|
+
- **Decision Engine (DE)**: Separate external microservice (own base URL, e.g., `https://de.influence.io`) for intelligent ad selection. Not part of Influence's `/api` namespace. Uses Redis for state tracking. API: `POST /v1/decision/simple`. Replaces round-robin with multi-factor scoring.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { build as esbuild } from "esbuild";
|
|
2
|
+
import { build as viteBuild } from "vite";
|
|
3
|
+
import { rm, readFile } from "fs/promises";
|
|
4
|
+
|
|
5
|
+
// server deps to bundle to reduce openat(2) syscalls
|
|
6
|
+
// which helps cold start times
|
|
7
|
+
const allowlist = [
|
|
8
|
+
"@google/generative-ai",
|
|
9
|
+
"axios",
|
|
10
|
+
"connect-pg-simple",
|
|
11
|
+
"cors",
|
|
12
|
+
"date-fns",
|
|
13
|
+
"drizzle-orm",
|
|
14
|
+
"drizzle-zod",
|
|
15
|
+
"express",
|
|
16
|
+
"express-rate-limit",
|
|
17
|
+
"express-session",
|
|
18
|
+
"jsonwebtoken",
|
|
19
|
+
"memorystore",
|
|
20
|
+
"multer",
|
|
21
|
+
"nanoid",
|
|
22
|
+
"nodemailer",
|
|
23
|
+
"openai",
|
|
24
|
+
"passport",
|
|
25
|
+
"passport-local",
|
|
26
|
+
"pg",
|
|
27
|
+
"stripe",
|
|
28
|
+
"uuid",
|
|
29
|
+
"ws",
|
|
30
|
+
"xlsx",
|
|
31
|
+
"zod",
|
|
32
|
+
"zod-validation-error",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
async function buildAll() {
|
|
36
|
+
await rm("dist", { recursive: true, force: true });
|
|
37
|
+
|
|
38
|
+
console.log("building client...");
|
|
39
|
+
await viteBuild();
|
|
40
|
+
|
|
41
|
+
console.log("building server...");
|
|
42
|
+
const pkg = JSON.parse(await readFile("package.json", "utf-8"));
|
|
43
|
+
const allDeps = [
|
|
44
|
+
...Object.keys(pkg.dependencies || {}),
|
|
45
|
+
...Object.keys(pkg.devDependencies || {}),
|
|
46
|
+
];
|
|
47
|
+
const externals = allDeps.filter((dep) => !allowlist.includes(dep));
|
|
48
|
+
|
|
49
|
+
await esbuild({
|
|
50
|
+
entryPoints: ["server/index.ts"],
|
|
51
|
+
platform: "node",
|
|
52
|
+
bundle: true,
|
|
53
|
+
format: "cjs",
|
|
54
|
+
outfile: "dist/index.cjs",
|
|
55
|
+
define: {
|
|
56
|
+
"process.env.NODE_ENV": '"production"',
|
|
57
|
+
},
|
|
58
|
+
minify: true,
|
|
59
|
+
external: externals,
|
|
60
|
+
logLevel: "info",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
buildAll().catch((err) => {
|
|
65
|
+
console.error(err);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
const https = require('https');
|
|
2
|
+
|
|
3
|
+
const MIRO_TOKEN = process.env.MIRO_ACCESS_TOKEN;
|
|
4
|
+
const BOARD_ID = 'uXjVGHwGbyo=';
|
|
5
|
+
const BOARD_URL = 'https://miro.com/app/board/uXjVGHwGbyo=';
|
|
6
|
+
|
|
7
|
+
const COLORS = {
|
|
8
|
+
gray: '#6B7280',
|
|
9
|
+
grayLight: '#9CA3AF',
|
|
10
|
+
lightBlue: '#DBEAFE',
|
|
11
|
+
blue: '#3B82F6',
|
|
12
|
+
blueDark: '#1E40AF',
|
|
13
|
+
orange: '#FDBA74',
|
|
14
|
+
orangeDark: '#F97316',
|
|
15
|
+
green: '#BBF7D0',
|
|
16
|
+
greenDark: '#22C55E',
|
|
17
|
+
purple: '#E9D5FF',
|
|
18
|
+
purpleDark: '#9333EA',
|
|
19
|
+
yellow: '#FEF3C7',
|
|
20
|
+
yellowDark: '#F59E0B',
|
|
21
|
+
red: '#FCA5A5',
|
|
22
|
+
redDark: '#EF4444',
|
|
23
|
+
white: '#FFFFFF',
|
|
24
|
+
black: '#1a1a2e'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const SHAPE = { width: 160, height: 70 };
|
|
28
|
+
const DIAMOND = { width: 140, height: 100 };
|
|
29
|
+
const CIRCLE = { width: 90, height: 90 };
|
|
30
|
+
|
|
31
|
+
function makeRequest(method, path, data = null) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const encodedPath = path.replace(/=/g, '%3D');
|
|
34
|
+
const options = {
|
|
35
|
+
hostname: 'api.miro.com',
|
|
36
|
+
port: 443,
|
|
37
|
+
path: encodedPath,
|
|
38
|
+
method: method,
|
|
39
|
+
headers: {
|
|
40
|
+
'Authorization': `Bearer ${MIRO_TOKEN}`,
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
'Accept': 'application/json'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const req = https.request(options, (res) => {
|
|
47
|
+
let body = '';
|
|
48
|
+
res.on('data', chunk => body += chunk);
|
|
49
|
+
res.on('end', () => {
|
|
50
|
+
try {
|
|
51
|
+
const result = body ? JSON.parse(body) : {};
|
|
52
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
53
|
+
resolve(result);
|
|
54
|
+
} else {
|
|
55
|
+
console.error(`API Error ${res.statusCode}: ${body}`);
|
|
56
|
+
reject(new Error(`API Error ${res.statusCode}`));
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {
|
|
59
|
+
reject(e);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
req.on('error', reject);
|
|
65
|
+
if (data) req.write(JSON.stringify(data));
|
|
66
|
+
req.end();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function sleep(ms) {
|
|
71
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function createFrame(title, x, y, width, height) {
|
|
75
|
+
console.log(` Creating frame: ${title}`);
|
|
76
|
+
const result = await makeRequest('POST', `/v2/boards/${BOARD_ID}/frames`, {
|
|
77
|
+
data: { title, format: 'custom', type: 'freeform' },
|
|
78
|
+
style: { fillColor: '#F8F9FA' },
|
|
79
|
+
geometry: { width, height },
|
|
80
|
+
position: { x, y, origin: 'center' }
|
|
81
|
+
});
|
|
82
|
+
await sleep(200);
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function createShape(text, x, y, shapeType, fillColor, borderColor, width, height) {
|
|
87
|
+
const payload = {
|
|
88
|
+
data: { shape: shapeType, content: `<p style="text-align:center">${text}</p>` },
|
|
89
|
+
style: {
|
|
90
|
+
fillColor, borderColor, borderWidth: '2',
|
|
91
|
+
fontFamily: 'arial', fontSize: '12', textAlign: 'center', textAlignVertical: 'middle'
|
|
92
|
+
},
|
|
93
|
+
geometry: { width, height },
|
|
94
|
+
position: { x, y, origin: 'center' }
|
|
95
|
+
};
|
|
96
|
+
const result = await makeRequest('POST', `/v2/boards/${BOARD_ID}/shapes`, payload);
|
|
97
|
+
await sleep(150);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function createConnector(startId, endId, startPos = null, endPos = null, caption = null, strokeColor = COLORS.black) {
|
|
102
|
+
const payload = {
|
|
103
|
+
startItem: { id: startId, position: startPos || { x: '100%', y: '50%' } },
|
|
104
|
+
endItem: { id: endId, position: endPos || { x: '0%', y: '50%' } },
|
|
105
|
+
style: { strokeColor, strokeWidth: '2', strokeStyle: 'normal', endStrokeCap: 'stealth' },
|
|
106
|
+
shape: 'elbowed'
|
|
107
|
+
};
|
|
108
|
+
if (caption) payload.captions = [{ content: caption, position: '50%' }];
|
|
109
|
+
const result = await makeRequest('POST', `/v2/boards/${BOARD_ID}/connectors`, payload);
|
|
110
|
+
await sleep(100);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function createText(content, x, y, fontSize = 12, color = '#000000') {
|
|
115
|
+
const payload = {
|
|
116
|
+
data: { content: `<p>${content}</p>` },
|
|
117
|
+
style: { color, fontFamily: 'arial', fontSize: fontSize.toString(), textAlign: 'left' },
|
|
118
|
+
position: { x, y, origin: 'center' }
|
|
119
|
+
};
|
|
120
|
+
const result = await makeRequest('POST', `/v2/boards/${BOARD_ID}/texts`, payload);
|
|
121
|
+
await sleep(100);
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function createLegend(x, y, items) {
|
|
126
|
+
await createText('<strong>LEGEND</strong>', x + 40, y - 25, 14, COLORS.black);
|
|
127
|
+
for (let i = 0; i < items.length; i++) {
|
|
128
|
+
const item = items[i];
|
|
129
|
+
const itemY = y + (i * 35);
|
|
130
|
+
await createShape('', x, itemY, 'rectangle', item.color, item.border, 25, 18);
|
|
131
|
+
await createText(item.label, x + 80, itemY, 11, '#374151');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function createHierarchyDiagram(baseX, baseY) {
|
|
136
|
+
console.log('\n Adding Hierarchy shapes...');
|
|
137
|
+
const colSpace = 280;
|
|
138
|
+
|
|
139
|
+
await createText('<strong>LEVEL 1</strong><br/>ADVERTISERS', baseX - 400, baseY - 130, 12, COLORS.gray);
|
|
140
|
+
await createText('<strong>LEVEL 2</strong><br/>DEALS', baseX - 400 + colSpace, baseY - 130, 12, COLORS.blue);
|
|
141
|
+
await createText('<strong>LEVEL 3</strong><br/>LINE ITEMS', baseX - 400 + colSpace*2, baseY - 130, 12, COLORS.orangeDark);
|
|
142
|
+
await createText('<strong>LEVEL 4</strong><br/>CREATIVE ASSIGNMENTS', baseX - 400 + colSpace*3, baseY - 130, 12, COLORS.purpleDark);
|
|
143
|
+
|
|
144
|
+
const a1 = await createShape('Coca-Cola', baseX - 400, baseY - 40, 'rectangle', COLORS.gray, COLORS.gray, SHAPE.width, SHAPE.height);
|
|
145
|
+
const a2 = await createShape('Nike', baseX - 400, baseY + 60, 'rectangle', COLORS.gray, COLORS.gray, SHAPE.width, SHAPE.height);
|
|
146
|
+
|
|
147
|
+
const d1 = await createShape('Summer Refresh', baseX - 400 + colSpace, baseY - 90, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
148
|
+
const d2 = await createShape('Holiday Season', baseX - 400 + colSpace, baseY + 10, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
149
|
+
const d3 = await createShape('Just Do It', baseX - 400 + colSpace, baseY + 110, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
150
|
+
|
|
151
|
+
const l1 = await createShape('15s Brand Video', baseX - 400 + colSpace*2, baseY - 90, 'rectangle', COLORS.orange, COLORS.orangeDark, SHAPE.width, SHAPE.height);
|
|
152
|
+
const l2 = await createShape('10s Product Promo', baseX - 400 + colSpace*2, baseY + 10, 'rectangle', COLORS.orange, COLORS.orangeDark, SHAPE.width, SHAPE.height);
|
|
153
|
+
const l3 = await createShape('20s Holiday Ad', baseX - 400 + colSpace*2, baseY + 110, 'rectangle', COLORS.orange, COLORS.orangeDark, SHAPE.width, SHAPE.height);
|
|
154
|
+
|
|
155
|
+
const ca1 = await createShape('Hero Video<br/>All Day', baseX - 400 + colSpace*3, baseY - 90, 'rectangle', COLORS.purple, COLORS.purpleDark, SHAPE.width, SHAPE.height);
|
|
156
|
+
const ca2 = await createShape('Promo Video<br/>Morning', baseX - 400 + colSpace*3, baseY + 10, 'rectangle', COLORS.purple, COLORS.purpleDark, SHAPE.width, SHAPE.height);
|
|
157
|
+
const ca3 = await createShape('Holiday Spot<br/>Evening', baseX - 400 + colSpace*3, baseY + 110, 'rectangle', COLORS.purple, COLORS.purpleDark, SHAPE.width, SHAPE.height);
|
|
158
|
+
|
|
159
|
+
console.log(' Adding connectors...');
|
|
160
|
+
await createConnector(a1.id, d1.id);
|
|
161
|
+
await createConnector(a1.id, d2.id);
|
|
162
|
+
await createConnector(a2.id, d3.id);
|
|
163
|
+
await createConnector(d1.id, l1.id);
|
|
164
|
+
await createConnector(d1.id, l2.id);
|
|
165
|
+
await createConnector(d2.id, l3.id);
|
|
166
|
+
await createConnector(l1.id, ca1.id);
|
|
167
|
+
await createConnector(l2.id, ca2.id);
|
|
168
|
+
await createConnector(l3.id, ca3.id);
|
|
169
|
+
|
|
170
|
+
await createLegend(baseX + 520, baseY - 80, [
|
|
171
|
+
{ color: COLORS.gray, border: COLORS.gray, label: 'Advertiser' },
|
|
172
|
+
{ color: COLORS.lightBlue, border: COLORS.blue, label: 'Deal' },
|
|
173
|
+
{ color: COLORS.orange, border: COLORS.orangeDark, label: 'Line Item' },
|
|
174
|
+
{ color: COLORS.purple, border: COLORS.purpleDark, label: 'Creative Assignment' }
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function createDealStatusDiagram(baseX, baseY) {
|
|
179
|
+
console.log('\n Adding Deal Status shapes...');
|
|
180
|
+
|
|
181
|
+
const start = await createShape('Create<br/>Deal', baseX - 250, baseY, 'circle', COLORS.yellow, COLORS.yellowDark, CIRCLE.width, CIRCLE.height);
|
|
182
|
+
const active = await createShape('Active', baseX - 50, baseY, 'rectangle', COLORS.green, COLORS.greenDark, SHAPE.width, SHAPE.height);
|
|
183
|
+
const paused = await createShape('Paused', baseX + 200, baseY, 'rectangle', COLORS.orange, COLORS.orangeDark, SHAPE.width, SHAPE.height);
|
|
184
|
+
|
|
185
|
+
await createConnector(start.id, active.id);
|
|
186
|
+
await createConnector(active.id, paused.id, { x: '100%', y: '30%' }, { x: '0%', y: '30%' }, 'Pause');
|
|
187
|
+
await createConnector(paused.id, active.id, { x: '0%', y: '70%' }, { x: '100%', y: '70%' }, 'Resume');
|
|
188
|
+
|
|
189
|
+
await createLegend(baseX + 380, baseY - 60, [
|
|
190
|
+
{ color: COLORS.yellow, border: COLORS.yellowDark, label: 'Start Event' },
|
|
191
|
+
{ color: COLORS.green, border: COLORS.greenDark, label: 'Active - Delivering' },
|
|
192
|
+
{ color: COLORS.orange, border: COLORS.orangeDark, label: 'Paused - Stopped' }
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function createAdServingDiagram(baseX, baseY) {
|
|
197
|
+
console.log('\n Adding Ad Serving Decision Flow shapes...');
|
|
198
|
+
const col = 200;
|
|
199
|
+
|
|
200
|
+
const start = await createShape('Screen<br/>requests ad', baseX - 800, baseY, 'circle', COLORS.yellow, COLORS.yellowDark, CIRCLE.width, CIRCLE.height);
|
|
201
|
+
|
|
202
|
+
const sc1 = await createShape('Look up screen', baseX - 800 + col, baseY, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
203
|
+
const sc2 = await createShape('Screen<br/>active?', baseX - 800 + col*2, baseY, 'rhombus', COLORS.orange, COLORS.orangeDark, DIAMOND.width, DIAMOND.height);
|
|
204
|
+
|
|
205
|
+
const c1 = await createShape('Find active deals', baseX - 800 + col*3, baseY, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
206
|
+
const c2 = await createShape('Deals<br/>found?', baseX - 800 + col*4, baseY, 'rhombus', COLORS.orange, COLORS.orangeDark, DIAMOND.width, DIAMOND.height);
|
|
207
|
+
|
|
208
|
+
const l1 = await createShape('Get line items', baseX - 800 + col*5, baseY, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
209
|
+
const l2 = await createShape('Items<br/>available?', baseX - 800 + col*6, baseY, 'rhombus', COLORS.orange, COLORS.orangeDark, DIAMOND.width, DIAMOND.height);
|
|
210
|
+
|
|
211
|
+
const w1 = await createShape('Calculate<br/>allocations', baseX - 800 + col*7, baseY, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
212
|
+
const w2 = await createShape('Select winner', baseX - 800 + col*8, baseY, 'rectangle', COLORS.lightBlue, COLORS.blue, SHAPE.width, SHAPE.height);
|
|
213
|
+
|
|
214
|
+
const ok = await createShape('Return ad<br/>to screen', baseX - 800 + col*8, baseY - 120, 'rectangle', COLORS.green, COLORS.greenDark, SHAPE.width, SHAPE.height);
|
|
215
|
+
const fail = await createShape('Show default<br/>content', baseX - 800 + col*4, baseY + 130, 'rectangle', COLORS.red, COLORS.redDark, SHAPE.width, SHAPE.height);
|
|
216
|
+
const end = await createShape('Done', baseX - 800 + col*8, baseY + 130, 'circle', COLORS.grayLight, COLORS.gray, CIRCLE.width, CIRCLE.height);
|
|
217
|
+
|
|
218
|
+
console.log(' Adding connectors...');
|
|
219
|
+
await createConnector(start.id, sc1.id);
|
|
220
|
+
await createConnector(sc1.id, sc2.id);
|
|
221
|
+
await createConnector(sc2.id, c1.id, { x: '100%', y: '50%' }, { x: '0%', y: '50%' }, 'Yes');
|
|
222
|
+
await createConnector(c1.id, c2.id);
|
|
223
|
+
await createConnector(c2.id, l1.id, { x: '100%', y: '50%' }, { x: '0%', y: '50%' }, 'Yes');
|
|
224
|
+
await createConnector(l1.id, l2.id);
|
|
225
|
+
await createConnector(l2.id, w1.id, { x: '100%', y: '50%' }, { x: '0%', y: '50%' }, 'Yes');
|
|
226
|
+
await createConnector(w1.id, w2.id);
|
|
227
|
+
await createConnector(w2.id, ok.id, { x: '50%', y: '0%' }, { x: '50%', y: '100%' }, '', COLORS.greenDark);
|
|
228
|
+
|
|
229
|
+
await createConnector(sc2.id, fail.id, { x: '50%', y: '100%' }, { x: '0%', y: '50%' }, 'No', COLORS.redDark);
|
|
230
|
+
await createConnector(c2.id, fail.id, { x: '50%', y: '100%' }, { x: '50%', y: '0%' }, 'No', COLORS.redDark);
|
|
231
|
+
await createConnector(l2.id, fail.id, { x: '50%', y: '100%' }, { x: '100%', y: '50%' }, 'No', COLORS.redDark);
|
|
232
|
+
|
|
233
|
+
await createConnector(ok.id, end.id, { x: '50%', y: '100%' }, { x: '50%', y: '0%' }, '');
|
|
234
|
+
await createConnector(fail.id, end.id);
|
|
235
|
+
|
|
236
|
+
await createLegend(baseX + 900, baseY - 100, [
|
|
237
|
+
{ color: COLORS.yellow, border: COLORS.yellowDark, label: 'Start Event' },
|
|
238
|
+
{ color: COLORS.lightBlue, border: COLORS.blue, label: 'Process Step' },
|
|
239
|
+
{ color: COLORS.orange, border: COLORS.orangeDark, label: 'Decision Point' },
|
|
240
|
+
{ color: COLORS.green, border: COLORS.greenDark, label: 'Success Outcome' },
|
|
241
|
+
{ color: COLORS.red, border: COLORS.redDark, label: 'Failure Outcome' },
|
|
242
|
+
{ color: COLORS.grayLight, border: COLORS.gray, label: 'End State' }
|
|
243
|
+
]);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function createIntegrationDiagram(baseX, baseY) {
|
|
247
|
+
console.log('\n Adding Integration Architecture shapes...');
|
|
248
|
+
|
|
249
|
+
await createShape('<strong>Influence Platform</strong>', baseX - 200, baseY, 'round_rectangle', '#E3F2FD', '#2196F3', 220, 180);
|
|
250
|
+
await createShape('<strong>Admin Console</strong>', baseX + 200, baseY, 'round_rectangle', '#E8F5E9', '#4CAF50', 220, 220);
|
|
251
|
+
|
|
252
|
+
const df = await createShape('Deal Form', baseX - 200, baseY - 40, 'rectangle', COLORS.lightBlue, COLORS.blue, 130, 40);
|
|
253
|
+
const af = await createShape('Agency Form', baseX - 200, baseY + 30, 'rectangle', COLORS.lightBlue, COLORS.blue, 130, 40);
|
|
254
|
+
|
|
255
|
+
const ssp = await createShape('SSP Config', baseX + 200, baseY - 70, 'rectangle', COLORS.green, COLORS.greenDark, 130, 35);
|
|
256
|
+
const dsp = await createShape('DSP Config', baseX + 200, baseY - 25, 'rectangle', COLORS.green, COLORS.greenDark, 130, 35);
|
|
257
|
+
const seat = await createShape('Seat Config', baseX + 200, baseY + 20, 'rectangle', COLORS.green, COLORS.greenDark, 130, 35);
|
|
258
|
+
const country = await createShape('Country Access', baseX + 200, baseY + 65, 'rectangle', COLORS.green, COLORS.greenDark, 130, 35);
|
|
259
|
+
|
|
260
|
+
await createConnector(df.id, ssp.id);
|
|
261
|
+
await createConnector(df.id, dsp.id);
|
|
262
|
+
await createConnector(df.id, seat.id);
|
|
263
|
+
await createConnector(df.id, country.id);
|
|
264
|
+
await createConnector(af.id, seat.id);
|
|
265
|
+
|
|
266
|
+
await createLegend(baseX + 400, baseY - 80, [
|
|
267
|
+
{ color: '#E3F2FD', border: '#2196F3', label: 'Influence Platform' },
|
|
268
|
+
{ color: '#E8F5E9', border: '#4CAF50', label: 'Admin Console' }
|
|
269
|
+
]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function main() {
|
|
273
|
+
try {
|
|
274
|
+
console.log('=== CREATING INFLUENCE DIAGRAMS IN MIRO ===');
|
|
275
|
+
console.log(`Board: ${BOARD_URL}\n`);
|
|
276
|
+
|
|
277
|
+
console.log('Creating Frame 1: Advertising Hierarchy');
|
|
278
|
+
const f1 = await createFrame('Influence - Advertising Hierarchy', 3000, 0, 1700, 500);
|
|
279
|
+
await createHierarchyDiagram(3000, 0);
|
|
280
|
+
|
|
281
|
+
console.log('\nCreating Frame 2: Deal Status Lifecycle');
|
|
282
|
+
const f2 = await createFrame('Influence - Deal Status Lifecycle', 3000, 700, 1000, 350);
|
|
283
|
+
await createDealStatusDiagram(3000, 700);
|
|
284
|
+
|
|
285
|
+
console.log('\nCreating Frame 3: Ad Serving Decision Flow');
|
|
286
|
+
const f3 = await createFrame('Influence - Ad Serving Decision Flow', 3000, 1300, 2200, 500);
|
|
287
|
+
await createAdServingDiagram(3000, 1300);
|
|
288
|
+
|
|
289
|
+
console.log('\nCreating Frame 4: Admin Console Integration');
|
|
290
|
+
const f4 = await createFrame('Influence - Admin Console Integration', 3000, 2000, 900, 450);
|
|
291
|
+
await createIntegrationDiagram(3000, 2000);
|
|
292
|
+
|
|
293
|
+
console.log('\n=== MIRO DIAGRAMS CREATED SUCCESSFULLY ===\n');
|
|
294
|
+
console.log(`Board URL: ${BOARD_URL}\n`);
|
|
295
|
+
console.log('Frame Links:');
|
|
296
|
+
console.log(` 1. Advertising Hierarchy: ${BOARD_URL}?moveToWidget=${f1.id}`);
|
|
297
|
+
console.log(` 2. Deal Status Lifecycle: ${BOARD_URL}?moveToWidget=${f2.id}`);
|
|
298
|
+
console.log(` 3. Ad Serving Decision Flow: ${BOARD_URL}?moveToWidget=${f3.id}`);
|
|
299
|
+
console.log(` 4. Admin Console Integration: ${BOARD_URL}?moveToWidget=${f4.id}`);
|
|
300
|
+
|
|
301
|
+
console.log('\n--- PRD UPDATE INFO ---');
|
|
302
|
+
console.log(JSON.stringify({
|
|
303
|
+
board: BOARD_URL,
|
|
304
|
+
frames: {
|
|
305
|
+
hierarchy: `${BOARD_URL}?moveToWidget=${f1.id}`,
|
|
306
|
+
dealStatus: `${BOARD_URL}?moveToWidget=${f2.id}`,
|
|
307
|
+
adServing: `${BOARD_URL}?moveToWidget=${f3.id}`,
|
|
308
|
+
integration: `${BOARD_URL}?moveToWidget=${f4.id}`
|
|
309
|
+
}
|
|
310
|
+
}, null, 2));
|
|
311
|
+
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error('Error:', error.message);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
main();
|