Skip to content

anstonbrick/PDS

Repository files navigation

PDS (OutRelay)

A React + Express web application for managing rendering requests with anime image reverse-search capabilities plus a global authenticated chat pool. Currently deployed on EC2, actively maintained as of February 2026.

For implementation-level onboarding, see DEVELOPER_DOCUMENTATION.md.

Current Status

Experimental / Active Development

This is a functional but evolving codebase. The architecture was recently refactored from a monolithic server design to a repository pattern. Security was hardened in late January 2026 to implement ephemeral admin sessions (no permanent admin accounts). The system is deployed and operational, but expect breaking changes and ongoing architectural improvements.

What This Actually Does

  1. Request Management System: Users sign up, submit rendering requests via a multi-step form, and receive cryptographic access keys to track their submissions.
  2. Admin Panel: SSH-gated admin dashboard with Just-In-Time (JIT) access. Admin sessions are ephemeral (1-hour lifespan) and credential reuse is prevented. All admin actions are audit-logged.
  3. Global Chat Pool: Authenticated users share a single chat pool via SSE. Messages are capped at 500 chars and auto-delete after 5 minutes. This chat is not AI-backed.
  4. Experimental GPU Route: /gpu is a WebGL/GPU experiment separate from the main flow.
  5. Cinematic UI: GSAP + Framer Motion powered scrollytelling experience with a dark "cyberpunk luxury" aesthetic.

Architecture

Frontend (React 19 + Vite)
  ├── React Router DOM + Context API
  ├── GSAP / Framer Motion animations
  ├── Tailwind CSS v4
  └── SSE clients (chat + admin logs)

Backend (Node.js + Express 5)
  ├── SQLite databases (better-sqlite3, WAL mode)
  │   ├── pds_auth.db (users, referrals, audit logs, ephemeral admin sessions)
  │   └── pds_requests.db (requests, beta feedback, chat messages)
  ├── Repository pattern for data access
  ├── JWT auth (httpOnly cookies; localStorage display only)
  ├── CSRF double-submit cookie (xsrf-token + x-xsrf-token)
  ├── Helmet + rate limiting + Zod validation
  └── External services (OpenAI for Mai, Redis in production)

API Surface (Summary)

  • Public GET /api/status, GET /api/tracking/:access_key
  • Auth POST /api/auth/signup, POST /api/auth/login, POST /api/auth/logout
  • Authenticated POST /api/request, GET /api/user/requests, POST /api/feedback, GET /api/chat/messages, POST /api/chat/messages, GET /api/chat/stream
  • Admin GET /api/admin/stats, GET /api/admin/requests, PUT /api/admin/requests/:id/status, GET /api/admin/users, GET /api/admin/referrals, POST /api/admin/referrals, DELETE /api/admin/referrals/:id, GET /api/admin/referrals/:id/users, GET /api/admin/feedback, GET /api/admin/audit-logs, GET /api/admin/logs/stream

Signup requires a referral code; usernames are 3-32 chars and limited to letters, numbers, and underscores.

Temporary Worker API Status

