new sub page paradigm

This commit is contained in:
samantha42
2026-08-28 01:36:11 +02:00
parent 5d3c428112
commit 3d3d87fad9
23 changed files with 896 additions and 252 deletions
+134 -247
View File
@@ -1,270 +1,157 @@
package main
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"embed"
"html/template"
"io/fs"
"log"
"net/http"
"os"
"strconv"
"sync"
"time"
"github.com/joho/godotenv"
"github.com/pquerna/otp/totp"
)
type Config struct {
Job string `json:"job"`
Emails []string `json:"emails"`
NewsSent int `json:"newletter-sent"`
}
func loadConfig() (*Config, error) {
data, err := os.ReadFile("data.json")
if err != nil {
return nil, err
}
var c Config
return &c, json.Unmarshal(data, &c)
}
func saveConfig(c *Config) error {
data, err := json.MarshalIndent(c, "", " ")
if err != nil {
return err
}
return os.WriteFile("data.json", data, 0644)
}
func validateEnv() {
// checking if env file is there in the directory:
err := godotenv.Load(".env")
if err != nil {
log.Fatal("Error loading .env file")
}
// checking secret for rooling 2fa
secret := os.Getenv("secret")
if secret == "" {
fmt.Println("set secret first")
os.Exit(1)
}
}
//go:embed source static
var sourceFS embed.FS
func main() {
validateEnv()
port := flag.String("port", "8081", "port to listen on")
flag.Parse()
mux := http.NewServeMux()
fs := http.FileServer(http.Dir("static"))
mux.Handle("/static/", http.StripPrefix("/static/", fs))
mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/index.html") })
mux.HandleFunc("GET /infra", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/infra.html") })
mux.HandleFunc("GET /finance", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/finance.html") })
mux.HandleFunc("GET /cinema", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/cinema.html") })
mux.HandleFunc("GET /engine", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/engine.html") })
mux.HandleFunc("GET /42", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/42.html") })
mux.HandleFunc("GET /secret", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/secret.html") })
mux.HandleFunc("GET /favicon.ico", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./static/icon.png") })
mux.HandleFunc("GET /login", func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("session")
if err == nil {
sessionMu.RLock()
expiry, ok := sessionStore[cookie.Value]
sessionMu.RUnlock()
// had session, but invalid
if !ok || time.Now().After(expiry) {
sessionMu.Lock()
delete(sessionStore, cookie.Value)
sessionMu.Unlock()
} else { // valid session
http.Redirect(w, r, "/admin", http.StatusSeeOther)
}
}
http.ServeFile(w, r, "./static/login.html")
})
mux.HandleFunc("GET /admin", requireAuth(func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./static/admin.html")
}))
mux.HandleFunc("GET /logout", requireAuth(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("session")
if err == nil {
// delete session cookie token
sessionMu.Lock()
delete(sessionStore, cookie.Value)
sessionMu.Unlock()
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}))
mux.HandleFunc("POST /newsletter/subscribe", func(w http.ResponseWriter, r *http.Request) {
var req struct {
Email string `json:"email"`
}
err := json.NewDecoder(r.Body).Decode(&req)
staticRoot, err := fs.Sub(sourceFS, "source")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
double := false
conf, err := loadConfig()
for _, e := range conf.Emails {
if e == req.Email {
double = true
}
}
if !double {
conf.Emails = append(conf.Emails, req.Email)
}
saveConfig(conf)
})
mux.HandleFunc("GET /status", func(w http.ResponseWriter, r *http.Request) {
config, err := loadConfig()
if err != nil {
http.Error(w, "failed to load config", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html")
//<span ">samantha42.xyz</span>
if config.Job == "" || config.Job == "none" {
fmt.Fprint(w, `<span class="available" ><span class="dot dot--available"></span>available for work</span>`)
} else {
fmt.Fprintf(w, `<span class="busy" ><span class="dot dot--busy"></span>working at: <b>%s</b></span>`, config.Job)
}
})
mux.HandleFunc("POST /login", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
password := r.Form.Get("password")
auth := r.Form.Get("totp")
// cheking password
h := sha256.New()
h.Write([]byte(password))
b := hex.EncodeToString(h.Sum(nil))
if string(b) == os.Getenv("password_sha") && totp.Validate(auth, os.Getenv("secret")) {
fmt.Println("logged in")
token := generateSession()
sessionMu.Lock()
sessionStore[token] = time.Now().Add(12 * time.Hour)
sessionMu.Unlock()
http.SetCookie(w, &http.Cookie{
Name: "session",
Value: token,
Path: "/",
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(48 * time.Hour),
})
// htmx reads this header and does the redirect client-side
w.Header().Set("HX-Redirect", "/admin")
w.WriteHeader(http.StatusOK)
} else {
// failure
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `<div class="error-banner">// incorrect password or 2FA code</div>`)
}
})
//http.HandleFunc("/portfolio", Portfolio)
mux.HandleFunc("/git", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "https://git.samantha42.xyz", http.StatusFound)
})
// --- /admin/ sub-mux ---
adminMux := http.NewServeMux()
adminMux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./static/admin.html")
})
// strip the /admin prefix before handing off
mux.Handle("/admin/", http.StripPrefix("/admin", adminMux))
// --- /admin/api/ sub-mux ---
apiMux := http.NewServeMux()
apiMux.HandleFunc("GET /stats/subscribers", requireAuth(func(w http.ResponseWriter, r *http.Request) {
conf, err := loadConfig()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
fmt.Fprintf(w, "%s", strconv.Itoa(len(conf.Emails)))
}))
apiMux.HandleFunc("GET /stats/sent", requireAuth(func(w http.ResponseWriter, r *http.Request) {
conf, err := loadConfig()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
fmt.Fprintf(w, "%s", strconv.Itoa(conf.NewsSent))
}))
// strip /admin/api before handing off
adminMux.Handle("/api/", http.StripPrefix("/api", apiMux))
fmt.Printf("running on http://localhost:%s/\n", *port)
if err := http.ListenAndServe(":"+*port, mux); err != nil {
log.Fatal(err)
}
}
var sessionStore = map[string]time.Time{}
var sessionMu sync.RWMutex
func generateSession() string {
b := make([]byte, 32)
rand.Read(b)
return hex.EncodeToString(b)
}
func requireAuth(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("session")
// print exactly what got embedded
fs.WalkDir(staticRoot, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
http.Redirect(w, r, "/login", http.StatusSeeOther)
log.Println("walk error:", err)
return nil
}
log.Println("embedded:", path)
return nil
})
mux := http.NewServeMux()
mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(staticRoot, "templates/main.html", "pages/index.html")
if err != nil {
log.Println("parse error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
sessionMu.RLock()
expiry, ok := sessionStore[cookie.Value]
sessionMu.RUnlock()
data := struct {
Title string
Sub bool
}{
Title: "home",
Sub: false,
}
if !ok || time.Now().After(expiry) {
sessionMu.Lock()
delete(sessionStore, cookie.Value)
sessionMu.Unlock()
http.Redirect(w, r, "/login", http.StatusSeeOther)
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// execute the base file by name — main.html is the entrypoint
if err := tmpl.ExecuteTemplate(w, "main.html", data); err != nil {
log.Println("execute error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
mux.HandleFunc("GET /research", func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(staticRoot, "templates/main.html", "pages/research.html")
if err != nil {
log.Println("parse error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
next(w, r)
data := struct {
Title string
Sub bool
}{
Title: "research",
Sub: true,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// execute the base file by name — main.html is the entrypoint
if err := tmpl.ExecuteTemplate(w, "main.html", data); err != nil {
log.Println("execute error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
mux.HandleFunc("GET /bookkeeping", func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(staticRoot, "templates/main.html", "pages/bookkeeping.html")
if err != nil {
log.Println("parse error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := struct {
Title string
Sub bool
}{
Title: "bookkeeping",
Sub: true,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// execute the base file by name — main.html is the entrypoint
if err := tmpl.ExecuteTemplate(w, "main.html", data); err != nil {
log.Println("execute error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
mux.HandleFunc("GET /automation", func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(staticRoot, "templates/main.html", "pages/automation.html")
if err != nil {
log.Println("parse error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := struct {
Title string
Sub bool
}{
Title: "automation",
Sub: true,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// execute the base file by name — main.html is the entrypoint
if err := tmpl.ExecuteTemplate(w, "main.html", data); err != nil {
log.Println("execute error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
mux.HandleFunc("GET /interests", func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(staticRoot, "templates/main.html", "pages/interests.html")
if err != nil {
log.Println("parse error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := struct {
Title string
Sub bool
}{
Title: "interests",
Sub: true,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// execute the base file by name — main.html is the entrypoint
if err := tmpl.ExecuteTemplate(w, "main.html", data); err != nil {
log.Println("execute error:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
assetsRoot, err := fs.Sub(sourceFS, "static")
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServerFS(assetsRoot)))
log.Println("running on http://localhost:8081/")
log.Fatal(http.ListenAndServe(":8081", mux))
}
BIN
View File
Binary file not shown.
View File
View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+208
View File
@@ -0,0 +1,208 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Samantha Vero Friis</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500&family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap"
rel="stylesheet" />
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<link rel="stylesheet" href="/static/output.css"/>
</head>
<body class="theme-root day " id="themeRoot">
<nav>
<a class="nav-logo" href="/#">samantha_vero_friis</a>
</nav>
<div class="shell">
<aside>
<div class="row">
<img id="day" src="/static/icons/lovesun.png" width="30px" class="hidden" onclick="makeday()" >
<img id="night" src="/static/icons/moon.png" width="30px" onclick="makenight()" >
</div>
<div>
<p class="sidebar-label">navigate</p>
<div class="sidebar-links">
<a href="#about">about</a>
<a href="#experience">experience</a>
<a href="#education">education</a>
<a href="#interests">interests</a>
</div>
</div>
<div>
<p class="sidebar-label">pages</p>
<div class="sidebar-links">
<a href="/automation">automation</a>
<a href="/research">research</a>
<a href="/bookkeeping">bookkeeping</a>
<a href="/interests">interests</a>
</div>
</div>
<div>
<p class="sidebar-label">skills</p>
<div class="skill-list">
<div class="skill-item">Excel</div>
<div class="skill-item">Python</div>
<div class="skill-item">SQL</div>
<div class="skill-item">Go</div>
<div class="skill-item">Git</div>
<div class="skill-item">Linux</div>
</div>
</div>
<div>
<p class="sidebar-label">location</p>
<div style="font-family:var(--ff-mono);font-size:0.75rem;color:var(--muted);">Denmark<br>Aalborg Øst, 9220</div>
</div>
<div>
<p class="sidebar-label">languages</p>
<div class="lang-row">
<span class="lang-badge">Danish</span>
<span class="lang-badge">English</span>
</div>
</div>
<div style="flex: 1;"></div>
</aside>
<main id="about">
<section class="hero">
<p class="hero-eyebrow">About Me · 2026</p>
<h1>Samantha<br><span>Vero Friis</span>
</h1>
<p class="hero-bio">Bachelor's student in Business Administration seeking an entry-level analyst or
finance-related role while studying. Strong numerical skills, advanced Excel, and experience in company, risk,
and financial analysis. Analytical, detail-oriented, and efficiency-focused.</p>
<div class="hero-meta">
<span>
<div hx-get="/status" hx-trigger="load" hx-swap="outerHTML"></div>
<span class="exp-tag">samantha42.xyz</span>
<span class="exp-tag">me@samantha42.xyz</span>
</div>
</section>
<section id="experience">
<div class="section-head">
<h2>experience</h2>
</div>
<div class="exp-grid">
<div class="exp-card link" onclick="window.location.href='/research'">
<div class="exp-header">
<span class="exp-title">Independent Equity Research</span>
<span class="exp-tag">finance</span>
</div>
<p class="exp-body">Fundamental analysis using SEC filings (10-K, 10-Q) and earnings reports. Assess
profitability, liquidity, risk factors, and long-term business sustainability. Handle incomplete or
low-transparency information through structured cross-validation.</p>
</div>
<div class="exp-card link" onclick="window.location.href='/bookkeeping'">
<div class="exp-header">
<span class="exp-title">Bookkeeping &amp; Administration</span>
<span class="exp-tag">Record keeping</span>
</div>
<p class="exp-body">Excel to In house Bookkeeping tooling and backups and safe sql databse for larger scale. made to better comply to lawmakers in KLACQ ApS(small self owned company) currently selling SaaS products. <a href="https:klacq.eu">klacq website</a> </p>
</div>
<div class="exp-card link" onclick="window.location.href='/automation'">
<div class="exp-header">
<span class="exp-title">Technical Tools &amp; Automation</span>
<span class="exp-tag">programing</span>
</div>
<p class="exp-body">Build lightweight backend tools to automate repetitive analytical and operational tasks.
Python for data processing, validation, and workflow automation. Lightweight online services in Go,
focusing on speed and reliability.</p>
</div>
</div>
</section>
<section id="education">
<div class="section-head">
<h2>education</h2>
</div>
<div class="edu-grid">
<div class="edu-card">
<div class="edu-year">2025 — present</div>
<div>
<div class="edu-degree">Bachelor of Economics &amp; Business Administration (HA)</div>
<div class="edu-inst">Aalborg University · Expected 2028</div>
</div>
</div>
<div class="edu-card">
<div class="edu-year">2024 — 2025
<br>
<span class="edu-tag tag-dropped">discontinued</span>
</div>
<div class="edu-body">
<div class="edu-degree">Mathematics-Technology (BSc)</div>
<div class="edu-inst">Aalborg University · 1 semester</div>
</div>
</div>
<div class="edu-card">
<div class="edu-year">2020 — 2023</div>
<div>
<div class="edu-degree">HTX Technical Upper Secondary Education</div>
<div class="edu-inst">Viden Gymnasier</div>
<div class="edu-detail">Mathematics A, Biology B · Study project: Mathematics &amp; Technology</div>
</div>
</div>
</div>
</section>
<section id="interests">
<div class="section-head">
<h2>interests</h2>
</div>
<div class="exp-grid">
<div class="exp-card link" onclick="window.location.href='/interests'">
<div class="exp-header">
<span class="exp-title">Personal Free Time Interest</span>
<span class="exp-tag">Personal</span>
</div>
<p class="exp-body">Movies, computers, PC gaming and oard games</p>
</div>
</div>
</section>
</main>
</div>
<footer>
<div class="footer-contact">
<a href="mailto:me@samantha42.xyz">me@samantha42.xyz</a>
</div>
<div class="footer-copy">© 2026 — all rights reserved</div>
</footer>
<script>
// just some fun.
console.log("%c👀 hi there!", "font-size:20px")
function makeday() {
themeRoot.classList.remove('night');
const day = document.getElementById('day');
const night = document.getElementById('night');
day.classList.add("hidden");
night.classList.remove("hidden");
}
function makenight() {
themeRoot.classList.add('night');
const day = document.getElementById('day');
const night = document.getElementById('night');
day.classList.remove("hidden");
night.classList.add("hidden");
}
</script>
</body>
</html>
+56
View File
@@ -0,0 +1,56 @@
{{define "nav"}}
{{end}}
{{define "body"}}
<section id="automation">
<div class="page-header">
<h2 class="page-title">Technical Tools & Automation</h2>
<span class="page-sub">engineering/programing</span>
</div>
<div class="exp-grid">
<p class="exp-body">
The task here is simple: to reduce work, it's a simple investment. The choice of picking the correct
bottleneck is as important as the tool itself, as this gives it use. If it's never used, it never creates
value. The same goes for uptime, it's important that stability is almost perfect, as downtime undermines
the utility of having the tool. Remember that making and using a tool also creates debt for future
maintenance of the tool.
<br>
To adhere to this, I often choose Golang or Python as they are cheap to maintain. Golang has good
stability because it is easy to code and compile checks give early error detection. A word of caution on
AI generated tools: while they are cheap to make, the maintenance debt grows exponentially, as the code is
often poorly understood by the team and difficult to reason about over time.
</p>
<div class="exp-card" >
<div class="exp-header">
<span class="exp-title">Portfolio Engine</span>
</div>
<p class="exp-body">A lightweight portfolio and financial data backend written in Go. Tracks companies,
currencies, revenue reports, and trades across configurable time periods — replacing spreadsheets with a
proper database, REST API, and interactive shell.</p>
<span class="exp-title">Roadmap</span>
<ul style="padding: 20px;">
<li class="exp-body">Price update endpoint</li>
<li class="exp-body">Multi-currency conversion</li>
<li class="exp-body">Frontend dashboard</li>
<li class="exp-body">Shares outstanding history database table</li>
<li class="exp-body">Earnings per share (EPS) based on shares owned</li>
<li class="exp-body">First-In, First-Out (FIFO) realized gains</li>
<li class="exp-body">Dividends earned and related taxes</li>
<li class="exp-body">Total tax obligations</li>
</ul>
<a class="outlink" href="https://git.samantha42.xyz/samantha/Portfolio-Engine">Git repo</a>
</div>
<div class="exp-card">
<div class="exp-header">
<span class="exp-title">Accounting Management</span>
</div>
<p class="exp-body">
A lightweight, SQL-backed, web-based CLI system designed to track assets and liabilities. The goal is to
provide a simple, fast, and scalable financial tracking tool that can grow from personal use to more
advanced scenarios.</p>
</div>
</div>
</section>
{{end}}
+7
View File
@@ -0,0 +1,7 @@
{{define "nav"}}
{{end}}
{{define "body"}}
{{end}}
+144
View File
@@ -0,0 +1,144 @@
{{define "nav"}}
<div>
<p class="sidebar-label">navigate</p>
<div class="sidebar-links">
<a href="#about">about</a>
<a href="#experience">experience</a>
<a href="#education">education</a>
<a href="#interests">interests</a>
</div>
</div>
<div>
<p class="sidebar-label">pages</p>
<div class="sidebar-links">
<a href="/automation">automation</a>
<a href="/research">research</a>
<a href="/bookkeeping">bookkeeping</a>
<a href="/interests">interests</a>
</div>
</div>
<div>
<p class="sidebar-label">skills</p>
<div class="skill-list">
<div class="skill-item">Excel</div>
<div class="skill-item">Python</div>
<div class="skill-item">SQL</div>
<div class="skill-item">Go</div>
<div class="skill-item">Git</div>
<div class="skill-item">Linux</div>
</div>
</div>
<div>
<p class="sidebar-label">location</p>
<div style="font-family:var(--ff-mono);font-size:0.75rem;color:var(--muted);">Denmark<br>Aalborg Øst, 9220</div>
</div>
<div>
<p class="sidebar-label">languages</p>
<div class="lang-row">
<span class="lang-badge">Danish</span>
<span class="lang-badge">English</span>
</div>
</div>
{{end}}
{{define "body"}}
<section class="hero">
<p class="hero-eyebrow">About Me · 2026</p>
<h1>Samantha<br><span>Vero Friis</span>
</h1>
<p class="hero-bio">Bachelor's student in Business Administration seeking an entry-level analyst or
finance-related role while studying. Strong numerical skills, advanced Excel, and experience in company, risk,
and financial analysis. Analytical, detail-oriented, and efficiency-focused.</p>
<div class="hero-meta">
<span>
<div hx-get="/status" hx-trigger="load" hx-swap="outerHTML"></div>
<span class="exp-tag">samantha42.xyz</span>
<span class="exp-tag">me@samantha42.xyz</span>
</div>
</section>
<section id="experience">
<div class="section-head">
<h2>experience</h2>
</div>
<div class="exp-grid">
<div class="exp-card link" onclick="window.location.href='/research'">
<div class="exp-header">
<span class="exp-title">Independent Equity Research</span>
<span class="exp-tag">finance</span>
</div>
<p class="exp-body">Fundamental analysis using SEC filings (10-K, 10-Q) and earnings reports. Assess
profitability, liquidity, risk factors, and long-term business sustainability. Handle incomplete or
low-transparency information through structured cross-validation.</p>
</div>
<div class="exp-card link" onclick="window.location.href='/bookkeeping'">
<div class="exp-header">
<span class="exp-title">Bookkeeping &amp; Administration</span>
<span class="exp-tag">Record keeping</span>
</div>
<p class="exp-body">Excel to In house Bookkeeping tooling and backups and safe sql databse for larger scale. made to better comply to lawmakers in KLACQ ApS(small self owned company) currently selling SaaS products. <a href="https:klacq.eu">klacq website</a> </p>
</div>
<div class="exp-card link" onclick="window.location.href='/automation'">
<div class="exp-header">
<span class="exp-title">Technical Tools &amp; Automation</span>
<span class="exp-tag">programing</span>
</div>
<p class="exp-body">Build lightweight backend tools to automate repetitive analytical and operational tasks.
Python for data processing, validation, and workflow automation. Lightweight online services in Go,
focusing on speed and reliability.</p>
</div>
</div>
</section>
<section id="education">
<div class="section-head">
<h2>education</h2>
</div>
<div class="edu-grid">
<div class="edu-card">
<div class="edu-year">2025 — present</div>
<div>
<div class="edu-degree">Bachelor of Economics &amp; Business Administration (HA)</div>
<div class="edu-inst">Aalborg University · Expected 2028</div>
</div>
</div>
<div class="edu-card">
<div class="edu-year">2024 — 2025
<br>
<span class="edu-tag tag-dropped">discontinued</span>
</div>
<div class="edu-body">
<div class="edu-degree">Mathematics-Technology (BSc)</div>
<div class="edu-inst">Aalborg University · 1 semester</div>
</div>
</div>
<div class="edu-card">
<div class="edu-year">2020 — 2023</div>
<div>
<div class="edu-degree">HTX Technical Upper Secondary Education</div>
<div class="edu-inst">Viden Gymnasier</div>
<div class="edu-detail">Mathematics A, Biology B · Study project: Mathematics &amp; Technology</div>
</div>
</div>
</div>
</section>
<section id="interests">
<div class="section-head">
<h2>interests</h2>
</div>
<div class="exp-grid">
<div class="exp-card link" onclick="window.location.href='/interests'">
<div class="exp-header">
<span class="exp-title">Personal Free Time Interest</span>
<span class="exp-tag">Personal</span>
</div>
<p class="exp-body">Movies, computers, PC gaming and oard games</p>
</div>
</div>
</section>
{{end}}
+139
View File
@@ -0,0 +1,139 @@
{{define "nav"}}
<div>
<p class="sidebar-label">pages</p>
<div class="sidebar-links">
<a href="/automation">automation</a>
<a href="/research">research</a>
<a href="/bookkeeping">bookkeeping</a>
</div>
</div>
<div>
<p class="sidebar-label">subjects</p>
<div class="skill-list">
<div class="skill-item">movies</div>
<div class="skill-item">games</div>
<div class="skill-item">linux</div>
<div class="skill-item">board games</div>
</div>
</div>
{{end}}
{{define "body"}}
<section id="interests">
<div id="interests-body" >
<span class="matrix-hidden" id="matrix-hidden">
Boy: Do not try and bend the spoon. That's impossible. Instead... only try to realize the truth.
<br>
Neo: What truth?
<br>
Boy: There is no spoon.
</span>
<div class="section-head">
<h2>Movie/Show Top list</h2>
</div>
<div class="toplist-group">
<h3>Top 5 Movies</h3>
<div class="toplist-body">
<div class="poster-grid">
<div class="poster-item posterhover" onclick="bladerunnerClick()">
<img src="/static/posters/bladerunner2049.jpg" alt="Blade Runner 2049">
<p>Blade Runner 2049</p>
</div>
<div class="poster-item posterhover" onclick="cureClick()">
<img src="/static/posters/AcureForWellness.jpg" alt="A Cure of Wellness">
<p>A Cure of Wellness</p>
</div>
<div class="poster-item posterhover" onclick="matrixClick()">
<img src="/static/posters/matrix.jpg" alt="matrix">
<p>The Matrix</p>
</div>
<div class="poster-item posterhover" onclick="draculaClick()">
<img src="/static/posters/Dracula.webp" alt="Dracula: A Love Tale">
<p>Dracula: A Love Tale</p>
</div>
<div class="poster-item posterhover" onclick="dragonTypewriterClick()">
<img src="/static/posters/TheGirlwiththeDragonTattoo.webp" alt="Girl with a Dragon Tattoos">
<p>Girl with a Dragon Tattoo</p>
</div>
</div>
</div>
<div class="toplist-group">
<h3>Top 5 Shows</h3>
<div class="toplist-body">
<div class="poster-grid">
<div class="poster-item">
<img src="/static/posters/foundation.jpg" alt="foundation">
<p>Foundation</p>
</div>
<div class="poster-item">
<img src="/static/posters/Chernobyl.webp" alt="Chernobyl">
<p>Chernobyl</p>
</div>
<div class="poster-item">
<img src="/static/posters/Breaking Bad.webp" alt="Breaking Bad">
<p>Breaking Bad</p>
</div>
<div class="poster-item">
<img src="/static/posters/Avatar.webp" alt="Avatar: The Last Airbender">
<p>Avatar: The Last Airbender</p>
</div>
<div class="poster-item">
<img src="/static/posters/Adolescence.webp" alt="Adolescence">
<p>Adolescence</p>
</div>
</div>
</div>
</div>
<div class="section-head">
<h2>Lunix rice</h2>
</div>
<div style="display: flex; align-items: center; gap: 1rem;">
<p class="exp-body">I love my custom Linux setup. I use Hyprland, which automatically arranges app windows
on my screen so everything stays organized without dragging things around. I also use Quickshell, which
lets me customize menus, shortcuts, and system controls to work exactly how I want.
My system is based on Arch Linux or Manjaro Linux, which are versions of Linux that give you more
control and customization than a typical computer setup. The result is a clean, fast, and super
efficient desktop thats hard to go back from.
<a class="outlink" href="https://git.samantha42.xyz/samantha/dotfiles">Git repo</a>
</p>
<img src="/static/images/rice.png" style="height: 200px; align-self: center;">
</div>
<div class="section-head">
<h2>programing</h2>
</div>
<div style="display: flex; align-items: center; gap: 1rem;">
<img src="/static/images/program.png" style="height: 350px;" alt="program">
<div>
<p class="exp-body">
Programming can be a task, but for me it's a source of joy. This is something I do as a hobby, and I
don't use AI much. It's about having fun and making a fool of yourself. It's not about how good it is,
in this case, I'd rather just listen to music and drink a cup of tea. I enjoy the struggle to debug, the
beauty in understanding why a bug is there to begin with.
</p>
<br>
<p class="exp-body">
The text editor I use most is VS Code, but I love the Neovim setup as it enables me to code on a
low-level system without a desktop environment being necessary. I do most of my coding on my own
desktop, synced with Git to other systems, like the server that hosts this website, which I have built
myself. The creation of this website is more of a fun dumb activity for me... go click on one of the
movie posters and see.
</p>
</div>
</div>
<br>
<div class="section-head">
<h2>Games</h2>
</div>
<p class="exp-body" >Game i will play in my free time to wind down.</p>
<div hx-get="/static/components/games.html" hx-trigger="load" hx-swap="outerHTML">
<span class="spinner">Loading stats…</span>
</div>
</div>
</section>
{{end}}
+72
View File
@@ -0,0 +1,72 @@
{{define "nav"}}
<div>
<p class="sidebar-label">subjects</p>
<div class="skill-list">
<div class="skill-item">opinion</div>
<div class="skill-item">due diligence</div>
<div class="skill-item">performance</div>
</div>
</div>
{{end}}
{{define "body"}}
<section id="research">
<div class="page-header">
<h2 class="page-title">Equity Research</h2>
</div>
<div class="exp-card">
<div class="exp-header">
<span class="exp-title">Story vs Fundamental value</span>
</div>
<p class="exp-body">
The truth I keep coming back to is simple: find value grounded in the fundamental numbers of a company.
<br>
My approach is rooted in fundamental analysis using SEC filings (10-K, 10-Q), earnings reports, profitability, liquidity, risk factors, and long-term business sustainability. In low-transparency situations I rely on structured cross-validation across sources.
<br>
A pattern I keep seeing is CEOs speaking just close enough to reality to generate a short-term price boost, then moving the goalposts when reality catches up. What companies state in filings and what they communicate to retail or even professional investors can be two very different stories. Guidance only needs to reach far enough into the future to say almost anything.
</p>
</div>
<br>
<div class="section-head">
<h2>Current stock analysis</h2>
</div>
<div class="exp-card link" onclick="window.open('/static/pdf/mstr.pdf', '_blank')">
<div class="exp-header">
<span class="exp-title">MSTR: Strategy<span style="color: red;"> (Sell)</span></span>
<span class="exp-tag">due diligence</span>
</div>
<p class="exp-body">
The company only owns btc by issuing debt and preferred stock offering.
<br>
The company is a ponzi scheme at its best.
</p>
</div>
<br>
<div class="exp-card link" onclick="window.open('/static/pdf/novo.pdf', '_blank')">
<div class="exp-header">
<span class="exp-title">Novo.B/NVO: Novo Nordisk A/S<span style="color: green"> (buy)</span></span>
<span class="exp-tag">due diligence</span>
</div>
<p class="exp-body">
The product sales of wieght loss drugs are highclass, pipeline is undervalued.
<br>
Pipeline and wegovy pil is not reconsiced correctly as high focus on expireation of current sold product. high pisimistic view of pipeline.
</p>
</div>
<br>
<div class="section-head">
<h2>Equity portfolio performance</h2>
</div>
<div class="exp-card">
<div hx-get="/static/components/eq.html" hx-trigger="load" hx-swap="outerHTML">
<span class="spinner">Loading chart...</span>
</div>
</div>
</section>
{{end}}
+72
View File
@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Samantha Vero Friis</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500&family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap"
rel="stylesheet" />
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<link rel="stylesheet" href="/static/output.css"/>
</head>
<body class="theme-root day " id="themeRoot">
<nav>
<a class="nav-logo" href="/#">samantha_vero_friis</a> {{if .Sub}}<a class="nav-logo sub">{{.Title}}</a> {{end}}
</nav>
<div class="shell">
<aside>
<div class="row">
<img id="day" src="/static/icons/lovesun.png" width="30px" class="hidden" onclick="makeday()" >
<img id="night" src="/static/icons/moon.png" width="30px" onclick="makenight()" >
</div>
{{if .Sub}}
<div>
<div class="sidebar-links back">
<a href="/">BACK</a>
</div>
</div>
{{end}}
{{template "nav" .}}
<div style="flex: 1;"></div>
</aside>
<main id="{{.Title}}">
{{template "body" .}}
</main>
</div>
<footer>
<div class="footer-contact">
<a href="mailto:me@samantha42.xyz">me@samantha42.xyz</a>
</div>
<div class="footer-copy">© 2026 — all rights reserved</div>
</footer>
<script>
console.log("%c👀 hi there!", "font-size:20px")
function makeday() {
themeRoot.classList.remove('night');
const day = document.getElementById('day');
const night = document.getElementById('night');
day.classList.add("hidden");
night.classList.remove("hidden");
}
function makenight() {
themeRoot.classList.add('night');
const day = document.getElementById('day');
const night = document.getElementById('night');
day.classList.remove("hidden");
night.classList.add("hidden");
}
</script>
</body>
</html>
+50
View File
@@ -0,0 +1,50 @@
<section id="automation">
<div class="page-header">
<h2 class="page-title">Technical Tools & Automation</h2>
<span class="page-sub">engineering/programing</span>
</div>
<div class="exp-grid">
<p class="exp-body">
The task here is simple: to reduce work, it's a simple investment. The choice of picking the correct
bottleneck is as important as the tool itself, as this gives it use. If it's never used, it never creates
value. The same goes for uptime, it's important that stability is almost perfect, as downtime undermines
the utility of having the tool. Remember that making and using a tool also creates debt for future
maintenance of the tool.
<br>
To adhere to this, I often choose Golang or Python as they are cheap to maintain. Golang has good
stability because it is easy to code and compile checks give early error detection. A word of caution on
AI generated tools: while they are cheap to make, the maintenance debt grows exponentially, as the code is
often poorly understood by the team and difficult to reason about over time.
</p>
<div class="exp-card" >
<div class="exp-header">
<span class="exp-title">Portfolio Engine</span>
</div>
<p class="exp-body">A lightweight portfolio and financial data backend written in Go. Tracks companies,
currencies, revenue reports, and trades across configurable time periods — replacing spreadsheets with a
proper database, REST API, and interactive shell.</p>
<span class="exp-title">Roadmap</span>
<ul style="padding: 20px;">
<li class="exp-body">Price update endpoint</li>
<li class="exp-body">Multi-currency conversion</li>
<li class="exp-body">Frontend dashboard</li>
<li class="exp-body">Shares outstanding history database table</li>
<li class="exp-body">Earnings per share (EPS) based on shares owned</li>
<li class="exp-body">First-In, First-Out (FIFO) realized gains</li>
<li class="exp-body">Dividends earned and related taxes</li>
<li class="exp-body">Total tax obligations</li>
</ul>
<a class="outlink" href="https://git.samantha42.xyz/samantha/Portfolio-Engine">Git repo</a>
</div>
<div class="exp-card">
<div class="exp-header">
<span class="exp-title">Accounting Management</span>
</div>
<p class="exp-body">
A lightweight, SQL-backed, web-based CLI system designed to track assets and liabilities. The goal is to
provide a simple, fast, and scalable financial tracking tool that can grow from personal use to more
advanced scenarios.</p>
</div>
</div>
</section>
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+11 -2
View File
@@ -60,12 +60,11 @@ body::before{
}
nav{
position:sticky;top:0;z-index:100;
display: flex;
background: var(--navback);
backdrop-filter:blur(10px);
border-bottom:1px solid var(--border);
padding:0 clamp(1rem,5vw,3rem);
display:flex;align-items:center;justify-content:space-between;
height:52px;
}
.nav-logo{
@@ -74,6 +73,8 @@ nav{
display:flex;align-items:center;gap:6px;
}
.nav-logo::before{content:'>';color:var(--green);font-weight:500;}
.nav-logo.sub::before{content:'/';color:var(--green);font-weight:500;}
.nav-links{display:flex;gap:0.2rem;align-items:center;}
.nav-links a{
font-family:var(--ff-mono);font-size:0.72rem;
@@ -125,6 +126,7 @@ aside{
display:flex;align-items:center;gap:6px;
}
.sidebar-links a::before{content:'//';color:var(--dim);font-size:0.65rem;}
.sidebar-links.back a::before{content:'<-';color:var(--dim);font-size:0.65rem;}
.sidebar-links a:hover{color:var(--text);background:var(--surface2);}
.skill-list{display:flex;flex-direction:column;gap:4px;}
.skill-item{
@@ -180,10 +182,17 @@ h1 span{color:var(--accent);}
transition:border-color 0.2s,box-shadow 0.2s;
}
.exp-card:hover{border-color:var(--border2);box-shadow:0 2px 12px rgba(0,0,0,0.06);}
.exp-header{
display:flex;align-items:baseline;justify-content:space-between;
margin-bottom:0.6rem;flex-wrap:wrap;gap:0.5rem;
}
.exp-card.link:hover{
border-color:var(--accent);
}
.exp-title{font-family:var(--ff-mono);font-size:0.9rem;font-weight:500;color:var(--text);}
.exp-tag{
font-family:var(--ff-mono);font-size:0.65rem;
+1 -1
View File
File diff suppressed because one or more lines are too long