steelforesight/panel
alireza ae69f310df feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +03:30
..
public feat: update and harden steel foresight 2026-07-16 09:07:33 +03:30
scripts feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +03:30
.env feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +03:30
.env.example Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
.gitignore feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +03:30
.liaraignore Refactor authentication handling across PostDetail, ProfilePage, Radar, and RadarPost components 2026-06-18 08:47:00 +03:30
Dockerfile feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +03:30
README.md Add admin panel + wire main site to fetch articles from panel API 2026-05-26 17:11:04 +03:30
clear-banners.js feat: Add caveman skills for compression, review, help, and stats 2026-07-04 10:40:11 +03:30
content-generator.js feat: update and harden steel foresight 2026-07-16 09:07:33 +03:30
db.js feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +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 feat: update membership gate copy for clarity and engagement 2026-06-29 17:06:42 +03:30
package.json feat: update membership gate copy for clarity and engagement 2026-06-29 17:06:42 +03:30
reset-password.js feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +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 feat: Add caveman skills for compression, review, help, and stats 2026-07-04 10:40:11 +03:30
seed-radar.js feat: update membership gate copy for clarity and engagement 2026-06-29 17:06:42 +03:30
seed.js feat: update membership gate copy for clarity and engagement 2026-06-29 17:06:42 +03:30
server.js feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +03:30
transfer.js feat: sync latest changes and include environment configurations 2026-08-25 15:19:17 +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