Takazudo Modular Docs

Type to search...

to open search from anywhere

Architecture

Architecture

Data Flow

The zpreorder cannot directly access Netlify Blobs from local development. Instead, it fetches data through the main site’s admin API endpoints.

graph TB
    subgraph "Local Development"
        PM[zpreorder<br/>localhost:9876]
    end

    subgraph "Netlify (Deployed)"
        API[Admin API<br/>/api/admin/*]
        BLOB[(Netlify Blobs<br/>preorder-data-preview)]
    end

    PM -->|"HTTPS + Auth Token"| API
    API <-->|Read/Write| BLOB

Development Modes

Mock Mode (Default)

For rapid UI development without network dependencies:

# No configuration needed - mock mode is the default
pnpm zpreorder:dev
  • Uses local JSON files in mock-data/
  • Fast iteration, no network latency
  • Predictable test data
  • Mutations persist in memory during session

Local API Mode

For testing with local Netlify Functions and offline blob storage:

pnpm zpreorder:dev:full
  • Starts Netlify Functions server on port 9999 with --offline flag
  • Uses file-based blob storage (.netlify/blobs-serve/)
  • Data stored locally in preorder-data-preview store
  • No network dependency — fully offline

Remote Preview Mode

For testing with real data from deployed preview:

pnpm zpreorder:dev:preview
  • Fetches from deployed preview site
  • Real blob storage data (preview store)
  • Requires PREORDER_API_TOKEN (set in .env)

Remote Production Mode

For testing with real production data (read-only recommended):

pnpm zpreorder:dev:prod
  • Fetches from production site
  • Real production blob storage data
  • Requires PREORDER_API_TOKEN (set in .env)

Manual Remote Configuration

For custom API endpoints, set environment variables in .env:

# .env (in sub-packages/zpreorder/)
VITE_BLOB_API_URL=https://preview--takazudomodular.netlify.app/api/admin
VITE_PREORDER_API_TOKEN=your-preorder-api-token-here
  • Requires ADMIN_API_TOKEN (set on Netlify)

Environment variables use VITE_ prefix because this sub-app uses Vite (not Next.js). Only VITE_-prefixed variables are exposed to client-side code.

File Structure

sub-packages/zpreorder/
├── src/
│   ├── App.jsx               # Main app with routing
│   ├── main.jsx              # Entry point
│   ├── index.css             # Global styles with CSS vars
│   ├── components/
│   │   ├── Dashboard.jsx     # Dashboard page
│   │   ├── NotifyList.jsx    # Notify subscriptions list
│   │   ├── ReservationList.jsx # Reservations list
│   │   ├── SendNotification.jsx # Send notification page
│   │   ├── Nav.jsx           # Navigation component
│   │   └── shared/
│   │       └── ConfirmSendModal.jsx # Notification confirmation modal
│   ├── utils/
│   │   ├── api-client.js     # Dual-mode API client (mock/remote)
│   │   ├── product-lookup.js # Product name lookup from master data
│   │   └── date.js           # Date formatting utility
│   └── mock-data/
│       ├── subscriptions.json
│       └── reservations.json
├── tests/
│   └── api/                  # API integration tests (Vitest)
│       ├── helpers.js        # Shared test utilities
│       ├── notify-list.test.js
│       ├── notify-send.test.js
│       ├── notify-status.test.js
│       ├── reservations.test.js
│       └── stats.test.js
├── package.json
├── vite.config.js
├── vitest.config.js          # Vitest configuration
├── tailwind.config.js
└── index.html

Authentication

Main Site Admin API

Admin endpoints on the main site require ADMIN_API_TOKEN in the Authorization header:

// src/utils/api-client.js
async function fetchFromRemote(endpoint, body = {}) {
  const response = await fetch(`${API_URL}${endpoint}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${AUTH_TOKEN}`,
    },
    body: JSON.stringify(body),
  });
  return response.json();
}

Sub-App Access

The sub-app itself does not require authentication in development. In production deployment (if any), consider adding basic auth or Netlify Identity.

API Client

The API client automatically switches between mock and remote modes:

// src/utils/api-client.js
const API_MODE = import.meta.env.VITE_BLOB_API_MODE || 'mock';

export function isMockMode() {
  return API_MODE === 'mock';
}

export async function listNotifySubscriptions(filters = {}) {
  if (isMockMode()) {
    // Return filtered mock data
    return { success: true, subscriptions: filteredMockData };
  }
  return fetchFromRemote('/admin-notify-list', filters);
}

Send Notification Feature

The Send Notification page allows admins to send restock notification emails to pending subscribers.

Workflow

  1. Select a product with pending subscribers from dropdown
  2. Email title and body auto-fill with templates:
  • Title: Takazudo Modular 入荷のお知らせ: {product name}
  • Body: Product announcement with link to product page
  1. Preview email and confirm recipient count
  2. Click Send to mark all pending subscribers as notified

Product Name Lookup

The app uses the @data alias to access product master data:

// vite.config.js
resolve: {
  alias: {
    '@data': path.resolve(__dirname, '../../src/data'),
  },
}

// src/utils/product-lookup.js
import { allProducts } from '@data/product-master-data.mjs';

export function getProductName(slug) {
  const product = allProducts.find(p => p.slug === slug);
  return product?.name || slug;
}

API Endpoint

The notification is sent via POST /api/admin/notify/send. See Admin Notify Send for details.

Currently, notifications are logged and subscribers are marked as notified, but actual email sending via Resend is planned for Issue #501.

API Testing

The zpreorder includes API tests using Vitest that make real HTTP requests to the admin endpoints. Tests can run against both local development (netlify dev) and remote preview environments.

Test Structure

tests/api/
├── helpers.js           # Shared utilities (fetch wrapper, auth)
├── notify-list.test.js  # POST /api/admin-notify-list
├── notify-send.test.js  # POST /api/admin/notify/send
├── notify-status.test.js # POST /api/admin-notify-status
├── reservations.test.js # POST /api/admin-reservation-list
└── stats.test.js        # POST /api/admin-stats

Running Tests

# Run against local functions server (http://localhost:9999)
# First start the functions server: cd <project-root> && pnpm functions:serve
pnpm test:local

# Run against preview environment
pnpm test:preview

# Watch mode for development
pnpm test:watch

Environment Variables

VariableDescriptionDefault
API_BASE_URLBase URL for API requestshttp://localhost:9999
PREORDER_API_TOKENBearer token for authentication (dedicated token, not Netlify PAT)Required
RUN_DESTRUCTIVE_TESTSEnable tests that modify datafalse

Test Categories

Tests are designed to be non-destructive by default:

CategorySafe to RunDescription
List endpointsYesRead-only, no data modification
Validation errorsYesTests error handling for invalid input
Auth errorsYesTests 401 responses without token
Status updatesNo*Modifies subscription status
Send notificationNo*Marks subscribers as notified

*Enable with RUN_DESTRUCTIVE_TESTS=true

Example: Running Full Test Suite

# Local testing with functions server
cd <project-root>
pnpm functions:serve &  # Start in background (port 9999)
cd sub-packages/zpreorder
PREORDER_API_TOKEN=your-token pnpm test:local

# Preview testing
PREORDER_API_TOKEN=your-token pnpm test:preview

Port Assignment

PortDomainService
9876zpreorder.localhost
zpreorder

Add to CLAUDE.md port mapping when implementing.