Merge pull request #6 from GoncaloRodri/docs/architecture-and-dashboard-plan

Docs/architecture and dashboard plan
This commit is contained in:
Gonçalo Rodrigues 2026-06-13 15:45:32 +01:00 committed by GitHub
commit be76117ce7
8 changed files with 114 additions and 141 deletions

View File

@ -0,0 +1,14 @@
{
"permissions": {
"allow": [
"Bash(/opt/homebrew/bin/gh pr create --draft --title 'feat\\(finance\\): improved UX across dashboard, transactions, reports and categories' --body ' *)",
"Bash(/opt/homebrew/bin/gh auth *)",
"Bash(go build *)",
"Bash(go test *)",
"Bash(git add *)",
"Bash(git commit -m ' *)",
"Bash(git push *)",
"mcp__visualize__read_me"
]
}
}

20
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Test
run: go test ./...

View File

@ -4,6 +4,7 @@ SHELL := /bin/zsh
K3D_SCRIPT := infrastructure/k3d/k3d.sh
TERRAFORM := terraform
SHA := $(shell git rev-parse --short HEAD)
.PHONY: up
up: ## Create the k3d dev cluster
@ -19,13 +20,28 @@ infra: ## Deploy shared infrastructure (MongoDB, monitoring, Traefik metrics)
SERVICES := $(shell find apps -name Makefile -path "*/services/*" -exec dirname {} \;)
.PHONY: deploy-finance
deploy-finance: ## Build and deploy the finance API
$(MAKE) -C apps/finance/services/api build-deploy IMAGE_TAG=$(SHA)
.PHONY: deploy-auth-users
deploy-auth-users: ## Build and deploy the auth users service
$(MAKE) -C apps/auth/services/users build-deploy IMAGE_TAG=$(SHA)
.PHONY: deploy-auth-gateway
deploy-auth-gateway: ## Build and deploy the auth gateway service
$(MAKE) -C apps/auth/services/gateway build-deploy IMAGE_TAG=$(SHA)
.PHONY: test
test: ## Run all tests
go test ./...
.PHONY: deploy-all
deploy-all: ## Build, load, deploy, and restart every service
@for dir in $(SERVICES); do \
echo "\033[36m>>> $$dir\033[0m"; \
$(MAKE) -C "$$dir" build-deploy || true; \
$(MAKE) -C "$$dir" build-deploy IMAGE_TAG=$(SHA) || true; \
done
$(MAKE) restart-all
.PHONY: restart-all
restart-all: ## Restart all deployments (pick up new images)

View File

@ -17,7 +17,7 @@ spec:
spec:
containers:
- name: gateway
image: homelab/gateway:latest
image: homelab/auth-gateway:latest
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@ -17,7 +17,7 @@ spec:
spec:
containers:
- name: users
image: homelab/users:latest
image: homelab/auth-users:latest
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@ -17,7 +17,7 @@ spec:
spec:
containers:
- name: api
image: homelab/api:latest
image: homelab/finance-api:latest
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@ -61,3 +61,25 @@ provider "registry.terraform.io/hashicorp/random" {
"zh:c94784f005708890dc6895afd53636ec00ec1e430b15d41e5aebfb1d4b39bd04",
]
}
provider "registry.terraform.io/integrations/github" {
version = "6.12.1"
constraints = "~> 6.0"
hashes = [
"h1:hHOwf554tYL9pQS2uRPbaAGSXRbbBJ/+HtQAoT9mtuA=",
"zh:3e1a4081ecb9518fdf0074db83c16ad00dc81ffe8249a6e3cf1894e947e28df6",
"zh:4cb8224b7f530795b674ac044675f6b22a7c9154f55eb9f76c5af6c7534056a4",
"zh:560bc08637926191f6871a89e986022ca67c70afda5bebca34b5216e6fac69c9",
"zh:5a70b5d2ac650c5c9819a1875411ebda229d0fcc6c9f57f9d751852ca3cd77ac",
"zh:8668d93bd4dc2ffa2545e1473af600a925d479b16033a71a4498a16f3b683c0c",
"zh:86eacc6059fd057948e178b665ba5cce74bd5488a9e1035734e60ff5ef1b6f8f",
"zh:a329fac98881d8dfc211a9bdc0ec6f2948f0b0c2704d1b6cbe5307403c7ad1b2",
"zh:dadd44abab3c52b9d572955afaef1658790e17ea355ee22b58996d81d28e02d8",
"zh:de9f455ef342cc38fb76bce844bfcd376fb81a4b9f9bc2fae023ff99efdf1338",
"zh:f8c6d2e8351b334491790358574e0a30a7c6d7f5b80f7daf32a7c0f3e9b1ab19",
"zh:fab41971a3edee04ab6eceaeab4eeb9a2b2f38a2af3b06eda93e2117b64994be",
"zh:fb1279b566dd9c8c117b2e4e0cc8344413b8fc8f2a3e24be22a9b2610551777b",
"zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25",
"zh:fe79d2a861fb9af420fa5bd7f02c031b2a0a3edf5dbc46022c8ecc7a33cf2b6d",
]
}

