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.
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.
- Request Management System: Users sign up, submit rendering requests via a multi-step form, and receive cryptographic access keys to track their submissions.
- 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.
- 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.
- Experimental GPU Route:
/gpuis a WebGL/GPU experiment separate from the main flow. - Cinematic UI: GSAP + Framer Motion powered scrollytelling experience with a dark "cyberpunk luxury" aesthetic.
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)
- 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.
As of February 9, 2026, worker automation endpoints are intentionally disabled by default.
/api/worker/*returns503 Worker API is temporarily disabled- To re-enable locally or in controlled environments, set
ENABLE_WORKER_API=trueinbackend/.env - Worker auth is database-backed per worker, not a single shared backend
.envsecret
Each worker now authenticates with:
X-WORKER-IDX-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-01Full 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.
The repository is configured to avoid committing operational secrets and local runtime artifacts.
- Never commit
.envfiles or private keys/certs - SQLite runtime files and logs are gitignored
- Local PowerShell automation files (
*.ps1) are gitignored - Keep only templates like
backend/.env.examplein version control
- Node.js: v18+ (developed on v18/v20)
- npm: 9+
- Platform: Tested on Windows 11 and Ubuntu (EC2). macOS untested.
-
Clone and install dependencies:
git clone https://github.com/anstonbrick/PDS.git cd PDS npm ci cd backend npm ci cd ..
-
Configure backend environment:
cd backend cp .env.example .envEdit
backend/.envwith 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_SECRETis the default placeholder. Generate a cryptographically secure secret. -
Run dev servers (two terminals):
Terminal 1 - Backend:
cd backend npm run devBackend runs on
http://localhost:3001Terminal 2 - Frontend:
npm run dev
Frontend runs on
http://localhost:5173
# 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_PROXYto match your proxy hop count (recommended:loopbackwhen Nginx is on the same host). - See "Deployment Details" section below for production environment 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.
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.
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).
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
- Database Foreign Keys: The
audit_logstable FK constraint was removed to support ephemeral admin IDs. This is intentional but reduces referential integrity. - CSRF Implementation: Custom CSRF token system exists but could be replaced with battle-tested library (csurf is deprecated, alternatives needed).
- Mixed Auth Patterns: JWT moved to httpOnly cookies, but user state still persists in
localStoragefor display purposes. Hybrid approach works but is inconsistent. - Admin Minting Tooling Missing:
verify_security.jsexpectsbackend/scripts/mint-admin-session.js, but that script is not in this repo. - No Automated Tests: Aside from
backend/verify_security.js, there is no CI/CD, no unit tests, and no integration tests. Manual verification only. - 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.
- 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_SECRETon 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.
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>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;"Symptoms: CORS errors in browser console.
Causes:
- Backend not running (
http://localhost:3001down) - Vite proxy misconfigured (check
vite.config.js) - CORS origin mismatch (check
backend/server.jsline 44-47)
Fix:
# Check backend is alive
curl http://localhost:3001/api/status
# If down, restart:
cd backend
npm run devSymptom: 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;"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());"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.
- Testing Infrastructure: No tests exist. Jest + Supertest for API tests, Vitest for frontend would be ideal.
- Error Handling: Sanitize SQLite errors before sending to client. Create a centralized error handler.
- Referral System: Code exists (
referralRepository.js) but frontend UX is incomplete. - Mobile UX: Navbar and request form are functional on mobile but not optimized.
- Documentation: JSDoc or TypeScript migration would massively improve maintainability.
- Dependency Audits: Run
npm auditperiodically. Some transitive deps may be stale.
- Fork the repo
- Create a feature branch (
git checkout -b feature/improve-error-handling) - Make atomic commits with descriptive messages
- Test locally (both dev servers running, verify affected features)
- 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.
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.
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:
pm2or systemd - Web Server: Nginx reverse proxy
Security Headers (Nginx):
- Apply the headers in
nginx.security.headers.confto 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 equivalentKnown Deployment Issues:
- Previous 502 errors traced to backend crashes (likely uncaught exceptions).
- Manual restarts required when backend dies. No auto-restart configured.
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.