index.html Repository Demand-Radar Original path index.htmlRole SOURCE Size 133270 bytes Lines 4046 SHA-256 bece94e1f815694e3db00dfa1480618e6692d3f0ab5c0ce667fb22f2bd33f6e4Displayed range 1001–1500 Previous file/page · Project index · Next file/page
line-height: 1.45;
}
.meta-inline-controls {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
margin-bottom: 2px;
}
.meta-inline-controls select {
width: auto;
min-width: 150px;
margin: 0;
padding: 5px 8px;
font-size: 12px;
}
.meta-inline-controls button {
padding: 4px 8px;
font-size: 11px;
}
.filter-help-wrap {
position: relative;
display: inline-flex;
align-items: center;
margin-left: 8px;
}
.info-btn {
width: 26px;
height: 26px;
border-radius: 999px;
border: 1px solid #4a5870;
background: #243248;
color: #d8e6ff;
font-weight: 800;
padding: 0;
}
.filter-help-bubble {
position: absolute;
right: 0;
top: 34px;
width: min(440px, 88vw);
z-index: 15;
border: 1px solid #47618b;
background: #14243b;
border-radius: 10px;
padding: 10px;
font-size: 12px;
line-height: 1.4;
color: #d7e8ff;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.db-size-chip {
border-color: #4a5f7f;
background: #213149;
color: #d2e5ff;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<header>
<h1>Market Demand Radar — Workbench</h1>
<div class="grow"></div>
<label style="margin:0">Webhook:
<select id="mode" style="width:auto; margin-left:6px">
<option value="production" selected>PRODUCTION /webhook</option>
<option value="test">TEST /webhook-test</option>
</select>
</label>
<span id="n8nStatus" class="status"><span class="dot"></span>sprawdzam n8n...</span>
<span id="dbSizeStatus" class="status db-size-chip"><span class="dot"></span>SQL: ...</span>
<nav class="tab-nav">
<button class="tab-btn active" data-tab="workbench">WORKBENCH</button>
<button class="tab-btn" data-tab="saved">ZAPISANE PROJEKTY</button>
<button class="tab-btn" data-tab="query-plan">QUERY PLAN</button>
<button class="tab-btn" data-tab="results">PRZEGLAD WYNIKOW</button>
</nav>
</header>
<section id="tab-workbench" class="tab-panel active">
<div class="seed-editor-wrap">
<section id="seedEditor" class="seed-editor" hidden>
<div class="seed-toolbar">
<div>
<h2 style="margin-bottom:4px">Seed Query Editor</h2>
<div class="seed-summary">
<span id="seedCount">0 seedow</span> ·
<span id="enabledSeedCount" class="seed-count-good">0 aktywnych</span>
do dalszego discovery / Query Planner
</div>
</div>
<div class="grow"></div>
<button id="addSeedBtn" class="secondary">+ Dodaj wlasny seed</button>
<button id="enableAllSeedsBtn" class="secondary">Wlacz wszystkie</button>
<button id="disableAllSeedsBtn" class="secondary">Wylacz wszystkie</button>
<button id="copyEnabledSeedsBtn" class="secondary">Kopiuj aktywne</button>
</div>
<div class="seed-table-wrap">
<table class="seed-table">
<thead>
<tr>
<th style="width:62px">Dalej?</th>
<th style="width:105px">Priorytet</th>
<th style="width:260px">Seed / query</th>
<th>Krotki opis / rationale</th>
<th style="width:120px">Zrodlo</th>
<th style="width:95px">ID</th>
<th style="width:78px"></th>
</tr>
</thead>
<tbody id="seedTableBody"></tbody>
</table>
</div>
<p class="muted" style="margin:10px 0 0">
Zmiany zapisuja sie od razu do <code>currentPlan</code>. MR-02 dostanie juz te edytowana wersje.
Collector powinien wykonywac tylko seedy z <code>enabled: true</code>.
</p>
</section>
</div>
<div class="layout">
<section>
<div class="panel">
<div class="panel-title-row">
<h2>MR-01 — Generate Discovery Plan</h2>
<button id="saveProjectBtn" class="success" disabled>ZAPISZ PROJEKT</button>
</div>
<div id="planBadge" class="plan-badge">
Projekt: <strong>—</strong><br>
Plan: <strong>—</strong><br>
Stan: <span class="muted">brak currentPlan</span>
</div>
<div id="saveResult" class="ok-line"></div>
<div id="saveError" class="error-line"></div>
<p class="muted">Wypelnij brief. Nie podawaj docelowego produktu ani odbiorcy — to ma byc wynik discovery.</p>
<label>Nazwa projektu</label>
<input id="projectName" value="Psychologia - Polska">
<label>Kompetencje</label>
<textarea id="competencies">Psycholog i psychotraumatolog. Moge tworzyc produkty edukacyjne z szeroko rozumianej psychologii, emocji, relacji, pracy terapeutycznej i zdrowia psychicznego.</textarea>
<label>Kwalifikacje / doswiadczenie</label>
<textarea id="qualifications" class="short">Doswiadczenie psychologiczne i psychotraumatologiczne.</textarea>
<label>Jakie produkty moge tworzyc?</label>
<div class="checks">
<label><input type="checkbox" name="format" value="recorded_training" checked> nagrane szkolenie</label>
<label><input type="checkbox" name="format" value="online_course" checked> kurs online</label>
<label><input type="checkbox" name="format" value="webinar" checked> webinar</label>
<label><input type="checkbox" name="format" value="educational_program" checked> program edukacyjny</label>
<label><input type="checkbox" name="format" value="workshop"> warsztat</label>
<label><input type="checkbox" name="format" value="digital_materials"> materialy cyfrowe</label>
</div>
<div class="row">
<div>
<label>Kraj</label>
<input id="country" value="PL">
</div>
<div>
<label>Jezyk</label>
<input id="language" value="pl">
</div>
</div>
<label>Ograniczenia (1 na linie)</label>
<textarea id="constraints" class="short">Produkt nie moze wymagac formalnej akredytacji uczelni.</textarea>
<label>Wykluczenia / czego nie chce tworzyc (1 na linie)</label>
<textarea id="exclusions" class="short"></textarea>
<div class="actions">
<button id="generateBtn">Generuj MR-01</button>
<button id="newProjectBtn" class="secondary">Nowy projectId</button>
</div>
<h3>Request IDs</h3>
<div class="muted">projectId: <code id="projectIdText"></code></div>
<div class="muted">ostatni requestId: <code id="requestIdText">—</code></div>
</div>
<div class="panel">
<h2>MR-02 — Chat / Revise Plan</h2>
<p id="planStateText" class="muted">Najpierw wygeneruj poprawny plan MR-01.</p>
<label>Instrukcja dla MR-02</label>
<textarea id="instruction">Nie ograniczaj sie tylko do rynku specjalistow. Uwzglednij rowniez produkty kupowane bezposrednio przez klientow indywidualnych.</textarea>
<div class="actions">
<button id="reviseBtn" disabled>Wyslij MR-02</button>
<button id="clearPlanBtn" class="danger">Wyczysc currentPlan</button>
</div>
<h3>Opcjonalnie: wklej currentPlan recznie</h3>
<textarea id="manualPlan" class="short" placeholder='{"schemaVersion":"1.1", ...}'></textarea>
<div class="actions">
<button id="loadPlanBtn" class="secondary">Wczytaj JSON jako currentPlan</button>
</div>
</div>
<div class="panel">
<h2>Historia rewizji w tej sesji</h2>
<div id="history" class="muted">Brak.</div>
</div>
</section>
<section>
<div class="panel">
<h2>Ostatnia odpowiedz</h2>
<div id="meta" class="meta"></div>
<div id="contract" class="contract">Brak odpowiedzi.</div>
<div class="actions" style="margin-bottom:10px">
<button id="copyBtn" class="secondary" disabled>Kopiuj JSON</button>
</div>
<pre id="output">Tu pojawi sie odpowiedz n8n.</pre>
</div>
<div class="panel">
<h2>Current Plan</h2>
<p class="muted">To dokladnie ten obiekt zostanie wyslany jako <code>currentPlan</code> do MR-02.</p>
<pre id="currentPlanOutput">Brak currentPlan.</pre>
</div>
</section>
</div>
</section>
<section id="tab-saved" class="tab-panel">
<div class="saved-layout">
<section>
<div class="panel">
<div class="panel-title-row">
<h2>Zapisane projekty</h2>
<button id="refreshProjectsBtn" class="secondary">Odswiez liste</button>
</div>
<div class="list-table-wrap">
<table class="list-table">
<thead>
<tr>
<th>Projekt</th>
<th>Aktualizacja</th>
<th>Wersje</th>
<th>Latest status</th>
<th></th>
</tr>
</thead>
<tbody id="savedProjectsBody">
<tr><td colspan="5" class="muted">Brak danych.</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<section>
<div class="panel">
<h2>Wybrany projekt</h2>
<div id="selectedProjectMeta" class="muted">Wybierz projekt z listy.</div>
<h3>Brief</h3>
<pre id="selectedProjectBrief">—</pre>
<h3>Versions</h3>
<div id="selectedProjectVersions" class="muted">Brak.</div>
</div>
<div class="panel">
<h2>Podglad wersji</h2>
<div id="versionPreview" class="muted">Kliknij POKAZ przy wybranej wersji.</div>
</div>
</section>
</div>
</section>
<section id="tab-query-plan" class="tab-panel">
<div class="query-plan-layout">
<section class="query-plan-top-row">
<div class="panel">
<h2>MR03 Query Planner</h2>
<div id="queryPlanProjectMeta" class="notice">Projekt: —</div>
<label>Maksymalna liczba query na seed</label>
<input id="queryPlanMaxQueries" type="number" min="1" max="12" value="6">
<div class="actions" style="margin-top:14px">
<button id="queryPlanGenerateBtn">GENERUJ QUERY PLAN</button>
<button id="queryPlanRefreshBtn" class="secondary">ODSWIEZ</button>
<button id="queryPlanSaveBtn" class="secondary">ZAPISZ ZMIANY</button>
<button id="queryPlanApproveBtn" class="success">ZATWIERDZ PLAN</button>
<button id="metaResearchStartBtn" class="success" disabled>URUCHOM BADANIE META ADS</button>
</div>
<div id="queryPlanActionOk" class="ok-line"></div>
<div id="queryPlanActionErr" class="error-line"></div>
</div>
<div class="panel">
<h2>Seedy z najnowszego planu projektu</h2>
<div class="tiny" id="queryPlanSeedSelectionSummary">To seedy pobierane przez backend z SQLite i wysylane do MR03.</div>
<div class="actions" style="margin-top:10px">
<button id="queryPlanSelectAllSeedsBtn" class="secondary">Zaznacz wszystkie</button>
<button id="queryPlanClearSeedSelectionBtn" class="secondary">Wyczysc zaznaczenie</button>
</div>
<div id="queryPlanSeedSourceList" class="seed-inspect-list">
<div class="muted">Brak danych.</div>
</div>
</div>
</section>
<section>
<div class="panel">
<h2>Query Plan</h2>
<div id="queryPlanSummary" class="muted">Brak Query Planu. Kliknij GENERUJ QUERY PLAN.</div>
<div id="queryPlanValidation" class="error-line"></div>
<div id="queryPlanEditor" class="seed-inspect-list" style="margin-top:10px"></div>
</div>
<div class="panel">
<h2>Query Plan JSON</h2>
<pre id="queryPlanRawOutput">Brak.</pre>
</div>
</section>
</div>
</section>
<section id="tab-results" class="tab-panel">
<div class="query-plan-layout">
<section>
<div class="panel">
<h2>PRZEGLAD WYNIKOW META ADS</h2>
<div id="metaResearchStatus" class="muted">Brak uruchomionego badania.</div>
<div id="metaResearchProgress" class="notice" style="margin-top:8px; display:none"></div>
<div id="metaResearchSummary" class="meta-summary-grid"></div>
<div id="metaRelevanceSummary" class="notice" style="margin-top:8px; display:none"></div>
<div class="actions" style="margin-top:8px">
<button id="metaRunRelevanceBtn" class="danger" disabled>ODRZUC SMIECI</button>
<button id="metaExportFullCsvBtn" class="secondary" disabled>POBIERZ PELNY CSV</button>
<button id="metaExportShortCsvBtn" class="secondary" disabled>POBIERZ SKROCONY CSV</button>
<div class="filter-help-wrap">
<button id="metaFilterHelpBtn" class="info-btn" title="Jak działają filtry query/seed">i</button>
<div id="metaFilterHelpBubble" class="filter-help-bubble hidden">
<strong>Filtr query / seed</strong><br>
- wpis bez znaku $: zwykłe wyszukiwanie fragmentu tekstu<br>
- znak $ oznacza dowolną liczbę znaków (wildcard)<br>
- przykład: <em>psycholog$ relac$</em> dopasuje także odmiany i dłuższe formy<br>
- filtry działają łącznie z pozostałymi polami (AND)
</div>
</div>
</div>
<div id="metaRelevanceRunStatus" class="tiny" style="margin-top:6px"></div>
<div id="adDetailsModalBackdrop" class="ad-details-modal-backdrop" aria-hidden="true">
<div class="ad-details-modal" role="dialog" aria-modal="true" aria-labelledby="adDetailsTitle">
<div class="ad-details-modal-header">
<h3 id="adDetailsTitle">Szczegóły reklamy</h3>
<button id="adDetailsCloseBtn" class="secondary" type="button">Zamknij</button>
</div>
<div id="adDetailsContent" class="ad-details-modal-content"></div>
</div>
</div>
<div class="meta-filters">
<select id="metaFilterRelevance">
<option value="USEFUL">Relevance: UZYTECZNE</option>
<option value="KEEP">Relevance: KEEP</option>
<option value="POTENTIAL">Relevance: POTENCJALNE</option>
<option value="UNREVIEWED">Relevance: NIESPRAWDZONE</option>
<option value="REJECT">Relevance: SMIECI</option>
<option value="ALL">Relevance: WSZYSTKIE</option>
</select>
<input id="metaFilterQuery" placeholder="Filtr query">
<input id="metaFilterSeed" placeholder="Filtr seed">
<input id="metaFilterPage" placeholder="Filtr page / advertiser">
<div id="metaLifecycleFilterWrap" class="meta-lifecycle-filter">
<div class="meta-lifecycle-header">
<strong>Lifecycle</strong>
<div class="meta-lifecycle-actions">
<button id="metaLifecycleHelpBtn" class="info-btn" type="button" title="Jak klasyfikujemy lifecycle">i</button>
<button id="metaLifecycleAllBtn" class="secondary" type="button">ALL</button>
<button id="metaLifecycleNoneBtn" class="secondary" type="button">NONE</button>
</div>
</div>
<div id="metaLifecycleHelpBubble" class="filter-help-bubble hidden" style="right:auto; left:0; top:42px; width:min(440px, 82vw);">
<strong>AD lifecycle (pojedyncza reklama)</strong><br>
- BALON_PROBNY: do 7 dni albo brak poprawnej daty startu<br>
- TEST_W_TOKU: 8-30 dni<br>
- ROKUJACA: 31-90 dni<br>
- MOCNA: 91-180 dni<br>
- EVERGREEN: powyzej 180 dni<br><br>
<strong>Offer Family Class (ta sama oferta, wiele reklam)</strong><br>
- TEST_ONLY: pojedynczy krotki test bez nastepcy<br>
- REPEATED_TEST: kilka krotkich testow bez dlugiej kontynuacji<br>
- PROMISING: widac przejscie z testu do dluzszej emisji<br>
- ESTABLISHED: wyrazny dowod dluzszego utrzymywania oferty<br>
- EVERGREEN: mocny sygnal dlugotrwalej obecnosci oferty, czesto z nastepstwami
</div>
<div id="metaLifecycleCheckboxes" class="meta-lifecycle-checkboxes">
<label><input type="checkbox" class="meta-lifecycle-check" value="BALON_PROBNY" checked> <span data-lifecycle-label="BALON_PROBNY">BALON PROBNY</span></label>
<label><input type="checkbox" class="meta-lifecycle-check" value="TEST_W_TOKU" checked> <span data-lifecycle-label="TEST_W_TOKU">TEST W TOKU</span></label>
<label><input type="checkbox" class="meta-lifecycle-check" value="ROKUJACA" checked> <span data-lifecycle-label="ROKUJACA">ROKUJACA</span></label>
<label><input type="checkbox" class="meta-lifecycle-check" value="MOCNA" checked> <span data-lifecycle-label="MOCNA">MOCNA</span></label>
<label><input type="checkbox" class="meta-lifecycle-check" value="EVERGREEN" checked> <span data-lifecycle-label="EVERGREEN">EVERGREEN</span></label>
</div>
</div>
<select id="metaFilterVisible">
<option value="ALL">Visible match: ALL</option>
<option value="YES">Visible match: TAK</option>
<option value="NO">Visible match: NIE</option>
</select>
<select id="metaFilterActive">
<option value="ALL">Status: ALL</option>
<option value="ACTIVE">Status: aktywne</option>
<option value="INACTIVE">Status: zakonczone</option>
</select>
<input id="metaFilterMinReach" type="number" min="0" placeholder="Min EU reach">
<input id="metaFilterStartDate" type="date">
<select id="metaSortBy">
<option value="lastSeen">Sort: Last seen</option>
<option value="lifecycle">Sort: Lifecycle</option>
<option value="duration">Sort: Duration</option>
<option value="reach">Sort: EU reach</option>
<option value="start">Sort: Start date</option>
<option value="firstSeen">Sort: First seen</option>
</select>
</div>
<div class="meta-filters" style="margin-top:8px">
<select id="metaFamilyClassFilter">
<option value="ALL">Family class: ALL</option>
<option value="TEST_ONLY">Family class: TEST_ONLY</option>
<option value="REPEATED_TEST">Family class: REPEATED_TEST</option>
<option value="PROMISING">Family class: PROMISING</option>
<option value="ESTABLISHED">Family class: ESTABLISHED</option>
<option value="EVERGREEN">Family class: EVERGREEN</option>
<option value="UNCLASSIFIED">Family class: UNCLASSIFIED</option>
</select>
<select id="metaFamilyStatusFilter">
<option value="ALL">Family status: ALL</option>
<option value="ACTIVE">Family status: ACTIVE</option>
<option value="ENDED">Family status: ENDED</option>
</select>
<select id="metaFamilyPatternFilter">
<option value="ALL">Family pattern: ALL</option>
<option value="DIRECT_SUCCESSOR">Pattern: DIRECT_SUCCESSOR</option>
<option value="PARALLEL_TEST">Pattern: PARALLEL_TEST</option>
<option value="RELAUNCH">Pattern: RELAUNCH</option>
<option value="CONTINUOUS_CAMPAIGN">Pattern: CONTINUOUS_CAMPAIGN</option>
<option value="CREATIVE_REFRESH">Pattern: CREATIVE_REFRESH</option>
</select>
<div id="offerFamilySummary" class="tiny" style="align-self:center; padding-left:6px;">Brak rodzin ofert.</div>
</div>
<div class="actions">
<button id="metaApplyFiltersBtn" class="secondary">ZASTOSUJ FILTRY</button>
</div>
<div class="meta-ads-table-wrap">
<table class="meta-ads-table">
<thead>
<tr>
<th>Reklama</th>
</tr>
</thead>
<tbody id="metaAdsBody">
<tr><td colspan="1" class="muted">Brak danych.</td></tr>
</tbody>
</table>
</div>
<div class="panel" style="margin-top:12px; padding:12px;">
<h3 style="margin-top:0">RODZINY OFERT</h3>
<div id="offerFamilyList" class="seed-inspect-list">Brak rodzin ofert.</div>
</div>
</div>
</section>
</div>
</section>
<script>
const REQUIRED_TOP = [
'schemaVersion',
'capabilityUnderstanding',
'marketBreadth',