Refine project structure by adding missing configuration files and updating directory organization
This commit is contained in:
58
.cursor/rules/atlas-project-rules.mdc
Normal file
58
.cursor/rules/atlas-project-rules.mdc
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
##########################################
|
||||||
|
# Atlas Project Standard Rules v1.0
|
||||||
|
# ISO Ref: DevOps-Config-2025
|
||||||
|
# Maintainer: Adastra - InfraOps Team
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- Template Name : Atlas Project Standard Rules
|
||||||
|
- Version : 1.0
|
||||||
|
- Maintainer : InfraOps Team
|
||||||
|
- Last Updated : 2025-12-14
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rule Categories
|
||||||
|
|
||||||
|
### 🔧 Indentation & Spacing
|
||||||
|
[ ] CURSOR-001: Gunakan 2 spasi untuk indentation
|
||||||
|
[ ] CURSOR-002: Hindari tab, gunakan spasi konsisten
|
||||||
|
|
||||||
|
### 📂 Naming Convention
|
||||||
|
[ ] CURSOR-010: File harus pakai snake_case
|
||||||
|
[ ] CURSOR-011: Folder pakai kebab-case
|
||||||
|
[ ] CURSOR-012: Config file wajib ada suffix `.conf`
|
||||||
|
[ ] CURSOR-013: Script file wajib ada suffix `.sh`
|
||||||
|
[ ] CURSOR-014: Log file wajib ada suffix `.log`
|
||||||
|
|
||||||
|
### 🗂 File Structure
|
||||||
|
[ ] CURSOR-020: Semua file harus ada header metadata
|
||||||
|
[ ] CURSOR-021: Pisahkan config, script, dan log folder
|
||||||
|
[ ] CURSOR-022: Tidak ada file kosong di repo
|
||||||
|
|
||||||
|
### ✅ Audit & Compliance
|
||||||
|
[ ] CURSOR-030: Checklist harus lengkap sebelum commit
|
||||||
|
[ ] CURSOR-031: Semua config tervalidasi linting
|
||||||
|
[ ] CURSOR-032: Banner branding wajib ada di setiap template
|
||||||
|
|
||||||
|
### ⚠️ Error Handling
|
||||||
|
[ ] CURSOR-040: Log error harus diarahkan ke folder `/logs`
|
||||||
|
[ ] CURSOR-041: Tidak ada hardcoded path di script
|
||||||
|
[ ] CURSOR-042: Semua service startup diverifikasi
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Compliance Scoring
|
||||||
|
- [ ] 100% → Audit Passed
|
||||||
|
- [ ] 80–99% → Minor Findings
|
||||||
|
- [ ] <80% → Audit Failed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- Semua rule harus dipetakan ke ID unik (CURSOR-XXX).
|
||||||
|
- Versi baru wajib update metadata & banner.
|
||||||
|
- Checklist ini bisa dipakai lintas project untuk konsistensi.
|
||||||
80
internal/httpapp/app.go
Normal file
80
internal/httpapp/app.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package httpapp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Addr string
|
||||||
|
TemplatesDir string
|
||||||
|
StaticDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
cfg Config
|
||||||
|
tmpl *template.Template
|
||||||
|
mux *http.ServeMux
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg Config) (*App, error) {
|
||||||
|
if cfg.TemplatesDir == "" {
|
||||||
|
cfg.TemplatesDir = "web/templates"
|
||||||
|
}
|
||||||
|
if cfg.StaticDir == "" {
|
||||||
|
cfg.StaticDir = "web/static"
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := parseTemplates(cfg.TemplatesDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := &App{
|
||||||
|
cfg: cfg,
|
||||||
|
tmpl: tmpl,
|
||||||
|
mux: http.NewServeMux(),
|
||||||
|
}
|
||||||
|
|
||||||
|
a.routes()
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Router() http.Handler {
|
||||||
|
// Wrap the mux with basic middleware chain
|
||||||
|
return requestID(logging(a.mux))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) routes() {
|
||||||
|
// Static
|
||||||
|
fs := http.FileServer(http.Dir(a.cfg.StaticDir))
|
||||||
|
a.mux.Handle("/static/", http.StripPrefix("/static/", fs))
|
||||||
|
|
||||||
|
// Core pages
|
||||||
|
a.mux.HandleFunc("/", a.handleDashboard)
|
||||||
|
|
||||||
|
// Health & metrics
|
||||||
|
a.mux.HandleFunc("/healthz", a.handleHealthz)
|
||||||
|
a.mux.HandleFunc("/metrics", a.handleMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTemplates(dir string) (*template.Template, error) {
|
||||||
|
pattern := filepath.Join(dir, "*.html")
|
||||||
|
files, err := filepath.Glob(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(files) == 0 {
|
||||||
|
return nil, fmt.Errorf("no templates found at %s", pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
funcs := template.FuncMap{
|
||||||
|
"nowRFC3339": func() string { return time.Now().Format(time.RFC3339) },
|
||||||
|
}
|
||||||
|
|
||||||
|
t := template.New("root").Funcs(funcs)
|
||||||
|
return t.ParseFiles(files...)
|
||||||
|
}
|
||||||
47
web/templates/base.html
Normal file
47
web/templates/base.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{{define "base"}}
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<title>{{.Title}} • PlutoOS</title>
|
||||||
|
|
||||||
|
<!-- v1: Tailwind CDN (later: bundle local) -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="bg-slate-950 text-slate-100">
|
||||||
|
<header class="border-b border-slate-800 bg-slate-950/80 backdrop-blur">
|
||||||
|
<div class="mx-auto max-w-6xl px-4 py-3 flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="h-9 w-9 rounded-lg bg-slate-800 flex items-center justify-center font-bold">P</div>
|
||||||
|
<div>
|
||||||
|
<div class="font-semibold leading-tight">PlutoOS</div>
|
||||||
|
<div class="text-xs text-slate-400 leading-tight">Storage Controller v1</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="text-sm text-slate-300 flex items-center gap-4">
|
||||||
|
<a class="hover:text-white" href="/">Dashboard</a>
|
||||||
|
<a class="hover:text-white opacity-50 cursor-not-allowed" href="#">Storage</a>
|
||||||
|
<a class="hover:text-white opacity-50 cursor-not-allowed" href="#">Shares</a>
|
||||||
|
<a class="hover:text-white opacity-50 cursor-not-allowed" href="#">iSCSI</a>
|
||||||
|
<a class="hover:text-white opacity-50 cursor-not-allowed" href="#">Monitoring</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="mx-auto max-w-6xl px-4 py-8">
|
||||||
|
{{template "content" .}}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="mx-auto max-w-6xl px-4 pb-10 text-xs text-slate-500">
|
||||||
|
<div class="border-t border-slate-800 pt-4 flex items-center justify-between">
|
||||||
|
<span>PlutoOS • {{nowRFC3339}}</span>
|
||||||
|
<span>Build: {{index .Build "version"}}</span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{end}}
|
||||||
0
web/templates/dashboard.html
Normal file
0
web/templates/dashboard.html
Normal file
Reference in New Issue
Block a user