From f49bdb7099a05080b6cbaa61e488c52bc870a53e Mon Sep 17 00:00:00 2001 From: Aiden Smith <29802327+DevVoxel@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:47:17 -0500 Subject: [PATCH] Add architecture docs and Go microservice to tech stack --- README.md | 7 ++- docs/api-spec.md | 135 +++++++++++++++++++++++++++++++++++++++++++ docs/architecture.md | 78 +++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 docs/api-spec.md create mode 100644 docs/architecture.md diff --git a/README.md b/README.md index 741289d..5c071e8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ DNS lookup, WHOIS, and domain monitoring tool. Search nameservers, check domain - **DNS**: Tangerine (DNS-over-HTTPS via Cloudflare/Google) - **WHOIS**: whoiser (RDAP-based, free) - **Email**: Resend -- **Deployment**: Vercel +- **DNS API**: Go microservice on VPS ([`miekg/dns`](https://github.com/miekg/dns) — direct UDP/TCP resolution, DNSSEC, propagation checks) +- **Deployment**: Vercel (frontend) + VPS (Go DNS API) - **Package Manager**: Bun ## Getting Started @@ -63,6 +64,10 @@ Open [http://localhost:3000](http://localhost:3000) to see the app. | `CRON_SECRET` | Yes | Secret to authenticate Vercel cron requests | | `RESEND_API_KEY` | No | Resend API key for email notifications | +## Architecture + +VectorDNS uses a hybrid architecture: Next.js on Vercel for the frontend, and a Go microservice on a VPS for DNS resolution and monitoring. See [docs/architecture.md](./docs/architecture.md) for details and [docs/api-spec.md](./docs/api-spec.md) for the Go API spec. + ## Project Structure ``` diff --git a/docs/api-spec.md b/docs/api-spec.md new file mode 100644 index 0000000..f65983b --- /dev/null +++ b/docs/api-spec.md @@ -0,0 +1,135 @@ +# Go DNS API Specification + +Base URL: `https:///api/v1` + +All requests require the header `X-API-Key: `. + +--- + +## Endpoints + +### `POST /dns/lookup` + +Resolve DNS records for a domain. + +**Request:** + +```json +{ + "domain": "example.com", + "types": ["A", "AAAA", "MX", "TXT", "NS", "CNAME", "SOA", "CAA", "SRV"], + "nameserver": "8.8.8.8" +} +``` + +- `domain` (required): The domain to query. +- `types` (optional): Record types to query. Defaults to all supported types. +- `nameserver` (optional): Specific nameserver to query. Defaults to system resolver. + +**Response (200):** + +```json +{ + "domain": "example.com", + "nameserver": "8.8.8.8", + "records": { + "A": [{ "value": "93.184.216.34", "ttl": 300 }], + "MX": [{ "value": "mail.example.com", "priority": 10, "ttl": 3600 }] + }, + "query_time_ms": 12 +} +``` + +--- + +### `POST /dns/propagation` + +Check DNS propagation across multiple resolvers. + +**Request:** + +```json +{ + "domain": "example.com", + "type": "A", + "resolvers": ["8.8.8.8", "1.1.1.1", "9.9.9.9"] +} +``` + +- `resolvers` (optional): Defaults to a built-in list of public resolvers. + +**Response (200):** + +```json +{ + "domain": "example.com", + "type": "A", + "results": [ + { "resolver": "8.8.8.8", "values": ["93.184.216.34"], "ttl": 300 }, + { "resolver": "1.1.1.1", "values": ["93.184.216.34"], "ttl": 280 }, + { "resolver": "9.9.9.9", "values": ["93.184.216.34"], "ttl": 295 } + ], + "consistent": true +} +``` + +--- + +### `POST /dns/validate` + +DNSSEC validation for a domain. + +**Request:** + +```json +{ + "domain": "example.com" +} +``` + +**Response (200):** + +```json +{ + "domain": "example.com", + "dnssec": true, + "chain_valid": true, + "details": "RRSIG verified for A record" +} +``` + +--- + +### `GET /health` + +Health check. No authentication required. + +**Response (200):** + +```json +{ + "status": "ok", + "version": "0.1.0" +} +``` + +--- + +## Error Responses + +All errors follow this format: + +```json +{ + "error": "invalid domain", + "code": "INVALID_DOMAIN" +} +``` + +| HTTP Status | Code | Description | +|---|---|---| +| 400 | `INVALID_DOMAIN` | Malformed or missing domain | +| 400 | `INVALID_TYPE` | Unsupported record type | +| 401 | `UNAUTHORIZED` | Missing or invalid API key | +| 500 | `DNS_ERROR` | Upstream DNS query failed | +| 500 | `INTERNAL` | Unexpected server error | diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..0fd5730 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,78 @@ +# VectorDNS Architecture + +## Overview + +VectorDNS uses a hybrid architecture: a Next.js frontend on Vercel and a Go DNS microservice on a VPS. + +``` +┌──────────────────────┐ ┌──────────────────────┐ +│ Vercel (Frontend) │ │ VPS (DNS API) │ +│ │ │ │ +│ Next.js 16 │ HTTP │ Go microservice │ +│ React 19 │◄──────►│ miekg/dns │ +│ Supabase SDK │ │ │ +│ Tailwind + shadcn │ │ - DNS resolution │ +│ │ │ - DNSSEC validation │ +│ Handles: │ │ - Propagation checks │ +│ - UI/SSR │ │ - Monitoring cron │ +│ - Auth (Supabase) │ │ - Change detection │ +│ - WHOIS lookups │ │ │ +│ - Static pages │ └───────────┬───────────┘ +│ │ │ +└──────────┬───────────┘ │ UDP/TCP + │ ▼ + │ ┌───────────────────────┐ + │ │ DNS Resolvers / │ + ▼ │ Authoritative NS │ +┌──────────────────────┐ └───────────────────────┘ +│ Supabase │ +│ │ +│ - Postgres DB │ +│ - Auth │ +│ - Row Level Security│ +└──────────────────────┘ +``` + +## Why Hybrid + +| Concern | Solution | +|---|---| +| Frontend hosting, SSR, auth | Vercel (serverless, zero-ops) | +| DNS resolution, monitoring | Go on VPS (persistent process, no cold starts) | +| Database, auth state | Supabase (managed Postgres) | + +## What Each Service Handles + +### Next.js (Vercel) + +- All UI rendering (SSR + client) +- Authentication via Supabase +- WHOIS lookups (whoiser library) +- Domain availability checks (IANA RDAP) +- Dashboard, notifications, settings pages +- Proxies DNS queries to the Go service + +### Go Microservice (VPS) + +- DNS record lookups via `miekg/dns` (UDP/TCP, not DoH) +- Query specific or authoritative nameservers directly +- DNSSEC validation +- DNS propagation checking across multiple resolvers +- Scheduled monitoring (native cron, no serverless time limits) +- Change detection (diff DNS snapshots, notify on changes) + +## Communication + +The Next.js API routes call the Go service over HTTPS. The Go service URL is configured via environment variable (`GO_DNS_API_URL`). Requests are authenticated with a shared API key (`GO_DNS_API_KEY`). + +``` +Next.js API route → HTTPS → Go DNS API → UDP/TCP → DNS resolvers +``` + +## Why Go Over DoH (Tangerine) + +- Direct UDP/TCP DNS queries — faster, no middleman +- Can query authoritative nameservers directly +- Supports DNSSEC validation, AXFR, propagation checks +- No cold starts, consistent latency +- No Vercel function timeout limits for monitoring jobs