{"id":50664797,"url":"https://github.com/ghwmelite-dotcom/skipper-detergents","last_synced_at":"2026-06-08T05:03:59.185Z","repository":{"id":352911792,"uuid":"1217165900","full_name":"ghwmelite-dotcom/skipper-detergents","owner":"ghwmelite-dotcom","description":"Edge-native e-commerce platform for Skipper Detergents — a Ghanaian household-essentials brand. Storefront + admin CMS + API on Cloudflare Workers / D1 / R2 / KV, with bulk pricing, Paystack \u0026 manual-transfer checkout, and a strict TypeScript monorepo.","archived":false,"fork":false,"pushed_at":"2026-05-13T19:27:19.000Z","size":857,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T21:28:11.030Z","etag":null,"topics":["cloudflare-d1","cloudflare-kv","cloudflare-r2","cloudflare-workers","ecommerce","edge-computing","ghana","hono","monorepo","paystack","pnpm-workspaces","serverless","sqlite","turborepo","typescript","zod"],"latest_commit_sha":null,"homepage":"https://skipper-api.ghwmelite.workers.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ghwmelite-dotcom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T15:58:35.000Z","updated_at":"2026-05-13T19:27:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ghwmelite-dotcom/skipper-detergents","commit_stats":null,"previous_names":["ghwmelite-dotcom/skipper-detergents"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ghwmelite-dotcom/skipper-detergents","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghwmelite-dotcom%2Fskipper-detergents","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghwmelite-dotcom%2Fskipper-detergents/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghwmelite-dotcom%2Fskipper-detergents/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghwmelite-dotcom%2Fskipper-detergents/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ghwmelite-dotcom","download_url":"https://codeload.github.com/ghwmelite-dotcom/skipper-detergents/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghwmelite-dotcom%2Fskipper-detergents/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34048707,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare-d1","cloudflare-kv","cloudflare-r2","cloudflare-workers","ecommerce","edge-computing","ghana","hono","monorepo","paystack","pnpm-workspaces","serverless","sqlite","turborepo","typescript","zod"],"created_at":"2026-06-08T05:03:59.085Z","updated_at":"2026-06-08T05:03:59.173Z","avatar_url":"https://github.com/ghwmelite-dotcom.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Skipper Detergents\n\n**Premium cleaning \u0026amp; bathroom essentials, delivered across Ghana.**\n\nProduction-grade e-commerce platform with bulk-quantity pricing, Paystack \u0026amp; manual-transfer checkout, and a lightweight admin CMS — built entirely on Cloudflare's edge.\n\n\u003cbr /\u003e\n\n[![CI](https://github.com/ghwmelite-dotcom/skipper-detergents/actions/workflows/ci.yml/badge.svg)](https://github.com/ghwmelite-dotcom/skipper-detergents/actions/workflows/ci.yml)\n[![Live API](https://img.shields.io/badge/API-live-10B981?logo=cloudflare\u0026logoColor=white)](https://skipper-api.ghwmelite.workers.dev/health)\n[![Live Storefront](https://img.shields.io/badge/Storefront-live-0B2545?logo=cloudflare\u0026logoColor=white)](https://skipper-storefront.pages.dev)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.5-3178C6?logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![Cloudflare Workers](https://img.shields.io/badge/Cloudflare-Workers-F38020?logo=cloudflare\u0026logoColor=white)](https://workers.cloudflare.com/)\n[![Hono](https://img.shields.io/badge/Hono-4-E36002)](https://hono.dev/)\n[![Turborepo](https://img.shields.io/badge/Turborepo-2-EF4444?logo=turborepo\u0026logoColor=white)](https://turbo.build/)\n[![Vitest](https://img.shields.io/badge/Vitest-2-6E9F18?logo=vitest\u0026logoColor=white)](https://vitest.dev/)\n[![pnpm](https://img.shields.io/badge/pnpm-9-F69220?logo=pnpm\u0026logoColor=white)](https://pnpm.io/)\n[![License: Proprietary](https://img.shields.io/badge/License-Proprietary-8B0000)](#license)\n\n\u003c/div\u003e\n\n---\n\n## Overview\n\nSkipper Detergents is a Ghanaian household-essentials brand selling its own \"Skipper\" line alongside trusted brands (Omo, Ariel, Dettol, Softcare, Premier, Bounty, Harpic) — detergents, toilet rolls, tissue, paper towels, and bathroom accessories. This repository is the full commerce platform powering the storefront, admin CMS, and APIs.\n\nEverything is **SEO-first**, **mobile-first**, and runs on the **Cloudflare edge** (Workers + D1 + R2 + KV) so a customer in Accra gets sub-100\u0026nbsp;ms responses and Google's crawler sees fully-hydrated product pages.\n\n## Highlights\n\n| Capability                   | Details                                                                                    |\n| ---------------------------- | ------------------------------------------------------------------------------------------ |\n| **Bulk ordering**            | Per-product quantity tiers with automatic cart-level discount resolution                   |\n| **Dual checkout**            | Paystack (card, mobile money, bank) + manual bank / MoMo transfer with proof upload        |\n| **SEO-first**                | JSON-LD structured data, dynamic sitemap, prerendered critical pages, canonical URLs       |\n| **Admin CMS**                | Product CRUD with R2 image uploads, order management, manual-payment verification          |\n| **Ghana-aware delivery**     | Zoned fees, pickup option, Ghana Post GPS addresses, optional third-party tracking link    |\n| **Strong typing end-to-end** | Shared Zod schemas validate client + server; every API boundary is typed                   |\n| **Edge-native**              | All compute in Cloudflare Workers; zero origin servers                                     |\n| **Accessibility baseline**   | WCAG AA contrast, 44\u0026nbsp;px touch targets, full keyboard navigation, reduced-motion aware |\n\n## Architecture\n\n```mermaid\ngraph TB\n  subgraph Browser\n    SF[Storefront SPA\u003cbr/\u003eReact + Vite]\n    AD[Admin SPA\u003cbr/\u003eReact + Vite]\n  end\n  subgraph \"Cloudflare Edge\"\n    API[API Worker\u003cbr/\u003eHono + TypeScript]\n    D1[(D1\u003cbr/\u003eSQLite)]\n    R2P[(R2\u003cbr/\u003eProduct Images)]\n    R2F[(R2\u003cbr/\u003ePayment Proofs)]\n    KV[(KV\u003cbr/\u003eSessions · Rate limit · Cache)]\n  end\n  subgraph External\n    PS[Paystack API]\n  end\n  SF -- HTTPS / JSON --\u003e API\n  AD -- HTTPS / JSON + JWT --\u003e API\n  API --\u003e D1\n  API --\u003e R2P\n  API --\u003e R2F\n  API --\u003e KV\n  API -- init + verify --\u003e PS\n  PS -- webhook HMAC-SHA-512 --\u003e API\n```\n\nThe storefront and admin are **two independent Cloudflare Pages deployments** so customers never download admin JavaScript and each surface gets its own CSP.\n\n## Tech stack\n\n| Layer            | Choice                                              | Why                                               |\n| ---------------- | --------------------------------------------------- | ------------------------------------------------- |\n| Monorepo         | pnpm workspaces + Turborepo                         | Fast installs, cached task pipeline               |\n| Language         | TypeScript 5.5 (strict, `noUncheckedIndexedAccess`) | Zero `any` policy, surface errors at compile time |\n| API framework    | Hono 4 on Cloudflare Workers                        | Edge-native, tiny, first-class TS types           |\n| Database         | Cloudflare D1 (SQLite + FTS5)                       | Co-located with compute, no cold connections      |\n| Object storage   | Cloudflare R2                                       | Product images, payment-proof uploads             |\n| Cache / sessions | Cloudflare KV                                       | JWT blacklist, rate-limit counters, cache layer   |\n| Validation       | Zod 3                                               | Same schema on client and server                  |\n| Auth             | JWT via `jose` + scrypt password hashing            | No external auth dependency; admin-only in v1     |\n| Payments         | Paystack + inline popup SDK                         | Ghana-native card + mobile money + bank           |\n| Frontend (m3–m5) | React 18 + Vite + Tailwind + shadcn/ui              | Widely known, fast builds, accessible primitives  |\n| Testing          | Vitest 2 + `@cloudflare/vitest-pool-workers`        | Fast, Workers-aware integration tests             |\n| CI / CD          | GitHub Actions + Wrangler                           | Deploy on merge to `main`                         |\n\n## Project structure\n\n```\nskipper-detergents/\n├── apps/\n│   ├── storefront/         # Customer-facing React SPA             (milestones 3–4)\n│   └── admin/              # Admin CMS React SPA                   (milestone 5)\n├── packages/\n│   ├── api/                # Hono Worker — routes, middleware, D1\n│   │   └── src/db/         # schema.sql · seed.sql · migrations/\n│   └── shared/             # Zod schemas · types · constants · utils\n├── docs/\n│   └── superpowers/\n│       ├── specs/          # Approved design specs\n│       └── plans/          # Milestone implementation plans\n└── .github/workflows/      # ci.yml + deploy.yml\n```\n\n## Quick start\n\nPrerequisites: **Node.js 20+**, **pnpm 9+**, a **Cloudflare account** (free tier is enough), and **Wrangler** (installed as a workspace dev-dep — no global install required).\n\n```bash\n# 1. Clone and install\ngit clone https://github.com/ghwmelite-dotcom/skipper-detergents.git\ncd skipper-detergents\npnpm install\n\n# 2. Authenticate with Cloudflare (one-time)\npnpm --filter @skipper/api exec wrangler login\n\n# 3. Create your Cloudflare resources (first setup only — copy the printed IDs)\npnpm --filter @skipper/api exec wrangler d1 create skipper-detergents-db\npnpm --filter @skipper/api exec wrangler r2 bucket create skipper-products\npnpm --filter @skipper/api exec wrangler r2 bucket create skipper-payment-proofs\npnpm --filter @skipper/api exec wrangler kv namespace create SESSIONS\npnpm --filter @skipper/api exec wrangler kv namespace create RATE_LIMIT\npnpm --filter @skipper/api exec wrangler kv namespace create CACHE\n\n# 4. Paste the IDs into packages/api/wrangler.toml (replacing PLACEHOLDER_FILL_IN_TASK_17)\n\n# 5. Initialize local D1 with schema + seed data\npnpm --filter @skipper/api db:setup\n\n# 6. Run the API\npnpm --filter @skipper/api dev\n# → http://localhost:8787/health\n```\n\n## Available scripts\n\nRun from the repo root unless noted:\n\n| Script              | What it does                                           |\n| ------------------- | ------------------------------------------------------ |\n| `pnpm dev`          | Start every dev server (currently just the API Worker) |\n| `pnpm test`         | Run every package's test suite via Turborepo           |\n| `pnpm typecheck`    | Strict TS check across the monorepo                    |\n| `pnpm lint`         | ESLint on every package                                |\n| `pnpm format`       | Prettier write on `**/*.{ts,tsx,md,json,yml,yaml}`     |\n| `pnpm format:check` | Prettier check (CI uses this)                          |\n| `pnpm build`        | Build every buildable package                          |\n\nPackage-specific (`packages/api`):\n\n| Script           | What it does                                       |\n| ---------------- | -------------------------------------------------- |\n| `db:setup`       | Apply `schema.sql` + `seed.sql` to local D1        |\n| `db:migrate`     | Apply pending migrations to **remote** D1          |\n| `db:reset:local` | List local tables then re-run `db:setup`           |\n| `deploy`         | `wrangler deploy` (CI runs this on push to `main`) |\n\n## Roadmap\n\nEach milestone ships independently and is tracked as a separate plan in [`docs/superpowers/plans/`](docs/superpowers/plans/).\n\n| #   | Milestone        | Status      | Scope                                                                  |\n| --- | ---------------- | ----------- | ---------------------------------------------------------------------- |\n| 1   | **Foundation**   | **Shipped** | Monorepo, shared types, Hono API skeleton, D1 schema + seed, CI/CD     |\n| 2   | Public API       | Next        | Product / category / search / checkout / Paystack + manual / tracking  |\n| 3   | Storefront shell | Planned     | Layout, routing, SEO, cart state, skeletons                            |\n| 4   | Storefront pages | Planned     | Home, Shop, Product detail, Bulk page, Cart, Checkout, Order tracking  |\n| 5   | Admin CMS        | Planned     | Login, Dashboard, Products CRUD, Orders, Settings, Activity log        |\n| 6   | Launch hardening | Planned     | Lighthouse pass, prerendering, CSP, email provider, production cutover |\n\n## Design \u0026amp; planning\n\n- **Design spec:** [`docs/superpowers/specs/2026-04-21-skipper-detergents-design.md`](docs/superpowers/specs/2026-04-21-skipper-detergents-design.md)\n- **Active plan (M1):** [`docs/superpowers/plans/2026-04-21-milestone-1-foundation.md`](docs/superpowers/plans/2026-04-21-milestone-1-foundation.md)\n\n## Deployment\n\nThe deploy workflow runs on **manual dispatch only** (Actions tab → \"Deploy API\" → \"Run workflow\") until credentials are in place. Once the team is ready for hands-off deploys, add a `push: branches: [main]` trigger to `.github/workflows/deploy.yml`.\n\nTwo **repository secrets** are required under **Settings → Secrets and variables → Actions** before the first dispatch:\n\n| Secret                  | How to get it                                                                  |\n| ----------------------- | ------------------------------------------------------------------------------ |\n| `CLOUDFLARE_API_TOKEN`  | Cloudflare dashboard → Profile → API Tokens → \"Edit Cloudflare Workers\" preset |\n| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare dashboard → right sidebar on any Workers page                       |\n\n**Worker secrets** (set per-environment via Wrangler, not GitHub):\n\n```bash\npnpm --filter @skipper/api exec wrangler secret put JWT_SECRET\npnpm --filter @skipper/api exec wrangler secret put PAYSTACK_SECRET_KEY\npnpm --filter @skipper/api exec wrangler secret put PAYSTACK_WEBHOOK_SECRET\n```\n\n### Storefront deployment\n\nThe storefront is a Vite + React SPA deployed to **Cloudflare Pages**. CI workflow: `.github/workflows/deploy-storefront.yml` (manual dispatch). Initial deploy is done locally:\n\n```bash\npnpm --filter @skipper/storefront build\npnpm --filter @skipper/storefront exec wrangler pages project create skipper-storefront --production-branch=main\npnpm --filter @skipper/storefront exec wrangler pages deploy ./dist --project-name=skipper-storefront\n```\n\nProduction URL: \u003chttps://skipper-storefront.pages.dev\u003e\n\nNote: `apps/storefront/public/_redirects` (`/*    /index.html   200`) enables client-side routing on Pages.\n\n## Conventions\n\n- **TypeScript strict mode everywhere.** No `any` without a justification comment.\n- **D1 queries use `.bind()`** — never string-concatenated SQL.\n- **All API request bodies** are validated with a Zod schema exported from `@skipper/shared`.\n- **Money** is stored as GHS in D1 and converted to pesewas only at the Paystack boundary.\n- **Commits** follow [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `chore:`, `docs:`, `test:`, `refactor:`, `style:`, `ci:`).\n- **Accessibility** is enforced at code review: 4.5:1 contrast on text, 44\u0026nbsp;px minimum touch targets, `prefers-reduced-motion` respected.\n\n## License\n\nProprietary — \u0026copy; Skipper Detergents Ltd. All rights reserved. Unauthorized reproduction, distribution, or use is prohibited.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\nBuilt with care for Ghana's households and businesses.\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghwmelite-dotcom%2Fskipper-detergents","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fghwmelite-dotcom%2Fskipper-detergents","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghwmelite-dotcom%2Fskipper-detergents/lists"}