diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index 97a8bd46..00000000 --- a/.codecov.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Codecov configuration - require 75% overall coverage by default -# Adjust target as needed - -coverage: - status: - project: - default: - target: 75% - threshold: 0% - -# Fail CI if Codecov upload/report indicates a problem -require_ci_to_pass: yes - -# Exclude folders from Codecov -ignore: - - "**/tests/*" - - "**/test/*" - - "**/__tests__/*" - - "**/test_*.go" - - "**/*_test.go" - - "**/*.test.ts" - - "**/*.test.tsx" - - "docs/*" - - ".github/*" - - "scripts/*" - - "tools/*" - - "frontend/node_modules/*" - - "frontend/dist/*" - - "frontend/coverage/*" - - "backend/cmd/seed/*" - - "backend/cmd/api/*" - - "backend/data/*" - - "backend/coverage/*" - - "backend/internal/services/docker_service.go" - - "backend/internal/api/handlers/docker_handler.go" - - "*.md" diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 83d95583..00000000 --- a/.dockerignore +++ /dev/null @@ -1,82 +0,0 @@ -# Version control -.git -.gitignore -.github/ - -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -.venv/ -venv/ -env/ -ENV/ -.pytest_cache/ -.coverage -*.cover -.hypothesis/ -htmlcov/ -*.egg-info/ - -# Node/Frontend build artifacts -frontend/node_modules/ -frontend/coverage/ -frontend/coverage.out -frontend/dist/ -frontend/.vite/ -frontend/*.tsbuildinfo -frontend/frontend/ - -# Go/Backend -backend/coverage.txt -backend/*.out -backend/coverage/ -backend/coverage.*.out -backend/package.json -backend/package-lock.json - -# Databases (runtime) -backend/data/*.db -backend/cmd/api/data/*.db -*.sqlite -*.sqlite3 - -# IDE -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# Logs -.trivy_logs -*.log -logs/ - -# Environment -.env -.env.local -.env.*.local - -# OS -.DS_Store -Thumbs.db - -# Documentation -docs/ -*.md -!README.md - -# Docker -docker-compose*.yml -**/Dockerfile.* - -# CI/CD -.github/ -.pre-commit-config.yaml - -# Scripts -scripts/ -tools/ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 706def22..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,14 +0,0 @@ -# These are supported funding model platforms -github: Wikid82 -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -polar: # Replace with a single Polar username -buy_me_a_coffee: Wikid82 -thanks_dev: # Replace with a single thanks.dev username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/alpha-feature.yml b/.github/ISSUE_TEMPLATE/alpha-feature.yml deleted file mode 100644 index 51d0cc0d..00000000 --- a/.github/ISSUE_TEMPLATE/alpha-feature.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: 🏗️ Alpha Feature -description: Create an issue for an Alpha milestone feature -title: "[ALPHA] " -labels: ["alpha", "feature"] -body: - - type: markdown - attributes: - value: | - ## Alpha Milestone Feature - Features that are part of the core foundation and initial release. - - - type: dropdown - id: priority - attributes: - label: Priority - description: How critical is this feature? - options: - - Critical (Blocking, must-have) - - High (Important, should have) - - Medium (Nice to have) - - Low (Future enhancement) - validations: - required: true - - - type: input - id: issue_number - attributes: - label: Planning Issue Number - description: Reference number from PROJECT_PLANNING.md (e.g., Issue #5) - placeholder: "Issue #" - validations: - required: false - - - type: textarea - id: description - attributes: - label: Feature Description - description: What should this feature do? - placeholder: Describe the feature in detail - validations: - required: true - - - type: textarea - id: tasks - attributes: - label: Implementation Tasks - description: List of tasks to complete this feature - placeholder: | - - [ ] Task 1 - - [ ] Task 2 - - [ ] Task 3 - value: | - - [ ] - validations: - required: true - - - type: textarea - id: acceptance - attributes: - label: Acceptance Criteria - description: How do we know this feature is complete? - placeholder: | - - [ ] Criteria 1 - - [ ] Criteria 2 - value: | - - [ ] - validations: - required: true - - - type: checkboxes - id: categories - attributes: - label: Categories - description: Select all that apply - options: - - label: Backend - - label: Frontend - - label: Database - - label: Caddy Integration - - label: Security - - label: SSL/TLS - - label: UI/UX - - label: Deployment - - label: Documentation - - - type: textarea - id: technical_notes - attributes: - label: Technical Notes - description: Any technical considerations or dependencies? - placeholder: Libraries, APIs, or other issues that need to be completed first - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/beta-monitoring-feature.yml b/.github/ISSUE_TEMPLATE/beta-monitoring-feature.yml deleted file mode 100644 index b1965956..00000000 --- a/.github/ISSUE_TEMPLATE/beta-monitoring-feature.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: 📊 Beta Monitoring Feature -description: Create an issue for a Beta milestone monitoring/logging feature -title: "[BETA] [MONITORING] " -labels: ["beta", "feature", "monitoring"] -body: - - type: markdown - attributes: - value: | - ## Beta Monitoring & Logging Feature - Features related to observability, logging, and system monitoring. - - - type: dropdown - id: priority - attributes: - label: Priority - description: How critical is this monitoring feature? - options: - - Critical (Essential for operations) - - High (Important visibility) - - Medium (Enhanced monitoring) - - Low (Nice-to-have metrics) - validations: - required: true - - - type: dropdown - id: monitoring_type - attributes: - label: Monitoring Type - description: What aspect of monitoring? - options: - - Dashboards & Statistics - - Log Viewing & Search - - Alerting & Notifications - - CrowdSec Dashboard - - Analytics Integration - - Health Checks - - Performance Metrics - validations: - required: true - - - type: input - id: issue_number - attributes: - label: Planning Issue Number - description: Reference number from PROJECT_PLANNING.md (e.g., Issue #23) - placeholder: "Issue #" - validations: - required: false - - - type: textarea - id: description - attributes: - label: Feature Description - description: What monitoring/logging capability should this provide? - placeholder: Describe what users will be able to see or do - validations: - required: true - - - type: textarea - id: metrics - attributes: - label: Metrics & Data Points - description: What data will be collected and displayed? - placeholder: | - - Metric 1: Description - - Metric 2: Description - validations: - required: false - - - type: textarea - id: tasks - attributes: - label: Implementation Tasks - description: List of tasks to complete this feature - placeholder: | - - [ ] Task 1 - - [ ] Task 2 - - [ ] Task 3 - value: | - - [ ] - validations: - required: true - - - type: textarea - id: acceptance - attributes: - label: Acceptance Criteria - description: How do we verify this monitoring feature works? - placeholder: | - - [ ] Data displays correctly - - [ ] Updates in real-time - - [ ] Performance is acceptable - value: | - - [ ] - validations: - required: true - - - type: checkboxes - id: categories - attributes: - label: Implementation Areas - description: Select all that apply - options: - - label: Backend (Data collection) - - label: Frontend (UI/Charts) - - label: Database (Storage) - - label: Real-time Updates (WebSocket) - - label: External Integration (GoAccess, CrowdSec) - - label: Documentation Required - - - type: textarea - id: ui_design - attributes: - label: UI/UX Considerations - description: Describe the user interface requirements - placeholder: Layout, charts, filters, export options, etc. - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/beta-security-feature.yml b/.github/ISSUE_TEMPLATE/beta-security-feature.yml deleted file mode 100644 index d28c9d0d..00000000 --- a/.github/ISSUE_TEMPLATE/beta-security-feature.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: 🔐 Beta Security Feature -description: Create an issue for a Beta milestone security feature -title: "[BETA] [SECURITY] " -labels: ["beta", "feature", "security"] -body: - - type: markdown - attributes: - value: | - ## Beta Security Feature - Advanced security features for the beta release. - - - type: dropdown - id: priority - attributes: - label: Priority - description: How critical is this security feature? - options: - - Critical (Essential security control) - - High (Important protection) - - Medium (Additional hardening) - - Low (Nice-to-have security enhancement) - validations: - required: true - - - type: dropdown - id: security_category - attributes: - label: Security Category - description: What type of security feature is this? - options: - - Authentication & Access Control - - Threat Protection - - SSL/TLS Management - - Monitoring & Logging - - Web Application Firewall - - Rate Limiting - - IP Access Control - validations: - required: true - - - type: input - id: issue_number - attributes: - label: Planning Issue Number - description: Reference number from PROJECT_PLANNING.md (e.g., Issue #15) - placeholder: "Issue #" - validations: - required: false - - - type: textarea - id: description - attributes: - label: Feature Description - description: What security capability should this provide? - placeholder: Describe the security feature and its purpose - validations: - required: true - - - type: textarea - id: threat_model - attributes: - label: Threat Model - description: What threats does this feature mitigate? - placeholder: | - - Threat 1: Description and severity - - Threat 2: Description and severity - validations: - required: false - - - type: textarea - id: tasks - attributes: - label: Implementation Tasks - description: List of tasks to complete this feature - placeholder: | - - [ ] Task 1 - - [ ] Task 2 - - [ ] Task 3 - value: | - - [ ] - validations: - required: true - - - type: textarea - id: acceptance - attributes: - label: Acceptance Criteria - description: How do we verify this security control works? - placeholder: | - - [ ] Security test 1 - - [ ] Security test 2 - value: | - - [ ] - validations: - required: true - - - type: checkboxes - id: special_labels - attributes: - label: Special Categories - description: Select all that apply - options: - - label: SSO (Single Sign-On) - - label: WAF (Web Application Firewall) - - label: CrowdSec Integration - - label: Plus Feature (Premium) - - label: Requires Documentation - - - type: textarea - id: security_testing - attributes: - label: Security Testing Plan - description: How will you test this security feature? - placeholder: Describe testing approach, tools, and scenarios - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index dd84ea78..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7d..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/general-feature.yml b/.github/ISSUE_TEMPLATE/general-feature.yml deleted file mode 100644 index 497d7735..00000000 --- a/.github/ISSUE_TEMPLATE/general-feature.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: ⚙️ General Feature -description: Create a feature request for any milestone -title: "[FEATURE] " -labels: ["feature"] -body: - - type: markdown - attributes: - value: | - ## Feature Request - Request a new feature or enhancement for CaddyProxyManager+ - - - type: dropdown - id: milestone - attributes: - label: Target Milestone - description: Which release should this be part of? - options: - - Alpha (Core foundation) - - Beta (Advanced features) - - Post-Beta (Future enhancements) - - Unsure (Help me decide) - validations: - required: true - - - type: dropdown - id: priority - attributes: - label: Priority - description: How important is this feature? - options: - - Critical - - High - - Medium - - Low - validations: - required: true - - - type: textarea - id: problem - attributes: - label: Problem Statement - description: What problem does this feature solve? - placeholder: Describe the use case or pain point - validations: - required: true - - - type: textarea - id: solution - attributes: - label: Proposed Solution - description: How should this feature work? - placeholder: Describe your ideal implementation - validations: - required: true - - - type: textarea - id: alternatives - attributes: - label: Alternatives Considered - description: What other approaches could solve this? - placeholder: List alternative solutions you've thought about - validations: - required: false - - - type: textarea - id: user_story - attributes: - label: User Story - description: Describe this from a user's perspective - placeholder: "As a [user type], I want to [action] so that [benefit]" - validations: - required: false - - - type: checkboxes - id: categories - attributes: - label: Feature Categories - description: Select all that apply - options: - - label: Authentication/Authorization - - label: Security - - label: SSL/TLS - - label: Monitoring/Logging - - label: UI/UX - - label: Performance - - label: Documentation - - label: API - - label: Plus Feature (Premium) - - - type: textarea - id: additional - attributes: - label: Additional Context - description: Any other information, screenshots, or examples? - placeholder: Add links, mockups, or references - validations: - required: false diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 9a11e9ff..00000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,43 +0,0 @@ -# CaddyProxyManager+ Copilot Instructions - -## 🚨 CRITICAL ARCHITECTURE RULES 🚨 -- **Single Frontend Source**: All frontend code MUST reside in `frontend/`. NEVER create `backend/frontend/` or any other nested frontend directory. -- **Single Backend Source**: All backend code MUST reside in `backend/`. -- **No Python**: This is a Go (Backend) + React/TypeScript (Frontend) project. Do not introduce Python scripts or requirements. - -## Big Picture -- `backend/cmd/api` loads config, opens SQLite, then hands off to `internal/server` where routes from `internal/api/routes` are registered. -- `internal/config` respects `CPM_ENV`, `CPM_HTTP_PORT`, `CPM_DB_PATH`, `CPM_FRONTEND_DIR` and creates the `data/` directory; lean on these instead of hard-coded paths. -- All HTTP endpoints live under `/api/v1/*`; keep new handlers inside `internal/api/handlers` and register them via `routes.Register` so `db.AutoMigrate` runs for their models. -- `internal/server` also mounts the built React app (via `attachFrontend`) whenever `frontend/dist` exists, falling back to JSON `{"error": ...}` for any `/api/*` misses. -- Persistent types live in `internal/models`; GORM auto-migrates them each boot, so evolve schemas there before touching handlers or the frontend. - -## Backend Workflow -- Run locally with `cd backend && go run ./cmd/api`; run tests with `go test ./...` (see `proxy_host_handler_test.go` for the in-memory SQLite/Gin harness pattern). -- Handlers return structured errors using `gin.H{"error": "message"}` and standard HTTP codes—mirror the `ProxyHostHandler` lifecycle for new CRUD endpoints. -- UUIDs (`github.com/google/uuid`) are generated server-side and exposed as `uuid` fields; clients never send numeric IDs. -- Query lists sorted by `updated_at desc` (see `.Order("updated_at desc")` in `List`); match that ordering for user-visible collections. -- Long-running work must respect the graceful shutdown flow in `server.Run(ctx)`—avoid background goroutines that ignore the context. - -## Frontend Workflow -- **Location**: Always work within `frontend/`. -- **Stack**: React 18 + Vite + TypeScript + TanStack Query (React Query). -- **State Management**: Use `src/hooks/use*.ts` wrapping React Query. Do not use raw `useEffect` for data fetching. -- **API Layer**: Create typed API clients in `src/api/*.ts` that wrap `client.ts`. -- **Development**: Run `cd frontend && npm run dev`. Vite proxies `/api` to `http://localhost:8080`. -- **Components**: Screens live in `src/pages`. Reusable UI in `src/components`. -- **Forms**: Use local `useState` for form fields, submit via `useMutation` from custom hooks, then `invalidateQueries` on success. - -## Cross-Cutting Notes -- Run the backend before the frontend; React Query expects the exact JSON produced by GORM tags (snake_case), so keep API and UI field names aligned. -- When adding models, update both `internal/models` and the `AutoMigrate` call inside `internal/api/routes/routes.go`; register new Gin routes right after migrations for clarity. -- Tests belong beside handlers (`*_test.go`); reuse the `setupTestRouter` helper structure (in-memory SQLite, Gin router, httptest requests) for fast feedback. -- **Testing Requirement**: All new code (features, bug fixes, refactors) MUST include accompanying unit tests. Ensure tests cover happy paths and error conditions. -- **Ignore Files**: When creating new file types, directories, or build artifacts, ALWAYS check and update `.gitignore`, `.dockerignore`, and `.codecov.yml` to ensure they are properly excluded or included as required. -- The root `Dockerfile` builds the Go binary and the React static assets (multi-stage build). -- Branch from `feature/**` and target `development`. - -## CI/CD & Commit Conventions -- **Docker Builds**: The `docker-publish` workflow skips builds for commits starting with `chore:`. -- **Triggering Builds**: To ensure a new Docker image is built (e.g., for testing on VPS), use `feat:`, `fix:`, or `perf:` prefixes. -- **Beta Branch**: The `feature/beta-release` branch is configured to ALWAYS build, overriding the skip logic. diff --git a/.github/renovate.json b/.github/renovate.json deleted file mode 100644 index 8302d397..00000000 --- a/.github/renovate.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended", - ":semanticCommits", - ":separateMultipleMajorReleases", - "helpers:pinGitHubActionDigests" - ], - "baseBranches": ["development"], - "timezone": "UTC", - "dependencyDashboard": true, - "prConcurrentLimit": 10, - "prHourlyLimit": 5, - "labels": ["dependencies"], - "rebaseWhen": "conflicted", - "vulnerabilityAlerts": { "enabled": true }, - "schedule": ["every weekday"], - "rangeStrategy": "bump", - "packageRules": [ - { - "description": "Automerge safe patch updates", - "matchUpdateTypes": ["patch"], - "automerge": true - }, - { - "description": "Frontend npm: automerge minor for devDependencies", - "matchManagers": ["npm"], - "matchDepTypes": ["devDependencies"], - "matchUpdateTypes": ["minor", "patch"], - "automerge": true, - "labels": ["dependencies", "npm"] - }, - { - "description": "Backend Go modules", - "matchManagers": ["gomod"], - "labels": ["dependencies", "go"], - "matchUpdateTypes": ["minor", "patch"], - "automerge": false - }, - { - "description": "GitHub Actions updates", - "matchManagers": ["github-actions"], - "labels": ["dependencies", "github-actions"], - "matchUpdateTypes": ["minor", "patch"], - "automerge": true - }, - { - "description": "Docker: keep Caddy within v2 (no automatic jump to v3)", - "matchManagers": ["dockerfile"], - "matchPackageNames": ["caddy"], - "allowedVersions": "<3.0.0", - "labels": ["dependencies", "docker"], - "automerge": true - }, - { - "description": "Group non-breaking npm minor/patch", - "matchManagers": ["npm"], - "matchUpdateTypes": ["minor", "patch"], - "groupName": "npm minor/patch", - "prPriority": -1 - }, - { - "description": "Group docker base minor/patch", - "matchManagers": ["dockerfile"], - "matchUpdateTypes": ["minor", "patch"], - "groupName": "docker base updates", - "prPriority": -1 - } - ] -} diff --git a/.github/workflows/auto-add-to-project.yml b/.github/workflows/auto-add-to-project.yml deleted file mode 100644 index 78804bb8..00000000 --- a/.github/workflows/auto-add-to-project.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Auto-add issues and PRs to Project - -on: - issues: - types: [opened, reopened] - pull_request: - types: [opened, reopened] - -jobs: - add-to-project: - runs-on: ubuntu-latest - steps: - - name: Determine project URL presence - id: project_check - run: | - if [ -n "${{ secrets.PROJECT_URL }}" ]; then - echo "has_project=true" >> $GITHUB_OUTPUT - else - echo "has_project=false" >> $GITHUB_OUTPUT - fi - - - name: Add issue or PR to project - if: steps.project_check.outputs.has_project == 'true' - uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2 - continue-on-error: true - with: - project-url: ${{ secrets.PROJECT_URL }} - github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} - - - name: Skip summary - if: steps.project_check.outputs.has_project == 'false' - run: echo "PROJECT_URL secret missing; skipping project assignment." >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/auto-label-issues.yml b/.github/workflows/auto-label-issues.yml deleted file mode 100644 index cdbafdbd..00000000 --- a/.github/workflows/auto-label-issues.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Auto-label Issues - -on: - issues: - types: [opened, edited] - -jobs: - auto-label: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Auto-label based on title and body - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const issue = context.payload.issue; - const title = issue.title.toLowerCase(); - const body = issue.body ? issue.body.toLowerCase() : ''; - const labels = []; - - // Priority detection - if (title.includes('[critical]') || body.includes('priority: critical')) { - labels.push('critical'); - } else if (title.includes('[high]') || body.includes('priority: high')) { - labels.push('high'); - } else if (title.includes('[medium]') || body.includes('priority: medium')) { - labels.push('medium'); - } else if (title.includes('[low]') || body.includes('priority: low')) { - labels.push('low'); - } - - // Milestone detection - if (title.includes('[alpha]') || body.includes('milestone: alpha')) { - labels.push('alpha'); - } else if (title.includes('[beta]') || body.includes('milestone: beta')) { - labels.push('beta'); - } else if (title.includes('[post-beta]') || body.includes('milestone: post-beta')) { - labels.push('post-beta'); - } - - // Category detection - if (title.includes('architecture') || body.includes('architecture')) labels.push('architecture'); - if (title.includes('backend') || body.includes('backend')) labels.push('backend'); - if (title.includes('frontend') || body.includes('frontend')) labels.push('frontend'); - if (title.includes('security') || body.includes('security')) labels.push('security'); - if (title.includes('ssl') || title.includes('tls') || body.includes('certificate')) labels.push('ssl'); - if (title.includes('sso') || body.includes('single sign-on')) labels.push('sso'); - if (title.includes('waf') || body.includes('web application firewall')) labels.push('waf'); - if (title.includes('crowdsec') || body.includes('crowdsec')) labels.push('crowdsec'); - if (title.includes('caddy') || body.includes('caddy')) labels.push('caddy'); - if (title.includes('database') || body.includes('database')) labels.push('database'); - if (title.includes('ui') || title.includes('interface')) labels.push('ui'); - if (title.includes('docker') || title.includes('deployment')) labels.push('deployment'); - if (title.includes('monitoring') || title.includes('logging')) labels.push('monitoring'); - if (title.includes('documentation') || title.includes('docs')) labels.push('documentation'); - if (title.includes('test') || body.includes('testing')) labels.push('testing'); - if (title.includes('performance') || body.includes('optimization')) labels.push('performance'); - if (title.includes('plus') || body.includes('premium feature')) labels.push('plus'); - - // Feature detection - if (title.includes('feature') || body.includes('feature request')) labels.push('feature'); - - // Only add labels if we detected any - if (labels.length > 0) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - labels: labels - }); - - console.log(`Added labels: ${labels.join(', ')}`); - } diff --git a/.github/workflows/caddy-major-monitor.yml b/.github/workflows/caddy-major-monitor.yml deleted file mode 100644 index 74a1921b..00000000 --- a/.github/workflows/caddy-major-monitor.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Monitor Caddy Major Release - -on: - schedule: - - cron: '17 7 * * 1' # Mondays at 07:17 UTC - workflow_dispatch: {} - -permissions: - contents: read - issues: write - -jobs: - check-caddy-major: - runs-on: ubuntu-latest - steps: - - name: Check for Caddy v3 and open issue - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const upstream = { owner: 'caddyserver', repo: 'caddy' }; - const { data: releases } = await github.rest.repos.listReleases({ - ...upstream, - per_page: 50, - }); - const latestV3 = releases.find(r => /^v3\./.test(r.tag_name)); - if (!latestV3) { - core.info('No Caddy v3 release detected.'); - return; - } - - const issueTitle = `Track upgrade to Caddy v3 (${latestV3.tag_name})`; - - const { data: existing } = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - per_page: 100, - }); - - if (existing.some(i => i.title === issueTitle)) { - core.info('Issue already exists — nothing to do.'); - return; - } - - const body = [ - 'Caddy v3 has been released upstream and detected by the scheduled monitor.', - '', - `Detected release: ${latestV3.tag_name} (${latestV3.html_url})`, - '', - '- Create a feature branch to evaluate the v3 migration.', - '- Review breaking changes and update Docker base images/workflows.', - '- Validate Trivy scans and update any policies as needed.', - '', - 'Current policy: remain on latest 2.x until v3 is validated.' - ].join('\n'); - - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: issueTitle, - body, - }); diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index d17a521a..00000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: CodeQL - Analyze - -on: - push: - branches: [ main, development, 'feature/**' ] - pull_request: - branches: [ main, development ] - schedule: - - cron: '0 3 * * 1' - -permissions: - contents: read - security-events: write - actions: read - pull-requests: read - -jobs: - analyze: - name: CodeQL analysis (${{ matrix.language }}) - runs-on: ubuntu-latest - # Skip forked PRs where CPMP_TOKEN lacks security-events permissions - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false - permissions: - contents: read - security-events: write - actions: read - pull-requests: read - strategy: - fail-fast: false - matrix: - language: [ 'go', 'javascript-typescript' ] - steps: - - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4 - with: - languages: ${{ matrix.language }} - - - name: Autobuild - uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4 - with: - category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/create-labels.yml b/.github/workflows/create-labels.yml deleted file mode 100644 index 21670aac..00000000 --- a/.github/workflows/create-labels.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Create Project Labels - -# This workflow only runs manually to set up labels -on: - workflow_dispatch: - -jobs: - create-labels: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Create all project labels - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const labels = [ - // Priority labels - { name: 'critical', color: 'B60205', description: 'Must have for the release, blocks other work' }, - { name: 'high', color: 'D93F0B', description: 'Important feature, should be included' }, - { name: 'medium', color: 'FBCA04', description: 'Nice to have, can be deferred' }, - { name: 'low', color: '0E8A16', description: 'Future enhancement, not urgent' }, - - // Milestone labels - { name: 'alpha', color: '5319E7', description: 'Part of initial alpha release' }, - { name: 'beta', color: '0052CC', description: 'Part of beta release' }, - { name: 'post-beta', color: '006B75', description: 'Post-beta enhancement' }, - - // Category labels - { name: 'architecture', color: 'C5DEF5', description: 'System design and structure' }, - { name: 'backend', color: '1D76DB', description: 'Server-side code' }, - { name: 'frontend', color: '5EBEFF', description: 'UI/UX code' }, - { name: 'feature', color: 'A2EEEF', description: 'New functionality' }, - { name: 'security', color: 'EE0701', description: 'Security-related' }, - { name: 'ssl', color: 'F9D0C4', description: 'SSL/TLS certificates' }, - { name: 'sso', color: 'D4C5F9', description: 'Single Sign-On' }, - { name: 'waf', color: 'B60205', description: 'Web Application Firewall' }, - { name: 'crowdsec', color: 'FF6B6B', description: 'CrowdSec integration' }, - { name: 'caddy', color: '1F6FEB', description: 'Caddy-specific' }, - { name: 'database', color: '006B75', description: 'Database-related' }, - { name: 'ui', color: '7057FF', description: 'User interface' }, - { name: 'deployment', color: '0E8A16', description: 'Docker, installation' }, - { name: 'monitoring', color: 'FEF2C0', description: 'Logging and statistics' }, - { name: 'documentation', color: '0075CA', description: 'Docs and guides' }, - { name: 'testing', color: 'BFD4F2', description: 'Test suite' }, - { name: 'performance', color: 'EDEDED', description: 'Optimization' }, - { name: 'community', color: 'D876E3', description: 'Community building' }, - { name: 'plus', color: 'FFD700', description: 'Premium/"Plus" feature' }, - { name: 'enterprise', color: '8B4513', description: 'Enterprise-grade feature' } - ]; - - for (const label of labels) { - try { - await github.rest.issues.createLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label.name, - color: label.color, - description: label.description - }); - console.log(`✓ Created label: ${label.name}`); - } catch (error) { - if (error.status === 422) { - console.log(`⚠ Label already exists: ${label.name}`); - // Update the label if it exists - await github.rest.issues.updateLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label.name, - color: label.color, - description: label.description - }); - console.log(`✓ Updated label: ${label.name}`); - } else { - console.error(`✗ Error creating label ${label.name}:`, error.message); - } - } - } diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml deleted file mode 100644 index a10b7079..00000000 --- a/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,252 +0,0 @@ -name: Docker Build, Publish & Test - -on: - push: - branches: - - main - - development - - feature/beta-release - tags: - - 'v*.*.*' - pull_request: - branches: - - main - - development - - feature/beta-release - workflow_dispatch: - workflow_call: - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository_owner }}/cpmp - -jobs: - build-and-push: - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - contents: read - packages: write - security-events: write - - outputs: - skip_build: ${{ steps.skip.outputs.skip_build }} - digest: ${{ steps.build-and-push.outputs.digest }} - - steps: - - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - - name: Normalize image name - run: | - echo "IMAGE_NAME=$(echo "${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - - - name: Determine skip condition - id: skip - env: - ACTOR: ${{ github.actor }} - EVENT: ${{ github.event_name }} - HEAD_MSG: ${{ github.event.head_commit.message }} - REF: ${{ github.ref }} - run: | - should_skip=false - pr_title="" - if [ "$EVENT" = "pull_request" ]; then - pr_title=$(jq -r '.pull_request.title' "$GITHUB_EVENT_PATH" 2>/dev/null || echo '') - fi - if [ "$ACTOR" = "renovate[bot]" ]; then should_skip=true; fi - if echo "$HEAD_MSG" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi - if echo "$HEAD_MSG" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi - if echo "$pr_title" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi - if echo "$pr_title" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi - - # Always build on beta-release branch to ensure artifacts for testing - if [[ "$REF" == "refs/heads/feature/beta-release" ]]; then - should_skip=false - echo "Force building on beta-release branch" - fi - - echo "skip_build=$should_skip" >> $GITHUB_OUTPUT - - - name: Set up QEMU - if: steps.skip.outputs.skip_build != 'true' - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - - - name: Set up Docker Buildx - if: steps.skip.outputs.skip_build != 'true' - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - - - name: Resolve Caddy base digest - if: steps.skip.outputs.skip_build != 'true' - id: caddy - run: | - docker pull caddy:2-alpine - DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' caddy:2-alpine) - echo "image=$DIGEST" >> $GITHUB_OUTPUT - - - name: Log in to Container Registry - if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.CPMP_TOKEN }} - - - name: Extract metadata (tags, labels) - if: steps.skip.outputs.skip_build != 'true' - id: meta - uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=raw,value=dev,enable=${{ github.ref == 'refs/heads/development' }} - type=raw,value=beta,enable=${{ github.ref == 'refs/heads/feature/beta-release' }} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=raw,value=pr-${{ github.ref_name }},enable=${{ github.event_name == 'pull_request' }} - type=sha,format=short,enable=${{ github.event_name != 'pull_request' }} - - - name: Build and push Docker image - if: steps.skip.outputs.skip_build != 'true' - id: build-and-push - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 - with: - context: . - platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }} - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ steps.meta.outputs.version }} - BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - VCS_REF=${{ github.sha }} - CADDY_IMAGE=${{ steps.caddy.outputs.image }} - - - name: Run Trivy scan (table output) - if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' - uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1 - with: - image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }} - format: 'table' - severity: 'CRITICAL,HIGH' - exit-code: '0' - continue-on-error: true - - - name: Run Trivy vulnerability scanner (SARIF) - if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' - id: trivy - uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1 - with: - image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }} - format: 'sarif' - output: 'trivy-results.sarif' - severity: 'CRITICAL,HIGH' - continue-on-error: true - - - name: Check Trivy SARIF exists - if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' - id: trivy-check - run: | - if [ -f trivy-results.sarif ]; then - echo "exists=true" >> $GITHUB_OUTPUT - else - echo "exists=false" >> $GITHUB_OUTPUT - fi - - - name: Upload Trivy results - if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.trivy-check.outputs.exists == 'true' - uses: github/codeql-action/upload-sarif@d3ced5c96c16c4332e2a61eb6f3649d6f1b20bb8 # v3.31.5 - with: - sarif_file: 'trivy-results.sarif' - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Create summary - if: steps.skip.outputs.skip_build != 'true' - run: | - echo "## 🎉 Docker Image Built Successfully!" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### 📦 Image Details" >> $GITHUB_STEP_SUMMARY - echo "- **Registry**: GitHub Container Registry (ghcr.io)" >> $GITHUB_STEP_SUMMARY - echo "- **Repository**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY - echo "- **Tags**: " >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - - test-image: - name: Test Docker Image - needs: build-and-push - runs-on: ubuntu-latest - if: needs.build-and-push.outputs.skip_build != 'true' && github.event_name != 'pull_request' - - steps: - - name: Normalize image name - run: | - raw="${{ github.repository_owner }}/${{ github.event.repository.name }}" - echo "IMAGE_NAME=$(echo "$raw" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - - - name: Determine image tag - id: tag - run: | - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "tag=latest" >> $GITHUB_OUTPUT - elif [[ "${{ github.ref }}" == "refs/heads/development" ]]; then - echo "tag=dev" >> $GITHUB_OUTPUT - elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then - echo "tag=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT - else - echo "tag=sha-$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT - fi - - - name: Log in to GitHub Container Registry - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.CPMP_TOKEN }} - - - name: Pull Docker image - run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }} - - - name: Run container - run: | - docker run -d \ - --name test-container \ - -p 8080:8080 \ - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }} - - - name: Test health endpoint (retries) - run: | - set +e - for i in $(seq 1 30); do - code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/api/v1/health || echo "000") - if [ "$code" = "200" ]; then - echo "✅ Health check passed on attempt $i" - exit 0 - fi - echo "Attempt $i/30: health not ready (code=$code); waiting..." - sleep 2 - done - echo "❌ Health check failed after retries" - docker logs test-container || true - exit 1 - - - name: Check container logs - if: always() - run: docker logs test-container - - - name: Stop container - if: always() - run: docker stop test-container && docker rm test-container - - - name: Create test summary - if: always() - run: | - echo "## 🧪 Docker Image Test Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- **Image**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY - echo "- **Health Check**: ${{ job.status == 'success' && '✅ Passed' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index c37e3a18..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,353 +0,0 @@ -name: Deploy Documentation to GitHub Pages - -on: - push: - branches: - - main # Deploy docs when pushing to main - paths: - - 'docs/**' # Only run if docs folder changes - - 'README.md' # Or if README changes - - '.github/workflows/docs.yml' # Or if this workflow changes - workflow_dispatch: # Allow manual trigger - -# Sets permissions to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - build: - name: Build Documentation - runs-on: ubuntu-latest - - steps: - # Step 1: Get the code - - name: 📥 Checkout code - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 - - # Step 2: Set up Node.js (for building any JS-based doc tools) - - name: 🔧 Set up Node.js - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 - with: - node-version: '24.11.1' - - # Step 3: Create a beautiful docs site structure - - name: 📝 Build documentation site - run: | - # Create output directory - mkdir -p _site - - # Copy all markdown files - cp README.md _site/ - cp -r docs _site/ - - # Create a simple HTML index that looks nice - cat > _site/index.html << 'EOF' - - - - - - Caddy Proxy Manager Plus - Documentation - - - - -
-

