Package/Folder Documentation Guidelines

Guidelines for writing comprehensive module documentation, derived from timezoned.md, observable.md, and reflection.md.

---

Workspace Metadata

Before working on documentation, consult the .tom_metadata/index.yaml file at the workspace root to understand: - Project structure (projects, parts, modules) - Correct naming and hierarchy - Module relationships

See project_structure.md for details on the metadata format.

---

User Documentation Location

1. Documentation Folder Structure

  • User documentation should always be placed in a doc/ folder, normally at project level
  • If a project has parts and/or modules, documents should be in subfolders accordingly
  • Example structure for a project with modules:
  project/
    doc/
      user_guide.md
      architecture.md
      api/
        api_summary_{module_a}.md
        api_summary_{module_b}.md
      {module a}/
        {module a}.md
      {module b}/
        {module b}.md
  • Example structure for a project with modules:
  project/
    doc/
      {project}_user_guide.md
      {project}_architecture.md
      api/
        api_summary_{module_a}.md
        api_summary_{module_b}.md
      {part1}/
      {part1}.md
        {module a}/
          {module a}.md
        {module b}/
          {module b}.md
        {part2}/
      {part2}.md
        {module c}/
          {module c}.md
        {module d}/
          {module d}.md

2. PDF Files

  • Some documentation may be in .pdf format (read-only)
  • PDFs should also be placed in the doc/ folder

3. README.md Files

  • README.md files should always remain where they are (project root, folder root, etc.)
  • Never move README.md files to doc/

README.md Structure

Every package README.md should include:

1. Title and Badge - Package name, pub.dev version badge 2. Description - One paragraph explaining what the package does 3. Features - Bulleted list of key capabilities 4. Installation - pubspec.yaml dependency snippet 5. Quick Start - Minimal working example 6. Basic Usage - Common usage patterns 7. Documentation Links - Links to detailed guides 8. License - License type (usually MIT)

Example Template:

# Package Name

Brief one-paragraph description of what this package does.

## Features

- Feature 1
- Feature 2
- Feature 3

## Installation

Add to your `pubspec.yaml`:

dependencies: package_name: ^1.0.0


## Quick Start

import 'package:package_name/package_name.dart';

