# Harbor Rates · Edge shield — Product Requirements (v7.2)

Harbor Rates is a container freight rates and booking portal that sits behind Edge shield, an edge bot-management layer. An open zone (overview and edge trace) needs no check; the rates board is a managed zone fronted by a checkbox interstitial with up to 3 attempts; the booking desk is a strict zone with a single attempt. Every verdict gets an Incident ID and is listed in a per-tab edge trace, and blocked visitors can file a false-positive report.

**Problem.** Shippers need live rates and booking space, while the operator must keep automated scraping and abuse away from them. Visitors must be able to understand why they were challenged or blocked, and a wrongly blocked human must have a way to report it with a reference that support can look up.

## Users
- **Shipper (human visitor)** — Pass a quick check once, browse rates, and request space without being challenged again for 15 minutes.
- **Automated runner** — Be detected consistently: blocked with a visible Incident ID instead of being let through or left in a loop.
- **Security operator** — See every edge decision with its score and the signals behind it, and receive false-positive reports that cite the right block.

## Goals
- Detected automation never reaches protected content; humans are cleared for 15 minutes per zone.
- Every verdict (challenge, retry, pass, block) is recorded with an Incident ID, score and signals, and what the page shows matches the trace.
- Protected data is never returned without clearance, on pages or on the API.

## Overview (OVR)

Open landing page that explains the three protection zones.

- **FR-OVR-01** (Must) The overview loads without any check and presents the three zones with a coloured tag and status dot each.
  - Hero "Ocean freight rates, refreshed weekly" with tiles Lanes 16, Carriers 5 and Edge PoP (a three-letter code)
  - Rates board: amber MANAGED tag, "Challenge on entry"; Booking desk: red STRICT tag, "Challenge on entry"; Edge trace: grey OPEN tag, "Open"
  - A green "Protected" chip in the top bar with tooltip "Traffic to this site passes through Edge shield"
- **FR-OVR-02** (Should) A protection-levels legend states what each level means.
  - OPEN: "No check."
  - MANAGED: up to 3 attempts, then blocked
  - STRICT: "One attempt; any automation signal blocks the visitor."
  - The Edge PoP tile tooltip reads "Point of presence that served this tab"
- **FR-OVR-03** (Should) Zone cards reflect the tab’s current state.
  - A blocked zone shows a red dot and "Blocked" while the other zone is unaffected
  - A cleared zone shows a green dot with "Cleared · m:ss"

## Managed challenge (rates board) (CHL)

Checkbox interstitial in front of the rates board with up to 3 attempts.

- **FR-CHL-01** (Should) Opening the rates board without clearance shows a full-page interstitial with all its parts.
  - Tab title "Just a moment… · harbor-rates.example"
  - Heading with the host name, "Verify you are human by completing the action below.", a checkbox widget labelled "Verify you are human" with the Edge shield mark and "Privacy · Terms" links
  - Chip "Attempt 1 of 3" with tooltip "Failed attempts block this browser for the rates board"
  - Footer with an Incident ID (16 hex characters, a dash and the PoP code), "Protected by Edge shield" and a MANAGED tag
- **FR-CHL-02** (Must) A failed managed check advances the attempt counter and re-issues the challenge.
  - Widget shows a red ✕ "Failed" and "✕ Verification failed. Try again."
  - A new Incident ID is shown, the widget resets after about 2 s and the chip reads "Attempt 2 of 3", then "Attempt 3 of 3"
- **FR-CHL-03** (Must) The third failed managed check blocks the visitor for the rates board.
  - The widget shows "Blocked", then the block page appears with tab title "Attention Required! · harbor-rates.example"
  - The explanation states the browser failed the verification challenge three times in a row
  - The block is per zone: the booking desk is not affected
- **FR-CHL-04** (Could) An unused challenge expires after 60 seconds and can be refreshed without costing an attempt.
  - Widget turns orange with label "Expired · Refresh"
  - After "Refresh" the widget is back to "Verify you are human" and the chip still shows "Attempt 1 of 3"

## Strict zone (booking desk) (STR)

Single-attempt interstitial in front of the booking desk.

- **FR-STR-01** (Must) A visitor showing automation signals is blocked on the first attempt and never sees the booking form.
  - Interstitial subtitle "Verifying your connection", a "Single attempt" chip and the line "This area is under strict protection — one attempt only."
  - After the click the widget shows "Blocked" and the block page "Access to this page is denied" appears with a STRICT tag
  - The page explains that a security service protects the site from automated access
  - No Lane select, stepper or "Request booking" button is shown
- **FR-STR-02** (Must) A block persists for the tab: reloading shows the same block page and Incident ID without a new challenge.
  - No checkbox widget is shown after reload and the Incident ID is unchanged
  - The overview shows the Booking desk as blocked while the Rates board still shows "Challenge on entry"

## Block page and false-positive report (BLK)

What a blocked visitor sees and how they can appeal.

