https://github.com/michaelasper/headstash
https://github.com/michaelasper/headstash
Last synced: about 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/michaelasper/headstash
- Owner: michaelasper
- Created: 2026-02-02T04:03:15.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-02-14T09:07:18.000Z (4 months ago)
- Last Synced: 2026-02-14T14:01:54.914Z (4 months ago)
- Language: TypeScript
- Size: 333 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Headstash
Mobile-friendly web app for logging cannabis strain reviews.
## Prereqs
## UI foundations
- See `docs/design.md` for semantic tokens + focus ring + typography/spacing guidance.
- See `docs/prisma-migration-hardening.md` for migration safety and deploy rollback checklist.
- See `docs/deployment-runbook.md` for deploy prerequisites, secret metadata requirements, and CI gate flow.
- See `docs/e2e-playbook.md` for E2E architecture, local debugging commands, CI behavior, flaky-test triage, and ownership/update process.
- See `docs/frontend-qa-visual-regression-checklist.md` for pre-merge UI regression checks across breakpoints, states, and interaction patterns.
- Node.js 20+
- npm
## Setup
```bash
# install deps
npm ci
# set env vars
cp .env.example .env
# create/apply local sqlite migration
make db-migrate
# seed deterministic local demo data
make db-seed
# run the dev server
make dev
```
## Runtime commands
Use these commands locally so dev/CI/prod workflows stay aligned:
```bash
make help
make dev
make lint
make typecheck
make build
make sanity
make db-generate
make db-migrate
make db-deploy
make db-reset
make db-seed
make db-reset-seed
```
### E2E quickstart
```bash
npm run e2e:install
npm run e2e:test -- --list
npm run e2e:test -- --grep "home page renders key navigation"
npm run e2e:test -- --project=chromium e2e/tests/critical/critical-path.spec.ts
npm run e2e:test:headed
```
For full triage/debug guidance, see `docs/e2e-playbook.md`.
### Deploy bootstrap helper scripts
Use these scripts to wire AWS + GitHub deployment prerequisites from machine-readable artifacts:
```bash
# 1) Create/verify AWS backend + OIDC + deploy role metadata artifact
npm run aws:bootstrap -- --plan --json
npm run aws:bootstrap -- --apply --repo --profile
# 2) Configure GitHub staging/production environments from aws artifact
npm run github:bootstrap -- --plan --json
npm run github:bootstrap -- --apply --artifact artifacts/aws-bootstrap.json
```
- `aws:bootstrap` writes `artifacts/aws-bootstrap.json` (backend + OIDC + role metadata contract).
- `github:bootstrap` consumes that artifact, upserts GitHub environments, sets env vars/secrets, and writes a redacted verification artifact.
- Both support `--plan` (default) and `--apply`; `--json` prints machine-readable output for CI logs.
### Staging DNS + health readiness automation
Use this script to verify rollback-drill readiness (DNS + TLS + health endpoint), with optional Route53 UPSERT support and Namecheap handoff guidance:
```bash
npm run staging:readiness -- --host=staging.headstash.app --health-path=/api/health
npm run staging:readiness -- --json
# Route53 apply aliases (both forms supported)
npm run staging:readiness -- --apply --aws-zone-id= --aws-target=
npm run staging:readiness -- --apply-route53 --route53-zone-id= --route53-record-name=staging.headstash.app --route53-record-value=
# Namecheap -> Route53 nameserver handoff helper
npm run staging:readiness -- --namecheap-guide --route53-zone-id= --namecheap-domain=headstash.app --json
```
- `staging:readiness` checks DNS resolution, TLS certificate validity, and health endpoint status.
- `--apply` / `--apply-route53` performs Route53 UPSERT before validation (AWS CLI required).
- `--namecheap-guide` fetches Route53 nameservers and prints the exact Namecheap handoff checklist.
- Use `--json` for CI/log-friendly machine output.
- Full operator steps: `docs/namecheap-to-route53-staging-runbook.md`.
### Local observability toggles
Use these optional env vars in `.env` for local diagnostics:
- `PRISMA_SLOW_QUERY_THRESHOLD_MS` (default `100`)
- `PRISMA_LOG_FORMAT` (`text` or `json`)
- `PRISMA_LOG_INCLUDE_QUERY` (`1` to include SQL + params in logs)
### GitHub OAuth setup (optional)
1) Create a GitHub OAuth App
- Callback URL: `http://localhost:3000/api/auth/callback/github`
2) Set env vars:
- `GITHUB_CLIENT_ID`
- `GITHUB_CLIENT_SECRET`
### Email + password setup (optional)
No extra env vars required.
- Use the **Email + password** section on `/auth/signin`.
- Passwords are hashed with bcrypt.
- Rate limiting is in-memory (dev-only) and resets on server restart.
### Local auth parity mode
Set `AUTH_LOCAL_MODE="credentials-only"` in `.env` to run a local auth mode that mirrors production-style protected-route behavior with credentials sessions only (disables GitHub + magic link on sign-in UI).
### Profile MVP
- Edit profile at `/profile` (requires sign-in)
- Public profile: `/u/[handle]` (no auth required)
- Fields: `displayName`, `handle` (unique, @format), `bio`, `avatarUrl`, `links` (URLs)
Handle rules:
- Stored in canonical form: lowercase, always prefixed with `@`
- Allowed chars: `a-z`, `0-9`, `_`
- Length: 3–20 characters (including `@`)
- Reserved handles are blocked (e.g. `@admin`, `@auth`, `@api`, `@posts`, `@u`, ...)
### Posts v0
- Global feed: `/posts` (public)
- Following feed: `/posts/following` (requires sign-in)
- Creating a post requires sign-in
- Posts can optionally attach a review (v0)
### Search v0
- Search users and posts at `/search`
- Simple substring matching (SQLite, no full-text search)
### Onboarding v0
- Signed-in users without a handle are prompted from `/me` to complete onboarding at `/onboarding`.
### Follow v0
- Follow/unfollow from public profiles: `/u/[handle]`
- Shows follower/following counts
### Reactions v0
- Like posts on `/posts` (auth required to like)
- Shows like count + current user state
### Favorites v0
- Favorite posts on `/posts` and `/posts/[id]` (auth required)
- View your favorites at `/me/favorites`
### Notifications v0
- In-app notifications at `/notifications` (auth required)
- Events: follow, like your post, comment on your post
### Comments v0
- Post detail page: `/posts/[id]`
- Commenting requires sign-in
### Avatar upload (dev-local only)
DEV ONLY: uploading an avatar writes into `public/uploads/avatars/` and sets `avatarUrl` to a local path.
- This is not suitable for serverless/production.
- Uploaded files are gitignored.
Open http://localhost:3000
## Verify
```bash
make sanity
# optionally, for full production-bundle verification when env is configured:
make build
```
## Prisma Studio (optional)
```bash
npx prisma studio
```
## Environment
Runtime env is validated at startup. Invalid/incomplete configuration fails fast with a clear error.
Required in **all** environments:
- `DATABASE_URL`
Required in **production**:
- `AUTH_SECRET` (or `NEXTAUTH_SECRET`)
- `AUTH_URL` (or `NEXTAUTH_URL`)
Development/test defaults:
- `AUTH_SECRET` / `NEXTAUTH_SECRET` default to a local dev secret if omitted
- `AUTH_URL` / `NEXTAUTH_URL` default to `http://localhost:3000` if omitted
Optional integrations:
- GitHub OAuth: `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` (must be set together)
- SMTP magic links: `EMAIL_SERVER_HOST`, `EMAIL_SERVER_PORT`, `EMAIL_SERVER_USER`, `EMAIL_SERVER_PASSWORD`, `EMAIL_FROM` (all-or-none)
- Local parity mode: `AUTH_LOCAL_MODE=full|credentials-only`
- Prisma slow query logging threshold: `PRISMA_SLOW_QUERY_THRESHOLD_MS` (default `100`)
See `.env.example` for complete values and comments.
## Validation / constraints
Request-boundary validation lives in `src/app/actions.ts` (Server Actions) and is intentionally kept small:
- `Review.rating` must be one of Prisma enum `ReviewRating` (`ONE`–`FIVE`).
- `Review.strainId` must be a `cuid()`.
- `Review.consumedAt` is optional; when provided it must parse as a valid date.
- `Review` can optionally be tagged with 1 Effect tag + 1 Terpene tag (v1).
## Tags (effects / terpenes)
Headstash supports two kinds of tags for filtering reviews:
- **Effects** (e.g., Relaxed, Uplifted)
- **Terpenes** (e.g., Limonene, Myrcene)
Create tags at `/tags` (or `/tags/new`), then select them when creating a review.
Filtering:
- Use the `/reviews` page search box for strain name (and notes).
- Use the Effect/Terpene dropdown filters to narrow results.
TODO (when we add fields/endpoints):
- If we start accepting `Strain.thcPct` / `Strain.cbdPct`, validate 0–100.