diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml deleted file mode 100644 index 61efbb4..0000000 --- a/.forgejo/workflows/deploy.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Deploy to Production - -on: - push: - branches: [ main ] - -jobs: - deploy: - name: Deploy to Server - runs-on: ubuntu-latest - - steps: - - name: Deploy via SSH - uses: appleboy/ssh-action@v1.1.0 - with: - host: ${{ secrets.SERVER_HOST }} - username: ${{ secrets.SERVER_USER }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - script: | - set -e - - echo "πŸš€ Starting deployment..." - - # Navigate to project directory - cd /root/docfast - - # Check current git status - echo "πŸ“‹ Current status:" - git status --short || true - - # Pull latest changes - echo "πŸ“₯ Pulling latest changes..." - git fetch origin - git pull origin main - - # Tag current running image for rollback - echo "🏷️ Tagging current image for rollback..." - TIMESTAMP=$(date +%Y%m%d-%H%M%S) - docker tag docfast-docfast:latest docfast-docfast:rollback-$TIMESTAMP || echo "No existing image to tag" - - # Build new image - echo "πŸ”¨ Building new Docker image..." - docker compose build --no-cache - - # Stop services gracefully - echo "⏹️ Stopping services..." - docker compose down --timeout 30 - - # Start services - echo "▢️ Starting services..." - docker compose up -d - - # Wait for service to be ready - echo "⏱️ Waiting for service to be ready..." - for i in {1..30}; do - if curl -f -s http://127.0.0.1:3100/health > /dev/null; then - echo "βœ… Service is healthy!" - break - fi - if [ $i -eq 30 ]; then - echo "❌ Service failed to start - initiating rollback..." - docker compose down - - # Try to rollback to previous image - ROLLBACK_IMAGE=$(docker images --format "table {{.Repository}}:{{.Tag}}" | grep "docfast-docfast:rollback-" | head -n1 | tr -s ' ' | cut -d' ' -f1) - if [ ! -z "$ROLLBACK_IMAGE" ]; then - echo "πŸ”„ Rolling back to $ROLLBACK_IMAGE" - docker tag $ROLLBACK_IMAGE docfast-docfast:latest - docker compose up -d - - # Wait for rollback to be healthy - sleep 10 - if curl -f -s http://127.0.0.1:3100/health > /dev/null; then - echo "βœ… Rollback successful" - else - echo "❌ Rollback failed - manual intervention required" - fi - else - echo "❌ No rollback image available" - fi - - exit 1 - fi - echo "⏳ Attempt $i/30 - waiting 5 seconds..." - sleep 5 - done - - # Cleanup old rollback images (keep last 5) - echo "🧹 Cleaning up old rollback images..." - docker images --format "table {{.Repository}}:{{.Tag}}" | grep "docfast-docfast:rollback-" | tail -n +6 | awk '{print $1":"$2}' | xargs -r docker rmi || true - - # Final health check and status - echo "πŸ” Final health check..." - HEALTH_STATUS=$(curl -f -s http://127.0.0.1:3100/health || echo "UNHEALTHY") - echo "Health status: $HEALTH_STATUS" - - echo "πŸ“Š Service status:" - docker compose ps - - echo "πŸŽ‰ Deployment completed successfully!" \ No newline at end of file diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md deleted file mode 100644 index f9ca614..0000000 --- a/DEPLOYMENT.md +++ /dev/null @@ -1,77 +0,0 @@ -# DocFast CI/CD Deployment - -This repository uses Forgejo Actions for automated deployment to production. - -## Setup Instructions - -### 1. Repository Secrets - -Go to repository settings β†’ Actions β†’ Secrets and add these secrets: - -- **SERVER_HOST**: `167.235.156.214` -- **SERVER_USER**: `root` -- **SSH_PRIVATE_KEY**: The private SSH key content from `/home/openclaw/.ssh/docfast` - -### 2. How Deployment Works - -**Trigger**: Push to `main` branch -**Process**: -1. SSH to production server -2. Pull latest code from git -3. Tag current Docker image for rollback -4. Build new Docker image -5. Stop current services -6. Start new services -7. Health check at `http://127.0.0.1:3100/health` -8. Rollback automatically if health check fails - -### 3. Rollback Procedure - -**Automatic Rollback**: -- Happens automatically if deployment fails health checks -- Reverts to the previously tagged image - -**Manual Rollback**: -```bash -# On the production server -cd /root/docfast -./scripts/rollback.sh -``` - -**Emergency Rollback via SSH**: -```bash -ssh root@167.235.156.214 -cd /root/docfast -docker compose down -docker tag docfast-docfast:rollback-YYYYMMDD-HHMMSS docfast-docfast:latest -docker compose up -d -``` - -### 4. Monitoring - -- **Health Check**: `curl http://127.0.0.1:3100/health` -- **Service Status**: `docker compose ps` -- **Logs**: `docker compose logs -f` - -### 5. File Structure - -``` -.forgejo/workflows/deploy.yml # Main deployment workflow -scripts/rollback.sh # Manual rollback script -scripts/setup-secrets.sh # Helper for setting up secrets -DEPLOYMENT.md # This documentation -``` - -### 6. Testing the Pipeline - -1. Make a small change (e.g., bump version comment) -2. Commit and push to main branch -3. Check Actions tab in Forgejo to see deployment progress -4. Verify service is running with `curl http://127.0.0.1:3100/health` - -## Troubleshooting - -- **SSH Issues**: Ensure SSH key is properly added to secrets -- **Docker Build Issues**: Check server has enough disk space and memory -- **Health Check Fails**: Check if service is binding to correct port (3100) -- **Permission Issues**: Ensure user has Docker privileges on server \ No newline at end of file diff --git a/bugs.md b/bugs.md deleted file mode 100644 index 8ebec70..0000000 --- a/bugs.md +++ /dev/null @@ -1,24 +0,0 @@ -# DocFast Bugs - -## Open - -### BUG-030: Email change backend not implemented -- **Severity:** High -- **Found:** 2026-02-14 QA session -- **Description:** Frontend UI for email change is deployed (modal, form, JS handlers), but no backend routes exist. Frontend calls `/v1/email-change` and `/v1/email-change/verify` which return 404. -- **Impact:** Users see "Change Email" link in footer but the feature doesn't work. -- **Fix:** Implement `src/routes/email-change.ts` with verification code flow similar to signup/recover. - -### BUG-031: Stray file "\001@" in repository -- **Severity:** Low -- **Found:** 2026-02-14 -- **Description:** An accidental file named `\001@` was committed to the repo. -- **Fix:** `git rm "\001@"` and commit. - -### BUG-032: Swagger UI content not rendered via web_fetch -- **Severity:** Low (cosmetic) -- **Found:** 2026-02-14 -- **Description:** /docs page loads (200) and has swagger-ui assets, but content is JS-rendered so web_fetch can't verify full render. Needs browser-based QA for full verification. - -## Fixed -(none yet - this is first QA session) diff --git a/decisions.md b/decisions.md deleted file mode 100644 index a68912d..0000000 --- a/decisions.md +++ /dev/null @@ -1,21 +0,0 @@ -# DocFast Decisions Log - -## 2026-02-14: Mandatory QA After Every Deployment - -**Rule:** Every deployment MUST be followed by a full QA session. No exceptions. - -**QA Checklist:** -- Landing page loads, zero console errors -- Signup flow works (email verification) -- Key recovery flow works -- Email change flow works (when backend is implemented) -- Swagger UI loads at /docs -- API endpoints work (HTMLβ†’PDF, Markdownβ†’PDF, URLβ†’PDF) -- Health endpoint returns ok -- All previous features still working - -**Rationale:** Code was deployed to production without verification multiple times, leading to broken features being live. QA catches regressions before users do. - -## 2026-02-14: Code Must Be Committed Before Deployment - -Changes were found uncommitted on the production server. All code changes must be committed and pushed to Forgejo before deploying. diff --git a/public/index.html b/public/index.html index 6a4f860..d529ad3 100644 --- a/public/index.html +++ b/public/index.html @@ -144,27 +144,6 @@ footer .container { display: flex; align-items: center; justify-content: space-b .trust-grid { gap: 24px; } } -/* Fix mobile terminal gaps at 375px and smaller */ -@media (max-width: 375px) { - .container { - padding: 0 12px !important; - } - .code-section { - margin: 32px auto 0; - max-width: calc(100vw - 24px) !important; - } - .code-header { - padding: 8px 12px; - } - .code-block { - padding: 12px !important; - font-size: 0.7rem; - } - .hero { - padding: 56px 0 40px; - } -} - /* Additional mobile overflow fixes */ html, body { overflow-x: hidden !important; diff --git a/public/openapi.json b/public/openapi.json index f3e5023..811ada6 100644 --- a/public/openapi.json +++ b/public/openapi.json @@ -3,7 +3,7 @@ "info": { "title": "DocFast API", "version": "1.0.0", - "description": "Convert HTML, Markdown, and URLs to pixel-perfect PDFs. Built-in invoice & receipt templates.\n\n## Authentication\nAll conversion and template endpoints require an API key via `Authorization: Bearer ` or `X-API-Key: ` header.\n\n## Rate Limits\n- Free tier: 100 PDFs/month, 10 req/min\n- Pro tier: 10,000 PDFs/month, 30 req/min\n\n## Getting Started\n1. Sign up at [docfast.dev](https://docfast.dev) or via `POST /v1/signup/free`\n2. Verify your email with the 6-digit code\n3. Use your API key to convert documents", + "description": "Convert HTML, Markdown, and URLs to pixel-perfect PDFs. Built-in invoice & receipt templates.\n\n## Authentication\nAll conversion and template endpoints require an API key via `Authorization: Bearer ` or `X-API-Key: ` header.\n\n## Rate Limits\n- Free tier: 100 PDFs/month, 10 req/min\n- Pro tier: 10,000 PDFs/month\n\n## Getting Started\n1. Sign up at [docfast.dev](https://docfast.dev) or via `POST /v1/signup/free`\n2. Verify your email with the 6-digit code\n3. Use your API key to convert documents", "contact": { "name": "DocFast", "url": "https://docfast.dev" } }, "servers": [{ "url": "https://docfast.dev", "description": "Production" }], diff --git a/scripts/rollback.sh b/scripts/rollback.sh deleted file mode 100755 index 4004a31..0000000 --- a/scripts/rollback.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash -set -e - -echo "πŸ”„ DocFast Rollback Script" -echo "==========================" - -# Check if we're on the server -if [ ! -d "/root/docfast" ]; then - echo "❌ This script should be run on the production server" - exit 1 -fi - -cd /root/docfast - -# List available rollback images -echo "πŸ“‹ Available rollback images:" -ROLLBACK_IMAGES=$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | grep "docfast-docfast:rollback-" | head -10) - -if [ -z "$ROLLBACK_IMAGES" ]; then - echo "❌ No rollback images available" - exit 1 -fi - -echo "$ROLLBACK_IMAGES" -echo "" - -# Get the most recent rollback image -LATEST_ROLLBACK=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "docfast-docfast:rollback-" | head -n1) - -if [ -z "$LATEST_ROLLBACK" ]; then - echo "❌ No rollback image found" - exit 1 -fi - -echo "🎯 Will rollback to: $LATEST_ROLLBACK" -echo "" - -# Confirm rollback -read -p "⚠️ Are you sure you want to rollback? (y/N): " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "❌ Rollback cancelled" - exit 1 -fi - -echo "πŸ›‘ Stopping current services..." -docker compose down --timeout 30 - -echo "πŸ”„ Rolling back to $LATEST_ROLLBACK..." -docker tag $LATEST_ROLLBACK docfast-docfast:latest - -echo "▢️ Starting services..." -docker compose up -d - -echo "⏱️ Waiting for service to be ready..." -for i in {1..20}; do - if curl -f -s http://127.0.0.1:3100/health > /dev/null; then - echo "βœ… Rollback successful! Service is healthy." - break - fi - if [ $i -eq 20 ]; then - echo "❌ Rollback failed - service is not responding" - exit 1 - fi - echo "⏳ Attempt $i/20 - waiting 3 seconds..." - sleep 3 -done - -echo "πŸ“Š Service status:" -docker compose ps - -echo "πŸŽ‰ Rollback completed successfully!" \ No newline at end of file diff --git a/scripts/setup-secrets.sh b/scripts/setup-secrets.sh deleted file mode 100755 index 90c7cae..0000000 --- a/scripts/setup-secrets.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -echo "πŸ” Forgejo Repository Secrets Setup" -echo "====================================" - -# Source credentials to get Forgejo token -source /home/openclaw/.openclaw/workspace/.credentials/docfast.env - -# Repository secrets to set up -REPO_URL="https://git.cloonar.com/api/v1/repos/openclawd/docfast/actions/secrets" - -echo "Setting up repository secrets for CI/CD..." - -# Server host -echo "πŸ“‘ Setting SERVER_HOST..." -curl -X PUT "$REPO_URL/SERVER_HOST" \ - -H "Authorization: token $FORGEJO_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"data":"167.235.156.214"}' \ - --silent - -# Server user -echo "πŸ‘€ Setting SERVER_USER..." -curl -X PUT "$REPO_URL/SERVER_USER" \ - -H "Authorization: token $FORGEJO_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"data":"root"}' \ - --silent - -# SSH Private Key -echo "πŸ”‘ Setting SSH_PRIVATE_KEY..." -SSH_KEY_CONTENT=$(cat /home/openclaw/.ssh/docfast | jq -Rs .) -curl -X PUT "$REPO_URL/SSH_PRIVATE_KEY" \ - -H "Authorization: token $FORGEJO_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"data\":$SSH_KEY_CONTENT}" \ - --silent - -echo "βœ… Repository secrets have been configured!" -echo "" -echo "πŸ” To verify, check: https://git.cloonar.com/openclawd/docfast/settings/actions/secrets" \ No newline at end of file diff --git a/sessions.md b/sessions.md deleted file mode 100644 index 436b3bf..0000000 --- a/sessions.md +++ /dev/null @@ -1,37 +0,0 @@ -# DocFast Sessions Log - -## 2026-02-14 22:14 UTC β€” Deployment + QA Session - -**Trigger:** Latest code changes (Swagger UI, key recovery UI, email change) were not deployed despite being in the working tree. - -**Actions:** -1. SSH'd into server (167.235.156.214) -2. Found uncommitted changes in working tree (email change UI, Swagger UI, key recovery link) -3. Committed all changes: `d859e9f` β€” "feat: email change UI, Swagger UI improvements, key recovery link on landing page" -4. Pushed to Forgejo (openclawd/docfast) -5. Rebuilt container with `docker compose build --no-cache` -6. Restarted: `docker compose up -d` -7. Verified server healthy: 15-page browser pool, version 0.2.1 - -**QA Results:** -| Test | Result | -|------|--------| -| Landing page loads | βœ… 200 OK | -| Key recovery link on landing | βœ… Present | -| Email change link in footer | βœ… Present | -| Swagger UI at /docs | βœ… 200 OK | -| Signup endpoint | βœ… Works (verification_required) | -| Key recovery endpoint | βœ… Works (recovery_sent) | -| Email change backend | ❌ NOT IMPLEMENTED (BUG-030) | -| HTMLβ†’PDF conversion | βœ… Valid PDF | -| Markdownβ†’PDF conversion | βœ… Valid PDF | -| URLβ†’PDF conversion | βœ… Valid PDF | -| Health endpoint | βœ… Pool: 15 pages, 0 active | -| Browser pool | βœ… 1 browser Γ— 15 pages | - -**Bugs Found:** -- BUG-030: Email change backend not implemented (frontend-only) -- BUG-031: Stray `\001@` file in repo -- BUG-032: Swagger UI needs browser QA for full verification - -**Note:** Browser-based QA not available (openclaw browser service unreachable). Console error check, mobile responsive test, and full Swagger UI render verification deferred. diff --git a/src/index.ts b/src/index.ts index 87a0d84..cc94be3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -56,7 +56,7 @@ app.use(express.text({ limit: "2mb", type: "text/*" })); // Trust nginx proxy app.set("trust proxy", 1); -// Global rate limiting - reduced from 10,000 to reasonable limit +// Global rate limiting const limiter = rateLimit({ windowMs: 60_000, max: 100, diff --git a/state.json b/state.json deleted file mode 100644 index 90f9593..0000000 --- a/state.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "project": "DocFast", - "domain": "docfast.dev", - "server": "167.235.156.214", - "sshKey": "/home/openclaw/.ssh/docfast", - "repo": "openclawd/docfast", - "status": "live", - "version": "0.2.1", - "lastDeployment": "2026-02-14T22:17:00Z", - "lastQA": "2026-02-14T22:18:00Z", - "features": { - "htmlToPdf": true, - "markdownToPdf": true, - "urlToPdf": true, - "templates": true, - "signup": true, - "emailVerification": true, - "keyRecovery": true, - "emailChange": "frontend-only", - "swaggerDocs": true, - "browserPool": "1 browser Γ— 15 pages", - "stripeIntegration": true - }, - "infrastructure": { - "webServer": "nginx", - "ssl": "letsencrypt", - "container": "docker-compose", - "email": "postfix + opendkim" - }, - "todos": [ - "Implement email change backend route (/v1/email-change + /v1/email-change/verify)", - "Set up staging environment for pre-production testing", - "Remove obsolete \\001@ file from repo" - ] -}