Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Dependencies
node_modules/

# Build artifacts
dist/
build/

# Environment files
.env
.env.local
.env.*.local

# Editor directories and files
.vscode/
.idea/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Temporary files
tmp/
temp/

# iOS build artifacts
ios/build/
ios/DerivedData/
ios/*.xcworkspace/xcuserdata/
ios/Pods/
ios/*.xcarchive
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 ObservationTracker Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,49 @@
# ObservationTracker
# ObservationTracker

A personal nature observation journal — log birds, plants, insects, and more from your browser.

## Features

- **Log observations** in under 30 seconds — date, time, category, species, count, location, and notes
- **Browse and filter** your observations by category, date range, or keyword search
- **Map view** showing geolocated observations on an OpenStreetMap (requires GPS coordinates)
- **Statistics** — totals, category breakdown, monthly charts, and top species
- **Export / import** observations as JSON for backup and transfer
- **Offline-first** — works entirely in the browser with no account or backend required

## Project Structure

```
ObservationTracker/
├── docs/ Project documentation
├── web/ Web application (vanilla JS SPA)
└── ios/ iOS app (planned — see docs/Milestones.md)
```

See [`docs/Repository.md`](docs/Repository.md) for the full directory map.

## Quick Start

1. Clone or download the repository
2. Open `web/index.html` in a modern browser (Chrome, Firefox, Safari, or Edge)

No build step or dependencies required.

## Documentation

| File | Contents |
|---|---|
| [`docs/Vision.md`](docs/Vision.md) | Why the project exists |
| [`docs/Requirements.md`](docs/Requirements.md) | Functional and non-functional requirements |
| [`docs/Architecture.md`](docs/Architecture.md) | Layer diagram and technology choices |
| [`docs/UX.md`](docs/UX.md) | Screen designs and interaction patterns |
| [`docs/DesignSystem.md`](docs/DesignSystem.md) | Colors, typography, spacing |
| [`docs/DataModel.md`](docs/DataModel.md) | Data schemas and localStorage details |
| [`docs/CodingStandards.md`](docs/CodingStandards.md) | Code style rules |
| [`docs/Milestones.md`](docs/Milestones.md) | Roadmap and planned releases |
| [`docs/DecisionLog.md`](docs/DecisionLog.md) | Architectural decisions with rationale |
| [`docs/AIInstructions.md`](docs/AIInstructions.md) | Guidelines for AI coding assistants |

## License

MIT — see [LICENSE](LICENSE).
68 changes: 68 additions & 0 deletions docs/AIInstructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# AI Instructions

Instructions for AI coding assistants (GitHub Copilot, Cursor, etc.) working on this codebase.

## Project Context

ObservationTracker is a client-side SPA for logging nature observations. It uses vanilla JavaScript ES2020+, plain CSS, and localStorage. There is no build step, no bundler, and no backend. See `Architecture.md` for the full layer diagram.

## Code Conventions

- Follow all rules in `CodingStandards.md`
- Use 2-space indentation, single quotes, no semicolons
- Prefer `const` over `let`; never use `var`
- Use `async`/`await` instead of `.then()` chains
- Use optional chaining (`?.`) and nullish coalescing (`??`) where appropriate

## File Patterns

- Each screen exports a default `render(container)` function
- Each component exports a factory function that returns an HTML string or DOM element
- The repository layer (`web/repository/`) handles all localStorage access
- Services (`web/services/`) contain business logic only — no DOM, no localStorage direct access
- Utils (`web/utils/`) contain pure functions only

## Styling Rules

- Use CSS custom properties from the `:root` block in `styles.css`
- Never hardcode color values — always reference a `--color-*` token
- Use BEM naming: `.block`, `.block__element`, `.block--modifier`
- Do not add `!important`

## What NOT to Do

- Do not add npm packages or a `package.json`
- Do not add a build/bundle step
- Do not use `document.write()`
- Do not use jQuery or other DOM libraries
- Do not store sensitive user data; do not add any analytics or tracking code
- Do not add backend endpoints or fetch calls to external APIs (except map tile CDN and species CDN if approved)

## Testing

Currently there is no automated test suite. Manual testing is done by opening `web/index.html` in a browser. When adding functionality, verify:
1. The happy path works as expected
2. Validation rejects invalid inputs with a clear error message
3. The UI is usable at 375px viewport width
4. No JavaScript errors appear in the browser console

## Adding a New Screen

1. Create `web/screens/MyNewScreen.js` with a default-exported `render(container)` function
2. Add the route in `app.js` router map
3. Add the nav item in `web/components/NavBar.js`
4. Document any new data fields in `docs/DataModel.md`

## Adding a New Component

1. Create `web/components/MyComponent.js`
2. Export a factory function: `export function myComponent(props) { return '<html string>' }`
3. Import and use it in the relevant screen

## Commit Messages

Use Conventional Commits format:
- `feat: add photo attachment to observation form`
- `fix: prevent duplicate observations on double-tap`
- `docs: update DataModel.md with photoDataUrl field`
- `chore: update categories.json with new species list`
82 changes: 82 additions & 0 deletions docs/Architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Architecture

## Overview

ObservationTracker v1 is a client-side Single Page Application (SPA) built with vanilla JavaScript, HTML5, and CSS. There is no backend; all data is stored in the browser's `localStorage`.

## Layer Diagram

```
┌──────────────────────────────────────────────────┐
│ Screens (UI) │
│ Home │ LogObservation │ MyObservations │ Map │ Stats │
├──────────────────────────────────────────────────┤
│ Components (UI) │
│ NavBar │ ObservationCard │ Modal │ FilterBar │ Chart │
├──────────────────────────────────────────────────┤
│ Services │
│ ObservationService │ LocationService │ ExportService │
├──────────────────────────────────────────────────┤
│ Repository │
│ ObservationRepository │
├──────────────────────────────────────────────────┤
│ Storage │
│ localStorage │
└──────────────────────────────────────────────────┘
```

## Module Descriptions

### Screens
Located in `web/screens/`. Each screen is a JavaScript module that exports a `render(container)` function responsible for injecting HTML into the main content area and binding event listeners.

### Components
Located in `web/components/`. Reusable UI fragments used by screens. Each component exports a factory function that returns a DOM element or HTML string.

### Services
Located in `web/services/`. Business logic layer. Services call the repository for data and apply domain rules before returning results to screens.

### Repository
Located in `web/repository/`. Handles all reads and writes to `localStorage`. Serializes/deserializes model objects. Provides simple CRUD operations.

### Models
Located in `web/models/`. Plain JavaScript objects (POJOs) with factory functions. No framework classes.

### Utils
Located in `web/utils/`. Stateless helper functions for date formatting, string manipulation, validation, and geolocation.

### Data
Located in `web/data/`. Static JSON reference files (species lists, category definitions).

## Routing

The app uses hash-based routing (`window.location.hash`). The router in `app.js` maps hash fragments to screen modules and calls their `render()` functions on navigation.

| Route | Screen |
|---|---|
| `#/` or `#/home` | Home |
| `#/log` | LogObservation |
| `#/observations` | MyObservations |
| `#/map` | Map |
| `#/stats` | Statistics |

## Data Flow

1. User triggers action in a Screen
2. Screen calls a Service method
3. Service applies business rules and calls Repository
4. Repository reads/writes localStorage
5. Repository returns model object(s) to Service
6. Service transforms if needed and returns to Screen
7. Screen re-renders the updated portion of the DOM

## Technology Choices

| Concern | Choice | Rationale |
|---|---|---|
| Language | Vanilla JS (ES2020) | No build step, no dependencies |
| Styling | Plain CSS with custom properties | Simple, no preprocessor needed |
| Storage | localStorage | Offline, no backend, sufficient for personal data volume |
| Mapping | Leaflet.js (CDN) | Lightweight, open-source, works offline with tiles cached |
| Charts | Chart.js (CDN) | Simple, well-documented, small footprint |
| Icons | Inline SVG | No external font dependency |
73 changes: 73 additions & 0 deletions docs/CodingStandards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Coding Standards

## Language

- Use ES2020+ features (optional chaining, nullish coalescing, `const`/`let`, arrow functions, template literals, destructuring, `async`/`await`)
- No TypeScript in v1 — use JSDoc comments for type hints if needed
- No build step, no bundler — code must run directly in modern browsers without transpilation

## Module System

- Use native ES Modules (`import`/`export`) via `<script type="module">` in `index.html`
- One module per file
- Default export for the primary screen/component/class; named exports for utilities and factories

## File Naming

- **PascalCase** for screen and component files: `HomeScreen.js`, `ObservationCard.js`
- **camelCase** for utility, service, and repository files: `date.js`, `observationService.js`
- **camelCase** for JSON data files: `categories.json`, `species.json`

## Code Style

- 2-space indentation
- Single quotes for strings
- No semicolons (ASI-safe style)
- Maximum line length: 100 characters
- Trailing commas in multi-line arrays and objects

## Functions

- Prefer pure functions in utils
- Keep functions short (< 30 lines); extract helpers for clarity
- Avoid deeply nested callbacks — use `async`/`await`

## DOM Manipulation

- Screens render HTML by setting `innerHTML` of the container element
- After initial render, use `querySelector` within the screen container (not global `document`)
- Bind event listeners after inserting HTML into the DOM
- Clean up event listeners on screen teardown if they are attached to `window` or `document`

## CSS

- Use CSS custom properties (design tokens) from `:root` — do not hardcode colors or sizes
- Use BEM-style class names: `.block`, `.block__element`, `.block--modifier`
- Media queries use `min-width` (mobile-first)
- No `!important`

## Error Handling

- Wrap localStorage operations in try/catch; log errors to `console.error`
- Display user-facing errors via the Toast component, not `alert()`
- Validate inputs before saving (use `web/utils/validation.js`)

## Comments

- Comment the *why*, not the *what*
- JSDoc for exported functions:

```js
/**
* Creates a new Observation object with a generated id and timestamps.
* @param {Partial<Observation>} fields
* @returns {Observation}
*/
export function createObservation(fields) { ... }
```

## Git

- Commit messages follow Conventional Commits: `feat:`, `fix:`, `docs:`, `chore:`
- Each commit should be a logical, working unit of change
- Do not commit `.DS_Store`, editor config, or `node_modules`
Loading