← Back to Blog

Tribe Marks: Collaborative Tactical Notes Without the Overhead

EVE Frontier is a social game—alliances coordinate territory control, corporations run joint mining operations, and explorer squads scout wormhole chains together. But spatial coordination is hard when everyone has their own mental map.

Tribe Marks solve this by letting groups share lightweight tactical annotations directly on the star map—no standing up servers, no complex permissions, no user accounts. Just pick a tribe name, start marking systems, and your squadmates see the same notes.

This post explains how Tribe Marks work, the privacy/concurrency safeguards we built, and how EVE Frontier communities are using them for real-time tactical coordination.

The Problem: Coordination Without Shared Context

Scenario 1: Explorer Squad Wormhole Chain Mapping

Your 5-person explorer squad is scanning a J-space wormhole chain. You discover:

You want to share this intel instantly with your squad, but:

Result: Squad members duplicate scanning (wasting time) or miss critical intel (walking into danger).

Scenario 2: Alliance Territory Markers

Your alliance controls 12 systems. You want to mark:

Without shared markers, every pilot maintains their own notes—inconsistent, out-of-date, and incomplete.

The Solution: Tribe Marks

Tribe Marks are shared tactical annotations on the star map. Each mark consists of:

Marks are grouped by tribe—any EF-Map user can create or join a tribe just by choosing a tribe name. No signup, no permissions, no admin overhead.

How It Works: Cloudflare KV + Optimistic Concurrency

Backend: Serverless Key-Value Storage

Tribe marks are stored in Cloudflare Workers KV—a globally distributed key-value store.

Key format:

tribe:<tribe_name>:marks

Value: JSON document with all marks for that tribe:

{
  "version": 1,
  "tribe": "wormhole-scouts",
  "marks": [
    {
      "id": "mark_1729000001",
      "system_id": "30000142",
      "title": "Safe mining",
      "note": "Veldspar belt A - no hostiles",
      "color": "#00ff00",
      "verified": true
    },
    {
      "id": "mark_1729000002",
      "system_id": "30000144",
      "title": "PvP danger",
      "note": "Hostile corp active - avoid",
      "color": "#ff0000",
      "verified": false
    }
  ],
  "etag": "abc123def456"
}

ETag: Version identifier for optimistic concurrency control (explained below).

Fetching Marks

When you join a tribe, the web app fetches its marks:

async function fetchTribeMarks(tribeName: string): Promise<TribeMark[]> {
  const response = await fetch(`/api/tribe-marks?tribe=${encodeURIComponent(tribeName)}`);
  
  if (!response.ok) return [];
  
  const data = await response.json();
  return data.marks;
}

The Cloudflare Worker queries KV:

export default {
  async fetch(req, env) {
    const url = new URL(req.url);
    const tribeName = url.searchParams.get('tribe');
    
    const key = `tribe:${tribeName}:marks`;
    const doc = await env.TRIBE_MARKS.get(key, { type: 'json' });
    
    if (!doc) {
      return new Response(JSON.stringify({ marks: [] }), {
        headers: { 'Content-Type': 'application/json' }
      });
    }
    
    return new Response(JSON.stringify(doc), {
      headers: { 
        'Content-Type': 'application/json',
        'ETag': doc.etag
      }
    });
  }
}

Marks appear on the map as colored icons next to system names.

Adding/Editing Marks: Optimistic Concurrency

When you add or edit a mark, the app uses optimistic concurrency control to prevent conflicts:

  1. Fetch current tribe document (includes etag)
  2. Make local changes (add/edit mark)
  3. Send mutation request with If-Match: header
  4. Server checks if etag matches current version

- Match: Apply changes, generate new etag, save

- Mismatch: Reject with 409 Conflict, return latest etag

  1. On conflict, client auto-retries with latest data

Code (client):

