Tutorial

Introducing Some of the PRD Documents Used to Build omnilude-tools

AAnonymous
10 min read

Introduction

As mentioned in the earlier post about omnilude-tools, a number of real tools in that project were backed by concrete PRD documents. The document published in this post is one of them: the Unix Timestamp Converter PRD.

This document was originally written in Korean to build the real timestamp-converter tool, and traces of that implementation still remain under src/app/[locale]/(tools)/developer/timestamp-converter/. In other words, this was not a loose idea memo. It was a working document that tied together screen structure, state management, SEO, and test design.

There are three points I especially want to make clear in this post.

  • This document is one of the PRDs used to build an actual tool inside omnilude-tools.
  • It is also a good real-world example of how the prd-generator skill can be used.
  • The original PRD was written in Korean, and for this post the full document is translated so that readers in each locale can read the entire text rather than a summary.

You can also access the live tool at tools.omnilude.com/developer/timestamp-converter.

If possible, I would have liked to share the prompt that was used to generate this PRD as well, but I deleted the session data because of disk space limitations, so I ask for your understanding that I cannot provide it here.

Main Body

In short, this document narrowed the scope down to a level where an implementer could move immediately.

  • What to build: a tool that converts between Unix timestamps and human-readable dates in both directions
  • How far to take it: MVP features, advanced features, timezones, live current time, code snippets, and a calculator
  • How to build it: file structure, Zustand state management, conversion utilities, SEO, tests, accessibility, and performance requirements
  • How to verify it: unit tests, E2E tests, and an implementation checklist

When a document reaches this level of detail, implementation becomes much simpler. The actual timestamp-converter page was built from this kind of structured guide, and it still remains as a developer tool inside omnilude-tools.

This document was translated from Korean

The source version for this post is a Korean PRD. For that reason, the translations in each locale focus on carrying the entire document across rather than reducing it to a short summary. Even though this is a PRD document, preserving the technical context and implementation background mattered more than shortening it.

Original PRD

Below is the full public version of the Unix Timestamp Converter PRD.

PRD: Unix Timestamp Converter

Basic Information

ItemValue
Tool IDtimestamp-converter
Groupdeveloper
Path/developer/timestamp-converter
PriorityP0 (Required)
Estimated Effort1-2 days
StatusDraft

1. Overview

1.1 Purpose

A tool that provides two-way conversion between Unix timestamps and human-readable date formats.

1.2 Target Users

  • Backend and frontend developers
  • Data analysts
  • System administrators

1.3 Competitor Review

SiteStrengthsWeaknesses
epochconverter.comMany formats, code snippetsOutdated UI
unixtimestamp.comSimple UILimited features
timestamp-converter.comClean designLimited timezone support

2. Functional Requirements

2.1 Core Features (MVP)

F1: Timestamp to Date Conversion

Typescript
Input: Unix timestamp (auto-detect seconds, milliseconds, or microseconds)
Output: Multiple date formats

Auto-detection logic:

Typescript
function detectTimestampUnit(value: number): 'seconds' | 'milliseconds' | 'microseconds' {
  if (value < 1e12) return 'seconds';       // fewer than 10 digits
  if (value < 1e15) return 'milliseconds';  // 13 digits
  return 'microseconds';                    // 16 digits
}

Output formats:

  • ISO 8601: 2026-01-29T13:45:30.000Z
  • RFC 2822: Wed, 29 Jan 2026 13:45:30 +0000
  • Local format: January 29, 2026, 10:45:30 PM
  • Relative time: 5 minutes ago, in 3 days

F2: Date to Timestamp Conversion

Typescript
Input: Date string or date picker
Output: Unix timestamp (seconds and milliseconds)

Supported input formats:

  • ISO 8601 string
  • Date and time picker (DatePicker)
  • Natural language (optional): now, yesterday, next week

F3: Timezone Support

Typescript
Default: Browser local timezone
Options: UTC and major city-based timezones

Major timezone list:

Typescript
const TIMEZONES = [
  { value: 'UTC', label: 'UTC' },
  { value: 'Asia/Seoul', label: 'Seoul (KST, UTC+9)' },
  { value: 'Asia/Tokyo', label: 'Tokyo (JST, UTC+9)' },
  { value: 'America/New_York', label: 'New York (EST/EDT, UTC-5/-4)' },
  { value: 'America/Los_Angeles', label: 'Los Angeles (PST/PDT, UTC-8/-7)' },
  { value: 'Europe/London', label: 'London (GMT/BST, UTC+0/+1)' },
  // ... add more
];

F4: Live Current Time Display

Typescript
Show the current Unix timestamp at the top of the screen and update it every second

2.2 Advanced Features

F5: Code Snippet Generation

Provide the selected timestamp as code in multiple programming languages.

