Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a33dc019a | |||
| 62654978af | |||
| 7da084c174 | |||
| 27f4cfe21e | |||
| 903fbcd143 | |||
| c5e1b7f687 | |||
| 9b33876c11 | |||
| 2d5572725d | |||
| da1f90449e | |||
| 2192c3f4c5 | |||
| 492859f17f |
@@ -1,13 +1,19 @@
|
|||||||
name: Build and Push Docker Images Staging
|
name: Build and Push Docker Images
|
||||||
|
|
||||||
|
# Branch-driven deploys — no yaml edits to switch environment:
|
||||||
|
# merge into `staging` -> tag :staging (staging Watchtower deploys)
|
||||||
|
# merge into `production` -> tag :production (production Watchtower deploys)
|
||||||
|
# `main` is the day-to-day work branch and deploys nothing.
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
- staging
|
||||||
- production
|
- production
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GIT_HOST: git.easysoft.ro
|
GIT_HOST: git.easysoft.ro
|
||||||
REGISTRY_HOST: registry.easysoft.ro
|
REGISTRY_HOST: registry.easysoft.ro
|
||||||
|
DOCKER_BUILDKIT: "1"
|
||||||
API_IMAGE: apps/myai-api
|
API_IMAGE: apps/myai-api
|
||||||
CV_MATCHER_API_IMAGE: apps/myai-cv-matcher-api
|
CV_MATCHER_API_IMAGE: apps/myai-cv-matcher-api
|
||||||
RAG_API_IMAGE: apps/myai-rag-api
|
RAG_API_IMAGE: apps/myai-rag-api
|
||||||
@@ -16,18 +22,19 @@ env:
|
|||||||
CV_CLEANUP_JOB_IMAGE: apps/myai-cv-cleanup-job
|
CV_CLEANUP_JOB_IMAGE: apps/myai-cv-cleanup-job
|
||||||
CV_SEARCH_JOB_IMAGE: apps/myai-cv-search-job
|
CV_SEARCH_JOB_IMAGE: apps/myai-cv-search-job
|
||||||
PAGE_FETCHER_API_IMAGE: apps/myai-page-fetcher-api
|
PAGE_FETCHER_API_IMAGE: apps/myai-page-fetcher-api
|
||||||
IMAGE_TAG: production
|
IMAGE_TAG: ${{ github.ref_name }} # branch name == image tag (staging | production)
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: host
|
runs-on: host
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout the pushed commit
|
||||||
env:
|
env:
|
||||||
TOKEN: ${{ secrets.REPO_TOKEN }}
|
TOKEN: ${{ secrets.REPO_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
git clone "http://gelu:${TOKEN}@${GIT_HOST}:3000/${GITHUB_REPOSITORY}.git" .
|
git clone "http://gelu:${TOKEN}@${GIT_HOST}:3000/${GITHUB_REPOSITORY}.git" .
|
||||||
|
git checkout "${{ github.sha }}"
|
||||||
|
|
||||||
- name: Login to registry
|
- name: Login to registry
|
||||||
run: |
|
run: |
|
||||||
@@ -97,4 +104,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Push Page Fetcher API image
|
- name: Push Page Fetcher API image
|
||||||
run: |
|
run: |
|
||||||
docker push "${REGISTRY_HOST}/${PAGE_FETCHER_API_IMAGE}:${IMAGE_TAG}"
|
docker push "${REGISTRY_HOST}/${PAGE_FETCHER_API_IMAGE}:${IMAGE_TAG}"
|
||||||
|
|
||||||
|
- name: Reclaim disk space (keep recent build cache)
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker image prune -f # dangling only (keep base images)
|
||||||
|
|||||||
@@ -376,3 +376,6 @@ files/
|
|||||||
|
|
||||||
/docker-compose/.env.production
|
/docker-compose/.env.production
|
||||||
/docker-compose/.env.staging
|
/docker-compose/.env.staging
|
||||||
|
|
||||||
|
# local infra access notes (secrets) — never commit
|
||||||
|
ACCESS.md
|
||||||
|
|||||||
@@ -34,11 +34,15 @@ This applies to both the staging and production repos as appropriate.
|
|||||||
- .NET 10, ASP.NET Core, Worker Service
|
- .NET 10, ASP.NET Core, Worker Service
|
||||||
- Entity Framework Core + SQL Server (multi-schema)
|
- Entity Framework Core + SQL Server (multi-schema)
|
||||||
- Refit for typed HTTP clients between services
|
- Refit for typed HTTP clients between services
|
||||||
- Serilog (JSON structured logging, Console + File + Email sinks)
|
- Serilog — Compact JSON logs to stdout (+ optional email sink); see Observability
|
||||||
- MailKit for SMTP (used exclusively in `email-api`)
|
- MailKit for SMTP (used exclusively in `email-api`)
|
||||||
- Docker Compose for local and production deployment
|
- Docker Compose for local and production deployment
|
||||||
- Watchtower for automatic container updates in production
|
- Watchtower for automatic container updates in production
|
||||||
|
|
||||||
|
## Observability (central stack on monitoring host 10.0.0.156)
|
||||||
|
- **Logs**: every service uses `ConfigureJsonSerilog(ServiceName, appVersion)` (startup-helpers) → Serilog **Compact JSON** to stdout, enriched `Application`/`Environment`/`AppVersion`. The host's Grafana **Alloy** agent ships stdout → **Loki**; view/query in Grafana. No file sink; optional email sink only if `SerilogEmail:*` is configured.
|
||||||
|
- **No app metrics/traces** — these are simple/minimal services, so (unlike easyDent) they don't expose Prometheus metrics or OTLP traces. Container/host metrics still come from the host's cAdvisor/node_exporter.
|
||||||
|
|
||||||
## Project taxonomy
|
## Project taxonomy
|
||||||
|
|
||||||
| Category | Naming | Contains | EF dependency |
|
| Category | Naming | Contains | EF dependency |
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
|
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||||
<PackageVersion Include="Serilog.Enrichers.Environment" Version="3.0.1" />
|
<PackageVersion Include="Serilog.Enrichers.Environment" Version="3.0.1" />
|
||||||
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
|
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||||
|
<PackageVersion Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||||
<PackageVersion Include="Serilog.Sinks.Email" Version="4.2.1" />
|
<PackageVersion Include="Serilog.Sinks.Email" Version="4.2.1" />
|
||||||
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
|
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<!-- Swagger -->
|
<!-- Swagger -->
|
||||||
|
|||||||
@@ -39,11 +39,10 @@ public static class StartupExtensions
|
|||||||
.ReadFrom.Configuration(context.Configuration)
|
.ReadFrom.Configuration(context.Configuration)
|
||||||
.ReadFrom.Services(services)
|
.ReadFrom.Services(services)
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.Enrich.WithMachineName()
|
.Enrich.WithProperty("Application", serviceName)
|
||||||
.Enrich.WithEnvironmentName()
|
.Enrich.WithProperty("Environment", context.HostingEnvironment.EnvironmentName)
|
||||||
.Enrich.WithProperty("Service", serviceName)
|
|
||||||
.Enrich.WithProperty("AppVersion", appVersion)
|
.Enrich.WithProperty("AppVersion", appVersion)
|
||||||
.WriteTo.Console(new Serilog.Formatting.Json.JsonFormatter());
|
.WriteTo.Console(new Serilog.Formatting.Compact.CompactJsonFormatter());
|
||||||
|
|
||||||
AddEmailSinkIfConfigured(configuration, context.Configuration, serviceName);
|
AddEmailSinkIfConfigured(configuration, context.Configuration, serviceName);
|
||||||
});
|
});
|
||||||
@@ -57,11 +56,10 @@ public static class StartupExtensions
|
|||||||
.ReadFrom.Configuration(builder.Configuration)
|
.ReadFrom.Configuration(builder.Configuration)
|
||||||
.ReadFrom.Services(services)
|
.ReadFrom.Services(services)
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.Enrich.WithMachineName()
|
.Enrich.WithProperty("Application", serviceName)
|
||||||
.Enrich.WithEnvironmentName()
|
.Enrich.WithProperty("Environment", builder.Environment.EnvironmentName)
|
||||||
.Enrich.WithProperty("Service", serviceName)
|
|
||||||
.Enrich.WithProperty("AppVersion", appVersion)
|
.Enrich.WithProperty("AppVersion", appVersion)
|
||||||
.WriteTo.Console(new Serilog.Formatting.Json.JsonFormatter());
|
.WriteTo.Console(new Serilog.Formatting.Compact.CompactJsonFormatter());
|
||||||
|
|
||||||
AddEmailSinkIfConfigured(configuration, builder.Configuration, serviceName);
|
AddEmailSinkIfConfigured(configuration, builder.Configuration, serviceName);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<PackageReference Include="DotNetEnv" />
|
<PackageReference Include="DotNetEnv" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" />
|
<PackageReference Include="Serilog.AspNetCore" />
|
||||||
<PackageReference Include="Serilog.Enrichers.Environment" />
|
<PackageReference Include="Serilog.Enrichers.Environment" />
|
||||||
|
<PackageReference Include="Serilog.Formatting.Compact" />
|
||||||
<PackageReference Include="Serilog.Sinks.Email" />
|
<PackageReference Include="Serilog.Sinks.Email" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" />
|
<PackageReference Include="Serilog.Sinks.File" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
# Introduction
|
# myAi
|
||||||
TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
|
|
||||||
|
|
||||||
# Getting Started
|
The **myai.ro** platform — a set of .NET microservices (CV matching, RAG, email, CV search, page
|
||||||
TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
|
fetching, …) behind a web frontend + API. Part of the easySoft platform.
|
||||||
1. Installation process
|
|
||||||
2. Software dependencies
|
|
||||||
3. Latest releases
|
|
||||||
4. API references
|
|
||||||
|
|
||||||
# Build and Test
|
## Layout
|
||||||
TODO: Describe and show how to build your code and run the tests.
|
Multiple services (`*-api`, `*-job`) + `web`, sharing a common bootstrap in
|
||||||
|
`startup-helpers/` (Serilog, Swagger, `.env`/Key Vault loading, middleware). See **CLAUDE.md**
|
||||||
|
for the full service map, dependency chain, and conventions.
|
||||||
|
|
||||||
# Contribute
|
## Run locally
|
||||||
TODO: Explain how other users and developers can contribute to make your code better.
|
```bash
|
||||||
|
docker compose up --build # or run individual services with: dotnet run --project <svc>
|
||||||
|
```
|
||||||
|
|
||||||
If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files:
|
## Deploy
|
||||||
- [ASP.NET Core](https://github.com/aspnet/Home)
|
CI builds `registry.easysoft.ro/apps/myai-*:{staging,production}`; Watchtower rolls them out to
|
||||||
- [Visual Studio Code](https://github.com/Microsoft/vscode)
|
the **staging (`10.0.0.183`)** + **production (`10.0.0.248`)** Portainer stacks. Edge Caddy serves
|
||||||
- [Chakra Core](https://github.com/Microsoft/ChakraCore)
|
**myai.ro** (prod) / **myai.easysoft.ro** (staging).
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
Every service: `ConfigureJsonSerilog(name, version)` → Serilog **Compact JSON** to stdout → Grafana
|
||||||
|
**Alloy** → **Loki**. No app metrics/traces (simple services).
|
||||||
|
|
||||||
|
---
|
||||||
|
See **CLAUDE.md** for the detailed solution guide and **ACCESS.md** (local, gitignored) for
|
||||||
|
infrastructure access.
|
||||||
|
|||||||
Reference in New Issue
Block a user