async function addTribeMark(tribeName: string, mark: TribeMark): Promise<void> {
  const currentDoc = await fetchTribeMarks(tribeName);
  const currentEtag = currentDoc.etag;
  
  const newDoc = {
    ...currentDoc,
    marks: [...currentDoc.marks, mark]
  };
  
  const response = await fetch('/api/tribe-marks/mutate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'If-Match': currentEtag
    },
    body: JSON.stringify({
      tribe: tribeName,
      ops: [{ type: 'add', mark }]
    })
  });
  
  if (response.status === 409) {
    // Conflict - retry with latest data
    return addTribeMark(tribeName, mark);
  }
  
  if (!response.ok) throw new Error('Failed to add mark');
}

Code (server):

async function handleMutation(req, env) {
  const { tribe, ops } = await req.json();
  const ifMatch = req.headers.get('If-Match');
  
  const key = `tribe:${tribe}:marks`;
  const currentDoc = await env.TRIBE_MARKS.get(key, { type: 'json' }) || { marks: [], etag: '' };
  
  // Check ETag
  if (ifMatch && ifMatch !== currentDoc.etag) {
    return new Response(JSON.stringify({ error: 'etag_mismatch', latest: currentDoc }), {
      status: 409,
      headers: { 'Content-Type': 'application/json', 'ETag': currentDoc.etag }
    });
  }
  
  // Apply mutations
  let marks = currentDoc.marks;
  for (const op of ops) {
    if (op.type === 'add') {
      marks.push(op.mark);
    } else if (op.type === 'edit') {
      marks = marks.map(m => m.id === op.mark.id ? op.mark : m);
    } else if (op.type === 'delete') {
      marks = marks.filter(m => m.id !== op.markId);
    }
  }
  
  // Generate new ETag
  const newEtag = generateEtag(marks);
  const newDoc = { version: 1, tribe, marks, etag: newEtag };
  
  await env.TRIBE_MARKS.put(key, JSON.stringify(newDoc));
  
  return new Response(JSON.stringify(newDoc), {
    headers: { 'Content-Type': 'application/json', 'ETag': newEtag }
  });
}

Why optimistic concurrency?

Without it, if two pilots add marks simultaneously:

Pilot A: Fetches tribe doc (10 marks)
Pilot B: Fetches tribe doc (10 marks)
Pilot A: Adds mark #11, saves (11 marks)
Pilot B: Adds mark #12, saves (11 marks) ← Pilot A's mark is LOST!

With ETag concurrency:

