| .. | ||
| example1-dark.png | ||
| example1-light.png | ||
| README.md | ||
Project Documentation
This documentation provides a precise overview of the project, its runtime architecture, configuration, data model, and operational guidance. It also lists observed issues and actionable recommendations without changing any source code.
Overview
- Purpose: Serve a personal resume as a simple Node.js web app with EJS templates and static assets.
- Stack:
Node.js,Express,EJS,Bootstrap,log4js,fs-extra. - Entry points:
- App:
app.js - Route:
routes/home.js - View:
views/cv.ejs - Static assets:
public/
- App:
Folder Structure
app.js: Express app setup, example content bootstrap, logging, server start.routes/home.js: Root route that reads JSON and renders the CV template.views/: EJS templates (cv.ejs, partials/head).public/: Static resources,examples/with sample resumes,ress/for icons and mounted content (public/ress/mountedRess).utils/logger.js:log4jsconfiguration writing tologs/out.logand stdout.utils/path.js: Helper to resolve the root directory.images/: README screenshots.Dockerfile: Container build (Node 22 Alpine base).package.json: Dependencies and project metadata.logs/: Runtime logs (created at runtime if not present).
Runtime Architecture
- Express app with a single route (
/) that rendersviews/cv.ejs. - On startup, if
public/ress/mountedRess/me.jsonis missing, the app copies the selected example directory intopublic/ress/mountedRessand verifiesme.json. - Static middleware serves assets from
public/, Bootstrap, and Font Awesome fromnode_modules. - Logging via
log4jsboth to stdout andlogs/out.log.
Configuration
- Example selector: environment variable
example(numeric) determines which example is copied on first run.1→public/examples/cvExample12→public/examples/cvExample2
- Port: server listens on env
PORT(default5555). - Mounted data: user-provided resume data and images should live in
public/ress/mountedRess(can be bind-mounted in Docker).
Notes and mismatches observed:
- Dockerfile sets
ENV EXAMPLE=2(uppercase), while the app readsprocess.env.example(lowercase). Recommend unifying on a single variable name. - No
npm startscript; app is run withnode app.js.
Data Model (me.json)
The resume is driven by a JSON document typically located at public/ress/mountedRess/me.json with the following top-level properties:
enableTestimonials(boolean): Enable/disable the testimonials feature.showTestimonialsInMain(boolean): Place testimonials in main column if true, otherwise in the sidebar.picture(string): Path to profile image (e.g.,/ress/mountedRess/me.jpg).name(string): Full name.header(string): Subtitle/role.about(string): About text.mail(string): Contact email.interests(array): Items withtitleand optionalsubentriesarray.educations(array): Items withdate,desc1,desc2.menus(array): Skill sections withtitleandsubentriesarray.links(array): Items withimagePathandlinkURL; optionallyidto tag an image.workexperiences(array): Items withdate,title,desc, and optionalhighlightsarray.testimonials(array): Items withname,title,text.
EJS uses <%= ... %> which escapes by default, reducing XSS risk when rendering untrusted text. Image paths and links are used directly; ensure they reference safe, expected locations.
Endpoints
GET /: Readsme.jsonand renders the CV page (views/cv.ejs).
Logging
log4jsis configured with two appenders: stdout andlogs/out.log.- The middleware
log4js.connectLoggeris enabled at app level for basic request logging. - A custom request logger is declared after route registration and may not run for requests that complete within routes; relying on
connectLoggeris sufficient for request logs. - No log rotation or size limits are configured.
Running Locally
Without Docker:
npm installnpm start- Open
http://localhost:5555
With Docker (examples):
- Example 1:
docker run --rm -p 8001:5555 -e example=1 blade34242/my-resume2:latest - Example 2:
docker run --rm -p 8002:5555 -e example=2 blade34242/my-resume2:latest
With Docker (mount your data):
docker run --rm -p 8003:5555 -v <LOCAL_PATH>:/home/node/app/public/ress/mountedRess blade34242/my-resume2:latest
Known Issues and Recommendations
- Env var: unified on
example(lowercase) consistently. - Docker base image: upgraded to
node:22-alpine. - Hardcoded port: make
PORTconfigurable via env. - Unused imports:
body-parserandreadLogare imported but unused. - Request logging placement: the custom logger middleware runs after routes; consider moving before routes or removing in favor of
connectLogger. - Sync file IO on request:
routes/home.jsusesfs.readFileSync; prefer asyncfs.promises.readFile. - Global variable leak:
pwdis assigned withoutconst/letinroutes/home.js. - Added npm scripts:
start,dev(nodemon). - Added 404/error handlers and graceful shutdown.
- No tests or linter: introduce a minimal test and lint setup.
- Log rotation: configure rolling file appender to prevent unbounded log growth.
- Docker runtime user/permissions: verify non-root user and proper ownership for mounted volumes.
Troubleshooting
- Blank page or errors on
/: check thatpublic/ress/mountedRess/me.jsonexists and contains valid JSON. - Images not loading: verify
pictureand linkimagePathpoint to existing files underpublic/ressor the mounted folder. - Port conflicts: change container port mapping or make app port configurable.
- Logs missing: ensure
logs/exists or that the process has write permissions; check stdout logs.
Roadmap (Actionable)
- Configuration
- Unify
example/EXAMPLEhandling and read viaprocess.envwith defaults. - Introduce
PORTenv.
- Unify
- Code health
- Remove unused imports; fix global
pwd. - Switch to async file IO for request path.
- Add input validation for
me.jsonstructure.
- Remove unused imports; fix global
- Build & Ops
- Upgrade Docker base to Node 18/20; add healthcheck.
- Add basic CI (lint + build).
- Add log rotation in
log4js.
- Features
- Implement PDF export or link to external print-to-PDF guidance.
- Optional dark mode and theme tweaks.
Reference
- Main app:
app.js - Route:
routes/home.js - View:
views/cv.ejs - Examples:
public/examples/cvExample1,public/examples/cvExample2 - Logger:
utils/logger.js