feat: add premium Next.js scaffold to Domain_web

Bundle geoexport-premium (Docker, docs, Next.js) alongside the
working static site mirror; production VPS install still uses site/.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Андрей Бобырев
2026-05-24 21:32:59 +03:00
parent 08e6f7a5a9
commit 93109106bc
30 changed files with 8332 additions and 1 deletions

4
.gitignore vendored
View File

@@ -1,2 +1,6 @@
.DS_Store
*.log
premium/node_modules/
premium/.next/
premium/.env
.env

View File

@@ -75,10 +75,15 @@ systemctl restart geoexport-site
- Экспорт, поиск и часть API проксируются на живой `geoexport.org` (нужен интернет на VPS).
- Это зеркало UI и кэшированных справочников, не полный автономный бэкенд.
## Premium (Next.js roadmap)
Каталог `premium/` — Next.js 16 scaffold (Docker, docs, `docker-compose.yml`). Продакшен на VPS сейчас использует **статическое зеркало** в `site/` (nginx + Node). Полный Next.js-стек — по `premium/docs/DEPLOYMENT.md`.
## Структура репозитория
```
install.sh — установка на VPS
uninstall.sh — удаление с VPS
site/ — index.html, assets/, data/, server.mjs
site/ — index.html, assets/, data/, server.mjs (production)
premium/ — Next.js rewrite, Docker, документация (roadmap)
```

41
premium/.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

5
premium/AGENTS.md Normal file
View File

@@ -0,0 +1,5 @@
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

1
premium/CLAUDE.md Normal file
View File

@@ -0,0 +1 @@
@AGENTS.md

26
premium/Dockerfile Normal file
View File

@@ -0,0 +1,26 @@
# GeoExport — production image (Next.js)
FROM node:22-alpine AS base
RUN apk add --no-cache libc6-compat
WORKDIR /app
FROM base AS deps
COPY package.json ./
RUN npm install
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
FROM base AS runner
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
CMD ["npm", "run", "start"]

21
premium/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 GeoExport Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

261
premium/README.md Normal file
View File