As of February 9, 2026, worker automation endpoints are intentionally disabled by default.

  • /api/worker/* returns 503 Worker API is temporarily disabled
  • To re-enable locally or in controlled environments, set ENABLE_WORKER_API=true in backend/.env
  • Worker auth is database-backed per worker, not a single shared backend .env secret

Worker Auth Model

Each worker now authenticates with:

  • X-WORKER-ID
  • X-WORKER-TOKEN

The backend stores only a token hash in worker_credentials, and requests.worker_assigned stores the real worker_id.

Provision credentials with:

cd backend
node scripts/manage-worker-credential.js create worker-east-01

Full lifecycle documentation is in backend/WORKER_CREDENTIALS.md.

External client implementation guidance is in backend/WORKER_API_INTEGRATION.md.

This is a safety hold, not a permanent removal of worker route code.

Git Safety / Secrets Policy

The repository is configured to avoid committing operational secrets and local runtime artifacts.

  • Never commit .env files or private keys/certs
  • SQLite runtime files and logs are gitignored
  • Local PowerShell automation files (*.ps1) are gitignored
  • Keep only templates like backend/.env.example in version control

Requirements

  • Node.js: v18+ (developed on v18/v20)
  • npm: 9+
  • Platform: Tested on Windows 11 and Ubuntu (EC2). macOS untested.

How to Run It

First-Time Setup

  1. Clone and install dependencies:

    git clone https://github.com/anstonbrick/PDS.git
    cd PDS
    npm ci
    cd backend
    npm ci
    cd ..
  2. Configure backend environment:

    cd backend
    cp .env.example .env

    Edit backend/.env with your values:

    PORT=3001
    NODE_ENV=development
    CORS_ALLOWED_ORIGINS=http://localhost:5173
    TRUST_PROXY=loopback
    CHAT_MAX_CONNECTIONS=500
    CHAT_MAX_CONNECTIONS_PER_USER=3
    CHAT_MAX_CONNECTIONS_PER_IP=20
    JWT_SECRET=<GENERATE_32_BYTE_HEX_STRING>  # Use: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

    IMPORTANT: The server will refuse to start if JWT_SECRET is the default placeholder. Generate a cryptographically secure secret.

  3. Run dev servers (two terminals):

    Terminal 1 - Backend:

    cd backend
    npm run dev

    Backend runs on http://localhost:3001

    Terminal 2 - Frontend:

    npm run dev

    Frontend runs on http://localhost:5173

Production Build

# Build frontend
npm run build  # Outputs to dist/

# Backend production mode
cd backend
NODE_ENV=production npm start

# Recommended: Use pm2 for process management
npm install -g pm2
pm2 start backend/server.js --name "pds-backend"

Deployment Notes:

  • Serve dist/ as static files via Nginx/Apache.
  • Proxy /api/* requests to backend on port 3001.
  • Set TRUST_PROXY to match your proxy hop count (recommended: loopback when Nginx is on the same host).
  • See "Deployment Details" section below for production environment information.

Admin Access (Critical Security Information)

There are NO permanent admin accounts.

Admin access uses ephemeral, one-time-use sessions that expire after 1 hour. This design assumes SSH-gated access for minting and prevents credential replay attacks.

Minting an Admin Session

Ephemeral admin sessions live in ephemeral_admin_sessions and are consumed on first login. This repository does not include a minting script. Use internal tooling or a custom Node script that inserts a bcrypt-hashed password via backend/db/repositories/ephemeralSessionRepository.js.

Login at http://localhost:5173/admin/login (or production domain). On first successful login, credentials are invalidated. Sessions expire within 1 hour of mint time.

Verification

A security verification script exists at backend/verify_security.js. It expects a minting script at backend/scripts/mint-admin-session.js (not included in this repo). Run it to confirm:

  • Credential reuse prevention (401 on replay)
  • Expiration enforcement (401 after 1 hour)
  • Audit log generation

See verification_report.md for the last test run (2026-01-30, all tests passed).

Repository Structure

PDS/
├── src/                          # Frontend source
│   ├── components/               # React components (Hero, Navbar, RequestForm, etc.)
│   │   ├── admin/                # Admin dashboard components
│   │   └── Auth/                 # Authentication UI
│   ├── gpu/                       # GPU experimental route
│   ├── hooks/                    # Custom React hooks (useTranslation, useTextDecrypter)
│   ├── utils/                    # CSRF token handler
│   └── App.jsx                   # Route definitions
├── backend/
│   ├── server.js                 # Express entry point
│   ├── config/                   # Environment config
│   ├── db/
│   │   ├── connection.js         # SQLite initialization (WAL mode)
│   │   ├── migrations.js         # Schema setup
│   │   └── repositories/         # Data access layer (6 repositories)
│   ├── routes/
│   │   ├── authRoutes.js         # Signup/login/logout
│   │   ├── requestRoutes.js      # Request CRUD
│   │   ├── adminRoutes.js        # Admin panel APIs
│   │   ├── findRoutes.js         # Anime image search
│   │   └── chatRoutes.js         # Global chat pool APIs
│   ├── services/                 # External API integrations + SSE hubs
│   │   ├── chatHub.js            # Chat SSE hub
│   │   └── logHub.js             # Admin console log SSE hub
│   ├── middleware/               # CSRF protection, JWT verification
│   └── verify_security.js        # Security verification script
├── nginx.security.headers.conf   # Nginx security headers snippet
├── public/                       # Static assets
├── dist/                         # Production build output (gitignored)
├── package.json                  # Frontend dependencies
└── backend/package.json          # Backend dependencies

Known Limitations and Technical Debt

Active Issues

  1. Database Foreign Keys: The audit_logs table FK constraint was removed to support ephemeral admin IDs. This is intentional but reduces referential integrity.
  2. CSRF Implementation: Custom CSRF token system exists but could be replaced with battle-tested library (csurf is deprecated, alternatives needed).
  3. Mixed Auth Patterns: JWT moved to httpOnly cookies, but user state still persists in localStorage for display purposes. Hybrid approach works but is inconsistent.
  4. Admin Minting Tooling Missing: verify_security.js expects backend/scripts/mint-admin-session.js, but that script is not in this repo.
  5. No Automated Tests: Aside from backend/verify_security.js, there is no CI/CD, no unit tests, and no integration tests. Manual verification only.
  6. WAL Mode Files: SQLite WAL/SHM files (*.db-wal, *.db-shm) are gitignored but not auto-managed. Expect ~600KB of WAL files to persist on disk.

Architectural Cruft

  • Repository Pattern: Recently refactored from monolithic server.js. Some routes still have business logic that should move to repositories.
  • Hardcoded Secrets Check: Server validates JWT_SECRET on startup but doesn't enforce rotation or alert on age.
  • Error Handling: Database errors often surface raw SQLite messages to clients instead of sanitized errors.

Common Failure Modes and How to Unfuck Them

1. Backend won't start: "SECURITY VALIDATION FAILED"

Cause: JWT_SECRET in .env is the default placeholder.

Fix:

cd backend
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" >> temp_secret.txt
# Copy output, paste into .env as JWT_SECRET=<value>

2. "Invalid credentials" on every admin login attempt

Cause: Either (a) credentials already used, (b) session expired, or (c) typo.

Fix:

# Mint a fresh session using your internal tooling (no script included in repo)

# Verify session in database (if paranoid)
sqlite3 pds_auth.db "SELECT username, expires_at FROM ephemeral_admin_sessions;"

3. Frontend shows "Network Error" on API calls

Symptoms: CORS errors in browser console.

Causes:

  • Backend not running (http://localhost:3001 down)
  • Vite proxy misconfigured (check vite.config.js)
  • CORS origin mismatch (check backend/server.js line 44-47)

Fix:

# Check backend is alive
curl http://localhost:3001/api/status

# If down, restart:
cd backend
npm run dev

4. Database locked errors

Symptom: SQLITE_BUSY errors in logs.

Cause: WAL mode not enabled, or multiple simultaneous writes.

Fix:

# Verify WAL is enabled
cd backend
sqlite3 pds_auth.db "PRAGMA journal_mode;"  # Should return "wal"

# If not:
sqlite3 pds_auth.db "PRAGMA journal_mode=WAL;"

5. sessions expire immediately after login

Cause: Server time drift or session minted in the past.

Fix:

# Check server time
date -u  # Should match UTC

# Cleanup expired sessions
cd backend
node -e "const repo = require('./db/repositories/ephemeralSessionRepository'); console.log('Cleaned:', repo.cleanupExpired());"

Contributing

What NOT to Touch

  • backend/db/migrations.js: Database schema changes need careful review. Coordinate with maintainer before modifying.
  • backend/db/repositories/ephemeralSessionRepository.js: Security-critical. Do not weaken the entropy or expiration logic.
  • backend/middleware/authMiddleware.js: Security-critical JWT validation.
  • JWT cookie flags (httpOnly, secure, sameSite): Changing these can introduce XSS/CSRF vulnerabilities.

What NEEDS Help

  1. Testing Infrastructure: No tests exist. Jest + Supertest for API tests, Vitest for frontend would be ideal.
  2. Error Handling: Sanitize SQLite errors before sending to client. Create a centralized error handler.
  3. Referral System: Code exists (referralRepository.js) but frontend UX is incomplete.
  4. Mobile UX: Navbar and request form are functional on mobile but not optimized.
  5. Documentation: JSDoc or TypeScript migration would massively improve maintainability.
  6. Dependency Audits: Run npm audit periodically. Some transitive deps may be stale.

Contribution Workflow

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/improve-error-handling)
  3. Make atomic commits with descriptive messages
  4. Test locally (both dev servers running, verify affected features)
  5. Push and open a PR

Note: There's no CI/CD pipeline. Deployment is manual via SSH to EC2. Breaking changes must be coordinated with the maintainer to avoid downtime.

License Status

MISSING / UNLICENSED

No LICENSE file exists in the repository root. Default copyright applies: all rights reserved to the author(s). If you plan to fork or redistribute, request explicit licensing from the repository owner.

Package licenses: All npm dependencies are bundled with their own licenses (mostly MIT/ISC). Run npm list --json to audit.

Deployment Details

Current Production Environment:

  • Platform: AWS EC2 (Ubuntu)
  • Instance: <EC2_INSTANCE_ADDRESS> (contact maintainer for details)
  • SSH Key: ~/.ssh/<PROJECT_KEY>.pem (not in repo, managed separately)
  • Process Manager: pm2 or systemd
  • Web Server: Nginx reverse proxy

Security Headers (Nginx):

  • Apply the headers in nginx.security.headers.conf to the SPA server block to enable clickjacking protection and a frontend CSP.
  • Ensure the backend port is not publicly reachable; Nginx should be the only ingress to /api.

To deploy updates:

# From local machine
git push origin main

# SSH into EC2
ssh -i ~/.ssh/<PROJECT_KEY>.pem ubuntu@<EC2_INSTANCE_ADDRESS>

# On server
cd /path/to/PDS
git pull
npm ci
cd backend && npm ci --omit=dev && cd ..
npm run build
pm2 restart pds-backend  # or equivalent

Known Deployment Issues:

  • Previous 502 errors traced to backend crashes (likely uncaught exceptions).
  • Manual restarts required when backend dies. No auto-restart configured.

Final Notes

This is a real project under active development, not a polished product. The security model is sound (ephemeral admin, httpOnly cookies, audit logs) but the codebase has the usual rough edges of a solo/small-team project:

  • Features added incrementally without comprehensive refactoring
  • Some dead code and unused routes may exist
  • Performance optimizations are selective (GSAP tuned, but no CDN, no aggressive caching)
  • Documentation is improving but inconsistent

If you're onboarding to contribute or maintain this, read the code, trace a request end-to-end, and don't assume the README is exhaustive. When in doubt, check verification_report.md for the last known-good security state, or SSH into the EC2 instance to see the deployed configuration.

Questions or issues? Open a GitHub issue or contact the maintainer directly.

About

Probably a websites

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors