Files
WhatIDo/AGENTS.md

7.2 KiB

AGENT.md — Developer Agent Guidelines for WhatIDo

This document defines how AI agents should work with the WhatIDo codebase. Follow these rules strictly.


Project Overview

WhatIDo — Accounting system for an educational center: attendance journal, student project works, group gallery, detached files, and public showcase pages (share links).

  • Stack: Node.js 20 + Express, PostgreSQL 16, Docker Compose, Tailscale (Serve/Funnel)
  • Architecture: Single Express server (server.js) + static frontend in public/
  • Deployment: Docker Compose (app + db + tailscale), bind-mounted uploads, named volume for Postgres data
  • Auth: Admin-only via X-Admin-Token header (value = ADMIN_PASSWORD env var). No user sessions.

Development Rules

1. Code Style

  • No comments unless explicitly requested
  • ES modules not used — CommonJS (require) throughout
  • Error handling: try/catch with explicit status codes, no global error handler
  • Validation: Inline helper functions (reqInt, reqStr, optInt, etc.) — use them
  • Security first: All uploads validated, path traversal blocked, rate limits on public routes

2. Database

  • Schema: Defined in db/init.sql (runs on first container start)
  • Migrations: db/migration.sql for existing DBs — update both when changing schema
  • Connection: Single Pool from pg, DATABASE_URL from env
  • Queries: Parameterized only ($1, $2...), never string interpolation
  • Transactions: Use client.query('BEGIN') / COMMIT / ROLLBACK for multi-statement ops

3. File Uploads

  • Multer configs: upload (images only), adminUpload (wider allowed ext), uploadBackup (restore)
  • Limits: 10 MB/file, 30 MB total per entry
  • Storage: uploads/ bind-mounted to host, filenames = timestamp-random.ext
  • HEIC: Auto-converted to JPEG via heic-convert
  • Cleanup: safeUnlink / sweepOrphanedUploads — never delete outside uploads/

4. API Patterns

  • Admin routes: requireAdmin middleware (checks X-Admin-Token)
  • Public routes: apiLimiter (300/15min), entryLimiter (10/15min), fileLimiter (300/15min)
  • Responses: JSON, { error: 'message' } on failure, data directly on success
  • Pagination: limit / offset query params, return { items, total } or { entries, total }
  • Filters: group_id, date_from, date_to, student_name, search, deleted

5. Frontend (public/)

  • Vanilla HTML/CSS/JS, no build step
  • Each page = single HTML file + shared admin.js / admin.css
  • API calls via fetch with X-Admin-Token from localStorage
  • Share pages (share.html, links.html) work without auth

6. Docker / Compose

  • Dockerfile: Node 20 Alpine, installs deps, generates self-signed TLS cert
  • docker-compose.yml: 3 services (db, app, tailscale)
    • db: postgres:16-alpine, healthcheck, init.sql mounted
    • app: builds from Dockerfile, exposes 3003/3443, mounts uploads
    • tailscale: host network, NET_ADMIN, runs start-tailscale.sh (funnel to 127.0.0.1:3443)
  • Env vars (required): ADMIN_PASSWORD, DB_PASSWORD
  • Port 443 on host must be free (tailscale listens directly)

7. Tailscale Publication

  • No external IP / port forwarding needed
  • Access: https://whatido.<tailnet>.ts.net (inside tailnet + internet via Funnel)
  • First run: docker exec -it whatido-tailscale-1 tailscale up --hostname=whatido → authorize in browser
  • Enable Serve/Funnel in Tailscale admin console for the node
  • Cert: app generates self-signed cert at build (certs/cert.pem), mounted into tailscale container

8. Backup / Restore

  • Admin UI: /api/backup (download tar.gz), /api/restore (upload tar.gz)
  • Scripts: scripts/backup.sh, scripts/restore.sh (host-level)
  • Backup format: data.json (all tables) + uploads/ directory
  • Restore validates all data, resets sequences, sweeps orphans

Common Tasks

Add a new API endpoint

  1. Add route in server.js (group with related routes)
  2. Use requireAdmin for admin, apiLimiter/fileLimiter for public
  3. Validate input with helper functions
  4. Use parameterized queries, transactions if multi-table
  5. Call logAudit(req, 'action.name', { ... }) for mutations
  6. Return JSON, handle errors with appropriate status codes

Add a database column/table

  1. Update db/init.sql (CREATE TABLE / ALTER TABLE)
  2. Update db/migration.sql (idempotent ALTERs)
  3. Update server.js queries that SELECT/INSERT the table
  4. Test: docker compose down && docker compose up -d --build

Add a frontend page

  1. Create public/newpage.html (copy structure from existing)
  2. Link in public/admin.html navigation if admin page
  3. Use admin.js utilities: api(), requireAuth(), formatDate(), etc.
  4. No build step — just refresh browser

Modify file upload rules

  • Edit BLOCKED_EXT, ALLOWED_IMAGE_EXT, ADMIN_ALLOWED_EXT constants
  • Update Multer fileFilter functions
  • Keep MAX_TOTAL_UPLOAD_BYTES and per-file limit in sync

Testing & Verification

No automated test suite exists. Verify manually:

# Start stack
docker compose up -d --build

# Check logs
docker compose logs -f app

# Test API (replace TOKEN)
curl -H "X-Admin-Token: $ADMIN_PASSWORD" http://localhost:3003/api/groups

# Run backup/restore scripts
./scripts/backup.sh
./scripts/restore.sh backups/whatido-backup-<date>.tar.gz

Security Checklist (before any change)

  • No SQL interpolation — only $1, $2...
  • Upload path validation via isSafeUploadPath / safeUnlink
  • Rate limiter on new public routes
  • Admin routes behind requireAdmin
  • No secrets in code — only via env vars
  • Helmet headers present (already global)
  • CORS disabled (no cors middleware)

File Map (key files)

File Purpose
server.js Entire backend (Express, routes, DB, uploads, backup)
worker.js Background AI auto-check worker for entry messages
db/init.sql Initial schema (runs on fresh DB)
db/migration.sql Idempotent migrations for existing DBs
docker-compose.yml Service definitions (app, db, tailscale)
Dockerfile App image build
public/*.html Frontend pages
public/admin.js Shared frontend logic
scripts/backup.sh Host-level backup script
scripts/restore.sh Host-level restore script
start-tailscale.sh Tailscale container entrypoint
.env.example Env var template

Do Not

  • ❌ Add dependencies without updating package.json and rebuilding
  • ❌ Write files outside uploads/ or certs/
  • ❌ Commit .env, certs/, uploads/, backups/, node_modules/
  • ❌ Expose DB port (5432) outside docker network
  • ❌ Use eval, Function constructor, or dynamic code execution
  • ❌ Add comments to code (this file excepted)

Quick Commands

# Full rebuild
docker compose down && docker compose up -d --build

# App logs
docker compose logs -f app

# DB shell
docker compose exec db psql -U app -d whereldo

# Tailscale status
docker exec -it whatido-tailscale-1 tailscale status

# Manual funnel restart
docker exec whatido-tailscale-1 tailscale funnel --bg --yes https://127.0.0.1:3443