mirror of
https://github.com/freedbygrace/DynamoDNS.git
synced 2026-07-26 11:38:13 +00:00
Document project architecture, setup, usage, and API endpoints
Adds comprehensive documentation including architecture, API reference, deployment, development, and user guides with README.md. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/910f6160-6716-488e-83e6-61256595c269.jpg
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
# DynamoDNS
|
||||
|
||||
A comprehensive web-based dynamic DNS management platform offering advanced infrastructure control, monitoring, and multi-provider integration with a focus on user experience and security.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-Provider DNS Management**: Support for Cloudflare, AWS Route53, GoDaddy, and custom providers
|
||||
- **Dynamic DNS Updates**: Automatic IP detection and DNS record updates
|
||||
- **Role-Based Access Control**: Granular permissions with customizable roles
|
||||
- **Customer Management**: Support for multiple organizations with isolated access
|
||||
- **Historical Tracking**: Complete audit trail of DNS changes
|
||||
- **Performance Metrics**: Visualize DNS performance and activity
|
||||
- **API Integration**: RESTful API with token-based authentication
|
||||
- **Webhook Notifications**: Real-time notifications for DNS events
|
||||
- **Multi-Factor Authentication**: Enhanced security for user accounts
|
||||
- **Customizable Dashboards**: Personalized monitoring views
|
||||
|
||||
## Technology Stack
|
||||
|
||||
- **Backend**:
|
||||
- Express.js for API server
|
||||
- PostgreSQL for robust data storage
|
||||
- Drizzle ORM for database interactions
|
||||
- Passport.js for multi-method authentication
|
||||
- WebSockets for real-time updates
|
||||
|
||||
- **Frontend**:
|
||||
- React for user interface
|
||||
- TanStack Query for data fetching and caching
|
||||
- Shadcn UI components for consistent design
|
||||
- Tailwind CSS for styling
|
||||
- Recharts for data visualization
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js (v18 or later)
|
||||
- PostgreSQL (v14 or later)
|
||||
- Modern web browser
|
||||
|
||||
### Installation
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/yourusername/dynamodns.git
|
||||
cd dynamodns
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Configure environment variables by creating a `.env` file:
|
||||
```
|
||||
DATABASE_URL=postgresql://username:password@localhost:5432/dynamodns
|
||||
PORT=5000
|
||||
SESSION_SECRET=your_secure_secret
|
||||
ENABLE_REGISTRATION=false
|
||||
```
|
||||
|
||||
4. Run database migrations:
|
||||
```bash
|
||||
npm run db:push
|
||||
```
|
||||
|
||||
5. Start the application:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
6. Access the application at http://localhost:5000
|
||||
|
||||
### Default Admin Account
|
||||
|
||||
On first launch, a default admin account is created:
|
||||
- Username: `admin`
|
||||
- Password: `admin`
|
||||
|
||||
**Important**: Change the default password immediately after first login.
|
||||
|
||||
## Documentation
|
||||
|
||||
Comprehensive documentation is available in the `/docs` directory:
|
||||
|
||||
- [User Guide](docs/user-guide.md) - For end users managing DNS records
|
||||
- [API Reference](docs/api-reference.md) - For developers integrating with the API
|
||||
- [Deployment Guide](docs/deployment-guide.md) - For system administrators
|
||||
- [Development Guide](docs/development-guide.md) - For contributors
|
||||
- [Architecture](docs/architecture.md) - System design and architecture overview
|
||||
|
||||
## Deployment
|
||||
|
||||
DynamoDNS can be deployed in various environments:
|
||||
|
||||
- **Standalone Server**: Direct installation on Linux/Windows servers
|
||||
- **Docker**: Container-based deployment with Docker Compose
|
||||
- **Cloud Platforms**: Deploy to AWS, Azure, Google Cloud, or other providers
|
||||
|
||||
See the [Deployment Guide](docs/deployment-guide.md) for detailed instructions.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions from the community! Please see our [Development Guide](docs/development-guide.md) for information on getting started with development.
|
||||
|
||||
To contribute:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Support
|
||||
|
||||
For support or questions, please [open an issue](https://github.com/yourusername/dynamodns/issues) on GitHub, or contact the maintainers directly.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
- The open source community for the amazing tools that make this project possible
|
||||
- Contributors who have helped improve and maintain this project
|
||||
- Users who have provided feedback and feature suggestions
|
||||
@@ -0,0 +1,586 @@
|
||||
# DynamoDNS API Reference
|
||||
|
||||
This document provides detailed information about the DynamoDNS REST API endpoints, request/response formats, and authentication mechanisms.
|
||||
|
||||
## Authentication
|
||||
|
||||
The API supports two authentication methods:
|
||||
|
||||
### Session Authentication (Web UI)
|
||||
|
||||
Used for browser-based interactions. Authenticate via:
|
||||
- POST `/api/login`
|
||||
- GET `/api/user` (verify current session)
|
||||
- POST `/api/logout`
|
||||
|
||||
### API Token Authentication
|
||||
|
||||
Required for programmatic access:
|
||||
- Include the token in the `Authorization` header: `Authorization: Bearer YOUR_API_TOKEN`
|
||||
- API tokens can be created and managed through the web interface or via API
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Authentication
|
||||
|
||||
#### `POST /api/login`
|
||||
|
||||
Authenticates a user and creates a session.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"username": "string",
|
||||
"password": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "string",
|
||||
"username": "string",
|
||||
"email": "string",
|
||||
"fullName": "string",
|
||||
"role": "string"
|
||||
}
|
||||
```
|
||||
|
||||
#### `POST /api/register`
|
||||
|
||||
Registers a new user (if enabled).
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"username": "string",
|
||||
"email": "string",
|
||||
"password": "string",
|
||||
"fullName": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "string",
|
||||
"username": "string",
|
||||
"email": "string",
|
||||
"fullName": "string",
|
||||
"role": "string"
|
||||
}
|
||||
```
|
||||
|
||||
#### `POST /api/logout`
|
||||
|
||||
Ends the current user session.
|
||||
|
||||
**Response:**
|
||||
HTTP 200 OK
|
||||
|
||||
#### `GET /api/user`
|
||||
|
||||
Retrieves the current authenticated user's information.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "string",
|
||||
"username": "string",
|
||||
"email": "string",
|
||||
"fullName": "string",
|
||||
"role": "string"
|
||||
}
|
||||
```
|
||||
|
||||
#### `GET /api/auth/config`
|
||||
|
||||
Retrieves the authentication configuration.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"localAuthEnabled": true,
|
||||
"registrationEnabled": false,
|
||||
"ldapEnabled": false,
|
||||
"oidcEnabled": false
|
||||
}
|
||||
```
|
||||
|
||||
### Customers
|
||||
|
||||
#### `GET /api/customers`
|
||||
|
||||
Returns all customers the authenticated user has access to.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"description": "string",
|
||||
"email": "string",
|
||||
"phone": "string",
|
||||
"address": "string",
|
||||
"city": "string",
|
||||
"state": "string",
|
||||
"zipCode": "string",
|
||||
"country": "string",
|
||||
"website": "string",
|
||||
"industry": "string",
|
||||
"notes": "string",
|
||||
"accountManager": "string",
|
||||
"billingEmail": "string",
|
||||
"billingAddress": "string",
|
||||
"isActive": true,
|
||||
"createdAt": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### `GET /api/customers/:id`
|
||||
|
||||
Returns a specific customer by ID.
|
||||
|
||||
**Response:** Customer object
|
||||
|
||||
#### `POST /api/customers`
|
||||
|
||||
Creates a new customer.
|
||||
|
||||
**Request:** Customer object without id and createdAt
|
||||
**Response:** Created customer object
|
||||
|
||||
#### `PUT /api/customers/:id`
|
||||
|
||||
Updates an existing customer.
|
||||
|
||||
**Request:** Partial customer object
|
||||
**Response:** Updated customer object
|
||||
|
||||
#### `DELETE /api/customers/:id`
|
||||
|
||||
Deletes a customer.
|
||||
|
||||
**Response:** HTTP 200 OK
|
||||
|
||||
### Domains
|
||||
|
||||
#### `GET /api/domains`
|
||||
|
||||
Returns all domains the user has access to.
|
||||
|
||||
**Query Parameters:**
|
||||
- `customerId` (optional): Filter by customer ID
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"customerId": "string",
|
||||
"providerId": "string",
|
||||
"isActive": true,
|
||||
"createdAt": "string",
|
||||
"lastUpdated": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### `GET /api/domains/:id`
|
||||
|
||||
Returns a specific domain by ID.
|
||||
|
||||
**Response:** Domain object
|
||||
|
||||
#### `POST /api/domains`
|
||||
|
||||
Creates a new domain.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"customerId": "string",
|
||||
"providerId": "string",
|
||||
"isActive": true
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** Created domain object
|
||||
|
||||
#### `PUT /api/domains/:id`
|
||||
|
||||
Updates an existing domain.
|
||||
|
||||
**Request:** Partial domain object
|
||||
**Response:** Updated domain object
|
||||
|
||||
#### `DELETE /api/domains/:id`
|
||||
|
||||
Deletes a domain.
|
||||
|
||||
**Response:** HTTP 200 OK
|
||||
|
||||
### DNS Records
|
||||
|
||||
#### `GET /api/dns-records`
|
||||
|
||||
Returns DNS records the user has access to.
|
||||
|
||||
**Query Parameters:**
|
||||
- `domainId` (optional): Filter by domain ID
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"type": "A | AAAA | CNAME | MX | TXT | SRV | NS | CAA | PTR",
|
||||
"content": "string",
|
||||
"domainId": "string",
|
||||
"priority": 0,
|
||||
"ttl": 3600,
|
||||
"proxied": false,
|
||||
"isAutoIP": false,
|
||||
"isActive": true,
|
||||
"notes": "string",
|
||||
"providerRecordId": "string",
|
||||
"createdAt": "string",
|
||||
"updatedAt": "string",
|
||||
"currentIp": "string" // Only present when isAutoIP is true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### `GET /api/dns-records/:id`
|
||||
|
||||
Returns a specific DNS record by ID.
|
||||
|
||||
**Response:** DNS record object
|
||||
|
||||
#### `POST /api/dns-records`
|
||||
|
||||
Creates a new DNS record.
|
||||
|
||||
**Request:** DNS record object without id, createdAt, updatedAt
|
||||
**Response:** Created DNS record object
|
||||
|
||||
#### `PUT /api/dns-records/:id`
|
||||
|
||||
Updates an existing DNS record.
|
||||
|
||||
**Request:** Partial DNS record object
|
||||
**Response:** Updated DNS record object
|
||||
|
||||
#### `DELETE /api/dns-records/:id`
|
||||
|
||||
Deletes a DNS record.
|
||||
|
||||
**Response:** HTTP 200 OK
|
||||
|
||||
#### `POST /api/dns-records/:id/toggle`
|
||||
|
||||
Toggles a DNS record's active status.
|
||||
|
||||
**Response:** Updated DNS record object
|
||||
|
||||
### Providers
|
||||
|
||||
#### `GET /api/providers`
|
||||
|
||||
Returns all DNS providers.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"type": "cloudflare | route53 | godaddy | other",
|
||||
"isActive": true,
|
||||
"credentials": {
|
||||
// Provider-specific credentials (redacted in response)
|
||||
},
|
||||
"createdAt": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### `GET /api/providers/:id`
|
||||
|
||||
Returns a specific provider by ID.
|
||||
|
||||
**Response:** Provider object (credentials redacted)
|
||||
|
||||
#### `POST /api/providers`
|
||||
|
||||
Creates a new provider.
|
||||
|
||||
**Request:** Provider object with credentials
|
||||
**Response:** Created provider object (credentials redacted)
|
||||
|
||||
#### `PUT /api/providers/:id`
|
||||
|
||||
Updates an existing provider.
|
||||
|
||||
**Request:** Partial provider object
|
||||
**Response:** Updated provider object (credentials redacted)
|
||||
|
||||
#### `DELETE /api/providers/:id`
|
||||
|
||||
Deletes a provider.
|
||||
|
||||
**Response:** HTTP 200 OK
|
||||
|
||||
### DNS History
|
||||
|
||||
#### `GET /api/dns-history`
|
||||
|
||||
Returns DNS history records.
|
||||
|
||||
**Query Parameters:**
|
||||
- `recordId` (optional): Filter by DNS record ID
|
||||
- `domainId` (optional): Filter by domain ID
|
||||
- `startDate` (optional): Filter by start date
|
||||
- `endDate` (optional): Filter by end date
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"recordId": "string",
|
||||
"domainId": "string",
|
||||
"previousValue": "string",
|
||||
"newValue": "string",
|
||||
"changedBy": "string",
|
||||
"createdAt": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Metrics
|
||||
|
||||
#### `GET /api/dns-metrics`
|
||||
|
||||
Returns DNS metrics.
|
||||
|
||||
**Query Parameters:**
|
||||
- `recordId` (optional): Filter by DNS record ID
|
||||
- `domainId` (optional): Filter by domain ID
|
||||
- `type` (optional): Filter by metric type
|
||||
- `startDate` (optional): Filter by start date
|
||||
- `endDate` (optional): Filter by end date
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"recordId": "string",
|
||||
"domainId": "string",
|
||||
"type": "string",
|
||||
"value": 0,
|
||||
"timestamp": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### API Tokens
|
||||
|
||||
#### `GET /api/api-tokens`
|
||||
|
||||
Returns all API tokens for the authenticated user.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"token": "string", // Only the first few and last few characters
|
||||
"createdBy": "string",
|
||||
"expiresAt": "string",
|
||||
"isActive": true,
|
||||
"role": "string",
|
||||
"createdAt": "string",
|
||||
"customerAccess": [
|
||||
{
|
||||
"customerId": "string",
|
||||
"customerName": "string" // Populated for convenience
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### `POST /api/api-tokens`
|
||||
|
||||
Creates a new API token.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"expiresAt": "string", // optional
|
||||
"role": "string",
|
||||
"customerIds": ["string"] // optional, if empty, grants access to all customers
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** Created API token object with the full token value (only returned once)
|
||||
|
||||
#### `PUT /api/api-tokens/:id`
|
||||
|
||||
Updates an existing API token.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"expiresAt": "string",
|
||||
"isActive": true,
|
||||
"customerIds": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** Updated API token object
|
||||
|
||||
#### `DELETE /api/api-tokens/:id`
|
||||
|
||||
Revokes an API token.
|
||||
|
||||
**Response:** HTTP 200 OK
|
||||
|
||||
### Webhooks
|
||||
|
||||
#### `GET /api/webhooks`
|
||||
|
||||
Returns all webhooks for the authenticated user's customers.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"customerId": "string",
|
||||
"name": "string",
|
||||
"url": "string",
|
||||
"secret": "string", // Redacted
|
||||
"events": ["string"],
|
||||
"isActive": true,
|
||||
"createdAt": "string",
|
||||
"lastTriggered": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### `POST /api/webhooks`
|
||||
|
||||
Creates a new webhook.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"customerId": "string",
|
||||
"name": "string",
|
||||
"url": "string",
|
||||
"secret": "string",
|
||||
"events": ["string"],
|
||||
"isActive": true
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** Created webhook object (secret redacted)
|
||||
|
||||
#### `GET /api/webhook-logs`
|
||||
|
||||
Returns webhook delivery logs.
|
||||
|
||||
**Query Parameters:**
|
||||
- `webhookId` (required): Filter by webhook ID
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"webhookId": "string",
|
||||
"event": "string",
|
||||
"payload": "object",
|
||||
"response": "string",
|
||||
"statusCode": 0,
|
||||
"success": true,
|
||||
"createdAt": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Utility Endpoints
|
||||
|
||||
#### `GET /api/public-ip`
|
||||
|
||||
Returns the public IP addresses of the client.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"ipv4": "string",
|
||||
"ipv6": "string"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
All API endpoints return standard HTTP status codes:
|
||||
|
||||
- **400 Bad Request**: Invalid input
|
||||
- **401 Unauthorized**: Missing or invalid authentication
|
||||
- **403 Forbidden**: Insufficient permissions
|
||||
- **404 Not Found**: Resource not found
|
||||
- **500 Internal Server Error**: Server-side error
|
||||
|
||||
Error responses include a JSON body with error details:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Error description",
|
||||
"code": "ERROR_CODE",
|
||||
"details": {} // Additional error details when available
|
||||
}
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
API requests are rate-limited to prevent abuse. Rate limit headers are included in all responses:
|
||||
|
||||
- `X-RateLimit-Limit`: Number of requests allowed in the current time window
|
||||
- `X-RateLimit-Remaining`: Number of requests remaining in the current time window
|
||||
- `X-RateLimit-Reset`: Time when the rate limit window resets (Unix timestamp)
|
||||
|
||||
When rate limits are exceeded, a 429 Too Many Requests response is returned.
|
||||
|
||||
## Pagination
|
||||
|
||||
List endpoints support pagination using the following query parameters:
|
||||
|
||||
- `page`: Page number (default: 1)
|
||||
- `limit`: Items per page (default: 20, max: 100)
|
||||
|
||||
Paginated responses include metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [],
|
||||
"pagination": {
|
||||
"total": 0,
|
||||
"pages": 0,
|
||||
"page": 1,
|
||||
"limit": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,118 @@
|
||||
# DynamoDNS Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
DynamoDNS is a comprehensive web-based dynamic DNS management platform that offers advanced infrastructure control, monitoring, and multi-provider integration. The application focuses on user experience and security while providing a robust solution for maintaining DNS records across multiple providers.
|
||||
|
||||
## System Architecture
|
||||
|
||||
The system is built on a modern web stack with the following components:
|
||||
|
||||
### Backend
|
||||
- **Express.js Server**: Handles API requests, authentication, and business logic
|
||||
- **PostgreSQL Database**: Provides robust data storage using the Neon serverless Postgres service
|
||||
- **Drizzle ORM**: Manages database interactions and schema definition
|
||||
- **Authentication System**: Supports multiple authentication methods (local, LDAP, OIDC)
|
||||
- **DNS Provider Modules**: Integrates with various DNS providers (Cloudflare, AWS Route53, GoDaddy, etc.)
|
||||
|
||||
### Frontend
|
||||
- **React**: Powers the user interface
|
||||
- **TanStack Query**: Manages data fetching and caching
|
||||
- **Shadcn UI**: Provides consistent, accessible UI components
|
||||
- **Tailwind CSS**: Handles styling with utility-first approach
|
||||
- **Wouter**: Manages client-side routing
|
||||
|
||||
## Component Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Client Browser │
|
||||
└───────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────────────▼─────────────────────────────────┐
|
||||
│ Express Server │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────────────┐ ┌────────────┐ │
|
||||
│ │ Authentication │ │ API Routes │ │ WebSockets │ │
|
||||
│ └─────────────────┘ └──────────────┘ └────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────────────┐ ┌────────────┐ │
|
||||
│ │ Storage Layer │ │ DNS Provider │ │ Metrics │ │
|
||||
│ └────────┬────────┘ │ Modules │ │ Collection │ │
|
||||
│ │ └──────┬───────┘ └────────────┘ │
|
||||
└───────────┼──────────────────────────────────────────────────┘
|
||||
│ │
|
||||
┌───────────▼────────┐ ┌────────▼───────────────────────────┐
|
||||
│ PostgreSQL DB │ │ External DNS APIs │
|
||||
│ (via Drizzle ORM) │ │ (Cloudflare, Route53, GoDaddy) │
|
||||
└────────────────────┘ └────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
The database schema is defined using Drizzle ORM and includes the following main entities:
|
||||
|
||||
- **Users**: Application users with authentication details
|
||||
- **Customers**: Organizations/accounts using the system
|
||||
- **Customer User Assignments**: Many-to-many relationship connecting users to customers
|
||||
- **Providers**: DNS service providers integrated with the system
|
||||
- **Domains**: DNS domains managed by the system
|
||||
- **DNS Records**: Individual DNS records within domains
|
||||
- **DNS History**: Historical record of DNS changes
|
||||
- **Metrics**: Performance and usage metrics
|
||||
- **API Tokens**: Tokens for API authentication
|
||||
- **Webhooks**: Notification integration points
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
The application supports multiple authentication methods:
|
||||
|
||||
1. **Local Authentication**: Username/password stored in the database
|
||||
2. **LDAP**: Integration with corporate directories
|
||||
3. **OpenID Connect**: Single sign-on with identity providers
|
||||
|
||||
Authentication is managed via Passport.js with session-based authentication for the web interface and token-based authentication for API access.
|
||||
|
||||
## Authorization Model
|
||||
|
||||
The system implements a role-based access control (RBAC) model with the following roles:
|
||||
|
||||
- **Admin**: Full system access
|
||||
- **Manager**: Can manage customers, domains, and DNS records
|
||||
- **User**: Can manage assigned domains and DNS records
|
||||
- **ReadOnly**: View-only access to assigned resources
|
||||
- **Custom Roles**: User-defined roles with specific permissions
|
||||
|
||||
## Data Flow
|
||||
|
||||
### DNS Record Updates
|
||||
|
||||
1. User initiates a DNS record update through the UI
|
||||
2. Server validates the request and user permissions
|
||||
3. Server dispatches the update to the appropriate DNS provider module
|
||||
4. Provider module makes API calls to the external DNS service
|
||||
5. Results are recorded in the database (success or failure)
|
||||
6. Historical entry is created
|
||||
7. Metrics are updated
|
||||
8. Webhooks are triggered (if configured)
|
||||
9. Client is notified of the outcome
|
||||
|
||||
### Automatic IP Updates
|
||||
|
||||
For dynamic DNS functionality:
|
||||
|
||||
1. Client periodically checks for IP changes
|
||||
2. When a change is detected, updates are sent to the server
|
||||
3. Server processes updates for all DNS records configured for automatic IP updates
|
||||
4. External DNS providers are updated
|
||||
5. History and metrics are recorded
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Authentication**: Multiple secure authentication methods
|
||||
- **Authorization**: Granular role-based access control
|
||||
- **API Tokens**: Scoped access with expiration
|
||||
- **Audit Trail**: Comprehensive history logging
|
||||
- **Credential Storage**: Secure storage of provider credentials
|
||||
- **Input Validation**: Strict validation of all inputs
|
||||
- **Rate Limiting**: Protection against abuse
|
||||
@@ -0,0 +1,380 @@
|
||||
# DynamoDNS Deployment Guide
|
||||
|
||||
This guide outlines the steps required to deploy and configure DynamoDNS in your environment.
|
||||
|
||||
## System Requirements
|
||||
|
||||
### Minimum Requirements
|
||||
|
||||
- **Node.js**: v18.0.0 or higher
|
||||
- **PostgreSQL**: v14.0 or higher (or Neon serverless database)
|
||||
- **Operating System**: Any OS that supports Node.js (Linux recommended for production)
|
||||
- **Memory**: 1GB RAM minimum (2GB+ recommended)
|
||||
- **Storage**: 1GB for application, database size depends on usage
|
||||
|
||||
### Recommended Production Setup
|
||||
|
||||
- **Node.js**: Latest LTS version
|
||||
- **PostgreSQL**: Latest stable version
|
||||
- **Operating System**: Linux (Ubuntu 22.04 LTS or similar)
|
||||
- **Memory**: 4GB RAM
|
||||
- **Storage**: 10GB SSD
|
||||
- **Web Server**: Nginx as a reverse proxy
|
||||
- **SSL Certificate**: Let's Encrypt or similar
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: Docker Deployment (Recommended)
|
||||
|
||||
1. **Clone the repository**:
|
||||
```bash
|
||||
git clone https://github.com/yourusername/dynamodns.git
|
||||
cd dynamodns
|
||||
```
|
||||
|
||||
2. **Configure environment variables**:
|
||||
Create a `.env` file based on the `.env.example` template:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
nano .env # Edit with your configuration
|
||||
```
|
||||
|
||||
3. **Build and start the containers**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Run database migrations**:
|
||||
```bash
|
||||
docker-compose exec app npm run db:push
|
||||
```
|
||||
|
||||
5. **Create initial admin user** (if not using the automated setup):
|
||||
```bash
|
||||
docker-compose exec app npm run create-admin
|
||||
```
|
||||
|
||||
### Option 2: Manual Deployment
|
||||
|
||||
1. **Clone the repository**:
|
||||
```bash
|
||||
git clone https://github.com/yourusername/dynamodns.git
|
||||
cd dynamodns
|
||||
```
|
||||
|
||||
2. **Install dependencies**:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. **Configure environment variables**:
|
||||
Create a `.env` file with your configuration:
|
||||
```
|
||||
# Database configuration
|
||||
DATABASE_URL=postgresql://user:password@localhost:5432/dynamodns
|
||||
|
||||
# Server configuration
|
||||
PORT=5000
|
||||
NODE_ENV=production
|
||||
SESSION_SECRET=your_secure_session_secret
|
||||
|
||||
# Authentication configuration
|
||||
ENABLE_REGISTRATION=false
|
||||
|
||||
# Optional: LDAP configuration
|
||||
LDAP_ENABLED=false
|
||||
LDAP_URL=ldap://ldap.example.com
|
||||
LDAP_BIND_DN=cn=admin,dc=example,dc=com
|
||||
LDAP_BIND_PASSWORD=password
|
||||
LDAP_SEARCH_BASE=ou=users,dc=example,dc=com
|
||||
LDAP_SEARCH_FILTER=(uid={{username}})
|
||||
|
||||
# Optional: OpenID Connect configuration
|
||||
OIDC_ENABLED=false
|
||||
OIDC_ISSUER=https://auth.example.com
|
||||
OIDC_CLIENT_ID=your_client_id
|
||||
OIDC_CLIENT_SECRET=your_client_secret
|
||||
OIDC_CALLBACK_URL=https://dynamodns.example.com/api/auth/oidc/callback
|
||||
```
|
||||
|
||||
4. **Run database migrations**:
|
||||
```bash
|
||||
npm run db:push
|
||||
```
|
||||
|
||||
5. **Build the application**:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
6. **Start the application**:
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Database Configuration
|
||||
|
||||
- **DATABASE_URL**: Connection string for PostgreSQL
|
||||
|
||||
### Server Configuration
|
||||
|
||||
- **PORT**: The port on which the server will listen (default: 5000)
|
||||
- **NODE_ENV**: Environment (development/production)
|
||||
- **HOST**: Host to bind to (default: 0.0.0.0)
|
||||
- **SESSION_SECRET**: Secret for session encryption (generate a secure random string)
|
||||
|
||||
### Authentication Configuration
|
||||
|
||||
- **ENABLE_REGISTRATION**: Allow new user registration (true/false)
|
||||
- **DEFAULT_ADMIN_USERNAME**: Username for the default admin (default: admin)
|
||||
- **DEFAULT_ADMIN_PASSWORD**: Password for the default admin (set this for initial setup)
|
||||
- **DEFAULT_ADMIN_EMAIL**: Email for the default admin (default: admin@example.com)
|
||||
|
||||
### LDAP Configuration (Optional)
|
||||
|
||||
- **LDAP_ENABLED**: Enable LDAP authentication (true/false)
|
||||
- **LDAP_URL**: LDAP server URL
|
||||
- **LDAP_BIND_DN**: DN for binding to LDAP
|
||||
- **LDAP_BIND_PASSWORD**: Password for binding to LDAP
|
||||
- **LDAP_SEARCH_BASE**: Base DN for user search
|
||||
- **LDAP_SEARCH_FILTER**: Filter for finding users (use {{username}} as placeholder)
|
||||
- **LDAP_USER_ATTR_USERNAME**: LDAP attribute for username (default: uid)
|
||||
- **LDAP_USER_ATTR_EMAIL**: LDAP attribute for email (default: mail)
|
||||
- **LDAP_USER_ATTR_DISPLAY_NAME**: LDAP attribute for display name (default: cn)
|
||||
|
||||
### OpenID Connect Configuration (Optional)
|
||||
|
||||
- **OIDC_ENABLED**: Enable OIDC authentication (true/false)
|
||||
- **OIDC_ISSUER**: OIDC issuer URL
|
||||
- **OIDC_CLIENT_ID**: Client ID for OIDC
|
||||
- **OIDC_CLIENT_SECRET**: Client secret for OIDC
|
||||
- **OIDC_CALLBACK_URL**: Callback URL for OIDC authentication
|
||||
- **OIDC_SCOPE**: Scopes to request (default: "openid profile email")
|
||||
|
||||
## DNS Provider Configuration
|
||||
|
||||
DynamoDNS supports multiple DNS providers. Each requires specific configuration:
|
||||
|
||||
### Cloudflare
|
||||
|
||||
Required credentials:
|
||||
- API Token or API Key + Email
|
||||
- Zone IDs (optional, can be fetched automatically)
|
||||
|
||||
### AWS Route53
|
||||
|
||||
Required credentials:
|
||||
- Access Key ID
|
||||
- Secret Access Key
|
||||
- Region
|
||||
|
||||
### GoDaddy
|
||||
|
||||
Required credentials:
|
||||
- API Key
|
||||
- API Secret
|
||||
|
||||
### Generic Provider
|
||||
|
||||
For custom or unsupported providers:
|
||||
- API URL
|
||||
- Authentication method
|
||||
- Request format
|
||||
|
||||
## Setting Up Reverse Proxy
|
||||
|
||||
For production deployments, it's recommended to use a reverse proxy like Nginx or Apache.
|
||||
|
||||
### Nginx Configuration Example
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name dynamodns.example.com;
|
||||
|
||||
# Redirect to HTTPS
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name dynamodns.example.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
# SSL configuration
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
|
||||
|
||||
# Proxy to Node.js application
|
||||
location / {
|
||||
proxy_pass http://localhost:5000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
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;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Database Backup and Maintenance
|
||||
|
||||
### Automated Backups
|
||||
|
||||
For PostgreSQL:
|
||||
|
||||
```bash
|
||||
# Add to crontab for daily backups
|
||||
0 2 * * * pg_dump -U username -d dynamodns > /path/to/backup/dynamodns_$(date +\%Y\%m\%d).sql
|
||||
```
|
||||
|
||||
For Neon PostgreSQL:
|
||||
- Enable automated backups through the Neon dashboard
|
||||
- Set an appropriate backup schedule and retention policy
|
||||
|
||||
### Database Maintenance
|
||||
|
||||
Regular maintenance tasks:
|
||||
|
||||
```bash
|
||||
# Vacuum the database to optimize performance
|
||||
psql -U username -d dynamodns -c "VACUUM ANALYZE;"
|
||||
|
||||
# Check for slow queries
|
||||
psql -U username -d dynamodns -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"
|
||||
```
|
||||
|
||||
## System Monitoring
|
||||
|
||||
### Health Check Endpoint
|
||||
|
||||
The application provides a health check endpoint at `/api/health` that returns:
|
||||
- Application status
|
||||
- Database connectivity
|
||||
- DNS provider connectivity
|
||||
|
||||
### Recommended Monitoring Tools
|
||||
|
||||
- **Uptime Monitoring**: Pingdom, UptimeRobot, or similar
|
||||
- **Application Monitoring**: New Relic, Datadog, or similar
|
||||
- **Log Management**: ELK Stack, Graylog, or similar
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Securing Your Deployment
|
||||
|
||||
1. **Use HTTPS**: Always use SSL/TLS in production
|
||||
2. **Firewall Configuration**: Restrict access to the server
|
||||
3. **Regular Updates**: Keep all dependencies up to date
|
||||
4. **Secure Credentials**: Use environment variables, not hardcoded values
|
||||
5. **Rate Limiting**: Configure rate limiting to prevent abuse
|
||||
|
||||
### Data Protection
|
||||
|
||||
1. **Encryption**: Sensitive data is encrypted in the database
|
||||
2. **Backups**: Regular encrypted backups
|
||||
3. **Access Control**: Implement least privilege principle
|
||||
4. **Audit Logs**: Monitor and review access logs
|
||||
|
||||
## Upgrading
|
||||
|
||||
### Standard Upgrade Process
|
||||
|
||||
1. **Backup your data**:
|
||||
```bash
|
||||
pg_dump -U username -d dynamodns > /path/to/backup/dynamodns_before_upgrade.sql
|
||||
```
|
||||
|
||||
2. **Pull the latest changes**:
|
||||
```bash
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
3. **Install dependencies**:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
4. **Run database migrations**:
|
||||
```bash
|
||||
npm run db:push
|
||||
```
|
||||
|
||||
5. **Rebuild the application**:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
6. **Restart the service**:
|
||||
```bash
|
||||
# If using systemd
|
||||
sudo systemctl restart dynamodns
|
||||
|
||||
# If using PM2
|
||||
pm2 restart dynamodns
|
||||
```
|
||||
|
||||
### Docker Upgrade Process
|
||||
|
||||
1. **Pull the latest image**:
|
||||
```bash
|
||||
docker-compose pull
|
||||
```
|
||||
|
||||
2. **Restart the containers**:
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
3. **Run migrations**:
|
||||
```bash
|
||||
docker-compose exec app npm run db:push
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Database Connection Errors**:
|
||||
- Check DATABASE_URL environment variable
|
||||
- Verify network connectivity and firewall rules
|
||||
- Ensure PostgreSQL is running
|
||||
|
||||
2. **Authentication Issues**:
|
||||
- Verify SESSION_SECRET is set
|
||||
- Check LDAP/OIDC configuration if using external authentication
|
||||
|
||||
3. **DNS Provider Integration Errors**:
|
||||
- Verify API credentials for the DNS provider
|
||||
- Check for rate limiting or IP restrictions
|
||||
|
||||
### Logs
|
||||
|
||||
Access logs for troubleshooting:
|
||||
|
||||
```bash
|
||||
# Application logs
|
||||
tail -f logs/app.log
|
||||
|
||||
# In Docker
|
||||
docker-compose logs -f app
|
||||
```
|
||||
|
||||
### Getting Support
|
||||
|
||||
If you encounter issues not covered in this documentation:
|
||||
|
||||
1. Check the GitHub repository issues
|
||||
2. Create a new issue with detailed information about your problem
|
||||
3. Contact commercial support if you have a support agreement
|
||||
@@ -0,0 +1,505 @@
|
||||
# DynamoDNS Development Guide
|
||||
|
||||
This guide provides information for developers who want to contribute to the DynamoDNS project or extend its functionality.
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Node.js**: v18.0.0 or higher
|
||||
- **npm**: v8.0.0 or higher
|
||||
- **PostgreSQL**: v14.0 or higher (or Neon serverless database)
|
||||
- **Git**: Latest version
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. **Clone the repository**:
|
||||
```bash
|
||||
git clone https://github.com/yourusername/dynamodns.git
|
||||
cd dynamodns
|
||||
```
|
||||
|
||||
2. **Install dependencies**:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. **Set up environment variables**:
|
||||
Create a `.env` file based on the `.env.example` template:
|
||||
```
|
||||
# Database - Use a local PostgreSQL instance for development
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/dynamodns_dev
|
||||
|
||||
# Server
|
||||
PORT=5000
|
||||
NODE_ENV=development
|
||||
SESSION_SECRET=dev_session_secret
|
||||
|
||||
# Auth - Enable registration for easier testing
|
||||
ENABLE_REGISTRATION=true
|
||||
```
|
||||
|
||||
4. **Set up the database**:
|
||||
```bash
|
||||
# Create the database
|
||||
createdb dynamodns_dev
|
||||
|
||||
# Run migrations
|
||||
npm run db:push
|
||||
```
|
||||
|
||||
5. **Start the development server**:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
6. **Access the application**:
|
||||
Open your browser and navigate to http://localhost:5000
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
dynamodns/
|
||||
├── client/ # Frontend React application
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/ # Reusable UI components
|
||||
│ │ ├── context/ # React context providers
|
||||
│ │ ├── hooks/ # Custom React hooks
|
||||
│ │ ├── lib/ # Utility functions
|
||||
│ │ ├── pages/ # Page components
|
||||
│ │ └── App.tsx # Main application component
|
||||
├── docs/ # Documentation
|
||||
├── migrations/ # Database migration files
|
||||
├── server/ # Backend Express application
|
||||
│ ├── providers/ # DNS provider integrations
|
||||
│ ├── utils/ # Utility functions
|
||||
│ ├── auth.ts # Authentication logic
|
||||
│ ├── db.ts # Database connection
|
||||
│ ├── index.ts # Application entry point
|
||||
│ ├── routes.ts # API routes
|
||||
│ ├── storage.ts # Storage interface
|
||||
│ └── vite.ts # Vite integration
|
||||
├── shared/ # Shared code between client and server
|
||||
│ └── schema.ts # Database schema with Drizzle ORM
|
||||
└── various config files # Configuration files for the project
|
||||
```
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Backend
|
||||
|
||||
- **Express.js**: Web server framework
|
||||
- **Drizzle ORM**: Database ORM for TypeScript
|
||||
- **PostgreSQL**: Relational database
|
||||
- **Passport.js**: Authentication middleware
|
||||
- **WebSockets**: Real-time communication
|
||||
|
||||
### Frontend
|
||||
|
||||
- **React**: UI library
|
||||
- **TanStack Query**: Data fetching and caching
|
||||
- **Shadcn UI**: Component library built on Radix UI
|
||||
- **Tailwind CSS**: Utility-first CSS framework
|
||||
- **Wouter**: Lightweight routing
|
||||
- **Zod**: Schema validation
|
||||
- **React Hook Form**: Form handling
|
||||
|
||||
## Architecture
|
||||
|
||||
### Frontend Architecture
|
||||
|
||||
The frontend follows a component-based architecture with React:
|
||||
|
||||
- **Context Providers**: Manage global state (auth, customer, theme)
|
||||
- **Hooks**: Custom hooks for data fetching and business logic
|
||||
- **Pages**: Top-level components for different routes
|
||||
- **Components**: Reusable UI building blocks
|
||||
|
||||
Data flow utilizes TanStack Query for client-side data fetching and caching:
|
||||
|
||||
```javascript
|
||||
// Example query
|
||||
const { data, isLoading, error } = useQuery({
|
||||
queryKey: ['/api/domains'],
|
||||
enabled: !!user
|
||||
});
|
||||
|
||||
// Example mutation
|
||||
const mutation = useMutation({
|
||||
mutationFn: async (data) => {
|
||||
const res = await apiRequest('POST', '/api/domains', data);
|
||||
return await res.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['/api/domains'] });
|
||||
// Handle success
|
||||
},
|
||||
onError: (error) => {
|
||||
// Handle error
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Backend Architecture
|
||||
|
||||
The backend follows a layered architecture:
|
||||
|
||||
1. **Routes Layer**: API endpoints and request handling
|
||||
2. **Service Layer**: Business logic
|
||||
3. **Data Access Layer**: Database interactions via Drizzle ORM
|
||||
4. **Provider Layer**: Integrations with external DNS services
|
||||
|
||||
The application uses a storage interface pattern to abstract database operations:
|
||||
|
||||
```typescript
|
||||
// Example storage interface method
|
||||
async getUser(id: string): Promise<User | undefined> {
|
||||
const [user] = await db.select().from(users).where(eq(users.id, id));
|
||||
return user || undefined;
|
||||
}
|
||||
```
|
||||
|
||||
## Adding Features
|
||||
|
||||
### Adding a New DNS Provider
|
||||
|
||||
1. **Create a provider module**:
|
||||
Create a new file in `server/providers/` directory (e.g., `cloudflare.ts`).
|
||||
|
||||
2. **Implement the provider interface**:
|
||||
```typescript
|
||||
import { DNSProvider, DNSRecord, DNSProviderError } from './types';
|
||||
|
||||
export class CloudflareProvider implements DNSProvider {
|
||||
constructor(private credentials: any) {
|
||||
// Initialize with provider credentials
|
||||
}
|
||||
|
||||
async createRecord(record: DNSRecord): Promise<string> {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
async updateRecord(recordId: string, record: DNSRecord): Promise<void> {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
async deleteRecord(recordId: string): Promise<void> {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
async getRecord(recordId: string): Promise<DNSRecord> {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Register the provider**:
|
||||
Add the provider to the provider factory in `server/providers/index.ts`.
|
||||
|
||||
### Adding a New API Endpoint
|
||||
|
||||
1. **Create the route handler**:
|
||||
Add your endpoint to `server/routes.ts`:
|
||||
|
||||
```typescript
|
||||
app.get('/api/your-endpoint', (req, res) => {
|
||||
// Implementation
|
||||
});
|
||||
```
|
||||
|
||||
2. **Add validation**:
|
||||
Use Zod to validate request inputs:
|
||||
|
||||
```typescript
|
||||
const schema = z.object({
|
||||
name: z.string().min(1),
|
||||
// Other fields
|
||||
});
|
||||
|
||||
app.post('/api/your-endpoint', (req, res) => {
|
||||
const result = schema.safeParse(req.body);
|
||||
if (!result.success) {
|
||||
return res.status(400).json({ errors: result.error.format() });
|
||||
}
|
||||
|
||||
// Implementation with validated data
|
||||
const data = result.data;
|
||||
});
|
||||
```
|
||||
|
||||
3. **Use the storage interface**:
|
||||
Interact with the database using the storage interface:
|
||||
|
||||
```typescript
|
||||
app.get('/api/your-endpoint/:id', async (req, res) => {
|
||||
try {
|
||||
const item = await storage.getItem(req.params.id);
|
||||
if (!item) {
|
||||
return res.status(404).json({ message: 'Not found' });
|
||||
}
|
||||
res.json(item);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Server error' });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Adding a New UI Component
|
||||
|
||||
1. **Create the component**:
|
||||
Create a new file in the appropriate directory under `client/src/components/`.
|
||||
|
||||
2. **Implement the component**:
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
|
||||
interface MyComponentProps {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function MyComponent({ title, children }: MyComponentProps) {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{children}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
3. **Use the component**:
|
||||
Import and use your component in a page or another component.
|
||||
|
||||
## Database Schema Management
|
||||
|
||||
The project uses Drizzle ORM with a schema defined in `shared/schema.ts`.
|
||||
|
||||
### Adding a New Table
|
||||
|
||||
1. **Define the table**:
|
||||
```typescript
|
||||
export const myNewTable = pgTable('my_new_table', {
|
||||
id: text('id').primaryKey().defaultRandom(),
|
||||
name: text('name').notNull(),
|
||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||
customerId: text('customer_id').references(() => customers.id, { onDelete: 'cascade' }),
|
||||
});
|
||||
```
|
||||
|
||||
2. **Define relations**:
|
||||
```typescript
|
||||
export const myNewTableRelations = relations(myNewTable, ({ one }) => ({
|
||||
customer: one(customers, {
|
||||
fields: [myNewTable.customerId],
|
||||
references: [customers.id],
|
||||
}),
|
||||
}));
|
||||
```
|
||||
|
||||
3. **Create insert schema and types**:
|
||||
```typescript
|
||||
export const insertMyNewTableSchema = createInsertSchema(myNewTable).pick({
|
||||
name: true,
|
||||
customerId: true,
|
||||
});
|
||||
|
||||
export type InsertMyNewTable = z.infer<typeof insertMyNewTableSchema>;
|
||||
export type MyNewTable = typeof myNewTable.$inferSelect;
|
||||
```
|
||||
|
||||
4. **Update the storage interface**:
|
||||
Add methods to `server/storage.ts` for CRUD operations on your new table.
|
||||
|
||||
5. **Push the schema changes**:
|
||||
```bash
|
||||
npm run db:push
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
The project uses Jest for unit testing:
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
npm test
|
||||
|
||||
# Run tests with coverage
|
||||
npm test -- --coverage
|
||||
|
||||
# Run specific test file
|
||||
npm test -- src/path/to/test.test.ts
|
||||
```
|
||||
|
||||
### Writing Tests
|
||||
|
||||
Example test for a utility function:
|
||||
|
||||
```typescript
|
||||
// src/utils/formatDate.test.ts
|
||||
import { formatDate } from './formatDate';
|
||||
|
||||
describe('formatDate', () => {
|
||||
it('formats a date correctly', () => {
|
||||
const date = new Date('2023-01-01T12:00:00Z');
|
||||
expect(formatDate(date)).toBe('Jan 1, 2023');
|
||||
});
|
||||
|
||||
it('handles null values', () => {
|
||||
expect(formatDate(null)).toBe('');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Example test for a React component using React Testing Library:
|
||||
|
||||
```typescript
|
||||
// src/components/Button.test.tsx
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { Button } from './Button';
|
||||
|
||||
describe('Button', () => {
|
||||
it('renders correctly', () => {
|
||||
render(<Button>Click me</Button>);
|
||||
expect(screen.getByText('Click me')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onClick when clicked', () => {
|
||||
const handleClick = jest.fn();
|
||||
render(<Button onClick={handleClick}>Click me</Button>);
|
||||
fireEvent.click(screen.getByText('Click me'));
|
||||
expect(handleClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### API Testing
|
||||
|
||||
For API endpoints, use Supertest:
|
||||
|
||||
```typescript
|
||||
// src/routes/domains.test.ts
|
||||
import request from 'supertest';
|
||||
import { app } from '../app';
|
||||
import { db } from '../db';
|
||||
|
||||
describe('Domains API', () => {
|
||||
beforeEach(async () => {
|
||||
// Set up test data
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Clean up test data
|
||||
});
|
||||
|
||||
it('GET /api/domains returns domains', async () => {
|
||||
const response = await request(app)
|
||||
.get('/api/domains')
|
||||
.set('Authorization', `Bearer ${testToken}`);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Code Style and Linting
|
||||
|
||||
The project uses ESLint and Prettier for code style and linting:
|
||||
|
||||
```bash
|
||||
# Run ESLint
|
||||
npm run lint
|
||||
|
||||
# Fix ESLint issues
|
||||
npm run lint:fix
|
||||
|
||||
# Format code with Prettier
|
||||
npm run format
|
||||
```
|
||||
|
||||
### Commit Guidelines
|
||||
|
||||
We follow the Conventional Commits specification:
|
||||
|
||||
- `feat`: A new feature
|
||||
- `fix`: A bug fix
|
||||
- `docs`: Documentation changes
|
||||
- `style`: Changes that do not affect the meaning of the code
|
||||
- `refactor`: Code changes that neither fix a bug nor add a feature
|
||||
- `perf`: Performance improvements
|
||||
- `test`: Adding or fixing tests
|
||||
- `chore`: Changes to the build process or auxiliary tools
|
||||
|
||||
Example:
|
||||
```
|
||||
feat(dns-records): add support for SRV records
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### Server-side Debugging
|
||||
|
||||
Add logging with debug statements:
|
||||
|
||||
```typescript
|
||||
import debug from 'debug';
|
||||
|
||||
const log = debug('dynamodns:server');
|
||||
|
||||
app.get('/api/domains', (req, res) => {
|
||||
log('Fetching domains for user', req.user?.id);
|
||||
// Implementation
|
||||
});
|
||||
```
|
||||
|
||||
Run the application with debug enabled:
|
||||
|
||||
```bash
|
||||
DEBUG=dynamodns:* npm run dev
|
||||
```
|
||||
|
||||
### Client-side Debugging
|
||||
|
||||
Use React DevTools for component inspection and debugging.
|
||||
|
||||
For network debugging, use the browser's developer tools and the Network tab.
|
||||
|
||||
## Deployment
|
||||
|
||||
See the [Deployment Guide](./deployment-guide.md) for information on deploying the application.
|
||||
|
||||
## Contributing
|
||||
|
||||
1. **Fork the repository**
|
||||
2. **Create a feature branch**:
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
3. **Make your changes**
|
||||
4. **Run tests**:
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
5. **Commit your changes** following the commit guidelines
|
||||
6. **Push to your fork**:
|
||||
```bash
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
7. **Create a Pull Request**
|
||||
|
||||
## Resources
|
||||
|
||||
- **Drizzle ORM Documentation**: [https://orm.drizzle.team/docs/overview](https://orm.drizzle.team/docs/overview)
|
||||
- **React Documentation**: [https://react.dev/](https://react.dev/)
|
||||
- **TanStack Query Documentation**: [https://tanstack.com/query/latest](https://tanstack.com/query/latest)
|
||||
- **Shadcn UI Documentation**: [https://ui.shadcn.com/](https://ui.shadcn.com/)
|
||||
- **Tailwind CSS Documentation**: [https://tailwindcss.com/docs](https://tailwindcss.com/docs)
|
||||
- **Express.js Documentation**: [https://expressjs.com/](https://expressjs.com/)
|
||||
@@ -0,0 +1,237 @@
|
||||
# DynamoDNS User Guide
|
||||
|
||||
This guide provides detailed instructions for using the DynamoDNS platform to manage your DNS records across multiple providers.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Account Setup
|
||||
|
||||
1. **Login**: Access the application using your provided credentials at the login page.
|
||||
2. **First-time Setup**: If this is your first time, you'll be prompted to create a new customer account.
|
||||
3. **Dashboard**: After login, you'll be directed to the main dashboard showing your DNS records and metrics.
|
||||
|
||||
### Navigation
|
||||
|
||||
The main navigation menu includes:
|
||||
|
||||
- **Dashboard**: Overview of your DNS infrastructure
|
||||
- **Domains**: Manage domain registrations
|
||||
- **DNS Records**: Create and manage DNS records
|
||||
- **History**: View historical changes to DNS records
|
||||
- **Metrics**: Analyze performance and usage statistics
|
||||
- **Webhooks**: Configure notification endpoints
|
||||
- **API Tokens**: Manage access tokens for API usage
|
||||
- **Settings**: Configure user and customer settings
|
||||
|
||||
## Managing Customers
|
||||
|
||||
Customers represent organizations that own domains in the system. Each customer can have multiple domains and users.
|
||||
|
||||
### Creating a Customer
|
||||
|
||||
1. Navigate to Settings → Customer tab
|
||||
2. Click "Create New Customer"
|
||||
3. Fill in the required information:
|
||||
- Customer Name (required)
|
||||
- Description (optional)
|
||||
- Contact Information (email, phone)
|
||||
- Address Information
|
||||
- Website and Industry
|
||||
- Notes and Account Manager
|
||||
4. Click "Create Customer"
|
||||
|
||||
### Editing Customer Details
|
||||
|
||||
1. Navigate to Settings → Customer tab
|
||||
2. Update the information as needed
|
||||
3. Click "Save Changes"
|
||||
|
||||
### Switching Between Customers
|
||||
|
||||
Use the customer selector in the top navigation bar to switch between different customers you have access to.
|
||||
|
||||
## Managing Domains
|
||||
|
||||
Domains are the DNS zones that contain your DNS records.
|
||||
|
||||
### Adding a Domain
|
||||
|
||||
1. Navigate to the Domains page
|
||||
2. Click "Add Domain"
|
||||
3. Enter the domain name (e.g., example.com)
|
||||
4. Select the DNS provider (Cloudflare, Route53, GoDaddy, etc.)
|
||||
5. Enter necessary provider credentials (if not already configured)
|
||||
6. Click "Add Domain"
|
||||
|
||||
### Managing Domain Settings
|
||||
|
||||
1. Navigate to the Domains page
|
||||
2. Click on a domain to view its details
|
||||
3. Use the "Edit" button to modify domain settings
|
||||
4. Use the "Delete" button to remove the domain
|
||||
|
||||
## Managing DNS Records
|
||||
|
||||
DNS records define how domain names are mapped to resources on the internet.
|
||||
|
||||
### Adding a DNS Record
|
||||
|
||||
1. Navigate to the DNS Records page
|
||||
2. Filter by domain if needed
|
||||
3. Click "Add Record"
|
||||
4. Select the record type (A, AAAA, CNAME, MX, TXT, etc.)
|
||||
5. Enter the required fields:
|
||||
- Name: The subdomain or @ for the root domain
|
||||
- Content: The value for the record (IP address, hostname, text)
|
||||
- TTL: Time To Live in seconds
|
||||
- Priority: For MX and SRV records
|
||||
6. Optional settings:
|
||||
- Enable "Auto IP" for dynamic DNS functionality
|
||||
- Enable "Proxied" for Cloudflare-specific features
|
||||
- Add notes for documentation
|
||||
7. Click "Create Record"
|
||||
|
||||
### Editing DNS Records
|
||||
|
||||
1. Navigate to the DNS Records page
|
||||
2. Click the "Edit" button for the record you want to modify
|
||||
3. Update the record information
|
||||
4. Click "Save Changes"
|
||||
|
||||
### Dynamic DNS Updates
|
||||
|
||||
For records with "Auto IP" enabled:
|
||||
|
||||
1. The system will automatically track your public IP address
|
||||
2. When changes are detected, DNS records are updated automatically
|
||||
3. The history of changes can be viewed on the History page
|
||||
|
||||
## Viewing History
|
||||
|
||||
The History page provides a complete audit trail of changes to your DNS records.
|
||||
|
||||
1. Navigate to the History page
|
||||
2. Filter by domain, record, or date range
|
||||
3. View details of each change including:
|
||||
- Previous value
|
||||
- New value
|
||||
- Timestamp
|
||||
- User who made the change
|
||||
|
||||
## Analyzing Metrics
|
||||
|
||||
The Metrics page provides insights into DNS performance and usage.
|
||||
|
||||
1. Navigate to the Metrics page
|
||||
2. Select the time period for analysis
|
||||
3. View metrics by:
|
||||
- Domain
|
||||
- Record type
|
||||
- Update frequency
|
||||
- Success/failure rates
|
||||
|
||||
## Configuring Webhooks
|
||||
|
||||
Webhooks allow external applications to receive notifications about DNS changes.
|
||||
|
||||
### Creating a Webhook
|
||||
|
||||
1. Navigate to the Webhooks page
|
||||
2. Click "Add Webhook"
|
||||
3. Configure the webhook:
|
||||
- Name: For identification
|
||||
- URL: The endpoint that will receive webhook data
|
||||
- Secret: Used to verify webhook authenticity
|
||||
- Events: Select which events trigger the webhook
|
||||
4. Click "Create Webhook"
|
||||
|
||||
### Testing Webhooks
|
||||
|
||||
1. Navigate to the Webhooks page
|
||||
2. Select a webhook
|
||||
3. Click "Test Webhook"
|
||||
4. View the delivery status and response
|
||||
|
||||
## Managing API Tokens
|
||||
|
||||
API tokens allow programmatic access to the DynamoDNS API.
|
||||
|
||||
### Creating an API Token
|
||||
|
||||
1. Navigate to the API Tokens page
|
||||
2. Click "Create Token"
|
||||
3. Configure the token:
|
||||
- Name: For identification
|
||||
- Expiration: When the token should expire
|
||||
- Access level: Which customers the token can access
|
||||
- Role: What permissions the token has
|
||||
4. Click "Create Token"
|
||||
5. Save the displayed token securely (it will only be shown once)
|
||||
|
||||
### Revoking API Tokens
|
||||
|
||||
1. Navigate to the API Tokens page
|
||||
2. Click "Revoke" next to the token you want to disable
|
||||
3. Confirm the action
|
||||
|
||||
## User Management
|
||||
|
||||
### Managing Your Account
|
||||
|
||||
1. Navigate to Settings → Account tab
|
||||
2. Update your profile information
|
||||
3. Change your password
|
||||
4. Configure two-factor authentication (if available)
|
||||
|
||||
### Managing Users (Admin Only)
|
||||
|
||||
1. Navigate to Users & Roles page
|
||||
2. View all users in the system
|
||||
3. Create new users by clicking "Add User"
|
||||
4. Edit user details by clicking "Edit"
|
||||
5. Disable users by toggling the "Active" status
|
||||
|
||||
## Role Management
|
||||
|
||||
Roles determine what actions users can perform in the system.
|
||||
|
||||
### System Roles
|
||||
|
||||
- **Admin**: Complete access to all features
|
||||
- **Manager**: Can manage customers, domains, and DNS records
|
||||
- **User**: Can manage assigned domains and DNS records
|
||||
- **ReadOnly**: View-only access to assigned resources
|
||||
|
||||
### Custom Roles (Admin Only)
|
||||
|
||||
1. Navigate to Users & Roles page
|
||||
2. Click on the "Roles" tab
|
||||
3. Click "Create Custom Role"
|
||||
4. Configure permissions for the role
|
||||
5. Assign users to the custom role
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **DNS Propagation Delays**: DNS changes may take time to propagate (up to 48 hours, though typically much faster)
|
||||
2. **Provider API Limitations**: Some DNS providers have rate limits or restrictions
|
||||
3. **Authentication Errors**: Check your credentials for the DNS provider
|
||||
|
||||
### Getting Support
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Check the detailed error message
|
||||
2. Review the documentation
|
||||
3. Contact system administrators for assistance
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Regularly review and clean up unused DNS records
|
||||
- Use descriptive names and notes for records
|
||||
- Set appropriate TTL values based on your needs
|
||||
- Use API tokens with the minimum necessary permissions
|
||||
- Regularly rotate API tokens for security
|
||||
- Configure webhooks for important events to maintain awareness
|
||||
- Review the history log periodically to audit changes
|
||||
Reference in New Issue
Block a user