7.6 KiB
🗂️ Gitea Project Dashboard
A self-hosted dashboard for centrally managing all personal projects – technical and non-technical alike. Projects can be linked to a Gitea repository, but don't have to be.
🏷️ How It Works: Tag-Based Project Display
Every repository on this Gitea instance that has the topic tag dashboard is automatically shown in the dashboard.
How it works:
- In a Gitea repository, go to Settings → Topics and add the tag
dashboard - The backend service polls the Gitea API regularly (or via webhook) for all repos with this tag
- The found repos are stored and cached in the PostgreSQL database
- The frontend displays all tagged repos as project cards with live data
Example: Repo
my-projectgets the topicdashboard→ immediately appears in the dashboard with issues, last commit, status, and description.
🧱 Architecture
┌─────────────────┐ Gitea REST API v1 ┌─────────────────────┐
│ Gitea Server │ ◄────────────────────► │ Backend Service │
│ (Repos + Topics)│ │ (Go, net/http) │
└─────────────────┘ └──────────┬──────────┘
│
┌──────────▼───────────┐
│ PostgreSQL DB │
│ (Repos, Issues, │
│ Milestones, Cache) │
└──────────┬───────────┘
│
┌──────────▼───────────┐
│ Frontend │
│ (SvelteKit) │
└──────────────────────┘
🖥️ Frontend: SvelteKit
Why SvelteKit?
- Lightweight and fast – ideal for an internal dashboard
- Server-Side Rendering (SSR) out of the box – no flickering on load
- Simple reactivity without overhead
- Perfect for data-driven dashboards with real-time updates via SSE or WebSocket
Frontend features:
- Project cards with repo name, description, last commit, open issues
- Filter function by topics, language, activity
- Detail view: edit issues & milestones directly in the dashboard (bi-directional)
- Live updates via webhook events (Server-Sent Events)
- Dark mode, responsive design
⚙️ Backend: Go (net/http + pgx)
Go is an excellent backend language – the standard library is so complete that no web framework is needed. net/http provides everything required: routing, handlers, middleware. The result is a dependency-light, readable codebase.
Why no framework?
net/httpfrom the standard library is fully sufficient for ~6 endpoints- No framework overhead, no breaking changes from external dependencies
- The Go-typical approach: explicit, simple, readable
- Compiles to a single static binary – minimal Docker footprint
External dependencies (minimal):
pgx– PostgreSQL driver (direct SQL, no ORM)godotenv– load.envfilegolang.org/x/oauth2– OAuth2 flow for Gitea login
Backend tasks:
GET /api/projects– return all tagged repos from the DBPOST /api/webhook– Gitea webhook listener for push, issue, tag eventsGET /api/projects/{id}/issues– fetch issues for a repo live from Gitea- Background goroutine: query Gitea API every 5 minutes for repos with tag
dashboard - Cache repo data in PostgreSQL (incl. topics, last activity, issue count)
Example – HTTP server without a framework:
mux := http.NewServeMux()
mux.HandleFunc("GET /api/projects", h.listProjects)
mux.HandleFunc("POST /api/webhook", h.handleWebhook)
mux.HandleFunc("GET /api/projects/{id}/issues", h.listIssues)
log.Fatal(http.ListenAndServe(":8080", mux))
🔐 Auth: Gitea OAuth2
Gitea can act as its own OAuth2 provider – users log into the dashboard with their Gitea account, just like "Login with GitHub".
Setup in Gitea:
- In Gitea under Settings → Applications → OAuth2 Applications, register a new app
- Enter Client ID and Client Secret in the
.envfile - Set the Redirect URI to
https://dashboard.example.com/auth/callback
Flow:
- User clicks "Login with Gitea"
- → Redirect to Gitea instance (Authorization Endpoint)
- → User confirms access
- → Gitea redirects back with Authorization Code
- → Backend exchanges code for Access Token
- → User is logged in, Gitea identity is known
Advantages:
- No custom auth system needed – Gitea handles passwords and sessions
- User identity directly available → repos and issues can be filtered per user
- Write permissions (create/close issues) only for the respective repo owner
- Implemented with
golang.org/x/oauth2– official Go package, no third-party lib needed
🗄️ Database: PostgreSQL
Schema overview:
-- Cached repo information
CREATE TABLE projects (
id SERIAL PRIMARY KEY,
gitea_id INTEGER UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
full_name VARCHAR(255) NOT NULL,
description TEXT,
html_url TEXT,
topics TEXT[], -- e.g. ["dashboard", "freelancer"]
language VARCHAR(100),
open_issues INTEGER DEFAULT 0,
last_push TIMESTAMPTZ,
is_private BOOLEAN DEFAULT false,
synced_at TIMESTAMPTZ DEFAULT NOW()
);
-- Managed issues / tasks
CREATE TABLE issues (
id SERIAL PRIMARY KEY,
gitea_id INTEGER NOT NULL,
project_id INTEGER REFERENCES projects(id),
title TEXT NOT NULL,
state VARCHAR(20), -- open / closed
assignee VARCHAR(100),
milestone TEXT,
updated_at TIMESTAMPTZ
);
-- Webhook event log
CREATE TABLE webhook_events (
id SERIAL PRIMARY KEY,
event_type VARCHAR(50),
payload JSONB,
received_at TIMESTAMPTZ DEFAULT NOW()
);
🚀 Roadmap
- v0.1 – Repo listing via tag
dashboard, polling every 5 min - v0.2 – Webhook listener for real-time updates
- v0.3 – Display issues & milestones in the dashboard
- v0.4 – Create/close issues directly from the dashboard (bi-directional)
- v0.5 – Gitea OAuth2 login
- v0.6 – Integration with freelancer dashboard (repos = projects)
- v1.0 – Multi-user, public project pages
🔧 Tech Stack
| Layer | Technology |
|---|---|
| Frontend | SvelteKit + TailwindCSS |
| Backend | Go + net/http (standard lib) |
| Database | PostgreSQL + pgx |
| Auth | Gitea OAuth2 + golang.org/x/oauth2 |
| API | Gitea REST API v1 |
| Deploy | Docker Compose |
📦 Getting Started
# Clone the repo
git clone https://gitea.starfour.de/Jannis/gitea-projekt-dashboard
# Set environment variables
cp .env.example .env
# Fill in GITEA_URL, GITEA_TOKEN, GITEA_CLIENT_ID, GITEA_CLIENT_SECRET, DATABASE_URL, DASHBOARD_TAG
# Start with Docker
docker compose up -d
This project is part of the personal project ideas collection. Related overview repo: projekt-ideen