Initial commit
This commit is contained in:
12
.claude-plugin/plugin.json
Normal file
12
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "stack-creator",
|
||||||
|
"description": "Create new GitLab stack projects with proper directory structure, git configuration (main branch, ff-only), validation hooks, and comprehensive documentation. Integrates stack-validator, secrets-manager, docker-validation, and config-generator. Complete only when all validations pass",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"author": {
|
||||||
|
"name": "rknall",
|
||||||
|
"email": "zhongweili@tubi.tv"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# stack-creator
|
||||||
|
|
||||||
|
Create new GitLab stack projects with proper directory structure, git configuration (main branch, ff-only), validation hooks, and comprehensive documentation. Integrates stack-validator, secrets-manager, docker-validation, and config-generator. Complete only when all validations pass
|
||||||
0
SKILL_COMPLETION.md
Normal file
0
SKILL_COMPLETION.md
Normal file
735
git-hooks-guide.md
Normal file
735
git-hooks-guide.md
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
# Git Hooks and Validation Scripts Guide
|
||||||
|
|
||||||
|
This guide provides comprehensive examples and guidelines for git hooks and validation scripts used in GitLab Stack projects.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Git hooks are scripts that run automatically at specific points in the git workflow. For GitLab Stack projects, we use hooks to ensure validation before commits.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
project-name/
|
||||||
|
├── .git/
|
||||||
|
│ └── hooks/
|
||||||
|
│ └── pre-commit # Installed hook
|
||||||
|
└── scripts/
|
||||||
|
├── pre-commit # Source hook script
|
||||||
|
├── validate-stack.sh # Full validation
|
||||||
|
└── setup-hooks.sh # Hook installer
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Scripts
|
||||||
|
|
||||||
|
### 1. scripts/pre-commit
|
||||||
|
|
||||||
|
The pre-commit hook runs before each commit to validate the stack.
|
||||||
|
|
||||||
|
**Location**: `scripts/pre-commit`
|
||||||
|
**Installed to**: `.git/hooks/pre-commit`
|
||||||
|
**When it runs**: Before `git commit`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Pre-commit hook for GitLab Stack validation
|
||||||
|
# Prevents commits that violate stack patterns
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo "Pre-commit validation"
|
||||||
|
echo "========================================="
|
||||||
|
echo
|
||||||
|
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Check 1: Secrets in staged files
|
||||||
|
echo "1. Checking for secrets in staged files..."
|
||||||
|
if git diff --cached --name-only | grep -qE "secrets/.*[^.gitkeep]|\.env$"; then
|
||||||
|
echo -e "${RED}✗ ERROR: Attempting to commit secrets or .env file!${NC}"
|
||||||
|
echo " Secrets should NEVER be committed to git."
|
||||||
|
echo " Files detected:"
|
||||||
|
git diff --cached --name-only | grep -E "secrets/.*[^.gitkeep]|\.env$" | sed 's/^/ /'
|
||||||
|
((ERRORS++))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ No secrets in staged files${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check 2: Root-owned files
|
||||||
|
echo "2. Checking for root-owned files..."
|
||||||
|
if find . -user root -not -path "./.git/*" 2>/dev/null | grep -q .; then
|
||||||
|
echo -e "${RED}✗ ERROR: Root-owned files detected!${NC}"
|
||||||
|
echo " All files should be owned by the user running Docker."
|
||||||
|
echo " Files detected:"
|
||||||
|
find . -user root -not -path "./.git/*" 2>/dev/null | sed 's/^/ /'
|
||||||
|
echo
|
||||||
|
echo " Fix with: sudo chown -R \$USER:\$USER ."
|
||||||
|
((ERRORS++))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ No root-owned files${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check 3: Secrets in file content (basic check)
|
||||||
|
echo "3. Checking for hardcoded secrets in code..."
|
||||||
|
SUSPICIOUS_PATTERNS=(
|
||||||
|
"password\s*=\s*['\"][^'\"]+['\"]"
|
||||||
|
"api[_-]?key\s*=\s*['\"][^'\"]+['\"]"
|
||||||
|
"secret\s*=\s*['\"][^'\"]+['\"]"
|
||||||
|
"token\s*=\s*['\"][^'\"]+['\"]"
|
||||||
|
)
|
||||||
|
|
||||||
|
FOUND_SECRETS=false
|
||||||
|
for pattern in "${SUSPICIOUS_PATTERNS[@]}"; do
|
||||||
|
if git diff --cached | grep -iE "$pattern" | grep -v "\.example" | grep -q .; then
|
||||||
|
if [ "$FOUND_SECRETS" = false ]; then
|
||||||
|
echo -e "${YELLOW}⚠ WARNING: Possible hardcoded secrets detected:${NC}"
|
||||||
|
FOUND_SECRETS=true
|
||||||
|
fi
|
||||||
|
git diff --cached | grep -iE "$pattern" | grep -v "\.example" | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$FOUND_SECRETS" = true ]; then
|
||||||
|
echo
|
||||||
|
echo " Review these carefully. Use environment variables or Docker secrets instead."
|
||||||
|
echo " If these are false positives, you can proceed."
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ No obvious hardcoded secrets${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check 4: Full stack validation (if available)
|
||||||
|
if [ -x "./scripts/validate-stack.sh" ]; then
|
||||||
|
echo "4. Running full stack validation..."
|
||||||
|
if ! ./scripts/validate-stack.sh; then
|
||||||
|
echo -e "${RED}✗ ERROR: Stack validation failed!${NC}"
|
||||||
|
echo " Fix all issues before committing."
|
||||||
|
echo " Or use 'git commit --no-verify' to skip (NOT recommended)."
|
||||||
|
((ERRORS++))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ Stack validation passed${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Skipping stack validation (./scripts/validate-stack.sh not found)${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Final result
|
||||||
|
echo "========================================="
|
||||||
|
if [ $ERRORS -gt 0 ]; then
|
||||||
|
echo -e "${RED}Pre-commit validation FAILED with $ERRORS error(s)${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
echo
|
||||||
|
echo "To skip this validation (NOT recommended):"
|
||||||
|
echo " git commit --no-verify"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Pre-commit validation PASSED!${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage**:
|
||||||
|
```bash
|
||||||
|
# Automatic - runs on every commit
|
||||||
|
git commit -m "message"
|
||||||
|
|
||||||
|
# Skip validation (emergency only)
|
||||||
|
git commit --no-verify -m "message"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. scripts/validate-stack.sh
|
||||||
|
|
||||||
|
Comprehensive validation script that runs all validators.
|
||||||
|
|
||||||
|
**Location**: `scripts/validate-stack.sh`
|
||||||
|
**When to run**: Before deployment, in CI/CD, or manually
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Full GitLab Stack validation
|
||||||
|
# Runs all validators to ensure stack compliance
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}========================================"
|
||||||
|
echo "GitLab Stack Validation"
|
||||||
|
echo "========================================${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
ERRORS=0
|
||||||
|
WARNINGS=0
|
||||||
|
|
||||||
|
# Check if we're in a stack directory
|
||||||
|
if [ ! -f "docker-compose.yml" ]; then
|
||||||
|
echo -e "${RED}✗ ERROR: docker-compose.yml not found!${NC}"
|
||||||
|
echo " Are you in a stack directory?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validation 1: Stack Validator
|
||||||
|
echo -e "${BLUE}[1/4] Running stack-validator...${NC}"
|
||||||
|
if command -v claude-code >/dev/null 2>&1; then
|
||||||
|
if claude-code run stack-validator 2>&1 | tee /tmp/stack-validator.log; then
|
||||||
|
echo -e "${GREEN}✓ Stack validation passed${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Stack validation failed${NC}"
|
||||||
|
echo " Review output above for details"
|
||||||
|
((ERRORS++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Claude Code not available, skipping stack-validator${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Validation 2: Secrets Manager
|
||||||
|
echo -e "${BLUE}[2/4] Running secrets-manager validation...${NC}"
|
||||||
|
if command -v claude-code >/dev/null 2>&1; then
|
||||||
|
if claude-code run secrets-manager --validate 2>&1 | tee /tmp/secrets-manager.log; then
|
||||||
|
echo -e "${GREEN}✓ Secrets validation passed${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Secrets validation failed${NC}"
|
||||||
|
echo " Review output above for details"
|
||||||
|
((ERRORS++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Claude Code not available, running basic secrets check${NC}"
|
||||||
|
|
||||||
|
# Basic secrets check without Claude Code
|
||||||
|
if find secrets/ -type f ! -name ".gitkeep" 2>/dev/null | grep -q .; then
|
||||||
|
if grep -r "DOCKER_SECRET" docker-compose.yml >/dev/null 2>&1; then
|
||||||
|
echo -e "${GREEN}✓ Basic secrets check passed${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Secrets files found but not referenced in docker-compose.yml${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ No secrets configured${NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Validation 3: Docker Validator
|
||||||
|
echo -e "${BLUE}[3/4] Running docker-validation...${NC}"
|
||||||
|
if command -v claude-code >/dev/null 2>&1; then
|
||||||
|
if claude-code run docker-validation 2>&1 | tee /tmp/docker-validation.log; then
|
||||||
|
echo -e "${GREEN}✓ Docker validation passed${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Docker validation failed${NC}"
|
||||||
|
echo " Review output above for details"
|
||||||
|
((ERRORS++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Claude Code not available, running basic Docker checks${NC}"
|
||||||
|
|
||||||
|
# Basic docker-compose syntax check
|
||||||
|
if docker compose config >/dev/null 2>&1; then
|
||||||
|
echo -e "${GREEN}✓ docker-compose.yml syntax valid${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ docker-compose.yml syntax invalid${NC}"
|
||||||
|
((ERRORS++))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Validation 4: File Ownership
|
||||||
|
echo -e "${BLUE}[4/4] Checking file ownership...${NC}"
|
||||||
|
if find . -user root -not -path "./.git/*" 2>/dev/null | grep -q .; then
|
||||||
|
echo -e "${RED}✗ Root-owned files detected:${NC}"
|
||||||
|
find . -user root -not -path "./.git/*" 2>/dev/null | sed 's/^/ /'
|
||||||
|
echo
|
||||||
|
echo " Fix with: sudo chown -R \$USER:\$USER ."
|
||||||
|
((ERRORS++))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ No root-owned files${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Additional checks
|
||||||
|
echo -e "${BLUE}Additional checks:${NC}"
|
||||||
|
|
||||||
|
# Check .env vs .env.example sync
|
||||||
|
if [ -f ".env.example" ]; then
|
||||||
|
ENV_KEYS=$(grep -v '^#' .env.example 2>/dev/null | grep '=' | cut -d= -f1 | sort)
|
||||||
|
if [ -f ".env" ]; then
|
||||||
|
ACTUAL_KEYS=$(grep -v '^#' .env 2>/dev/null | grep '=' | cut -d= -f1 | sort)
|
||||||
|
if [ "$ENV_KEYS" != "$ACTUAL_KEYS" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ .env and .env.example keys don't match${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ .env synced with .env.example${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ .env file not found (expected from .env.example)${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check git setup
|
||||||
|
if [ -d ".git" ]; then
|
||||||
|
# Check default branch
|
||||||
|
DEFAULT_BRANCH=$(git config init.defaultBranch 2>/dev/null || echo "")
|
||||||
|
if [ "$DEFAULT_BRANCH" = "main" ]; then
|
||||||
|
echo -e "${GREEN}✓ Git default branch: main${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Git default branch not set to 'main'${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check merge strategy
|
||||||
|
MERGE_FF=$(git config merge.ff 2>/dev/null || echo "")
|
||||||
|
if [ "$MERGE_FF" = "only" ]; then
|
||||||
|
echo -e "${GREEN}✓ Git merge strategy: ff-only${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Git merge strategy not set to 'ff-only'${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Not a git repository${NC}"
|
||||||
|
((WARNINGS++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Final report
|
||||||
|
echo -e "${BLUE}========================================"
|
||||||
|
echo "Validation Summary"
|
||||||
|
echo "========================================${NC}"
|
||||||
|
|
||||||
|
if [ $ERRORS -gt 0 ]; then
|
||||||
|
echo -e "${RED}FAILED: $ERRORS error(s) found${NC}"
|
||||||
|
if [ $WARNINGS -gt 0 ]; then
|
||||||
|
echo -e "${YELLOW}$WARNINGS warning(s) found${NC}"
|
||||||
|
fi
|
||||||
|
echo "========================================${NC}"
|
||||||
|
exit 1
|
||||||
|
elif [ $WARNINGS -gt 0 ]; then
|
||||||
|
echo -e "${YELLOW}PASSED with $WARNINGS warning(s)${NC}"
|
||||||
|
echo "========================================${NC}"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}ALL VALIDATIONS PASSED!${NC}"
|
||||||
|
echo "========================================${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage**:
|
||||||
|
```bash
|
||||||
|
# Run full validation
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
|
||||||
|
# In CI/CD
|
||||||
|
./scripts/validate-stack.sh || exit 1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. scripts/setup-hooks.sh
|
||||||
|
|
||||||
|
Script to install git hooks from scripts/ to .git/hooks/
|
||||||
|
|
||||||
|
**Location**: `scripts/setup-hooks.sh`
|
||||||
|
**When to run**: After cloning, during stack creation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Install git hooks from scripts/ to .git/hooks/
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo "Installing git hooks..."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check if .git exists
|
||||||
|
if [ ! -d ".git" ]; then
|
||||||
|
echo -e "${RED}✗ ERROR: Not a git repository!${NC}"
|
||||||
|
echo " Initialize git first: git init"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure hooks directory exists
|
||||||
|
mkdir -p .git/hooks
|
||||||
|
|
||||||
|
INSTALLED=0
|
||||||
|
FAILED=0
|
||||||
|
|
||||||
|
# Install pre-commit hook
|
||||||
|
if [ -f "scripts/pre-commit" ]; then
|
||||||
|
if cp scripts/pre-commit .git/hooks/pre-commit; then
|
||||||
|
chmod +x .git/hooks/pre-commit
|
||||||
|
echo -e "${GREEN}✓ Installed pre-commit hook${NC}"
|
||||||
|
((INSTALLED++))
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Failed to install pre-commit hook${NC}"
|
||||||
|
((FAILED++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ scripts/pre-commit not found, skipping${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install pre-push hook (if exists)
|
||||||
|
if [ -f "scripts/pre-push" ]; then
|
||||||
|
if cp scripts/pre-push .git/hooks/pre-push; then
|
||||||
|
chmod +x .git/hooks/pre-push
|
||||||
|
echo -e "${GREEN}✓ Installed pre-push hook${NC}"
|
||||||
|
((INSTALLED++))
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Failed to install pre-push hook${NC}"
|
||||||
|
((FAILED++))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "========================================="
|
||||||
|
if [ $FAILED -gt 0 ]; then
|
||||||
|
echo -e "${RED}Installation completed with $FAILED error(s)${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
exit 1
|
||||||
|
elif [ $INSTALLED -eq 0 ]; then
|
||||||
|
echo -e "${YELLOW}No hooks installed${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}Successfully installed $INSTALLED hook(s)!${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
echo
|
||||||
|
echo "Hooks will now run automatically:"
|
||||||
|
echo " - pre-commit: Before each commit"
|
||||||
|
echo
|
||||||
|
echo "To skip hooks (emergency only):"
|
||||||
|
echo " git commit --no-verify"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage**:
|
||||||
|
```bash
|
||||||
|
# Install hooks
|
||||||
|
./scripts/setup-hooks.sh
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
ls -la .git/hooks/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Optional Hooks
|
||||||
|
|
||||||
|
### scripts/pre-push (Optional)
|
||||||
|
|
||||||
|
Runs before `git push` to ensure remote-ready state.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Pre-push hook for GitLab Stack
|
||||||
|
# Runs before pushing to remote
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo "Pre-push validation"
|
||||||
|
echo "========================================="
|
||||||
|
echo
|
||||||
|
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Run full validation before push
|
||||||
|
echo "Running full stack validation..."
|
||||||
|
if [ -x "./scripts/validate-stack.sh" ]; then
|
||||||
|
if ! ./scripts/validate-stack.sh; then
|
||||||
|
echo -e "${RED}✗ Stack validation failed!${NC}"
|
||||||
|
echo " Fix issues before pushing."
|
||||||
|
((ERRORS++))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ ./scripts/validate-stack.sh not found${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for uncommitted changes
|
||||||
|
if ! git diff-index --quiet HEAD --; then
|
||||||
|
echo -e "${YELLOW}⚠ WARNING: You have uncommitted changes${NC}"
|
||||||
|
echo " Consider committing them before pushing."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
if [ $ERRORS -gt 0 ]; then
|
||||||
|
echo -e "${RED}Pre-push validation FAILED${NC}"
|
||||||
|
echo "To skip: git push --no-verify"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Pre-push validation PASSED${NC}"
|
||||||
|
exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD Integration
|
||||||
|
|
||||||
|
### GitLab CI (.gitlab-ci.yml)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
stages:
|
||||||
|
- validate
|
||||||
|
- build
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
validate:
|
||||||
|
stage: validate
|
||||||
|
image: docker:latest
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
before_script:
|
||||||
|
- apk add --no-cache bash findutils
|
||||||
|
script:
|
||||||
|
- chmod +x ./scripts/validate-stack.sh
|
||||||
|
- ./scripts/validate-stack.sh
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
|
- main
|
||||||
|
```
|
||||||
|
|
||||||
|
### GitHub Actions (.github/workflows/validate.yml)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Stack Validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Run stack validation
|
||||||
|
run: |
|
||||||
|
chmod +x ./scripts/validate-stack.sh
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Always Make Scripts Executable
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x scripts/*.sh
|
||||||
|
chmod +x scripts/pre-commit
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test Hooks Before Committing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test pre-commit manually
|
||||||
|
./scripts/pre-commit
|
||||||
|
|
||||||
|
# Test validation
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Document Hook Behavior
|
||||||
|
|
||||||
|
Include in README.md:
|
||||||
|
```markdown
|
||||||
|
## Git Hooks
|
||||||
|
|
||||||
|
This project uses git hooks for validation:
|
||||||
|
- **pre-commit**: Validates before each commit
|
||||||
|
- To skip: `git commit --no-verify` (emergency only)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Provide Skip Option
|
||||||
|
|
||||||
|
Always allow users to skip in emergencies:
|
||||||
|
```bash
|
||||||
|
git commit --no-verify -m "emergency fix"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Keep Hooks Fast
|
||||||
|
|
||||||
|
- Pre-commit should run in < 10 seconds
|
||||||
|
- Use quick checks when possible
|
||||||
|
- Defer expensive checks to CI/CD
|
||||||
|
|
||||||
|
### 6. Clear Error Messages
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo -e "${RED}✗ ERROR: Clear description${NC}"
|
||||||
|
echo " Explanation of what went wrong"
|
||||||
|
echo " How to fix it"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Exit Codes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Success
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
# Failure
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
# Always use set -e to catch errors
|
||||||
|
set -euo pipefail
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Hook Not Running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if hook is installed
|
||||||
|
ls -la .git/hooks/pre-commit
|
||||||
|
|
||||||
|
# Check if executable
|
||||||
|
chmod +x .git/hooks/pre-commit
|
||||||
|
|
||||||
|
# Reinstall hooks
|
||||||
|
./scripts/setup-hooks.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hook Fails Unexpectedly
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run hook manually to see output
|
||||||
|
./scripts/pre-commit
|
||||||
|
|
||||||
|
# Check validation separately
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
|
||||||
|
# Debug with set -x
|
||||||
|
bash -x scripts/pre-commit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Skip Hook Temporarily
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Skip pre-commit
|
||||||
|
git commit --no-verify -m "message"
|
||||||
|
|
||||||
|
# Skip pre-push
|
||||||
|
git push --no-verify
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission Denied
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Make script executable
|
||||||
|
chmod +x scripts/pre-commit
|
||||||
|
chmod +x scripts/validate-stack.sh
|
||||||
|
|
||||||
|
# Reinstall hooks
|
||||||
|
./scripts/setup-hooks.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### Adding Custom Checks
|
||||||
|
|
||||||
|
Edit `scripts/pre-commit`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add custom check
|
||||||
|
echo "5. Running custom validation..."
|
||||||
|
if ! ./scripts/my-custom-check.sh; then
|
||||||
|
echo -e "${RED}✗ Custom validation failed${NC}"
|
||||||
|
((ERRORS++))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ Custom validation passed${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adjusting Validation Strictness
|
||||||
|
|
||||||
|
**Strict Mode** (recommended for production):
|
||||||
|
```bash
|
||||||
|
# Fail on any error
|
||||||
|
set -euo pipefail
|
||||||
|
```
|
||||||
|
|
||||||
|
**Lenient Mode** (development only):
|
||||||
|
```bash
|
||||||
|
# Continue on errors, just report
|
||||||
|
set -uo pipefail
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment-Specific Hooks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check environment
|
||||||
|
if [ "${ENV:-}" = "production" ]; then
|
||||||
|
# Strict validation for production
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
else
|
||||||
|
# Lenient for development
|
||||||
|
echo "Development environment, skipping some checks"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Git hooks ensure:
|
||||||
|
- ✅ No secrets committed
|
||||||
|
- ✅ No root-owned files
|
||||||
|
- ✅ Full stack validation before commit
|
||||||
|
- ✅ Consistent code quality
|
||||||
|
- ✅ Automated validation in workflow
|
||||||
|
|
||||||
|
All scripts are:
|
||||||
|
- Executable (`chmod +x`)
|
||||||
|
- Well-documented
|
||||||
|
- Provide clear error messages
|
||||||
|
- Support emergency skip (`--no-verify`)
|
||||||
|
- Integrate with CI/CD
|
||||||
61
plugin.lock.json
Normal file
61
plugin.lock.json
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:rknall/claude-skills:stack-creator",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "c70a6893224ba93b0a28130010973fba7245f209",
|
||||||
|
"treeHash": "6d8faf1c532b90a3373db5c888a10fffdf8410f7c1ff83728560c76b13d337ef",
|
||||||
|
"generatedAt": "2025-11-28T10:27:59.895342Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "stack-creator",
|
||||||
|
"description": "Create new GitLab stack projects with proper directory structure, git configuration (main branch, ff-only), validation hooks, and comprehensive documentation. Integrates stack-validator, secrets-manager, docker-validation, and config-generator. Complete only when all validations pass",
|
||||||
|
"version": "0.1.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "SKILL_COMPLETION.md",
|
||||||
|
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "git-hooks-guide.md",
|
||||||
|
"sha256": "66c94275fe1c6f566d33231e2f23b7fda58c578f677d9bfdabeaefa78abaafc0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "b3998eac9e8449160b00792c37cf1ffb2d644c5894f7c87e0326d4a6e90fe8d6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "SKILL.md",
|
||||||
|
"sha256": "22fd3394c4eccdc9846a96f028983116581a8791a31becd5ac7fb9c3d3173a3c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "templates-reference.md",
|
||||||
|
"sha256": "31c1e5e5ac517e035e534c123faa5f9f2440ce87b1a2ce2334e589c94e2e7ce1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "workflow-examples.md",
|
||||||
|
"sha256": "e4f0a59a3a31aa76ae3813c9225485ebb7b08f5428aba8f880ffc05d8601e1d3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "4655e14dd9646d0206b1c5b55446acfb34943315588978253ecec2e5cbd761fc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "6d8faf1c532b90a3373db5c888a10fffdf8410f7c1ff83728560c76b13d337ef"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
905
templates-reference.md
Normal file
905
templates-reference.md
Normal file
@@ -0,0 +1,905 @@
|
|||||||
|
# Stack Templates Reference
|
||||||
|
|
||||||
|
This document provides ready-to-use templates for common stack configurations.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [docker-compose.yml Templates](#docker-composeyml-templates)
|
||||||
|
2. [.env.example Templates](#envexample-templates)
|
||||||
|
3. [Service Configuration Templates](#service-configuration-templates)
|
||||||
|
4. [Documentation Templates](#documentation-templates)
|
||||||
|
5. [Git Configuration Templates](#git-configuration-templates)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## docker-compose.yml Templates
|
||||||
|
|
||||||
|
### Minimal Stack (Development)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
container_name: ${PROJECT_NAME:-app}_main
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
ports:
|
||||||
|
- "${APP_PORT:-3000}:3000"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
### Web Stack (nginx + Application)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: ${PROJECT_NAME:-app}_nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${NGINX_HTTP_PORT:-80}:80"
|
||||||
|
- "${NGINX_HTTPS_PORT:-443}:443"
|
||||||
|
volumes:
|
||||||
|
- ./config/nginx:/etc/nginx/conf.d:ro
|
||||||
|
- ./ssl:/etc/nginx/ssl:ro
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
container_name: ${PROJECT_NAME:-app}_main
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Stack (nginx + App + PostgreSQL + Redis)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: ${PROJECT_NAME:-app}_nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${NGINX_HTTP_PORT:-80}:80"
|
||||||
|
- "${NGINX_HTTPS_PORT:-443}:443"
|
||||||
|
volumes:
|
||||||
|
- ./config/nginx:/etc/nginx/conf.d:ro
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
container_name: ${PROJECT_NAME:-app}_main
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DB_HOST=postgres
|
||||||
|
- DB_PORT=5432
|
||||||
|
- DB_NAME=${POSTGRES_DB}
|
||||||
|
- REDIS_HOST=redis
|
||||||
|
- REDIS_PORT=6379
|
||||||
|
secrets:
|
||||||
|
- db_password
|
||||||
|
- redis_password
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: ${PROJECT_NAME:-app}_postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB}
|
||||||
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
|
secrets:
|
||||||
|
- source: db_password
|
||||||
|
target: /run/secrets/db_password
|
||||||
|
volumes:
|
||||||
|
- ./config/postgres:/docker-entrypoint-initdb.d:ro
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: ${PROJECT_NAME:-app}_redis
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
|
||||||
|
volumes:
|
||||||
|
- ./config/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
|
||||||
|
- redis_data:/data
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
driver: local
|
||||||
|
redis_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
file: ./secrets/db_password
|
||||||
|
redis_password:
|
||||||
|
file: ./secrets/redis_password
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stack with Docker Secrets (Production)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
container_name: ${PROJECT_NAME:-app}_main
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DB_HOST=postgres
|
||||||
|
- DB_USER=${DB_USER}
|
||||||
|
# NO PASSWORDS IN ENVIRONMENT!
|
||||||
|
secrets:
|
||||||
|
- db_password
|
||||||
|
- api_key
|
||||||
|
- jwt_secret
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: ${PROJECT_NAME:-app}_postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB}
|
||||||
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
|
# Password via Docker secret, not environment!
|
||||||
|
secrets:
|
||||||
|
- source: db_password
|
||||||
|
target: /run/secrets/postgres-passwd
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
file: ./secrets/db_password
|
||||||
|
api_key:
|
||||||
|
file: ./secrets/api_key
|
||||||
|
jwt_secret:
|
||||||
|
file: ./secrets/jwt_secret
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## .env.example Templates
|
||||||
|
|
||||||
|
### Basic Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Project Configuration
|
||||||
|
PROJECT_NAME=myapp
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
|
NODE_ENV=production
|
||||||
|
APP_PORT=3000
|
||||||
|
|
||||||
|
# IMPORTANT: Copy this file to .env and configure
|
||||||
|
# .env is gitignored and should contain actual values
|
||||||
|
```
|
||||||
|
|
||||||
|
### Web Stack with nginx
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Project Configuration
|
||||||
|
PROJECT_NAME=mywebapp
|
||||||
|
|
||||||
|
# nginx Configuration
|
||||||
|
NGINX_HTTP_PORT=80
|
||||||
|
NGINX_HTTPS_PORT=443
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
# IMPORTANT: Copy this file to .env and configure for your environment
|
||||||
|
# .env is gitignored and should contain actual configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Stack (nginx + App + PostgreSQL + Redis)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Project Configuration
|
||||||
|
PROJECT_NAME=myapp
|
||||||
|
|
||||||
|
# nginx Configuration
|
||||||
|
NGINX_HTTP_PORT=80
|
||||||
|
NGINX_HTTPS_PORT=443
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
# PostgreSQL Configuration
|
||||||
|
POSTGRES_DB=myapp_db
|
||||||
|
POSTGRES_USER=myapp_user
|
||||||
|
# NOTE: Password stored in Docker secret, not here!
|
||||||
|
|
||||||
|
# Redis Configuration
|
||||||
|
REDIS_PORT=6379
|
||||||
|
# NOTE: Password stored in Docker secret, not here!
|
||||||
|
|
||||||
|
# IMPORTANT SECURITY NOTES:
|
||||||
|
# 1. Copy this file to .env for actual configuration
|
||||||
|
# 2. NEVER put secrets/passwords here - use Docker secrets in ./secrets/
|
||||||
|
# 3. .env is gitignored and should NEVER be committed
|
||||||
|
# 4. Keep .env and .env.example keys synchronized
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Service Configuration Templates
|
||||||
|
|
||||||
|
### nginx - Simple Reverse Proxy
|
||||||
|
|
||||||
|
**File**: `config/nginx/default.conf`
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
upstream app {
|
||||||
|
server app:3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://app;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### nginx - Production with SSL
|
||||||
|
|
||||||
|
**File**: `config/nginx/default.conf`
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
upstream app {
|
||||||
|
server app:3000;
|
||||||
|
keepalive 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect HTTP to HTTPS
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name example.com www.example.com;
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTPS Server
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name example.com www.example.com;
|
||||||
|
|
||||||
|
# SSL Configuration
|
||||||
|
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
# Security Headers
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
|
||||||
|
# Proxy Configuration
|
||||||
|
location / {
|
||||||
|
proxy_pass http://app;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Timeouts
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static files caching
|
||||||
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
|
||||||
|
proxy_pass http://app;
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL - Initialization Script
|
||||||
|
|
||||||
|
**File**: `config/postgres/init.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Initialize database
|
||||||
|
|
||||||
|
-- Create extensions
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
|
||||||
|
|
||||||
|
-- Create schemas
|
||||||
|
CREATE SCHEMA IF NOT EXISTS app;
|
||||||
|
|
||||||
|
-- Create tables
|
||||||
|
CREATE TABLE IF NOT EXISTS app.users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
email VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create indexes
|
||||||
|
CREATE INDEX idx_users_email ON app.users(email);
|
||||||
|
|
||||||
|
-- Grant permissions
|
||||||
|
GRANT ALL PRIVILEGES ON SCHEMA app TO ${POSTGRES_USER};
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA app TO ${POSTGRES_USER};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Redis - Production Configuration
|
||||||
|
|
||||||
|
**File**: `config/redis/redis.conf`
|
||||||
|
|
||||||
|
```conf
|
||||||
|
# Redis Production Configuration
|
||||||
|
|
||||||
|
# Network
|
||||||
|
bind 0.0.0.0
|
||||||
|
protected-mode yes
|
||||||
|
port 6379
|
||||||
|
|
||||||
|
# General
|
||||||
|
daemonize no
|
||||||
|
supervised no
|
||||||
|
pidfile /var/run/redis_6379.pid
|
||||||
|
loglevel notice
|
||||||
|
logfile ""
|
||||||
|
|
||||||
|
# Snapshotting
|
||||||
|
save 900 1
|
||||||
|
save 300 10
|
||||||
|
save 60 10000
|
||||||
|
stop-writes-on-bgsave-error yes
|
||||||
|
rdbcompression yes
|
||||||
|
rdbchecksum yes
|
||||||
|
dbfilename dump.rdb
|
||||||
|
dir /data
|
||||||
|
|
||||||
|
# Replication
|
||||||
|
replica-serve-stale-data yes
|
||||||
|
replica-read-only yes
|
||||||
|
|
||||||
|
# Security
|
||||||
|
# requirepass will be set via environment variable
|
||||||
|
# Use Docker secrets for password
|
||||||
|
|
||||||
|
# Limits
|
||||||
|
maxmemory 256mb
|
||||||
|
maxmemory-policy allkeys-lru
|
||||||
|
maxclients 10000
|
||||||
|
|
||||||
|
# Append Only Mode
|
||||||
|
appendonly yes
|
||||||
|
appendfilename "appendonly.aof"
|
||||||
|
appendfsync everysec
|
||||||
|
no-appendfsync-on-rewrite no
|
||||||
|
auto-aof-rewrite-percentage 100
|
||||||
|
auto-aof-rewrite-min-size 64mb
|
||||||
|
|
||||||
|
# Slow Log
|
||||||
|
slowlog-log-slower-than 10000
|
||||||
|
slowlog-max-len 128
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation Templates
|
||||||
|
|
||||||
|
### docs/setup.md
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Setup Instructions
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Docker Engine 20.10+
|
||||||
|
- Docker Compose V2
|
||||||
|
- Git
|
||||||
|
- [Other prerequisites]
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Clone repository
|
||||||
|
git clone <repository-url>
|
||||||
|
cd <project-name>
|
||||||
|
|
||||||
|
# Copy environment template
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Configure environment
|
||||||
|
nano .env
|
||||||
|
|
||||||
|
# Set up Docker secrets (if applicable)
|
||||||
|
# Follow instructions in ./secrets/README.md
|
||||||
|
|
||||||
|
# Install git hooks
|
||||||
|
./scripts/setup-hooks.sh
|
||||||
|
|
||||||
|
# Validate stack
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
|
||||||
|
# Start services
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
docker compose ps
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Detailed Setup
|
||||||
|
|
||||||
|
### 1. Environment Configuration
|
||||||
|
|
||||||
|
Edit `.env` with your settings:
|
||||||
|
\`\`\`bash
|
||||||
|
PROJECT_NAME=myapp
|
||||||
|
# Add other variables from .env.example
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 2. Secrets Configuration
|
||||||
|
|
||||||
|
Create required secrets in `./secrets/`:
|
||||||
|
\`\`\`bash
|
||||||
|
# Generate secure random password
|
||||||
|
openssl rand -base64 32 > ./secrets/db_password
|
||||||
|
|
||||||
|
# Set proper permissions
|
||||||
|
chmod 600 ./secrets/*
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 3. Validation
|
||||||
|
|
||||||
|
Always validate before deploying:
|
||||||
|
\`\`\`bash
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 4. Deployment
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
docker compose up -d
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Services Won't Start
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Check logs
|
||||||
|
docker compose logs
|
||||||
|
|
||||||
|
# Check specific service
|
||||||
|
docker compose logs <service-name>
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### Validation Fails
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Run individual validators
|
||||||
|
claude-code run stack-validator
|
||||||
|
claude-code run secrets-manager --validate
|
||||||
|
claude-code run docker-validation
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### Permission Issues
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Fix file ownership
|
||||||
|
sudo chown -R $USER:$USER .
|
||||||
|
|
||||||
|
# Re-validate
|
||||||
|
./scripts/validate-stack.sh
|
||||||
|
\`\`\`
|
||||||
|
```
|
||||||
|
|
||||||
|
### docs/services.md
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Services Documentation
|
||||||
|
|
||||||
|
## Service Overview
|
||||||
|
|
||||||
|
| Service | Port | Purpose | Configuration |
|
||||||
|
|---------|------|---------|---------------|
|
||||||
|
| nginx | 80, 443 | Web server & reverse proxy | ./config/nginx |
|
||||||
|
| app | 3000 (internal) | Application server | Environment variables |
|
||||||
|
| postgres | 5432 (internal) | Database | ./config/postgres |
|
||||||
|
| redis | 6379 (internal) | Cache & sessions | ./config/redis |
|
||||||
|
|
||||||
|
## Service Details
|
||||||
|
|
||||||
|
### nginx
|
||||||
|
|
||||||
|
**Image**: nginx:alpine
|
||||||
|
**Purpose**: Web server and reverse proxy
|
||||||
|
**Configuration**: ./config/nginx/default.conf
|
||||||
|
**Secrets**: None
|
||||||
|
**Volumes**:
|
||||||
|
- ./config/nginx:/etc/nginx/conf.d:ro
|
||||||
|
- ./ssl:/etc/nginx/ssl:ro (if using HTTPS)
|
||||||
|
|
||||||
|
**Health Check**: HTTP request to port 80
|
||||||
|
|
||||||
|
### Application
|
||||||
|
|
||||||
|
**Image**: myapp:latest
|
||||||
|
**Purpose**: Main application server
|
||||||
|
**Configuration**: Environment variables in .env
|
||||||
|
**Secrets**:
|
||||||
|
- db_password
|
||||||
|
- redis_password
|
||||||
|
- api_key
|
||||||
|
- jwt_secret
|
||||||
|
|
||||||
|
**Dependencies**:
|
||||||
|
- postgres (database)
|
||||||
|
- redis (cache)
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
|
||||||
|
**Image**: postgres:16-alpine
|
||||||
|
**Purpose**: Primary database
|
||||||
|
**Configuration**: ./config/postgres/init.sql
|
||||||
|
**Secrets**:
|
||||||
|
- db_password
|
||||||
|
|
||||||
|
**Volumes**:
|
||||||
|
- postgres_data:/var/lib/postgresql/data (persistent)
|
||||||
|
- ./config/postgres:/docker-entrypoint-initdb.d:ro (init scripts)
|
||||||
|
|
||||||
|
**Health Check**: `pg_isready` command
|
||||||
|
|
||||||
|
**Backup**:
|
||||||
|
\`\`\`bash
|
||||||
|
docker compose exec postgres pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} > backup.sql
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### Redis
|
||||||
|
|
||||||
|
**Image**: redis:7-alpine
|
||||||
|
**Purpose**: Cache and session storage
|
||||||
|
**Configuration**: ./config/redis/redis.conf
|
||||||
|
**Secrets**:
|
||||||
|
- redis_password
|
||||||
|
|
||||||
|
**Volumes**:
|
||||||
|
- redis_data:/data (persistent)
|
||||||
|
- ./config/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
|
||||||
|
|
||||||
|
**Health Check**: `redis-cli ping`
|
||||||
|
|
||||||
|
**Backup**:
|
||||||
|
\`\`\`bash
|
||||||
|
docker compose exec redis redis-cli SAVE
|
||||||
|
docker compose cp redis:/data/dump.rdb ./backup/
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Service Dependencies
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
nginx → app → postgres
|
||||||
|
↓
|
||||||
|
redis
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Scaling
|
||||||
|
|
||||||
|
To scale the application:
|
||||||
|
\`\`\`bash
|
||||||
|
docker compose up -d --scale app=3
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
Note: nginx configuration must support multiple backend servers.
|
||||||
|
```
|
||||||
|
|
||||||
|
### docs/decisions/0001-stack-architecture.md
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# 1. Stack Architecture
|
||||||
|
|
||||||
|
**Date**: YYYY-MM-DD
|
||||||
|
**Status**: Accepted
|
||||||
|
**Deciders**: [Names]
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
We need a consistent, maintainable approach for deploying our application stack.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
We will use GitLab Stack Management patterns:
|
||||||
|
1. All configuration in docker-compose.yml and ./config
|
||||||
|
2. All secrets in ./secrets and Docker secrets
|
||||||
|
3. docker-entrypoint.sh only when containers don't support native Docker secrets
|
||||||
|
4. No root-owned files
|
||||||
|
5. ./_temporary for transient files
|
||||||
|
6. Complete validation before deployment
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
**Positive**:
|
||||||
|
- Consistent structure across all stacks
|
||||||
|
- Automated validation prevents deployment issues
|
||||||
|
- Secure by default (secrets properly managed)
|
||||||
|
- Easy to maintain and update
|
||||||
|
- Clear separation of config and secrets
|
||||||
|
|
||||||
|
**Negative**:
|
||||||
|
- Initial setup requires more steps
|
||||||
|
- Must follow strict patterns
|
||||||
|
- Validation gates can slow rapid iteration
|
||||||
|
- Learning curve for team members
|
||||||
|
|
||||||
|
## Compliance
|
||||||
|
|
||||||
|
Stack creation enforces:
|
||||||
|
- stack-validator: Structure compliance
|
||||||
|
- secrets-manager: Secure secrets handling
|
||||||
|
- docker-validation: Docker best practices
|
||||||
|
- git hooks: Pre-commit validation
|
||||||
|
|
||||||
|
## Alternatives Considered
|
||||||
|
|
||||||
|
1. **Manual setup**: Rejected due to inconsistency
|
||||||
|
2. **.env for everything**: Rejected due to security concerns
|
||||||
|
3. **No validation**: Rejected due to quality issues
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
- Use stack-creator skill for all new projects
|
||||||
|
- Validate with ./scripts/validate-stack.sh
|
||||||
|
- Document all deviations in new ADRs
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Git Configuration Templates
|
||||||
|
|
||||||
|
### .gitignore
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
# Secrets - NEVER commit
|
||||||
|
secrets/*
|
||||||
|
!secrets/.gitkeep
|
||||||
|
!secrets/README.md
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
*.crt
|
||||||
|
*.p12
|
||||||
|
*.pfx
|
||||||
|
id_rsa
|
||||||
|
id_ed25519
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
_temporary/
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
.cache/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.docker/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
*.old
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
node_modules/
|
||||||
|
```
|
||||||
|
|
||||||
|
### .dockerignore
|
||||||
|
|
||||||
|
```dockerignore
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.github
|
||||||
|
.gitlab-ci.yml
|
||||||
|
README.md
|
||||||
|
LICENSE
|
||||||
|
docs/
|
||||||
|
_temporary/
|
||||||
|
*.md
|
||||||
|
.env
|
||||||
|
.env.example
|
||||||
|
.env.local
|
||||||
|
secrets/
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
node_modules/
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
```
|
||||||
|
|
||||||
|
### CLAUDE.md Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code when working with this GitLab Stack project.
|
||||||
|
|
||||||
|
## Project Type
|
||||||
|
|
||||||
|
This is a GitLab Stack project following strict management patterns.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
- `config/`: Service configurations (nginx, postgres, redis)
|
||||||
|
- `secrets/`: Docker secrets (NEVER commit actual secrets!)
|
||||||
|
- `_temporary/`: Temporary files (gitignored)
|
||||||
|
- `scripts/`: Validation and utility scripts
|
||||||
|
- `docs/`: Project documentation
|
||||||
|
|
||||||
|
## Required Skills
|
||||||
|
|
||||||
|
This project requires these Claude Code skills:
|
||||||
|
- **stack-validator**: Validate structure
|
||||||
|
- **secrets-manager**: Manage Docker secrets
|
||||||
|
- **docker-validation**: Validate Docker configs
|
||||||
|
- **config-generator**: Generate service configs
|
||||||
|
|
||||||
|
## Git Configuration
|
||||||
|
|
||||||
|
- **Branch**: main
|
||||||
|
- **Merge Strategy**: ff-only (fast-forward only)
|
||||||
|
- **Hooks**: Pre-commit validation enabled
|
||||||
|
|
||||||
|
## Validation Requirements
|
||||||
|
|
||||||
|
BEFORE any commit, ALL must pass:
|
||||||
|
1. stack-validator: NO issues
|
||||||
|
2. secrets-manager: Satisfied
|
||||||
|
3. docker-validation: NO issues
|
||||||
|
4. No root-owned files
|
||||||
|
5. No secrets in .env or docker-compose.yml environment
|
||||||
|
|
||||||
|
## Making Changes
|
||||||
|
|
||||||
|
### Adding a Service
|
||||||
|
|
||||||
|
1. Update docker-compose.yml
|
||||||
|
2. Use config-generator for configs
|
||||||
|
3. Use secrets-manager for secrets
|
||||||
|
4. Run ./scripts/validate-stack.sh
|
||||||
|
5. Fix ALL issues
|
||||||
|
6. Commit
|
||||||
|
|
||||||
|
### Modifying Configuration
|
||||||
|
|
||||||
|
1. Edit config files
|
||||||
|
2. Validate with docker-validation
|
||||||
|
3. Run ./scripts/validate-stack.sh
|
||||||
|
4. Fix issues
|
||||||
|
5. Commit
|
||||||
|
|
||||||
|
### Working with Secrets
|
||||||
|
|
||||||
|
1. Use secrets-manager for ALL secret operations
|
||||||
|
2. NEVER put secrets in .env
|
||||||
|
3. Use Docker secrets or ./secrets/
|
||||||
|
4. Validate before committing
|
||||||
|
|
||||||
|
## Important Rules
|
||||||
|
|
||||||
|
1. NEVER commit secrets
|
||||||
|
2. NEVER create root-owned files
|
||||||
|
3. NEVER skip validation without asking
|
||||||
|
4. NEVER use workarounds - ask user
|
||||||
|
5. ALWAYS validate before committing
|
||||||
|
6. ALWAYS document decisions
|
||||||
|
7. ALWAYS use ff-only merges
|
||||||
|
8. ALWAYS use main as branch name
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- Validation fails → Fix issues, don't skip
|
||||||
|
- Git conflicts → Use ff-only, ask user
|
||||||
|
- Permission issues → Check ownership, fix with chown
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
All templates follow GitLab Stack Management principles:
|
||||||
|
- ✅ Secrets in Docker secrets, never in .env
|
||||||
|
- ✅ Configuration in ./config directory
|
||||||
|
- ✅ Validated before deployment
|
||||||
|
- ✅ Documented thoroughly
|
||||||
|
- ✅ Git properly configured
|
||||||
|
|
||||||
|
Use these templates as starting points and customize for your specific needs.
|
||||||
6
workflow-examples.md
Normal file
6
workflow-examples.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Stack Creator - Additional Workflow Examples
|
||||||
|
|
||||||
|
## Workflow 2: Creating a Full Application Stack
|
||||||
|
|
||||||
|
```
|
||||||
|
User: "Create a stack with nginx, PostgreSQL, and Redis"
|
||||||
Reference in New Issue
Block a user