Skip to content

Commit 17568be

Browse files
committed
wip: alpha
1 parent bba2308 commit 17568be

100 files changed

Lines changed: 2902 additions & 3734 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.envrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
export DIRENV_WARN_TIMEOUT=20s
44
export NIX_CONFIG='pure-eval = false'
55

6+
echo "$PWD" > .stackpanel-root
7+
68
# Use flake-based devenv (via nix develop)
79
# This dogfoods our own flake-parts + devenv integration
810
use flake . --no-pure-eval --impure

.github/workflows/devenv-cache.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
with:
4242
extra_nix_config: |
4343
accept-flake-config = true
44-
extra-substituters = https://devenv.cachix.org https://stackpanel.cachix.org
44+
extra-substituters = https://devenv.cachix.org https://darkmatter.cachix.org
4545
extra-trusted-public-keys = devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw= darkmatter.cachix.org-1:FM0VM+D2fvMt8R899nyKsAxkcwERzDVYaeJEZ9oKejQ=
4646
4747
- name: Setup Cachix

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ build
1313
.env*.local
1414

1515
# IDEs and editors
16-
.vscode/*
1716
!.vscode/settings.json
1817
!.vscode/tasks.json
1918
!.vscode/launch.json
@@ -98,3 +97,6 @@ devenv.local.yaml
9897
/bts.jsonc
9998

10099
/result
100+
101+
# Stackpanel root marker (machine-specific)
102+
.stackpanel-root

.ruler/todo.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
## Nix refactor plan: shared core + thin adapters
2+
3+
### Goal
4+
- **Same functionality** in both entrypoints:
5+
- `nix develop --impure --no-eval-cache`
6+
- `devenv shell`
7+
- Make it **obvious** what is:
8+
- **core logic** (reusable)
9+
- **module adapter** (options + wiring)
10+
- Remove duplication between `nix/modules/*` and `nix/lib/*`.
11+
12+
### Target layout (north star)
13+
- **`nix/lib/core/`**: shared behavior (pure-ish functions returning `{ packages, env, shellHook/enterShell, files?, warnings? }`)
14+
- **`nix/modules/*`**: thin adapters that:
15+
- define options
16+
- map `config.stackpanel.*``nix/lib/core/*`
17+
- merge returned attrs into devenv/Nix module outputs
18+
- **Entrypoints**
19+
- `nix/stackpanel.nix`: devenv module aggregator
20+
- `nix/modules/devenv/devenv.nix`: devenv directory import entrypoint (obvious import path)
21+
- `nix/modules/devenv.nix`: compatibility shim (only if needed)
22+
- `flake.nix`: exports `flake.lib.*`, `flake.devenvModules.*` (and any module paths)
23+
24+
### Principles
25+
- **Single source of truth**: implement behavior once (core), call it from both adapters.
26+
- **Adapters stay tiny**: avoid duplicating computation in modules.
27+
- **Purity by default**: impure reads must be explicit and optional.
28+
- **Compatibility**: prefer shims/deprecations over breaking moves.
29+
30+
---
31+
32+
## Todo list
33+
34+
### Completed (already done)
35+
- [x] Create shared core for global services: `nix/lib/core/global-services.nix`
36+
- [x] Refactor `nix/lib/devshell.nix` to use shared core
37+
- [x] Refactor `nix/modules/global-services.nix` to use shared core
38+
- [x] Add obvious devenv import path: `nix/modules/devenv/devenv.nix`
39+
- [x] Add compatibility shim: `nix/modules/devenv.nix`
40+
- [x] Eval sanity checks:
41+
- [x] `nix eval '.#devenvModules.default'`
42+
- [x] `nix eval '.#lib'`
43+
- [x] `nix eval '.#nixosModules.default'`
44+
45+
### Next (core parity module-by-module) - COMPLETED
46+
- [x] **Ports**: moved deterministic port computation into `nix/lib/core/ports.nix`; `nix/modules/ports.nix` now uses shared core.
47+
- [x] **Caddy**: module already uses `nix/lib/caddy.nix` as the single source of truth; no duplicated behavior.
48+
- [x] **Network / Step CA**: module already uses `nix/lib/network.nix` as the single source of truth.
49+
- [x] **AWS**: module already uses `nix/lib/aws.nix` as the single source of truth.
50+
- [x] **Theme / starship**: module already uses `nix/lib/theme.nix` as the single source of truth.
51+
- [x] **IDE integration**:
52+
- [x] Already separates "pure generation" vs "impure merge existing settings" as explicit options (`existing-settings-path`)
53+
- [x] Module only wires + writes files; `nix/lib/integrations/ide.nix` generates content
54+
55+
### Optional (high-leverage)
56+
- [ ] Centralize shared option types/defaults in `nix/lib/modules/options.nix` (or `nix/modules/options/`) so both adapters share one schema.
57+
- [ ] Update docs to recommend `stackpanel/nix/modules/devenv` import path everywhere.
58+
59+
---
60+
61+
## Summary of Changes (2024-12-23)
62+
63+
### Files Created
64+
- `nix/lib/core/ports.nix`: Pure port computation library with functions:
65+
- `computeBasePort`: Deterministic port from project name
66+
- `computeServicePort`: Port for a service by index
67+
- `computeServicesWithPorts`: Compute ports for a list of services
68+
- `mkServicesByKey`: Create lookup attrset by service key
69+
- `mkServiceEnvVars`: Generate environment variables for services
70+
- `mkPortsConfig`: Convenience function for full port configuration
71+
72+
### Files Modified
73+
- `nix/modules/ports.nix`: Now imports and uses `nix/lib/core/ports.nix` for all computation
74+
- `nix/lib/default.nix`: Added `ports` export for port computation utilities
75+
- `nix/lib/devshell.nix`: Added `ports` export for mkShell users
76+
77+
### Architecture
78+
The codebase now follows a consistent pattern where:
79+
1. **Core libraries** (`nix/lib/core/*.nix`, `nix/lib/*.nix`): Pure functions that implement behavior
80+
2. **Modules** (`nix/modules/*.nix`): Thin adapters that define options and call core libraries

.rules

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
1-
# Ultracite Code Standards
2-
3-
This project uses **Ultracite**, a zero-config Biome preset that enforces strict code quality standards through automated formatting and linting.
4-
5-
## Quick Reference
6-
7-
- **Format code**: `npx ultracite fix`
8-
- **Check for issues**: `npx ultracite check`
9-
- **Diagnose setup**: `npx ultracite doctor`
10-
11-
Biome (the underlying engine) provides extremely fast Rust-based linting and formatting. Most issues are automatically fixable.
12-
13-
---
14-
151
## Core Principles
162

173
Write code that is **accessible, performant, type-safe, and maintainable**. Focus on clarity and explicit intent over brevity.
@@ -107,17 +93,4 @@ Write code that is **accessible, performant, type-safe, and maintainable**. Focu
10793
- Don't use `.only` or `.skip` in committed code
10894
- Keep test suites reasonably flat - avoid excessive `describe` nesting
10995

110-
## When Biome Can't Help
111-
112-
Biome's linter will catch most issues automatically. Focus your attention on:
113-
114-
1. **Business logic correctness** - Biome can't validate your algorithms
115-
2. **Meaningful naming** - Use descriptive names for functions, variables, and types
116-
3. **Architecture decisions** - Component structure, data flow, and API design
117-
4. **Edge cases** - Handle boundary conditions and error states
118-
5. **User experience** - Accessibility, performance, and usability considerations
119-
6. **Documentation** - Add comments for complex logic, but prefer self-documenting code
120-
12196
---
122-
123-
Most formatting and common issues are automatically fixed by Biome. Run `npx ultracite fix` before committing to ensure compliance.
Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,33 @@
1-
"{\"$id\":\"https://stackpanel.dev/schemas/secrets/app-config.json\",\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"additionalProperties\":false,\"description\":\"Per-app configuration for codegen and settings\",\"examples\":[{\"codegen\":{\"language\":\"typescript\",\"path\":\"packages/api/src/env.ts\"}}],\"properties\":{\"codegen\":{\"additionalProperties\":false,\"description\":\"Code generation settings for typed env access\",\"properties\":{\"language\":{\"description\":\"Target language for generated code (null to disable)\",\"enum\":[\"typescript\",\"python\",\"go\",null],\"type\":[\"string\",\"null\"]},\"path\":{\"description\":\"Output path for generated code (relative to repo root)\",\"examples\":[\"packages/api/src/env.ts\",\"apps/server/env.py\",\"internal/env/env.go\"],\"type\":\"string\"}},\"required\":[\"language\",\"path\"],\"type\":\"object\"}},\"title\":\"Stackpanel App Secrets Config\",\"type\":\"object\"}"
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"additionalProperties": false,
4+
"description": "Per-app secrets and codegen config (.stackpanel/secrets/apps/*/config.yaml)",
5+
"properties": {
6+
"codegen": {
7+
"additionalProperties": false,
8+
"description": "Code generation settings for type-safe env access",
9+
"properties": {
10+
"language": {
11+
"description": "Target language for generated code",
12+
"enum": [
13+
"typescript",
14+
"python",
15+
"go"
16+
],
17+
"type": "string"
18+
},
19+
"path": {
20+
"description": "Output path relative to project root (e.g., packages/api/src/env.ts)",
21+
"type": "string"
22+
}
23+
},
24+
"required": [
25+
"language",
26+
"path"
27+
],
28+
"type": "object"
29+
}
30+
},
31+
"title": "App Secrets Configuration",
32+
"type": "object"
33+
}
Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,30 @@
1-
"{\"$id\":\"https://stackpanel.dev/schemas/secrets/config.json\",\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"additionalProperties\":false,\"description\":\"Global configuration for the stackpanel secrets module\",\"properties\":{\"backend\":{\"default\":\"vals\",\"description\":\"Backend for secret resolution.\\n- vals: Multi-backend resolver (SOPS, AWS, 1Password, Vault, Doppler)\\n- sops: Direct SOPS usage only\",\"enum\":[\"vals\",\"sops\"],\"type\":\"string\"},\"defaultEnvironments\":{\"default\":[\"dev\",\"staging\",\"prod\"],\"description\":\"Default environments for all apps\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"generatePlaceholders\":{\"default\":true,\"description\":\"Generate placeholder .yaml files for each app/environment\",\"type\":\"boolean\"},\"secretsDir\":{\"default\":\"secrets\",\"description\":\"Directory for encrypted secrets files (relative to repo root)\",\"type\":\"string\"}},\"title\":\"Stackpanel Secrets Config\",\"type\":\"object\"}"
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"additionalProperties": false,
4+
"description": "Global secrets configuration (.stackpanel/secrets/config.yaml)",
5+
"properties": {
6+
"backend": {
7+
"default": "sops",
8+
"description": "Secrets backend to use (sops or vals)",
9+
"enum": [
10+
"sops",
11+
"vals"
12+
],
13+
"type": "string"
14+
},
15+
"default-environments": {
16+
"default": [
17+
"dev",
18+
"staging",
19+
"prod"
20+
],
21+
"description": "Default environments created for new apps",
22+
"items": {
23+
"type": "string"
24+
},
25+
"type": "array"
26+
}
27+
},
28+
"title": "Stackpanel Secrets Configuration",
29+
"type": "object"
30+
}
Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,38 @@
1-
"{\"$id\":\"https://stackpanel.dev/schemas/secrets/env.json\",\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"additionalProperties\":false,\"definitions\":{\"SecretEntry\":{\"additionalProperties\":false,\"properties\":{\"default\":{\"description\":\"Default value (only for non-required secrets)\",\"type\":\"string\"},\"description\":{\"description\":\"Description of what this secret is for\",\"type\":\"string\"},\"required\":{\"default\":true,\"description\":\"Whether this secret is required\",\"type\":\"boolean\"},\"sensitive\":{\"default\":true,\"description\":\"Whether this secret is sensitive (masked in logs)\",\"type\":\"boolean\"}},\"type\":\"object\"}},\"description\":\"Per-environment configuration (dev.yaml, staging.yaml, prod.yaml)\",\"examples\":[{\"extraKeys\":[],\"schema\":{\"DEBUG\":{\"required\":false,\"sensitive\":false},\"LOG_LEVEL\":{\"default\":\"debug\"}},\"users\":[\"alice\",\"bob\",\"charlie\"]},{\"extraKeys\":[\"age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p\"],\"schema\":{\"SENTRY_DSN\":{\"required\":true,\"sensitive\":true}},\"users\":[\"alice\"]}],\"properties\":{\"extraKeys\":{\"description\":\"Additional AGE keys for CI systems, servers, etc.\",\"items\":{\"pattern\":\"^age1[a-z0-9]{58}$\",\"type\":\"string\"},\"type\":\"array\"},\"schema\":{\"additionalProperties\":{\"$ref\":\"#/definitions/SecretEntry\"},\"description\":\"Environment-specific schema additions/overrides\",\"type\":\"object\"},\"users\":{\"description\":\"User names (from users.yaml) who can access this environment's secrets\",\"items\":{\"type\":\"string\"},\"type\":\"array\"}},\"title\":\"Stackpanel Environment Config\",\"type\":\"object\"}"
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"additionalProperties": false,
4+
"description": "Environment-specific secrets (.stackpanel/secrets/apps/*/{dev,staging,prod}.yaml)",
5+
"properties": {
6+
"schema": {
7+
"additionalProperties": {
8+
"additionalProperties": false,
9+
"properties": {
10+
"default": {
11+
"type": "string"
12+
},
13+
"description": {
14+
"type": "string"
15+
},
16+
"required": {
17+
"type": "boolean"
18+
},
19+
"sensitive": {
20+
"type": "boolean"
21+
}
22+
},
23+
"type": "object"
24+
},
25+
"description": "Environment-specific schema overrides (merged with common.yaml)",
26+
"type": "object"
27+
},
28+
"users": {
29+
"description": "Usernames (from users.yaml) who can access this environment",
30+
"items": {
31+
"type": "string"
32+
},
33+
"type": "array"
34+
}
35+
},
36+
"title": "Environment Secrets",
37+
"type": "object"
38+
}
Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,31 @@
1-
"{\"$id\":\"https://stackpanel.dev/schemas/secrets/schema.json\",\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"additionalProperties\":{\"$ref\":\"#/definitions/SecretEntry\"},\"definitions\":{\"SecretEntry\":{\"additionalProperties\":false,\"properties\":{\"default\":{\"description\":\"Default value (only for non-required secrets)\",\"type\":\"string\"},\"description\":{\"description\":\"Description of what this secret is for\",\"type\":\"string\"},\"required\":{\"default\":true,\"description\":\"Whether this secret is required\",\"type\":\"boolean\"},\"sensitive\":{\"default\":true,\"description\":\"Whether this secret is sensitive (masked in logs)\",\"type\":\"boolean\"}},\"type\":\"object\"}},\"description\":\"Schema for secrets entries (common.yaml)\",\"examples\":[{\"DATABASE_URL\":{\"description\":\"PostgreSQL connection string\",\"required\":true,\"sensitive\":true},\"LOG_LEVEL\":{\"default\":\"info\",\"required\":false,\"sensitive\":false}}],\"title\":\"Stackpanel Secrets Schema\",\"type\":\"object\"}"
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"additionalProperties": {
4+
"additionalProperties": false,
5+
"description": "Secret variable definition",
6+
"properties": {
7+
"default": {
8+
"description": "Default value (only for non-sensitive secrets)",
9+
"type": "string"
10+
},
11+
"description": {
12+
"description": "Human-readable description of this secret",
13+
"type": "string"
14+
},
15+
"required": {
16+
"default": false,
17+
"description": "Whether this secret must be set",
18+
"type": "boolean"
19+
},
20+
"sensitive": {
21+
"default": true,
22+
"description": "Whether to mask value in logs and output",
23+
"type": "boolean"
24+
}
25+
},
26+
"type": "object"
27+
},
28+
"description": "Schema for secret variables (.stackpanel/secrets/apps/*/common.yaml)",
29+
"title": "Secret Schema",
30+
"type": "object"
31+
}
Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,29 @@
1-
"{\"$id\":\"https://stackpanel.dev/schemas/secrets/users.json\",\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"additionalProperties\":{\"$ref\":\"#/definitions/User\"},\"definitions\":{\"User\":{\"additionalProperties\":false,\"properties\":{\"admin\":{\"default\":false,\"description\":\"Admins can decrypt all secrets across all environments\",\"type\":\"boolean\"},\"github\":{\"description\":\"GitHub username (for display/lookup)\",\"type\":\"string\"},\"pubkey\":{\"description\":\"AGE public key (starts with age1...)\",\"pattern\":\"^age1[a-z0-9]{58}$\",\"type\":\"string\"}},\"required\":[\"pubkey\"],\"type\":\"object\"}},\"description\":\"Team members and their AGE public keys for secrets access\",\"examples\":[{\"alice\":{\"admin\":true,\"github\":\"alice\",\"pubkey\":\"age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p\"},\"bob\":{\"github\":\"bobdev\",\"pubkey\":\"age1tpqft77pxl5qm7d7u0j5gsyvxzrxdg4krqjr3uvps7y0vfsueyeqg5ztsa\"}}],\"title\":\"Stackpanel Secrets Users\",\"type\":\"object\"}"
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"additionalProperties": {
4+
"additionalProperties": false,
5+
"properties": {
6+
"admin": {
7+
"default": false,
8+
"description": "Admins can decrypt secrets for all environments",
9+
"type": "boolean"
10+
},
11+
"github": {
12+
"description": "GitHub username (for key lookup)",
13+
"type": "string"
14+
},
15+
"pubkey": {
16+
"description": "AGE public key (starts with age1...)",
17+
"pattern": "^age1[a-z0-9]{58}$",
18+
"type": "string"
19+
}
20+
},
21+
"required": [
22+
"pubkey"
23+
],
24+
"type": "object"
25+
},
26+
"description": "Team members with access to secrets (.stackpanel/secrets/users.yaml)",
27+
"title": "Stackpanel Users",
28+
"type": "object"
29+
}

0 commit comments

Comments
 (0)