- **FR-BLK-01** (Must) The block page always shows the Incident ID of the block, with a copy control, so a report can be filed.
  - Headline "Access to this page is denied" / "You are unable to access harbor-rates.example"
  - Footer shows the Incident ID as 16 hex characters, a dash and the PoP code, plus a copy icon (toast "Copied")
  - "Your IP: Click to reveal" reveals the address
- **FR-BLK-02** (Could) The block page diagram marks the edge as the failing hop.
  - You / Browser: green ✓ "Working"; Edge shield / Security layer: red ✕ "Blocked"; host: green ✓ "Working"
  - Nodes are joined by dashed grey connectors
- **FR-BLK-03** (Must) A blocked visitor can file a false-positive report; the resulting ticket cites the Incident ID of the block shown on the page.
  - "Report a false positive" opens a modal showing the block’s Incident ID under the title
  - On success: "Report received", a ticket "FP-" followed by six digits and the same Incident ID
  - The note "The site owner reviews reports within two business days." is shown
  - The Details box shows a live counter such as "22 / 500"
- **FR-BLK-04** (Should) The report form validates its fields and reports each problem separately.
  - Invalid email: "Enter a valid email address"
  - No reason chosen: "Choose a reason"
  - Reason "Something else" with fewer than 10 characters of details: "Describe the problem (at least 10 characters)"
  - Nothing is filed until every rule passes
- **FR-BLK-05** (Could) The report modal can be dismissed by ✕, Cancel or a click on the backdrop; nothing is filed and the form is empty when reopened.

## Edge trace (TRC)

Per-tab, open-to-all log of every edge decision with its reasoning.

- **FR-TRC-01** (Should) A fresh tab shows an empty trace and clean zone tiles.
  - MANAGED "Rates board" tile: "Not cleared", "Failed attempts: 0 / 3"; STRICT "Booking desk" tile: "Not cleared"
  - Table row "No edge decisions yet — open the Rates board or Booking desk."
  - Legend chips "strong · 60", "medium · 25", "weak · 10" and a PoP chip equal to the overview tile
- **FR-TRC-02** (Must) Every verdict is recorded with the same Incident ID that the visitor saw, the zone, path, verdict, bot score and signals.
  - Serving an interstitial adds a blue CHALLENGE row (score "—", "challenge served") whose Incident ID equals the interstitial footer
  - A failed managed check adds an amber RETRY row; a block adds a red BLOCK row; a pass adds a green PASS row
  - BLOCK and RETRY rows always show the numeric score and at least one signal chip (strong signals have a red dot, tooltip "strong signal")
  - The score bar tooltip reads "Bot score <n> · <zone> threshold <t>" with thresholds 50 (managed) and 25 (strict)
- **FR-TRC-03** (Should) Zone tiles summarise the managed and strict state.
  - Managed tile counts failed attempts, e.g. "Failed attempts: 1 / 3"
  - A blocked zone shows a red dot with "Blocked (attempts)" for managed and "Blocked (signals)" for strict
  - Three failed managed checks yield two RETRY rows and one BLOCK row
- **FR-TRC-04** (Could) The Incident ID in the trace has a copy icon (tooltip "Copy", toast "Copied").

## Detection and scoring (SCR)

How client signals and request headers become a verdict.

- **FR-SCR-01** (Must) The score is the sum of the hit signals (strong 60, medium 25, weak 10, capped at 100); a visitor passes only when the score is below the zone threshold (managed 50, strict 25).
  - Strong signals: automation flag, headless user agent, automation runtime, invalid proof-of-work
  - Medium: no pointer movement, instant click, missing Accept-Language; weak: empty plugin list, empty language list, zero-size window
  - A visitor with the automation flag set is never passed in either zone
- **FR-SCR-02** (Must) A successful check issues a clearance for that zone only, valid for 15 minutes, and resets that zone’s failed attempts.
  - The rates board shows a green "Cleared · 14:5x" chip counting down, tooltip "Edge clearance for the rates board; you will be checked again when it runs out"
  - Clearing the managed zone does not clear the strict zone and vice versa
  - While clearance is valid the zone opens without a new interstitial

## Rates board (RAT)

Filterable, sortable board of 16 container lanes (managed zone).

- **FR-RAT-01** (Must) After clearing the managed check the rates board opens and lists all lanes with a clearance countdown and summary tiles.
  - Header "Rates board", "Week 42 · published Mon 12 Oct 2026"; lane count "16 of 16 lanes"
  - KPI tiles "Cheapest 40HC $2,650 · KRPUS→USLAX", "Avg transit 21 days", "This week ▲ 6 ▼ 6 = 4"
  - The trace gains a green PASS row for MANAGED /rates
- **FR-RAT-02** (Should) Filters for origin, equipment, direct-only and search combine, and the lane count updates.
  - Origin "VNSGN · Ho Chi Minh City" gives 5 lanes; with 40HC 3 lanes (R-1001, R-1002, R-1004); with Direct only 2 lanes (R-1002 is transshipment)
  - Origin VNSGN with equipment "All" and Direct only gives 4 lanes (R-1001, R-1003, R-1004, R-1016)
  - Search "kestrel" within that set gives 1 lane (R-1004)
