Compare commits
2 Commits
develop
...
6768946b0a
| Author | SHA1 | Date | |
|---|---|---|---|
|
6768946b0a
|
|||
|
1e769f0b39
|
6
.github/workflows/README.md
vendored
6
.github/workflows/README.md
vendored
@@ -7,7 +7,7 @@ The `publish-docker.yml` workflow automatically builds and publishes Docker imag
|
|||||||
### Triggers and Tagging Strategy
|
### Triggers and Tagging Strategy
|
||||||
|
|
||||||
| Event | Condition | Published Tags | Example |
|
| Event | Condition | Published Tags | Example |
|
||||||
|--------------|-----------------------------|------------------------|-------------------|
|
|--------------+-----------------------------+------------------------+-------------------|
|
||||||
| Tag push | Tag pushed to `main` branch | `latest` + version tag | `latest`, `1.0.0` |
|
| Tag push | Tag pushed to `main` branch | `latest` + version tag | `latest`, `1.0.0` |
|
||||||
| Branch push | Push to `develop` branch | `develop` | `develop` |
|
| Branch push | Push to `develop` branch | `develop` | `develop` |
|
||||||
| Pull request | PR opened or updated | `pr<number>` | `pr12` |
|
| Pull request | PR opened or updated | `pr<number>` | `pr12` |
|
||||||
@@ -18,7 +18,7 @@ The `publish-docker.yml` workflow automatically builds and publishes Docker imag
|
|||||||
Configure these secrets in your repository settings (`Settings` → `Secrets and variables` → `Actions`):
|
Configure these secrets in your repository settings (`Settings` → `Secrets and variables` → `Actions`):
|
||||||
|
|
||||||
| Secret Name | Description | Example Value |
|
| Secret Name | Description | Example Value |
|
||||||
|---------------------|---------------------------------------------|-----------------------------------------|
|
|---------------------+---------------------------------------------+-----------------------------------------|
|
||||||
| `DOCKER_USERNAME` | Username for Docker registry authentication | `phundrak` |
|
| `DOCKER_USERNAME` | Username for Docker registry authentication | `phundrak` |
|
||||||
| `DOCKER_PASSWORD` | Password or token for Docker registry | Personal Access Token (PAT) or password |
|
| `DOCKER_PASSWORD` | Password or token for Docker registry | Personal Access Token (PAT) or password |
|
||||||
| `CACHIX_AUTH_TOKEN` | (Optional) Token for Cachix caching | Your Cachix auth token |
|
| `CACHIX_AUTH_TOKEN` | (Optional) Token for Cachix caching | Your Cachix auth token |
|
||||||
@@ -84,7 +84,7 @@ Cachix is a Nix binary cache that dramatically speeds up builds by caching build
|
|||||||
Configure these in the workflow's `env` section or as repository variables:
|
Configure these in the workflow's `env` section or as repository variables:
|
||||||
|
|
||||||
| Variable | Description | Default Value | Example |
|
| Variable | Description | Default Value | Example |
|
||||||
|--------------------|------------------------------------------------|---------------|--------------------|
|
|--------------------+------------------------------------------------+---------------+--------------------|
|
||||||
| `CACHIX_NAME` | Name of the Cachix cache to use | `devenv` | `phundrak-dot-com` |
|
| `CACHIX_NAME` | Name of the Cachix cache to use | `devenv` | `phundrak-dot-com` |
|
||||||
| `CACHIX_SKIP_PUSH` | Whether to skip pushing artifacts to the cache | `true` | `false` |
|
| `CACHIX_SKIP_PUSH` | Whether to skip pushing artifacts to the cache | `true` | `false` |
|
||||||
|
|
||||||
|
|||||||
13
.github/workflows/publish-docker.yml
vendored
13
.github/workflows/publish-docker.yml
vendored
@@ -12,6 +12,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
CACHIX_NAME: devenv
|
CACHIX_NAME: devenv
|
||||||
|
CACHIX_SKIP_PUSH: true
|
||||||
DOCKER_REGISTRY: labs.phundrak.com # Override in repository settings if needed
|
DOCKER_REGISTRY: labs.phundrak.com # Override in repository settings if needed
|
||||||
IMAGE_NAME: phundrak/phundrak-dot-com-backend
|
IMAGE_NAME: phundrak/phundrak-dot-com-backend
|
||||||
|
|
||||||
@@ -37,17 +38,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: '${{ env.CACHIX_NAME }}'
|
name: '${{ env.CACHIX_NAME }}'
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||||
skipPush: ${{ github.event_name == 'pull_request' }}
|
skipPush: ${{ env.CACHIX_SKIP_PUSH }}
|
||||||
|
|
||||||
- name: Coverage
|
|
||||||
run: |
|
|
||||||
nix develop --no-pure-eval --command just coverage
|
|
||||||
|
|
||||||
- name: Sonar analysis
|
|
||||||
uses: SonarSource/sonarqube-scan-action@v6
|
|
||||||
env:
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
|
||||||
|
|
||||||
- name: Build Docker image with Nix
|
- name: Build Docker image with Nix
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
40
Cargo.lock
generated
40
Cargo.lock
generated
@@ -134,26 +134,6 @@ dependencies = [
|
|||||||
"fs_extra",
|
"fs_extra",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bakit"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"config",
|
|
||||||
"dotenvy",
|
|
||||||
"governor",
|
|
||||||
"lettre",
|
|
||||||
"poem",
|
|
||||||
"poem-openapi",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
"validator",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.7"
|
version = "0.21.7"
|
||||||
@@ -1593,6 +1573,26 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phundrak-dot-com-backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"config",
|
||||||
|
"dotenvy",
|
||||||
|
"governor",
|
||||||
|
"lettre",
|
||||||
|
"poem",
|
||||||
|
"poem-openapi",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"validator",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "0.4.30"
|
version = "0.4.30"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bakit"
|
name = "phundrak-dot-com-backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
publish = false
|
publish = false
|
||||||
@@ -11,7 +11,7 @@ path = "src/lib.rs"
|
|||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
name = "bakit"
|
name = "phundrak-dot-com-backend"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4.42", features = ["serde"] }
|
chrono = { version = "0.4.42", features = ["serde"] }
|
||||||
|
|||||||
88
README.md
88
README.md
@@ -1,30 +1,44 @@
|
|||||||
---
|
# phundrak.com Backend
|
||||||
include_toc: true
|
|
||||||
gitea: none
|
|
||||||
---
|
|
||||||
|
|
||||||
<h1 align="center">Bakit</h1>
|
<!--toc:start-->
|
||||||
<div align="center">
|
- [phundrak.com Backend](#phundrakcom-backend)
|
||||||
<strong>
|
- [Features](#features)
|
||||||
A backend for my personal website
|
- [API Endpoints](#api-endpoints)
|
||||||
</strong>
|
- [Configuration](#configuration)
|
||||||
</div>
|
- [Configuration Example](#configuration-example)
|
||||||
<br/>
|
- [Rate Limiting](#rate-limiting)
|
||||||
|
- [Development](#development)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Running the Server](#running-the-server)
|
||||||
|
- [Building](#building)
|
||||||
|
- [Testing](#testing)
|
||||||
|
- [Testing Notes](#testing-notes)
|
||||||
|
- [Code Quality](#code-quality)
|
||||||
|
- [Linting](#linting)
|
||||||
|
- [Continuous Checking with Bacon](#continuous-checking-with-bacon)
|
||||||
|
- [Code Style](#code-style)
|
||||||
|
- [Error Handling](#error-handling)
|
||||||
|
- [Logging](#logging)
|
||||||
|
- [Imports](#imports)
|
||||||
|
- [Testing Conventions](#testing-conventions)
|
||||||
|
- [Project Structure](#project-structure)
|
||||||
|
- [Architecture](#architecture)
|
||||||
|
- [Application Initialization Flow](#application-initialization-flow)
|
||||||
|
- [Email Handling](#email-handling)
|
||||||
|
- [Docker Deployment](#docker-deployment)
|
||||||
|
- [Using Pre-built Images](#using-pre-built-images)
|
||||||
|
- [Available Image Tags](#available-image-tags)
|
||||||
|
- [Building Images Locally](#building-images-locally)
|
||||||
|
- [Docker Compose Example](#docker-compose-example)
|
||||||
|
- [CI/CD Pipeline](#cicd-pipeline)
|
||||||
|
- [Automated Docker Publishing](#automated-docker-publishing)
|
||||||
|
- [Workflow Details](#workflow-details)
|
||||||
|
- [Registry Configuration](#registry-configuration)
|
||||||
|
- [Required Secrets](#required-secrets)
|
||||||
|
- [License](#license)
|
||||||
|
<!--toc:end-->
|
||||||
|
|
||||||
<div align="center">
|
The backend for [phundrak.com](https://phundrak.com), built with Rust and the [Poem](https://github.com/poem-web/poem) web framework.
|
||||||
<a href="https://sonar.phundrak.com/dashboard?id=bakit" target="_blank">
|
|
||||||
<img src="https://sonar.phundrak.com/api/project_badges/measure?project=bakit&metric=coverage&token=sqb_bda24bf36825576d6c6b76048044e103339c3c5f" alt="Sonar Coverage" />
|
|
||||||
</a>
|
|
||||||
<a href="https://sonar.phundrak.com/dashboard?id=bakit" target="_blank">
|
|
||||||
<img src="https://sonar.phundrak.com/api/project_badges/measure?project=bakit&metric=alert_status&token=sqb_bda24bf36825576d6c6b76048044e103339c3c5f" alt="Sonar Quality Gate Status" />
|
|
||||||
</a>
|
|
||||||
<a href="#license">
|
|
||||||
<img src="https://img.shields.io/badge/License-AGPL--3.0--only-blue" alt="License" />
|
|
||||||
</a>
|
|
||||||
<a href="https://www.gnu.org/software/emacs/" target="_blank">
|
|
||||||
<img src="https://img.shields.io/badge/Made%20with-GNU%2FEmacs-blueviolet.svg?logo=GNU%20Emacs&logoColor=white" alt="Made with GNU/Emacs" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -141,14 +155,14 @@ For optimized production builds:
|
|||||||
cargo build --release
|
cargo build --release
|
||||||
```
|
```
|
||||||
|
|
||||||
The compiled binary will be at `target/release/bakit`.
|
The compiled binary will be at `target/release/backend`.
|
||||||
|
|
||||||
**With Nix:**
|
**With Nix:**
|
||||||
|
|
||||||
Build the backend binary:
|
Build the backend binary:
|
||||||
```bash
|
```bash
|
||||||
nix build .#backend
|
nix build .#backend
|
||||||
# Binary available at: ./result/bin/bakit
|
# Binary available at: ./result/bin/backend
|
||||||
```
|
```
|
||||||
|
|
||||||
Build Docker images:
|
Build Docker images:
|
||||||
@@ -161,7 +175,7 @@ nix build .#backendDockerLatest
|
|||||||
|
|
||||||
# Load into Docker
|
# Load into Docker
|
||||||
docker load < result
|
docker load < result
|
||||||
# Image will be available as: localhost/phundrak/bakit:latest
|
# Image will be available as: localhost/phundrak/backend-rust:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
The Nix build ensures reproducible builds with all dependencies pinned.
|
The Nix build ensures reproducible builds with all dependencies pinned.
|
||||||
@@ -202,7 +216,6 @@ just coverage
|
|||||||
- Tests use `get_test_app()` helper for consistent test setup
|
- Tests use `get_test_app()` helper for consistent test setup
|
||||||
- Telemetry is automatically disabled during tests
|
- Telemetry is automatically disabled during tests
|
||||||
- Tests are organized in `#[cfg(test)]` modules within each file
|
- Tests are organized in `#[cfg(test)]` modules within each file
|
||||||
- Email sending is tested using lettre's `StubTransport` for mocking SMTP operations
|
|
||||||
|
|
||||||
## Code Quality
|
## Code Quality
|
||||||
|
|
||||||
@@ -281,15 +294,12 @@ backend/
|
|||||||
│ ├── startup.rs # Application builder, server setup
|
│ ├── startup.rs # Application builder, server setup
|
||||||
│ ├── settings.rs # Configuration management
|
│ ├── settings.rs # Configuration management
|
||||||
│ ├── telemetry.rs # Logging and tracing setup
|
│ ├── telemetry.rs # Logging and tracing setup
|
||||||
│ ├── errors.rs # Error type re-exports
|
|
||||||
│ ├── middleware/ # Custom middleware
|
│ ├── middleware/ # Custom middleware
|
||||||
│ │ ├── mod.rs # Middleware module
|
│ │ ├── mod.rs # Middleware module
|
||||||
│ │ └── rate_limit.rs # Rate limiting middleware
|
│ │ └── rate_limit.rs # Rate limiting middleware
|
||||||
│ └── route/ # API route handlers
|
│ └── route/ # API route handlers
|
||||||
│ ├── mod.rs # Route organization
|
│ ├── mod.rs # Route organization
|
||||||
│ ├── contact/ # Contact form module
|
│ ├── contact.rs # Contact form endpoint
|
||||||
│ │ ├── mod.rs # Contact form endpoint
|
|
||||||
│ │ └── errors.rs # Contact form error types
|
|
||||||
│ ├── health.rs # Health check endpoint
|
│ ├── health.rs # Health check endpoint
|
||||||
│ └── meta.rs # Metadata endpoint
|
│ └── meta.rs # Metadata endpoint
|
||||||
├── settings/ # Configuration files
|
├── settings/ # Configuration files
|
||||||
@@ -336,7 +346,7 @@ Docker images are automatically built and published via GitHub Actions to the co
|
|||||||
Pull and run the latest image:
|
Pull and run the latest image:
|
||||||
```bash
|
```bash
|
||||||
# Pull from Phundrak Labs (labs.phundrak.com)
|
# Pull from Phundrak Labs (labs.phundrak.com)
|
||||||
docker pull labs.phundrak.com/phundrak/bakit:latest
|
docker pull labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
|
||||||
|
|
||||||
# Run the container
|
# Run the container
|
||||||
docker run -d \
|
docker run -d \
|
||||||
@@ -349,7 +359,7 @@ docker run -d \
|
|||||||
-e APP__EMAIL__PASSWORD=your_password \
|
-e APP__EMAIL__PASSWORD=your_password \
|
||||||
-e APP__EMAIL__FROM="Contact Form <noreply@example.com>" \
|
-e APP__EMAIL__FROM="Contact Form <noreply@example.com>" \
|
||||||
-e APP__EMAIL__RECIPIENT="Admin <admin@example.com>" \
|
-e APP__EMAIL__RECIPIENT="Admin <admin@example.com>" \
|
||||||
labs.phundrak.com/phundrak/bakit:latest
|
labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Available Image Tags
|
### Available Image Tags
|
||||||
@@ -367,7 +377,7 @@ Build with Nix (recommended for reproducibility):
|
|||||||
```bash
|
```bash
|
||||||
nix build .#backendDockerLatest
|
nix build .#backendDockerLatest
|
||||||
docker load < result
|
docker load < result
|
||||||
docker run -p 3100:3100 localhost/phundrak/bakit:latest
|
docker run -p 3100:3100 localhost/phundrak/backend-rust:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Build with Docker directly:
|
Build with Docker directly:
|
||||||
@@ -383,7 +393,7 @@ version: '3.8'
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
image: labs.phundrak.com/phundrak/bakit:latest
|
image: labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
|
||||||
ports:
|
ports:
|
||||||
- "3100:3100"
|
- "3100:3100"
|
||||||
environment:
|
environment:
|
||||||
@@ -435,7 +445,7 @@ To use the published images, authenticate with the registry:
|
|||||||
echo $GITHUB_TOKEN | docker login labs.phundrak.com -u USERNAME --password-stdin
|
echo $GITHUB_TOKEN | docker login labs.phundrak.com -u USERNAME --password-stdin
|
||||||
|
|
||||||
# Pull the image
|
# Pull the image
|
||||||
docker pull labs.phundrak.com/phundrak/bakit:latest
|
docker pull labs.phundrak.com/phundrak/phundrak-dot-com-backend:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Required Secrets
|
### Required Secrets
|
||||||
@@ -449,4 +459,4 @@ See [.github/workflows/README.md](./.github/workflows/README.md) for detailed se
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
AGPL-3.0-only - See [LICENSE.md](./LICENSE.md) for full license information.
|
AGPL-3.0-only - See the root repository for full license information.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ application:
|
|||||||
protocol: http
|
protocol: http
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
base_url: http://127.0.0.1:3100
|
base_url: http://127.0.0.1:3100
|
||||||
name: "bakit-dev"
|
name: "com.phundrak.backend.dev"
|
||||||
|
|
||||||
email:
|
email:
|
||||||
host: localhost
|
host: localhost
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ debug: false
|
|||||||
frontend_url: ""
|
frontend_url: ""
|
||||||
|
|
||||||
application:
|
application:
|
||||||
name: "bakit-prod"
|
name: "com.phundrak.backend.prod"
|
||||||
protocol: https
|
protocol: https
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
base_url: ""
|
base_url: ""
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
sonar.projectKey=bakit
|
|
||||||
@@ -3,5 +3,5 @@
|
|||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
bakit::run(None).await
|
phundrak_dot_com_backend::run(None).await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_validation_errors_with_name_error() {
|
fn from_validation_errors_with_name_error() {
|
||||||
use validator::Validate;
|
use validator::{Validate, ValidationError};
|
||||||
|
|
||||||
#[derive(Validate)]
|
#[derive(Validate)]
|
||||||
struct TestStruct {
|
struct TestStruct {
|
||||||
|
|||||||
@@ -933,7 +933,7 @@ mod tests {
|
|||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
match result.unwrap_err() {
|
match result.unwrap_err() {
|
||||||
ContactError::CouldNotParseSettingsEmail(_) => (),
|
ContactError::CouldNotParseSettingsEmail(_) => (),
|
||||||
e => panic!("Expected CouldNotParseSettingsEmail, got {e:?}"),
|
e => panic!("Expected CouldNotParseSettingsEmail, got {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +964,7 @@ mod tests {
|
|||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
match result.unwrap_err() {
|
match result.unwrap_err() {
|
||||||
ContactError::CouldNotParseRequestEmailAddress(_) => (),
|
ContactError::CouldNotParseRequestEmailAddress(_) => (),
|
||||||
e => panic!("Expected CouldNotParseRequestEmailAddress, got {e:?}"),
|
e => panic!("Expected CouldNotParseRequestEmailAddress, got {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,7 +996,7 @@ mod tests {
|
|||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
match result.unwrap_err() {
|
match result.unwrap_err() {
|
||||||
ContactError::CouldNotSendEmail(_) => (),
|
ContactError::CouldNotSendEmail(_) => (),
|
||||||
e => panic!("Expected CouldNotSendEmail, got {e:?}"),
|
e => panic!("Expected CouldNotSendEmail, got {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user