docs: architecture, toolchain, resume highlights; AGENTS.md points to them
This commit is contained in:
68
docs/ARCHITECTURE.md
Normal file
68
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Where Woof — Architecture
|
||||
|
||||
How the system ties together, where everything runs, and how data flows.
|
||||
|
||||
## Systems at a glance
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
Finder scans tag ──► │ where-woof.com / www / .home.lab (public) │
|
||||
(QR / NFC → URL) │ Caddy (.35, TLS) ──► .13:3020 │
|
||||
│ GOAT frontend (Go + HTMX + Alpine + Tailwind) │
|
||||
│ systemd user service `where-woof` │
|
||||
└───────────────────┬─────────────────────────────┘
|
||||
│ same Postgres
|
||||
┌───────────────────▼─────────────────────────────┐
|
||||
Staff manage ──► │ admin.where-woof.com / www.admin (staff) │
|
||||
│ Caddy (.35, TLS) ──► .13:3031 │
|
||||
│ Laravel + Filament admin (Docker) │
|
||||
└───────────────────┬─────────────────────────────┘
|
||||
│
|
||||
┌───────────────────▼─────────────────────────────┐
|
||||
│ Postgres 16 `wherewoof-db` (.13:5434) │
|
||||
│ tables: users, tags, scans, products, orders │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Public path**: tag QR/NFC → `where-woof.com/t/<id>` → Caddy on `.35` → Go app on `.13:3020` → Postgres on `.13:5434`. Geolocation + alerts send SMS via SMSGlobal HTTP API.
|
||||
- **Admin path**: staff → `admin.where-woof.com` → Caddy → Laravel/Filament on `.13:3031` (Docker) → the **same** Postgres.
|
||||
- **Single source of truth**: one database, two apps. `db/schema.sql` is canonical (Laravel reads the existing tables via Eloquent; migration ownership moves to Laravel later).
|
||||
|
||||
## Where things run
|
||||
|
||||
| Machine | Role | Runs |
|
||||
|---|---|---|
|
||||
| **.27** (desktop) | Dev | Go frontend (`make run`, :3020), Laravel admin (Docker, :3030) — dev copies; build machine for the Go binary |
|
||||
| **.13** (server) | Production | `wherewoof-db` Postgres (Docker, :5434), frontend (systemd user service `where-woof`, :3020), Laravel admin (Docker, :3031) |
|
||||
| **.35** (caddy) | Reverse proxy | Caddy — TLS termination for all public domains |
|
||||
| Router | Public entry | Port-forwards 80/443 → .35; DNS A records → `144.6.86.11` |
|
||||
| InMotion | DNS/legacy | `where-woof.com` zone — A records → router IP (legacy site retired) |
|
||||
|
||||
## Data model (v2 + additions)
|
||||
|
||||
- `users` — owners + admins (`is_admin`), `password_hash`, `remember_token`
|
||||
- `tags` — the registry: `tag_code` (opaque AES-256-encrypted sequential IDs 0–99), status unset/active/suspended, owner, item details, `sms_enabled`, `product_id`, `order_id`
|
||||
- `scans` — every tag visit: lat/lng, `location_shared`, `scanner_phone`, `alert_sent`, `fingerprint`
|
||||
- `products` — product templates (sku, name, item type)
|
||||
- `orders` — sales: status pending/paid/lapsed/cancelled, linked to tags
|
||||
|
||||
## Key flows
|
||||
|
||||
1. **Claim**: owner registers → adds `tag_code` → must exist in registry (anti-scam) → edits details → status `active`.
|
||||
2. **Scan**: finder opens `/t/<code>` → JS geolocation + fingerprint → POST scan → recorded → alert decision (sms_enabled → fingerprint 24 h block → 10-min/250 m throttle → different-finder rule) → SMS to owner via SMSGlobal HTTP API (pooled/verified number).
|
||||
3. **Contact**: finder leaves number → stored on scan → owner SMS'd (deduped).
|
||||
4. **Admin**: manage users/tags/products/orders; assign tag → product/order; suspend; dashboard stats.
|
||||
|
||||
## Security & anti-abuse
|
||||
|
||||
- Registry-only tag codes (preset IDs; case-sensitive; no user-created codes).
|
||||
- Location-aware alert throttle (250 m / 10 min), different-finder re-alert, 24 h device fingerprint block.
|
||||
- Sessions: signed cookies (Go), Laravel sessions (admin); bcrypt passwords.
|
||||
- SMS cost protection via the above + per-tag `sms_enabled` kill-switch.
|
||||
|
||||
## Deployment
|
||||
|
||||
- Frontend: `make build` on .27 → rsync to `.13:/var/www/where-woof` → systemd restart.
|
||||
- Admin: rsync `admin/` → `.13:/home/sam/Docker/Containers/wherewoof-admin/` → `docker compose up -d` (rebuild image on schema/code change).
|
||||
- Secrets: env-only — `~/.config/where-woof.env` (.13 frontend), `admin/.env` (gitignored).
|
||||
- Docs: see `TOOLS.md` (toolchain) and `where_woof.md` (product plan + roadmap).
|
||||
25
docs/RESUME-HIGHLIGHTS.md
Normal file
25
docs/RESUME-HIGHLIGHTS.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Where Woof — Project Highlights (resume-ready)
|
||||
|
||||
A production return-item tag platform built end-to-end on a home-lab stack, from spec to live deployment.
|
||||
|
||||
## What it is
|
||||
A SaaS-style product: physical QR/NFC tags for pets/luggage; a finder scans → sees return details → the owner is alerted by SMS with the finder's location. Includes a full admin dashboard for users, tags, products and orders.
|
||||
|
||||
## What I built (the pipeline)
|
||||
1. **Spec-driven development** — OpenSpec: every feature went through proposal → design → specs (testable requirements) → tasks, validated, and tracked through the whole project.
|
||||
2. **Public web app (Go)** — "GOAT" stack: Go stdlib + HTMX + Alpine.js + Tailwind + Postgres. Auth, tag registry (anti-scam), scan flow with geolocation, location-aware SMS throttling, browser-fingerprint anti-spam, photo uploads.
|
||||
3. **Admin app (Laravel + Filament)** — CRUD for users/tags/products/orders, dashboard stats, admin auth gating — against the **same** shared Postgres.
|
||||
4. **Real SMS integration** — SMSGlobal HTTP API (verified sender), with a swappable sender abstraction and a log-mode fake for testing.
|
||||
5. **Deployment** — Go binary as a systemd service, Laravel in Docker, Caddy reverse proxy with automatic TLS, DNS migration off legacy hosting, internal DNS (Pi-hole), firewall management on NixOS.
|
||||
6. **AI-assisted engineering workflow** — used the pi coding agent with subagent delegation (database/coder/review agents), plan review tooling, memory/runbooks, and regression test suites (53 HTTP-level checks).
|
||||
|
||||
## Stack highlights
|
||||
Go 1.26 · HTMX · Alpine.js · Tailwind · PostgreSQL 16 · sqlc (type-safe SQL) · Laravel 13 · Filament v3 · Docker · NixOS · systemd · Caddy · Gitea · SMSGlobal API · OpenSpec · pi/agent tooling
|
||||
|
||||
## Things I'm proud of / learned
|
||||
- Decrypted a legacy AES-256-ECB product-ID scheme (100 encrypted sequential IDs recovered and re-seeded as a tamper-proof registry).
|
||||
- Debugged and fixed production-only issues: Filament's 403-after-login (model must implement `FilamentUser`), mixed-content asset blocking behind a reverse proxy, and a Caddy config crash from duplicate site blocks.
|
||||
- Rebuilt my own 2014-era product design (its comments anticipated distance throttling and fingerprint anti-spam) with modern tooling.
|
||||
|
||||
## Where it runs
|
||||
Live on `where-woof.com` and `admin.where-woof.com` — home-lab infra: desktop (.27, dev) → server (.13, prod) → Caddy box (.35), one shared Postgres.
|
||||
67
docs/TOOLS.md
Normal file
67
docs/TOOLS.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Where Woof — Toolchain
|
||||
|
||||
Everything used to build and run the project, with where it fits.
|
||||
|
||||
## Product stack (public site — "GOAT")
|
||||
|
||||
| Tool | Version | Used for |
|
||||
|---|---|---|
|
||||
| Go | 1.26 | Frontend: stdlib `net/http` (no framework), `html/template`, Go 1.22+ ServeMux routing |
|
||||
| HTMX | 1.9.12 | Inline editing, account panel swaps, contact forms (no page reloads) |
|
||||
| Alpine.js | 3.x | Live phone validation, small client behaviours |
|
||||
| Tailwind CSS | CDN | Utility-first styling (swap to a build step in Phase 3 polish later) |
|
||||
| Postgres | 16 | Single shared database (`wherewoof-db` on .13) |
|
||||
| pgx | v5 | Postgres driver + pool for Go |
|
||||
| sqlc | 1.31.1 | Type-safe query generation from SQL (compiled-checked queries) |
|
||||
| gorilla/sessions | — | Signed cookie sessions |
|
||||
| bcrypt | — | Password hashing |
|
||||
|
||||
## Admin stack
|
||||
|
||||
| Tool | Version | Used for |
|
||||
|---|---|---|
|
||||
| Laravel | 13 (PHP 8.3) | Admin backend; Eloquent reads the shared Postgres schema |
|
||||
| Filament | v3 | Admin panel UI: CRUD resources (User/Tag/Product/Order), dashboard widgets |
|
||||
| Livewire | (Filament dep) | Reactive admin pages |
|
||||
| Docker | — | Laravel dev (.27:3030) + prod (.13:3031); Postgres container |
|
||||
|
||||
## Infrastructure & deployment
|
||||
|
||||
| Tool | Role |
|
||||
|---|---|
|
||||
| NixOS | .27/.13/.51 hosts; systemd user services; firewall via config |
|
||||
| systemd | `where-woof.service` (frontend, auto-restart, linger) |
|
||||
| Docker Compose | Postgres, admin, other services |
|
||||
| Caddy | Reverse proxy + TLS on .35 (public domains) |
|
||||
| Pi-hole | Local DNS (`.home.lab` domains) |
|
||||
| rsync | Deploy artifacts to .13 |
|
||||
| Gitea | Git hosting (`sam/where_woof`) |
|
||||
|
||||
## SMS
|
||||
|
||||
| Tool | Role |
|
||||
|---|---|
|
||||
| SMSGlobal HTTP API | Live SMS (`api.smsglobal.com/http-api.php`, action=sendsms) — verified number as sender |
|
||||
| `internal/sms` (Go) | Swappable `Sender` interface: `LogSender` (dev), `HTTPClient` (live), `smsglobal` REST client (unused fallback) |
|
||||
|
||||
## Development workflow
|
||||
|
||||
| Tool | Role |
|
||||
|---|---|
|
||||
| OpenSpec | Spec-driven development: `openspec/changes/*` (proposal → design → specs → tasks), validated |
|
||||
| plannotator | Plan review (browser UI) for the first two phases |
|
||||
| pi subagents | Master/worker delegation: `database`, `coder-pro`, `code-analysis`, `devops` |
|
||||
| Makefile | `db-up`, `seed`, `seed-registry`, `run`, `build`, `generate`, `psql` |
|
||||
| Verify suites | `/tmp/verify.sh` (22 checks), `verify2.sh` (19), `verify3.sh` (12) — HTTP-level regression tests |
|
||||
|
||||
## Security tooling (guards package installs)
|
||||
|
||||
SafeDep Vet (`vet`), npq (typosquatting), Socket Firewall (`socket`) — the npm-security skill wraps installs.
|
||||
|
||||
## Notes / gotchas (hard-won)
|
||||
|
||||
- Filament v3: production 403 unless the User model implements `FilamentUser`.
|
||||
- Behind Caddy, force `URL::forceScheme('https')` to avoid mixed-content asset blocks.
|
||||
- sqlc: nullable columns → `pgtype.*`; explicit INSERT column lists must include new columns.
|
||||
- NixOS: `CGO_ENABLED=0` for Go builds (no gcc); `make` via nix profile; `psql` via `docker exec`.
|
||||
- Admin files created by Docker are root-owned — edit via `docker cp`.
|
||||
Reference in New Issue
Block a user