Files
gitea-projekt-dashboard/README.md
2026-05-13 08:11:47 +00:00

74 KiB
Raw Blame History

🗂️ Gitea Project Dashboard

Warning

⏸️ Project paused

This project is currently paused. I am continuing to develop my own solution to replace Beego. Once my own web framework is far enough along, this project will be rebuilt with it.

👉 Own solution in development: go-webframework

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:

  1. In a Gitea repository, go to Settings → Topics and add the tag dashboard
  2. The backend service polls the Gitea API regularly (or via webhook) for all repos with this tag
  3. The found repos are stored and cached in the PostgreSQL database
  4. The frontend displays all tagged repos as project cards with live data

Example: Repo my-project gets the topic dashboard → 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/http` from 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 `.env` file
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 - `golang.org/x/oauth2`  OAuth2 flow for Gitea login

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 **Backend tasks:**

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 - `GET /api/projects`  return all tagged repos from the DB
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 - `POST /api/webhook`  Gitea webhook listener for push, issue, tag events
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 - `GET /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:**

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 ```go
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 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:**
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 1. In Gitea under **Settings → Applications → OAuth2 Applications**, register a new app
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 2. Enter Client ID and Client Secret in the `.env` file
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 3. 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:**

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 ```sql
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 -- 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

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 ```bash
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 # 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](https://gitea.starfour.de/Jannis/projekt-ideen)