Add explicit guideline specifying 2-space indentation for all code files unless the language prohibits it. This ensures consistent formatting across the entire codebase and prevents debates about tab vs space preferences. The guideline is placed in the General section alongside other coding convention rules to maintain consistency in project standards.
19 KiB
19 KiB
Combined Project Guidelines for Bookhoard
🚨 CRITICAL PROHIBITIONS (Never violate these)
Backend & Database
- ❌ NEVER modify backend code when working on frontend-only tasks
- ❌ NEVER modify database schema unless explicitly instructed for full-stack changes
- ❌ NEVER use Docker - use Podman only
- ❌ NEVER build server binaries locally - all builds through Dockerfile/docker-compose
- ❌ NEVER create new migration files - merge changes into current one until release
- ❌ NEVER use
git checkouton schema files without checking what will be lost - ❌ NEVER break existing functionality unless explicitly instructed
- ❌ NEVER duplicate business logic - keep logic in services, not handlers
- ❌ NEVER bypass service layer - all database operations must go through services
Testing
- ✅ ALWAYS use
setupTestServer()helper fromcmd/server/tests/test_helpers.go - ✅ Share one test setup across all subtests - call
setupTestServer()once at test function level, not per subtest - ✅ Prefer table-driven tests - use
t.Run()with test cases instead of duplicate test functions - ✅ Configure database pools efficiently - use
max_conns=1for test pools (viapgxpool.ParseConfig()) to prevent connection exhaustion - ❌ NEVER create separate
pgxpoolper test - each pool creates 4 connections by default; 78 tests = 312 potential connections > PostgreSQL's 100 limit - ❌ NEVER call
setupTestServer()in loops or within subtests - creates unnecessary database pools and exhausts connections - ✅ DO verify tests pass - run full test suite before completing work
- ✅ Use
t.Cleanup()properly - theTestServerSetuppattern automatically handles cleanup viat.Cleanup()
Frontend & Styling
- ❌ NEVER modify backend/API for frontend features without user confirmation
- ❌ NEVER use custom CSS - TailwindCSS classes only
- ⚠️ EXCEPTION:
templates/error.templmay have inline CSS because error pages must work when main app fails (404, server errors, CSS fails to load)
- ⚠️ EXCEPTION:
- ❌ NEVER use JavaScript - convert all to TypeScript
- ⚠️ EXCEPTION: Inline JS function calls in HTML attributes (e.g.,
onclick="myFunction()") are acceptable for simple interactions
- ⚠️ EXCEPTION: Inline JS function calls in HTML attributes (e.g.,
- ❌ NEVER use Object-Oriented Programming (no classes, inheritance, or this-capture)
- ✅ DO use procedural/imperative style as your default
- ✅ DO borrow functional techniques when they simplify code
- ✅ DO avoid ideological purity - the best paradigm is the one that fits the problem
- ❌ NEVER add new Dockerfiles without user confirmation
- ❌ NEVER fetch initial data via AJAX on page load - use server-side rendering instead
- ❌ NEVER break progressive enhancement - pages must work without JavaScript
Note: Go methods in the backend are fine and encouraged. This guideline applies to TypeScript/JavaScript frontend code only.**
General
- ❌ NEVER skip pre-commit hooks unless explicitly requested
- ❌ NEVER force push to main/master branches
- ❌ NEVER commit files with secrets (.env, credentials.json, etc.)
- ❌ NEVER make assumptions - ask clarifying questions when uncertain
- ❌ NEVER delete code without reading full context first (minimum 20 lines before/after)
- ❌ NEVER make cascading fix-up edits without git diff review
- After compilation error: STOP, review
git diff, understand full impact - Use revert/reapply pattern instead of blind fixes
- After compilation error: STOP, review
- ❌ NEVER skip post-edit verification - must compile after each file edit
- ❌ NEVER run git commands concurrently - always run sequentially:
- Run
git add <files>and wait for completion - Run
git commit -m "<message>"and wait for completion - Run
git pushand wait for completion - Never use
&&to chain git commands together
- Run
- ✅ Make good organized git commits for the entire project (not just what you changed) and push - run git add, commit, push sequentially as separate commands, no need to repeatedly check status
- ✅ Indentation is always 2 spaces unless the language prohibits it
Cascading Fix-up Pattern (PROHIBITED)
WHAT NOT TO DO - This caused critical bugs:
// ❌ WRONG: Blindly making fixes after compilation error
Edit 1: Delete deprecated code
[Compilation error: undefined Register]
Edit 2: Try to fix error (over-broad deletion)
[More errors: undefined Login, GetProfile, etc.]
Edit 3: Try to fix again (worse damage)
[Even more errors: major functionality broken]
CORRECT APPROACH:
// ✅ CORRECT: Stop, understand, then fix deliberately
Edit 1: Delete deprecated code
[Compilation error: undefined Register]
STOP → Review git diff → Understand Register was accidentally deleted
RESTORE → Get exact Register function from git history
VERIFY → Compile successfully
Key Principle: When compilation errors occur after edits:
- STOP - Don't make more edits
- ANALYZE - Use
git diffto understand what was changed - RECOVER - Restore what was accidentally deleted/broken
- VERIFY - Compile and test before proceeding
🎯 CONTEXT-SPECIFIC RULES
When Working on Frontend-Only Tasks
- DO NOT touch backend code - handlers, services, database layer
- DO NOT modify API routes - use existing endpoints only
- DO NOT change database schema - work with existing structure
- If backend change seems necessary:
- Identify the required change
- Explain why you need it
- Provide impact analysis
- ASK FOR USER CONFIRMATION before proceeding
When Working on Full-Stack Tasks
- Backend changes are allowed when explicitly part of the task
- Still follow all database protocols (atomic changes, validation, etc.)
- If modifying database schema: Update local database after schema.sql changes (see Database Operations section)
- Still use Podman for all builds
- Still include Bruno tests for API changes
✅ MANDATORY REQUIREMENTS
Database Operations (Full-Stack Tasks Only)
- ✅ Follow pgx v5 standards for all database operations
- ✅ Treat schema changes as ATOMIC - complete success or complete rejection
- ✅ ⚠️ CRITICAL: This is a pre-production application (NO production deployments exist)
- When
database/schema/schema.sqlis updated, local databases must be updated - Option 1 (Recommended): Recreate database with fresh schema:
podman compose down -v # Delete volumes (WARNING: loses all data) podman compose up -d # Start fresh with new schema - Option 2: Manually apply schema changes to existing database using psql
- DO NOT create migration files - no legacy schema support needed
- When
- ✅ Use pre-change checklist: read schema → identify columns → plan changes → verify → read back
- ✅ Post-change validation: ensure schema.sql, models.go, and queries.sql are in sync
Build & Deployment
- ✅ Use Podman exclusively (not Docker)
- ✅ All builds through existing Dockerfile and docker-compose.yml
- ✅ Stop building server binaries - everything goes through containers
API Changes (Full-Stack Tasks Only)
- ✅ Include Bruno OpenCollection YAML requests with all API documentation
- ✅ Tests must be comprehensive and cover three contexts: no user, user, and admin
- ✅ Maintain backward compatibility for mobile apps and external consumers
Frontend & Styling
- ✅ Always use TailwindCSS classes for all styling
- ✅ Convert all JavaScript to TypeScript
- ✅ Never use Object-Oriented Programming (no classes, inheritance, or this-capture)
- ✅ Use procedural/imperative style as your default
- ✅ Borrow functional techniques when they simplify code
- ✅ Avoid ideological purity - the best paradigm is the one that fits the problem
- ✅ Extract domain concepts/types only when clearly beneficial - apply YAGNI, avoid over-engineering
- ✅ Render initial data server-side in Go templates for fast page loads
- ✅ Use JavaScript/HTMX for CRUD operations (create, update, delete)
- ✅ Ensure progressive enhancement - pages work without JavaScript
Service Layer Architecture
- ✅ All business logic in services - never in handlers
- ✅ Services must be reusable by both SSR handlers and API endpoints
- ✅ Database operations through services only - never direct from handlers
- ✅ When adding features: Add service logic → Create API endpoint → Use SSR for initial render → Use JS for updates
Code Organization
- ✅ Minimize project structure changes
- ✅ Place new files in contextually appropriate directories
- ✅ Follow KISS, DRY, and YAGNI principles
- ✅ Use multiple, logical git commits with clear messages
- ❌ NEVER duplicate types between handlers and templates - define data types in handlers, reuse directly in templates
- ✅ DO share handler types with templates - templates should use handlers.CollectionData, handlers.BookInfo, etc. directly
- ❌ NEVER create parallel type systems - no templates.XxxData types for data that originates from handlers
- ✅ DO enhance handler types with template-specific fields when needed (e.g., add Icon, FormattedDate fields to handlers structs)
- ✅ DO keep template-only types in templates package - PageData, UnsafeHTML, and template-specific utilities are appropriate
- ❌ NEVER create conversion helper functions to map between handler and template types - use handler types directly
Configuration & Environment
- ✅ If .env is missing, auto-generate secure values
- ✅ Never commit secrets to repository
Code Modification Safety
- ✅ Post-Edit Verification (MANDATORY for ALL file modifications):
- Run
go buildfor affected packages immediately after each edit - Review
git diff filenameto verify only intended changes - Validate functionality still works as expected
- Never proceed to next file until current edit is verified
- Run
- ✅ Backup Before Large Changes:
- Create a stash:
git stash push -m "Pre-cleanup snapshot"before removing >50 lines - Or create a backup branch:
git branch backup-before-cleanup - This allows instant recovery if mistakes occur
- Create a stash:
- ✅ Large Deletion Safety Pattern:
- Read at least 20 lines before/after deletion target
- Include unique identifiers in match (function signatures, specific comments)
- Use narrow matches - avoid generic patterns
- Verify line numbers match intended section
Documentation
Documentation Structure (updated with full docs system):
- ✅ README.md - Project overview, quick start, and setup instructions only
- ✅ docs/ - Comprehensive documentation system with search
- ✅ docs/developer/api/ - API reference documentation (split by endpoint/category)
- ✅ docs/user/ - User-facing features, guides, and workflows
- ✅ docs/user/devices/ - Device setup guides (KOBO, KOReader, etc.)
- ✅ docs/contributing/ - Development and contribution guides
Where to document changes:
| Change Type | Location | Examples |
|---|---|---|
| User-facing features | docs/user/ |
New features, UI changes, workflows |
| API endpoints | docs/developer/api/<category>/<endpoint>.md |
New endpoints, modified responses, authentication changes |
| API behavior | Update existing docs/developer/api/ files |
Parameter changes, error codes, rate limits |
| Device setup | docs/user/devices/ |
New device support, setup instructions |
| Development | docs/contributing/ |
Build changes, architecture decisions |
| Quick start/setup | README.md |
Installation, environment setup, first-run |
| Breaking changes | Both README.md and relevant docs/ |
Migration guides, deprecation notices |
| Bug fixes | Update relevant docs/ only if user-visible |
Clarifications, troubleshooting additions |
| Bruno OpenCollection YAML tests | .yml files in bruno folder in appropriate folder/sub-folder |
API contract testing, examples |
Documentation Update Workflow:
- Identify the audience (end users, developers, API consumers)
- Choose appropriate location based on table above
- Update documentation before or with code changes
- Verify documentation renders at
/docsendpoint - Test search finds new/updated content
- For API changes: Update both
docs/developer/api/files AND Bruno OpenCollection YAML.ymlfiles - Commit separately with clear message:
docs: <description>
When in doubt:
- End-user visible →
docs/user/ - API reference →
docs/developer/api/ - Setup/onboarding →
README.md - Development related →
docs/contributing/
Process & Continuity
- ✅ If mid-task and receive "no response", continue the task
- ✅ Verify no regressions before modifying/removing code
🔧 TECHNICAL STANDARDS
Backend Stack
- Language: Go 1.25+
- Database: PostgreSQL 15+ with pgx v5 driver only
- Authentication: JWT tokens with bcrypt password hashing
- Architecture: Service layer pattern (handlers → services → database)
Frontend Stack
- Styling: TailwindCSS (no custom CSS)
- Language: TypeScript (no JavaScript)
- Templates: HTMX with server-side rendering
- Patterns: Procedural/imperative with functional techniques where helpful (no OOP)
Containerization
- Runtime: Podman (not Docker)
- Build: Existing Dockerfile and docker-compose.yml only
- No local builds allowed
🔄 ERROR RECOVERY PROTOCOL
When code modification mistakes occur (deleted wrong code, broke compilation, etc.):
Immediate Actions
- STOP - Don't make more edits
- ASSESS - What was deleted? Is it critical?
- REVIEW - Run
git diffto see exact changes - RESTORE - Choose appropriate recovery method:
- Recent mistake:
git checkout -- filename - Complex restoration: Use
git show HEAD:filenameto recover deleted code - Multiple files:
git reset HEAD~1(if safe)
- Recent mistake:
- VERIFY - Compile and test restored code
- DOCUMENT - Note what went wrong for future reference
Recovery Examples
# Recover a deleted function from original file
git show HEAD:internal/handlers/auth.go | sed -n '70,275p' > recovery.txt
# Revert entire file to original state
git checkout HEAD -- internal/handlers/auth.go
# Use git stash to save current state before rollback
git stash push -m "Broken state before fix"
git checkout -- internal/handlers/auth.go
Prevention (Learn From Mistakes)
- Why did the mistake happen?
- Was it too-broad matching?
- Was it insufficient context reading?
- Was it cascading fix-up attempts?
- Update guidelines to prevent recurrence
📋 WORKFLOW CHECKLISTS
Before Making Frontend-Only Changes
- Identify if backend modification could make implementation simpler
- Plan to use existing API endpoints only
- If backend change seems necessary, prepare confirmation request:
- Required change description
- Why it would help
- Impact analysis
- Alternative approaches considered
- Plan git commit structure (multiple logical commits)
- Identify documentation location (see Documentation section):
- User-facing feature →
docs/user/ - UI/workflow changes →
docs/user/ - Setup instructions →
README.md
- User-facing feature →
Before Making Full-Stack Changes
- Read current schema completely (if database changes)
- Identify all columns that must be preserved
- Plan exact changes needed
- Verify Podman will be used for builds
- Plan git commit structure (multiple logical commits)
- Identify documentation location:
- API changes →
docs/developer/api/<category>/ - New endpoints → Create new
.mdfile indocs/developer/api/ - API behavior → Update existing
docs/developer/api/files - Breaking changes → Both
README.md+ relevantdocs/ - Bruno OpenCollection YAML
.ymlfiles → Update/create alongside API changes
- API changes →
During Schema Changes (Full-Stack Only)
- Read current schema completely
- Identify all columns that must be preserved
- Plan exact changes needed
- Set up verification step
- Make intended changes
- Immediately verify by reading back modified sections
- Confirm ALL expected columns are present
- Verify schema.sql, models.go, and queries.sql are in sync
- Update local database (choose ONE):
- Option 1 - Recreate database (recommended, loses data):
podman compose down -v # Delete all volumes podman compose up -d # Start with fresh schema - Option 2 - Manual SQL migration (preserves data):
podman exec bookhoard_db psql -U postgres -d bookhoard -c "YOUR SQL HERE"
- Option 1 - Recreate database (recommended, loses data):
- Verify database has new schema (check column types, indexes, etc.)
After API Changes
- Create/update Bruno OpenCollection YAML requests
- Test with no user context
- Test with regular user context
- Test with admin context
- Verify backward compatibility
Before Committing
- Run verification script:
bash scripts/verify-guidelines.sh - Fix any errors - verification must pass (0 errors) to commit
- Note warnings - informational only, do not auto-fix
- Run tests:
go test ./... -v - Run lint/typecheck if available
- Ensure no secrets in changes
- Verify logical commit structure
- Update documentation (see Documentation section):
- User-facing changes →
docs/user/ - API changes →
docs/developer/api/+ Bruno OpenCollection YAML.ymlfiles - Setup/onboarding →
README.md - Development changes →
docs/contributing/
- User-facing changes →
- Verify docs render at
/docsendpoint - Test docs search finds new content
Error Recovery Protocol (If Code Mistakes Occur)
- Stop immediately - don't make more edits
- Assess impact: What was deleted? Is it critical?
- Review git diff: See exact changes made
- Restore strategy:
- If recent mistake:
git checkout -- filename - If complex: Reconstruct from git diff using
git show HEAD:filename
- If recent mistake:
- Verify recovery: Compile and test restored code
- Document mistake: Note what went wrong for future reference
Phase Completion Verification (Before Declaring "Complete")
- All target code is removed/intact as intended
- No unintended code was deleted
- All affected files compile successfully
- Run
go build ./...for entire project - Run verification script:
bash scripts/verify-guidelines.sh- must pass (0 errors) - No critical functionality was broken
- Git diff shows only intended changes
- Review all modified files with
git diff --stat
🏗 ARCHITECTURAL PATTERNS
Current: Hybrid SSR
Browser → Go template (with data) → Display instantly
↓
JavaScript for interactivity (CRUD)
↓
Shared service layer
Ultimately, whenever you are unsure just ask for confirmation.