An end-to-end luxury gemstone commerce platform for Angammana Co. It combines a multilingual public storefront, a modular administration dashboard, two secured APIs, and a shared MySQL data model.
The platform supports gemstone discovery, stone-family browsing, product and inventory management, content publishing, customer accounts, orders, promotions, gift cards, analytics, media, translations, and guided ring design.
Project status: Active development. The application builds and its automated API test suites pass (customer API 42 tests, admin API 35 tests). Object storage (Cloudflare R2), Google Analytics 4, reCAPTCHA v3, and Google OAuth are integrated. Production payment, transactional email, shipping, and final deployment integrations remain environment-specific and require client-owned credentials. See
PLAN.mdfor the itemized status of each area.
| Application | Directory | Local address | Purpose |
|---|---|---|---|
| Storefront | frontend/ |
http://localhost:3100 |
Public shopping and customer experience |
| Customer API | backend/ |
http://localhost:4100/api/v1 |
Catalog, identity, carts, orders, content, privacy, and ring builder |
| Admin dashboard | admin-frontend/ |
http://localhost:3200 |
Staff-facing commerce, catalog, CMS, CRM, and reporting interface |
| Admin API | admin-backend/ |
http://localhost:5100/api/v1 |
Administrative operations, RBAC, workflows, analytics, and audit history |
All four applications are independently installable and deployable. The two APIs share one MySQL database but maintain separate, ordered migration histories.
Four independently deployable processes over one MySQL database, split into a
public storefront trust boundary and an isolated administration boundary. Each
API owns a background worker for off-request work (publishing, exports, privacy
deletions, audit). See docs/ARCHITECTURE.md for the
full trust-boundary and layering model.
flowchart TB
visitor(["Customer browser"])
staff(["Staff browser"])
CF["Edge — Cloudflare + Nginx/Caddy<br/>TLS · HTTP/3 · Brotli · CDN cache"]
subgraph store["Storefront trust boundary"]
FE["Storefront<br/>Next.js 15 · SSG/ISR · :3100"]
API["Customer API<br/>Express · Zod · :4100/api/v1"]
W1[["Customer worker"]]
end
subgraph adminz["Admin trust boundary"]
AFE["Admin dashboard<br/>Next.js 15 · :3200"]
AAPI["Admin API<br/>Express · RBAC · MFA · :5100/api/v1"]
W2[["Admin worker"]]
end
DB[("MySQL 8<br/>gem-ecomm")]
OBJ[("Object storage<br/>Cloudflare R2 / local disk")]
visitor --> CF
staff --> CF
CF --> FE --> API
CF --> AFE --> AAPI
API --> DB
AAPI --> DB
API --> OBJ
AAPI --> OBJ
AAPI -->|"signed cache invalidation"| FE
W1 -. privacy deletions, retention .-> DB
W2 -. audit chain, exports, publishing .-> DB
sequenceDiagram
autonumber
participant B as Browser
participant E as Edge (Cloudflare/Nginx)
participant FE as Storefront (Next.js)
participant API as Customer API
participant DB as MySQL
Note over B,DB: Public read — cacheable, no credentials
B->>E: GET /collections
E->>FE: cache miss → SSG/ISR render
FE->>API: serverApi fetch (revalidate 300s)
API->>DB: parameterized query
DB-->>API: rows
API-->>FE: JSON (Cache-Control: s-maxage, SWR)
FE-->>E: HTML with per-request nonce CSP
E-->>B: cached HTML + immutable /_next assets
Note over B,DB: Authenticated mutation — never cached
B->>API: POST /cart (httpOnly access cookie + CSRF token)
API->>API: verify JWT (issuer/audience) + CSRF double-submit
API->>DB: transactional write
API-->>B: Set-Cookie (rotated refresh) · Cache-Control: no-store
Self-managed Contabo VPS behind Cloudflare; both Next apps run next start and
both APIs run under a process manager, all reverse-proxied by Nginx/Caddy.
flowchart LR
U(["Users"]) --> CF["Cloudflare<br/>CDN · WAF · TLS · HTTP/3"]
CF --> NG["Nginx / Caddy<br/>TLS · HTTP/2 · immutable asset cache"]
subgraph vps["Contabo VPS — PM2 / systemd"]
NG --> P1["Storefront · next start :3100"]
NG --> P2["Admin dashboard · next start :3200"]
NG --> P3["Customer API · node :4100"]
NG --> P4["Admin API · node :5100"]
P3 --> WK1[["Customer worker"]]
P4 --> WK2[["Admin worker"]]
end
P3 --> DB[("MySQL 8 · :3306")]
P4 --> DB
P1 -. next/image AVIF/WebP .-> R2[("R2 media")]
- Multilingual English and French routes
- Stone-family navigation for rubies, emeralds, sapphires, and other gemstones
- Per-family homepages on their own crawlable, prerendered URLs (
/f/<family>), each resolved server-side so its copy is in the HTML that ships - Product search, filtering, comparison, wishlists, and recommendations
- Customer registration, authentication, profile, addresses, and notifications
- Guest and authenticated carts
- Checkout, gift cards, promotions, order history, and invoices
- Guided ring builder and saved designs
- CMS-driven homepage, landing pages, navigation, banners, pages, FAQs, blog, and education content
- Privacy consent, data export, and deletion-request workflows
- reCAPTCHA v3 on public forms and consent-gated Google Analytics 4
- Responsive images, SEO metadata, sitemap, structured data, and security headers
- Product, category, inventory, supplier, sourcing, and attribute management
- Editable product types, stone families, colors, shapes, treatments, origins, and certificates
- Square attribute imagery with upload and crop support
- Order status, shipment, return, refund, quote, and invoice operations
- Promotion and gift-card management
- Customer profiles, notes, messages, consultations, and review moderation
- Homepage, navbar, top bar, footer, banner, page, FAQ, blog, theme, and translation editing
- Per-family homepages and landing pages: give any stone family its own sections, order and imagery, or leave it inheriting the shared page
- Any section type can be placed on any page, duplicated in place, or copied to another page
- Landing pages (/sapphires, /rings-by-color, …) are created and edited entirely in the CMS — headings, imagery, tile grids and their filters. New pages start from an existing page's layout and are live at their own address immediately, with no deploy
- Scheduled banners, publishable/reorderable FAQs, and SEO titles/descriptions on pages and posts
- Customizable invoice/company details (legal name, contacts, addresses, colours, policy copy)
- Stone-family setup, navigation, and draft/preview/publish workflows
- Media library with image and video tooling
- Analytics, reports, tamper-evident activity history, staff roles, permissions, MFA, and account security
- HMAC-signed CMS cache invalidation to the storefront on content and catalog changes
- Per-request correlation IDs (
X-Request-Id), structured JSON logs in production, and a Prometheus-style/metricsendpoint on both APIs - Separated liveness (
/health/live) and dependency-aware readiness (/health/ready) checks - Background worker for publishing, privacy deletions, exports, and retention cleanup off the request path
| Layer | Technology |
|---|---|
| Web applications | Next.js 15, React 18, TypeScript, Tailwind CSS |
| Rich content | TipTap 3 |
| Media editing | react-easy-crop, FFmpeg WebAssembly |
| APIs | Node.js, Express 4, Zod |
| Database | MySQL 8 with mysql2, transactions, and ordered SQL migrations |
| Authentication | Short-lived JWT access tokens, rotating refresh tokens, HTTP-only cookies, CSRF protection |
| Admin security | Role-based permissions, forced password changes, MFA, recovery codes, activity history |
| Testing | Node test runner, TypeScript checks, production Next.js builds |
| Automation | GitHub Actions CI and release-delivery workflows |
.
├── frontend/ Public Next.js storefront
├── backend/ Customer-facing Express API
│ └── src/
│ ├── db/migrations/ Core database migrations
│ └── modules/ Domain modules
├── admin-frontend/ Next.js administration dashboard
├── admin-backend/ Administrative Express API
│ └── src/
│ ├── db/migrations/ Additive admin/CMS migrations
│ └── modules/ Admin domain modules
├── schema/ Reviewable schema snapshot and documentation
├── .github/workflows/ CI and release delivery automation
└── output/ Generated project deliverables (not application source)
frontend-ui/ is a legacy design prototype and is not part of the active
production application or CI pipeline.
- Node.js 22 recommended (
>=20 <25supported) - npm 10+
- MySQL 8
- macOS, Linux, or WSL for the documented local commands
The example development configuration expects MySQL at 127.0.0.1:8889 with
database name gem-ecomm. Change the environment values if your MySQL instance
uses a different host or port.
cd backend && npm install
cd ../admin-backend && npm install
cd ../frontend && npm install
cd ../admin-frontend && npm install
cd ..Create local environment files from the committed examples:
cp backend/.env.example backend/.env
cp admin-backend/.env.example admin-backend/.envThe frontend applications use these defaults when local environment files are not present:
# frontend/.env.local
NEXT_PUBLIC_API_URL=http://localhost:4100/api/v1
NEXT_PUBLIC_ADMIN_API_URL=http://localhost:5100/api/v1
API_URL_INTERNAL=http://localhost:4100/api/v1
# admin-frontend/.env.local
NEXT_PUBLIC_ADMIN_API_URL=http://localhost:5100/api/v1Never commit real credentials or production secrets. Local .env files are
ignored by Git.
Migration order matters because the admin schema references core commerce tables:
cd backend
npm run migrate
cd ../admin-backend
npm run migrate
cd ../backend
npm run seed
cd ../admin-backend
npm run seed
cd ..Both seeders are idempotent and can be run again safely. In development, staff
passwords are generated and printed once. To use explicit development passwords,
set the corresponding SEED_*_PASSWORD values before seeding.
Production seeding refuses to run without explicitly supplied credentials.
Open four terminals from the repository root:
# Terminal 1 — customer API
cd backend && npm run dev
# Terminal 2 — admin API
cd admin-backend && npm run dev
# Terminal 3 — storefront
cd frontend && npm run dev
# Terminal 4 — admin dashboard
cd admin-frontend && npm run devThen open:
- Storefront: http://localhost:3100
- Admin dashboard: http://localhost:3200
- Customer API health: http://localhost:4100/health (also
/health/live,/health/ready,/metrics) - Admin API health: http://localhost:5100/health (also
/health/live,/health/ready,/metrics)
Run commands inside the relevant application directory.
| Command | Available in | Purpose |
|---|---|---|
npm run dev |
All applications | Start a development server |
npm run build |
Both frontends | Create an optimized production build |
npm run typecheck |
Both frontends | Validate TypeScript without emitting files |
npm test |
Storefront and both APIs | Run the automated test suite |
npm run migrate |
Both APIs | Apply pending migrations |
npm run migrate:status |
Both APIs | Display applied and pending migrations |
npm run seed |
Both APIs | Seed reference and development data |
npm run rotate-credentials |
Admin API | Rotate seeded staff credentials |
For a new core database, backend/npm run migrate:fresh drops and rebuilds the
configured database. Use it only against disposable development or test data.
Migrations are the deployment source of truth:
backend/src/db/migrations/*.sql
└── tracked in schema_migrations
admin-backend/src/db/migrations/*.sql
└── tracked in admin_schema_migrations
Apply customer API migrations before admin API migrations. The committed
schema/schema.sql file is a reviewable structural snapshot,
not a deployment mechanism. See schema/README.md before
changing database structure.
Customer and admin authentication are intentionally separated. Both use HTTP-only cookies, rotating refresh sessions, CSRF protection, token issuer and audience checks, and immediate account-state validation.
The admin platform provides these base roles:
| Role | Intended responsibility |
|---|---|
| Admin | Full platform administration |
| Manager | Operational and commerce management |
| Staff | Day-to-day order, inventory, product, and customer work |
| Content editor | CMS, blog, media, translation, and publishing work |
Per-user permission overrides provide more precise access when a base role is too broad. Administrator accounts can also enable MFA and recovery codes.
Run the same primary checks used by CI:
cd backend && npm run lint && npm test
cd ../admin-backend && npm run lint && npm test
cd ../frontend && npm run lint && npm test && npm run typecheck && npm run build
cd ../admin-frontend && npm run lint && npm run typecheck && npm run build
cd .. && node scripts/generate-contracts.js --check && node scripts/verify-migrations.js && node scripts/quality-guard.jsDatabase integration tests require the complete core and admin migration sets. The CI workflow creates a clean MySQL database, applies both histories, seeds deterministic test data, and then runs the API suites.
ci.yml runs for every branch push and pull request.
It verifies:
- Locked dependency installation on Node.js 22
- Core and admin migrations against MySQL 8
- Deterministic database seeding
- Customer API and admin API tests
- Storefront tests
- TypeScript validation for both web applications
- Production builds for the storefront and admin dashboard
- High-severity production dependency audits for all four applications
- ESLint gates for all four applications
- Generated API-contract, immutable migration-manifest, and maintainability-budget drift checks
- Critical-journey Playwright end-to-end suite (
e2e.yml) on pull requests - Scheduled CodeQL and full-history secret scanning in
security.yml
Superseded runs on the same branch are cancelled automatically.
release.yml runs manually or for tags matching
v*, such as v1.2.0. It first reuses the complete CI workflow and then creates
separate delivery bundles for:
- Storefront
- Admin dashboard
- Customer API
- Admin API
Each bundle ships with a CycloneDX software bill of materials and a signed build-provenance attestation. Bundles are retained as GitHub Actions artifacts for 14 days. Provider-specific deployment is intentionally not included until the production host, environment URLs, secrets, and client credentials are confirmed.
Before a production release:
- Provision separate production secrets for both APIs.
- Configure production database TLS, backups, and restricted database users.
- Supply remaining client-owned credentials: payment, transactional email, and shipping. (Object storage/R2, Google OAuth, Analytics, and reCAPTCHA are already integrated — confirm production keys and allowed domains.)
- Set exact storefront, admin, API, media (R2 public URL), and CORS origins.
- Apply core migrations, then admin migrations, before deploying application code that requires them.
- Run the complete CI workflow and review dependency results.
- Use explicit production seed credentials or avoid production seeding entirely.
- Verify rollback procedures and database backups before switching traffic.
The current payment endpoint is a development placeholder. It must not be treated as a real payment capture integration.
- Customer API guide
- Admin API guide
- Storefront guide
- Database schema guide
- Architecture and data flow
- Threat model
- Architecture decision records
- Per-family homepages — design and rollout notes
- Database data dictionary
- Operations runbooks
- SLOs and alerts
- Capacity, data volumes, and recovery objectives
- Ownership and handover
- Handover checklist
- Credential-blocked acceptance checklist
- Monitoring configs (Prometheus/Grafana)
- Enterprise security and performance audit
- Admin panel user guide
- Keep domain logic out of route files and UI presentation components.
- Validate every external input at the API boundary.
- Preserve backward compatibility during database and API changes.
- Add or update tests for every corrected bug and business rule.
- Never commit
.envfiles, credentials, customer data, or generated uploads. - Update this README, module documentation, and schema snapshot when behavior changes.
- Keep pull requests focused, reviewable, and safe to roll back.
This repository contains client project code. Access, distribution, and use are subject to the applicable agreement with Angammana Co. (Pvt) Ltd.