Refine project structure by adding missing configuration files and updating directory organization

This commit is contained in:
2025-12-14 21:20:46 +07:00
parent cf7669191e
commit 52cbd13941
5 changed files with 185 additions and 0 deletions

View 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
- [ ] 8099% → 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
View 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...)
}

BIN
pluto-api Executable file

Binary file not shown.

47
web/templates/base.html Normal file
View 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}}

View File