Typescript
const CODE_SNIPPETS = {
  javascript: (ts: number) => `new Date(${ts * 1000})`,
  python: (ts: number) => `datetime.fromtimestamp(${ts})`,
  java: (ts: number) => `Instant.ofEpochSecond(${ts}L)`,
  go: (ts: number) => `time.Unix(${ts}, 0)`,
  php: (ts: number) => `date('Y-m-d H:i:s', ${ts})`,
  ruby: (ts: number) => `Time.at(${ts})`,
  csharp: (ts: number) => `DateTimeOffset.FromUnixTimeSeconds(${ts})`,
};

F6: Timestamp Calculator

Typescript
Base time + days/hours/minutes/seconds = result timestamp
Example: now + 7 days = timestamp for next week

3. UI/UX Design

3.1 Layout

┌─────────────────────────────────────────────────────────────┐
│  Current Unix Timestamp: 1738150800 (live update)  [Copy]  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────┐  ┌─────────────────────────────┐  │
│  │  Input              │  │  Result                     │  │
│  │                     │  │                             │  │
│  │  [Timestamp Input]  │  │  ISO 8601: ...      [Copy]  │  │
│  │  or                 │  │  RFC 2822: ...      [Copy]  │  │
│  │  [Date/Time Pick]   │  │  Local: ...         [Copy]  │  │
│  │                     │  │  Relative: ...      [Copy]  │  │
│  │  Timezone: [Pick ▼] │  │                             │  │
│  │                     │  │  Timestamp (s): ...         │  │
│  │  [Convert] [Clear]  │  │  Timestamp (ms): ...        │  │
│  └─────────────────────┘  └─────────────────────────────┘  │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│  Code Snippets                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  [JS] [Python] [Java] [Go] [PHP] [Ruby] [C#]        │   │
│  │  ─────────────────────────────────────────────────  │   │
│  │  new Date(1738150800000)                   [Copy]   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 Responsive Design

Desktop (lg+):

  • Two-column layout (input | result)

Tablet/Mobile (< lg):

  • One-column layout (input above, result below)

3.3 Interactions

  1. Live conversion: Convert automatically on input (300ms debounce)
  2. Copy feedback: Show a toast when the copy button is clicked
  3. Keyboard shortcuts: Enter to convert, Ctrl+C to copy results

4. Technical Specification

4.1 File Structure

src/app/[locale]/(tools)/developer/timestamp-converter/
├── page.tsx                              # page entry + SEO
├── _store/
│   └── timestamp-store.ts                # Zustand state management
└── _components/
    ├── timestamp-page.tsx                # main client component
    ├── current-time-display.tsx          # current time display
    ├── timestamp-input.tsx               # input section
    ├── conversion-result.tsx             # result section
    └── code-snippets.tsx                 # code snippet section

4.2 State Management (Zustand)

Typescript
// _store/timestamp-store.ts
import { create } from 'zustand';

type InputMode = 'timestamp' | 'datetime';

interface TimestampState {
  // input
  inputMode: InputMode;
  timestampInput: string;
  dateInput: Date | null;
  timezone: string;

  // result
  result: ConversionResult | null;

  // code snippets
  selectedLanguage: string;

  // actions
  setInputMode: (mode: InputMode) => void;
  setTimestampInput: (value: string) => void;
  setDateInput: (date: Date | null) => void;
  setTimezone: (tz: string) => void;
  setSelectedLanguage: (lang: string) => void;
  convert: () => void;
  clear: () => void;
}

interface ConversionResult {
  timestampSeconds: number;
  timestampMillis: number;
  iso8601: string;
  rfc2822: string;
  localFormat: string;
  relative: string;
}

export const useTimestampStore = create<TimestampState>((set, get) => ({
  inputMode: 'timestamp',
  timestampInput: '',
  dateInput: null,
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  result: null,
  selectedLanguage: 'javascript',

  setInputMode: (mode) => set({ inputMode: mode }),
  setTimestampInput: (value) => set({ timestampInput: value }),
  setDateInput: (date) => set({ dateInput: date }),
  setTimezone: (tz) => set({ timezone: tz }),
  setSelectedLanguage: (lang) => set({ selectedLanguage: lang }),

  convert: () => {
    const { inputMode, timestampInput, dateInput, timezone } = get();
    // conversion logic
  },

  clear: () => set({
    timestampInput: '',
    dateInput: null,
    result: null,
  }),
}));

4.3 Core Conversion Logic

Typescript
// lib/timestamp-utils.ts
import { format, formatDistanceToNow } from 'date-fns';
import { formatInTimeZone } from 'date-fns-tz';
import { ko, en, ja } from 'date-fns/locale';

export function convertTimestamp(
  timestamp: number,
  timezone: string,
  locale: string
): ConversionResult {
  // auto-detect unit
  const unit = detectTimestampUnit(timestamp);
  const timestampMs = unit === 'seconds'
    ? timestamp * 1000
    : unit === 'microseconds'
      ? Math.floor(timestamp / 1000)
      : timestamp;

  const date = new Date(timestampMs);
  const localeObj = { ko, en, ja }[locale] || ko;

  return {
    timestampSeconds: Math.floor(timestampMs / 1000),
    timestampMillis: timestampMs,
    iso8601: date.toISOString(),
    rfc2822: format(date, 'EEE, dd MMM yyyy HH:mm:ss xx', { locale: localeObj }),
    localFormat: formatInTimeZone(date, timezone, 'PPpp', { locale: localeObj }),
    relative: formatDistanceToNow(date, { addSuffix: true, locale: localeObj }),
  };
}

export function dateToTimestamp(date: Date): { seconds: number; millis: number } {
  const millis = date.getTime();
  return {
    seconds: Math.floor(millis / 1000),
    millis,
  };
}

4.4 Dependencies

JSON
{
  "dependencies": {
    "date-fns": "^3.x",
    "date-fns-tz": "^3.x"
  }
}

Already installed in the project.

5. Internationalization Support

5.1 Translation Keys

JSON
// messages/en/tools/developer/timestamp-converter.json
{
  "tools": {
    "developer": {
      "timestampConverter": "Timestamp Converter",
      "timestampConverterDesc": "Convert between Unix timestamps and dates",
      "timestamp": {
        "currentTime": "Current Unix Timestamp",
        "inputTimestamp": "Timestamp Input",
        "inputDatetime": "Date/Time Input",
        "timezone": "Timezone",
        "convert": "Convert",
        "clear": "Clear",
        "copy": "Copy",
        "copied": "Copied",
        "results": "Conversion Results",
        "iso8601": "ISO 8601",
        "rfc2822": "RFC 2822",
        "localFormat": "Local Format",
        "relative": "Relative Time",
        "timestampSeconds": "Timestamp (seconds)",
        "timestampMillis": "Timestamp (milliseconds)",
        "codeSnippets": "Code Snippets",
        "invalidTimestamp": "Invalid timestamp",
        "autoDetected": "Auto-detected: {unit}"
      }
    }
  }
}

6. SEO Metadata

Typescript
// page.tsx
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { locale } = await params;
  const t = await getTranslations({ locale });

  return generateSeoMetadata({
    locale,
    title: t('tools.developer.timestampConverter'),
    description: t('tools.developer.timestampConverterDesc'),
    path: '/developer/timestamp-converter',
    keywords: [
      'unix timestamp',
      'epoch converter',
      'timestamp converter',
      'date conversion',
      'timestamp to date',
      'date to timestamp',
    ],
  });
}