View File

@ -1,7 +1,7 @@
{
"version": 4,
"terraform_version": "1.15.5",
"serial": 352,
"serial": 412,
"lineage": "28673c1d-998f-000c-38f5-de7c9e848250",
"outputs": {},
"resources": [
@ -34,8 +34,8 @@
{
"app_version": "3.2.10",
"chart": "fluent-bit",
"first_deployed": 1780862639,
"last_deployed": 1780862639,
"first_deployed": 1781347541,
"last_deployed": 1781347541,
"name": "fluent-bit",
"namespace": "monitoring",
"notes": "Get Fluent Bit build information by running these commands:\n\nexport POD_NAME=$(kubectl get pods --namespace monitoring -l \"app.kubernetes.io/name=fluent-bit,app.kubernetes.io/instance=fluent-bit\" -o jsonpath=\"{.items[0].metadata.name}\")\nkubectl --namespace monitoring port-forward $POD_NAME 2020:2020\ncurl http://127.0.0.1:2020 \n\n",
@ -119,8 +119,8 @@
{
"app_version": "2.18.0",
"chart": "jaeger",
"first_deployed": 1780862639,
"last_deployed": 1780862639,
"first_deployed": 1781347536,
"last_deployed": 1781347536,
"name": "jaeger",
"namespace": "monitoring",
"notes": "###################################################################\n### ⚠️ EXPERIMENTAL - NO STABILITY GUARANTEES ###\n### ###\n### This chart is under active development. ###\n### Breaking changes may occur in minor versions. ###\n### ###\n### See README.md for configuration details. ###\n###################################################################\n\n🚀 Congratulations on successfully installing Jaeger v2.18.0 (Chart v4.8.0)!\n\nTo access the query UI:\n http://jaeger.homelab.local\n",
@ -175,105 +175,6 @@
}
]
},
{
"mode": "managed",
"type": "helm_release",
"name": "kube_prometheus_stack",
"provider": "provider[\"registry.terraform.io/hashicorp/helm\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"atomic": true,
"chart": "kube-prometheus-stack",
"cleanup_on_fail": false,
"create_namespace": false,
"dependency_update": false,
"description": null,
"devel": null,
"disable_crd_hooks": false,
"disable_openapi_validation": false,
"disable_webhooks": false,
"force_update": false,
"id": "kps",
"keyring": null,
"lint": false,
"manifest": null,
"max_history": 0,
"metadata": [
{
"app_version": "v0.91.0",
"chart": "kube-prometheus-stack",
"first_deployed": 1780862636,
"last_deployed": 1780862636,
"name": "kps",
"namespace": "monitoring",
"notes": "kube-prometheus-stack has been installed. Check its status by running:\n kubectl --namespace monitoring get pods -l \"release=kps\"\n\nGet Grafana 'admin' user password by running:\n\n kubectl --namespace monitoring get secrets kps-grafana -o jsonpath=\"{.data.admin-password}\" | base64 -d ; echo\n\nAccess Grafana local instance:\n\n export POD_NAME=$(kubectl --namespace monitoring get pod -l \"app.kubernetes.io/name=grafana,app.kubernetes.io/instance=kps\" -oname)\n kubectl --namespace monitoring port-forward $POD_NAME 3000\n\nGet your grafana admin user password by running:\n\n kubectl get secret --namespace monitoring -l app.kubernetes.io/component=admin-secret -o jsonpath=\"{.items[0].data.admin-password}\" | base64 --decode ; echo\n\n\nVisit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create \u0026 configure Alertmanager and Prometheus instances using the Operator.\n\nkube-state-metrics is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects.\nThe exposed metrics can be found here:\nhttps://github.com/kubernetes/kube-state-metrics/blob/master/docs/README.md#exposed-metrics\n\nThe metrics are exported on the HTTP endpoint /metrics on the listening port.\nIn your case, kps-kube-state-metrics.monitoring.svc.cluster.local:8080/metrics\n\nThey are served either as plaintext or protobuf depending on the Accept header.\nThey are designed to be consumed either by Prometheus itself or by a scraper that is compatible with scraping a Prometheus client endpoint.\n\n1. Get the application URL by running these commands:\n export POD_NAME=$(kubectl get pods --namespace monitoring -l \"app.kubernetes.io/name=prometheus-node-exporter,app.kubernetes.io/instance=kps\" -o jsonpath=\"{.items[0].metadata.name}\")\n echo \"Visit http://127.0.0.1:9100 to use your application\"\n kubectl port-forward --namespace monitoring $POD_NAME 9100\n1. Get your 'admin' user password by running:\n\n kubectl get secret --namespace monitoring kps-grafana -o jsonpath=\"{.data.admin-password}\" | base64 --decode ; echo\n\n\n2. The Grafana server can be accessed via port 80 on the following DNS name from within your cluster:\n\n kps-grafana.monitoring.svc.cluster.local\n\n If you bind grafana to 80, please update values in values.yaml and reinstall:\n ```\n securityContext:\n runAsUser: 0\n runAsGroup: 0\n fsGroup: 0\n\n command:\n - \"setcap\"\n - \"'cap_net_bind_service=+ep'\"\n - \"/usr/sbin/grafana-server \u0026\u0026\"\n - \"sh\"\n - \"/run.sh\"\n ```\n Details refer to https://grafana.com/docs/installation/configuration/#http-port.\n Or grafana would always crash.\n\n From outside the cluster, the server URL(s) are:\n http://grafana.homelab.local\n\n3. Login with the password from step 1 and the username: admin\n#################################################################################\n###### WARNING: Persistence is disabled!!! You will lose your data when #####\n###### the Grafana pod is terminated. #####\n#################################################################################\n",
"revision": 1,
"values": "{\"alertmanager\":{\"enabled\":false},\"grafana\":{\"additionalDataSources\":[{\"access\":\"proxy\",\"isDefault\":false,\"name\":\"Jaeger\",\"type\":\"jaeger\",\"uid\":\"jaeger\",\"url\":\"http://jaeger.monitoring.svc:16686\"},{\"access\":\"proxy\",\"isDefault\":false,\"name\":\"Loki\",\"type\":\"loki\",\"uid\":\"loki\",\"url\":\"http://loki-gateway.monitoring.svc\"}],\"adminPassword\":\"jXWfhChbpD6QEDK2wLXbLHy7\",\"ingress\":{\"annotations\":{\"traefik.ingress.kubernetes.io/router.middlewares\":\"auth-forward-auth@kubernetescrd\"},\"enabled\":true,\"hosts\":[\"grafana.homelab.local\"],\"ingressClassName\":\"traefik\"}},\"kube-state-metrics\":{\"resources\":{\"requests\":{\"cpu\":\"50m\",\"memory\":\"128Mi\"}}},\"node-exporter\":{\"resources\":{\"requests\":{\"cpu\":\"25m\",\"memory\":\"64Mi\"}}},\"prometheus\":{\"prometheusSpec\":{\"resources\":{\"limits\":{\"cpu\":\"1\",\"memory\":\"1Gi\"},\"requests\":{\"cpu\":\"200m\",\"memory\":\"512Mi\"}}}}}",
"version": "86.0.2"
}
],
"name": "kps",
"namespace": "monitoring",
"pass_credentials": false,
"postrender": [],
"recreate_pods": false,
"render_subchart_notes": true,
"replace": false,
"repository": "https://prometheus-community.github.io/helm-charts",
"repository_ca_file": null,
"repository_cert_file": null,
"repository_key_file": null,
"repository_password": null,
"repository_username": null,
"reset_values": false,
"reuse_values": false,
"set": [],
"set_list": [],
"set_sensitive": [],
"skip_crds": false,
"status": "deployed",
"timeout": 300,
"upgrade_install": null,
"values": [
"\"alertmanager\":\n \"enabled\": false\n\"grafana\":\n \"additionalDataSources\":\n - \"access\": \"proxy\"\n \"isDefault\": false\n \"name\": \"Jaeger\"\n \"type\": \"jaeger\"\n \"uid\": \"jaeger\"\n \"url\": \"http://jaeger.monitoring.svc:16686\"\n - \"access\": \"proxy\"\n \"isDefault\": false\n \"name\": \"Loki\"\n \"type\": \"loki\"\n \"uid\": \"loki\"\n \"url\": \"http://loki-gateway.monitoring.svc\"\n \"adminPassword\": \"jXWfhChbpD6QEDK2wLXbLHy7\"\n \"ingress\":\n \"annotations\":\n \"traefik.ingress.kubernetes.io/router.middlewares\": \"auth-forward-auth@kubernetescrd\"\n \"enabled\": true\n \"hosts\":\n - \"grafana.homelab.local\"\n \"ingressClassName\": \"traefik\"\n\"kube-state-metrics\":\n \"resources\":\n \"requests\":\n \"cpu\": \"50m\"\n \"memory\": \"128Mi\"\n\"node-exporter\":\n \"resources\":\n \"requests\":\n \"cpu\": \"25m\"\n \"memory\": \"64Mi\"\n\"prometheus\":\n \"prometheusSpec\":\n \"resources\":\n \"limits\":\n \"cpu\": \"1\"\n \"memory\": \"1Gi\"\n \"requests\":\n \"cpu\": \"200m\"\n \"memory\": \"512Mi\"\n"
],
"verify": false,
"version": "86.0.2",
"wait": true,
"wait_for_jobs": false
},
"sensitive_attributes": [
[
{
"type": "get_attr",
"value": "repository_password"
}
],
[
{
"type": "get_attr",
"value": "values"
},
{
"type": "index",
"value": {
"value": 0,
"type": "number"
}
}
]
],
"identity_schema_version": 0,
"private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==",
"dependencies": [
"kubernetes_namespace.domains",
"random_password.grafana"
]
}
]
},
{
"mode": "managed",
"type": "helm_release",
@ -303,8 +204,8 @@
{
"app_version": "3.4.2",
"chart": "loki",
"first_deployed": 1780862638,
"last_deployed": 1780862638,
"first_deployed": 1781347540,
"last_deployed": 1781347540,
"name": "loki",
"namespace": "monitoring",
"notes": "***********************************************************************\n Welcome to Grafana Loki\n Chart version: 6.28.0\n Chart Name: loki\n Loki version: 3.4.2\n***********************************************************************\n\n** Please be patient while the chart is being deployed **\n\nTip:\n\n Watch the deployment status using the command: kubectl get pods -w --namespace monitoring\n\nIf pods are taking too long to schedule make sure pod affinity can be fulfilled in the current cluster.\n\n***********************************************************************\nInstalled components:\n***********************************************************************\n* loki\n\nLoki has been deployed as a single binary.\nThis means a single pod is handling reads and writes. You can scale that pod vertically by adding more CPU and memory resources.\n\n\n***********************************************************************\nSending logs to Loki\n***********************************************************************\n\nLoki has been configured with a gateway (nginx) to support reads and writes from a single component.\n\nYou can send logs from inside the cluster using the cluster DNS:\n\nhttp://loki-gateway.monitoring.svc.cluster.local/loki/api/v1/push\n\nYou can test to send data from outside the cluster by port-forwarding the gateway to your local machine:\n\n kubectl port-forward --namespace monitoring svc/loki-gateway 3100:80 \u0026\n\nAnd then using http://127.0.0.1:3100/loki/api/v1/push URL as shown below:\n\n```\ncurl -H \"Content-Type: application/json\" -XPOST -s \"http://127.0.0.1:3100/loki/api/v1/push\" \\\n--data-raw \"{\\\"streams\\\": [{\\\"stream\\\": {\\\"job\\\": \\\"test\\\"}, \\\"values\\\": [[\\\"$(date +%s)000000000\\\", \\\"fizzbuzz\\\"]]}]}\"\n```\n\nThen verify that Loki did receive the data using the following command:\n\n```\ncurl \"http://127.0.0.1:3100/loki/api/v1/query_range\" --data-urlencode 'query={job=\"test\"}' | jq .data.result\n```\n\n***********************************************************************\nConnecting Grafana to Loki\n***********************************************************************\n\nIf Grafana operates within the cluster, you'll set up a new Loki datasource by utilizing the following URL:\n\nhttp://loki-gateway.monitoring.svc.cluster.local/\n",
@ -377,8 +278,8 @@
"generation": 0,
"labels": null,
"name": "auth",
"resource_version": "563",
"uid": "955b1b5e-870d-4e10-ba2a-df9fd3837886"
"resource_version": "560",
"uid": "a6f4f18e-ebfa-445d-9021-01e7e3443df5"
}
],
"timeouts": null,
@ -400,8 +301,8 @@
"generation": 0,
"labels": null,
"name": "finance",
"resource_version": "560",
"uid": "c5e86a50-58dd-4449-8009-021fc4db6c47"
"resource_version": "558",
"uid": "bb8df1ed-024b-407c-8ded-65ba7d5983af"
}
],
"timeouts": null,
@ -423,8 +324,8 @@
"generation": 0,
"labels": null,
"name": "home",
"resource_version": "562",
"uid": "832f867c-1c87-4916-bb2a-6a553ff9fe97"
"resource_version": "561",
"uid": "b79f5a4a-345e-4fa7-9ab2-d4b71a6ac4d7"
}
],
"timeouts": null,
@ -446,8 +347,8 @@
"generation": 0,
"labels": null,
"name": "infrastructure",
"resource_version": "561",
"uid": "946fad48-8db3-4c65-901f-a41647aff588"
"resource_version": "563",
"uid": "9d9e5d6e-47fc-4833-b63e-8cc0d4fdce03"
}
],
"timeouts": null,
@ -470,7 +371,7 @@
"labels": null,
"name": "monitoring",
"resource_version": "559",
"uid": "890e74f8-5aab-4ab1-b29f-aeca95468824"
"uid": "bf35e1ff-1a6b-46f9-ae6c-3a67ac42a82e"
}
],
"timeouts": null,
@ -492,8 +393,8 @@
"generation": 0,
"labels": null,
"name": "test",
"resource_version": "564",
"uid": "cea8776d-af80-4031-9f2a-8db84300bbfc"
"resource_version": "557",
"uid": "d60671b5-4764-4bbb-acd0-bb02c246dcbc"
}
],
"timeouts": null,
@ -530,8 +431,8 @@
"labels": null,
"name": "mongodb",
"namespace": "infrastructure",
"resource_version": "571",
"uid": "b060268d-ca4e-435d-860e-40a3d88c7593"
"resource_version": "580",
"uid": "57167d70-7714-4c9e-ba80-333c83e483a9"
}
],
"timeouts": null,
@ -612,8 +513,8 @@
"labels": null,
"name": "mongodb-shared-config",
"namespace": "auth",
"resource_version": "576",
"uid": "d15b185d-4df9-459b-a404-e213f362284b"
"resource_version": "586",
"uid": "77fdd3c5-50ed-41f4-916c-3625cbbe244c"
}
],
"timeouts": null,
@ -673,8 +574,8 @@
"labels": null,
"name": "mongodb-shared-config",
"namespace": "finance",
"resource_version": "574",
"uid": "8b9cefc6-147f-4beb-99c5-7fd1845a26bb"
"resource_version": "587",
"uid": "def8ec73-bb14-475b-b26e-e3ae7146fe0a"
}
],
"timeouts": null,
@ -734,8 +635,8 @@
"labels": null,
"name": "mongodb-shared-config",
"namespace": "home",
"resource_version": "577",
"uid": "83e46b25-edec-42e9-9e03-fb394779d6d5"
"resource_version": "578",
"uid": "f8fb372f-98e4-4a59-9e40-ae4dd8424bc0"
}
],
"timeouts": null,
@ -795,8 +696,8 @@
"labels": null,
"name": "mongodb-shared-config",
"namespace": "infrastructure",
"resource_version": "589",
"uid": "470fd582-2e00-4c00-98b9-e42b67a2d455"
"resource_version": "577",
"uid": "f7604981-db0a-4ef0-b8ff-c633cd107b7a"
}
],
"timeouts": null,
@ -856,8 +757,8 @@
"labels": null,
"name": "mongodb-shared-config",
"namespace": "monitoring",
"resource_version": "588",
"uid": "1f20a3be-a400-47e9-8526-6c3825189302"
"resource_version": "576",
"uid": "72b10323-8251-4188-b980-456c4066abe8"
}
],
"timeouts": null,
@ -918,7 +819,7 @@
"name": "mongodb-shared-config",
"namespace": "test",
"resource_version": "575",
"uid": "df1de823-571b-46d3-b85b-5082b03b8bed"
"uid": "fc743768-ceee-4e2b-afb9-9edb671668a8"
}
],
"timeouts": null,
@ -979,16 +880,16 @@
"labels": null,
"name": "mongodb",
"namespace": "infrastructure",
"resource_version": "578",
"uid": "435bfa82-026a-4ad3-92af-5913673d9819"
"resource_version": "582",
"uid": "f555214a-ead6-4e93-9d9a-a2b522d71e24"
}
],
"spec": [
{
"allocate_load_balancer_node_ports": true,
"cluster_ip": "10.43.49.246",
"cluster_ip": "10.43.171.195",
"cluster_ips": [
"10.43.49.246"
"10.43.171.195"
],
"external_ips": null,
"external_name": "",
@ -1060,8 +961,8 @@
"labels": null,
"name": "mongodb",
"namespace": "infrastructure",
"resource_version": "590",
"uid": "ea21f54f-e972-4fdf-97f2-a8c538e3868f"
"resource_version": "588",
"uid": "7e5f61fe-b6a1-457e-8db3-cbb13c0f671a"
}
],
"spec": [