🚀 Caddy Proxy Manager Plus

-

Make your websites easy to reach - No coding required!

-
- -
-
-

👋 Welcome!

-

- This documentation will help you get started with Caddy Proxy Manager Plus. - Whether you're a complete beginner or an experienced developer, we've got you covered! -

-
- -

📚 Getting Started

-
-
-

🏠 Getting Started Guide Start Here

-

Your first setup in just 5 minutes! We'll walk you through everything step by step.

- Read the Guide → -
- -
-

📖 README Essential

-

Learn what the app does, how to install it, and see examples of what you can build.

- Read More → -
- -
-

📥 Import Guide

-

Already using Caddy? Learn how to bring your existing configuration into the app.

- Import Your Configs → -
-
- -

🔧 Developer Documentation

-
-
-

🔌 API Reference Advanced

-

Complete REST API documentation with examples in JavaScript and Python.

- View API Docs → -
- -
-

💾 Database Schema Advanced

-

Understand how data is stored, relationships, and backup strategies.

- View Schema → -
- -
-

✨ Contributing Guide

-

Want to help make this better? Learn how to contribute code, docs, or ideas.

- Start Contributing → -
-
- -

📋 All Documentation

-
-

📚 Documentation Index

-

Browse all available documentation organized by topic and skill level.

