ObscureIQ — System Documentation
ObscureIQ
Restricted Access

System Documentation

Internal architecture details.
Enter the access password to continue.

Incorrect password — please try again.
Internal use only · ObscureIQ confidential
Internal Technical Documentation

ObscureIQ Hostility Index
Survey Portal

A complete reference covering how every part of this system works — from survey intake on the WordPress site to advanced report delivery — written for the ObscureIQ team and developers.

Portal: surveys.obscureiq.com
Stack: PHP · MySQL · Vanilla JS
Host: Hostinger shared
Updated: July 2026
15
Sections Covered
3 database tables
6 API endpoints
24 report sections
Full scoring logic
1

System Overview

What this system does and how its three parts fit together

The Hostility Index Survey Portal is a PHP/MySQL web application at surveys.obscureiq.com. Three core responsibilities:

Job 1
Survey Intake
Survey runs in the browser (WordPress shortcode). Scores calculated locally, then POSTed to the API.
Job 2
Data & Dashboard
All submissions stored in MySQL. Team accesses a password-protected admin dashboard.
Job 3
Report Delivery
Team generates a formatted Advanced Hostility Index report and sends the client a secure, time-limited login link.

Key principle: Scoring happens entirely in the browser. The server stores and displays scores — it never recalculates them.

2

Technology Stack

Languages, frameworks, and infrastructure

LayerTechnologyNotes
Server languagePHPNo framework — plain PHP files
DatabaseMySQLConnected via mysqli
FrontendVanilla JS / HTML / CSSNo React, no Vue — pure browser JS
HostingHostingerShared hosting, files in public_html/
EmailPHP mail()Server-side SMTP via Hostinger
Survey frontendWordPress Shortcode[hostility_index_survey] on obscureiq.com
Admin authPHP SessionsHardcoded password, 1-hour timeout
Client authToken + credentialsprotected_pages table, 72-hour expiry
3

Database

Schema, tables, and what gets stored where

Database Name
u535059212_OIQsurveys
Connection File
db_config.php
Also db_config_local.php for dev

Table: survey_data — one row per submission

ColumnTypeNotes
idINT AUTO_INCREMENTPrimary key
typeVARCHARbasic or advanced
nameVARCHAR(255)NULL for basic — set when user requests advanced analysis
emailVARCHAR(255)NULL for basic — set after OTP verification
scoreINTOverall Hostility Index (0–196)
risk_levelVARCHAR(50)LOW / MODERATE / ELEVATED / HIGH / CRITICAL
dataLONGTEXT (JSON)risk_factors, recommendations, responses, response_labels
share_idVARCHAR(64)Random 16-char hex on insert — used for share/upgrade links
created_atDATETIMEAuto-set on insert
admin_pdf_pathVARCHARServer path to uploaded admin PDF
admin_protected_linkVARCHARURL saved by admin for internal reference
admin_protected_passwordVARCHARPassword saved by admin for internal reference

Table: email_verification — temporary OTP storage

ColumnTypeNotes
email / nameVARCHAR(255)User's email and name/alias
otp_codeVARCHAR(6)6-digit one-time code
survey_dataLONGTEXTFull survey JSON copied here for the verify step
expires_atDATETIME10 minutes from creation
verified / usedBOOLEANSet TRUE after verification; prevents reuse
verification_ipVARCHARClient IP at request time

Table: protected_pages — client access credentials

ColumnTypeNotes
survey_idINTFK → survey_data.id
access_tokenVARCHARUUID in the email link URL
username / passwordVARCHARAuto-generated, sent to client in email
expires_atDATETIME72 hours from creation
last_login / access_countDATETIME / INTTracked on each login
4

File Structure

Every file in public_html/ and what it does

