steelforesight/panel
alireza fc103c8534 Add stack-specific hardening guidelines for Node + Postgres/MySQL applications
This document provides detailed security measures tailored for applications using Node.js with Postgres or MySQL, including authentication, authorization, file uploads, Stripe integration, and more. It emphasizes the importance of rebuilding safety nets such as Postgres Row Level Security and implementing strict ownership checks to mitigate risks associated with direct database access. Additionally, it covers best practices for CORS, CSRF protection, error handling, and secrets management, ensuring a comprehensive approach to securing the stack.
2026-06-27 17:10:53 +03:30
..
public Add stack-specific hardening guidelines for Node + Postgres/MySQL applications 2026-06-27 17:10:53 +03:30
scripts feat: phone+OTP auth, profile redesign, At-a-Glance Figma polish, radar/article fixes 2026-06-23 16:56:16 +03:30
.env.example Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
.gitignore Add admin panel + wire main site to fetch articles from panel API 2026-05-26 17:11:04 +03:30
.liaraignore Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
README.md Add admin panel + wire main site to fetch articles from panel API 2026-05-26 17:11:04 +03:30
db.js Add stack-specific hardening guidelines for Node + Postgres/MySQL applications 2026-06-27 17:10:53 +03:30
imports-data.json feat: add RadarPost page with membership gate and related sidebar 2026-06-18 08:45:02 +03:30
insert-events.mjs Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
insert-factory.mjs Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
liara.json Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
package-lock.json Add stack-specific hardening guidelines for Node + Postgres/MySQL applications 2026-06-27 17:10:53 +03:30
package.json Add stack-specific hardening guidelines for Node + Postgres/MySQL applications 2026-06-27 17:10:53 +03:30
run-import.mjs feat: add RadarPost page with membership gate and related sidebar 2026-06-18 08:45:02 +03:30
scraper.js Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
seed-content.js Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
seed.js Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
server.js Add stack-specific hardening guidelines for Node + Postgres/MySQL applications 2026-06-27 17:10:53 +03:30
update-radar-images.mjs Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30

README.md

Andishkade Foolad — Admin Panel

A standalone Node/Express + SQLite admin panel for managing articles published on the Andishkade Foolad site.

Features

  • Login (single admin, bcrypt-hashed password, JWT session)
  • CRUD for articles with all fields used on the site: title, category, type, author / role / initial, publish date (Jalali string), pages, price, isFree, summary, body, cover image, tags, featured flag
  • Cover image upload (multer, stored on disk under uploads/)
  • Public read API (GET /api/articles) that the main React site can consume

Stack

  • Node 20+
  • Express 4
  • better-sqlite3 (single-file data.db)
  • multer for uploads
  • bcryptjs + jsonwebtoken for auth
  • Vanilla JS admin UI (no build step)

First-time setup

cd panel
npm install
cp .env.example .env       # then edit .env, especially JWT_SECRET and ADMIN_PASSWORD
npm run seed               # creates the admin user from .env
npm start

Then open http://localhost:3001.

Login with the ADMIN_USERNAME / ADMIN_PASSWORD values from .env.

API

All write endpoints require Authorization: Bearer <token>. The token is returned by POST /api/auth/login.

Method Path Auth Purpose
POST /api/auth/login {username, password}{token, user}
GET /api/auth/me yes current user info
GET /api/articles list articles (newest first)
GET /api/articles/:id single article
POST /api/articles yes create article
PUT /api/articles/:id yes update article
DELETE /api/articles/:id yes delete article
POST /api/uploads yes multipart file{url}
GET /api/health {ok: true}

Article shape

{
  "id": "abc123…",
  "title": "…",
  "category": "بازار جهانی",
  "type": "special",
  "author": "دکتر علی محمدی",
  "authorRole": "مدیر ارشد پژوهش",
  "authorInitial": "م",
  "publishDate": "بهمن ۱۴۰۳",
  "pages": 84,
  "price": 850000,
  "isFree": false,
  "summary": "…",
  "body": "متن کامل …",
  "coverImage": "/uploads/abc.jpg",
  "tags": ["تجارت جهانی", "صادرات"],
  "featured": true,
  "createdAt": "2026-05-26T13:20:00.000Z",
  "updatedAt": "2026-05-26T13:20:00.000Z"
}

This shape is intentionally compatible with the Report type in ../src/data/reports.ts, so the main site can swap the hardcoded array for fetch('/api/articles') without touching its UI components.

Wiring the main site to the panel

In the main Vite app, replace the hardcoded import:

// src/lib/articles.ts
const API = import.meta.env.VITE_PANEL_API || 'http://localhost:3001';

export async function fetchReports() {
  const res = await fetch(`${API}/api/articles`);
  return res.json();
}

Then in the consuming components (e.g. LatestNewsBentoSection.tsx), call fetchReports() inside a useEffect / React Query hook instead of the static reports array.

Set VITE_PANEL_API in the main app's .env to the panel's public URL when deploying.

Deployment notes

  • The panel listens on PORT (default 3001). It serves the admin UI at / and exposes /api/*.
  • Persist the data.db file and the uploads/ folder — these are your content. Both are gitignored.
  • For HF Spaces, the panel is not the same image as the main site; deploy it as a separate Space (Docker SDK) or on a small VPS.
  • Always change JWT_SECRET and ADMIN_PASSWORD in production.

Reset admin password

sqlite3 data.db "DELETE FROM users WHERE username='admin';"
# edit .env with the new password, then:
npm run seed