Initial monorepo scaffold

Turborepo + pnpm monorepo for k3s homelab cluster on Intel NUCs.

- Apps: Next.js web frontend, Express API (TypeScript, Dockerfiles, k8s manifests)
- Packages: shared UI, ESLint config, TypeScript config, Drizzle DB schemas
- Infra/Ansible: bare-metal provisioning with roles for common, k3s-server, k3s-agent, hardening
- Infra/Kubernetes: ArgoCD GitOps (app-of-apps + ApplicationSets), platform components
  (cert-manager, Traefik, CloudNativePG, Valkey, Longhorn, Sealed Secrets), namespaces
- Observability: kube-prometheus-stack, Loki, Promtail as ArgoCD Applications
- CI/CD: GitHub Actions for PR builds, preview deploys, production deploys
- DX: Taskfile, utility scripts, copier templates, Ubiquiti network docs
This commit is contained in:
Julia McGhee
2026-03-19 22:24:56 +00:00
commit 96e3f32f28
118 changed files with 2681 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
module.exports = {
extends: ["next/core-web-vitals", "prettier"],
rules: {
"no-console": "warn",
},
};

View File

@@ -0,0 +1,10 @@
{
"name": "@homelab/config-eslint",
"version": "0.1.0",
"private": true,
"main": "./index.js",
"dependencies": {
"eslint-config-next": "^15.1.0",
"eslint-config-prettier": "^9.1.0"
}
}

View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"declaration": true,
"declarationMap": true
},
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,14 @@
{
"extends": "./base.json",
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"noEmit": true,
"module": "esnext",
"moduleResolution": "bundler",
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }]
}
}

View File

@@ -0,0 +1,10 @@
{
"extends": "./base.json",
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"sourceMap": true
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "@homelab/config-typescript",
"version": "0.1.0",
"private": true,
"files": ["base.json", "nextjs.json", "node.json"]
}

View File

@@ -0,0 +1,10 @@
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/schema.ts",
out: "./drizzle",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});

22
packages/db/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "@homelab/db",
"version": "0.1.0",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"lint": "tsc --noEmit",
"build": "tsc",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"drizzle-orm": "^0.36.0",
"postgres": "^3.4.0"
},
"devDependencies": {
"drizzle-kit": "^0.28.0",
"typescript": "^5.7.0"
}
}

View File

@@ -0,0 +1,8 @@
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as schema from "./schema";
const connectionString = process.env.DATABASE_URL!;
const client = postgres(connectionString);
export const db = drizzle(client, { schema });

2
packages/db/src/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from "./schema";
export * from "./client";

View File

@@ -0,0 +1,9 @@
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
email: text("email").notNull().unique(),
name: text("name"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});

14
packages/db/tsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

18
packages/ui/package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "@homelab/ui",
"version": "0.1.0",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"lint": "tsc --noEmit",
"build": "tsc"
},
"devDependencies": {
"typescript": "^5.7.0",
"@types/react": "^19.0.0"
},
"peerDependencies": {
"react": "^19.0.0"
}
}

View File

@@ -0,0 +1,13 @@
import React from "react";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary";
}
export function Button({ variant = "primary", children, ...props }: ButtonProps) {
return (
<button data-variant={variant} {...props}>
{children}
</button>
);
}

1
packages/ui/src/index.ts Normal file
View File

@@ -0,0 +1 @@
export { Button } from "./button";

17
packages/ui/tsconfig.json Normal file
View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"jsx": "react-jsx",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}