- Fix incorrect function references in ALPINE_COMPLETION_GUIDE.md - header.changeThemeTo -> changeTheme - header.logout -> logout - woodPaneling.change -> changeWoodPaneling - Add SSR-first principles section to PROJECT_GUIDELINES.md - Add page type classifications (Type 1, 2, 3) - Fix extra asterisks on line 43 - Update to reference TypeScript instead of JavaScript
481 lines
22 KiB
Markdown
481 lines
22 KiB
Markdown
# 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 checkout` on 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 from `cmd/server/tests/test_helpers_test.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=1` for test pools (via `pgxpool.ParseConfig()`) to prevent connection exhaustion
|
|
- ❌ **NEVER create separate `pgxpool` per 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** - the `TestServerSetup` pattern automatically handles cleanup via `t.Cleanup()`
|
|
|
|
### Frontend & Styling
|
|
|
|
- ❌ **NEVER modify backend/API for frontend features without user confirmation*
|
|
- ❌ **NEVER use custom CSS** - TailwindCSS classes only
|
|
- **⚠️ EXCEPTION**: `templates/error.templ` may have inline CSS because error pages must work when main app fails (404, server errors, CSS fails to load)
|
|
- ❌ **NEVER use JavaScript** - convert all to TypeScript
|
|
- **⚠️ EXCEPTION**: Inline JS function calls in HTML attributes (e.g., `onclick="myFunction()"`) are acceptable for simple interactions
|
|
- ❌ **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
|
|
- ❌ **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 push` and wait for completion
|
|
- Never use `&&` to chain git commands together
|
|
- ✅ **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:
|
|
|
|
```go
|
|
// ❌ 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**:
|
|
|
|
```go
|
|
// ✅ 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:
|
|
|
|
1. STOP - Don't make more edits
|
|
2. ANALYZE - Use `git diff` to understand what was changed
|
|
3. RECOVER - Restore what was accidentally deleted/broken
|
|
4. 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**:
|
|
1. Identify the required change
|
|
2. Explain why you need it
|
|
3. Provide impact analysis
|
|
4. **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 requests 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.sql` is updated, local databases must be updated
|
|
- **Option 1 (Recommended):** Recreate database with fresh schema:
|
|
```bash
|
|
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
|
|
- ✅ 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
|
|
- ✅ Integration Tests (cmd/server/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 build` for affected packages immediately after each edit
|
|
- Review `git diff filename` to verify only intended changes
|
|
- Validate functionality still works as expected
|
|
- Never proceed to next file until current edit is verified
|
|
- ✅ **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
|
|
- ✅ **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 requests** | `.yml` files in bruno folder in appropriate folder/sub-folder | API contract testing, examples |
|
|
|
|
**Documentation Update Workflow**:
|
|
|
|
1. **Identify the audience** (end users, developers, API consumers)
|
|
2. **Choose appropriate location** based on table above
|
|
3. **Update documentation** before or with code changes
|
|
4. **Verify documentation renders** at `/docs` endpoint
|
|
5. **Test search** finds new/updated content
|
|
6. **For API changes**: Update both `docs/developer/api/` files, integration test files (cmd/server/tests) AND Bruno OpenCollection YAML `.yml` files
|
|
7. **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
|
|
|
|
- **Rendering**: SSR-first - Go templates render initial page with all data
|
|
- **Interactivity**: Alpine.js for UI state (modals, dropdowns, transitions)
|
|
- **Dynamic Updates**: HTMX for CRUD operations (no full page reloads)
|
|
- **Styling**: TailwindCSS (no custom CSS)
|
|
- **Language**: TypeScript (no JavaScript)
|
|
- **Patterns**: Procedural/imperative with functional techniques where helpful (no OOP)
|
|
|
|
### SSR-First Principles
|
|
|
|
- ❌ **NEVER fetch initial data via AJAX** - server renders complete page
|
|
- ❌ **NEVER fetch data in Alpine x-init** - data already SSR'd
|
|
- ✅ **Use Alpine.js only for UI state** - modal visibility, dropdown toggles
|
|
- ✅ **Use HTMX for dynamic operations** - form submissions, partial page updates
|
|
- ✅ **x-init is for setup only** - event listeners, not data fetching
|
|
- ✅ **Data fetching happens after user actions** - not on page load
|
|
|
|
### Page Type Classifications
|
|
|
|
1. **Type 1: 80% SSR (most pages)**
|
|
- Backend provides all initial data
|
|
- Alpine handles modals/dropdowns only
|
|
- x-init NEVER fetches data
|
|
|
|
2. **Type 2: SSR + Interactive (dashboard, bookshelf)**
|
|
- Backend provides initial data
|
|
- Alpine handles interactivity (drag-drop, filtering)
|
|
- x-init ONLY sets up event listeners
|
|
|
|
3. **Type 3: 80% TypeScript (analytics, complex dashboards)**
|
|
- Some client-side data fetching acceptable
|
|
- Still prefer SSR when possible
|
|
|
|
### 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
|
|
|
|
1. **STOP** - Don't make more edits
|
|
2. **ASSESS** - What was deleted? Is it critical?
|
|
3. **REVIEW** - Run `git diff` to see exact changes
|
|
4. **RESTORE** - Choose appropriate recovery method:
|
|
- **Recent mistake**: `git checkout -- filename`
|
|
- **Complex restoration**: Use `git show HEAD:filename` to recover deleted code
|
|
- **Multiple files**: `git reset HEAD~1` (if safe)
|
|
5. **VERIFY** - Compile and test restored code
|
|
6. **DOCUMENT** - Note what went wrong for future reference
|
|
|
|
### Recovery Examples
|
|
|
|
```bash
|
|
# 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`
|
|
|
|
### 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 `.md` file in `docs/developer/api/`
|
|
- [ ] API behavior → Update existing `docs/developer/api/` files
|
|
- [ ] Breaking changes → Both `README.md` + relevant `docs/`
|
|
- [ ] Bruno OpenCollection YAML `.yml` files → Update/create alongside API changes
|
|
- [ ] Integration tests (cmd/server/tests) → Update/create alongside 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):
|
|
```bash
|
|
podman compose down -v # Delete all volumes
|
|
podman compose up -d # Start with fresh schema
|
|
```
|
|
- [ ] **Option 2 - Manual SQL migration** (preserves data):
|
|
```bash
|
|
podman exec bookhoard_db psql -U postgres -d bookhoard -c "YOUR SQL HERE"
|
|
```
|
|
- [ ] Verify database has new schema (check column types, indexes, etc.)
|
|
|
|
### After API Changes
|
|
|
|
- [ ] Create/update Bruno OpenCollection YAML requests
|
|
- [ ] Create/update Integration tests (cmd/server/tests)
|
|
- [ ] 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/` + Integration tests + Bruno OpenCollection YAML `.yml` files
|
|
- [ ] Setup/onboarding → `README.md`
|
|
- [ ] Development changes → `docs/contributing/`
|
|
- [ ] **Verify docs render** at `/docs` endpoint
|
|
- [ ] **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`
|
|
- [ ] **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: SSR-First with Alpine.js + HTMX
|
|
|
|
```
|
|
Browser → Go template (SSR with all data) → Display instantly
|
|
↓
|
|
Alpine.js for UI state (modals, dropdowns)
|
|
↓
|
|
HTMX for CRUD (forms, updates)
|
|
↓
|
|
Shared service layer (Go)
|
|
```
|
|
|
|
**Layer Responsibilities:**
|
|
|
|
| Layer | Responsibility |
|
|
|-------|---------------|
|
|
| **Go Template** | SSR initial page with real data |
|
|
| **Alpine.js** | UI state only (x-data, x-show, transitions) |
|
|
| **HTMX** | Dynamic updates without page reload |
|
|
| **TypeScript** | Pure business logic (API calls, data processing) |
|
|
|
|
**See also:** `SSR_FIRST_ALPINE_GUIDE.md` and `ALPINE_COMPLETION_GUIDE.md`
|
|
|
|
Ultimately, whenever you are unsure just ask for confirmation.
|