public_html/ ├── index.php Admin login (password gate) ├── secured.php Main admin dashboard <-- USE THIS ├── view_survey.php Full detail view for one survey ├── generate_advanced_report.php Generate formatted advanced report * ├── generate_public_report_page.php Generate public-facing report page ├── public_report.php Public-facing report (client-accessible) ├── login.php Client login (token + username + password) ├── protected.php Client protected report view ├── premium.php Premium client report view ├── export_advanced_csv.php Export all advanced surveys as CSV ├── admin_pdf.php Serves an uploaded admin PDF ├── db_config.php Production database credentials ├── styles.css Shared admin styles ├── docs.html <-- This page │ ├── api/ │ ├── submit_survey.php Receives survey from browser * │ ├── verify_email.php Sends and verifies OTP * │ ├── notify.php Fallback notification (no DB save) │ ├── send_notification.php Sends secure link to client * │ ├── upload_admin_pdf.php Admin PDF uploads │ └── save_protected_link.php Saves protected link + password │ └── *.sql Migration scripts (run once)

* = actively called in the production flow

5

Survey Flow — End to End

From “Start Assessment” to client receiving their report

1
User completes the survey — browser only, no server contact

100% client-side JS on the ObscureIQ WordPress site. On “Complete Assessment”: answers collected, scores calculated, results shown instantly, full payload POSTed to api/submit_survey.php.

2
Basic submission saved

submit_survey.php validates API key + origin, inserts a type=basic record, generates a share_id, emails the team, returns { survey_id, share_id }.

3
User requests Advanced Analysis (optional)
  • Modal asks for name + email
  • verify_email.php (send_otp) stores a 6-digit OTP and emails it
  • User enters OTP → verified → basic record upgraded to advanced
  • Team receives “EMAIL VERIFIED — Advanced Analysis Request”
4
Team reviews in admin dashboard

Login to secured.php. View full Q&A answers, generate the report, upload a PDF, save internal notes.

5
Report delivered to client

Team clicks Send Alert → send_notification.php creates protected_pages row with token + auto credentials. Client emailed secure login. They log in via login.php → land on premium.php.

6

API Endpoints

All api/ endpoints — auth requirements and request/response shapes

All require: POST  ·  Content-Type: application/json  ·  X-API-Key header  ·  Origin in allowed list
POST/api/submit_survey.phpSave survey

New submission: { score, risk_level, risk_factors, recommendations, responses, response_labels }

Response 201: { message, survey_id, share_id }

Upgrade to advanced: { share_id, name, email }

POST/api/verify_email.phpOTP flow

Send: { action:"send_otp", name, email, survey_data }

Verify: { action:"verify_otp", email, otp_code }

10-min expiry 1 req/email/min 3 failures → new code
POST/api/notify.phpFallback only

Called if submit_survey.php fails. Emails team only — no DB save. Body: { notification_only:true, score, risk_level }

POST/api/send_notification.phpSend secure link

Generates UUID token + auto credentials, creates protected_pages row, emails the client.

Body: { survey_id, custom_url, message }  ·  Returns: login URL, username, password, expiry

POST/api/upload_admin_pdf.phpPDF upload

multipart/form-data with survey_id + pdf_file. Stores file, saves path to admin_pdf_path.

POST/api/save_protected_link.phpInternal link

Saves URL + optional password against a survey for internal admin tracking. Not sent to client.

7

Admin Dashboard

What you can do from secured.php

URL
surveys.obscureiq.com/secured.php
Login via
index.php
Password hardcoded there
Session Timeout
1 hour
Of inactivity

Tab 1 — Basic Surveys

Shows type=basic. Auto-deleted after 7 days on every dashboard load.

View Delete

Tab 2 — Advanced Surveys

Shows type=advanced. Permanently stored.

View Send Alert Upload PDF View PDF Protected Link See Password Delete

Export CSV button at top of this tab downloads all advanced survey data.

Tab 3 — Generate Advanced Report

Enter a Survey ID → Generate Report → formatted HTML page → print to PDF. Optional Analyst Pre-Analysis Note influences report tone (never shown verbatim to client).

8

Advanced Report Generation

How generate_advanced_report.php builds the analysis document

How it works

  1. Loads the survey record from DB by Survey ID
  2. Reads score, risk factors, response labels, heat tags
  3. Computes a deterministic seed from: client name + survey ID + score
  4. Each section selects from pools of pre-written phrases using that seed — same survey = same report, but two clients in the same band see different wording
  5. Renders full HTML; admin prints to PDF from browser

