Compare commits

...

5 Commits

Author SHA1 Message Date
Paul Huliganga afdc915aa2 fix(backend): remove require() usage in ESM database saver
Use writeFileSync import instead of require('fs') to avoid runtime
ReferenceError in Node ESM mode during periodic DB saves.
2026-03-24 20:04:28 -04:00
Paul Huliganga e6d6d3f776 docs(readme): add setup and production deployment instructions for MVP 2026-03-24 18:51:59 -04:00
Paul Huliganga c885381d3a docs(user-guide): add MVP user guide and mark task complete 2026-03-24 18:41:43 -04:00
Paul Huliganga ce839e3ce1 docs(api): add initial API documentation for all endpoints (MVP) 2026-03-24 18:06:35 -04:00
Paul Huliganga 1a4b984d2c chore(devops): mark 'Test local deployment' as blocked (no Docker in environment) 2026-03-24 17:52:50 -04:00
5 changed files with 318 additions and 41 deletions

View File

@ -61,20 +61,35 @@ npm run dev:frontend
npm test
```
### Production Deployment
### Production Setup & Deployment
1. **Build and start containers** (from project root):
```bash
# Build and start containers
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down
```
Access at `http://localhost:3000` (or `https://recipes.paje.ca` in production).
2. **Check running services:**
```bash
docker-compose ps
```
3. **View container logs:**
```bash
docker-compose logs -f
```
4. **Access the app:**
- Frontend: http://localhost:8080 (default)
- Backend API: http://localhost:3000
5. **Stop services:**
```bash
docker-compose down
```
---
@ -139,8 +154,8 @@ recipe-manager/
- [Architecture Guide](ARCHITECTURE.md) — Technical decisions & patterns
- [Roadmap](ROADMAP.md) — Planned features & milestones
- [Agent Instructions](AGENT_INSTRUCTIONS.md) — How AI agents contribute
- [API Docs](docs/api.md) — Endpoint reference *(coming soon)*
- [User Guide](docs/user-guide.md) — How to use the app *(coming soon)*
- [API Docs](docs/api.md) — Endpoint reference
- [User Guide](docs/user-guide.md) — How to use the app
---

30
TODO.md
View File

@ -7,36 +7,12 @@
## 🎯 Active Tasks
### Backend Setup
- [x] Initialize Node.js backend: Create src/backend/, package.json with express, better-sqlite3, zod, vitest. Create src/backend/index.ts with "Hello World" server on port 3000. Verify: npm install && npm run dev (server starts). Commit as "feat(backend): initialize Node.js project with Express"
- [x] Set up TypeScript: Create tsconfig.json (strict mode, ES2022, Node16 module resolution). Add build script to package.json. Verify: npm run build succeeds. Commit.
- [x] Create SQLite schema: Create src/backend/db/schema.sql with recipes, tags, recipe_tags tables per ARCHITECTURE.md. Create src/backend/db/migrate.ts to apply schema using sql.js (see ADR-001). Verify: npm run migrate creates data/recipes.db. Commit.
- [x] Implement recipe CRUD API endpoints
- [x] Add Zod validation schemas
- [x] Write API integration tests
### Frontend Setup
- [x] Initialize React + Vite project
- [x] Configure Tailwind CSS
- [x] Set up React Router
- [x] Create recipe list page
- [x] Create recipe detail/edit page
- [x] Implement cook mode UI
### Features
- [x] Tag management (create, assign, filter)
- [x] Text search (title + ingredients)
- [x] Basic error handling + loading states
### DevOps
- [x] Create Dockerfile for backend
- [x] Create Dockerfile for frontend (nginx)
- [x] Write docker-compose.yml
- [ ] Test local deployment
- [ ] Test local deployment *(Unable to run `docker compose up` in environment: docker is unavailable. Manual test required on host.)*
### Documentation
- [ ] Write API documentation (docs/api.md)
- [ ] Create user guide (docs/user-guide.md)
- [x] Write API documentation (docs/api.md)
- [x] Create user guide (docs/user-guide.md)
- [ ] Add setup instructions to README
- [ ] Document first architecture decisions (ADRs)

142
docs/api.md Normal file
View File

