From 29ee01afba49f7334186a002503b9b6d3cc385b4 Mon Sep 17 00:00:00 2001
From: KartoffelChips <104089082+KartoffelChipss@users.noreply.github.com>
Date: Fri, 3 Apr 2026 11:51:36 +0200
Subject: [PATCH] Added frontend
---
.idea/sqldialects.xml | 1 -
.idea/vcs.xml | 1 +
.gitignore => backend/.gitignore | 0
.../app}/cachedrepo/cached_site_repository.go | 0
{app => backend/app}/github/github.go | 0
{app => backend/app}/handlers/health.go | 0
{app => backend/app}/handlers/site.go | 0
.../app}/handlers/site_relations.go | 0
{app => backend/app}/handlers/static.go | 0
{app => backend/app}/handlers/update.go | 0
.../app}/middleware/api_host_guard.go | 0
{app => backend/app}/models/api_error.go | 0
{app => backend/app}/models/site.go | 0
.../app}/repository/site_repository.go | 0
{app => backend/app}/routes/routes.go | 0
.../config.example.yaml | 0
{docs => backend/docs}/docs.go | 0
{docs => backend/docs}/swagger.json | 0
{docs => backend/docs}/swagger.yaml | 0
go.mod => backend/go.mod | 0
go.sum => backend/go.sum | 0
.../internal}/database/init_sqlite.go | 0
.../internal}/database/site_sqlite.go | 0
.../internal}/database/sqlite.go | 0
.../internal}/envconfig/envconfig.go | 0
.../internal}/fiberconfig/fiberconfig.go | 0
.../internal}/security/deploy_token.go | 0
main.go => backend/main.go | 0
internal/config/config.go | 163 -----------------
theme.css | 173 ------------------
30 files changed, 1 insertion(+), 337 deletions(-)
rename .gitignore => backend/.gitignore (100%)
rename {app => backend/app}/cachedrepo/cached_site_repository.go (100%)
rename {app => backend/app}/github/github.go (100%)
rename {app => backend/app}/handlers/health.go (100%)
rename {app => backend/app}/handlers/site.go (100%)
rename {app => backend/app}/handlers/site_relations.go (100%)
rename {app => backend/app}/handlers/static.go (100%)
rename {app => backend/app}/handlers/update.go (100%)
rename {app => backend/app}/middleware/api_host_guard.go (100%)
rename {app => backend/app}/models/api_error.go (100%)
rename {app => backend/app}/models/site.go (100%)
rename {app => backend/app}/repository/site_repository.go (100%)
rename {app => backend/app}/routes/routes.go (100%)
rename config.example.yaml => backend/config.example.yaml (100%)
rename {docs => backend/docs}/docs.go (100%)
rename {docs => backend/docs}/swagger.json (100%)
rename {docs => backend/docs}/swagger.yaml (100%)
rename go.mod => backend/go.mod (100%)
rename go.sum => backend/go.sum (100%)
rename {internal => backend/internal}/database/init_sqlite.go (100%)
rename {internal => backend/internal}/database/site_sqlite.go (100%)
rename {internal => backend/internal}/database/sqlite.go (100%)
rename {internal => backend/internal}/envconfig/envconfig.go (100%)
rename {internal => backend/internal}/fiberconfig/fiberconfig.go (100%)
rename {internal => backend/internal}/security/deploy_token.go (100%)
rename main.go => backend/main.go (100%)
delete mode 100644 internal/config/config.go
delete mode 100644 theme.css
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
index 12103cf..c0e01ca 100644
--- a/.idea/sqldialects.xml
+++ b/.idea/sqldialects.xml
@@ -1,7 +1,6 @@
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..317ebc3 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/.gitignore b/backend/.gitignore
similarity index 100%
rename from .gitignore
rename to backend/.gitignore
diff --git a/app/cachedrepo/cached_site_repository.go b/backend/app/cachedrepo/cached_site_repository.go
similarity index 100%
rename from app/cachedrepo/cached_site_repository.go
rename to backend/app/cachedrepo/cached_site_repository.go
diff --git a/app/github/github.go b/backend/app/github/github.go
similarity index 100%
rename from app/github/github.go
rename to backend/app/github/github.go
diff --git a/app/handlers/health.go b/backend/app/handlers/health.go
similarity index 100%
rename from app/handlers/health.go
rename to backend/app/handlers/health.go
diff --git a/app/handlers/site.go b/backend/app/handlers/site.go
similarity index 100%
rename from app/handlers/site.go
rename to backend/app/handlers/site.go
diff --git a/app/handlers/site_relations.go b/backend/app/handlers/site_relations.go
similarity index 100%
rename from app/handlers/site_relations.go
rename to backend/app/handlers/site_relations.go
diff --git a/app/handlers/static.go b/backend/app/handlers/static.go
similarity index 100%
rename from app/handlers/static.go
rename to backend/app/handlers/static.go
diff --git a/app/handlers/update.go b/backend/app/handlers/update.go
similarity index 100%
rename from app/handlers/update.go
rename to backend/app/handlers/update.go
diff --git a/app/middleware/api_host_guard.go b/backend/app/middleware/api_host_guard.go
similarity index 100%
rename from app/middleware/api_host_guard.go
rename to backend/app/middleware/api_host_guard.go
diff --git a/app/models/api_error.go b/backend/app/models/api_error.go
similarity index 100%
rename from app/models/api_error.go
rename to backend/app/models/api_error.go
diff --git a/app/models/site.go b/backend/app/models/site.go
similarity index 100%
rename from app/models/site.go
rename to backend/app/models/site.go
diff --git a/app/repository/site_repository.go b/backend/app/repository/site_repository.go
similarity index 100%
rename from app/repository/site_repository.go
rename to backend/app/repository/site_repository.go
diff --git a/app/routes/routes.go b/backend/app/routes/routes.go
similarity index 100%
rename from app/routes/routes.go
rename to backend/app/routes/routes.go
diff --git a/config.example.yaml b/backend/config.example.yaml
similarity index 100%
rename from config.example.yaml
rename to backend/config.example.yaml
diff --git a/docs/docs.go b/backend/docs/docs.go
similarity index 100%
rename from docs/docs.go
rename to backend/docs/docs.go
diff --git a/docs/swagger.json b/backend/docs/swagger.json
similarity index 100%
rename from docs/swagger.json
rename to backend/docs/swagger.json
diff --git a/docs/swagger.yaml b/backend/docs/swagger.yaml
similarity index 100%
rename from docs/swagger.yaml
rename to backend/docs/swagger.yaml
diff --git a/go.mod b/backend/go.mod
similarity index 100%
rename from go.mod
rename to backend/go.mod
diff --git a/go.sum b/backend/go.sum
similarity index 100%
rename from go.sum
rename to backend/go.sum
diff --git a/internal/database/init_sqlite.go b/backend/internal/database/init_sqlite.go
similarity index 100%
rename from internal/database/init_sqlite.go
rename to backend/internal/database/init_sqlite.go
diff --git a/internal/database/site_sqlite.go b/backend/internal/database/site_sqlite.go
similarity index 100%
rename from internal/database/site_sqlite.go
rename to backend/internal/database/site_sqlite.go
diff --git a/internal/database/sqlite.go b/backend/internal/database/sqlite.go
similarity index 100%
rename from internal/database/sqlite.go
rename to backend/internal/database/sqlite.go
diff --git a/internal/envconfig/envconfig.go b/backend/internal/envconfig/envconfig.go
similarity index 100%
rename from internal/envconfig/envconfig.go
rename to backend/internal/envconfig/envconfig.go
diff --git a/internal/fiberconfig/fiberconfig.go b/backend/internal/fiberconfig/fiberconfig.go
similarity index 100%
rename from internal/fiberconfig/fiberconfig.go
rename to backend/internal/fiberconfig/fiberconfig.go
diff --git a/internal/security/deploy_token.go b/backend/internal/security/deploy_token.go
similarity index 100%
rename from internal/security/deploy_token.go
rename to backend/internal/security/deploy_token.go
diff --git a/main.go b/backend/main.go
similarity index 100%
rename from main.go
rename to backend/main.go
diff --git a/internal/config/config.go b/internal/config/config.go
deleted file mode 100644
index b292b8b..0000000
--- a/internal/config/config.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package config
-
-import (
- "fmt"
- "os"
- "path"
- "regexp"
- "strconv"
-
- "gopkg.in/yaml.v3"
-)
-
-type ForwardRule struct {
- Source string `yaml:"source"`
- Destination string `yaml:"destination"`
- StatusCode int `yaml:"status_code"`
- Regex bool `yaml:"regex"`
- Compiled *regexp.Regexp
-}
-
-type CustomHeader struct {
- Source string `yaml:"source"`
- Regex bool `yaml:"regex"`
- Headers map[string]string `yaml:"headers"`
- Compiled *regexp.Regexp
-}
-
-type SiteConfig struct {
- Name string `yaml:"name"`
- Repo string `yaml:"repo"`
- Owner string `yaml:"owner"`
- Branch string `yaml:"branch"`
- Domain string `yaml:"domain"`
- Enabled bool `yaml:"enabled"`
- SPA bool `yaml:"spa"`
- NotFoundFile string `yaml:"not_found_file"`
- DeployToken string `yaml:"deploy_token"`
- ForwardRules []ForwardRule `yaml:"forward_rules"`
- CustomHeaders []CustomHeader `yaml:"custom_headers"`
-}
-
-type Config struct {
- Sites []SiteConfig `yaml:"sites"`
-}
-
-type Error struct {
- Field string
- Message string
-}
-
-func (c Error) Error() string {
- return "Config error: " + c.Field + " - " + c.Message
-}
-
-func validateConfig(config *Config) error {
- for i, site := range config.Sites {
- if site.Name == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].name", Message: "Name is required"}
- }
- if site.Repo == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].repo", Message: "Repo is required"}
- }
- if site.Owner == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].owner", Message: "Owner is required"}
- }
- if site.Branch == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].branch", Message: "Branch is required"}
- }
- if site.Domain == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].domain", Message: "Domain is required"}
- }
- for j, rule := range site.ForwardRules {
- if rule.Source == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].forward_rules[" + strconv.Itoa(j) + "].source", Message: "Source is required"}
- }
- if rule.Destination == "" {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].forward_rules[" + strconv.Itoa(j) + "].destination", Message: "Destination is required"}
- }
- if rule.StatusCode == 0 {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].forward_rules[" + strconv.Itoa(j) + "].status_code", Message: "Status code is required"}
- }
- if rule.StatusCode < 300 || rule.StatusCode >= 400 {
- return &Error{Field: "sites[" + strconv.Itoa(i) + "].forward_rules[" + strconv.Itoa(j) + "].status_code", Message: "Status code must be a valid redirect code (300-399)"}
- }
- if rule.Regex {
- re, err := regexp.Compile(rule.Source)
- if err != nil {
- return &Error{
- Field: fmt.Sprintf("sites[%d].forward_rules[%d].source", i, j),
- Message: "Invalid regex: " + err.Error(),
- }
- }
- config.Sites[i].ForwardRules[j].Compiled = re
- }
- }
- for k, header := range site.CustomHeaders {
- if header.Source == "" {
- return &Error{Field: fmt.Sprintf("sites[%d].custom_headers[%d].source", i, k), Message: "Source is required"}
- }
- if len(header.Headers) == 0 {
- return &Error{Field: fmt.Sprintf("sites[%d].custom_headers[%d].headers", i, k), Message: "At least one header is required"}
- }
- if header.Regex {
- re, err := regexp.Compile(header.Source)
- if err != nil {
- return &Error{
- Field: fmt.Sprintf("sites[%d].custom_headers[%d].source", i, k),
- Message: "Invalid regex: " + err.Error(),
- }
- }
- config.Sites[i].CustomHeaders[k].Compiled = re
- } else {
- if _, err := path.Match(header.Source, ""); err != nil {
- return &Error{
- Field: fmt.Sprintf("sites[%d].custom_headers[%d].source", i, k),
- Message: "Invalid glob pattern: " + err.Error(),
- }
- }
- }
- }
- }
- return nil
-}
-
-func applyDefaults(config *Config) {
- for i := range config.Sites {
- if config.Sites[i].NotFoundFile == "" {
- config.Sites[i].NotFoundFile = "404.html"
- }
- for j := range config.Sites[i].ForwardRules {
- if config.Sites[i].ForwardRules[j].StatusCode == 0 {
- config.Sites[i].ForwardRules[j].StatusCode = 302
- }
- }
- }
-}
-
-func Load(path string) (*Config, error) {
- f, err := os.ReadFile(path)
- if err != nil {
- return nil, err
- }
- expanded := os.Expand(string(f), func(key string) string {
- val, ok := os.LookupEnv(key)
- if !ok {
- return "${" + key + "}" // env vars that aren't set are left as is to not cause errors with regex patterns
- }
- return val
- })
- var config Config
- err = yaml.Unmarshal([]byte(expanded), &config)
- if err != nil {
- return nil, err
- }
-
- applyDefaults(&config)
-
- err = validateConfig(&config)
- if err != nil {
- return nil, err
- }
- return &config, nil
-}
diff --git a/theme.css b/theme.css
deleted file mode 100644
index 7841966..0000000
--- a/theme.css
+++ /dev/null
@@ -1,173 +0,0 @@
-@import "tailwindcss";
-
-@custom-variant dark (&:is(.dark *));
-
-:root {
- --background: oklch(1.0000 0 0);
- --foreground: oklch(0.3211 0 0);
- --card: oklch(1.0000 0 0);
- --card-foreground: oklch(0.3211 0 0);
- --popover: oklch(1.0000 0 0);
- --popover-foreground: oklch(0.3211 0 0);
- --primary: oklch(0.6225 0.2041 259.9027);
- --primary-foreground: oklch(1.0000 0 0);
- --secondary: oklch(0.9665 0.0045 258.3247);
- --secondary-foreground: oklch(0.4419 0.0375 257.2811);
- --muted: oklch(0.9846 0.0017 247.8389);
- --muted-foreground: oklch(0.5471 0.0321 263.2921);
- --accent: oklch(0.9510 0.0267 237.5723);
- --accent-foreground: oklch(0.3742 0.1844 263.9420);
- --destructive: oklch(0.6496 0.2362 26.9032);
- --destructive-foreground: oklch(1.0000 0 0);
- --border: oklch(0.9271 0.0075 260.7315);
- --input: oklch(0.9271 0.0075 260.7315);
- --ring: oklch(0.6225 0.2041 259.9027);
- --chart-1: oklch(0.6225 0.2041 259.9027);
- --chart-2: oklch(0.5469 0.2507 262.8085);
- --chart-3: oklch(0.4902 0.2693 263.7106);
- --chart-4: oklch(0.4234 0.2370 263.9162);
- --chart-5: oklch(0.3742 0.1844 263.9420);
- --sidebar: oklch(0.9846 0.0017 247.8389);
- --sidebar-foreground: oklch(0.3211 0 0);
- --sidebar-primary: oklch(0.6225 0.2041 259.9027);
- --sidebar-primary-foreground: oklch(1.0000 0 0);
- --sidebar-accent: oklch(0.9510 0.0267 237.5723);
- --sidebar-accent-foreground: oklch(0.3742 0.1844 263.9420);
- --sidebar-border: oklch(0.9271 0.0075 260.7315);
- --sidebar-ring: oklch(0.6225 0.2041 259.9027);
- --font-sans: Inter, sans-serif;
- --font-serif: Source Serif 4, serif;
- --font-mono: JetBrains Mono, monospace;
- --radius: 1.15rem;
- --shadow-x: 0;
- --shadow-y: 1px;
- --shadow-blur: 3px;
- --shadow-spread: 0px;
- --shadow-opacity: 0.1;
- --shadow-color: oklch(0 0 0);
- --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
- --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
- --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
- --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
- --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10);
- --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10);
- --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10);
- --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
- --tracking-normal: 0em;
- --spacing: 0.25rem;
-}
-
-.dark {
- --background: oklch(0.2046 0 0);
- --foreground: oklch(0.9219 0 0);
- --card: oklch(0.2686 0 0);
- --card-foreground: oklch(0.9219 0 0);
- --popover: oklch(0.2686 0 0);
- --popover-foreground: oklch(0.9219 0 0);
- --primary: oklch(0.6225 0.2041 259.9027);
- --primary-foreground: oklch(1.0000 0 0);
- --secondary: oklch(0.2686 0 0);
- --secondary-foreground: oklch(0.9219 0 0);
- --muted: oklch(0.2393 0 0);
- --muted-foreground: oklch(0.7155 0 0);
- --accent: oklch(0.5802 0.1915 259.7416);
- --accent-foreground: oklch(0.8820 0.0588 253.9688);
- --destructive: oklch(0.6496 0.2362 26.9032);
- --destructive-foreground: oklch(1.0000 0 0);
- --border: oklch(0.3715 0 0);
- --input: oklch(0.3715 0 0);
- --ring: oklch(0.6225 0.2041 259.9027);
- --chart-1: oklch(0.7122 0.1526 254.9868);
- --chart-2: oklch(0.6225 0.2041 259.9027);
- --chart-3: oklch(0.5739 0.2334 262.7735);
- --chart-4: oklch(0.6225 0.2041 259.9027);
- --chart-5: oklch(0.6225 0.2041 259.9027);
- --sidebar: oklch(0.2046 0 0);
- --sidebar-foreground: oklch(0.9219 0 0);
- --sidebar-primary: oklch(0.6225 0.2041 259.9027);
- --sidebar-primary-foreground: oklch(1.0000 0 0);
- --sidebar-accent: oklch(0.6225 0.2041 259.9027);
- --sidebar-accent-foreground: oklch(0.8820 0.0588 253.9688);
- --sidebar-border: oklch(0.3715 0 0);
- --sidebar-ring: oklch(0.6225 0.2041 259.9027);
- --font-sans: Inter, sans-serif;
- --font-serif: Source Serif 4, serif;
- --font-mono: JetBrains Mono, monospace;
- --radius: 1.15rem;
- --shadow-x: 0;
- --shadow-y: 1px;
- --shadow-blur: 3px;
- --shadow-spread: 0px;
- --shadow-opacity: 0.1;
- --shadow-color: oklch(0 0 0);
- --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
- --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
- --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
- --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
- --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10);
- --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10);
- --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10);
- --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
-}
-
-@theme inline {
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --color-card: var(--card);
- --color-card-foreground: var(--card-foreground);
- --color-popover: var(--popover);
- --color-popover-foreground: var(--popover-foreground);
- --color-primary: var(--primary);
- --color-primary-foreground: var(--primary-foreground);
- --color-secondary: var(--secondary);
- --color-secondary-foreground: var(--secondary-foreground);
- --color-muted: var(--muted);
- --color-muted-foreground: var(--muted-foreground);
- --color-accent: var(--accent);
- --color-accent-foreground: var(--accent-foreground);
- --color-destructive: var(--destructive);
- --color-destructive-foreground: var(--destructive-foreground);
- --color-border: var(--border);
- --color-input: var(--input);
- --color-ring: var(--ring);
- --color-chart-1: var(--chart-1);
- --color-chart-2: var(--chart-2);
- --color-chart-3: var(--chart-3);
- --color-chart-4: var(--chart-4);
- --color-chart-5: var(--chart-5);
- --color-sidebar: var(--sidebar);
- --color-sidebar-foreground: var(--sidebar-foreground);
- --color-sidebar-primary: var(--sidebar-primary);
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
- --color-sidebar-accent: var(--sidebar-accent);
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
- --color-sidebar-border: var(--sidebar-border);
- --color-sidebar-ring: var(--sidebar-ring);
-
- --font-sans: var(--font-sans);
- --font-mono: var(--font-mono);
- --font-serif: var(--font-serif);
-
- --radius-sm: calc(var(--radius) - 4px);
- --radius-md: calc(var(--radius) - 2px);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) + 4px);
-
- --shadow-2xs: var(--shadow-2xs);
- --shadow-xs: var(--shadow-xs);
- --shadow-sm: var(--shadow-sm);
- --shadow: var(--shadow);
- --shadow-md: var(--shadow-md);
- --shadow-lg: var(--shadow-lg);
- --shadow-xl: var(--shadow-xl);
- --shadow-2xl: var(--shadow-2xl);
-}
-
-@layer base {
- * {
- @apply border-border outline-ring/50;
- }
- body {
- @apply bg-background text-foreground;
- }
-}