Report sections (24 total, in order)

SectionWhat it contains
Report SnapshotClient, date, score, risk band, exposure state
Risk Band LegendWhat each band means in practice
Two-Sentence TruthTwo sentences on the client's core risk mechanism
What This Report Means For You6 plain-language bullets
Bottom Line Assessment3 lines: status, linkage, timing warning
Likely Threat ScenariosTwo named scenarios — 3 paragraphs each
In Plain TermsWhat is happening / Why it matters / What accelerates risk
Likely Trajectory If UncheckedNow / Next / Failure mode
Recommended PosturePosture label + 4 actions
Index OverviewOne paragraph
Analytical SummaryOne paragraph
Primary Drivers4 bullets
Overall ReadOne paragraph
Hostility Index BreakdownPer-category scores + 2 bullets each
Heat Tag Risk IndexSelected tags + capped score
Activation Vectors / Fragility Zones / TriggersHow risk activates, exposed surfaces, escalation triggers
Threat Archetypes / Trajectory / ConfidenceStructural profile, forecasts, data quality assessment
Interpretation + TakeawayFinal paragraphs + posture reminder

Interpretive signal (internal only)

The synthesizeInterpretiveSignal() function reads the client’s optional free-text (Step 17) and the analyst’s pre-analysis note. It classifies them via keyword matching and selects an internal tone value (drift, tense, close, or persistent) that subtly shapes phrase selection. Neither the client text nor the analyst note is ever rendered verbatim.

9

Client Delivery

Protected links, PDFs, and how clients access their reports

Sending a secure link

Admin clicks “Send Alert” on any advanced row

Enters the results URL (defaults to premium.php) and writes a custom message.

api/send_notification.php creates credentials
  • UUID access token generated
  • Auto username + password created
  • Row inserted into protected_pages (72-hour expiry)
  • Client emailed: login URL, credentials, admin’s message
Client accesses their report

Visits link → login.php?token=… → enters credentials → lands on premium.php

Token expiry: Link expires after 72 hours. Client needs a new link from admin after that.

Admin PDF (internal only)

Upload PDF via the Upload PDF button → stored on server → viewable at admin_pdf.php?id={id}. Not automatically sent to the client.

10

Email Notifications

When, to whom, and what they contain

Team Recipients
jeff.jockisch@avantisprivacy.com
breachcheck@obscureiq.com
Method
PHP mail()
Hostinger server SMTP
TriggerToSubject / Content
New survey submittedTeam[ObscureIQ] New Survey Submission - {type} ({risk} Risk)
OTP verified (advanced request)Team[ObscureIQ] VERIFIED Advanced Analysis Request - {risk} Risk
Basic completion fallbackTeam[ObscureIQ] Survey Completed - Basic ({risk} Risk)
User requests advanced analysisUser's email6-digit OTP code, expires 10 minutes
Admin clicks Send AlertClient's emailSecure login URL, username, password, admin's custom message
11

Scoring System

How the Hostility Index score (0–196) is calculated

All scoring is browser-side JavaScript. The server stores the score as-is. To change scoring logic, update the WordPress shortcode JS file.

Structural score (max 121)

CategoryFieldsMax
Public Profileprofessional_visibility + public_recognition + obsessive_attention21
Financial Visibilityfinancial_visibility + financial_inquiries6
Social Media Reachsocial_media_reach6
Job / Leveljob_risk + sensitive_topics10
Threat Appetiteharassment_experience + doxxed_experience + safety_feeling24
Public Recordspublic_records (sum) + address_visibility + media_appearance11
Identity Threat Amplifierstargeted_groups (sum) + identity_harassment9
Network & Proximity Riskfamily_visibility + network_targeting9
Volatility / Visibility Riskattention_spike + polarizing_stances13
Identity Disclosurepublic_affiliations + controversial_topics + public_advocate12

Heat Tags (max 30–75 based on Identity Disclosure)

