mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-23 03:27:43 +09:00
Add .claude skills and update .gitignore
Introduce six new .claude skill definitions for developer workflows: audit-subprocess, code-review, create-pr, db-inspect, deploy, and new-feature (each added under .claude/skills/). Update .gitignore to stop globally excluding the .claude directory (so skills can be tracked) and add ignores for generated artifacts and local settings: /.pr, /.reviews, and .claude/settings.local.json.
This commit is contained in:
1 parent
683653d402
commit
023d3c40c5
7 files changed
+621
-4
No files matched your search
@@ -0,0 +1,158 @@
|
||||
---
|
||||
name: audit-subprocess
|
||||
description: Scan backend services for subprocess bugs — missing sudo, missing exception handling on distro-specific commands, raw subprocess calls bypassing system utilities, and container/environment assumptions that break in LXC or restricted environments. Reports issues with file, line, and fix.
|
||||
argument-hint: "[file-or-directory]"
|
||||
---
|
||||
|
||||
Audit subprocess calls in ServerKit backend services for recurring bug patterns.
|
||||
Scope: **${ARGUMENTS:-backend/app/services/}**
|
||||
|
||||
## What to Scan For
|
||||
|
||||
### Pattern 1: Missing `sudo` on privileged commands
|
||||
|
||||
Search for `subprocess.run()` calls that invoke commands requiring root but lack `sudo`:
|
||||
|
||||
- **`systemctl`** (start, stop, restart, enable, disable, daemon-reload) — ALL require sudo
|
||||
- **`firewall-cmd`** (--state, --get-default-zone, --list-services, --list-ports, --list-rich-rules, --get-zones, --zone=*, --add-*, --remove-*, --reload) — ALL require sudo
|
||||
- **`ufw`** (status, enable, disable, allow, deny, delete) — ALL require sudo
|
||||
- **`iptables`** / **`ip6tables`** — ALL require sudo
|
||||
- **`nginx`** (-s reload, -t) — ALL require sudo
|
||||
- **`certbot`** — ALL require sudo
|
||||
- **`freshclam`** — requires sudo
|
||||
|
||||
For each match, check if the command list starts with `'sudo'`. If not, flag it.
|
||||
|
||||
**Ignore**: Commands that legitimately don't need sudo (git, python, pip, npm, node, which, cat, ls, grep, df, free, uptime, whoami, hostname, lsb_release).
|
||||
|
||||
### Pattern 2: Missing exception handling on distro-specific commands
|
||||
|
||||
Search for `subprocess.run()` calls that use distro-specific package managers without `try/except FileNotFoundError`:
|
||||
|
||||
- **`dpkg`** — Debian/Ubuntu only, doesn't exist on RHEL/Fedora/CentOS
|
||||
- **`apt`** / **`apt-get`** — Debian/Ubuntu only
|
||||
- **`rpm`** — RHEL family only, doesn't exist on Debian
|
||||
- **`dnf`** / **`yum`** — RHEL family only
|
||||
|
||||
For each match, check if it's wrapped in a `try/except` that catches `FileNotFoundError` (or a broad `Exception` on the immediate call). If not, flag it.
|
||||
|
||||
**Acceptable**: If the call is guarded by `os.path.exists('/usr/bin/<cmd>')` before the subprocess call, that's fine — don't flag it.
|
||||
|
||||
### Pattern 3: Raw subprocess calls that should use system utilities
|
||||
|
||||
The project provides centralized utilities in `app/utils/system.py`. Flag direct subprocess calls that bypass them:
|
||||
|
||||
- **`subprocess.run(['sudo', 'systemctl', ...])`** → should use `ServiceControl.start/stop/restart/reload/enable/disable/daemon_reload()`
|
||||
- **`subprocess.run(['systemctl', 'is-active', ...])`** → should use `ServiceControl.is_active()`
|
||||
- **`subprocess.run(['systemctl', 'is-enabled', ...])`** → should use `ServiceControl.is_enabled()`
|
||||
- **`subprocess.run(['dpkg', ...])`** or **`subprocess.run(['rpm', ...])`** for package checks → should use `PackageManager.is_installed()`
|
||||
- **`os.path.exists('/usr/bin/apt')`** or similar distro detection → should use `PackageManager.detect()`
|
||||
- **`for path in ['/usr/bin/X', '/usr/sbin/X']: if os.path.exists(path)`** binary search → should use `is_command_available()`
|
||||
- **`subprocess.run(['sudo', 'apt-get', 'install', ...])`** or **`['sudo', 'dnf', 'install', ...]`** → should use `PackageManager.install()`
|
||||
- **`subprocess.run(['sudo', <privileged-cmd>, ...])`** for other privileged commands → should use `run_privileged()`
|
||||
|
||||
**Acceptable exceptions** (do NOT flag these):
|
||||
- Docker CLI calls in `docker_service.py` (uses Docker socket)
|
||||
- Git CLI calls (no privilege needed)
|
||||
- Python/pip in venvs (per-app, no root)
|
||||
- MySQL/PostgreSQL CLI (auth via socket/password)
|
||||
- WP-CLI (`sudo -u www-data` pattern)
|
||||
- Read-only commands (`clamscan`, `fail2ban-client status`, `uname`, `which`, `ssh-keygen`, etc.)
|
||||
|
||||
### Pattern 4: Container/environment assumptions
|
||||
|
||||
Code that assumes bare-metal or KVM and breaks inside LXC containers, Docker, or restricted environments. Search for these patterns:
|
||||
|
||||
#### 4a. Unguarded `/proc` and `/sys` reads
|
||||
|
||||
- **`open('/proc/cpuinfo')`** or similar `/proc/` reads without `try/except (FileNotFoundError, PermissionError)`
|
||||
- **`open('/sys/class/...')`** or `/sys/` reads — often restricted in unprivileged containers
|
||||
- **`/proc/meminfo`**, **`/proc/net/`**, **`/proc/diskstats`** — may be empty or permission-denied
|
||||
|
||||
Flag if the read is NOT wrapped in a try/except that handles `FileNotFoundError` or `PermissionError`.
|
||||
|
||||
#### 4b. `psutil` calls that fail in containers
|
||||
|
||||
- **`psutil.disk_io_counters()`** — returns `None` when `/proc/diskstats` is unavailable
|
||||
- **`psutil.disk_partitions()`** — returns container-internal mounts, not host disks
|
||||
- **`psutil.sensors_temperatures()`** — fails without `/sys/class/thermal/`
|
||||
- **`psutil.sensors_fans()`** — same issue
|
||||
- **`psutil.net_io_counters(pernic=True)`** — may show veth interfaces only
|
||||
|
||||
Flag if the return value is used without a `None` / empty check. For example, `psutil.disk_io_counters().read_bytes` will crash if the call returns `None`.
|
||||
|
||||
#### 4c. Docker socket assumptions
|
||||
|
||||
- **`subprocess.run(['docker', ...])`** without checking if Docker is installed/running first
|
||||
- Direct access to **`/var/run/docker.sock`** without verifying the socket exists
|
||||
- Any Docker operation that doesn't handle `FileNotFoundError` or `ConnectionError`
|
||||
|
||||
Flag if there's no pre-check (e.g., `is_docker_installed()`) or no try/except around the call.
|
||||
|
||||
**Acceptable**: Calls inside `docker_service.py` that are already gated behind `is_docker_installed()` at the API layer.
|
||||
|
||||
#### 4d. Firewall/network commands without capability checks
|
||||
|
||||
- **`firewall-cmd`**, **`ufw`**, **`iptables`** — require `CAP_NET_ADMIN` which is dropped in unprivileged LXC
|
||||
- These commands fail silently or with cryptic errors when capabilities are missing
|
||||
|
||||
Flag if the subprocess call doesn't handle the failure case (no try/except, or no check of `returncode`).
|
||||
|
||||
#### 4e. Hardcoded device paths
|
||||
|
||||
- **`/dev/`** references (e.g., `/dev/sda`, `/dev/null` is fine) — block devices don't exist in containers
|
||||
- **`/dev/fuse`** — FUSE device, unavailable in unprivileged LXC
|
||||
|
||||
Flag hardcoded `/dev/` paths (except `/dev/null`, `/dev/stdin`, `/dev/stdout`, `/dev/stderr`, `/dev/urandom`, `/dev/random`).
|
||||
|
||||
**Acceptable**: Paths discovered dynamically from `psutil` or `lsblk` output.
|
||||
|
||||
## How to Audit
|
||||
|
||||
1. Use **Grep** to find all `subprocess.run(` calls in the target scope
|
||||
2. For each match, read the surrounding context (5-10 lines) to check:
|
||||
- Is `sudo` present for privileged commands?
|
||||
- Is there a `try/except FileNotFoundError` for distro-specific commands?
|
||||
- Is there an `os.path.exists()` guard?
|
||||
- Is there a system utility (`ServiceControl`, `PackageManager`, `run_privileged`, `is_command_available`) that should be used instead?
|
||||
3. Also search for `os.path.exists('/usr/bin/apt')` and similar distro-detection patterns
|
||||
4. Search for `open('/proc/` and `open('/sys/` — check for missing error handling
|
||||
5. Search for `psutil.disk_io_counters`, `psutil.disk_partitions`, `psutil.sensors_` — check return values are guarded against `None`
|
||||
6. Search for `/dev/` string literals — flag hardcoded device paths (except standard ones)
|
||||
7. Search for `docker` subprocess calls outside `docker_service.py` — check for availability guards
|
||||
8. For firewall commands, check that `returncode` is inspected or the call is wrapped in try/except
|
||||
9. Collect all violations
|
||||
|
||||
## Report Format
|
||||
|
||||
For each issue found, report:
|
||||
|
||||
```
|
||||
[PATTERN] file_path:line_number
|
||||
Command: ['systemctl', 'restart', ...]
|
||||
Fix: Add 'sudo' as first element
|
||||
```
|
||||
|
||||
or for Pattern 3:
|
||||
|
||||
```
|
||||
[PATTERN 3] file_path:line_number
|
||||
Command: subprocess.run(['sudo', 'systemctl', 'restart', service], ...)
|
||||
Fix: Use ServiceControl.restart(service)
|
||||
```
|
||||
|
||||
Then provide a summary:
|
||||
|
||||
```
|
||||
## Summary
|
||||
- Files scanned: X
|
||||
- Total subprocess calls: X
|
||||
- Missing sudo: X instances across Y files
|
||||
- Missing exception handling: X instances across Y files
|
||||
- Should use system utilities: X instances across Y files
|
||||
- Container/environment assumptions: X instances across Y files
|
||||
- Clean: X calls
|
||||
```
|
||||
|
||||
If issues are found, ask the user if they want you to fix them automatically.
|
||||
If no issues are found, confirm the codebase is clean for these patterns.
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
name: code-review
|
||||
description: Run a multi-perspective code review on recent changes using specialized reviewer personas. Each reviewer focuses on their domain — security, ops, cross-platform, API design, frontend, and performance. Produces a dated review report.
|
||||
argument-hint: "[file, directory, or git range]"
|
||||
---
|
||||
|
||||
# Code Review — Multi-Perspective Audit
|
||||
|
||||
Review code from the perspective of 6 specialized reviewers, each with their own focus area. Produces a structured report in `.reviews/`.
|
||||
|
||||
## Scope
|
||||
|
||||
Determine what to review based on the argument:
|
||||
|
||||
- **No argument**: Review all uncommitted changes (`git diff` + `git diff --cached`)
|
||||
- **A file or directory path**: Review that specific path
|
||||
- **A git range** (e.g., `main..HEAD`, `HEAD~3`): Review that commit range
|
||||
- **`last`**: Review the last commit (`HEAD~1..HEAD`)
|
||||
|
||||
## The Reviewers
|
||||
|
||||
### Mara — Security
|
||||
|
||||
Focuses on authentication, authorization, and injection vectors.
|
||||
|
||||
- JWT handling: token validation, expiry, refresh flows
|
||||
- SQL injection: raw queries, unparameterized input
|
||||
- XSS: unsanitized user input rendered in responses or frontend
|
||||
- CORS misconfigurations
|
||||
- Path traversal in file operations (`../` in user-supplied paths)
|
||||
- Secrets in code (API keys, passwords, hardcoded tokens)
|
||||
- Missing `@jwt_required()` on API routes that need auth
|
||||
- CSRF protection gaps
|
||||
|
||||
### Raj — Ops & Infrastructure
|
||||
|
||||
Focuses on subprocess calls, privilege escalation, and system operations.
|
||||
|
||||
- Missing `sudo` on privileged commands (systemctl, firewall-cmd, ufw, certbot, nginx)
|
||||
- Raw `subprocess.run()` that should use `run_privileged()`, `ServiceControl`, or `PackageManager`
|
||||
- Missing error handling on subprocess calls (unchecked `returncode`, no try/except)
|
||||
- Hardcoded paths that assume specific filesystem layout
|
||||
- Logging gaps: operations that modify system state without logging what they did
|
||||
- Service restart ordering issues
|
||||
|
||||
### Sol — Cross-Platform & Containers
|
||||
|
||||
Focuses on portability across distros and container environments.
|
||||
|
||||
- Distro-specific commands (`dpkg`, `apt`, `rpm`, `dnf`) without `FileNotFoundError` handling
|
||||
- Unguarded `/proc/` and `/sys/` reads that fail in LXC/containers
|
||||
- `psutil` calls that return `None` in containers (`disk_io_counters`, `sensors_temperatures`) used without null checks
|
||||
- Docker socket assumptions without availability checks
|
||||
- Firewall commands that need `CAP_NET_ADMIN` (dropped in unprivileged LXC)
|
||||
- Hardcoded `/dev/` device paths
|
||||
- Assumptions about init system (systemd vs others)
|
||||
- Package manager detection that only checks one family
|
||||
|
||||
### Kai — API Design
|
||||
|
||||
Focuses on REST conventions, error handling, and request/response patterns.
|
||||
|
||||
- Inconsistent error response format (should always be `{'error': 'message'}, status_code`)
|
||||
- Missing input validation on request body fields
|
||||
- Wrong HTTP status codes (e.g., 200 on error, 404 when it should be 403)
|
||||
- Missing pagination on list endpoints
|
||||
- Endpoints that return too much data (no field filtering)
|
||||
- Inconsistent URL naming (`/api/v1/` prefix, plural nouns)
|
||||
- Missing rate limiting on sensitive endpoints (login, password reset)
|
||||
- N+1 query patterns in endpoints that return lists
|
||||
|
||||
### Lena — Frontend
|
||||
|
||||
Focuses on React patterns, UX quality, and style consistency.
|
||||
|
||||
- Class components or non-hook patterns (should be functional + hooks only)
|
||||
- Inline styles (should use LESS with design system variables)
|
||||
- Missing loading states or error handling on data fetches
|
||||
- Accessibility gaps: missing alt text, aria labels, keyboard navigation
|
||||
- Hardcoded strings that should come from the API or config
|
||||
- Memory leaks: missing cleanup in `useEffect`
|
||||
- Props drilling beyond 3 levels (should use Context)
|
||||
- Missing key props in lists
|
||||
- Console.log left in production code
|
||||
|
||||
### Omar — Performance
|
||||
|
||||
Focuses on efficiency, caching, and resource usage.
|
||||
|
||||
- Synchronous blocking calls that should be async (especially subprocess calls in request handlers)
|
||||
- Missing database indexes on frequently queried columns
|
||||
- Unbounded queries: `SELECT *` without `LIMIT` or pagination
|
||||
- Repeated identical subprocess calls that could be cached
|
||||
- Large file reads loaded entirely into memory
|
||||
- Frontend: unnecessary re-renders, missing `useMemo`/`useCallback` where expensive
|
||||
- Missing `timeout` on subprocess calls or external HTTP requests
|
||||
- Socket.IO events that broadcast too frequently
|
||||
|
||||
## How to Review
|
||||
|
||||
1. Determine the scope from `$ARGUMENTS` and read all relevant code
|
||||
2. For each reviewer, analyze the code **only through their lens** — don't overlap
|
||||
3. Rate each finding:
|
||||
- **Fix** — Bug, vulnerability, or will break in production. Must address.
|
||||
- **Improve** — Works but suboptimal. Should address.
|
||||
- **Note** — Observation or suggestion. Nice to know, no action needed.
|
||||
4. Collect all findings
|
||||
|
||||
## Report
|
||||
|
||||
Create the `.reviews/` directory if it doesn't exist. Write to `.reviews/YYYY-MM-DD-review.md` (use today's date). If a file for today exists, append a counter: `YYYY-MM-DD-2-review.md`.
|
||||
|
||||
```markdown
|
||||
# Code Review — YYYY-MM-DD
|
||||
|
||||
**Scope:** <what was reviewed>
|
||||
**Files reviewed:** N
|
||||
|
||||
## Summary
|
||||
|
||||
| Reviewer | Focus | Fix | Improve | Note |
|
||||
|----------|-------|-----|---------|------|
|
||||
| Mara | Security | N | N | N |
|
||||
| Raj | Ops | N | N | N |
|
||||
| Sol | Cross-Platform | N | N | N |
|
||||
| Kai | API Design | N | N | N |
|
||||
| Lena | Frontend | N | N | N |
|
||||
| Omar | Performance | N | N | N |
|
||||
| **Total** | | **N** | **N** | **N** |
|
||||
|
||||
## Findings
|
||||
|
||||
### Mara — Security
|
||||
|
||||
#### [Fix] Short description
|
||||
`file_path:line_number`
|
||||
Explanation of the issue and why it matters.
|
||||
**Suggested fix:** What to change.
|
||||
|
||||
#### [Improve] Short description
|
||||
...
|
||||
|
||||
### Raj — Ops & Infrastructure
|
||||
...
|
||||
|
||||
### Sol — Cross-Platform & Containers
|
||||
...
|
||||
|
||||
### Kai — API Design
|
||||
...
|
||||
|
||||
### Lena — Frontend
|
||||
...
|
||||
|
||||
### Omar — Performance
|
||||
...
|
||||
|
||||
## Verdict
|
||||
|
||||
**PASS** — No Fix-severity findings. Ship it.
|
||||
or
|
||||
**NEEDS WORK** — N Fix-severity findings must be addressed before merging.
|
||||
```
|
||||
|
||||
After writing the report, print the summary table and verdict to the user. If there are Fix-severity findings, ask if they want you to address them now.
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
name: create-pr
|
||||
description: Generate a pull request title and description from the current branch's commits. Produces a concise summary, optional feature highlights, and collapsible technical details.
|
||||
---
|
||||
|
||||
# Create PR Description
|
||||
|
||||
Generate a pull request title and description that's scannable, informative, and has just enough personality to feel human.
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Gather context (do ALL of these)
|
||||
|
||||
Run these commands to build a complete picture before writing anything:
|
||||
|
||||
```bash
|
||||
# Commit overview
|
||||
git log main..HEAD --oneline --stat
|
||||
|
||||
# Full diff stat for file-level scope
|
||||
git diff main..HEAD --stat
|
||||
|
||||
# Actual code changes — read the diff, don't just skim filenames
|
||||
git diff main..HEAD
|
||||
```
|
||||
|
||||
If the full diff is too large, diff individual areas (backend routes, frontend, storage, etc.) in batches. You must understand **what the code actually does**, not just which files were touched.
|
||||
|
||||
### 2. Write the PR file
|
||||
|
||||
Write the file to `.pr/YYYY-MM-DD.md` (using today's date). Create the `.pr/` directory if it doesn't exist. If a file for today's date already exists, append a counter: `YYYY-MM-DD-2.md`, `YYYY-MM-DD-3.md`, etc.
|
||||
|
||||
The structure depends on whether the PR introduces user-facing features or is purely internal (refactors, bug fixes, infra).
|
||||
|
||||
#### When the PR has user-facing features:
|
||||
|
||||
~~~markdown
|
||||
# <Title>
|
||||
|
||||
<2-3 sentence summary>
|
||||
|
||||
### Highlights
|
||||
|
||||
- Highlight 1
|
||||
- Highlight 2
|
||||
- ...
|
||||
|
||||
<details>
|
||||
<summary>Technical changes</summary>
|
||||
|
||||
- Detail 1
|
||||
- Detail 2
|
||||
- ...
|
||||
|
||||
</details>
|
||||
~~~
|
||||
|
||||
#### When the PR is purely internal (no user-facing features):
|
||||
|
||||
~~~markdown
|
||||
# <Title>
|
||||
|
||||
<2-3 sentence summary>
|
||||
|
||||
<details>
|
||||
<summary>Technical changes</summary>
|
||||
|
||||
- Detail 1
|
||||
- Detail 2
|
||||
- ...
|
||||
|
||||
</details>
|
||||
~~~
|
||||
|
||||
Omit the Highlights section entirely for internal-only PRs — don't force it.
|
||||
|
||||
### Style Rules
|
||||
|
||||
#### Title
|
||||
- Imperative mood, start with a verb (Add, Fix, Refactor, etc.)
|
||||
- Summarize the entire PR scope — not just one commit
|
||||
|
||||
#### Summary
|
||||
- **2-3 sentences max.** This is the elevator pitch, not the full story.
|
||||
- **Open with a touch of personality.** One line that makes the reader smile — a wry observation, a lighthearted remark, a playful metaphor. Not forced, just human. Examples of the energy (don't copy these literally, invent your own each time):
|
||||
- "This one's mostly about cleaning house."
|
||||
- "Turns out the type checker was right to complain."
|
||||
- A playful metaphor about what the code was doing wrong
|
||||
- A wry observation about the state of things before this PR
|
||||
- **Then say what the PR does at a high level.** Name the main change areas (new feature, refactor target, bug fixed) but don't enumerate every file. The personality is in *how* you describe the changes, not in being vague.
|
||||
- **Do not repeat what Highlights or Technical changes already cover.** The summary is the "why" and the big picture; details live below.
|
||||
|
||||
#### Highlights (only when applicable)
|
||||
- One bullet per user-facing feature, behavior change, or notable improvement.
|
||||
- Write from the user's perspective — what they'll notice, not internal implementation.
|
||||
- Plain language, no code references. "Schedules now respect your configured timezone" not "`SchedulerService` gains a `timezone` attribute".
|
||||
- 3-7 bullets is the sweet spot. If you can only think of 1-2, fold them into the summary and skip this section.
|
||||
|
||||
#### Technical changes (inside the accordion)
|
||||
- One bullet per discrete change. Be specific — name files, classes, functions, patterns.
|
||||
- Format: `backtick code references` for identifiers, plain text for descriptions.
|
||||
- Every meaningful change in the diff must have a bullet. If a change touches security (CORS, auth, SQL injection), error handling, accessibility, or concurrency, it gets its own bullet — do not bury these.
|
||||
- Bullets should describe the mechanism, not just the intent. "Race condition in `get_or_create_chat` fixed by moving creation inside the lookup session" is good. "Fix database issues" is not.
|
||||
- Group related changes together (all typing fixes, all security hardening, all API changes, etc.)
|
||||
|
||||
#### General
|
||||
- **No test plan section.** Do not include "Test plan" or "Testing".
|
||||
- **No mention of tests.** Do not reference test files, test results, or testing.
|
||||
- **No emoji.**
|
||||
- **No "Generated by" footer.**
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: db-inspect
|
||||
description: Inspect the ServerKit SQLite database — show tables, schemas, row counts, and run queries. Runs via WSL for local dev or SSH MCP for production. Use when debugging data issues or understanding the current database state.
|
||||
disable-model-invocation: true
|
||||
argument-hint: "[query or table-name]"
|
||||
allowed-tools: Bash, mcp__ssh-mcp__exec
|
||||
---
|
||||
|
||||
Inspect the ServerKit database. Argument: **$ARGUMENTS**
|
||||
|
||||
## Database Location
|
||||
|
||||
- **Local dev**: `backend/instance/serverkit.db` (relative to project root)
|
||||
- **Production**: `/opt/serverkit/backend/instance/serverkit.db` (access via SSH MCP)
|
||||
|
||||
## If no argument or argument is "schema"
|
||||
|
||||
Show the full database schema:
|
||||
```bash
|
||||
sqlite3 backend/instance/serverkit.db '.schema'
|
||||
```
|
||||
|
||||
And row counts for all tables:
|
||||
```bash
|
||||
sqlite3 backend/instance/serverkit.db "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;"
|
||||
```
|
||||
Then for each table, get the row count and present as a formatted table: Table Name | Row Count
|
||||
|
||||
## If argument is a table name
|
||||
|
||||
Show the schema and last 10 rows:
|
||||
```bash
|
||||
sqlite3 -header -column backend/instance/serverkit.db 'PRAGMA table_info(<table>);'
|
||||
sqlite3 -header -column backend/instance/serverkit.db 'SELECT * FROM <table> ORDER BY id DESC LIMIT 10;'
|
||||
```
|
||||
|
||||
## If argument looks like a SQL query
|
||||
|
||||
Run it directly:
|
||||
```bash
|
||||
sqlite3 -header -column backend/instance/serverkit.db '<query>'
|
||||
```
|
||||
|
||||
## If argument is "production" or "prod"
|
||||
|
||||
Run the schema/overview commands on the production server via SSH MCP instead, using `/opt/serverkit/backend/instance/serverkit.db`.
|
||||
|
||||
## Safety
|
||||
|
||||
- NEVER run DELETE, DROP, UPDATE, or INSERT queries unless explicitly asked
|
||||
- Always show the query before running it
|
||||
- For production, double-check with the user before running any query
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
name: deploy
|
||||
description: Deploy ServerKit to the production server via SSH. Runs update, rebuilds frontend, restarts services, and performs health checks. Use when pushing changes to production.
|
||||
disable-model-invocation: true
|
||||
argument-hint: "[branch]"
|
||||
allowed-tools: mcp__ssh-mcp__exec, mcp__ssh-mcp__sudo-exec, Bash
|
||||
---
|
||||
|
||||
Deploy ServerKit to the production server. Target branch: **${ARGUMENTS:-main}**
|
||||
|
||||
## Pre-deploy Checks
|
||||
|
||||
1. Check the current git status locally — warn if there are uncommitted changes
|
||||
2. Check if the local branch is ahead of remote — warn if unpushed commits exist
|
||||
|
||||
## Deploy Steps
|
||||
|
||||
Run these on the remote server via SSH MCP:
|
||||
|
||||
### 1. Check current state
|
||||
```
|
||||
serverkit version
|
||||
serverkit status
|
||||
```
|
||||
|
||||
### 2. Run the update
|
||||
```
|
||||
serverkit update --branch ${ARGUMENTS:-main}
|
||||
```
|
||||
|
||||
This will:
|
||||
- Stop services
|
||||
- Pull latest code from the target branch
|
||||
- Update Python dependencies
|
||||
- Sync app templates
|
||||
- Rebuild frontend Docker container
|
||||
- Restart all services
|
||||
|
||||
### 3. Health check (wait 10 seconds after update)
|
||||
```
|
||||
curl -s http://127.0.0.1:5000/api/v1/system/health
|
||||
curl -s http://localhost
|
||||
serverkit status
|
||||
```
|
||||
|
||||
### 4. Report results
|
||||
|
||||
Report clearly:
|
||||
- Previous version vs new version
|
||||
- Which branch is deployed
|
||||
- Backend status (systemd)
|
||||
- Frontend status (Docker)
|
||||
- API health check result
|
||||
- Any errors from logs: `journalctl -u serverkit -n 20 --no-pager`
|
||||
|
||||
## On Failure
|
||||
|
||||
If any health check fails:
|
||||
1. Show the last 50 lines of backend logs: `journalctl -u serverkit -n 50 --no-pager`
|
||||
2. Show frontend Docker logs: `cd /opt/serverkit && docker compose logs --tail=50`
|
||||
3. Suggest rollback: `serverkit update --branch main --force`
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: new-feature
|
||||
description: Scaffold a new full-stack feature for ServerKit with Flask backend (model, service, API blueprint) and React frontend (page, styles, route). Use when creating new modules, pages, or API endpoints.
|
||||
disable-model-invocation: true
|
||||
argument-hint: "[feature-name]"
|
||||
---
|
||||
|
||||
Scaffold a new full-stack feature named **$ARGUMENTS** for ServerKit.
|
||||
|
||||
Follow these steps in order:
|
||||
|
||||
## 1. Backend Model
|
||||
|
||||
Create `backend/app/models/$ARGUMENTS.py` with:
|
||||
- SQLAlchemy model class (PascalCase name)
|
||||
- Standard columns: `id`, `created_at`, `updated_at`
|
||||
- A `to_dict()` method returning JSON-serializable data
|
||||
- Follow existing model patterns in `backend/app/models/`
|
||||
|
||||
## 2. Backend Service
|
||||
|
||||
Create `backend/app/services/${ARGUMENTS}_service.py` with:
|
||||
- Stateless module functions (no classes unless stateful)
|
||||
- CRUD operations: `create_*`, `get_*`, `get_all_*`, `update_*`, `delete_*`
|
||||
- Consistent error handling returning `{'error': 'message'}, status_code`
|
||||
- Import and use the model from step 1
|
||||
|
||||
## 3. Backend API Blueprint
|
||||
|
||||
Create `backend/app/api/$ARGUMENTS.py` with:
|
||||
- Flask Blueprint named `${ARGUMENTS}_bp`
|
||||
- RESTful routes prefixed with the feature name
|
||||
- All routes decorated with `@jwt_required()`
|
||||
- JSON request parsing and response formatting
|
||||
- Call service functions from step 2
|
||||
|
||||
Then register the blueprint in `backend/app/__init__.py`:
|
||||
```python
|
||||
from app.api.$ARGUMENTS import ${ARGUMENTS}_bp
|
||||
app.register_blueprint(${ARGUMENTS}_bp, url_prefix='/api/v1/$ARGUMENTS')
|
||||
```
|
||||
|
||||
## 4. Frontend API Methods
|
||||
|
||||
Add methods to `frontend/src/services/api.js` in the `ApiService` class:
|
||||
- `get$ARGUMENTS()`, `create$ARGUMENTS()`, `update$ARGUMENTS()`, `delete$ARGUMENTS()`
|
||||
- Follow the existing pattern of other API methods in that file
|
||||
|
||||
## 5. Frontend Page
|
||||
|
||||
Create `frontend/src/pages/$ARGUMENTS.jsx` with:
|
||||
- Functional component using React hooks
|
||||
- Fetch data on mount using the API methods from step 4
|
||||
- Basic CRUD UI with table/list and form
|
||||
- Loading states and error handling
|
||||
- Import the LESS stylesheet from step 6
|
||||
|
||||
Then add the route in `frontend/src/App.jsx` inside the authenticated routes.
|
||||
|
||||
## 6. Frontend Styles
|
||||
|
||||
Create `frontend/src/styles/pages/$ARGUMENTS.less` with:
|
||||
- BEM-like naming: `.${ARGUMENTS}__element--modifier`
|
||||
- Use existing design system variables (`@card-bg`, `@primary-color`, `@spacing-md`, etc.)
|
||||
- Import the new file in `frontend/src/styles/main.less`
|
||||
|
||||
## Rules
|
||||
|
||||
- Python: PEP 8, type hints where helpful
|
||||
- React: Functional components with hooks only, PascalCase filenames
|
||||
- LESS: No inline styles, use design system variables
|
||||
- One logical change per commit
|
||||
+3
-4
@@ -36,10 +36,6 @@
|
||||
Thumbs.db
|
||||
nul
|
||||
|
||||
# Claude Code
|
||||
/.claude/
|
||||
/.claude_/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
@@ -62,3 +58,6 @@ new_templates/
|
||||
backend/dev-data/
|
||||
/.vscode
|
||||
/.vscode1
|
||||
/.pr
|
||||
/.reviews
|
||||
/.claude/settings.local.json
|
||||
Reference in new issue
Block a user