Portfolio Pro is a production-oriented personal portfolio platform built with Flask and PostgreSQL. It includes a public portfolio site, admin content management screens, contact capture, REST API endpoints, authentication, migrations, and Render-ready deployment configuration.
Live demo: https://emmanuel-amponsah.onrender.com
- Public homepage, about page, project listing, project detail pages, and contact form
- Admin dashboard for project and contact management
- Flask-Login authentication for browser admin sessions
- JWT-protected API endpoints for admin API operations
- SQLAlchemy models with Flask-Migrate migrations
- Contact persistence with optional SMTP notification
- Custom error pages for common failures
- Health endpoint at
/healthfor deployment checks - Pytest test structure with unit and integration coverage
- Ruff, Black, isort, and GitHub Actions CI preparation
- Python, Flask, SQLAlchemy, Flask-Migrate
- Flask-Login, Flask-WTF, WTForms
- Flask-RESTful, Flask-JWT-Extended, Flask-Limiter
- PostgreSQL in production, SQLite fallback for local development
- Gunicorn and Render for deployment
- pytest, pytest-flask, factory-boy
portfolio_pro/
├── app/
│ ├── admin/
│ ├── api/
│ ├── auth/
│ ├── errors/
│ ├── forms/
│ ├── main/
│ ├── models/
│ ├── services/
│ ├── static/
│ ├── templates/
│ ├── utils/
│ └── __init__.py
├── docs/
├── migrations/
├── scripts/
├── tests/
├── config.py
├── manage.py
├── run.py
├── wsgi.py
└── requirements.txt
The application uses the Flask application factory pattern. Feature routes are grouped into main, auth, and admin blueprints, while JSON endpoints are registered from app/api. Shared infrastructure such as logging, error handlers, template filters, and extension initialization is centralized.
This project uses proenv as the official local virtual environment directory.
git clone <repository-url>
cd portfolio_pro
python -m venv proenv
source proenv/bin/activate
pip install -r requirements.txt
cp .env.example .envUpdate .env with local secrets and database settings before running production-like workflows.
Key variables:
FLASK_CONFIG:local,development,testing, orproductionSECRET_KEY: Flask session signing secretJWT_SECRET_KEY: JWT signing secretDATABASE_URL: PostgreSQL connection URLADMIN_EMAIL: notification recipientMAIL_SERVER,MAIL_PORT,MAIL_USERNAME,MAIL_PASSWORD: SMTP configurationCORS_ORIGINS: comma-separated allowed API originsREDIS_URL: optional rate-limit storage backend
See .env.example for a complete template.
For local SQLite fallback, no PostgreSQL URL is required. For PostgreSQL, set DATABASE_URL, then run:
flask --app manage.py db upgrade
flask --app manage.py create-adminpython run.pyThe app runs at http://localhost:5000 by default.
Copy the example environment file and adjust secrets before starting containers:
cp .env.example .envFor Docker, DATABASE_URL must use the Compose database hostname:
postgresql://portfolio_user:portfolio_password@db:5432/portfolio_pro
Build and start the application:
docker compose config
docker compose build
docker compose upOpen the app at http://127.0.0.1:5000 and check health at http://127.0.0.1:5000/health.
Run migrations and verification commands in the running web container:
docker compose exec web flask db upgrade
docker compose exec web pytest
docker compose exec web python scripts/verify_startup.pyStop containers:
docker compose downReset the local Docker database volume:
docker compose down -v
docker compose up --buildIf web cannot connect to PostgreSQL, confirm .env uses POSTGRES_HOST=db and a DATABASE_URL with @db:5432, not @localhost:5432.
pytestQuality checks:
ruff check .
black --check .
isort --check-only .Render configuration:
- Build command:
bash build.sh - Start command:
gunicorn wsgi:app - Environment:
FLASK_CONFIG=production - Health check path:
/health
Run migrations with flask db upgrade from a trusted deployment shell or release process.
Add screenshots for:
- Homepage
- Projects page
- Project detail page
- Admin dashboard
- Contact workflow
Current static project screenshots live under app/static/images/project/.
- Add coverage reporting thresholds in CI
- Add API schema validation with Marshmallow or Pydantic
- Move email delivery to a background worker if traffic grows
- Add Redis-backed rate limiting in production
- Add admin audit logging for content changes
- Add browser-level smoke tests for critical public pages
This project is maintained as a professional portfolio and learning resource.