chore: GitHub workflow revamp — GitHub Flow, community files, CI updates (#101)

* chore: add comprehensive .gitignore

* ci: update CI workflow for GitHub Flow

- Change triggers from develop to main (PRs to main + pushes to main)
- Add concurrency controls to cancel stale runs
- Update docker/build-push-action to v6
- Add descriptive job names for branch protection status checks
- Update screenshot refresh and docs sync to trigger on main pushes

* ci: update docker-publish for GitHub Flow

- Remove develop branch trigger (no more dev tag)
- Keep v* tag trigger for releases
- Update docker/build-push-action to v6

* docs: add community and governance files

- CONTRIBUTING.md with dev setup and PR guidelines
- SECURITY.md with vulnerability reporting policy
- CODE_OF_CONDUCT.md (Contributor Covenant v2.1 reference)
- PR template with conventional commits checklist
- Issue templates for bug reports and feature requests
- CODEOWNERS defaulting to @AnsoCode
- Dependabot config for npm (root, backend, frontend) and GitHub Actions

* docs: add README with badges, quick start, and contributing section

* chore: add LICENSE placeholder and open license decision issue (#100)

* docs: update CLAUDE.md for GitHub Flow branching model

- Replace develop-based Git Flow with GitHub Flow (main only)
- All branches now created off main, PRs target main
- Simplify release checklist (no develop-to-main merge step)
- Update testing strategy to reference Vitest and Playwright
- Fix docs.json reference (was mint.json)

* chore: track CLAUDE.md in version control

Remove CLAUDE.md from .gitignore so project workflow instructions
are versioned alongside the code they govern.

* docs: add MANUAL_STEPS.md for GitHub settings that require UI configuration
This commit is contained in:
Anso
2026-03-24 22:32:44 -04:00
committed by GitHub
parent 6f1b2cfa9c
commit 9f9de482ce
16 changed files with 696 additions and 30 deletions
+2
View File
@@ -0,0 +1,2 @@
# Default owner for everything
* @AnsoCode
+56
View File
@@ -0,0 +1,56 @@
name: Bug Report
description: Report a bug in Sencho
labels: ["bug"]
body:
- type: textarea
id: description
attributes:
label: Describe the bug
placeholder: A clear description of the bug
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
placeholder: |
1. Go to '...'
2. Click on '...'
3. See error
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
validations:
required: true
- type: input
id: version
attributes:
label: Sencho version
placeholder: "0.2.2"
validations:
required: true
- type: dropdown
id: deployment
attributes:
label: Deployment method
options:
- Docker Compose
- Docker run
- Development (npm run dev)
- Other
validations:
required: true
- type: input
id: browser
attributes:
label: Browser (if UI issue)
placeholder: "Chrome 120, Firefox 121, etc."
- type: textarea
id: logs
attributes:
label: Relevant logs
description: Paste any relevant container or browser console logs
render: shell
@@ -0,0 +1,40 @@
name: Feature Request
description: Suggest a new feature for Sencho
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: Problem or motivation
description: What problem does this feature solve? Why do you need it?
placeholder: I'm always frustrated when...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed solution
description: Describe the feature you'd like to see
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Any workarounds or alternative approaches you've considered
- type: dropdown
id: scope
attributes:
label: Feature scope
options:
- Dashboard / UI
- Stack management
- Multi-node / remote nodes
- App Store
- Observability / Logs
- Settings / Configuration
- Docker / Infrastructure
- API
- Other
validations:
required: true
+15
View File
@@ -0,0 +1,15 @@
## What does this PR do?
<!-- Brief description of the change -->
## Related Issue
<!-- Link to issue: Closes #123 -->
## Checklist
- [ ] Tests added/updated (if applicable)
- [ ] Documentation updated (if applicable)
- [ ] ESLint passes (`npm run lint` in backend/ and frontend/)
- [ ] Commit messages follow Conventional Commits
- [ ] CHANGELOG.md updated under `## [Unreleased]` (for user-facing changes)
+32
View File
@@ -0,0 +1,32 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/backend"
schedule:
interval: "weekly"
labels:
- "dependencies"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
labels:
- "dependencies"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "ci"
+19 -14
View File
@@ -2,12 +2,18 @@ name: Sencho CI
on:
pull_request:
branches: [ main, develop ]
branches: [main]
push:
branches: [ develop ]
branches: [main]
# Cancel previous runs on the same branch/PR
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
backend:
name: Backend (Build, Test, Lint)
runs-on: ubuntu-latest
steps:
- name: Checkout Code
@@ -41,6 +47,7 @@ jobs:
run: npm audit --audit-level=high
frontend:
name: Frontend (Build, Lint)
runs-on: ubuntu-latest
steps:
- name: Checkout Code
@@ -70,6 +77,7 @@ jobs:
run: npm audit --audit-level=high
docker-validate:
name: Docker Build & Scan
runs-on: ubuntu-latest
steps:
- name: Checkout Code
@@ -79,7 +87,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Build Docker image (validation only)
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
push: false
@@ -98,6 +106,7 @@ jobs:
continue-on-error: true
e2e:
name: E2E Tests (Playwright)
runs-on: ubuntu-latest
needs: [backend, frontend]
steps:
@@ -163,9 +172,10 @@ jobs:
retention-days: 7
update-screenshots:
name: Refresh Doc Screenshots
runs-on: ubuntu-latest
# Only on develop pushes; skip bot commits to avoid an infinite loop
if: "github.event_name == 'push' && github.ref == 'refs/heads/develop' && !contains(github.event.head_commit.message, 'docs: refresh screenshots')"
# Only on main pushes (merged PRs); skip bot commits to avoid infinite loop
if: "github.event_name == 'push' && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'docs: refresh screenshots')"
needs: [backend, frontend]
permissions:
contents: write
@@ -174,8 +184,6 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v4
with:
# PAT required — GITHUB_TOKEN cannot create PRs against a protected
# branch. DOCS_REPO_TOKEN is a classic PAT with repo scope.
token: ${{ secrets.DOCS_REPO_TOKEN }}
- name: Setup Node.js
@@ -234,7 +242,7 @@ jobs:
branch: chore/refresh-screenshots
commit-message: "docs: refresh screenshots"
title: "docs: refresh screenshots"
body: "Automated screenshot refresh — generated by the `update-screenshots` CI job on every push to `develop`."
body: "Automated screenshot refresh — generated by the `update-screenshots` CI job on push to `main`."
add-paths: docs/images/
delete-branch: true
@@ -248,8 +256,9 @@ jobs:
--repo ${{ github.repository }}
sync-docs:
name: Sync Docs to sencho-docs
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout Sencho repo
uses: actions/checkout@v4
@@ -260,8 +269,6 @@ jobs:
env:
DOCS_TOKEN: ${{ secrets.DOCS_REPO_TOKEN }}
run: |
# Always start clean so a previous partial/broken checkout can't cause
# "not in a git directory" on subsequent steps.
rm -rf sencho-docs
REMOTE="https://x-access-token:${DOCS_TOKEN}@github.com/AnsoCode/sencho-docs.git"
@@ -278,8 +285,6 @@ jobs:
fi
- name: Copy /docs into sencho-docs root
# --exclude='.git' prevents rsync --delete from wiping the .git
# directory that was just cloned/initialized in the previous step.
run: rsync -av --delete --exclude='.git' sencho/docs/ sencho-docs/
- name: Commit and push to sencho-docs
@@ -288,5 +293,5 @@ jobs:
git config user.email "docs-bot@sencho.io"
git config user.name "Sencho Docs Bot"
git add -A
git commit -m "docs: sync from develop@${{ github.sha }}" || echo "No changes to commit"
git commit -m "docs: sync from main@${{ github.sha }}" || echo "No changes to commit"
git push origin HEAD:main
+1 -6
View File
@@ -2,8 +2,6 @@ name: Build and Publish Docker Image
on:
push:
branches:
- develop
tags:
- 'v*'
workflow_dispatch:
@@ -36,14 +34,11 @@ jobs:
with:
images: saelix/sencho
tags: |
# If pushing to develop, tag as 'dev'
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/develop' }}
# If pushing a v* tag, tag as 'latest' and the specific semver version
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
push: true
+21 -7
View File
@@ -1,7 +1,5 @@
# Dependencies
node_modules/
frontend/node_modules/
backend/node_modules/
# Environment Variables (CRITICAL: Never commit secrets)
.env
@@ -10,8 +8,6 @@ backend/node_modules/
# Build Outputs
dist/
frontend/dist/
backend/dist/
# Sencho User Data & Mocks
data/
@@ -22,13 +18,31 @@ sencho.json
# OS Generated Files
.DS_Store
Thumbs.db
Desktop.ini
ehthumbs.db
#PRD
Product Requirements Document
# IDE / Editors
.vscode/
.idea/
*.swp
*.swo
*~
*.sublime-project
*.sublime-workspace
# Testing
test-results/
e2e/report/
html-report/
.coverage/
coverage/
# Logs
*.log
npm-debug.log*
# Claude Code
.claude/
CLAUDE.md
plans/
# Playwright MCP
+271
View File
@@ -0,0 +1,271 @@
# CLAUDE.md
> **Every session:** Read this file fully before starting any task.
> **Every commit:** Before committing, run through the checklist below.
## Project Overview
Sencho is a self-hosted Docker Compose management dashboard - a React + Express full-stack app that provides a GUI for managing Docker Compose stacks.
**Architecture Model:** It uses a "Distributed API" model. It manages local stacks directly. To manage remote nodes, it acts as a transparent HTTP/WebSocket proxy, routing requests to other autonomous Sencho instances running on those remote servers via long-lived JWT Bearer tokens.
## Development Commands
### Backend
```bash
cd backend
npm install
npm run dev # nodemon + ts-node, watches src/
npm run build # tsc → dist/
npm start # node dist/index.js (production)
```
### Frontend
```bash
cd frontend
npm install
npm run dev # Vite dev server (proxies /api → localhost:3000)
npm run build # tsc -b && vite build
npm run lint # ESLint 9 flat config
npm run preview # preview production build
```
### Full Docker build
```bash
docker build -t sencho . # multi-stage: frontend build → backend build → runtime
```
---
## Versioning & Release Flow
Sencho uses **Semantic Versioning** (`MAJOR.MINOR.PATCH`) driven by **Conventional Commits** and automated by the `release-please` GitHub Action.
### How it works (GitHub Flow)
1. Create a short-lived feature branch off `main` (e.g., `feat/my-feature`, `fix/my-bug`).
2. Commit using conventional commit prefixes (see below).
3. Open a PR into `main`. CI runs automatically.
4. Once CI is green, merge the PR (squash-merge recommended for clean history).
5. On every push to `main`, the `release-please` workflow automatically opens or updates a **Release PR** titled `chore(main): release vX.Y.Z`. This PR contains:
- An updated `CHANGELOG.md` entry generated from commit messages.
- A `package.json` version bump.
6. When you're ready to publish, **merge the Release PR**. This triggers:
- A `vX.Y.Z` git tag created by release-please.
- The `docker-publish.yml` workflow fires on the tag → builds and pushes `latest` + `X.Y.Z` to Docker Hub.
> You never create tags manually. Merging the Release PR is the only release action required.
> There is no `develop` branch. `main` is the only long-lived branch.
### Conventional Commit format
```
<type>(optional scope): <short description>
# Examples
fix(auth): prevent login loop on remote node 401
feat(app-store): add category filter pill bar
feat!: replace SSH with Distributed API proxy ← BREAKING CHANGE
docs(quickstart): update Docker run command
chore(deps): bump express to 4.19.2
ci: add arm64 platform to docker-publish
```
### Version bump rules
| Commit type | Example | Version bump |
|---|---|---|
| `fix:` / `perf:` / `revert:` | Bug fixes, perf improvements | `PATCH` — 0.1.0 → 0.1.1 |
| `feat:` | New user-facing feature | `MINOR` — 0.1.x → 0.2.0 |
| `feat!:` / `BREAKING CHANGE:` footer | Breaking API or UX change | `MAJOR` — 0.x.y → 1.0.0 |
| `docs:` / `chore:` / `ci:` / `test:` / `refactor:` | Infrastructure, no user impact | No bump (hidden in CHANGELOG) |
> While the version is `0.x`, `feat:` bumps the **minor** digit (0.1 → 0.2), not the patch. `fix:` still bumps patch (0.1.0 → 0.1.1). A `feat!:` will bump to `1.0.0`.
### Enriching the auto-generated Release PR
release-please generates CHANGELOG entries from commit subject lines. If a change deserves more context (e.g. a security fix or complex feature), **edit the Release PR description and CHANGELOG entry directly** before merging — release-please preserves manual edits on subsequent updates.
---
## Architecture & Request Flow
### The Distributed API Proxy Flow
1. **Frontend:** Makes API calls via `apiFetch` (`frontend/src/lib/api.ts`), which injects the `x-node-id` header (or `?nodeId=` query param for WebSockets) from `NodeContext`.
2. **Backend Gateway (`index.ts`):** The `nodeContextMiddleware` evaluates the node ID.
- **If Local:** The request passes through standard auth and hits the local Express route handlers.
- **If Remote:** The request hits `http-proxy-middleware`. The backend strips the `x-node-id` header, injects `Authorization: Bearer <api_token>`, and seamlessly proxies the entire HTTP or WebSocket request to the remote Sencho instance's `api_url`.
### Backend Services (`backend/src/services/`)
All core services execute **locally only**. (Remote execution is handled by proxying the request to the remote Sencho instance, which then executes locally on its own machine).
- **`DockerController`** - Dockerode wrapper for local containers, images, volumes, networks, stats, exec.
- **`ComposeService`** - Spawns `docker compose` CLI child processes locally.
- **`FileSystemService`** - Simple `fs.promises` wrapper. All reads/writes happen against the local `COMPOSE_DIR`.
- **`DatabaseService`** - SQLite via `better-sqlite3`. Stores alerts, settings, metrics, and node routing configs at `/app/data/sencho.db`.
- **`NodeRegistry`** - Manages node configurations. Returns the local Docker socket for local ops, and returns `{ api_url, api_token }` targets for remote proxies.
### Frontend Structure
- **`App.tsx`** - Root router: setup flow → login → `EditorLayout`.
- **`context/AuthContext.tsx`** - JWT auth state; handles first-boot setup detection.
- **`context/NodeContext.tsx`** - Active node selection state.
- **`components/NodeManager.tsx`** - UI for adding nodes (requires Name, Sencho API URL, and API Token).
- **`lib/api.ts`** - `apiFetch` wrapper that handles headers and 401 redirects.
### Authentication
- **Browser-to-Backend:** JWT stored in `httpOnly` cookies.
- **Node-to-Node (Proxy):** Long-lived JWT passed via `Authorization: Bearer <token>` header.
- **Middleware:** `authMiddleware` accepts *both* cookies and Bearer tokens seamlessly.
---
## 🛑 AGENT DIRECTIVES (CRITICAL INSTRUCTIONS)
To prevent hallucinations, regressions, and context loss, you MUST adhere to the following rules:
**1. Targeted Reading of index.ts (Avoid Full-File Context Waste)**
- Before modifying `index.ts`, do NOT read the entire ~1500-line file. Read only the relevant section: Lines 50-250 (Auth/Setup), Lines 300-500 (Stacks/Compose), Lines 550-750 (Docker Entities), Lines 800-1000 (System/Metrics), Lines 1050-1250 (Nodes/Proxy), Lines 1300+ (WebSockets/Errors).
- For middleware ordering, check lines 100-300.
- Confirm exact placement by searching for the prefix.
2. **Respect the Architecture:**
- We do NOT use SSH, SFTP, or remote Docker TCP sockets. For remote file reading, you must use the HTTP Proxy model.
- Ensure `http-proxy-middleware` catches remote requests before local route handlers.
3. **Limit Repetition & Be Concise:**
- Do not output massive blocks of unchanged code. Use precise edits, diffs, or surgical replacements.
- Do not over-explain your steps unless asked. State your intent, perform the file modifications, and report the result.
4. **Strict GitHub Flow & Conventional Commits:**
- All feature work and bug fixes must happen on a newly created branch off `main`.
- **Every commit MUST use a conventional commit prefix** (`fix:`, `feat:`, `docs:`, `chore:`, `ci:`, `refactor:`, `test:`, `perf:`). This is what drives automated versioning — no prefix means no version bump and no CHANGELOG entry.
- Update `CHANGELOG.md` under `## [Unreleased]` before committing (the auto-generated entry from release-please will be terse; add context here for significant changes).
- Stage, commit, push to `origin`, and **open a PR into `main`**. This is required to trigger automated CI/CD actions.
- **Do NOT manually create git tags or push version commits.** Versioning is fully automated by `release-please` — it fires on every push to `main` and creates the Release PR automatically.
5. **Strict Security & API Standards:**
- **Default Deny:** EVERY new endpoint in `index.ts` under `/api/` MUST be protected by `authMiddleware` unless explicitly designated as public.
- **SQL Injection Prevention:** ALWAYS use `better-sqlite3` parameterized statements. Do not manually sanitize or string-escape inputs.
- **No Secrets in Code:** Never hardcode secrets. Rely on `DatabaseService.getInstance().getGlobalSettings()`.
6. **UX & UI Engineering Constraints:**
- Use only Tailwind CSS and existing `shadcn/ui` components.
- Handle loading states. Every frontend API call must be wrapped in `try/catch`.
- When using `sonner` toast, use this exact defensive pattern: `toast.error(error?.message || error?.error || error?.data?.error || 'Something went wrong.');`
- Do not assume `error` is a standard Error instance.
7. **Backend Error Handling:**
- **Do Not Swallow Errors:** Do not write empty `catch` blocks.
- **Standardized Responses:** If a backend operation fails, log the actual error to the console for debugging, but return a clean, standard JSON error to the frontend: `res.status(500).json({ error: "Clear message" });`.
- **No Server Crashes:** Ensure all asynchronous proxy streams (WebSockets/SSE) have robust error handling and `.on('error')` listeners to prevent the Node event loop from crashing.
8. **WebSocket Nuances & Middleware Bypasses:**
- Express middlewares (`authMiddleware`, `nodeContextMiddleware`, `cookieParser`) **DO NOT RUN** on WebSocket (`server.on('upgrade')`) connections.
- You MUST manually parse cookies/headers and manually execute `jwt.verify()` inside the `upgrade` event handler.
- Extract `nodeId` from URL query parameters (`?nodeId=`) for WebSockets, NOT from the `x-node-id` header.
9. **Filesystem Security & Path Traversal:**
- Perform strict directory traversal validation at the Express route level before any `FileSystemService` call.
- Use this exact pattern: `const safePath = path.resolve(COMPOSE_DIR, stackName, filename);` `if (!safePath.startsWith(path.resolve(COMPOSE_DIR))) { return res.status(400).json({ error: 'Invalid path' }); }`
- Reject inputs with `..` or absolute paths.
10. **React Dependency Traps (Infinite Loops):**
- Be extremely cautious fixing `react-hooks/exhaustive-deps` warnings in global context files like `NodeContext.tsx`.
- We intentionally use `useRef` (e.g., `activeNodeRef`) to hold current state inside `useCallback` functions. **DO NOT blindly add state variables to dependency arrays** to satisfy ESLint, as it will trigger infinite API-fetching loops.
11. **The Monolithic index.ts Constraint:**
- The backend `index.ts` file is currently a monolith (~1500 lines).
- Continue appending new routes into their logical groups (e.g., Auth, Stacks, System, Nodes). **DO NOT** attempt to proactively split or refactor this file into a multi-router architecture unless explicitly instructed by the user.
12. **Environment & File System Context:**
- `FileSystemService` strictly operates against the `COMPOSE_DIR` environment variable.
- **DO NOT** hardcode `/app/compose` as an immutable path or implicitly assume it is the only path. It is merely the Docker default. Your code must dynamically read `process.env.COMPOSE_DIR` (or rely on `FileSystemService.getInstance(nodeId).getBaseDir()`) to respect each user's unique volume mounts or local OS paths.
13. **Mandatory Test Validation Before Completing Any Task:**
- Validate behavior before considering a task done.
- **Always kill existing services first** — do not assume a running process has the latest code (it may have been started with `npm start` or `node dist/index.js`, not nodemon):
```bash
kill $(lsof -ti:3000) 2>/dev/null; kill $(lsof -ti:5173) 2>/dev/null
```
- Then start fresh in the background using `npm run dev` (nodemon) only:
```bash
cd backend && npm run dev &
cd frontend && npm run dev &
```
- Wait for readiness before proceeding:
```bash
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/api/health # expect 200
curl -s -o /dev/null -w "%{http_code}" http://localhost:5173 # expect 200
```
- If Playwright MCP is available, use it to navigate and interact with the affected UI and confirm expected behavior.
- If Playwright is unavailable: explicitly state "Playwright validation unavailable; recommend manual testing: [describe exact steps]".
- **Always kill both services when done with validation** — never leave orphan processes:
```bash
kill $(lsof -ti:3000) 2>/dev/null; kill $(lsof -ti:5173) 2>/dev/null
```
- Explicitly confirm in your response that services have been stopped after validation.
- Never open a PR without documented validation.
14. **TypeScript Strictness Rules**
- `tsconfig.json` has `"strict": true`.
- Write code that compiles without `any` casts or `@ts-ignore`. Prefer proper types over `any`.
- If a library lacks types, import `@types/...` or use `unknown` + narrowing.
- Never add casts to silence errors.
15. **Testing Strategy Reference**
- **Backend unit tests:** Vitest (`cd backend && npm test`). Add tests for new backend logic.
- **E2E tests:** Playwright (`npm run test:e2e`). Covers auth, stack management, and node management flows.
- **Manual validation:** Use the Playwright MCP server for UI changes, or `curl` for backend-only changes.
- For UI changes: use the Playwright MCP server to navigate to `http://localhost:5173`, interact with the affected components, and confirm expected behavior.
- For backend-only changes: validate via `curl` against `localhost:3000/api/...` with a valid `Authorization: Bearer <token>` or session cookie.
16. **Environment Variables Reference**
- Read vars from `process.env` or `DatabaseService`.
- Never hardcode. Key vars: `COMPOSE_DIR` (base directory), `JWT_SECRET` (token signing), `PORT` (listen port), `NODE_ENV`. Check `.env.example` for the full list.
17. **Code Review Standards**
- After completing any implementation, review the code for:
- Functions longer than 30 lines (likely doing too much)
- Logic duplicated more than twice (extract to utility)
- Any `any` type usage in TypeScript (replace with real types)
- Components with more than 3 props that could be grouped into an object
- Missing error handling on async operations
- Run /simplify before presenting code to the user.
---
## Documentation
Whenever you create, modify, or remove a user-facing feature, API endpoint, or configuration option, you MUST also update or create the relevant `.mdx` file inside the `/docs` folder.
- Follow the existing structure in `/docs/docs.json` navigation
- Write docs from the perspective of the end user, not internal implementation
- Use Mintlify MDX components where useful (e.g. `<Card>`, `<CodeGroup>`, `<Note>`)
- Add the new/updated doc page to the `navigation` array in `mint.json` if it's a new file
- Keep tone friendly and concise
### Screenshots
When adding or updating a doc page for a user-facing feature:
1. Follow the service lifecycle in Directive 13: kill any running processes on ports 3000/5173, restart with `npm run dev`, wait for readiness, and kill again when done
2. Use the Playwright MCP server to navigate to the relevant page/feature in the app
3. Take a screenshot and save it to `/docs/images/<feature-name>/<screenshot-name>.png`
4. Use descriptive filenames (e.g. `dashboard-overview.png`, `settings-dark-mode.png`)
5. For multi-step flows, highlight the relevant UI element by injecting a CSS border
before screenshotting: `element.style.border = '3px solid #0F172A'`
6. Reference screenshots in MDX files using:
`<img src="/images/<feature-name>/<screenshot-name>.png" alt="..." />`
or Mintlify's `<Frame>` component for a polished look:
`<Frame><img src="/images/..." alt="..." /></Frame>`
7. Always take screenshots at 1280x800 desktop resolution for consistency
## Pre-Commit Checklist
- [ ] Am I on a feature branch off `main`? (never commit to main directly)
- [ ] Does my commit message start with a conventional prefix? (`fix:`, `feat:`, `docs:`, `chore:`, `ci:`, `refactor:`, `test:`, `perf:`)
- [ ] Did I update CHANGELOG.md under `## [Unreleased]`? (add context beyond what the commit subject captures)
- [ ] Did I update or create the relevant `/docs/*.mdx` file?
- [ ] Did I take/update screenshots via Playwright MCP if UI changed?
- [ ] Did I validate behavior via Playwright MCP (UI) or `curl` (backend), and kill the dev servers afterwards? (Directive 13)
- [ ] Is the PR going into `main`?
## Release Checklist (when shipping to users)
- [ ] Is `main` stable and CI green?
- [ ] Wait for the `release-please` workflow to open the Release PR (titled `chore(main): release vX.Y.Z`).
- [ ] Review and optionally enrich the auto-generated CHANGELOG entry in the Release PR.
- [ ] Merge the Release PR → tag is created → Docker Hub `latest` + semver tags are published automatically.
+19
View File
@@ -0,0 +1,19 @@
# Code of Conduct
This project follows the **Contributor Covenant Code of Conduct v2.1**.
The full text is available at: https://www.contributor-covenant.org/version/2/1/code_of_conduct/
## Summary
We are committed to providing a friendly, safe, and welcoming environment for all contributors, regardless of experience level, identity, or background.
## Enforcement
Instances of unacceptable behavior may be reported to the project maintainers at **conduct@sencho.io**.
All reports will be reviewed and investigated promptly and fairly. Project maintainers are obligated to respect the privacy and security of the reporter.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
+47
View File
@@ -0,0 +1,47 @@
# Contributing to Sencho
Thank you for your interest in contributing to Sencho!
## Getting Started
1. Fork the repository
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/Sencho.git`
3. Create a branch: `git checkout -b feature/your-feature`
4. Install dependencies:
```bash
cd backend && npm install
cd ../frontend && npm install
```
5. Start the dev servers:
```bash
cd backend && npm run dev # Express + nodemon on :3000
cd frontend && npm run dev # Vite on :5173
```
## Development
- **Backend:** Node.js + Express + TypeScript in `backend/`
- **Frontend:** React 19 + Vite + TypeScript in `frontend/`
- **Tests:** `cd backend && npm test` (Vitest) and `npm run test:e2e` (Playwright)
- **Lint:** `npm run lint` in both `backend/` and `frontend/`
## Pull Request Process
- All PRs target `main`
- Ensure CI passes before requesting review
- Use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages
- Update documentation if your change affects user-facing behavior
- Add tests for new functionality
- Keep PRs focused — one feature or fix per PR
- Update `CHANGELOG.md` under `## [Unreleased]` for user-facing changes
## Reporting Bugs
Use the [bug report template](https://github.com/AnsoCode/Sencho/issues/new?template=bug_report.yml). Include: deployment method, Sencho version, browser (for UI issues), steps to reproduce, and expected vs actual behavior.
## Code Style
- TypeScript with `strict: true` — no `any` casts or `@ts-ignore`
- ESLint 9 flat config for both backend and frontend
- Tailwind CSS + shadcn/ui for frontend styling
- Follow existing patterns in the codebase
+6
View File
@@ -0,0 +1,6 @@
License pending — see https://github.com/AnsoCode/Sencho/issues/100
This project's license has not yet been finalized. The license decision is
being tracked in the issue linked above.
Until a license is chosen, all rights are reserved by the project maintainers.
+63
View File
@@ -0,0 +1,63 @@
# Manual Steps Required
These actions could not be performed automatically and need to be done manually in the GitHub UI.
## 1. Branch Protection Rules for `main`
Go to **Settings > Branches > Add branch ruleset** for `main`:
- [x] Require a pull request before merging
- Required approvals: 0 (solo dev — you merge your own PRs after CI passes)
- Dismiss stale reviews when new commits are pushed: ON
- [x] Require status checks to pass before merging
- Add these job names: `Backend (Build, Test, Lint)`, `Frontend (Build, Lint)`, `Docker Build & Scan`, `E2E Tests (Playwright)`
- [x] Require conversation resolution before merging
- [x] Do not allow bypassing the above settings (even you must go through PRs)
- [x] Do not allow deletions
- [ ] Require signed commits (optional — future improvement)
## 2. Repository Settings
Go to **Settings > General > Pull Requests**:
- [x] Check **"Automatically delete head branches"**
- [x] Set **squash merge** as default merge strategy
## 3. Security Settings
Go to **Settings > Code security and analysis**:
- [x] Enable **Dependabot alerts**
- [x] Enable **Dependabot security updates**
- [x] Enable **Secret scanning**
- [x] Enable **Secret scanning push protection**
- [x] Enable **Private vulnerability reporting**
## 4. Default Branch
Verify that `main` is set as the default branch:
- Go to **Settings > Branches > Default branch**
- Should already be `main`
## 5. Delete `develop` Branch (When Ready)
The `develop` branch has 1 unmerged commit (`37f751c docs: refresh screenshots`).
**Before deleting**, decide whether to:
- Cherry-pick that commit to main via a PR, OR
- Let it go (it's just a screenshot refresh)
Then delete via: **Branches page > delete `develop`**
Also clean up stale feature branches that have been merged:
- `chore/refresh-screenshots`
- `fix/editor-loading`
- `fix/release-please-config`
- `feat/automated-versioning`
- `fix/docker-publish-tag-trigger`
- `feat/arm64-docker-build`
- `chore/migrate-to-docs-json`
- `fix/sync-docs-rsync-excludes-git`
- `fix/ci-docs-jobs`, `fix/ci-docs-jobs-v2`
## 6. Delete This File
Once all manual steps are complete, delete `MANUAL_STEPS.md` from the repo.
+72
View File
@@ -0,0 +1,72 @@
# Sencho
[![CI](https://github.com/AnsoCode/Sencho/actions/workflows/ci.yml/badge.svg)](https://github.com/AnsoCode/Sencho/actions/workflows/ci.yml)
[![Docker](https://img.shields.io/docker/v/saelix/sencho?sort=semver&label=Docker%20Hub)](https://hub.docker.com/r/saelix/sencho)
[![License](https://img.shields.io/badge/license-pending-lightgrey)](#license)
A self-hosted Docker Compose management dashboard. Manage your stacks, containers, images, volumes, and networks through a modern web UI.
![Sencho Dashboard](docs/images/dashboard.png)
## Features
- **Stack Management** — Create, edit, start, stop, and remove Docker Compose stacks with a built-in Monaco code editor
- **Multi-Node Support** — Manage remote Sencho instances through a transparent HTTP/WebSocket proxy (Distributed API model)
- **App Store** — One-click deployment from LinuxServer.io templates with editable ports, volumes, and environment variables
- **Resource Hub** — Browse and manage images, volumes, and networks with managed/external/unused classification
- **Live Logs** — Aggregated real-time log streaming across all containers with search and filtering
- **Dashboard** — Container stats, CPU/RAM metrics, health checks, and image update notifications
- **Alerts** — Configurable threshold alerts for CPU, RAM, and disk usage
- **Terminal** — In-browser host console and container exec via WebSocket
## Quick Start
```yaml
services:
sencho:
image: saelix/sencho:latest
container_name: sencho
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data
# 1:1 Compose Path Rule: host path MUST match container path
- /opt/docker:/opt/docker
environment:
- COMPOSE_DIR=/opt/docker
- DATA_DIR=/app/data
```
```bash
docker compose up -d
```
Then open `http://your-server:3000` and create your admin account.
See the [full documentation](https://docs.sencho.io) for configuration details, multi-node setup, and more.
## Development
```bash
# Backend (Express + TypeScript)
cd backend && npm install && npm run dev
# Frontend (React + Vite)
cd frontend && npm install && npm run dev
```
The frontend dev server proxies `/api` requests to the backend on port 3000.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and PR guidelines.
## Security
See [SECURITY.md](SECURITY.md) for vulnerability reporting. **Do not open public issues for security vulnerabilities.**
## License
License pending. See [issue #100](https://github.com/AnsoCode/Sencho/issues/100) for the license decision discussion and [LICENSE](LICENSE) for current status.
+29
View File
@@ -0,0 +1,29 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 0.2.x | Yes |
| < 0.2 | No |
## Reporting a Vulnerability
**Please do not open a public issue for security vulnerabilities.**
Instead, use GitHub's private vulnerability reporting:
1. Go to the [Security tab](https://github.com/AnsoCode/Sencho/security) of this repository
2. Click **"Report a vulnerability"**
3. Provide details including: steps to reproduce, impact assessment, and any suggested fixes
You can expect an initial response within 72 hours. We will work with you to understand and address the issue before any public disclosure.
## Security Considerations
Sencho manages Docker containers and has access to the Docker socket. When deploying:
- Always run behind a reverse proxy with TLS in production
- Use strong passwords and rotate JWT secrets
- Restrict network access to the Sencho port
- Review the [security configuration docs](https://docs.sencho.io) for hardening guidance
+1 -1
View File
@@ -14,7 +14,7 @@
},
"keywords": [],
"author": "",
"license": "ISC",
"license": "SEE LICENSE IN LICENSE",
"type": "commonjs",
"bugs": {
"url": "https://github.com/AnsoCode/Sencho/issues"