chore: update compose.prod.yml (worker+nats external), CI builds frontend, deprecate thoughts-backend
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Has been cancelled
test / unit (pull_request) Has been cancelled
test / integration (pull_request) Has been cancelled
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Has been cancelled
test / unit (pull_request) Has been cancelled
test / integration (pull_request) Has been cancelled
This commit is contained in:
@@ -7,10 +7,11 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: git.gabrielkaszewski.dev
|
REGISTRY: git.gabrielkaszewski.dev
|
||||||
IMAGE: git.gabrielkaszewski.dev/gkaszewski/thoughts
|
BACKEND_IMAGE: git.gabrielkaszewski.dev/gkaszewski/thoughts
|
||||||
|
FRONTEND_IMAGE: git.gabrielkaszewski.dev/gkaszewski/thoughts-frontend
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-backend:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -26,25 +27,61 @@ jobs:
|
|||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ${{ env.IMAGE }}
|
images: ${{ env.BACKEND_IMAGE }}
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push backend
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache
|
cache-from: type=registry,ref=${{ env.BACKEND_IMAGE }}:buildcache
|
||||||
cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max
|
cache-to: type=registry,ref=${{ env.BACKEND_IMAGE }}:buildcache,mode=max
|
||||||
|
|
||||||
|
build-frontend:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Log in to registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ secrets.REGISTRY_USER }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Docker metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ${{ env.FRONTEND_IMAGE }}
|
||||||
|
tags: |
|
||||||
|
type=ref,event=branch
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
|
- name: Build and push frontend
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: ./thoughts-frontend
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }}
|
||||||
|
NEXT_PUBLIC_SERVER_SIDE_API_URL=${{ secrets.NEXT_PUBLIC_SERVER_SIDE_API_URL }}
|
||||||
|
cache-from: type=registry,ref=${{ env.FRONTEND_IMAGE }}:buildcache
|
||||||
|
cache-to: type=registry,ref=${{ env.FRONTEND_IMAGE }}:buildcache,mode=max
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
needs: build-and-push
|
needs: [build-backend, build-frontend]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
steps:
|
steps:
|
||||||
@@ -55,5 +92,6 @@ jobs:
|
|||||||
username: ${{ secrets.DEPLOY_USER }}
|
username: ${{ secrets.DEPLOY_USER }}
|
||||||
key: ${{ secrets.DEPLOY_KEY }}
|
key: ${{ secrets.DEPLOY_KEY }}
|
||||||
script: |
|
script: |
|
||||||
docker pull ${{ env.IMAGE }}:latest
|
docker pull ${{ env.BACKEND_IMAGE }}:latest
|
||||||
|
docker pull ${{ env.FRONTEND_IMAGE }}:latest
|
||||||
docker compose -f /opt/thoughts/docker-compose.yml up -d
|
docker compose -f /opt/thoughts/docker-compose.yml up -d
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
container_name: thoughts-db
|
container_name: thoughts-db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
@@ -17,19 +17,21 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
|
|
||||||
backend:
|
api:
|
||||||
container_name: thoughts-backend
|
container_name: thoughts-api
|
||||||
image: thoughts-backend:latest
|
image: registry.gabrielkaszewski.dev/thoughts:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- RUST_LOG=info
|
RUST_LOG: info
|
||||||
- RUST_BACKTRACE=1
|
RUST_ENV: production
|
||||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database/${POSTGRES_DB}
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database/${POSTGRES_DB}
|
||||||
- HOST=0.0.0.0
|
HOST: 0.0.0.0
|
||||||
- PORT=8000
|
PORT: 8000
|
||||||
- PREFORK=1
|
JWT_SECRET: ${JWT_SECRET}
|
||||||
- AUTH_SECRET=${AUTH_SECRET}
|
BASE_URL: ${BASE_URL}
|
||||||
- BASE_URL=https://thoughts.gabrielkaszewski.dev
|
NATS_URL: ${NATS_URL}
|
||||||
|
CORS_ORIGINS: ${CORS_ORIGINS:-*}
|
||||||
|
ALLOW_REGISTRATION: ${ALLOW_REGISTRATION:-false}
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -40,22 +42,41 @@ services:
|
|||||||
retries: 5
|
retries: 5
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
|
- nats
|
||||||
|
|
||||||
|
worker:
|
||||||
|
container_name: thoughts-worker
|
||||||
|
image: registry.gabrielkaszewski.dev/thoughts:latest
|
||||||
|
entrypoint: ["./thoughts-worker"]
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
RUST_LOG: info
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database/${POSTGRES_DB}
|
||||||
|
BASE_URL: ${BASE_URL}
|
||||||
|
NATS_URL: ${NATS_URL}
|
||||||
|
depends_on:
|
||||||
|
database:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- nats
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
container_name: thoughts-frontend
|
container_name: thoughts-frontend
|
||||||
image: thoughts-frontend:latest
|
image: registry.gabrielkaszewski.dev/thoughts-frontend:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
NEXT_PUBLIC_SERVER_SIDE_API_URL: http://api:8000
|
||||||
|
PORT: 3000
|
||||||
|
HOSTNAME: 0.0.0.0
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
api:
|
||||||
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
environment:
|
|
||||||
- NEXT_PUBLIC_SERVER_SIDE_API_URL=http://proxy/api
|
|
||||||
- PORT=3000
|
|
||||||
- HOSTNAME=0.0.0.0
|
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
|
|
||||||
@@ -66,7 +87,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
frontend:
|
frontend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
backend:
|
api:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
@@ -83,7 +104,13 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
driver: local
|
driver: local
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
# Shared NATS network — must already exist on the host (external: true).
|
||||||
|
# Set NATS_NETWORK env var to match your shared network name (default: nats).
|
||||||
|
nats:
|
||||||
|
name: ${NATS_NETWORK:-nats}
|
||||||
|
external: true
|
||||||
traefik:
|
traefik:
|
||||||
name: traefik
|
name: traefik
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -1,129 +1,17 @@
|
|||||||
# clean-axum
|
# ⚠️ DEPRECATED — thoughts-backend (v1)
|
||||||
|
|
||||||
Axum scaffold with clean architecture.
|
> **This directory is the original v1 implementation and is no longer maintained.**
|
||||||
|
> It will be removed in a future release.
|
||||||
|
|
||||||
You probably don't need [Rust on Rails](https://github.com/loco-rs/loco).
|
## Use v2 instead
|
||||||
|
|
||||||
Refer to [this post](https://kigawas.me/posts/rustacean-clean-architecture-approach/) for rationale and background.
|
The active codebase lives at the **repository root** (`/crates/`). It is a complete rewrite with:
|
||||||
|
|
||||||
## Features
|
- Hexagonal (Ports & Adapters) architecture
|
||||||
|
- Full ActivityPub federation
|
||||||
|
- Remote actor discovery and profile browsing
|
||||||
|
- NATS JetStream event bus
|
||||||
|
- Clean REST API with content negotiation
|
||||||
|
- Next.js frontend (`/thoughts-frontend/`)
|
||||||
|
|
||||||
- [Axum](https://github.com/tokio-rs/axum) framework
|
Do not build, run, or modify anything in this directory.
|
||||||
- [SeaORM](https://github.com/SeaQL/sea-orm) domain models
|
|
||||||
- Completely separated API routers and DB-related logic (named "persistence" layer)
|
|
||||||
- Completely separated input parameters, queries and output schemas
|
|
||||||
- OpenAPI documentation ([Swagger UI](https://clean-axum.shuttleapp.rs/docs) and [Scalar](https://clean-axum.shuttleapp.rs/scalar)) powered by [Utoipa](https://github.com/juhaku/utoipa)
|
|
||||||
- Error handling with [Anyhow](https://github.com/dtolnay/anyhow)
|
|
||||||
- Custom parameter validation with [validator](https://github.com/Keats/validator)
|
|
||||||
- Optional [Shuttle](https://www.shuttle.rs/) runtime
|
|
||||||
- Optional [prefork](https://docs.rs/prefork/latest/prefork/) workers for maximizing performance on Linux
|
|
||||||
|
|
||||||
## Module hierarchy
|
|
||||||
|
|
||||||
### API logic
|
|
||||||
|
|
||||||
- `api::routers`: Axum endpoints
|
|
||||||
- `api::error`: Models and traits for error handling
|
|
||||||
- `api::extractor` Custom Axum extractors
|
|
||||||
- `api::extractor::json`: `Json` for bodies and responses
|
|
||||||
- `api::extractor::valid`: `Valid` for JSON body validation
|
|
||||||
- `api::validation`: JSON validation model based on `validator`
|
|
||||||
- `api::models`: Non domain model API models
|
|
||||||
- `api::models::response`: JSON error response
|
|
||||||
|
|
||||||
### OpenAPI documentation
|
|
||||||
|
|
||||||
- `doc`: Utoipa doc declaration
|
|
||||||
|
|
||||||
### API-agonistic application logic
|
|
||||||
|
|
||||||
Main concept: Web framework is replaceable.
|
|
||||||
|
|
||||||
All modules here should not include any specific API web framework logic.
|
|
||||||
|
|
||||||
- `app::persistence`: DB manipulation (CRUD) functions
|
|
||||||
- `app::config`: DB or API server configuration
|
|
||||||
- `app::state`: APP state, e.g. DB connection
|
|
||||||
- `app::error`: APP errors used by `api::error`. e.g. "User not found"
|
|
||||||
|
|
||||||
### DB/API-agnostic domain models
|
|
||||||
|
|
||||||
Main concept: Database (Sqlite/MySQL/PostgreSQL) is replaceable.
|
|
||||||
|
|
||||||
Except `models::domains` and `migration`, all modules are ORM library agnostic.
|
|
||||||
|
|
||||||
- `models::domains`: SeaORM domain models
|
|
||||||
- `models::params`: Serde input parameters for creating/updating domain models in DB
|
|
||||||
- `models::schemas`: Serde output schemas for combining different domain models
|
|
||||||
- `models::queries`: Serde queries for filtering domain models
|
|
||||||
- `migration`: SeaORM migration files
|
|
||||||
|
|
||||||
### Unit and integration tests
|
|
||||||
|
|
||||||
- `tests::api`: API integration tests. Hierarchy is the same as `api::routers`
|
|
||||||
- `tests::app::persistence`: DB/ORM-related unit tests. Hierarchy is the same as `app::persistence`
|
|
||||||
|
|
||||||
### Others
|
|
||||||
|
|
||||||
- `utils`: Utility functions
|
|
||||||
- `main`: Tokio and Shuttle conditional entry point
|
|
||||||
|
|
||||||
## Run
|
|
||||||
|
|
||||||
### Start server
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
# touch dev.db
|
|
||||||
# cargo install sea-orm-cli
|
|
||||||
# sea-orm-cli migrate up
|
|
||||||
cargo run
|
|
||||||
|
|
||||||
# or for production
|
|
||||||
cargo run --release
|
|
||||||
```
|
|
||||||
|
|
||||||
### Call API
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"username":"aaa"}'
|
|
||||||
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d '{"username":"abc"}'
|
|
||||||
curl http://localhost:3000/users\?username\=a
|
|
||||||
```
|
|
||||||
|
|
||||||
### OpenAPI doc (Swagger UI/Scalar)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
open http://localhost:3000/docs
|
|
||||||
open http://localhost:3000/scalar
|
|
||||||
```
|
|
||||||
|
|
||||||
## Start Shuttle local server
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# cargo install cargo-shuttle
|
|
||||||
cargo shuttle run
|
|
||||||
```
|
|
||||||
|
|
||||||
Make sure docker engine is running, otherwise:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install colima docker
|
|
||||||
colima start
|
|
||||||
sudo ln -sf $HOME/.colima/default/docker.sock /var/run/docker.sock
|
|
||||||
```
|
|
||||||
|
|
||||||
## Shuttle deployment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo shuttle login
|
|
||||||
cargo shuttle deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
## Benchmark
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# edit .env to use Postgres
|
|
||||||
cargo run --release
|
|
||||||
wrk --latency -t20 -c50 -d10s http://localhost:3000/users\?username\=
|
|
||||||
```
|
|
||||||
|
|||||||
Reference in New Issue
Block a user