- **FR-RAT-03** (Should) Sortable headers sort ascending then descending with a visible direction marker.
  - Default All-in ascending (▲), first row R-1016 $560; clicking All-in gives ▼ with R-1012 $6,450 first
  - Reliab. ascending starts at R-1010 (66%, red dot); Transit ascending starts at R-1016 "3 d"
  - Other sortable headers show a faint ↕
- **FR-RAT-04** (Must) A lane’s all-in price equals base plus all surcharges, and the drawer breakdown sums to it.
  - R-1007 drawer: "Shanghai → Rotterdam", Base $3,015, BAF $480, CAF $55, THC $210, "All-in per container $3,760"
  - Meta row shows carrier "Orion Lines", chip "40HC" and "28 days direct"
  - Trend shows low $2,800 and high $3,015
- **FR-RAT-05** (Could) Row markers read correctly.
  - R-1005: VNHPH tooltip "Haiphong", carrier MRD tooltip "Meridian Box", Transit "34 d" with a "T/S" badge (tooltip "Transshipment via a hub port")
  - Reliab. "68%" with a red dot; Δ wk green "▼ 4.2%"; falling sparkline; surcharge badges BAF, PSS, THC, EBS (tooltip "EBS · Emergency bunker surcharge · $120")
  - All-in "$5,490" and Valid "10-31" with an amber "!" badge
- **FR-RAT-06** (Could) The star icon pins a lane without opening the drawer, and the "★ Pinned" switch filters to pinned lanes.
  - Tooltip "Pin lane"; the star fills yellow
  - Pinned filter shows "1 of 16 lanes"; unpinning the only lane shows "0 of 16 lanes" and "No lanes match these filters."

## Booking desk (BKG)

Request container space once cleared by the strict check.

- **FR-BKG-01** (Must) A cleared visitor can request a booking; the estimate is quantity times the lane all-in price and the request is listed with its reference.
  - Lane "KRPUS → USLAX · HLX · 40GP · $2,450" with quantity 1 shows "$2,450 (1 × $2,450)"; with 3 containers "$7,350 (3 × $2,450)"
  - The − button is disabled at quantity 1
  - Confirmation "Booking requested", "Reference HBR-xxxxx · total $7,350"
  - "Your requests" lists HBR-xxxxx · R-1015 · 3 · 2026-11-20 · — · Lotus Garments Co. with an amber "Requested" status
- **FR-BKG-02** (Must) The booking desk validates lane, quantity, shipper, ready date, UN number and equipment, and creates nothing on failure.
  - No lane: "Choose a lane" (lane select outlined red)
  - Ready date after the lane validity: "Rate is valid until 2026-10-31" for R-1016
  - Quantity must be 1–50: "Containers must be 1–50"; shipper required: "Shipper is required"
  - Dangerous goods require "UN" followed by four digits: "UN number must look like UN1263"
  - Dangerous goods on reefer equipment (40RF): "Reefer equipment cannot carry dangerous goods"
  - A valid dangerous-goods booking shows an orange UN badge on its row
- **FR-BKG-03** (Should) Booking a lane from the rates drawer opens the strict check and preselects the lane after clearing.
  - R-1001 preselects "VNSGN → USLAX · ORN · 40HC · $3,715"
  - The rates board stays open without a new interstitial

## API protection (API)

Protected API routes honour the same clearance as the pages.

- **FR-API-01** (Must) Protected API routes never return data without clearance.
  - The rates and booking routes answer 403 with marker "challenge", the zone and an Incident ID
  - A challenge request for a zone returns an id, nonce, difficulty 14 bits, attempt 1 and maxAttempts (3 managed, 1 strict)
  - A failed strict verification answers 403 "Access to this page is denied" with marker "block" and an Incident ID; later requests return the same block and Incident ID
  - The trace lists that BLOCK with its signals (e.g. webdriver and pow_invalid)

## Non-functional requirements

- **NFR-01** (Must) The Incident ID format is 16 lowercase hex characters, a dash and the PoP code, and an Incident ID is unique per verdict.
- **NFR-02** (Should) State (clearance, blocks, trace, reports) is isolated per browser tab; a fresh tab starts with no clearance and an empty trace.
- **NFR-03** (Should) Challenge and clearance behaviour is deterministic: repeated visits within clearance never loop back to the interstitial.

## Glossary and rules

- **Incident ID** — Reference for one edge decision: 16 hex characters, a dash and the PoP code.
- **PoP** — Point of presence: the edge location that served the tab, shown as a three-letter code.
- **Clearance** — A 15-minute permission, per zone, issued after a passed check.
- **Bot score** — Sum of signal weights (0–100) compared with the zone threshold.

## Out of scope

- Evading or bypassing the shield
- Real network or IP reputation
- Payment and carrier fulfilment
