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,32 @@
1
+ {
2
+ "name": "nodejs",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "module": "index.js",
7
+ "scripts": {
8
+ "start": "node index.js",
9
+ "test": "node --test tests/e2e-comprehensive.test.js",
10
+ "seed": "node scripts/seed-comprehensive.js",
11
+ "seed:comprehensive": "node scripts/seed-comprehensive.js",
12
+ "seed:prod": "node scripts/seed-production.js"
13
+ },
14
+ "keywords": [],
15
+ "author": "",
16
+ "license": "ISC",
17
+ "dependencies": {
18
+ "@types/node": "^24.3.1",
19
+ "cors": "^2.8.5",
20
+ "dotenv": "^17.2.3",
21
+ "express": "^5.1.0",
22
+ "joi": "^18.0.1",
23
+ "node-fetch": "^3.3.2",
24
+ "nodemon": "^3.1.10",
25
+ "pg": "^8.16.3",
26
+ "pg-hstore": "^2.3.4",
27
+ "sequelize": "^6.37.7",
28
+ "swagger-jsdoc": "^6.2.8",
29
+ "swagger-ui-express": "^5.0.1",
30
+ "uuid": "^13.0.0"
31
+ }
32
+ }
package/PCM/replit.md ADDED
@@ -0,0 +1,64 @@
1
+ # DOOH AdServer API
2
+
3
+ ## Overview
4
+ This Node.js/Express.js microservice manages Digital Out-of-Home (DOOH) advertising. It provides RESTful APIs for programmatic and direct ad deals, line items, and creative asset management. The service supports various transaction types (guaranteed, private auctions), cost models (CPD, CPM, CPS), and creative types (display, video, audio). It ensures data integrity, tracks requests, and maintains audit trails, aiming to integrate programmatic and traditional direct campaigns within the expanding DOOH market.
5
+
6
+ ## User Preferences
7
+ Preferred communication style: Simple, everyday language.
8
+
9
+ ## System Architecture
10
+
11
+ ### UI/UX Decisions
12
+ The API supports dual ID resolution (internal UUIDs or external identifiers). Responses organize mode-specific fields under `direct` and `programmatic` objects.
13
+
14
+ ### Technical Implementations
15
+ The service utilizes Express.js v5 with ES Modules. Joi is used for schema validation. A middleware pipeline handles JSON parsing, logging, routing, and centralized error handling. The API accommodates both `camelCase` and `snake_case` JSON payloads. Soft deletion is implemented for line items and deals, while creatives use hard delete. The system is designed for autoscale deployment and Replit Deployments.
16
+
17
+ ### Feature Specifications
18
+ - **Deal Management**: Supports `PROGRAMMATIC` and `DIRECT` campaign modes with specific `dealType` constraints (e.g., `GUARANTEED`, `PRIVATE_AUCTION`). Deal IDs are auto-generated. Includes `Seller`, `Account`, and `Publisher` objects.
19
+ - **Cost Models**: Supports `CPD`, `CPM`, `CPS`, with `CPS` restricted to non-guaranteed deals.
20
+ - **Status Workflow**: Deals progress through statuses like `DRAFT`, `APPROVED`, `LIVE`, `ARCHIVED`, with edit restrictions based on status. Automated deal metrics are calculated.
21
+ - **Nested Data Structure**: Uses nested objects for mode-specific fields.
22
+ - **Line Item Scheduling and Pacing**: Priority-based scheduling with various types and pacing strategies (`even`, `asap`, `front-loaded`, `back-loaded`).
23
+ - **Line Item Extended Fields**: `priority` (1-10), `customFees` (array of {name, amount, type: fixed/percentage, invoiced}), `frequencyCap` ({period: hour/day/week/month/lifetime, target}), `trafficAllocation` (0-100%), `inventorySource` (string).
24
+ - **Base Price Fields**: Store original prices before custom fees are applied. PROGRAMMATIC mode uses `bidFloorBase` (number). DIRECT mode uses `pricing.cpmBase` and `pricing.estimatedCostBase` within the direct object.
25
+ - **Creative Management**: Creatives are assigned to line items with validation and automatic inventory matching. Creatives follow a workflow: `PENDING`, `APPROVED`, `REJECTED`. Creative approval/rejection uses a unified `POST /deals/{dealId}/line-items/{lineItemId}/creatives/{creativeId}` endpoint with a decision-based payload (`decision`: `APPROVED`/`REJECTED`, case-insensitive). Reviewer fields (`reviewerId`, `reviewerName`, `reason`) are optional.
26
+ - **API Filtering**: Extensive filtering for `GET /deals` by various parameters.
27
+ - **Bulk Operations**: `POST /deals/sync` enables atomic insertion of deals with nested entities.
28
+ - **Campaign Import/Sync**: Supports importing campaigns from external platforms with `payloadType`s such as `PROGRAMMATIC_STANDARD`, `DIRECT_STANDARD`, and `DIRECT_PUBLISHER_SPLIT`. Captures `account` (userId, companyName, companyId, externalId) and `advertiser` (id, seatId, name) from import payloads. It intelligently handles inventory scheduling and grouping during import, updating `totalInventories` count. Includes proportional budget capping logic to prevent inventory costs from exceeding campaign budget limits (proportional split: `(campaignBudget / totalInventories) * inventoryCount`).
29
+ - **DIRECT Mode Auto-IO Creation**: Automatically creates Publisher Insertion Orders for `DIRECT_PUBLISHER_SPLIT` imports with derived dates and budgets from line items. Insertion order start/end dates are calculated as the earliest/latest from their publisher's line items. Budget amounts are derived from inventory `planning.pricing.estimatedCost` when available, falling back to proportional split based on inventory count. Includes budget capping to ensure total IO budget does not exceed campaign budget.
30
+ - **Targeting**: `targeting` (demographics, venue types, geofencing) available for both `PROGRAMMATIC` and `DIRECT`. `deliveryTargeting` (real-time signals) is `DIRECT`-only. Geofencing supports Points of Interest (POIs).
31
+ - **Campaign Approval Workflow (DIRECT Mode)**: Multi-approver workflow with OTP authentication, email notifications, a public approval portal, and decision submission. Tracks rejection reasons, cascades status to line items, and maintains an audit trail. Configurable via environment variables for email notifications and security. Supports resending approval emails via `POST /deals/{dealId}/approval/resend`.
32
+ - **Planning (DIRECT Mode)**: Provides capacity, allocation, estimates, and pricing at line item, inventory, and deal levels.
33
+ - **Inventory Metadata and Replacement**: Inventories support optional `deviceId` and `metadata.externalRefIds` for third-party integrations. `PUT /deals/{dealId}/line-items/{lineItemId}/inventories` replaces existing inventories atomically.
34
+ - **Change History**: Comprehensive audit trail for deals and line items.
35
+ - **Deal Reopen (DIRECT Mode)**: Allows reopening any DIRECT deal from various statuses, cascading to `REOPENED` status. Both internal (`influence`) and external source campaigns can be reopened by authorized users.
36
+ - **Campaign Status Workflow**: Workflow-aware status management supporting `DIRECT` and `PROGRAMMATIC` campaigns with canonical statuses (e.g., `GENERATED`, `APPROVED`, `LIVE`), editable statuses, and transition ownership. Includes guardrail logic and auto-approval for specific conditions.
37
+ - **Source-Based Permissions**: Enforces modification restrictions based on `INTERNAL` (`"influence"`) or `EXTERNAL` sources. External sources have limited control over pacing and budget allocation, while internal sources have full control. Import APIs do not accept "influence" as a source.
38
+ - **Deterministic Re-Import Upsert Logic**: Campaign re-imports via `/deals/import` use deterministic identifiers for proper upsert matching:
39
+ - **Upsert Status Restriction**: Re-imports that update an existing deal are ONLY allowed when the deal is in `REOPENED` status. Other statuses return 409 with guidance to reopen first.
40
+ - **Line Item ExternalId Pattern**: For grouped inventories: `{campaignExternalId}-{publisherId}-{duration}-{inventoryFingerprint}` (MD5 hash of sorted inventory IDs). Grouping key is publisher + duration; multiple resolutions are collected into the `resolutions` array. For scheduled inventories: includes inventoryId for determinism.
41
+ - **Archiving Strategy**: Line items and insertion orders for removed publishers are archived (status → ARCHIVED) instead of deleted, preserving audit trails.
42
+ - **Publisher Reactivation**: Archived insertion orders are reactivated (status → DRAFT) when publisher returns in a subsequent import.
43
+
44
+ ### System Design Choices
45
+ - **Data Persistence**: PostgreSQL via Sequelize ORM (v6) utilizing UUIDs, foreign keys, JSONB fields, and ENUM types.
46
+ - **API Design**: RESTful architecture with nested resources, standard HTTP methods, and pagination.
47
+ - **Auditability**: All API requests are logged to a `transaction_history` table.
48
+ - **Error Handling**: Centralized error handling for consistent responses.
49
+
50
+ ## External Dependencies
51
+
52
+ ### Runtime
53
+ - `express`
54
+ - `sequelize`
55
+ - `pg`, `pg-hstore`
56
+ - `joi`
57
+ - `uuid`
58
+ - `dotenv`
59
+
60
+ ### Database
61
+ - **PostgreSQL**: Primary data store (version 12+).
62
+
63
+ ### Documentation
64
+ - **Swagger Documentation**: API v1.7.0 - Available at `/api-docs` (UI) and `/api-docs.json` (spec)
package/PCM/schema.sql ADDED
@@ -0,0 +1,495 @@
1
+ -- DOOH AdServer Schema Export
2
+ -- Generated: 2026-01-07 (from pg_dump)
3
+ -- Order: Extensions -> ENUMs -> Tables -> Sequences -> Constraints -> Indexes -> Foreign Keys
4
+
5
+ -- Extensions
6
+ CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
7
+ CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public;
8
+
9
+ -- ENUM Types
10
+ CREATE TYPE public.campaign_inventory_status AS ENUM (
11
+ 'ACTIVE',
12
+ 'INACTIVE',
13
+ 'PENDING',
14
+ 'ARCHIVED'
15
+ );
16
+
17
+ CREATE TYPE public.change_action_type AS ENUM (
18
+ 'CREATE',
19
+ 'UPDATE',
20
+ 'DELETE',
21
+ 'STATUS_CHANGE'
22
+ );
23
+
24
+ CREATE TYPE public.change_entity_type AS ENUM (
25
+ 'DEAL',
26
+ 'LINE_ITEM'
27
+ );
28
+
29
+ CREATE TYPE public.cost_type_enum AS ENUM (
30
+ 'CPD',
31
+ 'CPM',
32
+ 'CPS'
33
+ );
34
+
35
+ CREATE TYPE public.creative_rotation_type_enum AS ENUM (
36
+ 'EVEN',
37
+ 'OPTIMIZED',
38
+ 'MANUAL',
39
+ 'SEQUENTIAL'
40
+ );
41
+
42
+ CREATE TYPE public.creative_type_enum AS ENUM (
43
+ 'DISPLAY',
44
+ 'VIDEO',
45
+ 'AUDIO'
46
+ );
47
+
48
+ CREATE TYPE public.deal_type_enum AS ENUM (
49
+ 'GUARANTEED',
50
+ 'PREFERRED_DEAL',
51
+ 'PRIVATE_AUCTION',
52
+ 'EVERGREEN_PMP',
53
+ 'DIRECT'
54
+ );
55
+
56
+ CREATE TYPE public.enum_deals_cost_type AS ENUM (
57
+ 'CPD',
58
+ 'CPM',
59
+ 'CPS'
60
+ );
61
+
62
+ CREATE TYPE public.enum_deals_deal_type AS ENUM (
63
+ 'GUARANTEED',
64
+ 'PREFERRED_DEAL',
65
+ 'PRIVATE_AUCTION',
66
+ 'EVERGREEN_PMP',
67
+ 'DIRECT'
68
+ );
69
+
70
+ CREATE TYPE public.enum_deals_status AS ENUM (
71
+ 'GENERATED',
72
+ 'PENDING',
73
+ 'APPROVED',
74
+ 'LIVE',
75
+ 'COMPLETED',
76
+ 'REOPENED',
77
+ 'ARCHIVED',
78
+ 'EXPIRED',
79
+ 'DRAFT',
80
+ 'REQUESTED'
81
+ );
82
+
83
+ CREATE TYPE public.imp_multiplier_type_enum AS ENUM (
84
+ 'MAD',
85
+ 'CUSTOM'
86
+ );
87
+
88
+ CREATE TYPE public.impression_type_enum AS ENUM (
89
+ 'SPOT',
90
+ 'AUDIENCE'
91
+ );
92
+
93
+ CREATE TYPE public.insertion_order_status AS ENUM (
94
+ 'DRAFT',
95
+ 'PENDING',
96
+ 'APPROVED',
97
+ 'LIVE',
98
+ 'COMPLETED',
99
+ 'ARCHIVED'
100
+ );
101
+
102
+ CREATE TYPE public.schedule_type_enum AS ENUM (
103
+ 'ALL_TIME',
104
+ 'ON_SCHEDULE'
105
+ );
106
+
107
+ CREATE TYPE public.status_enum AS ENUM (
108
+ 'DRAFT',
109
+ 'GENERATED',
110
+ 'PENDING',
111
+ 'APPROVED',
112
+ 'LIVE',
113
+ 'COMPLETED',
114
+ 'REOPENED',
115
+ 'ARCHIVED',
116
+ 'EXPIRED',
117
+ 'REQUESTED',
118
+ 'REJECTED',
119
+ 'CANCELED',
120
+ 'DELETED',
121
+ 'PENDING_CREATIVES',
122
+ 'IN_ACTIVE'
123
+ );
124
+
125
+ CREATE TYPE public.transaction_type_enum AS ENUM (
126
+ 'SPOT',
127
+ 'AUDIENCE'
128
+ );
129
+
130
+ -- Table: approval_otps
131
+ CREATE TABLE public.approval_otps (
132
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
133
+ approval_token_id uuid NOT NULL,
134
+ otp_code text NOT NULL,
135
+ expires_at timestamp with time zone NOT NULL,
136
+ verified boolean DEFAULT false NOT NULL,
137
+ attempts integer DEFAULT 0 NOT NULL,
138
+ created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
139
+ updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP
140
+ );
141
+
142
+ -- Table: approval_tokens
143
+ CREATE TABLE public.approval_tokens (
144
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
145
+ deal_id text NOT NULL,
146
+ approver_email text NOT NULL,
147
+ token text NOT NULL,
148
+ status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL,
149
+ rejection_reason text,
150
+ decision_at timestamp with time zone,
151
+ expires_at timestamp with time zone NOT NULL,
152
+ otp_verified boolean DEFAULT false NOT NULL,
153
+ request_id text,
154
+ created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
155
+ updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
156
+ encrypted_token text,
157
+ CONSTRAINT approval_tokens_status_check CHECK (((status)::text = ANY ((ARRAY['PENDING'::character varying, 'APPROVED'::character varying, 'REJECTED'::character varying])::text[])))
158
+ );
159
+
160
+ -- Table: change_history
161
+ CREATE TABLE public.change_history (
162
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
163
+ entity_type public.change_entity_type NOT NULL,
164
+ entity_id uuid NOT NULL,
165
+ deal_id text,
166
+ line_item_id text,
167
+ action public.change_action_type NOT NULL,
168
+ field_name text,
169
+ previous_value jsonb,
170
+ current_value jsonb,
171
+ changed_by text,
172
+ changed_by_email text,
173
+ request_id text,
174
+ ip_address text,
175
+ user_agent text,
176
+ summary text,
177
+ metadata jsonb DEFAULT '{}'::jsonb,
178
+ created_at timestamp with time zone DEFAULT now()
179
+ );
180
+
181
+ -- Table: deal_id_counters
182
+ CREATE TABLE public.deal_id_counters (
183
+ id integer NOT NULL,
184
+ prefix character varying(10) NOT NULL,
185
+ current_value bigint DEFAULT 0 NOT NULL,
186
+ created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
187
+ updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP
188
+ );
189
+
190
+ -- Sequence for deal_id_counters
191
+ CREATE SEQUENCE public.deal_id_counters_id_seq
192
+ AS integer
193
+ START WITH 1
194
+ INCREMENT BY 1
195
+ NO MINVALUE
196
+ NO MAXVALUE
197
+ CACHE 1;
198
+
199
+ ALTER SEQUENCE public.deal_id_counters_id_seq OWNED BY public.deal_id_counters.id;
200
+
201
+ -- Table: deals
202
+ CREATE TABLE public.deals (
203
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
204
+ source text NOT NULL,
205
+ external_id text,
206
+ deal_id text,
207
+ name text,
208
+ deal_type public.deal_type_enum,
209
+ transaction_type text,
210
+ auction_type smallint,
211
+ buyers jsonb,
212
+ seller jsonb,
213
+ currency text,
214
+ cost_type public.cost_type_enum,
215
+ delivery_goal bigint,
216
+ net_cost numeric(14,2),
217
+ net_cost_per_day numeric(14,2),
218
+ timezone_id text,
219
+ start_date date,
220
+ end_date date,
221
+ impressions bigint,
222
+ account jsonb,
223
+ country text,
224
+ status public.status_enum DEFAULT 'GENERATED'::public.status_enum,
225
+ active boolean DEFAULT true,
226
+ is_playing boolean DEFAULT false,
227
+ metadata jsonb,
228
+ created_at timestamp with time zone DEFAULT now(),
229
+ updated_at timestamp with time zone DEFAULT now(),
230
+ version integer DEFAULT 1,
231
+ brand text,
232
+ client_type text,
233
+ mode text,
234
+ approval_emails text[],
235
+ market_selection jsonb,
236
+ budget_setup jsonb,
237
+ campaign_goal jsonb,
238
+ publishers jsonb,
239
+ advertiser jsonb,
240
+ published boolean DEFAULT false,
241
+ reopened boolean DEFAULT false,
242
+ non_billable boolean DEFAULT false,
243
+ stop_bid_requests boolean DEFAULT false,
244
+ imp_multiplier_type text,
245
+ line_items_count integer DEFAULT 0,
246
+ planning jsonb,
247
+ CONSTRAINT deals_client_type_check CHECK (((client_type IS NULL) OR (client_type = ANY (ARRAY['DIRECT_ADVERTISER'::text, 'AGENCY'::text])))),
248
+ CONSTRAINT deals_mode_check CHECK (((mode IS NULL) OR (mode = ANY (ARRAY['PROGRAMMATIC'::text, 'DIRECT'::text]))))
249
+ );
250
+
251
+ -- Table: line_item_creatives
252
+ CREATE TABLE public.line_item_creatives (
253
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
254
+ creative_id text,
255
+ creative_uri text,
256
+ mime_type text,
257
+ duration integer,
258
+ deal_id text,
259
+ inventory_ids text[],
260
+ metadata jsonb,
261
+ created_at timestamp with time zone DEFAULT now(),
262
+ updated_at timestamp with time zone DEFAULT now(),
263
+ creative_type text,
264
+ resolution text,
265
+ status text DEFAULT 'PENDING'::text,
266
+ reviewer_id text,
267
+ reviewer_name text,
268
+ reviewed_at timestamp with time zone,
269
+ thumbnail text,
270
+ line_item_id uuid
271
+ );
272
+
273
+ -- Table: line_item_inventories
274
+ CREATE TABLE public.line_item_inventories (
275
+ id text NOT NULL,
276
+ deal_id text,
277
+ name text,
278
+ size text,
279
+ publisher_id text,
280
+ publisher_name text,
281
+ publisher_external_id text,
282
+ latitude double precision,
283
+ longitude double precision,
284
+ venue_type text,
285
+ thumbnail text,
286
+ timezone text,
287
+ metadata jsonb,
288
+ created_at timestamp with time zone DEFAULT now(),
289
+ updated_at timestamp with time zone DEFAULT now(),
290
+ ad_unit_code text,
291
+ reference_id text,
292
+ device_id text,
293
+ country_iso2 text,
294
+ country_iso3 text,
295
+ venue_type_ids text[],
296
+ bcat jsonb,
297
+ publisher_domain text,
298
+ enable_aspect_ratio boolean DEFAULT false,
299
+ display_aspect_ratio text,
300
+ planning jsonb,
301
+ line_item_id uuid NOT NULL
302
+ );
303
+
304
+ -- Table: line_items
305
+ CREATE TABLE public.line_items (
306
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
307
+ source text NOT NULL,
308
+ external_id text,
309
+ deal_id text,
310
+ name text,
311
+ deal_type public.deal_type_enum,
312
+ auction_type smallint,
313
+ creative_type public.creative_type_enum,
314
+ duration integer,
315
+ impression_type public.impression_type_enum,
316
+ timezone_id text,
317
+ start_date date,
318
+ end_date date,
319
+ threshold_count_per_day integer,
320
+ delivery_goal bigint,
321
+ sizes text[],
322
+ schedule jsonb,
323
+ currency text,
324
+ cost_type public.cost_type_enum,
325
+ bid_floor numeric(12,2),
326
+ net_cost numeric(14,2),
327
+ net_cost_per_day numeric(14,2),
328
+ impressions bigint,
329
+ status public.status_enum,
330
+ is_playing boolean DEFAULT false,
331
+ publisher_id text,
332
+ creative_rotation_type public.creative_rotation_type_enum,
333
+ metadata jsonb,
334
+ created_at timestamp with time zone DEFAULT now(),
335
+ updated_at timestamp with time zone DEFAULT now(),
336
+ version integer DEFAULT 1,
337
+ mode text,
338
+ resolutions text[],
339
+ creative_source text,
340
+ total_inventories integer DEFAULT 0,
341
+ adm_creative_sync boolean DEFAULT false,
342
+ non_billable boolean DEFAULT false,
343
+ stop_bid_requests boolean DEFAULT false,
344
+ imp_multiplier jsonb,
345
+ budget_setup jsonb,
346
+ campaign_goal jsonb,
347
+ pacing jsonb,
348
+ targeting jsonb,
349
+ planning jsonb,
350
+ delivery_targeting jsonb
351
+ );
352
+
353
+ -- Table: publisher_insertion_orders
354
+ CREATE TABLE public.publisher_insertion_orders (
355
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
356
+ deal_id text NOT NULL,
357
+ publisher_id text NOT NULL,
358
+ publisher_name text,
359
+ io_number text,
360
+ status public.insertion_order_status DEFAULT 'DRAFT'::public.insertion_order_status,
361
+ budget_amount numeric(14,2),
362
+ currency text,
363
+ start_date date,
364
+ end_date date,
365
+ summary jsonb DEFAULT '{}'::jsonb,
366
+ external_sync_reference jsonb DEFAULT '{}'::jsonb,
367
+ published boolean DEFAULT false,
368
+ published_at timestamp with time zone,
369
+ metadata jsonb DEFAULT '{}'::jsonb,
370
+ version integer DEFAULT 1,
371
+ created_at timestamp with time zone DEFAULT now(),
372
+ updated_at timestamp with time zone DEFAULT now()
373
+ );
374
+
375
+ -- Table: transaction_history
376
+ CREATE TABLE public.transaction_history (
377
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
378
+ request_id text,
379
+ method text,
380
+ endpoint text,
381
+ payload jsonb,
382
+ response_status integer,
383
+ created_at timestamp with time zone NOT NULL
384
+ );
385
+
386
+ -- Column defaults
387
+ ALTER TABLE ONLY public.deal_id_counters ALTER COLUMN id SET DEFAULT nextval('public.deal_id_counters_id_seq'::regclass);
388
+
389
+ -- Primary Key Constraints
390
+ ALTER TABLE ONLY public.approval_otps
391
+ ADD CONSTRAINT approval_otps_pkey PRIMARY KEY (id);
392
+
393
+ ALTER TABLE ONLY public.approval_tokens
394
+ ADD CONSTRAINT approval_tokens_pkey PRIMARY KEY (id);
395
+
396
+ ALTER TABLE ONLY public.approval_tokens
397
+ ADD CONSTRAINT approval_tokens_token_key UNIQUE (token);
398
+
399
+ ALTER TABLE ONLY public.change_history
400
+ ADD CONSTRAINT change_history_pkey PRIMARY KEY (id);
401
+
402
+ ALTER TABLE ONLY public.deal_id_counters
403
+ ADD CONSTRAINT deal_id_counters_pkey PRIMARY KEY (id);
404
+
405
+ ALTER TABLE ONLY public.deal_id_counters
406
+ ADD CONSTRAINT deal_id_counters_prefix_key UNIQUE (prefix);
407
+
408
+ ALTER TABLE ONLY public.deals
409
+ ADD CONSTRAINT deals_deal_id_key UNIQUE (deal_id);
410
+
411
+ ALTER TABLE ONLY public.deals
412
+ ADD CONSTRAINT deals_pkey PRIMARY KEY (id);
413
+
414
+ ALTER TABLE ONLY public.deals
415
+ ADD CONSTRAINT deals_source_external_id_key UNIQUE (source, external_id);
416
+
417
+ ALTER TABLE ONLY public.line_item_creatives
418
+ ADD CONSTRAINT line_item_creatives_creative_id_deal_id_key UNIQUE (creative_id, deal_id);
419
+
420
+ ALTER TABLE ONLY public.line_item_creatives
421
+ ADD CONSTRAINT line_item_creatives_pkey PRIMARY KEY (id);
422
+
423
+ ALTER TABLE ONLY public.line_item_inventories
424
+ ADD CONSTRAINT line_item_inventories_pkey PRIMARY KEY (id, line_item_id);
425
+
426
+ ALTER TABLE ONLY public.line_items
427
+ ADD CONSTRAINT line_items_pkey PRIMARY KEY (id);
428
+
429
+ ALTER TABLE ONLY public.line_items
430
+ ADD CONSTRAINT line_items_source_external_id_key UNIQUE (source, external_id);
431
+
432
+ ALTER TABLE ONLY public.publisher_insertion_orders
433
+ ADD CONSTRAINT publisher_insertion_orders_pkey PRIMARY KEY (id);
434
+
435
+ ALTER TABLE ONLY public.transaction_history
436
+ ADD CONSTRAINT transaction_history_pkey PRIMARY KEY (id);
437
+
438
+ ALTER TABLE ONLY public.deals
439
+ ADD CONSTRAINT unique_deal_id UNIQUE (deal_id);
440
+
441
+ ALTER TABLE ONLY public.line_items
442
+ ADD CONSTRAINT unique_external_id UNIQUE (external_id);
443
+
444
+ -- Indexes
445
+ CREATE INDEX idx_approval_otps_approval_token_id ON public.approval_otps USING btree (approval_token_id);
446
+ CREATE INDEX idx_approval_otps_otp_code ON public.approval_otps USING btree (otp_code);
447
+ CREATE INDEX idx_approval_tokens_approver_email ON public.approval_tokens USING btree (approver_email);
448
+ CREATE INDEX idx_approval_tokens_deal_id ON public.approval_tokens USING btree (deal_id);
449
+ CREATE INDEX idx_approval_tokens_status ON public.approval_tokens USING btree (status);
450
+ CREATE INDEX idx_approval_tokens_token ON public.approval_tokens USING btree (token);
451
+ CREATE INDEX idx_change_history_action ON public.change_history USING btree (action);
452
+ CREATE INDEX idx_change_history_created_at ON public.change_history USING btree (created_at);
453
+ CREATE INDEX idx_change_history_deal_id ON public.change_history USING btree (deal_id);
454
+ CREATE INDEX idx_change_history_entity ON public.change_history USING btree (entity_type, entity_id);
455
+ CREATE INDEX idx_change_history_line_item_id ON public.change_history USING btree (line_item_id);
456
+ CREATE INDEX idx_creatives_uri_trgm ON public.line_item_creatives USING gin (creative_uri public.gin_trgm_ops);
457
+ CREATE INDEX idx_deal_id_counters_prefix ON public.deal_id_counters USING btree (prefix);
458
+ CREATE INDEX idx_deals_source ON public.deals USING btree (source);
459
+ CREATE INDEX idx_deals_time ON public.deals USING btree (start_date, end_date);
460
+ CREATE INDEX idx_line_item_inventories_id ON public.line_item_inventories USING btree (id);
461
+ CREATE INDEX idx_line_item_inventories_line_item_id ON public.line_item_inventories USING btree (line_item_id);
462
+ CREATE INDEX idx_line_item_inventories_planning ON public.line_item_inventories USING gin (planning) WHERE (planning IS NOT NULL);
463
+ CREATE INDEX idx_line_items_planning ON public.line_items USING gin (planning) WHERE (planning IS NOT NULL);
464
+ CREATE INDEX idx_lineitem_inv_pub ON public.line_item_inventories USING btree (publisher_id);
465
+ CREATE INDEX idx_lineitems_deal ON public.line_items USING btree (deal_id);
466
+ CREATE INDEX idx_lineitems_publisher ON public.line_items USING btree (publisher_id);
467
+ CREATE INDEX idx_lineitems_time ON public.line_items USING btree (start_date, end_date);
468
+ CREATE INDEX idx_publisher_insertion_orders_deal_id ON public.publisher_insertion_orders USING btree (deal_id);
469
+ CREATE UNIQUE INDEX idx_publisher_insertion_orders_deal_publisher ON public.publisher_insertion_orders USING btree (deal_id, publisher_id);
470
+ CREATE INDEX idx_publisher_insertion_orders_publisher_id ON public.publisher_insertion_orders USING btree (publisher_id);
471
+
472
+ -- Foreign Key Constraints
473
+ ALTER TABLE ONLY public.approval_otps
474
+ ADD CONSTRAINT approval_otps_approval_token_id_fkey FOREIGN KEY (approval_token_id) REFERENCES public.approval_tokens(id) ON DELETE CASCADE;
475
+
476
+ ALTER TABLE ONLY public.approval_tokens
477
+ ADD CONSTRAINT approval_tokens_deal_id_fkey FOREIGN KEY (deal_id) REFERENCES public.deals(deal_id) ON DELETE CASCADE;
478
+
479
+ ALTER TABLE ONLY public.line_item_creatives
480
+ ADD CONSTRAINT line_item_creatives_deal_id_fkey FOREIGN KEY (deal_id) REFERENCES public.deals(deal_id) ON DELETE CASCADE;
481
+
482
+ ALTER TABLE ONLY public.line_item_creatives
483
+ ADD CONSTRAINT line_item_creatives_line_item_id_fkey FOREIGN KEY (line_item_id) REFERENCES public.line_items(id) ON DELETE CASCADE;
484
+
485
+ ALTER TABLE ONLY public.line_item_inventories
486
+ ADD CONSTRAINT line_item_inventories_deal_id_fkey FOREIGN KEY (deal_id) REFERENCES public.deals(deal_id) ON DELETE CASCADE;
487
+
488
+ ALTER TABLE ONLY public.line_item_inventories
489
+ ADD CONSTRAINT line_item_inventories_line_item_id_fkey FOREIGN KEY (line_item_id) REFERENCES public.line_items(id) ON DELETE CASCADE;
490
+
491
+ ALTER TABLE ONLY public.line_items
492
+ ADD CONSTRAINT line_items_deal_id_fkey FOREIGN KEY (deal_id) REFERENCES public.deals(deal_id) ON DELETE CASCADE;
493
+
494
+ ALTER TABLE ONLY public.publisher_insertion_orders
495
+ ADD CONSTRAINT publisher_insertion_orders_deal_id_fkey FOREIGN KEY (deal_id) REFERENCES public.deals(deal_id) ON DELETE CASCADE;