void main() { // Minimal example }


## Documentation

- [User Guide](doc/user_guide.md)
- [API Reference](doc/api/)

## License

MIT License

4. CHANGELOG.md Files

Every package should have a CHANGELOG.md at the root following Keep a Changelog format.

CHANGELOG Structure

# Changelog

All notable changes to this project will be documented in this file.

## [Unreleased]

### Added
- New features being developed

## [1.2.0] - 2024-01-15

### Added
- New feature X that does Y

### Changed
- Modified behavior of Z

### Deprecated
- Feature A will be removed in v2.0

### Fixed
- Bug where X happened under Y conditions

### Removed
- Removed deprecated feature B

### Security
- Fixed vulnerability in X

## [1.1.0] - 2024-01-01
...

CHANGELOG Guidelines

  • Keep entries concise - One line per change
  • Use present tense - "Add feature" not "Added feature"
  • Group by type - Added, Changed, Deprecated, Fixed, Removed, Security
  • Most recent first - Newest version at the top
  • Include dates - ISO format (YYYY-MM-DD)
  • Link to issues - Reference issue numbers where applicable

5. Project-Specific Guidelines

Some projects have their own _copilot_guidelines/ folder with project-specific documentation rules.

Always check for project-level guidelines: 1. Look for {project}/_copilot_guidelines/ folder 2. Check index.md for available documentation 3. Follow project-specific rules over global rules when they conflict

Creating Project Guidelines: When creating a new _copilot_guidelines/ folder for a project, include: - index.md - Index of available guidelines - example.md - Example file creation guidelines - documentation.md - Project-specific documentation rules - build.md - Build, test, and publishing guidelines

6. Module Documentation

  • Module-level technical documentation (API docs) may remain alongside source code
  • User-facing documentation goes to doc/

7. API Documentation

---

File Naming and Location

1. File Naming

  • Name the documentation file after the folder/module: {module_name}.md
  • Place it in the same folder as the source files it documents
  • Examples:
  • lib/src/tombase/timezoned/timezoned.md
  • lib/src/tombase/observable/observable.md
  • lib/src/tombase/reflection/reflection.md

2. One File Per Module

Each module folder should have exactly one main documentation file that covers all classes and concepts in that module.

---

Document Structure

Required Sections (in order)

Every module documentation file must include these sections:

# Tom {Module Name} System

{One-paragraph summary of what the module does}

## Table of Contents

- [Overview](#overview)
- [Quick Start](#quick-start)
- [Core Components](#core-components)
- ... {feature-specific sections}
- [Error Handling](#error-handling)
- [Best Practices](#best-practices)

## Overview

{Detailed explanation of the module}

## Quick Start

{Minimal working examples}

## Core Components

{Main classes and their roles}

## {Feature Sections}

{Deep dives into each feature}

## Error Handling

{Common errors and solutions}

## Best Practices

{Usage recommendations}

Optional Sections (as needed)

  • ## Dependencies - External packages or other modules required
  • ## Build Configuration - For modules requiring code generation
  • ## Class Hierarchy - For complex inheritance structures
  • ## Serialization - For modules with custom serialization formats

---

Section Guidelines

1. Title

# Tom {Module Name} System
  • Always prefix with "Tom"
  • Use "System" suffix for modules
  • One sentence summary immediately follows:
# Tom Timezoned System

The Tom Timezoned System provides robust timezone-aware date and time handling for Dart applications.
It extends Dart's built-in `DateTime` with proper timezone support, serialization, and
automatic handling of daylight saving time (DST) transitions.

2. Table of Contents

  • Use markdown links to section anchors
  • Include all major sections
  • Nest sub-sections with indentation for complex modules:
## Table of Contents

- [Overview](#overview)
- [Quick Start](#quick-start)
- [Core Components](#core-components)
  - [TomObservable](#tomobservable)
  - [TomObserver](#tomobserver)
  - [TomFunctionObserver](#tomfunctionobserver)
- [Observable Primitives](#observable-primitives)
  - [Non-Nullable Types](#non-nullable-types)
  - [Nullable Types](#nullable-types)

3. Overview

The overview section must include:

a) Component List

Describe the main files/classes and their responsibilities:

## Overview

The timezoned system consists of two main components:

1. **`TomTimezone`**: A wrapper around the `timezone` package's `Location` class that provides
   timezone lookup, UTC offset calculation, and formatting.

2. **`TomTimezoned`** and subclasses: DateTime extensions that store values as **true UTC internally**
   while maintaining the associated timezone for display and conversion.
The type table, and why it is exhaustive

A module document whose Overview opens with a table of the module's types undertakes to list every public type the package barrel reaches from that module — not a selection:

## Overview

| Type | Kind | Purpose |
| ---- | ---- | ------- |
| `TomUserPreference` | class | The `tom_user_preference` row; carries the row scope |
| `TomUserPreferenceRepository` | class | Persists that entity |

A curated list cannot be checked, and that is not an abstract objection. tom_core_server's preferences document named five of its six public types, and the missing one was the subject of the document's own longest section. It went unnoticed for months because, with no rule about what belongs, an omission contradicts nothing.

Exhaustive costs something, and the cost is accepted. A module with eighty-five public types gets an eighty-five-row table, most rows one line. Such a table is closer to an index than an overview — but an index that is complete beats an overview that is silently partial, because a reader takes the silence of a list for an answer.

Presentation stays free. A row may cover names that are used as a set — ` TomSelect / TomCount / TomDelete on one row — and a family may share a row provided every member is named on it. What is not allowed is an ellipsis: TomButtonBase, TomInputBase, … ` is where a type goes missing without contradicting anything, which is the defect this rule exists for.

The table is what puts the document in scope. An Overview written as prose is a different shape and this rule does not reach it; a table with a Type (or Symbol) column beside a Kind column is the document declaring that this region enumerates its module. In the Tom workspace, tom_ai/core/tool/check_doc_overview_types.py enforces it for the packages that write one.

b) Internal Model (if applicable)

Explain non-obvious internal design decisions:

### Internal Storage Model

All `TomTimezoned` values store the actual UTC moment internally:

- **Standard accessors** (`year`, `month`, `day`, `hour`, etc.) return **UTC values**
- **Local accessors** (`localYear`, `localMonth`, `localDay`, `localHour`, etc.) return **local time values**

c) Value Proposition

A bulleted list of why users should use this module:

### Why Use TomTimezoned?

- **Timezone preservation**: Unlike `DateTime`, timezone context is preserved across operations
- **Automatic DST handling**: UTC offsets are calculated correctly for any point in time
- **Serialization**: Built-in string format preserves both the datetime and timezone information
- **Type safety**: Separate classes for date-only, time-only, and full datetime values
- **IANA timezone names**: Uses standard identifiers like `'America/New_York'` or `'Asia/Tokyo'`

4. Quick Start

Provide the absolute minimum code to get started. Structure as numbered steps:

## Quick Start

### 1. Annotate Your Class

import 'package:tom_core/tom_core.dart';

@tomReflector class Person { String name = ''; int age = 0; }


### 2. Initialize Reflectable

import 'my_file.reflectable.dart';

void main() { initializeReflectable(); }


### 3. Use Reflection

final person = tomReflectionInfo.createInstance<Person>(); tomReflectionInfo.setValues(person, {'name': 'John', 'age': 30});

Quick Start Requirements: - Maximum 3-5 steps - Each step has a clear heading - Code examples are complete and runnable - Include imports - Show the most common use case

5. Core Components

For each main class, provide:

## Core Components

### TomReflector

The `TomReflector` class extends `Reflectable` and is configured with the necessary
capabilities for reflection operations:

class TomReflector extends Reflectable { const TomReflector() : super.fromList(const [ invokingCapability, typingCapability, // ... ]); }


### TomReflectionInfo

The main class for reflection operations. Key methods:

| Method | Description |
|--------|-------------|
| `createInstance<T>()` | Create a new instance using default constructor |
| `setValues<T>(object, values)` | Set field values on an existing object |
| `getValues(object)` | Get all field values as a map |

Component Documentation Pattern: 1. One-sentence description 2. Brief explanation paragraph 3. Code example showing structure OR method table 4. Link to detailed section if complex

6. Feature Sections

Each major feature gets its own section with:

## TomZonedDateTime

Full date and time values. **Serialization prefix**: `@X@`

final tokyo = TomTimezone.fromName('Asia/Tokyo')!;

// Create with components final dt = TomZonedDateTime( year: 2024, month: 6, day: 15, hour: 14, minute: 30, timezone: tokyo, );

// Create from DateTime final now = TomZonedDateTime.fromDateTime(DateTime.now(), tokyo);

// Parse from string final parsed = TomZonedDateTime.parseFromString( '@X@2024-06-15T05:30:00.000Z_+09:00_Asia/Tokyo' );

// Check string format if (TomZonedDateTime.isTomZonedDateTimeString(input)) { ... }

Feature Section Pattern: 1. One-line description with key metadata (e.g., serialization prefix) 2. Code examples showing all common operations: - Creation (multiple ways) - Parsing - Validation - Key methods

7. Tables for Reference

Use tables for quick-reference information:

Method Tables

| Method | Description |
|--------|-------------|
| `createInstance<T>()` | Create a new instance using default constructor |
| `setValues<T>(object, values)` | Set field values on an existing object |

Type Tables

| Class | Wraps | Default Value |
|-------|-------|---------------|
| `TomString` | `String` | `""` |
| `TomInt` | `int` | `0` |
| `TomDouble` | `double` | `0.0` |

Operator Tables

| Operator | Usage | Description |
|----------|-------|-------------|
| `~` | `~observable` | Get the current value |
| `\|` | `observable \| value` | Set the value and notify |
| `>>` | `observable >> callback` | Add an observer callback |

Error Key Tables

| Error Key | Description |
|-----------|-------------|
| `reflector.instance_creation.failed` | Failed to create instance |
| `reflection.set.unexpected_type` | Unexpected value type during deserialization |

8. Error Handling Section

Structure:

## Error Handling

### TomTimezoneException

Thrown when timezone validation fails:

try { TomTimezone.findTimezone('America/New_York', 540); // +9:00 doesn't match NY } on TomTimezoneException catch (e) { print(e.defaultUserMessage); }


### Null Returns

Lookup methods return `null` for unknown values:

final tz = TomTimezone.fromName('Invalid/Zone'); // null final offset = TomTimezone.firstWithOffset(99999); // null


### Format Exceptions

Thrown when parsing fails:

try { TomZonedDateTime.parseFromString('invalid'); } on FormatException catch (e) { print(e.message); }


### Common Error Keys

| Error Key | Description |
|-----------|-------------|
| `timezone.not_found.name_offset_mismatch` | Name and offset don't match |

Required elements: 1. Each exception type with example 2. Table of common error keys 3. Safe pattern for handling (try-catch example)

9. Best Practices Section

Structure as actionable headings with code examples:

## Best Practices

### Use Local Accessors for Display

// Display: use local accessors print('${meeting.localHour}:${meeting.localMinute}'); // 14:30 (Tokyo time)

// Internal: UTC values print('${meeting.hour}:${meeting.minute}'); // 05:30 (UTC)


### Preserve Timezone in Serialization

// Good - preserves timezone final json = {'meeting_time': meeting.toString()};

// Avoid - loses timezone final json = {'meeting_time': meeting.toIso8601String()};


### Validate Before Parsing

if (TomZonedDateTime.isTomZonedDateTimeString(input)) { final dt = TomZonedDateTime.parseFromString(input); } else { // Handle invalid input }

Best Practice Pattern: 1. Action-oriented heading (verb phrase) 2. Brief explanation (optional) 3. Code example showing the recommended approach 4. Counter-example showing what to avoid (when helpful)

10. Class Hierarchy Section (if applicable)

Use ASCII tree diagrams:

## Class Hierarchy

TomObservable (base class) └── TomObject<T> ├── TomString, TomInt, TomDouble, TomBool, TomDateTime ├── TomNString, TomNInt, TomNDouble, TomNBool, TomNDateTime ├── TomOTimezoned<TZ> │ ├── TomOZonedTime, TomOZonedDate, TomOZonedDateTime │ └── TomNOTimezoned<TZ> │ └── TomNOZonedTime, TomNOZonedDate, TomNOZonedDateTime ├── TomClass (also implements TomObserver) │ └── TomDateRange, TomTimeRange, TomDateTimeRange ├── TomList<E> (also implements TomObserver, Iterable) └── TomMap<K, V> (also implements TomObserver)

11. Dependencies Section (if applicable)

## Dependencies

The observable system depends on:

- **`reflection.dart`**: `@tomReflector` annotation for `TomClass` reflection
- **`date_timestamp.dart`**: `TomZonedDate`, `TomZonedTime`, `TomZonedDateTime`
- **`tom_exception.dart`**: Base `TomException` class

### Required Import

import 'package:tom_core/tom_core.dart';

---

Code Example Standards

1. Complete and Runnable

Every code example should be complete enough to copy-paste and run:

// Good - includes import and context
import 'package:tom_core/tom_core.dart';

void main() {
  final tokyo = TomTimezone.fromName('Asia/Tokyo')!;
  final meeting = TomZonedDateTime(
    year: 2024, month: 6, day: 15, hour: 14,
    timezone: tokyo,
  );
  print(meeting.localHour); // 14
}

// Bad - missing context
final meeting = TomZonedDateTime(...);  // Where does this go?

2. Show Expected Output

Include comments showing expected results:

print(~name);           // "Jane"
print(meeting.localHour); // 14 (local time in Tokyo)
print(meeting.hour);      // 5 (UTC time)

3. Use Realistic Values

Use meaningful, realistic data in examples:

// Good - realistic data
final meeting = TomZonedDateTime(
  year: 2024, month: 6, day: 15, hour: 14, minute: 30,
  timezone: TomTimezone.fromName('Asia/Tokyo')!,
);

// Avoid - generic placeholder data
final meeting = TomZonedDateTime(year: 1, month: 1, day: 1, hour: 0);

4. Use Deterministic Values

Avoid DateTime.now() in examples - use fixed dates:

// Good - deterministic
final winter = DateTime.utc(2024, 1, 15);
final summer = DateTime.utc(2024, 7, 15);

// Avoid - non-deterministic
final now = DateTime.now();  // Different every time

5. Group Related Examples

When showing multiple creation methods, group them together:

// Create with components
final dt = TomZonedDateTime(year: 2024, month: 6, day: 15, timezone: tokyo);

// Create from DateTime
final now = TomZonedDateTime.fromDateTime(DateTime.now(), tokyo);

// Parse from string
final parsed = TomZonedDateTime.parseFromString('...');

---

Formatting Standards

1. Headings

  • # - Document title only (one per file)
  • ## - Major sections
  • ### - Subsections
  • #### - Sub-subsections (use sparingly)

2. Emphasis

  • Bold for class names in prose: "The TomReflector class..."
  • Backticks for inline code: "Use the >> operator..."
  • Italics for emphasis on concepts (rare)

3. Lists

Use unordered lists for features/options:

- **Timezone preservation**: Unlike `DateTime`, timezone context is preserved
- **Automatic DST handling**: UTC offsets are calculated correctly
- **Serialization**: Built-in string format preserves datetime and timezone

Use ordered lists for sequential steps:

1. Annotate your class with `@tomReflector`
2. Run `dart run build_runner build`
3. Import the generated `.reflectable.dart` file
4. Call `initializeReflectable()` in your main function

4. Code Blocks

Always specify the language:

// Dart code here

YAML configuration here

Shell commands here

5. Fenced Code for Serialization Formats

Use plain code blocks for showing format patterns:

{PREFIX}ISO8601_UTC_OFFSET_TIMEZONE

---

Length Guidelines

SectionTarget LengthMaximum
Title + Summary2-4 lines5 lines
Table of ContentsMatch sectionsN/A
Overview150-300 words400 words
Quick Start3-5 steps7 steps
Core Components50-100 words per class150 words
Feature Sections100-200 words + code300 words
Error Handling100-200 words300 words
Best Practices5-10 practices15 practices

Total document length: - Small modules: 300-500 lines - Medium modules: 500-800 lines - Large modules: 800-1100 lines

---

Checklist for New Documentation

  • [ ] File named {module_name}.md in module folder
  • [ ] Title follows "Tom {Name} System" pattern
  • [ ] One-paragraph summary immediately after title
  • [ ] Table of Contents with all sections linked
  • [ ] Overview explains components and value proposition
  • [ ] Quick Start has 3-5 numbered steps with complete code
  • [ ] Core Components section covers all main classes
  • [ ] Feature sections have code examples for all operations
  • [ ] Tables used for methods, types, operators, errors
  • [ ] Error Handling covers all exception types
  • [ ] Best Practices has 5+ actionable recommendations
  • [ ] All code examples are complete and show expected output
  • [ ] No DateTime.now() or non-deterministic values in examples
  • [ ] Imports included in code examples where needed
  • [ ] Consistent heading hierarchy (no skipped levels)
  • [ ] Markdown code blocks specify language

---

Maintenance Guidelines

When to Update Documentation

1. New public API - Add to relevant section 2. Breaking changes - Update examples and add migration notes 3. New best practices discovered - Add to Best Practices 4. Common user errors identified - Add to Error Handling 5. New use cases - Add examples to relevant sections

Documentation Review Checklist

  • [ ] All public classes/methods documented
  • [ ] Examples still compile and run
  • [ ] Output comments match actual output
  • [ ] Links in Table of Contents work
  • [ ] No outdated API references
  • [ ] Consistent with actual code behavior