7. Test Cases

7.1 Unit Tests

Typescript
describe('detectTimestampUnit', () => {
  it('should detect seconds', () => {
    expect(detectTimestampUnit(1738150800)).toBe('seconds');
  });

  it('should detect milliseconds', () => {
    expect(detectTimestampUnit(1738150800000)).toBe('milliseconds');
  });

  it('should detect microseconds', () => {
    expect(detectTimestampUnit(1738150800000000)).toBe('microseconds');
  });
});

describe('convertTimestamp', () => {
  it('should convert timestamp to ISO 8601', () => {
    const result = convertTimestamp(1738150800, 'UTC', 'en');
    expect(result.iso8601).toBe('2025-01-29T09:00:00.000Z');
  });
});

7.2 E2E Test

Typescript
test('timestamp conversion flow', async ({ page }) => {
  await page.goto('/en/developer/timestamp-converter');

  // enter timestamp
  await page.fill('[data-testid="timestamp-input"]', '1738150800');

  // verify result
  await expect(page.locator('[data-testid="iso8601-result"]'))
    .toContainText('2025-01-29');

  // click copy button
  await page.click('[data-testid="copy-iso8601"]');
  await expect(page.locator('.toast')).toContainText('Copied');
});

8. Accessibility Requirements

  • Proper labels for all input fields
  • aria-label on copy buttons
  • Keyboard navigation support
  • Screen reader compatibility

9. Performance Requirements

  • Show conversion results after input: < 100ms
  • Current time update: accurate every second
  • Bundle size increase: < 5KB (gzip)

10. Implementation Checklist

  • Create file structure
  • Implement Zustand store
  • Implement conversion utility functions
  • Implement main page component
  • Implement current time display component
  • Implement input section component
  • Implement result section component
  • Implement code snippet section component
  • Add translation keys for 7 languages
  • Register the tool in tools.ts
  • Apply responsive styling
  • Review accessibility
  • Write tests