- View Full Index → -
- -

🆘 Need Help?

-
-

Get Support

-

- Stuck? Have questions? We're here to help! -

-
- - 💬 Ask a Question - - - 🐛 Report a Bug - - - ⭐ View on GitHub - -
-
-
- - - - - EOF - - # Convert markdown files to HTML using a simple converter - npm install -g marked - - # Convert each markdown file - for file in _site/docs/*.md; do - if [ -f "$file" ]; then - filename=$(basename "$file" .md) - marked "$file" -o "_site/docs/${filename}.html" --gfm - fi - done - - # Convert README and CONTRIBUTING - marked _site/README.md -o _site/README.html --gfm - if [ -f "CONTRIBUTING.md" ]; then - cp CONTRIBUTING.md _site/ - marked _site/CONTRIBUTING.md -o _site/CONTRIBUTING.html --gfm - fi - - # Add simple styling to all HTML files - for html_file in _site/*.html _site/docs/*.html; do - if [ -f "$html_file" ] && [ "$html_file" != "_site/index.html" ]; then - # Add a header with navigation to each page - temp_file="${html_file}.tmp" - cat > "$temp_file" << 'HEADER' - - - - - - Caddy Proxy Manager Plus - Documentation - - - - - -
- HEADER - - # Append original content - cat "$html_file" >> "$temp_file" - - # Add footer - cat >> "$temp_file" << 'FOOTER' -
- - - - FOOTER - - mv "$temp_file" "$html_file" - fi - done - - echo "✅ Documentation site built successfully!" - - # Step 4: Upload the built site - - name: 📤 Upload artifact - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 - with: - path: '_site' - - deploy: - name: Deploy to GitHub Pages - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - - steps: - # Deploy to GitHub Pages - - name: 🚀 Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 - - # Create a summary - - name: 📋 Create deployment summary - run: | - echo "## 🎉 Documentation Deployed!" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Your documentation is now live at:" >> $GITHUB_STEP_SUMMARY - echo "🔗 ${{ steps.deployment.outputs.page_url }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### 📚 What's Included" >> $GITHUB_STEP_SUMMARY - echo "- Getting Started Guide" >> $GITHUB_STEP_SUMMARY - echo "- Complete README" >> $GITHUB_STEP_SUMMARY - echo "- API Documentation" >> $GITHUB_STEP_SUMMARY - echo "- Database Schema" >> $GITHUB_STEP_SUMMARY - echo "- Import Guide" >> $GITHUB_STEP_SUMMARY - echo "- Contributing Guidelines" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/propagate-changes.yml b/.github/workflows/propagate-changes.yml deleted file mode 100644 index d7238ba8..00000000 --- a/.github/workflows/propagate-changes.yml +++ /dev/null @@ -1,106 +0,0 @@ -name: Propagate Changes Between Branches - -on: - push: - branches: - - main - - development - -permissions: - contents: write - pull-requests: write - -jobs: - propagate: - name: Create PR to synchronize branches - runs-on: ubuntu-latest - if: github.actor != 'github-actions[bot]' && github.event.pusher != null - steps: - - name: Set up Node (for github-script) - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 - with: - node-version: '24.11.1' - - - name: Propagate Changes - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const currentBranch = context.ref.replace('refs/heads/', ''); - - async function createPR(src, base) { - if (src === base) return; - - core.info(`Checking propagation from ${src} to ${base}...`); - - // Check for existing open PRs - const { data: pulls } = await github.rest.pulls.list({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - head: `${context.repo.owner}:${src}`, - base: base, - }); - - if (pulls.length > 0) { - core.info(`Existing PR found for ${src} -> ${base}. Skipping.`); - return; - } - - // Compare commits to see if src is ahead of base - try { - const compare = await github.rest.repos.compareCommits({ - owner: context.repo.owner, - repo: context.repo.repo, - base: base, - head: src, - }); - - // If src is not ahead, nothing to merge - if (compare.data.ahead_by === 0) { - core.info(`${src} is not ahead of ${base}. No propagation needed.`); - return; - } - } catch (error) { - // If base branch doesn't exist, etc. - core.warning(`Error comparing ${src} to ${base}: ${error.message}`); - return; - } - - // Create PR - try { - const pr = await github.rest.pulls.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: `Propagate changes from ${src} into ${base}`, - head: src, - base: base, - body: `Automated PR to propagate changes from ${src} into ${base}.\n\nTriggered by push to ${currentBranch}.`, - }); - core.info(`Created PR #${pr.data.number} to merge ${src} into ${base}`); - } catch (error) { - core.warning(`Failed to create PR from ${src} to ${base}: ${error.message}`); - } - } - - if (currentBranch === 'main') { - // Main -> Development - await createPR('main', 'development'); - } else if (currentBranch === 'development') { - // Development -> Feature branches - const branches = await github.paginate(github.rest.repos.listBranches, { - owner: context.repo.owner, - repo: context.repo.repo, - }); - - const featureBranches = branches - .map(b => b.name) - .filter(name => name.startsWith('feature/')); - - core.info(`Found ${featureBranches.length} feature branches: ${featureBranches.join(', ')}`); - - for (const featureBranch of featureBranches) { - await createPR('development', featureBranch); - } - } - env: - CPMP_TOKEN: ${{ secrets.CPMP_TOKEN }} diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml deleted file mode 100644 index ec51014a..00000000 --- a/.github/workflows/quality-checks.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Quality Checks - -on: - push: - branches: [ main, development, 'feature/**' ] - pull_request: - branches: [ main, development ] - -jobs: - backend-quality: - name: Backend (Go) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 - with: - go-version: '1.25.4' - cache-dependency-path: backend/go.sum - - - name: Run Go tests - working-directory: backend - run: go test -v -coverprofile=coverage.out ./... - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./backend/coverage.out - flags: backend - fail_ci_if_error: true - - - name: Run golangci-lint - uses: golangci/golangci-lint-action@e7fa5ac41e1cf5b7d48e45e42232ce7ada589601 # v9.1.0 - with: - version: latest - working-directory: backend - args: --timeout=5m - continue-on-error: true - - frontend-quality: - name: Frontend (React) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - - name: Set up Node.js - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - with: - node-version: '24.11.1' - cache: 'npm' - cache-dependency-path: frontend/package-lock.json - - - name: Install dependencies - working-directory: frontend - run: npm ci - - - name: Run frontend tests - working-directory: frontend - run: npm run test:coverage - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./frontend/coverage - flags: frontend - fail_ci_if_error: true - - - name: Run frontend lint - working-directory: frontend - run: npm run lint - continue-on-error: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index aaf00d4a..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,133 +0,0 @@ -name: Release - -on: - push: - tags: - - 'v*.*.*' - -permissions: - contents: write - packages: write - -jobs: - build-frontend: - name: Build Frontend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 - with: - node-version: '20.19.5' - cache: 'npm' - cache-dependency-path: frontend/package-lock.json - - - name: Install Dependencies - working-directory: frontend - run: npm ci - - - name: Build - working-directory: frontend - run: npm run build - - - name: Archive Frontend - working-directory: frontend - run: tar -czf ../frontend-dist.tar.gz dist/ - - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: frontend-dist - path: frontend-dist.tar.gz - - build-backend: - name: Build Backend - runs-on: ubuntu-latest - strategy: - matrix: - goos: [linux] - goarch: [amd64, arm64] - steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 - with: - go-version: '1.25.4' - - - name: Build - working-directory: backend - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - CGO_ENABLED: 1 - run: | - # Install dependencies for CGO (sqlite) - if [ "${{ matrix.goarch }}" = "arm64" ]; then - sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu - export CC=aarch64-linux-gnu-gcc - fi - - go build -ldflags "-s -w -X github.com/Wikid82/CaddyProxyManagerPlus/backend/internal/version.Version=${{ github.ref_name }}" -o ../cpmp-${{ matrix.goos }}-${{ matrix.goarch }} ./cmd/api - - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: backend-${{ matrix.goos }}-${{ matrix.goarch }} - path: cpmp-${{ matrix.goos }}-${{ matrix.goarch }} - - build-caddy: - name: Build Caddy - runs-on: ubuntu-latest - strategy: - matrix: - goos: [linux] - goarch: [amd64, arm64] - steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 - with: - go-version: '1.25.4' - - - name: Install xcaddy - run: go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest - - - name: Build Caddy - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - run: | - xcaddy build v2.9.1 \ - --replace github.com/quic-go/quic-go=github.com/quic-go/quic-go@v0.49.1 \ - --replace golang.org/x/crypto=golang.org/x/crypto@v0.35.0 \ - --output caddy-${{ matrix.goos }}-${{ matrix.goarch }} - - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: caddy-${{ matrix.goos }}-${{ matrix.goarch }} - path: caddy-${{ matrix.goos }}-${{ matrix.goarch }} - - create-release: - name: Create Release - needs: [build-frontend, build-backend, build-caddy] - runs-on: ubuntu-latest - steps: - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - path: artifacts - - - name: Display structure of downloaded files - run: ls -R artifacts - - - name: Create GitHub Release - uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2 - with: - files: | - artifacts/frontend-dist/frontend-dist.tar.gz - artifacts/backend-linux-amd64/cpmp-linux-amd64 - artifacts/backend-linux-arm64/cpmp-linux-arm64 - artifacts/caddy-linux-amd64/caddy-linux-amd64 - artifacts/caddy-linux-arm64/caddy-linux-arm64 - generate_release_notes: true - prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }} - token: ${{ secrets.CPMP_TOKEN }} - - build-and-publish: - needs: create-release - uses: ./.github/workflows/docker-publish.yml # Reusable workflow present; path validated - secrets: inherit diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml deleted file mode 100644 index d5e2b7da..00000000 --- a/.github/workflows/renovate.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Renovate - -on: - schedule: - - cron: '0 5 * * *' # daily 05:00 EST - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - issues: write - -jobs: - renovate: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 - with: - fetch-depth: 1 - - name: Run Renovate - uses: renovatebot/github-action@03026bd55840025343414baec5d9337c5f9c7ea7 # v44.0.4 - with: - configurationFile: .github/renovate.json - token: ${{ secrets.CPMP_TOKEN }} - env: - LOG_LEVEL: info diff --git a/.github/workflows/renovate_prune.yml b/.github/workflows/renovate_prune.yml deleted file mode 100644 index f7005a05..00000000 --- a/.github/workflows/renovate_prune.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: "Prune Renovate Branches" - -on: - workflow_dispatch: - schedule: - - cron: '0 3 * * *' # daily at 03:00 UTC - pull_request: - types: [closed] # also run when any PR is closed (makes pruning near-real-time) - -permissions: - contents: write # required to delete branch refs - pull-requests: read - -jobs: - prune: - runs-on: ubuntu-latest - concurrency: - group: prune-renovate-branches - cancel-in-progress: true - - env: - BRANCH_PREFIX: "renovate/" # adjust if you use a different prefix - - steps: - - name: Prune renovate branches - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - github-token: ${{ secrets.CPMP_TOKEN }} - script: | - const owner = context.repo.owner; - const repo = context.repo.repo; - const branchPrefix = (process.env.BRANCH_PREFIX || 'renovate/').replace(/^refs\/heads\//, ''); - const refPrefix = `heads/${branchPrefix}`; // e.g. "heads/renovate/" - - core.info(`Searching for refs with prefix: ${refPrefix}`); - - // List matching refs (branches) under the prefix - let refs; - try { - refs = await github.rest.git.listMatchingRefs({ - owner, - repo, - ref: refPrefix - }); - } catch (err) { - core.info(`No matching refs or API error: ${err.message}`); - refs = { data: [] }; - } - - for (const r of refs.data) { - const fullRef = r.ref; // "refs/heads/renovate/..." - const branchName = fullRef.replace('refs/heads/', ''); - core.info(`Evaluating branch: ${branchName}`); - - // Find PRs for this branch (head = "owner:branch") - const prs = await github.rest.pulls.list({ - owner, - repo, - head: `${owner}:${branchName}`, - state: 'all', - per_page: 100 - }); - - let shouldDelete = false; - if (!prs.data || prs.data.length === 0) { - core.info(`No PRs found for ${branchName} — marking for deletion.`); - shouldDelete = true; - } else { - // If none of the PRs are open, safe to delete - const hasOpen = prs.data.some(p => p.state === 'open'); - if (!hasOpen) { - core.info(`All PRs for ${branchName} are closed — marking for deletion.`); - shouldDelete = true; - } else { - core.info(`Open PR(s) exist for ${branchName} — skipping deletion.`); - } - } - - if (shouldDelete) { - try { - await github.rest.git.deleteRef({ - owner, - repo, - ref: `heads/${branchName}` - }); - core.info(`Deleted branch: ${branchName}`); - } catch (delErr) { - core.warning(`Failed to delete ${branchName}: ${delErr.message}`); - } - } - } - - - name: Done - run: echo "Prune run completed." diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0a0f3832..00000000 --- a/.gitignore +++ /dev/null @@ -1,83 +0,0 @@ -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -.venv/ -venv/ -env/ -ENV/ -.pytest_cache/ -.coverage -*.cover -.hypothesis/ -htmlcov/ - -# Node/Frontend -node_modules/ -frontend/node_modules/ -backend/node_modules/ -frontend/dist/ -frontend/coverage/ -frontend/.vite/ -frontend/*.tsbuildinfo - -# Go/Backend -backend/api -backend/*.out -backend/coverage/ -backend/coverage.*.out - -# Databases -*.db -*.sqlite -*.sqlite3 -backend/data/*.db -backend/cmd/api/data/*.db - -# IDE -.idea/ -*.swp -*.swo -*~ -.DS_Store - - -# Logs -.trivy_logs -*.log -logs/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Environment -.env -.env.* -!.env.example - -# OS -Thumbs.db - -# Caddy -backend/data/caddy/ - -# Docker -docker-compose.override.yml - -# Testing -coverage/ -*.xml -.trivy_logs/trivy-report.txt -backend/coverage.txt - -# CodeQL -codeql-db/ -codeql-results.sarif -**.sarif -codeql-results-js.sarif -codeql-results-go.sarif -remote_logs/Unconfirmed 312410.crdownload -.vscode/launch.json -docker-compose.local.yml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 1e92ba74..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,59 +0,0 @@ -repos: - - repo: local - hooks: - - id: python-compile - name: python compile check - entry: tools/python_compile_check.sh - language: script - files: ".*\\.py$" - pass_filenames: false - always_run: true - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 - hooks: - - id: end-of-file-fixer - exclude: '^(frontend/(coverage|dist|node_modules|\.vite)/|.*\.tsbuildinfo$)' - - id: trailing-whitespace - exclude: '^(frontend/(coverage|dist|node_modules|\.vite)/|.*\.tsbuildinfo$)' - - id: check-yaml - - id: check-added-large-files - - repo: local - hooks: - - id: dockerfile-check - name: dockerfile validation - entry: tools/dockerfile_check.sh - language: script - files: "Dockerfile.*" - pass_filenames: true - - id: go-test-coverage - name: Go Test Coverage - entry: scripts/go-test-coverage.sh - language: script - files: '\.go$' - pass_filenames: false - verbose: true - - id: go-vet - name: Go Vet - entry: bash -c 'cd backend && go vet ./...' - language: system - files: '\.go$' - pass_filenames: false - - id: frontend-type-check - name: Frontend TypeScript Check - entry: bash -c 'cd frontend && npm run type-check' - language: system - files: '^frontend/.*\.(ts|tsx)$' - pass_filenames: false - - id: frontend-lint - name: Frontend Lint (Fix) - entry: bash -c 'cd frontend && npm run lint -- --fix' - language: system - files: '^frontend/.*\.(ts|tsx|js|jsx)$' - pass_filenames: false - - id: frontend-test-coverage - name: Frontend Test Coverage - entry: scripts/frontend-test-coverage.sh - language: script - files: '^frontend/.*\.(ts|tsx|js|jsx)$' - pass_filenames: false - verbose: true diff --git a/.sourcery.yml b/.sourcery.yml deleted file mode 100644 index 628ec063..00000000 --- a/.sourcery.yml +++ /dev/null @@ -1,4 +0,0 @@ -version: 1 -exclude: - - frontend/dist/** - - frontend/node_modules/** diff --git a/.version b/.version deleted file mode 100644 index 6e172a05..00000000 --- a/.version +++ /dev/null @@ -1 +0,0 @@ -0.2.0-beta.1 diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 90ad73a3..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Attach to Backend (Docker)", - "type": "go", - "request": "attach", - "mode": "remote", - "substitutePath": [ - { - "from": "${workspaceFolder}", - "to": "/app" - } - ], - "port": 2345, - "host": "127.0.0.1", - "showLog": true, - "trace": "log", - "logOutput": "rpc" - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 5eef0001..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Git Remove Cached", - "type": "shell", - "command": "git rm -r --cached .", - "group": "test" - }, - { - "label": "Run Pre-commit (All Files)", - "type": "shell", - "command": "${workspaceFolder}/.venv/bin/pre-commit run --all-files", - "group": "test" - }, - { - "label": "Build & Run Local Docker", - "type": "shell", - "command": "docker build --build-arg VCS_REF=$(git rev-parse HEAD) -t cpmp:local . && docker compose -f docker-compose.local.yml up -d", - "group": "test" - }, - { - "label": "Run Local Docker (debug)", - "type": "shell", - "command": "docker run --rm -it --name cpmp-debug --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 2345:2345 -e CPM_ENV=development -e CPMP_DEBUG=1 cpmp:local", - "group": "test" - }, - { - "label": "Run Trivy Scan (Local)", - "type": "shell", - "command": "docker", - "args": [ - "run", - "--rm", - "-v", - "/var/run/docker.sock:/var/run/docker.sock", - "-v", - "${userHome}/.cache/trivy:/root/.cache/trivy", - "-v", - "${workspaceFolder}/.trivy_logs:/logs", - "aquasec/trivy:latest", - "image", - "--severity", - "CRITICAL,HIGH", - "--output", - "/logs/trivy-report.txt", - "cpmp:local" - ], - "isBackground": false, - "group": "test" - }, - { - "label": "Run CodeQL Scan (Local)", - "type": "shell", - "command": "${workspaceFolder}/tools/codeql_scan.sh", - "group": "test" - } - ] -} diff --git a/ARCHITECTURE_PLAN.md b/ARCHITECTURE_PLAN.md deleted file mode 100644 index 4801271e..00000000 --- a/ARCHITECTURE_PLAN.md +++ /dev/null @@ -1,49 +0,0 @@ -# CaddyProxyManager+ Architecture Plan - -## Stack Overview -- **Backend**: Go 1.24, Gin HTTP framework, GORM ORM, SQLite for local/stateful storage. -- **Frontend**: React 18 + TypeScript with Vite, React Query for data fetching, React Router for navigation. -- **API Contract**: REST/JSON over `/api/v1`, versioned to keep room for breaking changes. -- **Deployment**: Container-first via multi-stage Docker build (Node → Go), future compose bundle for Caddy runtime. - -## Backend -- `backend/cmd/api`: Entry point wires configuration, database, and HTTP server lifecycle. -- `internal/config`: Reads environment variables (`CPM_ENV`, `CPM_HTTP_PORT`, `CPM_DB_PATH`). Defaults to `development`, `8080`, `./data/cpm.db` respectively. -- `internal/database`: Wraps GORM + SQLite connection handling and enforces data-directory creation. -- `internal/server`: Creates Gin engine, registers middleware, wires graceful shutdown, and exposes `Run(ctx)` for signal-aware lifecycle. -- `internal/api`: Versioned routing layer. Initial resources: - - `GET /api/v1/health`: Simple status response for readiness checks. - - CRUD `/api/v1/proxy-hosts`: Minimal data model used to validate persistence, shape matches Issue #1 requirements (name, domain, upstream target, toggles). -- `internal/models`: Source of truth for persistent entities. Future migrations will extend `ProxyHost` with SSL, ACL, audit metadata. -- Testing: In-memory SQLite harness verifies handler lifecycle via unit tests (`go test ./...`). - -## Frontend -- Vite dev server with proxy to `http://localhost:8080` for `/api` paths keeps CORS trivial. -- React Router organizes initial pages (Dashboard, Proxy Hosts, System Status) to mirror Issue roadmap. -- React Query centralizes API caching, invalidation, and loading states. -- Basic layout shell provides left-nav reminiscent of NPM while keeping styling simple (CSS utility file, no design system yet). Future work will slot shadcn/ui components without rewriting data layer. -- Build outputs static assets in `frontend/dist` consumed by Docker multi-stage for production. - -## Data & Persistence -- SQLite chosen for Alpha milestone simplicity; GORM migrates schema automatically on boot (`AutoMigrate`). -- Database path configurable via env to allow persistent volumes in Docker or alternative DB (PostgreSQL/MySQL) when scaling. - -## API Principles -1. **Version Everything** (`/api/v1`). -2. **Stateless**: Each request carries all context; session/story features will rely on cookies/JWT later. -3. **Dependable validation**: Gin binding ensures HTTP 400 responses include validation errors. -4. **Observability**: Gin logging + structured error responses keep early debugging simple; plan to add Zap/zerolog instrumentation during Beta. - -## Local Development Workflow -1. Start backend: `cd backend && go run ./cmd/api`. -2. Start frontend: `cd frontend && npm run dev` (Vite proxy sends API calls to backend automatically). -3. Optional: run both via Docker (see updated Dockerfile) once containers land. -4. Tests: - - Backend: `cd backend && go test ./...` - - Frontend build check: `cd frontend && npm run build` - -## Next Steps -- Layer authentication (Issue #7) once scaffolding lands. -- Expand data model (certificates, access lists) and add migrations. -- Replace basic CSS with component system (e.g., shadcn/ui) + design tokens. -- Compose file bundling backend, frontend assets, Caddy runtime, and SQLite volume. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 9e55d7b5..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,387 +0,0 @@ -# Contributing to CaddyProxyManager+ - -Thank you for your interest in contributing to CaddyProxyManager+! This document provides guidelines and instructions for contributing to the project. - -## Table of Contents - -- [Code of Conduct](#code-of-conduct) -- [Getting Started](#getting-started) -- [Development Workflow](#development-workflow) -- [Coding Standards](#coding-standards) -- [Testing Guidelines](#testing-guidelines) -- [Pull Request Process](#pull-request-process) -- [Issue Guidelines](#issue-guidelines) -- [Documentation](#documentation) - -## Code of Conduct - -This project follows a Code of Conduct that all contributors are expected to adhere to: - -- Be respectful and inclusive -- Welcome newcomers and help them get started -- Focus on what's best for the community -- Show empathy towards other community members - -## Getting Started - --### Prerequisites - -- **Go 1.24+** for backend development -- **Node.js 20+** and npm for frontend development -- Git for version control -- A GitHub account - -### Fork and Clone - -1. Fork the repository on GitHub -2. Clone your fork locally: -```bash -git clone https://github.com/YOUR_USERNAME/CaddyProxyManagerPlus.git -cd CaddyProxyManagerPlus -``` - -3. Add the upstream remote: -```bash -git remote add upstream https://github.com/Wikid82/CaddyProxyManagerPlus.git -``` - -### Set Up Development Environment - -**Backend:** -```bash -cd backend -go mod download -go run ./cmd/seed/main.go # Seed test data -go run ./cmd/api/main.go # Start backend -``` - -**Frontend:** -```bash -cd frontend -npm install -npm run dev # Start frontend dev server -``` - -## Development Workflow - -### Branching Strategy - -- **main** - Production-ready code -- **development** - Main development branch (default) -- **feature/** - Feature branches (e.g., `feature/add-ssl-support`) -- **bugfix/** - Bug fix branches (e.g., `bugfix/fix-import-crash`) -- **hotfix/** - Urgent production fixes - -### Creating a Feature Branch - -Always branch from `development`: - -```bash -git checkout development -git pull upstream development -git checkout -b feature/your-feature-name -``` - -### Commit Message Guidelines - -Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification: - -``` -(): - - - -