Leptos Portfolio Admin is a comprehensive, full-stack portfolio website solution built entirely in Rust. It leverages the Leptos framework for server-side rendering (SSR) and interactive frontend components, coupled with an Actix Web backend API. You can see a demo of the project by visiting my website. Check it out!
Key Highlights:
This project aims to provide a ready-to-use, customizable portfolio site that is easy to maintain through its dedicated admin interface and offers an engaging chat experience.
dynamic-agent
backend can query its configured vector database. This database should be populated with your portfolio information (profile, skills, experiences, etc.). The agent retrieves relevant text chunks and uses them, along with the user's query, to generate an informed answer via the LLM. This ensures responses are grounded in your actual portfolio data.The pre-defined chat suggestions are loaded from the /assets/pre-suggest.json
file. You can customize these suggestions to better fit your portfolio content and to trigger specific RAG queries.
1. Edit assets/pre-suggest.json
:
The file should be an array of suggestion groups. Each group object has the following structure:
[
{
"group_title": "General Topics",
"icon": "BsChatRightText", // Icon identifier
"suggestions": [
"Hello, how are you?",
"What can you do?"
]
},
{
"group_title": "Vector Database (Profile)", // Example for RAG
"icon": "ImProfile",
"suggestions": [
"What is your profile fullname?", // This query will leverage RAG
"List profile position name from experiences." // This also uses RAG
]
}
// Add more groups as needed
]
group_title
: The title displayed for the category of suggestions.icon
: A string identifier for the icon to be displayed next to the group title.suggestions
: An array of strings, where each string is a pre-defined question or prompt. Queries aimed at retrieving specific portfolio details (like those under "Vector Database (Profile)") will typically be handled by the dynamic-agent
's RAG pipeline.2. Configure Icons:
The icon
field in pre-suggest.json
is a key that maps to an actual icon from the icondata
crate. This mapping is defined in the ICON_MAP
static variable within the src/app/utils/utils.rs
file.
Finding Icons: You can browse available icons at the icondata icon explorer.
Adding New Icons to ICON_MAP
: If you want to use an icon that's not already in ICON_MAP
, you'll need to add it. Open src/app/utils/utils.rs
and add a new entry to the ICON_MAP
. For example, if you find an icon AiStarOutline
in icondata
(which would be i::AiStarOutline
in the code) and you want to use the key "MyStarIcon"
in your pre-suggest.json
:
// filepath: src/app/utils/utils.rs
// ...
pub static ICON_MAP: phf::Map<
&'static str,
&'static icondata_core::IconData
> = phf_map! {
// ... existing icons ...
"BsChatRightText" => i::BsChatRightText,
"ImProfile" => i::ImProfile,
"MyStarIcon" => i::AiStarOutline, // Add your new icon here
// ...
};
// ...
Ensure you have the correct use icondata as i;
statement at the top of utils.rs
. After updating ICON_MAP
, you can then use "MyStarIcon"
as the value for the icon
field in assets/pre-suggest.json
.
3. Ensure dynamic-agent
is Configured for RAG:
For the chat to effectively answer questions about your "profile" or other specific data using RAG:
dynamic-agent
backend must be configured with a data source containing your portfolio information (e.g., markdown files, database connection).dynamic-agent
README for detailed instructions on setting up its data sources, vector store, and RAG pipeline. The effectiveness of queries like "What profile fullname?" depends entirely on this backend configuration..env
) to enable adding, editing, and deleting content.Clone Project:
git clone https://github.com/DevsHero/leptos_portfolio_admin.git
cd leptos_portfolio_admin
Prepare .env
file:
Copy the example environment file. You will need to fill this file with your specific configuration details.
cp .env-example .env
Below are the variables defined in .env-example
and their purpose:
# --- SurrealDB Connection ---
# Defines the protocol (http/https) and host/port for the SurrealDB instance.
# Example: http:127.0.0.1:8000 or https:[your-cloud-instance.com](https://www.google.com/search?q=your-cloud-instance.com)
SURREAL_PROTOCOL_HOST=http:127.0.0.1:8000
# Username for SurrealDB authentication.
SURREAL_USER=root
# Password for SurrealDB authentication.
SURREAL_PASS=root
# The specific database name to use within SurrealDB.
SURREAL_DB=portfolio
# The namespace within SurrealDB.
SURREAL_NAMESPACE=portfolio
# --- Admin Panel ---
# Password required to access the Admin Mode for editing site content.
# Generate this using `cargo run --bin hash-password`
ADMIN_PASSWORD_HASH_ENCODED=
# --- Site Configuration ---
# The title displayed in the browser tab.
SITE_TITLE="Portfolio site based on pure rust"
# --- Redis Connection ---
# Redis connection URL used during local development (cargo leptos watch).
REDIS_URL_DEV="redis://localhost:6379"
# Redis connection URL used in the production Docker environment (connects to the 'redis' service).
REDIS_URL_PROD="redis://redis:6379"
# --- LLM Chat WebSocket Configuration (Optional) ---
# Full WebSocket URL (including ws:// or wss:// and port) for the dynamic-agent backend.
# Example: ws://127.0.0.1:4000 or wss://your-agent.example.com
WS_HOST="ws://127.0.0.1:4000"
# Optional secret API key used by this Leptos application to sign WebSocket connection requests to the dynamic-agent backend.
# If the dynamic-agent's SERVER_API_KEY is set, this key must match it.
# The Leptos server uses this key to generate an HMAC-SHA256 signature (X-Api-Sign) based on a timestamp (X-Api-Ts),
# which are then sent as query parameters to the WebSocket server for authentication.
CLIENT_WS_API_KEY=
Important: Replace the default values (like SURREAL_USER
, SURREAL_PASS
) with your own secure settings before deployment. Ensure ADMIN_PASSWORD_HASH_ENCODED
is generated and WS_HOST
points to your running dynamic-agent
instance if using the chat feature. The CLIENT_WS_API_KEY
should be a strong, unique secret if used.
Setup SurrealDB: You need a running SurrealDB instance. You can set one up locally or use a cloud provider.
Initialize Database Schema:
Connect to your SurrealDB instance (using the surreal sql
command-line tool or a GUI like Surrealist). Copy and execute all the commands from the surreal/script.surql
file to set up the necessary tables and schemas. Ensure you are connected to the correct namespace and database defined in your .env
file (NAMESPACE portfolio; USE DB portfolio;
).
This project uses an environment variable (ADMIN_PASSWORD_HASH_ENCODED
) stored in a .env
file for local admin access. Use this script to generate the hash and automatically update the file:
1. Run the Script:
Cargo.toml
is).cargo run --bin hash-password
2. Check .env
File:
.env
file in your project root, adding or replacing the ADMIN_PASSWORD_HASH_ENCODED
line with the newly generated hash..env
file to confirm the change and ensure other variables are still present.
(Note: If you're running the project via Docker, make sure to copy the .env file and include your ADMIN_PASSWORD_HASH_ENCODED value inside same docker-compose.yml)To enable the LLM Chat feature, you need to run the dynamic-agent project as the backend. This is a flexible AI agent framework built in Rust, designed for Retrieval-Augmented Generation (RAG). It can connect to various LLM providers and vector stores, allowing you to create a chat experience tailored to your portfolio data.
dynamic-agent
:git clone https://github.com/DevsHero/dynamic-agent.git
cd dynamic-agent
dynamic-agent
:cp .env-example .env
.env
file in the dynamic-agent
directory. You must configure:OPENAI_API_KEY
, ANTHROPIC_API_KEY
).LISTEN_ADDR
: The address and port the agent server will listen on (e.g., 0.0.0.0:4000
).SERVER_API_KEY
(Optional): If you set this, clients (like leptos_portfolio_admin
) must provide this key to connect.TLS_CERT_PATH
/ TLS_KEY_PATH
(Optional): Provide paths to your TLS certificate and key files to enable secure wss://
connections.dynamic-agent
README for detailed configuration options.dynamic-agent
:cargo run --release
dynamic-agent
's Docker instructions if available).leptos_portfolio_admin
:leptos_portfolio_admin
directory..env
file:WS_HOST
to the full URL of your running dynamic-agent
server (e.g., ws://127.0.0.1:4000
or wss://your-agent.domain.com
if using TLS).SERVER_API_KEY
in dynamic-agent
(this is the secret key for HMAC verification on the server), set the same secret value for CLIENT_WS_API_KEY
in leptos_portfolio_admin
's .env
file. This CLIENT_WS_API_KEY
will be used by the Leptos frontend server to sign its WebSocket connection requests.Select an option to run the main leptos_portfolio_admin
application:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env" # Or restart your terminal
rustup toolchain install nightly
rustup default nightly
rustup target add wasm32-unknown-unknown
cargo install cargo-leptos
# Ensure Docker is running
docker compose -f docker-compose.yml up -d redis
(Alternatively, install Redis directly via your system's package manager.)chromium
, not google-chrome
. Installation methods vary by OS. See this guide for help: Chromium Installation Guide.env
file (specifically REDIS_URL_DEV
and potentially WS_HOST
/CLIENT_WS_API_KEY
).cargo leptos watch
(If you have updated information on the web production, I suggest clearing the local Redis cache to sync the latest data from the database.)docker exec -i dragonfly_redis redis-cli FLUSHDB
http://localhost:3000
. The chat page should now connect to your dynamic-agent
backend if configured.--platform
if needed.)docker build --platform linux/amd64 -t leptos-portfolio-admin:latest .
.env
file is configured correctly in the project root. This command will start the application container and the Redis container. The application inside Docker uses REDIS_URL_PROD
. Ensure WS_HOST
in your .env
is accessible from within the Docker network (e.g., use Docker service names if dynamic-agent
is also containerized).docker compose -f docker-compose.yml up -d --force-recreate leptos-portfolio-admin redis
(This assumes your docker-compose.yml
defines services named leptos-portfolio-admin
and redis
, configured to use the built image and read the .env
file.)http://localhost:8080
(or the port mapped in your docker-compose.yml
).(Assuming you have published an image to Docker Hub and have a suitable docker-compose.yml
)
.env
file is configured, paying attention to WS_HOST
accessibility.# Ensure your docker-compose.yml points to the Docker Hub image for the leptos-portfolio-admin service
docker compose pull && docker compose up -d --force-recreate
http://localhost:8080
(or the port mapped in your docker-compose.yml
).Contributions are welcome! This is my first Rust project. Please open issues or PRs for bugs, suggestions, or new features. Note: Primarily tested on macOS and Debian. Windows stability (Docker/WSL) not guaranteed.
Thanon Aphithanawat (Hero)