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.
Files changed (525) hide show
  1. package/.ci/staging.yml +191 -0
  2. package/.dockerignore +117 -0
  3. package/.env +40 -0
  4. package/.env.staging +38 -0
  5. package/.gitlab-ci.yml +16 -0
  6. package/DEMO_STATUS.md +579 -0
  7. package/Dockerfile +61 -0
  8. package/Influence-MW-AdServer-12-02-2026/client/index.html +17 -0
  9. package/Influence-MW-AdServer-12-02-2026/client/public/favicon.png +0 -0
  10. package/Influence-MW-AdServer-12-02-2026/client/src/App.tsx +91 -0
  11. package/Influence-MW-AdServer-12-02-2026/client/src/components/advanced-map-drawer.tsx +1131 -0
  12. package/Influence-MW-AdServer-12-02-2026/client/src/components/ai-recommendation-panel.tsx +379 -0
  13. package/Influence-MW-AdServer-12-02-2026/client/src/components/app-sidebar.tsx +183 -0
  14. package/Influence-MW-AdServer-12-02-2026/client/src/components/auto-optimize-button.tsx +184 -0
  15. package/Influence-MW-AdServer-12-02-2026/client/src/components/availability-drawer.tsx +385 -0
  16. package/Influence-MW-AdServer-12-02-2026/client/src/components/brand-insights-panel.tsx +87 -0
  17. package/Influence-MW-AdServer-12-02-2026/client/src/components/create-agency-drawer.tsx +198 -0
  18. package/Influence-MW-AdServer-12-02-2026/client/src/components/create-brand-drawer.tsx +275 -0
  19. package/Influence-MW-AdServer-12-02-2026/client/src/components/creative-assignment.tsx +526 -0
  20. package/Influence-MW-AdServer-12-02-2026/client/src/components/data-table-toolbar.tsx +148 -0
  21. package/Influence-MW-AdServer-12-02-2026/client/src/components/data-table.tsx +158 -0
  22. package/Influence-MW-AdServer-12-02-2026/client/src/components/filter-drawer.tsx +356 -0
  23. package/Influence-MW-AdServer-12-02-2026/client/src/components/form-insights-panel.tsx +82 -0
  24. package/Influence-MW-AdServer-12-02-2026/client/src/components/geography-selector.tsx +699 -0
  25. package/Influence-MW-AdServer-12-02-2026/client/src/components/header-user-menu.tsx +178 -0
  26. package/Influence-MW-AdServer-12-02-2026/client/src/components/history-drawer.tsx +313 -0
  27. package/Influence-MW-AdServer-12-02-2026/client/src/components/inventory-availability-section.tsx +176 -0
  28. package/Influence-MW-AdServer-12-02-2026/client/src/components/inventory-format-drawer.tsx +173 -0
  29. package/Influence-MW-AdServer-12-02-2026/client/src/components/inventory-selector.tsx +401 -0
  30. package/Influence-MW-AdServer-12-02-2026/client/src/components/manual-inventory-drawer.tsx +368 -0
  31. package/Influence-MW-AdServer-12-02-2026/client/src/components/mapbox-map.tsx +368 -0
  32. package/Influence-MW-AdServer-12-02-2026/client/src/components/market-insights-panel.tsx +202 -0
  33. package/Influence-MW-AdServer-12-02-2026/client/src/components/media-owner-drawer.tsx +217 -0
  34. package/Influence-MW-AdServer-12-02-2026/client/src/components/metric-card.tsx +58 -0
  35. package/Influence-MW-AdServer-12-02-2026/client/src/components/page-header.tsx +27 -0
  36. package/Influence-MW-AdServer-12-02-2026/client/src/components/player-status-indicator.tsx +137 -0
  37. package/Influence-MW-AdServer-12-02-2026/client/src/components/poi-targeting-drawer.tsx +298 -0
  38. package/Influence-MW-AdServer-12-02-2026/client/src/components/recommendation-score-badge.tsx +102 -0
  39. package/Influence-MW-AdServer-12-02-2026/client/src/components/recommended-inventories-panel.tsx +248 -0
  40. package/Influence-MW-AdServer-12-02-2026/client/src/components/searchable-combobox.tsx +134 -0
  41. package/Influence-MW-AdServer-12-02-2026/client/src/components/signal-visualizations.tsx +407 -0
  42. package/Influence-MW-AdServer-12-02-2026/client/src/components/status-badge.tsx +35 -0
  43. package/Influence-MW-AdServer-12-02-2026/client/src/components/theme-provider.tsx +73 -0
  44. package/Influence-MW-AdServer-12-02-2026/client/src/components/theme-toggle.tsx +37 -0
  45. package/Influence-MW-AdServer-12-02-2026/client/src/components/traffic-slider.tsx +75 -0
  46. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/accordion.tsx +56 -0
  47. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/alert-dialog.tsx +139 -0
  48. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/alert.tsx +59 -0
  49. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/aspect-ratio.tsx +5 -0
  50. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/avatar.tsx +51 -0
  51. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/badge.tsx +38 -0
  52. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/breadcrumb.tsx +115 -0
  53. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/button.tsx +62 -0
  54. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/calendar.tsx +68 -0
  55. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/card.tsx +85 -0
  56. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/carousel.tsx +260 -0
  57. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/chart.tsx +365 -0
  58. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/checkbox.tsx +28 -0
  59. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/collapsible.tsx +11 -0
  60. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/command.tsx +151 -0
  61. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/context-menu.tsx +198 -0
  62. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/dialog.tsx +122 -0
  63. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/drawer.tsx +118 -0
  64. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/dropdown-menu.tsx +198 -0
  65. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/form.tsx +178 -0
  66. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/hover-card.tsx +29 -0
  67. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/input-otp.tsx +69 -0
  68. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/input.tsx +23 -0
  69. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/label.tsx +24 -0
  70. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/menubar.tsx +256 -0
  71. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/navigation-menu.tsx +128 -0
  72. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/pagination.tsx +117 -0
  73. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/popover.tsx +29 -0
  74. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/progress.tsx +28 -0
  75. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/radio-group.tsx +42 -0
  76. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/resizable.tsx +45 -0
  77. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/scroll-area.tsx +46 -0
  78. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/select.tsx +160 -0
  79. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/separator.tsx +29 -0
  80. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/sheet.tsx +140 -0
  81. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/sidebar.tsx +727 -0
  82. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/skeleton.tsx +15 -0
  83. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/slider.tsx +26 -0
  84. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/switch.tsx +27 -0
  85. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/table.tsx +117 -0
  86. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/tabs.tsx +53 -0
  87. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/textarea.tsx +22 -0
  88. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toast.tsx +127 -0
  89. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toaster.tsx +33 -0
  90. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toggle-group.tsx +61 -0
  91. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/toggle.tsx +43 -0
  92. package/Influence-MW-AdServer-12-02-2026/client/src/components/ui/tooltip.tsx +30 -0
  93. package/Influence-MW-AdServer-12-02-2026/client/src/components/vendor-stores-modal.tsx +336 -0
  94. package/Influence-MW-AdServer-12-02-2026/client/src/components/venue-type-drawer.tsx +359 -0
  95. package/Influence-MW-AdServer-12-02-2026/client/src/components/venue-type-selector.tsx +436 -0
  96. package/Influence-MW-AdServer-12-02-2026/client/src/hooks/use-mobile.tsx +19 -0
  97. package/Influence-MW-AdServer-12-02-2026/client/src/hooks/use-toast.ts +191 -0
  98. package/Influence-MW-AdServer-12-02-2026/client/src/index.css +244 -0
  99. package/Influence-MW-AdServer-12-02-2026/client/src/lib/queryClient.ts +57 -0
  100. package/Influence-MW-AdServer-12-02-2026/client/src/lib/utils.ts +39 -0
  101. package/Influence-MW-AdServer-12-02-2026/client/src/lib/venue-taxonomy.ts +532 -0
  102. package/Influence-MW-AdServer-12-02-2026/client/src/main.tsx +5 -0
  103. package/Influence-MW-AdServer-12-02-2026/client/src/pages/assign-creative.tsx +781 -0
  104. package/Influence-MW-AdServer-12-02-2026/client/src/pages/content-hub.tsx +995 -0
  105. package/Influence-MW-AdServer-12-02-2026/client/src/pages/custom-pois.tsx +431 -0
  106. package/Influence-MW-AdServer-12-02-2026/client/src/pages/dashboard.tsx +620 -0
  107. package/Influence-MW-AdServer-12-02-2026/client/src/pages/deal-detail.tsx +1062 -0
  108. package/Influence-MW-AdServer-12-02-2026/client/src/pages/deal-form.tsx +1570 -0
  109. package/Influence-MW-AdServer-12-02-2026/client/src/pages/deals.tsx +716 -0
  110. package/Influence-MW-AdServer-12-02-2026/client/src/pages/edit-creative-assignment.tsx +1051 -0
  111. package/Influence-MW-AdServer-12-02-2026/client/src/pages/geotargeting.tsx +675 -0
  112. package/Influence-MW-AdServer-12-02-2026/client/src/pages/integrations.tsx +425 -0
  113. package/Influence-MW-AdServer-12-02-2026/client/src/pages/line-item-creatives.tsx +622 -0
  114. package/Influence-MW-AdServer-12-02-2026/client/src/pages/line-item-form.tsx +3132 -0
  115. package/Influence-MW-AdServer-12-02-2026/client/src/pages/line-items.tsx +530 -0
  116. package/Influence-MW-AdServer-12-02-2026/client/src/pages/not-found.tsx +21 -0
  117. package/Influence-MW-AdServer-12-02-2026/client/src/pages/proof-of-play-upload.tsx +479 -0
  118. package/Influence-MW-AdServer-12-02-2026/client/src/pages/proof-of-play.tsx +880 -0
  119. package/Influence-MW-AdServer-12-02-2026/client/src/pages/reports.tsx +235 -0
  120. package/Influence-MW-AdServer-12-02-2026/client/src/pages/settings.tsx +652 -0
  121. package/Influence-MW-AdServer-12-02-2026/client/src/pages/signal-form.tsx +1117 -0
  122. package/Influence-MW-AdServer-12-02-2026/client/src/pages/signals.tsx +366 -0
  123. package/Influence-MW-AdServer-12-02-2026/client/src/pages/tags.tsx +332 -0
  124. package/Influence-MW-AdServer-12-02-2026/client/src/pages/venues.tsx +381 -0
  125. package/Influence-MW-AdServer-12-02-2026/client/src/types/mapbox-gl-draw.d.ts +37 -0
  126. package/Influence-MW-AdServer-12-02-2026/client/src/types/react-simple-maps.d.ts +57 -0
  127. package/Influence-MW-AdServer-12-02-2026/components.json +20 -0
  128. package/Influence-MW-AdServer-12-02-2026/docs/PRD.md +3373 -0
  129. package/Influence-MW-AdServer-12-02-2026/docs/influence-feature-mapping.csv +498 -0
  130. package/Influence-MW-AdServer-12-02-2026/drizzle.config.ts +14 -0
  131. package/Influence-MW-AdServer-12-02-2026/package-lock.json +9672 -0
  132. package/Influence-MW-AdServer-12-02-2026/package.json +118 -0
  133. package/Influence-MW-AdServer-12-02-2026/postcss.config.js +6 -0
  134. package/Influence-MW-AdServer-12-02-2026/replit.md +91 -0
  135. package/Influence-MW-AdServer-12-02-2026/script/build.ts +67 -0
  136. package/Influence-MW-AdServer-12-02-2026/scripts/create-miro-diagrams.cjs +318 -0
  137. package/Influence-MW-AdServer-12-02-2026/scripts/create-remaining-diagrams.cjs +270 -0
  138. package/Influence-MW-AdServer-12-02-2026/server/index.ts +103 -0
  139. package/Influence-MW-AdServer-12-02-2026/server/recommendation-service.ts +319 -0
  140. package/Influence-MW-AdServer-12-02-2026/server/routes.ts +1890 -0
  141. package/Influence-MW-AdServer-12-02-2026/server/static.ts +19 -0
  142. package/Influence-MW-AdServer-12-02-2026/server/storage.ts +2058 -0
  143. package/Influence-MW-AdServer-12-02-2026/server/vite.ts +58 -0
  144. package/Influence-MW-AdServer-12-02-2026/shared/schema.ts +1595 -0
  145. package/Influence-MW-AdServer-12-02-2026/tailwind.config.ts +107 -0
  146. package/Influence-MW-AdServer-12-02-2026/tsconfig.json +23 -0
  147. package/Influence-MW-AdServer-12-02-2026/vite.config.ts +40 -0
  148. package/LINE_ITEM_BUDGET_FIELD_MAPPING.md +178 -0
  149. package/PCM/.env.example +92 -0
  150. package/PCM/README.md +558 -0
  151. package/PCM/docs/TEST_CASES.md +422 -0
  152. package/PCM/index.js +106 -0
  153. package/PCM/package-lock.json +3282 -0
  154. package/PCM/package.json +32 -0
  155. package/PCM/replit.md +64 -0
  156. package/PCM/schema.sql +495 -0
  157. package/PCM/scripts/export-schema.js +183 -0
  158. package/PCM/scripts/seed-comprehensive.js +631 -0
  159. package/PCM/scripts/seed-production.js +477 -0
  160. package/PCM/src/config/db.js +56 -0
  161. package/PCM/src/config/swagger.js +5975 -0
  162. package/PCM/src/dto/EmailRequestDTO.js +166 -0
  163. package/PCM/src/middleware/errorHandler.js +52 -0
  164. package/PCM/src/middleware/logger.js +26 -0
  165. package/PCM/src/migrations/001_add_campaign_mode_fields.sql +36 -0
  166. package/PCM/src/migrations/002_create_deal_id_counters.sql +22 -0
  167. package/PCM/src/migrations/003_update_publishers_column.sql +15 -0
  168. package/PCM/src/migrations/004_add_direct_dealtype_and_advertiser.sql +5 -0
  169. package/PCM/src/migrations/005_add_programmatic_fields_and_update_enums.sql +31 -0
  170. package/PCM/src/migrations/006_add_line_item_programmatic_fields.sql +12 -0
  171. package/PCM/src/migrations/007_add_line_item_direct_fields.sql +15 -0
  172. package/PCM/src/migrations/008_add_inventory_fields.sql +45 -0
  173. package/PCM/src/migrations/009_move_inventory_fields_to_metadata.sql +32 -0
  174. package/PCM/src/migrations/010_add_draft_status_and_line_items_count.sql +23 -0
  175. package/PCM/src/migrations/011_add_planning_field.sql +21 -0
  176. package/PCM/src/migrations/012_fix_inventory_composite_pk.sql +17 -0
  177. package/PCM/src/migrations/013_make_external_id_optional.sql +3 -0
  178. package/PCM/src/migrations/014_create_change_history.sql +38 -0
  179. package/PCM/src/migrations/016_create_publisher_insertion_orders.sql +33 -0
  180. package/PCM/src/migrations/017_fix_line_item_id_fk_reference.sql +86 -0
  181. package/PCM/src/migrations/018_create_approval_tables.sql +44 -0
  182. package/PCM/src/migrations/019_add_encrypted_token_column.sql +2 -0
  183. package/PCM/src/migrations/020_add_rejection_reason_to_deals.sql +10 -0
  184. package/PCM/src/migrations/021_add_publisher_external_id_to_inventories.sql +12 -0
  185. package/PCM/src/migrations/022_add_line_item_extended_fields.sql +24 -0
  186. package/PCM/src/migrations/023_add_base_price_fields.sql +8 -0
  187. package/PCM/src/migrations/run-migrations.js +46 -0
  188. package/PCM/src/models/ApprovalOTP.js +51 -0
  189. package/PCM/src/models/ApprovalToken.js +79 -0
  190. package/PCM/src/models/ChangeHistory.js +107 -0
  191. package/PCM/src/models/Deal.js +186 -0
  192. package/PCM/src/models/DealIdCounter.js +28 -0
  193. package/PCM/src/models/LineItem.js +227 -0
  194. package/PCM/src/models/LineItemCreative.js +89 -0
  195. package/PCM/src/models/LineItemInventory.js +115 -0
  196. package/PCM/src/models/PublisherInsertionOrder.js +93 -0
  197. package/PCM/src/models/TransactionHistory.js +34 -0
  198. package/PCM/src/models/associations.js +81 -0
  199. package/PCM/src/routes/approval.js +321 -0
  200. package/PCM/src/routes/creatives.js +437 -0
  201. package/PCM/src/routes/deals.js +1638 -0
  202. package/PCM/src/routes/digitalSignage.js +242 -0
  203. package/PCM/src/routes/insertionOrders.js +380 -0
  204. package/PCM/src/routes/lineItems.js +926 -0
  205. package/PCM/src/routes/system.js +384 -0
  206. package/PCM/src/services/ApprovalService.js +885 -0
  207. package/PCM/src/services/CampaignImportConverter.js +631 -0
  208. package/PCM/src/services/CampaignModeService.js +273 -0
  209. package/PCM/src/services/CampaignStatusService.js +395 -0
  210. package/PCM/src/services/ChangeHistoryService.js +316 -0
  211. package/PCM/src/services/DealIdService.js +94 -0
  212. package/PCM/src/services/DealResponseFormatter.js +90 -0
  213. package/PCM/src/services/EmailNotificationService.js +315 -0
  214. package/PCM/src/services/LineItemResponseFormatter.js +122 -0
  215. package/PCM/src/services/LineItemStatusService.js +380 -0
  216. package/PCM/src/tests/comprehensiveTestRunner.js +360 -0
  217. package/PCM/src/tests/comprehensiveTests.js +1277 -0
  218. package/PCM/src/tests/dealTypeUnitTests.js +1058 -0
  219. package/PCM/src/tests/testRunner.js +248 -0
  220. package/PCM/src/utils/caseConverter.js +92 -0
  221. package/PCM/src/utils/dealCalculations.js +206 -0
  222. package/PCM/src/utils/lineItemPayloadNormalizer.js +41 -0
  223. package/PCM/src/utils/payloadNormalizer.js +34 -0
  224. package/PCM/src/utils/sourceNormalizer.js +56 -0
  225. package/PCM/src/validators/creativeValidator.js +27 -0
  226. package/PCM/src/validators/dealValidator.js +203 -0
  227. package/PCM/src/validators/lineItemValidator.js +489 -0
  228. package/PCM/tests/approval-flows.test.js +238 -0
  229. package/PCM/tests/approval-workflow.test.js +291 -0
  230. package/PCM/tests/campaign-import-converter.test.js +543 -0
  231. package/PCM/tests/campaign-import-e2e.test.js +520 -0
  232. package/PCM/tests/campaign-status.test.js +539 -0
  233. package/PCM/tests/direct-publisher-split-reimport.test.js +460 -0
  234. package/PCM/tests/e2e/digital-signage.test.js +145 -0
  235. package/PCM/tests/e2e/search-filter-pagination.test.js +399 -0
  236. package/PCM/tests/e2e-comprehensive.test.js +3446 -0
  237. package/PCM/tests/edge-cases.test.js +340 -0
  238. package/PCM/tests/line-item-status.test.js +340 -0
  239. package/PCM/tests/seller-account-external-ids.test.js +877 -0
  240. package/PCM/tests/source-validation.test.js +324 -0
  241. package/PRD.md +3373 -0
  242. package/README.md +186 -0
  243. package/client/index.html +35 -0
  244. package/client/public/DEMO_STATUS.md +579 -0
  245. package/client/public/img/MW-logo-trans_1754045676555.png +0 -0
  246. package/client/public/locales/ar/approval.json +144 -0
  247. package/client/public/locales/ar/buyer.json +61 -0
  248. package/client/public/locales/ar/campaigns.json +1 -0
  249. package/client/public/locales/ar/common.json +218 -0
  250. package/client/public/locales/ar/contentHub.json +266 -0
  251. package/client/public/locales/ar/creatives.json +79 -0
  252. package/client/public/locales/ar/dashboard.json +57 -0
  253. package/client/public/locales/ar/deals.json +886 -0
  254. package/client/public/locales/ar/dsp.json +131 -0
  255. package/client/public/locales/ar/inventory.json +201 -0
  256. package/client/public/locales/ar/lineItems.json +553 -0
  257. package/client/public/locales/ar/navigation.json +48 -0
  258. package/client/public/locales/ar/wizard.json +1 -0
  259. package/client/public/locales/en/approval.json +144 -0
  260. package/client/public/locales/en/buyer.json +65 -0
  261. package/client/public/locales/en/campaigns.json +1 -0
  262. package/client/public/locales/en/common.json +218 -0
  263. package/client/public/locales/en/contentHub.json +266 -0
  264. package/client/public/locales/en/creatives.json +79 -0
  265. package/client/public/locales/en/dashboard.json +57 -0
  266. package/client/public/locales/en/deals.json +886 -0
  267. package/client/public/locales/en/dsp.json +131 -0
  268. package/client/public/locales/en/inventory.json +201 -0
  269. package/client/public/locales/en/lineItems.json +659 -0
  270. package/client/public/locales/en/navigation.json +48 -0
  271. package/client/public/locales/en/wizard.json +1 -0
  272. package/client/public/locales/ja/approval.json +144 -0
  273. package/client/public/locales/ja/buyer.json +61 -0
  274. package/client/public/locales/ja/campaigns.json +1 -0
  275. package/client/public/locales/ja/common.json +218 -0
  276. package/client/public/locales/ja/contentHub.json +266 -0
  277. package/client/public/locales/ja/creatives.json +79 -0
  278. package/client/public/locales/ja/dashboard.json +57 -0
  279. package/client/public/locales/ja/deals.json +886 -0
  280. package/client/public/locales/ja/dsp.json +131 -0
  281. package/client/public/locales/ja/inventory.json +201 -0
  282. package/client/public/locales/ja/lineItems.json +553 -0
  283. package/client/public/locales/ja/navigation.json +48 -0
  284. package/client/public/locales/ja/wizard.json +1 -0
  285. package/client/public/locales/zh/approval.json +144 -0
  286. package/client/public/locales/zh/buyer.json +61 -0
  287. package/client/public/locales/zh/campaigns.json +1 -0
  288. package/client/public/locales/zh/common.json +218 -0
  289. package/client/public/locales/zh/contentHub.json +266 -0
  290. package/client/public/locales/zh/creatives.json +79 -0
  291. package/client/public/locales/zh/dashboard.json +57 -0
  292. package/client/public/locales/zh/deals.json +886 -0
  293. package/client/public/locales/zh/dsp.json +131 -0
  294. package/client/public/locales/zh/inventory.json +201 -0
  295. package/client/public/locales/zh/lineItems.json +553 -0
  296. package/client/public/locales/zh/navigation.json +48 -0
  297. package/client/public/locales/zh/wizard.json +1 -0
  298. package/client/public/manifest.json +36 -0
  299. package/client/src/App.tsx +464 -0
  300. package/client/src/components/app-sidebar.tsx +312 -0
  301. package/client/src/components/approval/approval-decision-form.test.tsx +294 -0
  302. package/client/src/components/approval/approval-decision-form.tsx +326 -0
  303. package/client/src/components/approval/approval-sheet.tsx +631 -0
  304. package/client/src/components/approval/line-item-details-sheet.tsx +371 -0
  305. package/client/src/components/approval/otp-verification.test.tsx +337 -0
  306. package/client/src/components/approval/otp-verification.tsx +180 -0
  307. package/client/src/components/content-hub/bulk-transcode-dialog.tsx +379 -0
  308. package/client/src/components/content-hub/content-hub-manager-v2.tsx +574 -0
  309. package/client/src/components/content-hub/content-hub-manager.tsx +330 -0
  310. package/client/src/components/content-hub/creative-card.tsx +456 -0
  311. package/client/src/components/content-hub/creative-detail-sheet.tsx +685 -0
  312. package/client/src/components/content-hub/creative-filters.tsx +457 -0
  313. package/client/src/components/content-hub/creative-grid.tsx +329 -0
  314. package/client/src/components/content-hub/creative-selector.tsx +415 -0
  315. package/client/src/components/content-hub/creative-upload.tsx +547 -0
  316. package/client/src/components/content-hub/folder-dialogs.tsx +445 -0
  317. package/client/src/components/content-hub/folder-list.tsx +280 -0
  318. package/client/src/components/content-hub/review-dialogs.tsx +268 -0
  319. package/client/src/components/content-hub/transcode-dialog.tsx +226 -0
  320. package/client/src/components/creative-library/creative-details-view.tsx +446 -0
  321. package/client/src/components/creative-library/creative-filters-panel.tsx +203 -0
  322. package/client/src/components/creative-library/creative-list.tsx +360 -0
  323. package/client/src/components/creative-library/creative-status-badge.tsx +71 -0
  324. package/client/src/components/creative-library/folder-card.tsx +78 -0
  325. package/client/src/components/creative-library/index.ts +27 -0
  326. package/client/src/components/creative-library/new-creative-card.tsx +211 -0
  327. package/client/src/components/creative-library/upload-creative-dialog.tsx +261 -0
  328. package/client/src/components/dashboard-overview.tsx +109 -0
  329. package/client/src/components/deals/approval-history-panel.test.tsx +240 -0
  330. package/client/src/components/deals/approval-history-panel.tsx +156 -0
  331. package/client/src/components/deals/deal-status-badge.tsx +92 -0
  332. package/client/src/components/deals/import-from-planner-dialog.tsx +399 -0
  333. package/client/src/components/deals/market-insights-panel.tsx +237 -0
  334. package/client/src/components/deals/reopen-deal-sheet.tsx +191 -0
  335. package/client/src/components/deals/request-approval-sheet.test.tsx +323 -0
  336. package/client/src/components/deals/request-approval-sheet.tsx +136 -0
  337. package/client/src/components/deals/resend-approval-sheet.tsx +201 -0
  338. package/client/src/components/direct-campaigns/campaign-card.tsx +283 -0
  339. package/client/src/components/direct-campaigns/deal-filter-panel.tsx +325 -0
  340. package/client/src/components/inventory/advanced-filters-panel.tsx +273 -0
  341. package/client/src/components/inventory/csv-upload-modal.tsx +639 -0
  342. package/client/src/components/inventory/inventory-availability-view.tsx +486 -0
  343. package/client/src/components/inventory/inventory-details-sheet.tsx +376 -0
  344. package/client/src/components/inventory/inventory-map-view.tsx +596 -0
  345. package/client/src/components/inventory/inventory-settings-menu.tsx +52 -0
  346. package/client/src/components/language-switcher.tsx +53 -0
  347. package/client/src/components/line-items/campaign-forecast-panel.tsx +138 -0
  348. package/client/src/components/line-items/form-insights.tsx +89 -0
  349. package/client/src/components/line-items/geofencing/LocationCsvUploadDrawer.tsx +100 -0
  350. package/client/src/components/line-items/geofencing/POIDropdown.tsx +379 -0
  351. package/client/src/components/line-items/geofencing/SelectedLocationsSidebar.tsx +436 -0
  352. package/client/src/components/line-items/geofencing/ViewFileLocationDrawer.tsx +199 -0
  353. package/client/src/components/line-items/geofencing/components/ExistingFilesTab.tsx +268 -0
  354. package/client/src/components/line-items/geofencing/components/TemplateDownloadSection.tsx +59 -0
  355. package/client/src/components/line-items/geofencing/components/UploadTab.tsx +215 -0
  356. package/client/src/components/line-items/geofencing-map.tsx +1270 -0
  357. package/client/src/components/line-items/inventory-availability-section.tsx +178 -0
  358. package/client/src/components/line-items/line-item-schedule-manager.tsx +313 -0
  359. package/client/src/components/line-items/manual-inventory-drawer.tsx +346 -0
  360. package/client/src/components/line-items/planner-inventory-card.tsx +495 -0
  361. package/client/src/components/line-items/planner-schedule-grid.tsx +495 -0
  362. package/client/src/components/line-items/schedule-rule-editor.tsx +649 -0
  363. package/client/src/components/line-items/schedule-rule-types.ts +122 -0
  364. package/client/src/components/line-items/steps/creatives-step.tsx +681 -0
  365. package/client/src/components/line-items/steps/inventory-schedule-step.tsx +1596 -0
  366. package/client/src/components/line-items/steps/inventory-step.tsx +1533 -0
  367. package/client/src/components/line-items/steps/line-item-details-step.tsx +916 -0
  368. package/client/src/components/line-items/steps/schedule-step.tsx +273 -0
  369. package/client/src/components/line-items/steps/summary-step.tsx +680 -0
  370. package/client/src/components/line-items/steps/targeting-step.tsx +1708 -0
  371. package/client/src/components/product-switcher.tsx +105 -0
  372. package/client/src/components/protected-route.tsx +49 -0
  373. package/client/src/components/skip-link.tsx +22 -0
  374. package/client/src/components/stat-card.tsx +53 -0
  375. package/client/src/components/status-badge.tsx +96 -0
  376. package/client/src/components/ui/hierarchical-venue-selector.tsx +389 -0
  377. package/client/src/components/ui/toaster.tsx +111 -0
  378. package/client/src/contexts/auth-context.tsx +181 -0
  379. package/client/src/contexts/sidebar-state.tsx +50 -0
  380. package/client/src/contexts/theme-context.tsx +66 -0
  381. package/client/src/data/campaign-data.json +107 -0
  382. package/client/src/data/countries.json +22 -0
  383. package/client/src/hooks/use-approval.ts +366 -0
  384. package/client/src/hooks/use-keyboard-shortcuts.ts +74 -0
  385. package/client/src/hooks/use-media-query.ts +46 -0
  386. package/client/src/hooks/use-mobile.tsx +19 -0
  387. package/client/src/hooks/use-page-title.ts +21 -0
  388. package/client/src/hooks/use-toast.ts +195 -0
  389. package/client/src/index.css +694 -0
  390. package/client/src/lib/__tests__/accessibility.test.ts +104 -0
  391. package/client/src/lib/__tests__/date-utils.test.ts +199 -0
  392. package/client/src/lib/__tests__/dsp-buyer-api.test.ts +127 -0
  393. package/client/src/lib/__tests__/dsp-buyer-integration.test.ts +247 -0
  394. package/client/src/lib/__tests__/storage-utils.test.ts +167 -0
  395. package/client/src/lib/__tests__/utils.test.ts +57 -0
  396. package/client/src/lib/accessibility.ts +141 -0
  397. package/client/src/lib/api-config.ts +9 -0
  398. package/client/src/lib/auth-service.ts +209 -0
  399. package/client/src/lib/campaign-creative-api.ts +82 -0
  400. package/client/src/lib/company-api.ts +61 -0
  401. package/client/src/lib/content-hub-api.ts +407 -0
  402. package/client/src/lib/creative-mapper.ts +61 -0
  403. package/client/src/lib/date-utils.ts +119 -0
  404. package/client/src/lib/deal-helpers.ts +220 -0
  405. package/client/src/lib/dsp-buyer-api.ts +196 -0
  406. package/client/src/lib/geo-import-api.ts +151 -0
  407. package/client/src/lib/google-poi-api.ts +305 -0
  408. package/client/src/lib/i18n/__tests__/formatting.test.ts +202 -0
  409. package/client/src/lib/i18n/formatting.ts +130 -0
  410. package/client/src/lib/i18n/index.ts +8 -0
  411. package/client/src/lib/i18n-compat.ts +76 -0
  412. package/client/src/lib/influence-deals-api.ts +896 -0
  413. package/client/src/lib/inventory-api.ts +399 -0
  414. package/client/src/lib/oauth-service.ts +678 -0
  415. package/client/src/lib/poi-types.ts +75 -0
  416. package/client/src/lib/queryClient.ts +144 -0
  417. package/client/src/lib/recommendation-api.ts +380 -0
  418. package/client/src/lib/storage-utils.ts +104 -0
  419. package/client/src/lib/tolgee.ts +85 -0
  420. package/client/src/lib/utils.ts +0 -0
  421. package/client/src/main.tsx +67 -0
  422. package/client/src/mapbox-draw-modes.d.ts +32 -0
  423. package/client/src/pages/all-folders.tsx +203 -0
  424. package/client/src/pages/auth-callback.tsx +115 -0
  425. package/client/src/pages/buyer-form.tsx +339 -0
  426. package/client/src/pages/buyer-list.tsx +622 -0
  427. package/client/src/pages/content-hub.tsx +1358 -0
  428. package/client/src/pages/create-deal.tsx +2093 -0
  429. package/client/src/pages/creative-assignment-page.tsx +548 -0
  430. package/client/src/pages/creatives.tsx +5 -0
  431. package/client/src/pages/custom-pois.tsx +425 -0
  432. package/client/src/pages/dashboard.tsx +615 -0
  433. package/client/src/pages/deal-history.tsx +434 -0
  434. package/client/src/pages/deal-line-items.tsx +1703 -0
  435. package/client/src/pages/demo-status.tsx +113 -0
  436. package/client/src/pages/direct-campaign-details.tsx +361 -0
  437. package/client/src/pages/direct-campaigns-new.tsx +824 -0
  438. package/client/src/pages/dsp-form.tsx +803 -0
  439. package/client/src/pages/dsp-list.tsx +239 -0
  440. package/client/src/pages/folder-content.tsx +336 -0
  441. package/client/src/pages/integrations.tsx +429 -0
  442. package/client/src/pages/line-item-creatives.tsx +789 -0
  443. package/client/src/pages/line-item-detail-page.tsx +684 -0
  444. package/client/src/pages/line-item-form-page.tsx +3261 -0
  445. package/client/src/pages/line-item-wizard.tsx +1207 -0
  446. package/client/src/pages/login.tsx +154 -0
  447. package/client/src/pages/not-found.tsx +23 -0
  448. package/client/src/pages/proof-of-play.tsx +397 -0
  449. package/client/src/pages/public-approval.tsx +551 -0
  450. package/client/src/pages/reports.tsx +231 -0
  451. package/client/src/pages/settings.tsx +760 -0
  452. package/client/src/pages/signals.tsx +389 -0
  453. package/client/src/pages/tags.tsx +318 -0
  454. package/client/src/pages/test-results.tsx +328 -0
  455. package/client/src/store/hooks.ts +5 -0
  456. package/client/src/store/index.ts +15 -0
  457. package/client/src/store/mapMarkerLocationsSlice.ts +241 -0
  458. package/client/src/styles/design-tokens.css +324 -0
  459. package/client/src/test/setup.ts +261 -0
  460. package/client/src/test/test-utils.tsx +40 -0
  461. package/client/src/types/approval.ts +221 -0
  462. package/client/src/types/content-hub.ts +209 -0
  463. package/client/src/types/geofencing.ts +67 -0
  464. package/client/src/types/transcoding.ts +140 -0
  465. package/client/src/vite-env.d.ts +18 -0
  466. package/components.json +20 -0
  467. package/creative-api.json +1 -0
  468. package/docs/AI_REFERENCE.md +459 -0
  469. package/docs/MWDesign-Prompt.md +132 -0
  470. package/docs/MWDesign-System.md +344 -0
  471. package/docs/test-plan.md +277 -0
  472. package/e2e/AUTONOMOUS-TESTING.md +406 -0
  473. package/e2e/README.md +219 -0
  474. package/e2e/autonomous-flow.spec.ts +308 -0
  475. package/e2e/debug-sso.spec.ts +163 -0
  476. package/e2e/direct-campaigns.spec.ts +219 -0
  477. package/e2e/explore-sso.spec.ts +149 -0
  478. package/e2e/fixtures/auth.ts +26 -0
  479. package/e2e/fixtures/enhanced-test.ts +331 -0
  480. package/e2e/pagination.spec.ts +280 -0
  481. package/e2e/view-toggle.spec.ts +312 -0
  482. package/generated-icon.png +0 -0
  483. package/i18next-scanner.config.cjs +46 -0
  484. package/package.json +141 -0
  485. package/playwright.config.ts +93 -0
  486. package/postcss.config.js +6 -0
  487. package/replit.md +196 -0
  488. package/screenshot-after-login.png +0 -0
  489. package/screenshot-contenthub-grid.png +0 -0
  490. package/screenshot-contenthub-list-fixed.png +0 -0
  491. package/screenshot-contenthub-list.png +0 -0
  492. package/screenshot-create-deal.png +0 -0
  493. package/screenshot-dashboard.png +0 -0
  494. package/screenshot-deals.png +0 -0
  495. package/screenshot-login-filled.png +0 -0
  496. package/screenshot-login.png +0 -0
  497. package/screenshot.mjs +24 -0
  498. package/scripts/deploy-stg.sh +185 -0
  499. package/shared/direct-io-schema.ts +383 -0
  500. package/shared/schema.ts +439 -0
  501. package/shared/screen-types.ts +149 -0
  502. package/springdocDefault.json +1 -0
  503. package/swagger-ui-bundle.js +2 -0
  504. package/swagger-ui-init.js +10316 -0
  505. package/tailwind.config.ts +282 -0
  506. package/terraform/README.md +306 -0
  507. package/terraform/cloudfront.tf +289 -0
  508. package/terraform/ecs.tf +727 -0
  509. package/terraform/environments/dev.tfvars +59 -0
  510. package/terraform/environments/production.tfvars +60 -0
  511. package/terraform/main.tf +47 -0
  512. package/terraform/outputs.tf +145 -0
  513. package/terraform/s3.tf +192 -0
  514. package/terraform/variables.tf +226 -0
  515. package/terraform/waf.tf +165 -0
  516. package/terraform-frontend/.terraform.lock.hcl +25 -0
  517. package/terraform-frontend/README.md +85 -0
  518. package/terraform-frontend/cloudfront.tf +125 -0
  519. package/terraform-frontend/main.tf +31 -0
  520. package/terraform-frontend/outputs.tf +24 -0
  521. package/terraform-frontend/terraform.tfvars +12 -0
  522. package/terraform-frontend/variables.tf +53 -0
  523. package/tsconfig.json +23 -0
  524. package/vite.config.ts +226 -0
  525. package/vitest.config.ts +56 -0