@ -0,0 +1,142 @@
# API Documentation — Recipe Manager
**Base URL:** `/api`
---
## Authentication
No authentication required for MVP (local/private use). Consider adding in v1.0.
---
## Endpoints
### Recipe Endpoints
#### List Recipes
- **GET `/api/recipes`**
- Query params:
- `search` *(string, optional)*: Filter recipes by title, description, or ingredients substring
- `offset` *(integer, optional)*: Pagination offset (default: 0)
- `limit` *(integer, optional)*: Pagination limit (default: 20)
- Returns: `{ recipes: Recipe[], total: number }`
#### Get Single Recipe
- **GET `/api/recipes/:id`**
- Path param: `id` (number)
- Returns: `{ recipe: Recipe }`
#### Create Recipe
- **POST `/api/recipes`**
- Body:
```json
{
"title": "Chocolate Cake",
"ingredients": ["2 cups flour", "1 cup sugar"],
"instructions": ["Mix dry ingredients", "Bake at 350°F for 30 min"],
"tags": [1, 2], // optional tag IDs
"servings": 8, // optional
"sourceUrl": "https://foosite.com/recipe", // optional
"notes": "Best with dark chocolate"
}
```
- Returns: `{ recipe: Recipe }`
#### Update Recipe
- **PUT `/api/recipes/:id`**
- Body: Same as POST
- Returns: `{ recipe: Recipe }`
#### Delete Recipe
- **DELETE `/api/recipes/:id`**
- Returns: `{ success: true }`
---
### Tag Endpoints
#### List Tags
- **GET `/api/tags`**
- Returns: `{ tags: Tag[] }`
#### Create Tag
- **POST `/api/tags`**
- Body:
```json
{ "name": "Dessert" }
```
- Returns: `{ tag: Tag }`
#### Update Tag
- **PUT `/api/tags/:id`**
- Body: `{ "name": "Lunch" }`
- Returns: `{ tag: Tag }`
#### Delete Tag
- **DELETE `/api/tags/:id`**
- Returns: `{ success: true }`
#### Assign Tag to Recipe
- **POST `/api/tags/recipes/:id/tags`
- Body: `{ "tagId": 1 }`
- Returns: `{ success: true }`
#### Remove Tag from Recipe
- **DELETE `/api/tags/recipes/:id/tags`
- Body: `{ "tagId": 1 }`
- Returns: `{ success: true }`
---
## Data Models
### Recipe
```ts
interface Recipe {
id: number;
title: string;
description?: string;
ingredients: string[];
instructions: string[];
servings?: number;
tags?: Tag[];
sourceUrl?: string;
notes?: string;
createdAt: string; // ISO date
updatedAt: string; // ISO date
}
```
### Tag
```ts
interface Tag {
id: number;
name: string;
}
```
---
## Errors
Responses follow the pattern:
```json
{
"success": false,
"error": "Description of error"
}
```
Validation errors will return HTTP 400 with detailed messages.
---
## Versioning
Current version: MVP v0.1 (2026-03-24)
Future versions may introduce breaking API changes (see ROADMAP.md).
---
_Last updated: 2026-03-24_

144
docs/user-guide.md Normal file
View File

@ -0,0 +1,144 @@
# Recipe Manager User Guide
This guide explains how to use Recipe Manager for day-to-day cooking and recipe organization.
## What You Can Do
- Add recipes manually
- Edit or delete recipes
- Organize recipes with tags
- Search recipes by text
- Use Cook Mode with step and ingredient checklists
---
## Getting Started
1. Open Recipe Manager in your browser.
2. From the home page (`Recipes`), click **+ New Recipe** to create your first recipe.
---
## Create a Recipe
1. Click **+ New Recipe**.
2. Fill in the required fields:
- **Title**
- **Ingredients** (one per line)
- **Instructions** (one step per line)
3. Optionally add:
- Description
- Source URL
- Notes
- Servings
- Prep time and cook time
- Tags
4. Click **Save Recipe**.
### Tips
- Keep ingredient lines simple (example: `2 cups flour`).
- Keep instruction steps short and clear for easier Cook Mode tracking.
---
## Browse and Search Recipes
On the **Recipes** page you can:
- Scroll through recipe cards
- Use the search box to find recipes by title, description, or ingredient text
- Click **Load More** to view additional recipes when available
---
## View, Edit, and Delete a Recipe
1. Click a recipe card to open details.
2. Use **Edit** to update any fields.
3. Use **Delete** to remove the recipe permanently.
> Deleting a recipe cannot be undone.
---
## Manage Tags
Tags help you group recipes (for example: `Dinner`, `Dessert`, `Quick`, `Vegetarian`).
### Add tags to a recipe
1. Open a recipe detail page.
2. Edit the recipe.
3. Select existing tags (or create new ones if available in the tag selector).
4. Save changes.
### Remove tags
- Edit the recipe and deselect the tag, then save.
---
## Cook Mode
Cook Mode is designed for active cooking:
1. Open a recipe.
2. Click **Cook Mode**.
3. Check off ingredients as you prep.
4. Check off instruction steps as you complete them.
5. Follow progress indicators until complete.
### Screen Stay Awake
Cook Mode uses your browsers Wake Lock support (when available) to keep your screen on while cooking.
If wake lock is not supported, the app still works normally.
---
## Troubleshooting
### I cant save a recipe
- Make sure title, ingredients, and instructions are not empty.
- Check for network/server errors and try again.
### I dont see my latest changes
- Refresh the page.
- Verify the save completed successfully (look for confirmation toast).
### Search is not finding a recipe
- Try a simpler keyword from title, description, or ingredient lines.
- Confirm the recipe was saved.
---
## Keyboard and Mobile Usage
- The interface works on desktop and mobile browsers.
- In Cook Mode, controls are touch-friendly for kitchen use.
---
## Privacy and Data
Recipe Manager is self-hosted for household use.
- Your recipe data is stored in your own deployment database.
- No external recipe-sharing account is required for MVP use.
---
## MVP Feature Notes
Current MVP includes core recipe CRUD, search, tags, and cook mode.
Planned future features include:
- Recipe web scraping/import
- Advanced filtering
- Serving-size scaling
- Print-friendly layouts

View File

@ -1,5 +1,5 @@
import initSqlJs, { Database } from 'sql.js';
import { readFileSync, existsSync, mkdirSync } from 'fs';
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
import { dirname } from 'path';
let dbInstance: Database | null = null;
@ -55,7 +55,7 @@ export function saveDatabase(dbPath: string = 'data/recipes.db'): void {
}
// Write to disk
require('fs').writeFileSync(dbPath, buffer);
writeFileSync(dbPath, buffer);
}
/**