hot_button_brands
Cap: 35
hot_button_political
Cap: 25
hot_button_professional
Cap: 15
hot_button_tech
Cap: 15
hot_button_identity
Cap: 10
hot_button_science
Cap: 10

Overall Heat Tag cap: Identity Disclosure <4 → 30  ·  4–7 → 60  ·  ≥8 → 75

JS
overall_score = Math.min(structural + heat_tags, 196)

Risk bands

LOW
0–31
MODERATE
32–80
ELEVATED
81–117
HIGH
118–148
CRITICAL
149–196
12

Authentication & Sessions

How admin and client logins work

Admin login

index.php has a hardcoded password. On success sets $_SESSION['logged_in']=true. All dashboard pages check this on every load. Timeout: 1 hour of inactivity.

Client login

login.php?token=… looks up token in protected_pages, verifies username + password, then sets session vars and redirects to protected.php or premium.php.

13

Data Retention

What gets kept, deleted, and when

7 days
Basic Surveys
Auto-deleted on every secured.php load. Anonymous score data only.
∞ Forever
Advanced Surveys
Permanently stored. Name, email, full responses. Never auto-deleted.
On request
OTP Codes
Expired OTP records cleaned up on next OTP request for same email.

Note: Basic deletion only runs when an admin visits secured.php. A cron job would eliminate this dependency.

14

Advanced Analysis Architecture

How the analysis engine works and what data it receives

The analysis is generated in one file: generate_advanced_report.php. Every report section is a dedicated PHP function in this file, each producing structured output based on the survey data.

How the analysis engine works

Each section is produced by a dedicated PHP function (e.g. twoSentenceTruth(), likelyThreatScenarios(), wtmBullets()) that selects from pools of carefully written phrases using a deterministic seed derived from the client’s data. Same survey always produces the same report; different clients in the same risk band see different phrasing.

Complete data set available per survey record

$hostilityScore
Integer 0–196. The overall calculated score.
$riskBand
Low / Moderate / Elevated / High / Critical
$riskFactors
Per-category { score, max } for all 11 categories
$heatTags
Array of selected heat tag labels (e.g. “Journalist”, “MAGA”)
$surveyExtraContext
Client’s free-text from Step 17 (“additional context”)
$portalNotes
Analyst’s pre-analysis note from the “Generate Advanced Report” dashboard tab
$clientIdentifier
Name, email, or “Survey ID {n}” if neither is available
response_labels
Human-readable answers to every question in the survey

Privacy constraint: The client’s free-text and analyst notes are never rendered verbatim in the report output. They are used only to infer tone and framing, not echoed back.

15

Security Notes

Known issues and things to be aware of

API key exposed in browser source
Hardcoded in frontend JS — visible in DevTools. Acts as a caller gate, not a real secret. To rotate: update all 6 API PHP files and the WordPress shortcode JS simultaneously.
Database credentials in plain text
db_config.php has DB username + password in plain text. Hostinger blocks direct access by default — verify .htaccess if adding new paths.
CORS open to all origins in verify_email.php
Access-Control-Allow-Origin: * was set during debugging. Should be locked to the allowed origins list (obscureiq.com, surveys.obscureiq.com) when stable.
Admin password is hardcoded in index.php
Consider moving to an environment variable or .env file for easier rotation.
Basic survey cleanup depends on admin activity
The 7-day delete only runs when someone visits secured.php. A scheduled cron job would run it independently.
Jeff Jockisch
Special Thanks
Jeff Jockisch
Privacy Strategist & Co-Founder, ObscureIQ

One of the world’s leading experts on data brokers and commercial surveillance, Jeff has spent years mapping the architecture of the commercial data ecosystem — understanding what’s being collected, by whom, and exactly how to neutralize it.

The product vision behind this entire survey system — from the Hostility Index scoring model to every section of the Advanced Analysis report — was shaped and guided by Jeff’s deep expertise in privacy risk, identity exposure, and threat profiling. His fingerprints are on every page of this portal.

ObscureIQ
ObscureIQ Survey Portal — Internal System Documentation · July 2026
obscureiq.com