Introducing Some of the PRD Documents Used to Build omnilude-tools
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-generatorskill 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
| Item | Value |
|---|---|
| Tool ID | timestamp-converter |
| Group | developer |
| Path | /developer/timestamp-converter |
| Priority | P0 (Required) |
| Estimated Effort | 1-2 days |
| Status | Draft |
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
| Site | Strengths | Weaknesses |
|---|---|---|
| epochconverter.com | Many formats, code snippets | Outdated UI |
| unixtimestamp.com | Simple UI | Limited features |
| timestamp-converter.com | Clean design | Limited timezone support |
2. Functional Requirements
2.1 Core Features (MVP)
F1: Timestamp to Date Conversion
Input: Unix timestamp (auto-detect seconds, milliseconds, or microseconds)
Output: Multiple date formats
Auto-detection logic:
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
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
Default: Browser local timezone
Options: UTC and major city-based timezones
Major timezone list:
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
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.
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
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
- Live conversion: Convert automatically on input (300ms debounce)
- Copy feedback: Show a toast when the copy button is clicked
- 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)
// _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
// 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
{
"dependencies": {
"date-fns": "^3.x",
"date-fns-tz": "^3.x"
}
}
Already installed in the project.
5. Internationalization Support
5.1 Translation Keys
// 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
// 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
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
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-labelon 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