feat: MVP implementation — MCP server, partner one-pager, legal docs
Code (code/): - TypeScript MCP server with 5 tools (business info, hours, services, booking, related) - PostgreSQL schema with pilot business seed data - /.well-known/mcp-server manifest generator - Railway deployment config (Dockerfile, railway.json) - Multi-tenant gateway placeholder GTM (docs/gtm/): - Partner One-Pager: agency sales asset with economics, onboarding, competitive comparison Legal (docs/legal/): - Data Flow & Privacy: data collection, storage, sharing, GDPR/CCPA commitments - Partnership Agreement Skeleton: template for agency/CoC partnerships - IP Notes: well-known convention positioning, telemetry ownership, open-source strategy
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.env
|
||||||
|
*.log
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FROM node:22-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
RUN npm ci --production
|
||||||
|
|
||||||
|
COPY dist/ ./dist/
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
Generated
+2456
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "geolocal-io-mcp",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Multi-tenant MCP server for geolocal.io \u2014 AI-native local business discovery",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tsx src/index.ts",
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "node dist/index.js",
|
||||||
|
"seed": "tsx src/db/seed.ts",
|
||||||
|
"test": "tsx --test tests/*.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||||
|
"fastify": "^5.0.0",
|
||||||
|
"pg": "^8.13.0",
|
||||||
|
"dotenv": "^16.4.0",
|
||||||
|
"zod": "^3.24.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"tsx": "^4.0.0",
|
||||||
|
"typescript": "^5.7.0",
|
||||||
|
"@types/pg": "^8.11.0",
|
||||||
|
"@types/node": "^22.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://railway.app/railway.schema.json",
|
||||||
|
"build": {
|
||||||
|
"builder": "DOCKERFILE",
|
||||||
|
"dockerfilePath": "./Dockerfile"
|
||||||
|
},
|
||||||
|
"deploy": {
|
||||||
|
"startCommand": "npm start",
|
||||||
|
"healthcheckPath": "/health",
|
||||||
|
"healthcheckTimeout": 100,
|
||||||
|
"restartPolicyType": "ON_FAILURE",
|
||||||
|
"restartPolicyMaxRetries": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const config = {
|
||||||
|
port: parseInt(process.env.PORT || '3000', 10),
|
||||||
|
databaseUrl: process.env.DATABASE_URL || 'postgresql://localhost:5432/geolocal',
|
||||||
|
calcomBaseUrl: process.env.CALCOM_BASE_URL || 'https://api.cal.com',
|
||||||
|
stripeApiKey: process.env.STRIPE_API_KEY || '',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Pool } from 'pg';
|
||||||
|
import { config } from '../config.js';
|
||||||
|
|
||||||
|
const pool = new Pool({ connectionString: config.databaseUrl });
|
||||||
|
|
||||||
|
export async function initSchema() {
|
||||||
|
await pool.query(`
|
||||||
|
CREATE TABLE IF NOT EXISTS businesses (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
slug VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
name VARCHAR(500) NOT NULL,
|
||||||
|
category VARCHAR(100),
|
||||||
|
address TEXT,
|
||||||
|
city VARCHAR(200),
|
||||||
|
state VARCHAR(50),
|
||||||
|
zip VARCHAR(20),
|
||||||
|
phone VARCHAR(50),
|
||||||
|
website VARCHAR(500),
|
||||||
|
hours JSONB DEFAULT '{}',
|
||||||
|
services JSONB DEFAULT '[]',
|
||||||
|
story TEXT,
|
||||||
|
owner_bio TEXT,
|
||||||
|
photos JSONB DEFAULT '[]',
|
||||||
|
calcom_link VARCHAR(500),
|
||||||
|
mcp_endpoint VARCHAR(500),
|
||||||
|
related_business_ids INTEGER[] DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_businesses_slug ON businesses(slug);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_businesses_category ON businesses(category);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_businesses_city_state ON businesses(city, state);
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { pool };
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { pool, initSchema } from './schema.js';
|
||||||
|
|
||||||
|
async function seed() {
|
||||||
|
await initSchema();
|
||||||
|
|
||||||
|
await pool.query(`
|
||||||
|
INSERT INTO businesses (slug, name, category, address, city, state, zip, phone, website, hours, services, story, calcom_link, photos)
|
||||||
|
VALUES (
|
||||||
|
'frisco-german-auto',
|
||||||
|
'Frisco German Auto Specialists',
|
||||||
|
'auto-repair',
|
||||||
|
'1234 Main St',
|
||||||
|
'Frisco',
|
||||||
|
'TX',
|
||||||
|
'75034',
|
||||||
|
'(469) 555-0123',
|
||||||
|
'https://friscogermanauto.example.com',
|
||||||
|
'{"monday_friday": "8AM-6PM", "saturday": "9AM-3PM", "sunday": "closed"}',
|
||||||
|
'[
|
||||||
|
{"name": "Oil Change", "price": 65, "description": "Full synthetic oil change for European vehicles"},
|
||||||
|
{"name": "Brake Inspection", "price": 100, "description": "Complete brake system inspection and quote"},
|
||||||
|
{"name": "Diagnostics", "price": 150, "description": "Computer diagnostics for check engine light and electrical issues"},
|
||||||
|
{"name": "Tire Rotation", "price": 40, "description": "Tire rotation and balancing"}
|
||||||
|
]',
|
||||||
|
'Family-run shop with 40 years of experience, specializing in BMW, Mercedes, and Audi. We treat every car like our own.',
|
||||||
|
'https://cal.com/friscogermanauto',
|
||||||
|
'["https://example.com/photos/shop-front.jpg", "https://example.com/photos/service-bay.jpg"]'
|
||||||
|
)
|
||||||
|
ON CONFLICT (slug) DO NOTHING;
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log('\u2705 Seed data inserted');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
seed().catch(console.error);
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||||
|
import { createMCPServer } from './mcp-server.js';
|
||||||
|
import { initSchema } from './db/schema.js';
|
||||||
|
import { config } from './config.js';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Initialize database
|
||||||
|
await initSchema();
|
||||||
|
console.error('\u2705 Database schema initialized');
|
||||||
|
|
||||||
|
// Create and start MCP server
|
||||||
|
const server = createMCPServer();
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
|
||||||
|
await server.connect(transport);
|
||||||
|
|
||||||
|
console.error(`\u2705 geolocal.io MCP server v0.1.0 running`);
|
||||||
|
console.error(` Port: ${config.port}`);
|
||||||
|
console.error(` Tools: get_business_info, get_hours, get_services, get_booking_link, get_related_businesses`);
|
||||||
|
console.error(` Discovery: /.well-known/mcp-server`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error('\u274C Failed to start:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { pool } from './db/schema.js';
|
||||||
|
|
||||||
|
interface ManifestConfig {
|
||||||
|
businessSlug: string;
|
||||||
|
serverBaseUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the /.well-known/mcp-server JSON manifest.
|
||||||
|
*
|
||||||
|
* Businesses (or their agencies) upload this file to their website root
|
||||||
|
* at `/.well-known/mcp-server`. AI agents discover it automatically.
|
||||||
|
*/
|
||||||
|
export function generateManifest(config: ManifestConfig): Record<string, any> {
|
||||||
|
const { businessSlug, serverBaseUrl } = config;
|
||||||
|
return {
|
||||||
|
mcp_server: `${serverBaseUrl}/mcp/${businessSlug}`,
|
||||||
|
protocol: 'streamable-http',
|
||||||
|
version: '0.1.0',
|
||||||
|
business: businessSlug,
|
||||||
|
provider: 'geolocal.io',
|
||||||
|
discovery: {
|
||||||
|
transport: 'stdio',
|
||||||
|
tools: [
|
||||||
|
'get_business_info',
|
||||||
|
'get_hours',
|
||||||
|
'get_services',
|
||||||
|
'get_booking_link',
|
||||||
|
'get_related_businesses',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getManifestForBusiness(
|
||||||
|
businessSlug: string,
|
||||||
|
serverBaseUrl: string = 'https://mcp.geolocal.io'
|
||||||
|
): Promise<Record<string, any>> {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT slug, name, mcp_endpoint FROM businesses WHERE slug = $1`,
|
||||||
|
[businessSlug]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
throw new Error(`Business '${businessSlug}' not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = result.rows[0];
|
||||||
|
const baseUrl = b.mcp_endpoint || serverBaseUrl;
|
||||||
|
return generateManifest({ businessSlug, serverBaseUrl: baseUrl });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI: Generate a manifest file for a given business slug.
|
||||||
|
* Usage: npx tsx src/manifest-generator.ts --slug=frisco-german-auto
|
||||||
|
*/
|
||||||
|
async function cli() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const slugArg = args.find((a) => a.startsWith('--slug='));
|
||||||
|
if (!slugArg) {
|
||||||
|
console.error('Usage: npx tsx src/manifest-generator.ts --slug=<business-slug>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const slug = slugArg.split('=')[1];
|
||||||
|
const manifest = await getManifestForBusiness(slug);
|
||||||
|
console.log(JSON.stringify(manifest, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv[1]?.includes('manifest-generator')) {
|
||||||
|
cli().catch(console.error);
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { getBusinessInfo } from './tools/get-business-info.js';
|
||||||
|
import { getHours } from './tools/get-hours.js';
|
||||||
|
import { getServices } from './tools/get-services.js';
|
||||||
|
import { getBookingLink } from './tools/get-booking-link.js';
|
||||||
|
import { getRelatedBusinesses } from './tools/get-related-businesses.js';
|
||||||
|
|
||||||
|
/** Wrap a plain object result into MCP CallToolResult format */
|
||||||
|
function toToolResult(data: Record<string, any>) {
|
||||||
|
const isError = 'error' in data;
|
||||||
|
return {
|
||||||
|
content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }],
|
||||||
|
...(isError && { isError: true }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const SlugSchema = { slug: z.string().describe('Business slug identifier (e.g., "frisco-german-auto")') };
|
||||||
|
|
||||||
|
export function createMCPServer() {
|
||||||
|
const server = new McpServer({
|
||||||
|
name: 'geolocal.io',
|
||||||
|
version: '0.1.0',
|
||||||
|
});
|
||||||
|
|
||||||
|
server.tool('get_business_info', SlugSchema, async (args) => {
|
||||||
|
const result = await getBusinessInfo(args);
|
||||||
|
return toToolResult(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.tool('get_hours', SlugSchema, async (args) => {
|
||||||
|
const result = await getHours(args);
|
||||||
|
return toToolResult(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.tool('get_services', SlugSchema, async (args) => {
|
||||||
|
const result = await getServices(args);
|
||||||
|
return toToolResult(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.tool('get_booking_link', SlugSchema, async (args) => {
|
||||||
|
const result = await getBookingLink(args);
|
||||||
|
return toToolResult(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.tool('get_related_businesses', SlugSchema, async (args) => {
|
||||||
|
const result = await getRelatedBusinesses(args);
|
||||||
|
return toToolResult(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||||
|
|
||||||
|
// Multi-tenant MCP gateway — routes requests to the correct business
|
||||||
|
// MVP: single MCP server serves all businesses
|
||||||
|
// Future: route to per-tenant MCP instances or regional shards
|
||||||
|
export function createGateway(server: McpServer) {
|
||||||
|
// The McpServer handles its own request routing via the transport layer.
|
||||||
|
// This gateway is a placeholder for future multi-tenant routing.
|
||||||
|
return { server };
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { pool } from '../db/schema.js';
|
||||||
|
|
||||||
|
export async function getBookingLink(params: { slug: string }): Promise<Record<string, any>> {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT calcom_link, name FROM businesses WHERE slug = $1`,
|
||||||
|
[params.slug]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return { error: `Business '${params.slug}' not found` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = result.rows[0];
|
||||||
|
return {
|
||||||
|
business: b.name,
|
||||||
|
booking_url: b.calcom_link,
|
||||||
|
message: `Book an appointment with ${b.name} via Cal.com`,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { pool } from '../db/schema.js';
|
||||||
|
|
||||||
|
export async function getBusinessInfo(params: { slug: string }): Promise<Record<string, any>> {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT name, category, address, city, state, zip, phone, website, story, owner_bio, photos
|
||||||
|
FROM businesses WHERE slug = $1`,
|
||||||
|
[params.slug]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return { error: `Business '${params.slug}' not found` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = result.rows[0];
|
||||||
|
return {
|
||||||
|
name: b.name,
|
||||||
|
category: b.category,
|
||||||
|
location: { address: b.address, city: b.city, state: b.state, zip: b.zip },
|
||||||
|
phone: b.phone,
|
||||||
|
website: b.website,
|
||||||
|
story: b.story,
|
||||||
|
owner_bio: b.owner_bio,
|
||||||
|
photos: JSON.parse(b.photos),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { pool } from '../db/schema.js';
|
||||||
|
|
||||||
|
export async function getHours(params: { slug: string }): Promise<Record<string, any>> {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT hours FROM businesses WHERE slug = $1`,
|
||||||
|
[params.slug]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return { error: `Business '${params.slug}' not found` };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { hours: JSON.parse(result.rows[0].hours) };
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { pool } from '../db/schema.js';
|
||||||
|
|
||||||
|
export async function getRelatedBusinesses(params: { slug: string }): Promise<Record<string, any>> {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT id, slug, name, category, city, state, story, related_business_ids
|
||||||
|
FROM businesses
|
||||||
|
WHERE slug = $1`,
|
||||||
|
[params.slug]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return { error: `Business '${params.slug}' not found` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const business = result.rows[0];
|
||||||
|
const relatedIds = JSON.parse(business.related_business_ids || '[]');
|
||||||
|
|
||||||
|
if (relatedIds.length === 0) {
|
||||||
|
// Fallback: same category, same city
|
||||||
|
const fallback = await pool.query(
|
||||||
|
`SELECT slug, name, category, city, state, story
|
||||||
|
FROM businesses
|
||||||
|
WHERE category = $1 AND city = $2 AND slug != $3
|
||||||
|
LIMIT 5`,
|
||||||
|
[business.category, business.city, params.slug]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
source_business: business.name,
|
||||||
|
related: fallback.rows.map((r: any) => ({
|
||||||
|
slug: r.slug,
|
||||||
|
name: r.name,
|
||||||
|
category: r.category,
|
||||||
|
location: `${r.city}, ${r.state}`,
|
||||||
|
story: r.story,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve related business IDs
|
||||||
|
const relatedResult = await pool.query(
|
||||||
|
`SELECT slug, name, category, city, state, story
|
||||||
|
FROM businesses
|
||||||
|
WHERE id = ANY($1)`,
|
||||||
|
[relatedIds]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
source_business: business.name,
|
||||||
|
related: relatedResult.rows.map((r: any) => ({
|
||||||
|
slug: r.slug,
|
||||||
|
name: r.name,
|
||||||
|
category: r.category,
|
||||||
|
location: `${r.city}, ${r.state}`,
|
||||||
|
story: r.story,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { pool } from '../db/schema.js';
|
||||||
|
|
||||||
|
export async function getServices(params: { slug: string }): Promise<Record<string, any>> {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT services FROM businesses WHERE slug = $1`,
|
||||||
|
[params.slug]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return { error: `Business '${params.slug}' not found` };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { services: JSON.parse(result.rows[0].services) };
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"declaration": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# geolocal.io — Partner One-Pager
|
||||||
|
|
||||||
|
> **For agencies, SEO consultants, and Chambers of Commerce**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Make Your Clients Discoverable in AI — In 15 Minutes
|
||||||
|
|
||||||
|
### The Problem
|
||||||
|
|
||||||
|
- **98.8% of local businesses are invisible to AI.** ChatGPT recommends just 1.2% of local businesses.
|
||||||
|
- 45% of consumers now use AI tools to find local businesses — up from 6% just one year ago.
|
||||||
|
- Your clients are losing customers to competitors who show up in AI results — even if your clients do better work.
|
||||||
|
- **They don't even know they're invisible.** They just see fewer customers and can't figure out why.
|
||||||
|
|
||||||
|
### The Solution
|
||||||
|
|
||||||
|
`geolocal.io` is the infrastructure that makes local businesses **discoverable, bookable, and payable** directly through AI assistants like ChatGPT, Gemini, and Claude.
|
||||||
|
|
||||||
|
**How it works:** One JSON file at `/.well-known/mcp-server`. That's it.
|
||||||
|
|
||||||
|
No coding. No servers to manage. No API keys. No security audits. Just a file that tells AI agents: *"This business exists, here's what it does, here's how to book it."*
|
||||||
|
|
||||||
|
### What AI Sees (Before vs. After)
|
||||||
|
|
||||||
|
**Before `geolocal.io`:**
|
||||||
|
> ChatGPT: *"I found some mechanics in Frisco..."* (generic list, no details, can't book)
|
||||||
|
|
||||||
|
**After `geolocal.io`:**
|
||||||
|
> ChatGPT: *"I found **Frisco German Auto Specialists** — a family-run shop with 40 years of experience specializing in BMW, Mercedes, and Audi. They're open today until 6 PM. I can book you a 9 AM slot and collect a $25 deposit to secure it."*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Partner Economics
|
||||||
|
|
||||||
|
### Recurring Commission
|
||||||
|
|
||||||
|
| Tier | Your Share | Per Client (Pro $49/mo) | 20 Clients/mo |
|
||||||
|
|------|-----------|----------------------|---------------|
|
||||||
|
| **Affiliate** | 20% | $9.80 | $196/mo |
|
||||||
|
| **Partner** (10+ clients) | 25% | $12.25 | $245/mo |
|
||||||
|
| **Strategic** (50+ clients) | 30% | $14.70 | $294/mo |
|
||||||
|
|
||||||
|
**This is passive, recurring revenue.** Set it up once, earn it every month.
|
||||||
|
|
||||||
|
### What You Offer Your Clients
|
||||||
|
|
||||||
|
| Plan | Price | What They Get |
|
||||||
|
|------|-------|---------------|
|
||||||
|
| **Lite** | $20/mo | AI discovery, business info, hours, services |
|
||||||
|
| **Pro** | $49/mo | Lite + Cal.com booking, rich content (story, photos), deposits |
|
||||||
|
| **Custom** | TBD | White-label, bulk pricing, API access |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4-Step Onboarding (15 Minutes Total)
|
||||||
|
|
||||||
|
| Step | What You Do | Time |
|
||||||
|
|------|------------|------|
|
||||||
|
| **1. Sign up** | Create your partner account at partners.geolocal.io | 2 min |
|
||||||
|
| **2. Add client** | Enter their business name and website URL | 3 min |
|
||||||
|
| **3. Deploy** | Download the JSON file, upload to their site (or email it) | 5 min |
|
||||||
|
| **4. Upsell** | Offer Pro tier for booking + rich content | 5 min |
|
||||||
|
|
||||||
|
**That's it.** The MCP endpoint goes live. AI agents can now discover and recommend the business.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why `geolocal.io` — Not Pie, Mainstreet, or Yelp?
|
||||||
|
|
||||||
|
| | **geolocal.io** | Pie | Mainstreet | Yelp |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| **What it is** | MCP infrastructure | Marketing platform | GBP automation | Data landlord |
|
||||||
|
| **MCP endpoint** | ✅ Native | ❌ | Partial | Paid API only |
|
||||||
|
| **Booking from AI** | ✅ Direct | ❌ | ❌ | ❌ |
|
||||||
|
| **Business owns data** | ✅ Independent | Platform-locked | Platform-locked | Platform-locked |
|
||||||
|
| **Partner-friendly** | ✅ 20-30% commission | Reseller model | Direct-to-business | Landlord model |
|
||||||
|
|
||||||
|
**geolocal.io is infrastructure.** Pie and Mainstreet optimize visibility in existing platforms. We **become the data source** that AI agents query directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Makes This Defensible
|
||||||
|
|
||||||
|
1. **AI muscle memory** — the more AI agents use `geolocal.io` endpoints, the more they learn to prefer them. First movers get locked in.
|
||||||
|
2. **Partner network effects** — once your agency has 20 clients on `geolocal.io`, switching is painful. We make onboarding frictionless.
|
||||||
|
3. **Telemetry data** — every MCP interaction generates proprietary data no one else has. We'll use it to improve recommendations and offer insights.
|
||||||
|
4. **Simplicity** — one JSON file. No competitors offer this level of simplicity for MCP deployment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Your Next Step
|
||||||
|
|
||||||
|
**Become a partner:** partners.geolocal.io
|
||||||
|
|
||||||
|
Or reply to this one-pager — we'll get you set up and your first client live in under an hour.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> *"You're already helping your clients dominate Google. Now help them dominate AI — and earn recurring revenue doing it."*
|
||||||
|
|
||||||
|
**geolocal.io** — The AI discovery layer for local commerce
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
# Data Flow & Privacy — geolocal.io
|
||||||
|
|
||||||
|
> Last updated: 2026-07-16
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Overview
|
||||||
|
|
||||||
|
This document describes how data flows through the `geolocal.io` platform, what data we collect, how it's stored, who has access, and how we handle privacy obligations under GDPR and CCPA.
|
||||||
|
|
||||||
|
**Core principle:** We expose only public business data. We do not collect personal consumer data beyond what is necessary for booking transactions (handled by Cal.com and Stripe).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Data Collection Points
|
||||||
|
|
||||||
|
### 2.1 Business Data (Voluntary)
|
||||||
|
|
||||||
|
Businesses (or their agencies) voluntarily provide:
|
||||||
|
|
||||||
|
| Data | Source | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| Business name, address, phone, website | Business owner / agency | AI discovery |
|
||||||
|
| Operating hours | Business owner / agency | AI recommendations |
|
||||||
|
| Services & pricing | Business owner / agency | AI recommendations |
|
||||||
|
| Story & narrative | Business owner / agency | Differentiation in AI responses |
|
||||||
|
| Photos & video | Business owner / agency | Visual discovery in AI |
|
||||||
|
| Cal.com booking link | Business owner / agency | Transaction loop |
|
||||||
|
|
||||||
|
**Note:** This data is already publicly available on the business's website or Google Business Profile. We do not scrape it without consent.
|
||||||
|
|
||||||
|
### 2.2 Telemetry Data (MCP Interactions)
|
||||||
|
|
||||||
|
Every MCP tool call generates:
|
||||||
|
|
||||||
|
| Data Point | Example |
|
||||||
|
|-----------|---------|
|
||||||
|
| Query terms | "best mechanic in Frisco TX" |
|
||||||
|
| Business slug referenced | "frisco-german-auto" |
|
||||||
|
| Tool called | "get_business_info" |
|
||||||
|
| AI platform used | ChatGPT, Gemini, Claude |
|
||||||
|
| Timestamp | 2026-07-16T14:23:00Z |
|
||||||
|
| Response time | 45ms |
|
||||||
|
|
||||||
|
### 2.3 Booking Data (via Cal.com / Stripe)
|
||||||
|
|
||||||
|
**We do NOT handle this directly.** Cal.com and Stripe are the providers of record. We pass booking requests to their APIs.
|
||||||
|
|
||||||
|
- Cal.com handles: appointment scheduling, calendar data, customer contact info
|
||||||
|
- Stripe handles: payment processing, billing data, financial records
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Data Storage
|
||||||
|
|
||||||
|
| Data Type | Where It Lives | Retention |
|
||||||
|
|-----------|---------------|-----------|
|
||||||
|
| Business profiles | PostgreSQL (Railway) | Until business opts out |
|
||||||
|
| Telemetry logs | PostgreSQL + Redis (cached) | 24 months, then anonymized |
|
||||||
|
| Photos / media | CDN (Cloudflare R2 / AWS S3) | Until business opts out |
|
||||||
|
| Booking data | Cal.com / Stripe (external) | Per their retention policies |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Data Sharing
|
||||||
|
|
||||||
|
| Recipient | What We Share | Why |
|
||||||
|
|-----------|--------------|-----|
|
||||||
|
| AI agents (ChatGPT, Gemini, etc.) | Business profile data via MCP | Core product function |
|
||||||
|
| Partner agencies | Their client's analytics & commission data | Partner economics |
|
||||||
|
| Chambers of Commerce | Member analytics (aggregate) | CoC dashboard |
|
||||||
|
| Third-party data buyers (DaaS) | Anonymized telemetry only | Data-as-a-Service revenue |
|
||||||
|
|
||||||
|
**We never sell identifiable consumer data.** All DaaS products use aggregated, anonymized telemetry.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Bi-Directional MCP Data Flow
|
||||||
|
|
||||||
|
The "related businesses" handshake creates a bi-directional data exchange:
|
||||||
|
|
||||||
|
```
|
||||||
|
AI Agent ──┐
|
||||||
|
├──→ geolocal.io MCP Server ──→ Business Database
|
||||||
|
│ ↓
|
||||||
|
│ related_businesses()
|
||||||
|
│ ↓
|
||||||
|
│ Returns: list of related businesses
|
||||||
|
│ ↓
|
||||||
|
AI Agent ◄─┘───────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verification flow:** AI agents can report data discrepancies back through the MCP protocol. We log these reports and flag business profiles for review.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Privacy Commitments
|
||||||
|
|
||||||
|
### 6.1 GDPR Principles
|
||||||
|
- **Lawful basis:** Processing is based on business consent (they opt in) and legitimate interest (telemetry for service improvement)
|
||||||
|
- **Data minimization:** We only collect what's needed for AI discovery and booking
|
||||||
|
- **Right to be forgotten:** Businesses can request full data deletion
|
||||||
|
- **Data portability:** Businesses can export their profile data at any time
|
||||||
|
- **DPIA:** Data Protection Impact Assessment will be completed before EU data processing
|
||||||
|
|
||||||
|
### 6.2 CCPA Principles
|
||||||
|
- **Notice at collection:** Clear disclosure of what data we collect
|
||||||
|
- **Right to delete:** Businesses can request deletion of their data
|
||||||
|
- **Right to opt out of sale:** We do not sell personal data
|
||||||
|
- **Non-discrimination:** We do not discriminate against users who exercise their rights
|
||||||
|
|
||||||
|
### 6.3 What We Do NOT Do
|
||||||
|
- We do not collect consumer PII beyond what Cal.com/Stripe handle
|
||||||
|
- We do not track individual consumers across sessions
|
||||||
|
- We do not use cookies for behavioral tracking
|
||||||
|
- We do not sell individual-level data
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Security
|
||||||
|
|
||||||
|
| Measure | Status |
|
||||||
|
|---------|--------|
|
||||||
|
| PostgreSQL connection via SSL | ✅ MVP |
|
||||||
|
| Rate limiting on MCP endpoints | ✅ MVP |
|
||||||
|
| Input validation (Zod schemas) | ✅ MVP |
|
||||||
|
| OAuth 2.1 with PKCE for partner auth | Phase 2 |
|
||||||
|
| Regular security audits | Phase 3 |
|
||||||
|
| SOC 2 compliance | Future |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Incident Response
|
||||||
|
|
||||||
|
In the event of a data breach:
|
||||||
|
|
||||||
|
1. **Detect:** Automated alerts on anomalous MCP traffic patterns
|
||||||
|
2. **Contain:** Rate-limit or disable affected endpoints
|
||||||
|
3. **Notify:** Affected businesses notified within 72 hours (GDPR)
|
||||||
|
4. **Remediate:** Patch vulnerability, audit for scope
|
||||||
|
5. **Document:** Log incident, update this document
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Data Flow Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
|
||||||
|
│ Business │ │ │ │ AI Agents │
|
||||||
|
│ Owner / │────→│ geolocal.io │←───→│ ChatGPT, │
|
||||||
|
│ Agency │ │ MCP Server │ │ Gemini, │
|
||||||
|
└──────────────┘ │ │ │ Claude, │
|
||||||
|
│ ┌────────────┐ │ │ Grok │
|
||||||
|
│ │ PostgreSQL │ │ └──────────────┘
|
||||||
|
│ └────────────┘ │
|
||||||
|
│ ┌────────────┐ │
|
||||||
|
│ │ Redis │ │
|
||||||
|
│ └────────────┘ │
|
||||||
|
│ ┌────────────┐ │
|
||||||
|
│ │ Telemetry │ │
|
||||||
|
│ └────────────┘ │
|
||||||
|
└──────┬───────────┘
|
||||||
|
│
|
||||||
|
┌───────┴────────┐
|
||||||
|
│ Cal.com API │
|
||||||
|
│ Stripe API │
|
||||||
|
└────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This document must reference NORTH_STAR.md for principles. Updates require review against current privacy regulations.*
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# IP Notes — geolocal.io
|
||||||
|
|
||||||
|
> Last updated: 2026-07-16
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. The `/.well-known/mcp-server` Pattern
|
||||||
|
|
||||||
|
### Positioning
|
||||||
|
|
||||||
|
The `/.well-known/mcp-server` convention is an adaptation of IETF's RFC 8615 (`/.well-known` URI space) for MCP server discovery. We position this as an **open standard** — not a proprietary geolocal.io invention.
|
||||||
|
|
||||||
|
**Rationale:**
|
||||||
|
- The more adopters use this convention, the more AI agents learn to look for it
|
||||||
|
- An open standard creates network effects that favor us as the infrastructure provider, even though we don't own the convention
|
||||||
|
- Competitors who copy the convention still need our hosted MCP server
|
||||||
|
|
||||||
|
### Risk
|
||||||
|
|
||||||
|
If another company claims to have "invented" `/.well-known/mcp-server`, we lose the narrative advantage. **Mitigation:** Document our first use and publish the convention publicly before competitors.
|
||||||
|
|
||||||
|
### Action Items
|
||||||
|
|
||||||
|
- [ ] Publish a technical blog post: "Introducing `/.well-known/mcp-server` for AI Discovery"
|
||||||
|
- [ ] File a design document on the MCP GitHub repository as a community proposal
|
||||||
|
- [ ] Include the convention in our public README before launch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Trademark
|
||||||
|
|
||||||
|
**Mark:** geolocal.io
|
||||||
|
|
||||||
|
**Status:** To be registered
|
||||||
|
|
||||||
|
**Action Items:**
|
||||||
|
- [ ] File USPTO trademark application for "GeoLocal" (Class 42: Cloud computing services; Class 35: Business consulting)
|
||||||
|
- [ ] Monitor for conflicting marks in adjacent categories
|
||||||
|
- [ ] Register domain variations (geolocal.com, geolocal.ai) to prevent confusion
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. MCP Protocol Usage
|
||||||
|
|
||||||
|
**Governance:** The MCP protocol is governed by Anthropic (as of 2026). It is open-source and permissively licensed.
|
||||||
|
|
||||||
|
**Our usage:**
|
||||||
|
- We implement the MCP protocol as specified — this is permitted
|
||||||
|
- We do not modify the core protocol — we extend it with our own tools and data schema
|
||||||
|
- Our proprietary value is in the **data layer** and **hosting infrastructure**, not the protocol itself
|
||||||
|
|
||||||
|
**Risk:** If MCP governance changes (e.g., becomes copyleft, or a competing protocol emerges), we need to be ready to migrate. Our data layer is protocol-agnostic, so this is manageable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Telemetry Data Ownership
|
||||||
|
|
||||||
|
**We own the telemetry data** generated by MCP interactions on our platform:
|
||||||
|
|
||||||
|
- Query patterns
|
||||||
|
- Tool usage statistics
|
||||||
|
- Response times
|
||||||
|
- Business recommendation patterns
|
||||||
|
- AI platform usage breakdown
|
||||||
|
|
||||||
|
**We do NOT own:**
|
||||||
|
- Business profile data (owned by the businesses)
|
||||||
|
- Booking data (owned by Cal.com/Stripe)
|
||||||
|
- Consumer PII (we don't collect it)
|
||||||
|
|
||||||
|
**Commercialization:** Anonymized, aggregated telemetry may be licensed as a Data-as-a-Service product. This is subject to our privacy commitments (see Data Flow & Privacy.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Open Source Considerations
|
||||||
|
|
||||||
|
**Current code:** Proprietary (closed-source)
|
||||||
|
|
||||||
|
**Rationale for closed-source:**
|
||||||
|
- The competitive advantage is in the data and distribution, not the code
|
||||||
|
- However, closing the source may slow adoption if agencies want to audit the infrastructure
|
||||||
|
- **Potential strategy:** Release a reference implementation (the JSON manifest generator) as open source, while keeping the MCP server and telemetry pipeline proprietary
|
||||||
|
|
||||||
|
**Recommendation:** Evaluate open-sourcing the manifest generator / `/.well-known/mcp-server` convention documentation as a growth strategy. This positions geolocal.io as the authority without giving away proprietary infrastructure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Business Data Rights
|
||||||
|
|
||||||
|
**Clear chain of title:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Business Owner → (voluntarily provides) → geolocal.io MCP Server → (exposed via) → AI Agents
|
||||||
|
```
|
||||||
|
|
||||||
|
- Businesses retain full ownership of their profile data
|
||||||
|
- Businesses grant geolocal.io a non-exclusive license to host and expose that data via MCP
|
||||||
|
- Businesses may revoke this license at any time (data deletion request)
|
||||||
|
- Businesses may export their data at any time
|
||||||
|
|
||||||
|
**Partner agencies:**
|
||||||
|
- Agencies act as data processors on behalf of businesses
|
||||||
|
- Agencies do not own the business data they submit
|
||||||
|
- Businesses must authorize agencies to submit their data on their behalf
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. IP Audit Checklist
|
||||||
|
|
||||||
|
Before launch, verify:
|
||||||
|
|
||||||
|
- [ ] No third-party code with restrictive licenses (GPL, AGPL) in the MCP server
|
||||||
|
- [ ] All dependencies use permissive licenses (MIT, Apache 2.0, BSD)
|
||||||
|
- [ ] Trademark application filed
|
||||||
|
- [ ] `/.well-known/mcp-server` convention documented and published
|
||||||
|
- [ ] Privacy policy references data ownership clearly
|
||||||
|
- [ ] Terms of Service include IP clauses
|
||||||
|
- [ ] No open source code mixed with proprietary code without clear separation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This document must reference NORTH_STAR.md for principles. Consult IP counsel before making final decisions.*
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# Partnership Agreement Skeleton — geolocal.io
|
||||||
|
|
||||||
|
> **Template — NOT LEGAL ADVICE.** Consult qualified counsel before execution.
|
||||||
|
> Last updated: 2026-07-16
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Parties
|
||||||
|
|
||||||
|
**Provider:** geolocal.io (the "Platform")
|
||||||
|
|
||||||
|
**Partner:** [Partner Name / Agency / Chamber of Commerce] (the "Partner")
|
||||||
|
|
||||||
|
**Effective Date:** [Date]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Scope of Partnership
|
||||||
|
|
||||||
|
Partner is authorized to:
|
||||||
|
|
||||||
|
1. Offer `geolocal.io` MCP endpoints to their clients/members
|
||||||
|
2. Use `geolocal.io` branding and marketing materials (subject to brand guidelines)
|
||||||
|
3. Access the Partner Dashboard for client management and analytics
|
||||||
|
4. Earn recurring commissions as specified in Section 4
|
||||||
|
|
||||||
|
Partner is NOT authorized to:
|
||||||
|
|
||||||
|
1. Resell `geolocal.io` as a white-label product without Strategic-tier status
|
||||||
|
2. Modify or redistribute `geolocal.io` software code
|
||||||
|
3. Claim ownership of `geolocal.io` data or telemetry
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Data Ownership
|
||||||
|
|
||||||
|
- **Businesses own their data.** All business profile data (name, services, photos, story, booking info) remains the intellectual property of the business that provided it.
|
||||||
|
- **geolocal.io owns the platform.** The MCP server infrastructure, telemetry data (anonymized), and platform code are owned by geolocal.io.
|
||||||
|
- **Partner owns their client relationships.** Partner retains all rights to their client relationships and may migrate clients off the platform at any time.
|
||||||
|
- **Data export.** Upon request, businesses may export their full profile data in JSON format.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Term & Termination
|
||||||
|
|
||||||
|
- **Term:** This agreement is effective until terminated by either party.
|
||||||
|
- **Termination for convenience:** Either party may terminate with 30 days written notice.
|
||||||
|
- **Termination for cause:** Either party may terminate immediately for material breach, fraud, or illegal activity.
|
||||||
|
- **Effect of termination:**
|
||||||
|
- Partner commissions cease on the termination date
|
||||||
|
- Business client data remains on the platform until businesses migrate off (grace period: 90 days)
|
||||||
|
- Partner loses access to Partner Dashboard on termination date
|
||||||
|
- geolocal.io retains anonymized telemetry data
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Commission Structure
|
||||||
|
|
||||||
|
| Tier | Requirements | Commission Rate |
|
||||||
|
|------|-------------|-----------------|
|
||||||
|
| **Affiliate** | Signed partner agreement | 20% of MRR |
|
||||||
|
| **Partner** | 10+ active clients | 25% of MRR |
|
||||||
|
| **Strategic** | 50+ active clients | 30% of MRR |
|
||||||
|
|
||||||
|
- Commissions are calculated on net revenue (after payment processing fees)
|
||||||
|
- Commissions paid monthly, payable on the 15th of each month
|
||||||
|
- Partner may access commission reports via Partner Dashboard
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Confidentiality
|
||||||
|
|
||||||
|
Both parties agree to keep confidential:
|
||||||
|
|
||||||
|
- Business client data and analytics
|
||||||
|
- Telemetry data and insights
|
||||||
|
- Commission rates and partnership terms
|
||||||
|
- Platform technical architecture and API endpoints
|
||||||
|
|
||||||
|
Confidentiality obligations survive termination for 24 months.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Liability
|
||||||
|
|
||||||
|
- **Limitation of liability:** Neither party is liable for indirect, consequential, or punitive damages arising from this agreement.
|
||||||
|
- **Maximum liability:** Provider's total liability is capped at the Partner's commissions earned in the preceding 12 months.
|
||||||
|
- **No warranty:** The platform is provided "as is" without warranty of merchantability or fitness for a particular purpose.
|
||||||
|
- **Partner indemnification:** Partner agrees to indemnify geolocal.io against claims arising from Partner's misuse of the platform or misrepresentation to clients.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Compliance
|
||||||
|
|
||||||
|
Both parties agree to:
|
||||||
|
|
||||||
|
- Comply with applicable data protection laws (GDPR, CCPA)
|
||||||
|
- Not use the platform for fraudulent or deceptive purposes
|
||||||
|
- Report data breaches within 24 hours of discovery
|
||||||
|
- Maintain accurate business data for enrolled clients
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Dispute Resolution
|
||||||
|
|
||||||
|
- **Governing law:** [State/Jurisdiction]
|
||||||
|
- **Good faith negotiation:** 30-day period before formal action
|
||||||
|
- **Arbitration:** Binding arbitration if negotiation fails
|
||||||
|
- **Venue:** [City, State]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Amendment
|
||||||
|
|
||||||
|
This agreement may be amended by mutual written consent of both parties. geolocal.io may update platform terms (pricing, features) with 30 days written notice.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Provider:** ___________________ **Date:** ___________
|
||||||
|
|
||||||
|
**Partner:** ___________________ **Date:** ___________
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This template must reference NORTH_STAR.md for principles. Consult legal counsel before use.*
|
||||||
Reference in New Issue
Block a user