@@ -0,0 +1,86 @@
1
+ -- Migration: Fix line_item_id FK references to use line_items.id (UUID) instead of external_id
2
+ -- This migration converts the line_item_id column in line_item_inventories and line_item_creatives
3
+ -- from TEXT (referencing external_id) to UUID (referencing id)
4
+
5
+ -- Check if migration is already applied by checking if line_item_id is already UUID type
6
+ DO $$
7
+ DECLARE
8
+ inv_col_type TEXT;
9
+ creative_col_type TEXT;
10
+ BEGIN
11
+ -- Check line_item_inventories column type
12
+ SELECT data_type INTO inv_col_type
13
+ FROM information_schema.columns
14
+ WHERE table_name = 'line_item_inventories' AND column_name = 'line_item_id';
15
+
16
+ -- Check line_item_creatives column type
17
+ SELECT data_type INTO creative_col_type
18
+ FROM information_schema.columns
19
+ WHERE table_name = 'line_item_creatives' AND column_name = 'line_item_id';
20
+
21
+ -- Migrate line_item_inventories if needed
22
+ IF inv_col_type = 'text' THEN
23
+ -- Add temporary UUID column
24
+ ALTER TABLE line_item_inventories ADD COLUMN IF NOT EXISTS line_item_uuid UUID;
25
+
26
+ -- Populate with UUIDs by joining with line_items
27
+ UPDATE line_item_inventories inv
28
+ SET line_item_uuid = li.id
29
+ FROM line_items li
30
+ WHERE inv.line_item_id = li.external_id AND inv.line_item_uuid IS NULL;
31
+
32
+ -- Drop old FK constraint if exists
33
+ ALTER TABLE line_item_inventories
34
+ DROP CONSTRAINT IF EXISTS line_item_inventories_line_item_id_fkey;
35
+
36
+ -- Drop old PK constraint
37
+ ALTER TABLE line_item_inventories
38
+ DROP CONSTRAINT IF EXISTS line_item_inventories_pkey;
39
+
40
+ -- Drop old column and rename new one
41
+ ALTER TABLE line_item_inventories DROP COLUMN line_item_id;
42
+ ALTER TABLE line_item_inventories RENAME COLUMN line_item_uuid TO line_item_id;
43
+
44
+ -- Recreate PK constraint
45
+ ALTER TABLE line_item_inventories
46
+ ADD CONSTRAINT line_item_inventories_pkey PRIMARY KEY (id, line_item_id);
47
+
48
+ -- Add new FK constraint referencing line_items.id
49
+ ALTER TABLE line_item_inventories
50
+ ADD CONSTRAINT line_item_inventories_line_item_id_fkey
51
+ FOREIGN KEY (line_item_id) REFERENCES line_items(id) ON DELETE CASCADE;
52
+
53
+ RAISE NOTICE 'Migrated line_item_inventories.line_item_id to UUID';
54
+ ELSE
55
+ RAISE NOTICE 'line_item_inventories.line_item_id already migrated (type: %)', inv_col_type;
56
+ END IF;
57
+
58
+ -- Migrate line_item_creatives if needed
59
+ IF creative_col_type = 'text' THEN
60
+ -- Add temporary UUID column
61
+ ALTER TABLE line_item_creatives ADD COLUMN IF NOT EXISTS line_item_uuid UUID;
62
+
63
+ -- Populate with UUIDs by joining with line_items
64
+ UPDATE line_item_creatives c
65
+ SET line_item_uuid = li.id
66
+ FROM line_items li
67
+ WHERE c.line_item_id = li.external_id AND c.line_item_uuid IS NULL;
68
+
69
+ -- Drop old FK constraint if exists
70
+ ALTER TABLE line_item_creatives
71
+ DROP CONSTRAINT IF EXISTS line_item_creatives_line_item_id_fkey;
72
+
73
+ -- Drop old column and rename new one
74
+ ALTER TABLE line_item_creatives DROP COLUMN line_item_id;
75
+ ALTER TABLE line_item_creatives RENAME COLUMN line_item_uuid TO line_item_id;
76
+
77
+ -- Add new FK constraint referencing line_items.id
78
+ ALTER TABLE line_item_creatives
79
+ ADD CONSTRAINT line_item_creatives_line_item_id_fkey
80
+ FOREIGN KEY (line_item_id) REFERENCES line_items(id) ON DELETE CASCADE;
81
+
82
+ RAISE NOTICE 'Migrated line_item_creatives.line_item_id to UUID';
83
+ ELSE
84
+ RAISE NOTICE 'line_item_creatives.line_item_id already migrated (type: %)', creative_col_type;
85
+ END IF;
86
+ END $$;
@@ -0,0 +1,44 @@
1
+ -- Create approval_tokens table for campaign approval workflow
2
+ CREATE TABLE IF NOT EXISTS approval_tokens (
3
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
4
+ deal_id TEXT NOT NULL REFERENCES deals(deal_id) ON DELETE CASCADE,
5
+ approver_email TEXT NOT NULL,
6
+ token TEXT NOT NULL UNIQUE,
7
+ status VARCHAR(20) NOT NULL DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'APPROVED', 'REJECTED')),
8
+ rejection_reason TEXT,
9
+ decision_at TIMESTAMP WITH TIME ZONE,
10
+ expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
11
+ otp_verified BOOLEAN NOT NULL DEFAULT FALSE,
12
+ request_id TEXT,
13
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
14
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_approval_tokens_deal_id ON approval_tokens(deal_id);
18
+ CREATE INDEX IF NOT EXISTS idx_approval_tokens_token ON approval_tokens(token);
19
+ CREATE INDEX IF NOT EXISTS idx_approval_tokens_approver_email ON approval_tokens(approver_email);
20
+ CREATE INDEX IF NOT EXISTS idx_approval_tokens_status ON approval_tokens(status);
21
+
22
+ -- Create approval_otps table for OTP verification
23
+ CREATE TABLE IF NOT EXISTS approval_otps (
24
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
25
+ approval_token_id UUID NOT NULL REFERENCES approval_tokens(id) ON DELETE CASCADE,
26
+ otp_code TEXT NOT NULL,
27
+ expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
28
+ verified BOOLEAN NOT NULL DEFAULT FALSE,
29
+ attempts INTEGER NOT NULL DEFAULT 0,
30
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
31
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
32
+ );
33
+
34
+ CREATE INDEX IF NOT EXISTS idx_approval_otps_approval_token_id ON approval_otps(approval_token_id);
35
+ CREATE INDEX IF NOT EXISTS idx_approval_otps_otp_code ON approval_otps(otp_code);
36
+
37
+ -- Add approval_emails column to deals table if not exists
38
+ DO $$
39
+ BEGIN
40
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
41
+ WHERE table_name = 'deals' AND column_name = 'approval_emails') THEN
42
+ ALTER TABLE deals ADD COLUMN approval_emails JSONB DEFAULT '[]'::jsonb;
43
+ END IF;
44
+ END $$;
@@ -0,0 +1,2 @@
1
+ -- Add encrypted_token column to approval_tokens table
2
+ ALTER TABLE approval_tokens ADD COLUMN IF NOT EXISTS encrypted_token TEXT;
@@ -0,0 +1,10 @@
1
+ -- Add rejection_reason column to deals table for storing the reason when a campaign is rejected
2
+ DO $$
3
+ BEGIN
4
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
5
+ WHERE table_name = 'deals' AND column_name = 'rejection_reason') THEN
6
+ ALTER TABLE deals ADD COLUMN rejection_reason TEXT;
7
+ END IF;
8
+ END $$;
9
+
10
+ CREATE INDEX IF NOT EXISTS idx_deals_rejection_reason ON deals(rejection_reason) WHERE rejection_reason IS NOT NULL;
@@ -0,0 +1,12 @@
1
+ -- Migration 021: Add publisher_external_id column to line_item_inventories table
2
+
3
+ DO $$
4
+ BEGIN
5
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
6
+ WHERE table_name = 'line_item_inventories' AND column_name = 'publisher_external_id') THEN
7
+ ALTER TABLE line_item_inventories ADD COLUMN publisher_external_id TEXT;
8
+ END IF;
9
+ END $$;
10
+
11
+ CREATE INDEX IF NOT EXISTS idx_line_item_inventories_publisher_external_id
12
+ ON line_item_inventories(publisher_external_id) WHERE publisher_external_id IS NOT NULL;
@@ -0,0 +1,24 @@
1
+ -- Migration: Add extended fields to line_items table
2
+ -- Fields: priority, custom_fees, frequency_cap, traffic_allocation, inventory_source
3
+
4
+ -- Add priority field (integer 1-10)
5
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS priority INTEGER;
6
+
7
+ -- Add custom_fees field (JSONB array of fee objects)
8
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS custom_fees JSONB;
9
+
10
+ -- Add frequency_cap field (JSONB object with period and target)
11
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS frequency_cap JSONB;
12
+
13
+ -- Add traffic_allocation field (percentage 0-100)
14
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS traffic_allocation DECIMAL(5,2);
15
+
16
+ -- Add inventory_source field (string)
17
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS inventory_source TEXT;
18
+
19
+ -- Add check constraints for validation
20
+ ALTER TABLE line_items DROP CONSTRAINT IF EXISTS check_priority_range;
21
+ ALTER TABLE line_items ADD CONSTRAINT check_priority_range CHECK (priority IS NULL OR (priority >= 1 AND priority <= 10));
22
+
23
+ ALTER TABLE line_items DROP CONSTRAINT IF EXISTS check_traffic_allocation_range;
24
+ ALTER TABLE line_items ADD CONSTRAINT check_traffic_allocation_range CHECK (traffic_allocation IS NULL OR (traffic_allocation >= 0 AND traffic_allocation <= 100));
@@ -0,0 +1,8 @@
1
+ -- Migration: Add base price fields to line_items table
2
+ -- Fields: bid_floor_base (PROGRAMMATIC), pricing (DIRECT with estimatedCostBase, cpmBase)
3
+
4
+ -- Add bid_floor_base field for PROGRAMMATIC mode (base price before custom fees)
5
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS bid_floor_base DECIMAL(12, 2);
6
+
7
+ -- Add pricing JSONB field for DIRECT mode (contains estimatedCostBase, cpmBase)
8
+ ALTER TABLE line_items ADD COLUMN IF NOT EXISTS pricing JSONB;
@@ -0,0 +1,46 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import sequelize from '../config/db.js';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ async function runMigrations() {
10
+ try {
11
+ await sequelize.authenticate();
12
+ console.log('Database connection established for migrations.');
13
+
14
+ const migrationsDir = __dirname;
15
+ const sqlFiles = fs.readdirSync(migrationsDir)
16
+ .filter(f => f.endsWith('.sql'))
17
+ .sort();
18
+
19
+ let hasErrors = false;
20
+ for (const file of sqlFiles) {
21
+ console.log(`Running migration: ${file}`);
22
+ const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf8');
23
+
24
+ try {
25
+ await sequelize.query(sql);
26
+ console.log(` ✓ Migration ${file} completed successfully`);
27
+ } catch (error) {
28
+ console.error(` ✗ Migration ${file} failed: ${error.message}`);
29
+ hasErrors = true;
30
+ }
31
+ }
32
+
33
+ if (hasErrors) {
34
+ console.error('Some migrations failed. Please review errors above.');
35
+ process.exit(1);
36
+ }
37
+
38
+ console.log('All migrations completed successfully.');
39
+ process.exit(0);
40
+ } catch (error) {
41
+ console.error('Migration failed:', error.message);
42
+ process.exit(1);
43
+ }
44
+ }
45
+
46
+ runMigrations();
@@ -0,0 +1,51 @@
1
+ import { DataTypes } from 'sequelize';
2
+ import sequelize from '../config/db.js';
3
+
4
+ const ApprovalOTP = sequelize.define('ApprovalOTP', {
5
+ id: {
6
+ type: DataTypes.UUID,
7
+ defaultValue: DataTypes.UUIDV4,
8
+ primaryKey: true
9
+ },
10
+ approval_token_id: {
11
+ type: DataTypes.UUID,
12
+ field: 'approval_token_id',
13
+ allowNull: false,
14
+ references: {
15
+ model: 'approval_tokens',
16
+ key: 'id'
17
+ },
18
+ onDelete: 'CASCADE'
19
+ },
20
+ otp_code: {
21
+ type: DataTypes.TEXT,
22
+ field: 'otp_code',
23
+ allowNull: false
24
+ },
25
+ expires_at: {
26
+ type: DataTypes.DATE,
27
+ field: 'expires_at',
28
+ allowNull: false
29
+ },
30
+ verified: {
31
+ type: DataTypes.BOOLEAN,
32
+ allowNull: false,
33
+ defaultValue: false
34
+ },
35
+ attempts: {
36
+ type: DataTypes.INTEGER,
37
+ allowNull: false,
38
+ defaultValue: 0
39
+ }
40
+ }, {
41
+ tableName: 'approval_otps',
42
+ timestamps: true,
43
+ createdAt: 'created_at',
44
+ updatedAt: 'updated_at',
45
+ indexes: [
46
+ { fields: ['approval_token_id'] },
47
+ { fields: ['otp_code'] }
48
+ ]
49
+ });
50
+
51
+ export default ApprovalOTP;
@@ -0,0 +1,79 @@
1
+ import { DataTypes } from 'sequelize';
2
+ import sequelize from '../config/db.js';
3
+
4
+ const ApprovalToken = sequelize.define('ApprovalToken', {
5
+ id: {
6
+ type: DataTypes.UUID,
7
+ defaultValue: DataTypes.UUIDV4,
8
+ primaryKey: true
9
+ },
10
+ deal_id: {
11
+ type: DataTypes.TEXT,
12
+ field: 'deal_id',
13
+ allowNull: false,
14
+ references: {
15
+ model: 'deals',
16
+ key: 'deal_id'
17
+ },
18
+ onDelete: 'CASCADE'
19
+ },
20
+ approver_email: {
21
+ type: DataTypes.TEXT,
22
+ field: 'approver_email',
23
+ allowNull: false
24
+ },
25
+ token: {
26
+ type: DataTypes.TEXT,
27
+ allowNull: false,
28
+ unique: true
29
+ },
30
+ encrypted_token: {
31
+ type: DataTypes.TEXT,
32
+ field: 'encrypted_token',
33
+ allowNull: true
34
+ },
35
+ status: {
36
+ type: DataTypes.ENUM('PENDING', 'APPROVED', 'REJECTED'),
37
+ allowNull: false,
38
+ defaultValue: 'PENDING'
39
+ },
40
+ rejection_reason: {
41
+ type: DataTypes.TEXT,
42
+ field: 'rejection_reason',
43
+ allowNull: true
44
+ },
45
+ decision_at: {
46
+ type: DataTypes.DATE,
47
+ field: 'decision_at',
48
+ allowNull: true
49
+ },
50
+ expires_at: {
51
+ type: DataTypes.DATE,
52
+ field: 'expires_at',
53
+ allowNull: false
54
+ },
55
+ otp_verified: {
56
+ type: DataTypes.BOOLEAN,
57
+ field: 'otp_verified',
58
+ allowNull: false,
59
+ defaultValue: false
60
+ },
61
+ request_id: {
62
+ type: DataTypes.TEXT,
63
+ field: 'request_id',
64
+ allowNull: true
65
+ }
66
+ }, {
67
+ tableName: 'approval_tokens',
68
+ timestamps: true,
69
+ createdAt: 'created_at',
70
+ updatedAt: 'updated_at',
71
+ indexes: [
72
+ { fields: ['deal_id'] },
73
+ { fields: ['token'] },
74
+ { fields: ['approver_email'] },
75
+ { fields: ['status'] }
76
+ ]
77
+ });
78
+
79
+ export default ApprovalToken;
@@ -0,0 +1,107 @@
1
+ import { DataTypes } from 'sequelize';
2
+ import sequelize from '../config/db.js';
3
+
4
+ const ChangeHistory = sequelize.define('ChangeHistory', {
5
+ id: {
6
+ type: DataTypes.UUID,
7
+ defaultValue: DataTypes.UUIDV4,
8
+ primaryKey: true
9
+ },
10
+ entity_type: {
11
+ type: DataTypes.ENUM('DEAL', 'LINE_ITEM'),
12
+ allowNull: false,
13
+ field: 'entity_type'
14
+ },
15
+ entity_id: {
16
+ type: DataTypes.UUID,
17
+ allowNull: false,
18
+ field: 'entity_id'
19
+ },
20
+ deal_id: {
21
+ type: DataTypes.TEXT,
22
+ allowNull: true,
23
+ field: 'deal_id'
24
+ },
25
+ line_item_id: {
26
+ type: DataTypes.TEXT,
27
+ allowNull: true,
28
+ field: 'line_item_id'
29
+ },
30
+ action: {
31
+ type: DataTypes.ENUM('CREATE', 'UPDATE', 'DELETE', 'STATUS_CHANGE'),
32
+ allowNull: false
33
+ },
34
+ field_name: {
35
+ type: DataTypes.TEXT,
36
+ allowNull: true,
37
+ field: 'field_name'
38
+ },
39
+ previous_value: {
40
+ type: DataTypes.JSONB,
41
+ allowNull: true,
42
+ field: 'previous_value'
43
+ },
44
+ current_value: {
45
+ type: DataTypes.JSONB,
46
+ allowNull: true,
47
+ field: 'current_value'
48
+ },
49
+ changed_by: {
50
+ type: DataTypes.TEXT,
51
+ allowNull: true,
52
+ field: 'changed_by'
53
+ },
54
+ changed_by_email: {
55
+ type: DataTypes.TEXT,
56
+ allowNull: true,
57
+ field: 'changed_by_email'
58
+ },
59
+ request_id: {
60
+ type: DataTypes.TEXT,
61
+ allowNull: true,
62
+ field: 'request_id'
63
+ },
64
+ ip_address: {
65
+ type: DataTypes.TEXT,
66
+ allowNull: true,
67
+ field: 'ip_address'
68
+ },
69
+ user_agent: {
70
+ type: DataTypes.TEXT,
71
+ allowNull: true,
72
+ field: 'user_agent'
73
+ },
74
+ summary: {
75
+ type: DataTypes.TEXT,
76
+ allowNull: true
77
+ },
78
+ metadata: {
79
+ type: DataTypes.JSONB,
80
+ allowNull: true,
81
+ defaultValue: {}
82
+ }
83
+ }, {
84
+ tableName: 'change_history',
85
+ timestamps: true,
86
+ createdAt: 'created_at',
87
+ updatedAt: false,
88
+ indexes: [
89
+ {
90
+ fields: ['entity_type', 'entity_id']
91
+ },
92
+ {
93
+ fields: ['deal_id']
94
+ },
95
+ {
96
+ fields: ['line_item_id']
97
+ },
98
+ {
99
+ fields: ['created_at']
100
+ },
101
+ {
102
+ fields: ['action']
103
+ }
104
+ ]
105
+ });
106
+
107
+ export default ChangeHistory;
@@ -0,0 +1,186 @@
1
+ import { DataTypes } from 'sequelize';
2
+ import sequelize from '../config/db.js';
3
+
4
+ const Deal = sequelize.define('Deal', {
5
+ id: {
6
+ type: DataTypes.UUID,
7
+ defaultValue: DataTypes.UUIDV4,
8
+ primaryKey: true
9
+ },
10
+ source: {
11
+ type: DataTypes.TEXT,
12
+ allowNull: false
13
+ },
14
+ external_id: {
15
+ type: DataTypes.TEXT,
16
+ allowNull: true,
17
+ field: 'external_id'
18
+ },
19
+ deal_id: {
20
+ type: DataTypes.TEXT,
21
+ field: 'deal_id',
22
+ unique: true
23
+ },
24
+ name: {
25
+ type: DataTypes.TEXT
26
+ },
27
+ deal_type: {
28
+ type: DataTypes.ENUM('GUARANTEED', 'PREFERRED_DEAL', 'PRIVATE_AUCTION', 'EVERGREEN_PMP', 'DIRECT'),
29
+ field: 'deal_type'
30
+ },
31
+ transaction_type: {
32
+ type: DataTypes.ENUM('SPOT', 'AUDIENCE'),
33
+ field: 'transaction_type'
34
+ },
35
+ auction_type: {
36
+ type: DataTypes.SMALLINT,
37
+ field: 'auction_type'
38
+ },
39
+ buyers: {
40
+ type: DataTypes.JSONB
41
+ },
42
+ advertiser: {
43
+ type: DataTypes.JSONB
44
+ },
45
+ seller: {
46
+ type: DataTypes.JSONB
47
+ },
48
+ currency: {
49
+ type: DataTypes.TEXT
50
+ },
51
+ cost_type: {
52
+ type: DataTypes.ENUM('CPD', 'CPM', 'CPS'),
53
+ field: 'cost_type'
54
+ },
55
+ delivery_goal: {
56
+ type: DataTypes.BIGINT,
57
+ field: 'delivery_goal'
58
+ },
59
+ net_cost: {
60
+ type: DataTypes.DECIMAL(14, 2),
61
+ field: 'net_cost'
62
+ },
63
+ net_cost_per_day: {
64
+ type: DataTypes.DECIMAL(14, 2),
65
+ field: 'net_cost_per_day'
66
+ },
67
+ timezone_id: {
68
+ type: DataTypes.TEXT,
69
+ field: 'timezone_id'
70
+ },
71
+ start_date: {
72
+ type: DataTypes.DATEONLY,
73
+ field: 'start_date'
74
+ },
75
+ end_date: {
76
+ type: DataTypes.DATEONLY,
77
+ field: 'end_date'
78
+ },
79
+ impressions: {
80
+ type: DataTypes.BIGINT
81
+ },
82
+ account: {
83
+ type: DataTypes.JSONB
84
+ },
85
+ country: {
86
+ type: DataTypes.TEXT
87
+ },
88
+ status: {
89
+ type: DataTypes.ENUM('DRAFT', 'REQUESTED', 'GENERATED', 'PENDING', 'APPROVED', 'REJECTED', 'CANCELED', 'DELETED', 'PENDING_CREATIVES', 'LIVE', 'COMPLETED', 'IN_ACTIVE', 'REOPENED', 'ARCHIVED', 'EXPIRED'),
90
+ defaultValue: 'GENERATED'
91
+ },
92
+ line_items_count: {
93
+ type: DataTypes.INTEGER,
94
+ defaultValue: 0,
95
+ field: 'line_items_count'
96
+ },
97
+ active: {
98
+ type: DataTypes.BOOLEAN,
99
+ defaultValue: true
100
+ },
101
+ is_playing: {
102
+ type: DataTypes.BOOLEAN,
103
+ defaultValue: false,
104
+ field: 'is_playing'
105
+ },
106
+ publishers: {
107
+ type: DataTypes.JSONB,
108
+ field: 'publishers'
109
+ },
110
+ metadata: {
111
+ type: DataTypes.JSONB
112
+ },
113
+ version: {
114
+ type: DataTypes.INTEGER,
115
+ defaultValue: 1
116
+ },
117
+ brand: {
118
+ type: DataTypes.TEXT
119
+ },
120
+ client_type: {
121
+ type: DataTypes.TEXT,
122
+ field: 'client_type'
123
+ },
124
+ mode: {
125
+ type: DataTypes.TEXT
126
+ },
127
+ approval_emails: {
128
+ type: DataTypes.ARRAY(DataTypes.TEXT),
129
+ field: 'approval_emails'
130
+ },
131
+ market_selection: {
132
+ type: DataTypes.JSONB,
133
+ field: 'market_selection'
134
+ },
135
+ budget_setup: {
136
+ type: DataTypes.JSONB,
137
+ field: 'budget_setup'
138
+ },
139
+ campaign_goal: {
140
+ type: DataTypes.JSONB,
141
+ field: 'campaign_goal'
142
+ },
143
+ planning: {
144
+ type: DataTypes.JSONB,
145
+ field: 'planning'
146
+ },
147
+ published: {
148
+ type: DataTypes.BOOLEAN,
149
+ defaultValue: false
150
+ },
151
+ reopened: {
152
+ type: DataTypes.BOOLEAN,
153
+ defaultValue: false
154
+ },
155
+ non_billable: {
156
+ type: DataTypes.BOOLEAN,
157
+ defaultValue: false,
158
+ field: 'non_billable'
159
+ },
160
+ stop_bid_requests: {
161
+ type: DataTypes.BOOLEAN,
162
+ defaultValue: false,
163
+ field: 'stop_bid_requests'
164
+ },
165
+ imp_multiplier_type: {
166
+ type: DataTypes.ENUM('MAD', 'CUSTOM'),
167
+ field: 'imp_multiplier_type'
168
+ },
169
+ rejection_reason: {
170
+ type: DataTypes.TEXT,
171
+ field: 'rejection_reason'
172
+ }
173
+ }, {
174
+ tableName: 'deals',
175
+ timestamps: true,
176
+ createdAt: 'created_at',
177
+ updatedAt: 'updated_at',
178
+ indexes: [
179
+ {
180
+ unique: true,
181
+ fields: ['source', 'external_id']
182
+ }
183
+ ]
184
+ });
185
+
186
+ export default Deal;
@@ -0,0 +1,28 @@
1
+ import { DataTypes } from 'sequelize';
2
+ import sequelize from '../config/db.js';
3
+
4
+ const DealIdCounter = sequelize.define('DealIdCounter', {
5
+ id: {
6
+ type: DataTypes.INTEGER,
7
+ primaryKey: true,
8
+ autoIncrement: true
9
+ },
10
+ prefix: {
11
+ type: DataTypes.STRING(10),
12
+ allowNull: false,
13
+ unique: true
14
+ },
15
+ current_value: {
16
+ type: DataTypes.BIGINT,
17
+ allowNull: false,
18
+ defaultValue: 0,
19
+ field: 'current_value'
20
+ }
21
+ }, {
22
+ tableName: 'deal_id_counters',
23
+ timestamps: true,
24
+ createdAt: 'created_at',
25
+ updatedAt: 'updated_at'
26
+ });
27
+
28
+ export default DealIdCounter;