Pilot A: Fetches (etag: "v1")
Pilot B: Fetches (etag: "v1")
Pilot A: Adds mark #11, saves with If-Match: "v1" → SUCCESS (etag: "v2")
Pilot B: Adds mark #12, saves with If-Match: "v1" → CONFLICT (etag is now "v2")
Pilot B: Retries with latest doc (includes mark #11), adds mark #12 → SUCCESS

Both marks are preserved.

Tribe Name as Access Key

No user accounts. You join a tribe just by typing its name:

Enter tribe name: wormhole-scouts

Anyone who knows the name can read and write marks. This is intentional—tribes are lightweight coordination tools, not secure vaults.

Security model:

Why no authentication?

Adding auth (login, roles, permissions) would:

For ad-hoc tactical coordination, the trade-off isn't worth it. Tribes are ephemeral by design.

Content Sanitization

All mark text is sanitized to prevent XSS and keep annotations signal-focused:

Blocked Content

Example:

Input:  "Join our Discord: https://discord.gg/abc123"
Output: "Join our Discord: [link]"

Why block links?

Tribes are for tactical notes, not advertising. If you need to share a link, use a separate communication channel (Discord, forum post, etc.).

Allowed Content

Example valid marks:

Title: "⚠️ PvP Zone"
Note:  "Hostile corp spotted @ 14:30 UTC. 3 battleships patrolling."

Limits and Quotas

To keep tribes lightweight and prevent abuse:

If you hit limits, consider splitting into multiple tribes (e.g., tribe-alpha-mining, tribe-alpha-pvp).

Verified Flag: Crowd-Sourced Intel

Any tribe member can toggle the verified flag on a mark:

✓ Safe mining (verified by 3 pilots)
✗ Hostile spotted (unverified report)

Use case: An explorer reports "Hostile spotted" (unverified). Two squadmates jump to the system, confirm the hostile is still there, and mark it verified. Now everyone trusts the intel.

Implementation:

The verified flag is just a boolean—no vote counting (yet). Future versions might track "verified by X pilots" counts.

Color Coding: Visual Shortcuts

Marks support 8 preset colors + custom hex:

Custom hex: For tribe-specific color schemes (e.g., alliance branding).

Rendering: Marks appear as colored dots next to system names on the map. Hover to see title/note.

Folders: Organizing Marks

Tribes can create folders to group related marks:

📁 Mining Sites
  ├─ System A: Veldspar belt
  ├─ System B: Scordite rich
  └─ System C: Gas cloud

📁 PvP Hotspots
  ├─ System X: Border patrol
  └─ System Y: Chokepoint

📁 Wormhole Exits
  └─ System Z: K-space connection

Limit: 100 folders per tribe.

Use case: An alliance creates folders for each region they control, organizing marks by territory.

Privacy and Transparency

No PII Stored

Marks contain only:

Never stored:

Public Read Access

Anyone can read any tribe's marks if they know the tribe name:

GET /api/tribe-marks?tribe=wormhole-scouts

Returns all marks (no auth required).

Why public?

This enables:

If you need private notes, use personal browser bookmarks or a separate tool.

Use Cases

Use Case 1: Wormhole Explorer Squad

Tribe: wh-scouts-oct25

Marks:

Workflow:

  1. Scout jumps to System A, scans down sites
  2. Creates mark: "Safe mining - 3 data sites"
  3. Squadmates see mark instantly on their maps
  4. Everyone avoids System B (red flag)
  5. When done, everyone uses System C exit

Result: Zero duplicate scanning, instant intel propagation.

Use Case 2: Alliance Territory Management

Tribe: alliance-alpha-territory

Marks:

Workflow:

  1. FCs create marks for strategic systems
  2. New members join tribe, see all marks
  3. Haulers prioritize orange-marked systems
  4. Patrols focus on red-marked borders

Result: Coordinated operations without complex spreadsheets.

Use Case 3: Event Organizers

Tribe: pvp-tournament-oct25

Marks:

Workflow:

  1. Organizers create marks before event
  2. Participants join tribe week before
  3. Everyone knows where to stage, where to avoid
  4. Day of event, marks guide participants to arena

Result: Smooth event execution, clear boundaries.

Troubleshooting

"My mark isn't appearing for others"

Cause: Network lag or cache staleness.

Fix: Wait 30 seconds (marks propagate globally within 60s). If still missing, ask squadmate to refresh the page.

"Someone deleted my mark"

Cause: Any tribe member can delete marks.

Fix: Use verified marks for critical intel (less likely to be deleted). For permanent notes, consider a separate tool (Discord pins, Google Doc, etc.).

"I can't add more marks"

Cause: Tribe hit the 300-mark limit.

Fix: Delete old/outdated marks, or create a new tribe (tribe-name-v2).

Future Enhancements

Planned Features

Community Requests

Content Policy

Tribe marks must comply with our content policy:

Report violations: email [email protected] with tribe name and mark excerpt.

Enforcement: Offending marks are removed within 72 hours. Repeated violations may lead to tribe suspension.

Full policy: https://ef-map.com/POLICY.md

Getting Started (2 Minutes)

Step 1: Pick a Tribe Name

Choose a unique, memorable name:

wormhole-scouts
alliance-alpha-mining
pvp-fleet-bravo

Share it with your squadmates via Discord/voice.

Step 2: Join the Tribe

In EF-Map, open the Tribe Marks panel → Enter tribe name → "Join Tribe".

Step 3: Add Your First Mark

  1. Right-click a system on the map
  2. Select "Add Tribe Mark"
  3. Fill in title, note, color
  4. Save

Squadmates see the mark within 30 seconds.

Step 4: Verify Important Intel

For critical marks (e.g., "Hostile spotted"), toggle the verified flag after confirming the info.

You're now coordinating!

Related Posts

Tribe Marks bring real-time tactical coordination to EVE Frontier without the overhead of complex permission systems or user accounts—just pick a name, start marking, and fly together!

collaborationtribe marksannotationscloudflare kvoptimistic concurrency