@@ -0,0 +1,261 @@
# GeoExport
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)](https://nextjs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5-blue?logo=typescript)](https://www.typescriptlang.org)
[![Docker](https://img.shields.io/badge/Docker-ready-2496ED?logo=docker)](docker-compose.yml)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.md)
Self-hosted platform to browse, export, and generate routing rules from **geoip** and **geosite** databases — built for VPN stacks: **Xray**, **3x-ui**, **V2Ray**, **Mihomo**, **Sing-box**.
GeoExport is an open-source, API-first alternative to hosted geo list tools: fast UI, privacy-friendly defaults, and a deployment model you control.
> **Status:** This repository is the **premium Next.js rewrite** (`geoexport-premium`). The UI scaffold is active; PostgreSQL, Prisma, Redis, and full API routes are on the roadmap. For a working static mirror today, see [andrey271192/Domain_web](https://github.com/andrey271192/Domain_web).
---
## Table of contents
- [Why GeoExport](#why-geoexport)
- [Features](#features)
- [Architecture](#architecture)
- [Screenshots](#screenshots)
- [Quick start](#quick-start)
- [Configuration](#configuration)
- [Docker](#docker)
- [API](#api)
- [Deployment](#deployment)
- [Security](#security)
- [Performance](#performance)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
- [License](#license)
---
## Why GeoExport
| | Hosted geo tools | GeoExport |
|---|------------------|-----------|
| **Data location** | Third-party SaaS | Your VPS / private cloud |
| **API access** | Opaque or limited | REST-first, documented |
| **UI** | Functional | Linear-grade layout, dark/light |
| **Stack** | Unknown | Next.js, TypeScript, Prisma, Redis |
| **Scale** | Shared tenancy | Horizontal app + cache layer |
GeoExport does not replace community rule repos (Loyalsoldier, RuNet Freedom, v2fly, etc.) — it **indexes** them, maps services to categories, and gives you export and routing helpers in one place.
---
## Features
### Presets & sources
- **9 preset groups**, **59 curated services** (messengers, video, social, AI, games, work, CDN, RU-blocked lists, …)
- **4 rule sources**: RuNet Freedom, Loyalsoldier, DanielLavrushin (b4geoip), v2fly — with per-source `geoip.dat` / `geosite.dat` links
### Discovery & export
- Full-text **search** across geoip/geosite categories
- **DNS lookup**: resolve domains to IPs/subdomains and cross-check against loaded databases
- One-click **export** to `.txt` for client import
- **Routing generator** with saved routing presets (Xray / Mihomo / Sing-box oriented)
### Platform
- **Dark / light** theme
- **REST API** for automation (GraphQL optional on roadmap)
- **Self-hosted** via Docker or bare Node
- **Edge-ready** Next.js deployment (Vercel, Cloudflare, or nginx reverse proxy)
---
## Architecture
High-level layout:
```
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Browser │────▶│ Next.js │────▶│ PostgreSQL │
│ (React) │ │ App Router │ │ (Prisma) │
└─────────────┘ │ + API routes│ └─────────────────┘
│ │────▶┌─────────────────┐
│ │ │ Redis (cache) │
└──────┬───────┘ └─────────────────┘
┌──────────────┐
│ Geo workers │──▶ upstream .dat / GitHub releases
└──────────────┘
```
Details: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
### Stack
| Layer | Technology |
|-------|------------|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS 4, Framer Motion, shadcn/ui |
| API | Next.js Route Handlers (REST); GraphQL optional later |
| Data | PostgreSQL + Prisma |
| Cache | Redis |
| Ops | Docker, docker-compose, nginx (production) |
---
## Screenshots
| Presets browser | DNS lookup | Routing generator |
|-----------------|------------|-------------------|
| _Coming soon — add `docs/images/presets.png`_ | _Coming soon_ | _Coming soon_ |
Place assets under `docs/images/` and reference them here before release.
---
## Quick start
### Requirements
- **Node.js** 20+ (22 LTS recommended)
- **npm**, **pnpm**, or **bun**
### Local development
```bash
git clone https://github.com/andrey271192/geoexport.git
cd geoexport # or geoexport-premium while the repo is being renamed
cp .env.example .env
npm install
npm run dev
```
Open [http://localhost:3000](http://localhost:3000).
### Production build
```bash
npm run build
npm run start
```
### Lint
```bash
npm run lint
```
---
## Configuration
Copy `.env.example` to `.env` and adjust:
| Variable | Description |
|----------|-------------|
| `DATABASE_URL` | PostgreSQL connection string (Prisma) |
| `REDIS_URL` | Redis for API/cache layers |
| `NEXT_PUBLIC_APP_URL` | Public URL (CORS, auth callbacks) |
| `GEOEXPORT_UPSTREAM` | Upstream host for mirror/proxy mode during migration |
Full reference: [.env.example](.env.example)
---
## Docker
Run the full stack (app + PostgreSQL + Redis):
```bash
cp .env.example .env
docker compose up -d --build
```
| Service | Port (host) | Notes |
|---------|-------------|--------|
| `web` | 3000 | Next.js (`npm run start` in container) |
| `postgres` | 5432 | Persistent volume `postgres_data` |
| `redis` | 6379 | Cache / rate limit |
Health check: `curl -f http://localhost:3000`
> Prisma migrations and geo data seeding are not wired in Docker yet — track progress in [Roadmap](#roadmap).
---
## API
Base path: `/api`
| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/presets` | Service preset groups |
| `GET` | `/api/sources` | Rule source metadata |
| `GET` | `/api/last-update` | Last database refresh timestamp |
| `GET` | `/api/routing/presets` | Saved routing templates |
| `POST` | `/api/routing/generate` | Generate routing config |
| `GET` | `/api/search?q=` | Search categories |
| `GET` | `/api/export?...` | Export list as plain text |
| `GET` | `/api/lookup?domain=` | DNS + geodb cross-check |
| `GET` | `/api/update/status` | Background update job status |
Contract details: [docs/API.md](docs/API.md)
---
## Deployment
- **Docker Compose** — single VPS, see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)
- **Vercel / edge** — frontend + serverless API routes (Redis/Postgres via managed providers)
- **nginx** — terminate TLS, proxy to `127.0.0.1:3000` (pattern used in [Domain_web](https://github.com/andrey271192/Domain_web))
---
## Security
- Run behind HTTPS in production
- Do not commit `.env` or API keys
- Rate-limit public `/api/*` when exposed to the internet
- Report issues: [docs/SECURITY.md](docs/SECURITY.md)
---
## Performance
- Static preset JSON can be CDN-cached (`Cache-Control` on read-only catalog endpoints)
- Redis backs hot search/export paths
- Next.js App Router + edge caching for public pages
- Geo `.dat` parsing runs in workers — not on the request thread
---
## Roadmap
- [ ] Port Domain_web UI into Next.js App Router
- [ ] Prisma schema + PostgreSQL seed from geoexport.org catalogs
- [ ] Self-contained geo workers (no upstream proxy)
- [ ] API keys + rate limiting
- [ ] GraphQL read API (optional)
- [ ] Helm chart / Terraform module
---
## Contributing
See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md). Marketing copy and launch templates: [docs/MARKETING.md](docs/MARKETING.md).
---
## Related projects
| Repo | Role |
|------|------|
| [andrey271192/Domain_web](https://github.com/andrey271192/Domain_web) | Production VPS mirror (nginx + Node static server) |
| [geoexport-clone](https://github.com/andrey271192/geoexport-clone) | Local dev mirror of geoexport.org UI |
---
## License
[MIT](LICENSE) — Copyright (c) 2026 GeoExport Contributors

View File

@@ -0,0 +1,57 @@
# GeoExport — local / single-node production stack
# Prisma migrations and geo workers: see docs/DEPLOYMENT.md (roadmap)
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "${PORT:-3000}:3000"
environment:
NODE_ENV: production
DATABASE_URL: postgresql://geoexport:geoexport@postgres:5432/geoexport?schema=public
REDIS_URL: redis://redis:6379
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
GEOEXPORT_UPSTREAM: ${GEOEXPORT_UPSTREAM:-https://geoexport.org}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: geoexport
POSTGRES_PASSWORD: geoexport
POSTGRES_DB: geoexport
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U geoexport -d geoexport"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
volumes:
postgres_data:
redis_data:

239
premium/docs/API.md Normal file
View File

@@ -0,0 +1,239 @@
# API reference
GeoExport exposes a **REST** API under `/api`. The contract matches [geoexport.org](https://geoexport.org) so existing clients and mirrors stay compatible.
**Base URL:** `https://your-instance.example.com`
**Content-Type:** `application/json` unless noted
**Errors:** JSON body `{ "error": "message" }` with appropriate HTTP status
---
## Catalog (cacheable)
### `GET /api/presets`
Returns preset groups with nested services and geoip/geosite category mappings.
**Response:** `200` — JSON array
```json
[
{
"group": "Мессенджеры",
"icon": "💬",
"slug": "messengers",
"services": [
{
"name": "Telegram",
"domain": "telegram.org",
"keywords": ["telegram"],
"categories": [
{
"full_name": "geosite:telegram",
"name": "telegram",
"type": "geosite",
"source_slug": "loyalsoldier",
"source_name": "Loyalsoldier"
}
]
}
]
}
]
```
---
### `GET /api/sources`
Rule database sources (download URLs, compatibility).
**Response:** `200` — JSON array
```json
[
{
"slug": "loyalsoldier",
"name": "Loyalsoldier",
"description": "…",
"compatible": "Xray, 3x-ui, V2Ray, Mihomo",
"geoip_url": "https://github.com/.../geoip.dat",
"geosite_url": "https://github.com/.../geosite.dat"
}
]
```
---
### `GET /api/last-update`
Timestamp of the last successful geo database refresh.
**Response:** `200`
```json
{
"updated_at": "2026-05-24T12:00:00Z"
}
```
---
### `GET /api/routing/presets`
Saved routing templates for the generator UI.
**Response:** `200` — JSON array of preset objects (structure varies by client target).
---
## Search & export
### `GET /api/search`
Search geoip/geosite categories.
**Query parameters**
| Param | Required | Description |
|-------|----------|-------------|
| `q` | yes | Search string |
| `source` | no | Filter by `source_slug` |
| `type` | no | `geoip` or `geosite` |
**Example**
```http
GET /api/search?q=telegram&source=loyalsoldier
```
**Response:** `200` — JSON array of matching categories
---
### `GET /api/export`
Export resolved entries as **plain text** (one category or domain per line depending on mode).
**Query parameters**
| Param | Required | Description |
|-------|----------|-------------|
| `category` | conditional | Full name, e.g. `geosite:telegram` |
| `source` | no | Source slug |
| `format` | no | Output variant (client-specific) |
**Response:** `200``text/plain`
**Example**
```bash
curl -s 'https://your-instance/api/export?category=geosite:telegram&source=loyalsoldier' -o telegram.txt
```
---
## DNS lookup
### `GET /api/lookup`
Resolve a domain and cross-check against loaded geo databases.
**Query parameters**
| Param | Required | Description |
|-------|----------|-------------|
| `domain` | yes | FQDN, e.g. `example.com` |
**Example**
```http
GET /api/lookup?domain=anydesk.com
```
**Response:** `200` — JSON with IPs, subdomains, and geodb hits (exact schema mirrors upstream).
---
## Routing generator
### `POST /api/routing/generate`
Generate a routing configuration snippet from selected rules and a template.
**Request body:** `application/json`
```json
{
"preset_id": "xray-default",
"rules": ["geosite:telegram", "geoip:netflix"],
"outbound": "proxy",
"client": "xray"
}
```
**Response:** `200` — JSON or plain text snippet (depends on `client`)
**Errors:** `400` validation, `422` unsupported combination
---
## Operations
### `GET /api/update/status`
Background geo database refresh status (worker jobs).
**Response:** `200`
```json
{
"status": "idle",
"last_run": "2026-05-24T06:00:00Z",
"progress": null
}
```
---
## Rate limiting (planned)
Public instances should enforce per-IP limits on:
- `/api/lookup`
- `/api/search`
- `/api/export`
Recommended defaults: **120 req/min** per IP (configurable via `GEOEXPORT_RATE_LIMIT_PER_MINUTE`).
---
## Authentication (planned)
Optional header:
```http
Authorization: Bearer <GEOEXPORT_API_KEY>
```
Required only when `GEOEXPORT_API_KEY` is set server-side.
---
## Compatibility notes
| Endpoint | Local JSON (mirror) | Full backend |
|----------|---------------------|--------------|
| `/api/presets` | Served from `data/presets.json` | PostgreSQL or static cache |
| `/api/sources` | `data/sources.json` | Same |
| `/api/last-update` | `data/last-update.json` | Same |
| `/api/routing/presets` | `data/routing-presets.json` | Same |
| `/api/search`, `/api/export`, `/api/lookup`, `/api/routing/generate` | Proxied upstream | Native handlers |
Mirror behavior is implemented in [Domain_web `server.mjs`](https://github.com/andrey271192/Domain_web/blob/main/site/server.mjs).
---
## GraphQL (roadmap)
A read-only GraphQL layer may expose `presets`, `sources`, and `search` for panel integrations. REST remains the stable contract.

View File

@@ -0,0 +1,145 @@
# Architecture
GeoExport is a full-stack web application for browsing geoip/geosite rule catalogs, exporting plain-text lists, and generating client routing snippets. This document describes the **target** architecture for `geoexport-premium` and how it relates to the existing static mirror.
## Goals
1. **Self-hosted** — operators run their own instance; no mandatory third-party backend.
2. **API-first** — every UI action has a REST equivalent for scripts and panels.
3. **Fast catalog UX** — presets and sources are served from cache/DB, not parsed on each page view.
4. **Heavy work off the hot path**`.dat` ingestion and DNS resolution run in workers or upstream services.
## System context
```mermaid
flowchart LR
subgraph clients [Clients]
Browser[Web UI]
CLI[Scripts / panels]
end
subgraph geoexport [GeoExport]
Next[Next.js App Router]
API[REST /api]
Worker[Geo workers]
end
subgraph data [Data plane]
PG[(PostgreSQL)]
RD[(Redis)]
GH[GitHub rule releases]
end
Browser --> Next
CLI --> API
Next --> API
API --> PG
API --> RD
Worker --> PG
Worker --> GH
API --> Worker
```
## Layers
### Presentation (`src/app`, `src/components`)
- **Next.js App Router** — server components for catalog pages; client components for search, export, DNS lookup, routing builder.
- **Tailwind CSS 4** + **shadcn/ui** — design system aligned with Linear/Vercel density.
- **Framer Motion** — transitions for panels, modals, and theme toggle.
### API (`src/app/api` — planned)
Route handlers mirror the public contract documented in [API.md](./API.md):
| Concern | Implementation |
|---------|----------------|
| Catalog | Read presets/sources from PostgreSQL or baked JSON during bootstrap |
| Search | Redis-backed index or PostgreSQL full-text |
| Export | Stream plain text from resolved category lists |
| Lookup | DNS resolver + geodb membership check |
| Routing | Template engine for Xray / Mihomo / Sing-box snippets |
During migration, some routes may **proxy** to `GEOEXPORT_UPSTREAM` (default `https://geoexport.org`), matching behavior in [Domain_web](https://github.com/andrey271192/Domain_web) `server.mjs`.
### Data (`prisma/` — planned)
| Model area | Purpose |
|------------|---------|
| `Source` | Rule repo metadata (slug, URLs, compatibility) |
| `PresetGroup` / `Service` | Curated UI presets |
| `Category` | geoip:/geosite: entries per source |
| `RoutingPreset` | Saved routing templates |
| `UpdateJob` | Refresh status for `.dat` pulls |
### Cache (`redis`)
- Catalog responses (`presets`, `sources`, `last-update`)
- Search result pages
- Rate limiting counters for public API
### Workers (planned)
Background jobs:
1. Download `geoip.dat` / `geosite.dat` from configured GitHub releases.
2. Parse and upsert category index into PostgreSQL.
3. Expose progress via `GET /api/update/status`.
## Deployment topologies
### A — Single VPS (Docker Compose)
`web` + `postgres` + `redis` on one host. nginx terminates TLS and proxies to port 3000.
### B — Split managed
- Next.js on Vercel / Cloudflare Pages
- Neon / RDS for PostgreSQL
- Upstash for Redis
### C — Mirror-only (legacy)
[Domain_web](https://github.com/andrey271192/Domain_web): static SPA + Node proxy on port 4173. No PostgreSQL. Suitable until the Next.js port is feature-complete.
## Repository layout (target)
```
geoexport-premium/
├── src/
│ ├── app/ # routes, layouts, API handlers
│ ├── components/ # UI primitives (shadcn)
│ └── lib/ # db, redis, geo parsers
├── prisma/
│ └── schema.prisma
├── public/
├── docs/
├── docker-compose.yml
├── Dockerfile
└── .env.example
```
## Compatibility matrix
| Client | Import format | Notes |
|--------|---------------|-------|
| Xray | geoip.dat, geosite.dat, routing rules | Primary target |
| 3x-ui | Same as Xray | Panel import |
| V2Ray | `.dat` lists | v2fly source |
| Mihomo | YAML routing | Generator output |
| Sing-box | JSON / rule-set | Generator output |
## Security boundaries
- Public read APIs are unauthenticated by default; operators should place GeoExport behind VPN or enable API keys (roadmap).
- DNS lookup must be rate-limited to prevent abuse as an open resolver.
- Upstream proxy mode forwards only whitelisted `/api/*` paths — never arbitrary SSRF targets.
## Evolution from Domain_web
| Domain_web | geoexport-premium |
|------------|-------------------|
| Static `index.html` + `server.mjs` | Next.js SSR/ISR |
| JSON files in `data/` | PostgreSQL + optional JSON seed |
| Proxied dynamic API | Native handlers + workers |
| systemd + nginx install script | Docker Compose + generic reverse proxy |

View File

@@ -0,0 +1,72 @@
# Contributing to GeoExport
Thanks for helping improve GeoExport. This project aims for production-grade quality — clear PRs, tested behavior, and docs that match the code.
## Ways to contribute
- Report bugs and gaps in [GitHub Issues](https://github.com/andrey271192/geoexport/issues)
- Improve docs (README, `docs/`, API examples)
- Port UI features from [Domain_web](https://github.com/andrey271192/Domain_web) into Next.js
- Implement API routes and Prisma models
- Add tests for parsers, export formatters, and routing generator
## Development setup
```bash
git clone https://github.com/andrey271192/geoexport.git
cd geoexport
cp .env.example .env
npm install
npm run dev
```
Open http://localhost:3000
### With Docker data services only
```bash
docker compose up -d postgres redis
# Run app on host:
npm run dev
```
## Branching
- `main` — stable, deployable
- `feat/*` — features
- `fix/*` — bug fixes
- `docs/*` — documentation only
## Pull request checklist
- [ ] `npm run lint` passes
- [ ] `npm run build` succeeds
- [ ] User-facing changes documented in README or `docs/`
- [ ] No secrets, `.env`, or large binary blobs committed
- [ ] PR description explains **why**, not only **what**
## Code style
- **TypeScript** strict mode
- **React** — functional components, hooks
- **Tailwind** — utility-first; use shadcn patterns for forms/dialogs
- **API routes** — validate input, return consistent JSON errors
- Keep diffs focused; avoid drive-by refactors
## Commit messages
Use [Conventional Commits](https://www.conventionalcommits.org/):
```
feat(api): add lookup rate limiter
fix(export): handle empty category
docs: update Docker deployment steps
```
## Security
Do not open public issues for vulnerabilities. See [SECURITY.md](./SECURITY.md).
## License
By contributing, you agree that your contributions are licensed under the [MIT License](../LICENSE).

195
premium/docs/DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,195 @@
# Deployment
This guide covers deploying **GeoExport** (`geoexport-premium`) on a VPS or container platform. For the **static mirror** that is production-ready today, use [andrey271192/Domain_web](https://github.com/andrey271192/Domain_web).
## Prerequisites
| Resource | Minimum | Recommended |
|----------|---------|-------------|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB | 2 GB+ |
| Disk | 10 GB | 20 GB+ (geo databases grow) |
| OS | Linux (Debian/Ubuntu/Alpine) | Ubuntu 22.04 LTS |
Software:
- Docker 24+ and Docker Compose v2, **or**
- Node.js 20+ with PostgreSQL 16 and Redis 7
---
## Option 1 — Docker Compose (recommended)
### 1. Clone and configure
```bash
git clone https://github.com/andrey271192/geoexport.git geoexport
cd geoexport
cp .env.example .env
# Edit DATABASE_URL / secrets if not using compose defaults
```
### 2. Start stack
```bash
docker compose up -d --build
```
Services:
| Name | Image | Host port |
|------|-------|-----------|
| `web` | Built from `Dockerfile` | `3000` |
| `postgres` | `postgres:16-alpine` | `5432` |
| `redis` | `redis:7-alpine` | `6379` |
Verify:
```bash
curl -f http://localhost:3000
docker compose logs -f web
```
### 3. Reverse proxy (nginx)
```nginx
server {
listen 80;
server_name geo.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
Add TLS with Certbot or Caddy. Set `NEXT_PUBLIC_APP_URL=https://geo.example.com` in `.env` and restart `web`.
---
## Option 2 — Bare Node.js
```bash
git clone https://github.com/andrey271192/geoexport.git geoexport
cd geoexport
cp .env.example .env
# Point DATABASE_URL and REDIS_URL to your instances
npm install
npm run build
NODE_ENV=production npm run start
```
Use **pm2** or **systemd** for process supervision:
```ini
# /etc/systemd/system/geoexport.service
[Unit]
Description=GeoExport Next.js
After=network.target
[Service]
Type=simple
User=geoexport
WorkingDirectory=/opt/geoexport
EnvironmentFile=/opt/geoexport/.env
ExecStart=/usr/bin/npm run start
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
---
## Option 3 — Domain_web mirror (available now)
One-line install on a fresh VPS:
```bash
curl -fsSL https://raw.githubusercontent.com/andrey271192/Domain_web/main/install.sh | sudo bash
```
- Site files: `/opt/domain_web/site/`
- Node service: `geoexport-site` on `127.0.0.1:4173`
- nginx on port 80
Update cached JSON:
```bash
cd /opt/domain_web/site
curl -fsSL https://geoexport.org/api/presets -o data/presets.json
curl -fsSL https://geoexport.org/api/sources -o data/sources.json
curl -fsSL https://geoexport.org/api/last-update -o data/last-update.json
curl -fsSL https://geoexport.org/api/routing/presets -o data/routing-presets.json
sudo systemctl restart geoexport-site
```
---
## Environment variables
See [.env.example](../.env.example). Critical production values:
| Variable | Notes |
|----------|-------|
| `NEXT_PUBLIC_APP_URL` | Canonical public URL |
| `DATABASE_URL` | Required when Prisma is enabled |
| `REDIS_URL` | Required for cache/rate limits |
| `GEOEXPORT_UPSTREAM` | Set only for hybrid/mirror mode |
---
## Database migrations (roadmap)
When Prisma lands in this repo:
```bash
npx prisma migrate deploy
npx prisma db seed
```
Until then, Docker Postgres is provisioned but unused by the app.
---
## Updates
**Docker:**
```bash
git pull
docker compose up -d --build
```
**Domain_web:**
```bash
cd /opt/domain_web && sudo git pull && sudo systemctl restart geoexport-site
```
---
## Health checks
| Check | Command |
|-------|---------|
| HTTP | `curl -sf http://localhost:3000` |
| Postgres | `docker compose exec postgres pg_isready -U geoexport` |
| Redis | `docker compose exec redis redis-cli ping` |
---
## Troubleshooting
| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| Export/search 502 | Upstream unreachable | Check `GEOEXPORT_UPSTREAM`, outbound HTTPS |
| Empty presets | DB not seeded | Use cached JSON or run seed (roadmap) |
| Docker build fails | Missing lockfile | `npm install` locally, commit `package-lock.json` |
| Port 3000 in use | Conflict | Set `PORT=3001` in `.env` and compose |

214
premium/docs/MARKETING.md Normal file
View File

@@ -0,0 +1,214 @@
# Marketing & launch copy
Repository: **GeoExport** (`geoexport`) — open-source geoip/geosite export platform.
English README: [../README.md](../README.md). Russian snippets below where noted.
---
## GitHub short description (≤350 chars)
```
Self-hosted geoip/geosite export & routing platform for Xray, 3x-ui, V2Ray, Mihomo, Sing-box. 59 service presets, DNS lookup, routing generator, REST API. Next.js, PostgreSQL, Redis, Docker. Privacy-friendly alternative to hosted geo list tools.
```
---
## GitHub About section
**Website:** `https://github.com/andrey271192/geoexport` (or your docs URL when live)
**Description:** (same as short description above)
**Topics:** see [Topics list](#github-topics-15-20)
---
## GitHub Topics (1520)
```
geoip
geosite
v2ray
xray
sing-box
mihomo
3x-ui
vpn
routing
proxy
self-hosted
nextjs
typescript
docker
postgresql
open-source
privacy
networking
devtools
russia-vpn
```
---
## Repository structure tree
```
geoexport/
├── src/
│ ├── app/ # Next.js App Router (pages + API)
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── api/ # REST handlers (planned)
│ ├── components/ # UI (shadcn/ui) — planned
│ └── lib/ # db, redis, geo utils — planned
├── prisma/ # schema & migrations — planned
├── public/ # static assets
├── docs/
│ ├── ARCHITECTURE.md
│ ├── API.md
│ ├── DEPLOYMENT.md
│ ├── CONTRIBUTING.md
│ ├── SECURITY.md
│ └── MARKETING.md # this file
├── docker-compose.yml
├── Dockerfile
├── .env.example
├── LICENSE
├── package.json
└── README.md
```
---
## SEO meta description (~155 chars)
```
GeoExport — self-hosted geoip & geosite lists for Xray, V2Ray, Mihomo. Export .txt, DNS lookup, routing rules. Open source, Docker, REST API.
```
---
## Product Hunt tagline & blurb
**Tagline:** Self-hosted geo lists for your VPN stack
**Description:**
GeoExport helps you browse, search, and export geoip/geosite categories from Loyalsoldier, RuNet Freedom, v2fly, and b4geoip — without relying on a closed SaaS.
- 59 service presets across 9 groups
- DNS lookup with geodb cross-check
- Routing snippet generator for Xray / Mihomo / Sing-box
- REST API + Docker deploy
Open source. Run it on your VPS in minutes.
---
## Telegram post (RU)
```
🌍 GeoExport — open-source замена geoexport.org на своём сервере
Экспорт geoip/geosite для Xray, 3x-ui, V2Ray, Mihomo, Sing-box:
• 9 групп пресетов, 59 сервисов
• поиск по категориям
• DNS lookup + проверка в базах
• генератор routing-правил
• экспорт .txt
• REST API + Docker
Стек: Next.js, PostgreSQL, Redis.
Код: github.com/andrey271192/geoexport
Звезда на GitHub = поддержка проекта ⭐
```
---
## Twitter / X launch
```
We shipped GeoExport — self-hosted geoip/geosite export for Xray, V2Ray, Mihomo, Sing-box.
59 presets · DNS lookup · routing generator · REST API · Docker
Open source. Your VPS. Your data.
⭐ github.com/andrey271192/geoexport
```
---
## Hacker News — Show HN
**Title:** Show HN: GeoExport self-hosted geoip/geosite export for Xray/V2Ray/Mihomo
**Body:**
I built GeoExport, an open-source platform to browse and export geoip/geosite rule lists used by VPN clients (Xray, 3x-ui, V2Ray, Mihomo, Sing-box).
It indexes categories from Loyalsoldier, RuNet Freedom, v2fly, and DanielLavrushin b4geoip, with 59 curated service presets (Telegram, YouTube, Steam, RU-blocked lists, etc.).
Features:
- Search and export plain-text lists
- DNS lookup with geodb cross-check
- Routing config generator
- REST API
- Docker Compose deploy (Next.js + Postgres + Redis)
Motivation: operators often depend on hosted geo tools with no self-host path. GeoExport is API-first and designed to run on a cheap VPS.
Repo: https://github.com/andrey271192/geoexport
A static mirror installer already exists (Domain_web); this repo is the full Next.js rewrite.
Feedback on API shape and self-hosted geo DB ingestion is especially welcome.
---
## Dev.to post outline
**Title:** Self-hosting geoip/geosite lists with GeoExport
1. **Problem** — VPN panels need fresh geoip/geosite data; hosted tools are convenient but opaque.
2. **What GeoExport does** — catalog UI, export, lookup, routing generator.
3. **Architecture sketch** — Next.js, Postgres, Redis, workers (diagram from ARCHITECTURE.md).
4. **Quick start**`docker compose up`, open localhost:3000.
5. **API examples**`curl` for presets, search, export.
6. **Comparison** — mirror mode (Domain_web) vs full stack.
7. **Roadmap** — Prisma, native workers, API keys.
8. **CTA** — star the repo, contribute via CONTRIBUTING.md.
Tags: `#opensource` `#vpn` `#nextjs` `#docker` `#devtools`
---
## Suggested repo naming
| Use case | Name |
|----------|------|
| Product | **GeoExport** |
| Premium fork folder | `geoexport-premium` |
| GitHub repo (recommended) | `geoexport` |
| Legacy mirror | `Domain_web` (keep for install scripts) |
Rename path when publishing:
```bash
# Example: push premium tree to new repo
git remote add origin git@github.com:andrey271192/geoexport.git
git push -u origin main
```
Or continue on `andrey271192/Domain_web` by merging `geoexport-premium` into `site/` when the Next port is ready.
---
## One-line pitch (EN)
**GeoExport:** run your own geoip/geosite export API and UI for Xray-class clients — open source, Docker-ready.
## One-line pitch (RU)
**GeoExport:** свой сервер для экспорта geoip/geosite и routing-правил под Xray и Mihomo — open source, Docker.

69
premium/docs/SECURITY.md Normal file
View File

@@ -0,0 +1,69 @@
# Security policy
## Supported versions
| Version | Supported |
|---------|-----------|
| `main` (latest) | Yes |
| Older tags | Best effort |
## Reporting a vulnerability
**Please do not** file public GitHub issues for security problems.
1. Email or DM the maintainer with a description and reproduction steps.
2. Allow up to **90 days** for a fix before public disclosure.
3. We will acknowledge receipt within **72 hours** when possible.
Include:
- Affected endpoints or components
- Impact (data leak, SSRF, RCE, etc.)
- Proof of concept if available
- Suggested fix (optional)
## Threat model (self-hosted)
GeoExport is typically deployed on a private VPS or internal network. Common risks:
| Risk | Mitigation |
|------|------------|
| Open DNS lookup abuse | Rate-limit `/api/lookup`; block private IP ranges in resolver |
| SSRF via upstream proxy | Whitelist paths; fixed `GEOEXPORT_UPSTREAM` host only |
| API scraping / DoS | Redis rate limits; nginx `limit_req` |
| Leaked `.env` | Never commit secrets; rotate DB passwords on deploy |
| Outdated geo databases | Monitor `/api/last-update`; automate refresh jobs |
## Hardening checklist (production)
- [ ] HTTPS only (TLS 1.2+)
- [ ] `NEXT_PUBLIC_APP_URL` matches real hostname
- [ ] Strong PostgreSQL password (not compose defaults)
- [ ] Redis bound to localhost or private network
- [ ] Firewall: expose only 80/443
- [ ] Disable directory listing on nginx
- [ ] Keep Node.js and base images patched (`docker compose pull`)
## Dependencies
- Run `npm audit` before releases
- Pin Docker image digests in production compose overrides
- Subscribe to GitHub security advisories for this repo
## Data privacy
GeoExport processes **domains and IPs** users submit for lookup. Operators should:
- Document retention (if logging lookups)
- Avoid shipping lookup logs to third parties without consent
- Prefer self-hosted rule databases over permanent upstream proxy when feasible
## Safe defaults
- No default API keys in repository
- Example compose passwords are for **local dev only** — change before internet exposure
- CSP headers on Next.js responses (planned)
## Recognition
We credit reporters in release notes when they agree to be named.

18
premium/eslint.config.mjs Normal file
View File

@@ -0,0 +1,18 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);
export default eslintConfig;

7
premium/next.config.ts Normal file
View File

@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

6755
premium/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
premium/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "geoexport-premium",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"next": "16.2.6",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.6",
"tailwindcss": "^4",
"typescript": "^5"
}
}

View File

@@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;

1
premium/public/file.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

1
premium/public/globe.svg Normal file
View File

@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
premium/public/next.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

View File

@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

BIN
premium/src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,26 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}

View File

@@ -0,0 +1,33 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>
</html>
);
}

65
premium/src/app/page.tsx Normal file
View File

@@ -0,0 +1,65 @@
import Image from "next/image";
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
</div>
);
}

34
premium/tsconfig.json Normal file
View File

@@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}