This is a CV / Resume management system with an editable theme, persistent database storage, and Docker deployment ready for Unraid.
Live GitHub Pages demo: https://aedankerr.github.io/site-manager/
- Template/demo exports: Includes a standalone generic technical dossier template under
examples/technical-dossier-template/for theme/layout reference. - 7 Sections: About, Timeline (auto-generated), Experience, Certifications, Education, Skills, Projects
- Custom Sections: Add your own sections with different layout possibilities
- Full CRUD: Add, edit, delete any item
- Visibility Toggles: Hide items from PDF export while keeping them in database
- Print/PDF Export: Clean print styles, hidden items excluded
- Import/Export: Backup and restore your CV data as JSON - ideal to process the data via any LLM for optimization
- Persistent Storage: SQLite database survives container restarts
- Multi CV: Save different of your CV. Preview them and load them as need be
- Responsive Design: Works on desktop and mobile
- Auto-Generated Timeline: Timeline automatically builds from your experiences
- ATS Optimized: Schema.org markup, semantic HTML, hidden keywords for job site parsing
- SEO Ready: Dynamic robots.txt and sitemap.xml for the public site
The repository includes a standalone static dossier template in examples/technical-dossier-template/. It is useful as a theme/layout reference or as a starting point for exported resume pages without replacing the main installable Site Manager app.
cd examples/technical-dossier-template
python3 -m http.server 8080Then open http://localhost:8080/index.html. The static demo includes index.html, cv.html, projects.html, and contact.html, all using the same shared assets/site-style.css file.
curl -fsSL https://raw.githubusercontent.com/Aedankerr/site-manager/main/install.sh | bashOr download and run:
wget https://raw.githubusercontent.com/Aedankerr/site-manager/main/install.sh
chmod +x install.sh
./install.sh# Clone or copy the files
cd site-manager
# Create data directory
mkdir -p /mnt/user/appdata/site-manager/data/uploads
# Start the container
docker-compose up -d --build
# Access at:
# - http://localhost:3010 (Admin - full edit access)
# - http://localhost:3011 (Public - read-only)Use docker-compose.volume.yml if you prefer Docker-managed volumes:
docker-compose -f docker-compose.volume.yml up -d --build# Build the image
docker build -t site-manager .
# Run with persistent data
docker run -d \
--name site-manager \
-p 3010:3010 \
-p 3011:3011 \
-v /mnt/user/appdata/site-manager/data:/app/data \
--restart unless-stopped \
site-manager| Port | Mode | Description |
|---|---|---|
| 3010 | Admin | Full edit access, toolbar, all controls |
| 3011 | Public | Read-only, no toolbar, no edit buttons, security hardened |
- GET-only: All POST/PUT/DELETE requests blocked
- Rate limiting: 60 requests/minute per IP
- Security headers: X-Frame-Options, CSP, XSS protection
- No sensitive data: Email/phone not exposed in API
- Visible items only: Hidden items not returned by API
- No IDs exposed: Database IDs not included in responses
- SEO files: Dynamic robots.txt and sitemap.xml
Point your CF tunnel to port 3011 for public access:
# In your cloudflared config
ingress:
- hostname: cv.yourdomain.com
service: http://site-manager:3011The sitemap.xml and robots.txt are automatically generated with the correct domain based on the incoming request headers.
Site Manager has Community Apps-compatible XML templates in this repo, but the public Unraid Apps listing is not published yet.
The templates are suitable for Unraid 7.3.1: they include a minimum supported version of 6.9 and do not set a maximum version cap.
Expected Unraid container logs show the admin server on localhost:3010, the public server on localhost:3011, and Database path: /app/data/site.db. If logs show 3000/3001 or /app/data/cv.db, refresh/reapply the current XML template variables.
To add it to Community Apps, submit this repository from the Unraid Community Applications submit flow:
https://github.com/Aedankerr/site-manager
Once it is listed:
- In the Unraid Apps tab, search for Site Manager.
- Install Site Manager (Admin) first.
- Install Site Manager (Public) second if you want a separate read-only public container.
- Use the same AppData and Uploads paths for both containers so they share the same database and images.
Until the Community Apps listing is published, use Method 2 or the custom XML templates documented in
docs/getting-started/unraid.md.
The repository includes current Unraid/Community Apps template files under templates/:
templates/site-manager.xmlβ Admin template for Community Apps submission and direct template installstemplates/site-manager-public.xmlβ Public read-only template for Community Apps submission and direct template installs
Follow the detailed custom-template and Community Apps submission notes in docs/getting-started/unraid.md.
- Install the "Docker Compose Manager" plugin from Community Apps
- Create a new stack with the
docker-compose.ymlcontent - Set the path for data persistence (e.g.,
/mnt/user/appdata/site-manager/data) - Start the stack
The SQLite database is stored in the data directory. Make sure to:
- Mount
/app/datato a persistent location on your host - Back up the
cv.dbfile periodically - Use the Export feature for JSON backups
To add your profile picture:
- Name your picture
picture.jpeg - Place it in the
data/uploads/folder:- Docker:
/app/data/uploads/picture.jpeg(inside container) - Unraid bind mount:
/mnt/user/appdata/site-manager/data/uploads/picture.jpeg - Docker volume: Use
docker cp picture.jpeg site-manager:/app/data/uploads/
- Docker:
The picture will automatically display instead of initials. If no picture is found, initials are shown as fallback.
Supported format: JPEG (must be named picture.jpeg)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/profile |
Get profile data |
| PUT | /api/profile |
Update profile |
| GET | /api/experiences |
List all experiences |
| POST | /api/experiences |
Create experience |
| PUT | /api/experiences/:id |
Update experience |
| DELETE | /api/experiences/:id |
Delete experience |
| GET | /api/certifications |
List certifications |
| POST | /api/certifications |
Create certification |
| PUT | /api/certifications/:id |
Update certification |
| DELETE | /api/certifications/:id |
Delete certification |
| GET | /api/education |
List education |
| POST | /api/education |
Create education |
| PUT | /api/education/:id |
Update education |
| DELETE | /api/education/:id |
Delete education |
| GET | /api/skills |
List skill categories |
| POST | /api/skills |
Create skill category |
| PUT | /api/skills/:id |
Update skill category |
| DELETE | /api/skills/:id |
Delete skill category |
| GET | /api/projects |
List projects |
| POST | /api/projects |
Create project |
| PUT | /api/projects/:id |
Update project |
| DELETE | /api/projects/:id |
Delete project |
| GET | /api/timeline |
Get auto-generated timeline |
| GET | /api/sections |
Get section visibility |
| PUT | /api/sections/:name |
Update section visibility |
| GET | /api/cv |
Export all CV data |
| POST | /api/import |
Import CV data |
Create a JSON file with your CV data and use the Import button, or POST to /api/import:
{
"profile": {
"name": "Your Name",
"initials": "YN",
"title": "Your Title",
"subtitle": "Your tagline",
"bio": "Your bio...",
"location": "City, Country",
"linkedin": "https://linkedin.com/in/yourprofile",
"languages": "English, French"
},
"experiences": [
{
"job_title": "Senior Developer",
"company_name": "Company Inc",
"start_date": "2020-01",
"end_date": "",
"location": "Remote",
"country_code": "us",
"highlights": ["Led team of 5", "Delivered project X"]
}
],
"certifications": [
{
"name": "AWS Solutions Architect",
"provider": "Amazon",
"issue_date": "Jan 2023"
}
],
"education": [
{
"degree_title": "MSc Computer Science",
"institution_name": "University",
"start_date": "2010",
"end_date": "2014",
"description": "Focus on AI"
}
],
"skills": [
{
"name": "Programming",
"icon": "π»",
"skills": ["JavaScript", "Python", "Go"]
}
],
"projects": [
{
"title": "Project Name",
"description": "What it does",
"technologies": ["React", "Node.js"]
}
]
}| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Server port |
PUBLIC_PORT |
3001 |
Server port Read only |
DB_PATH |
./data/cv.db |
SQLite database path |
# Install dependencies
npm install
# Run in development mode (auto-reload)
npm run dev
# Run in production mode
npm startPolyForm Noncommercial 1.0.0 β free for personal and non-commercial use. Commercial use is not permitted. See LICENSE.txt for details.