Compare commits

..

3 commits

Author SHA1 Message Date
53ba0c815d
fix: devShell packages with sd-card tools
All checks were successful
Build and Push OCI Image / build (pull_request) Successful in 1m57s
Use inputsFrom instead of concatenating to packages list
2026-02-27 00:26:37 +01:00
9621c1b727
Merge branch 'main' into feat/20260226-photo-capture
Resolved conflicts:
- flake.nix: Combined flake-parts + sd-card + OCI image
- flake.lock: Updated to include flake-parts input
2026-02-27 00:25:53 +01:00
16e9c891a8 feat: integrate sd-card for interactive spec generation (#2)
## Summary

Integrated **sd-card** workflow for interactive specification generation:

-  Added sd-card flake input
-  Created `nix run .#dev` - starts Vite with annotation proxy
-  Updated dev shell with sd-card tools (tea, playwright, nodejs)
-  Replaced old forgejo-workflow with sd-card

## Usage

### Widget-based annotation
```bash
FORGEJO_TOKEN="your-token" nix run .#dev
```

Opens SvelteKit with ✦ widget injected on every page.

### Interactive annotation (recommended)
Ask Claude to interact with the app via Claudezilla:
```
User: "Open solidhaus"
Claude: [opens in Firefox]
User: "Click the scan barcode button"
Claude: [clicks, shows screenshot]
User: "This should open the camera"
Claude: [generates Gherkin scenario]
```

## Test Plan

- [x] Flake builds successfully
- [x] `nix run .#dev` starts dev server with proxy
- [x] Widget injects on pages
- [x] Claudezilla can open and interact with app
- [x] Dev shell includes all sd-card tools

🤖 Generated with Claude Code

Reviewed-on: toph/solidhaus#2
Co-authored-by: Christopher Mühl <toki@toph.so>
Co-committed-by: Christopher Mühl <toki@toph.so>
2026-02-26 23:07:38 +00:00

244
flake.nix
View file

@ -27,153 +27,153 @@
nodejs = nodejs; nodejs = nodejs;
}; };
in { in {
packages = { packages = {
# Build the SvelteKit app # Build the SvelteKit app
solidhaus = buildNpmPackage { solidhaus = buildNpmPackage {
pname = "solidhaus"; pname = "solidhaus";
version = "0.0.1"; version = "0.0.1";
src = ./.; src = ./.;
npmDepsHash = "sha256-d7k2YpmFt/Ba0j0SrhgoHQdhYjxHO46BliOzyecZgbY="; npmDepsHash = "sha256-d7k2YpmFt/Ba0j0SrhgoHQdhYjxHO46BliOzyecZgbY=";
buildPhase = '' buildPhase = ''
npm run build npm run build
''; '';
installPhase = '' installPhase = ''
mkdir -p $out mkdir -p $out
cp -r build/* $out/ cp -r build/* $out/
''; '';
meta = { meta = {
description = "Local-first household inventory app with barcode scanning"; description = "Local-first household inventory app with barcode scanning";
homepage = "https://git.toph.so/toph/solidhaus"; homepage = "https://git.toph.so/toph/solidhaus";
};
};
# OCI image with nginx serving the built app
solidhaus-image = pkgs.dockerTools.buildLayeredImage {
name = "registry.toph.so/solidhaus";
tag = "latest";
contents = with pkgs; [
fakeNss
nginx
];
config = {
Cmd = [
"${pkgs.nginx}/bin/nginx"
"-c"
"/etc/nginx/nginx.conf"
"-g"
"daemon off;"
];
ExposedPorts = {
"80/tcp" = {};
}; };
WorkingDir = "/usr/share/nginx/html";
}; };
extraCommands = '' # OCI image with nginx serving the built app
# Create directory structure solidhaus-image = pkgs.dockerTools.buildLayeredImage {
mkdir -p var/log/nginx name = "registry.toph.so/solidhaus";
mkdir -p var/cache/nginx tag = "latest";
mkdir -p tmp
mkdir -p etc/nginx
# Copy built app contents = with pkgs; [
mkdir -p usr/share/nginx/html fakeNss
cp -r ${config.packages.solidhaus}/* usr/share/nginx/html/ nginx
];
# Create nginx config config = {
cat > etc/nginx/nginx.conf <<'EOF' Cmd = [
user nobody nobody; "${pkgs.nginx}/bin/nginx"
worker_processes auto; "-c"
error_log /var/log/nginx/error.log warn; "/etc/nginx/nginx.conf"
pid /tmp/nginx.pid; "-g"
"daemon off;"
];
ExposedPorts = {
"80/tcp" = {};
};
WorkingDir = "/usr/share/nginx/html";
};
events { extraCommands = ''
worker_connections 1024; # Create directory structure
} mkdir -p var/log/nginx
mkdir -p var/cache/nginx
mkdir -p tmp
mkdir -p etc/nginx
http { # Copy built app
include ${pkgs.nginx}/conf/mime.types; mkdir -p usr/share/nginx/html
default_type application/octet-stream; cp -r ${config.packages.solidhaus}/* usr/share/nginx/html/
access_log /var/log/nginx/access.log; # Create nginx config
cat > etc/nginx/nginx.conf <<'EOF'
user nobody nobody;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /tmp/nginx.pid;
sendfile on; events {
keepalive_timeout 65; worker_connections 1024;
}
# Gzip compression http {
gzip on; include ${pkgs.nginx}/conf/mime.types;
gzip_vary on; default_type application/octet-stream;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss;
server { access_log /var/log/nginx/access.log;
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA fallback sendfile on;
location / { keepalive_timeout 65;
try_files $uri $uri/ /index.html;
}
# Security headers # Gzip compression
add_header X-Frame-Options "SAMEORIGIN" always; gzip on;
add_header X-Content-Type-Options "nosniff" always; gzip_vary on;
add_header X-XSS-Protection "1; mode=block" always; gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss;
# Cache static assets server {
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { listen 80;
expires 1y; server_name _;
add_header Cache-Control "public, immutable"; root /usr/share/nginx/html;
index index.html;
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
} }
} }
} EOF
EOF
'';
};
# nix run .#dev — start SvelteKit dev server with annotation proxy
dev = sd-card.lib.${system}.mkDevApp {
inherit pkgs;
devCmd = "${nodejs}/bin/npm run dev";
devPort = 5173; # Vite default port
};
default = config.packages.solidhaus;
};
apps = {
# Push image to registry
push-solidhaus-image = {
type = "app";
program = pkgs.lib.getExe (pkgs.writeShellApplication {
name = "push-solidhaus-image";
runtimeInputs = [pkgs.skopeo];
text = ''
image=$(nix build --no-link --print-out-paths .#solidhaus-image)
skopeo copy \
--insecure-policy \
"docker-archive:$image" \
"docker://registry.toph.so/solidhaus:latest"
''; '';
}); };
# nix run .#dev — start SvelteKit dev server with annotation proxy
dev = sd-card.lib.${system}.mkDevApp {
inherit pkgs;
devCmd = "${nodejs}/bin/npm run dev";
devPort = 5173; # Vite default port
};
default = config.packages.solidhaus;
};
apps = {
# Push image to registry
push-solidhaus-image = {
type = "app";
program = pkgs.lib.getExe (pkgs.writeShellApplication {
name = "push-solidhaus-image";
runtimeInputs = [pkgs.skopeo];
text = ''
image=$(nix build --no-link --print-out-paths .#solidhaus-image)
skopeo copy \
--insecure-policy \
"docker-archive:$image" \
"docker://registry.toph.so/solidhaus:latest"
'';
});
};
}; };
};
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
packages = sd-card.packages.${system}.tools # tea, jq, nodejs, playwright packages = with pkgs; [
++ (with pkgs; [ nodejs
nodejs nodePackages.npm
nodePackages.npm ];
]); inputsFrom = [sd-card.packages.${system}.tools];
}; };
}; };
}; };