refactor: implement database-specific schema architecture with schema-as-query pattern
🏗️ **Major Database Schema Refactoring** **Problem Solved**: Eliminated model duplication and multiple sources of truth by: - Removed duplicate models (`internal/models/content.go`) - Replaced inlined schema strings with sqlc-generated setup functions - Implemented database-specific schemas with proper NOT NULL constraints **Key Improvements**: ✅ **Single Source of Truth**: Database schemas define all types, no manual sync needed ✅ **Clean Generated Types**: sqlc generates `string` and `int64` instead of `sql.NullString/sql.NullTime` ✅ **Schema-as-Query Pattern**: Setup functions generated by sqlc for type safety ✅ **Database-Specific Optimization**: SQLite INTEGER timestamps, PostgreSQL BIGINT timestamps ✅ **Cross-Database Compatibility**: Single codebase supports both SQLite and PostgreSQL **Architecture Changes**: - `db/sqlite/` - SQLite-specific schema and setup queries - `db/postgresql/` - PostgreSQL-specific schema and setup queries - `db/queries/` - Cross-database CRUD queries using `sqlc.arg()` syntax - `internal/db/database.go` - Database abstraction with runtime selection - `internal/api/models.go` - Clean API models for requests/responses **Version Control System**: Complete element-level history with user attribution and rollback **Verification**: ✅ Full API workflow tested (create → update → rollback → versions) **Production Ready**: Supports SQLite (development) → PostgreSQL (production) migration
This commit is contained in:
@@ -1,158 +1,123 @@
|
||||
# Insertr Content Server
|
||||
|
||||
The HTTP API server that provides content storage and retrieval for the Insertr CMS system.
|
||||
REST API server for the Insertr CMS system. Provides content management with version control and user attribution.
|
||||
|
||||
## 🚀 Quick Start
|
||||
## Features
|
||||
|
||||
### Build and Run
|
||||
```bash
|
||||
# Build the server
|
||||
go build -o insertr-server ./cmd/server
|
||||
- **Content Management**: Full CRUD operations for content items
|
||||
- **Version Control**: Complete edit history with rollback functionality
|
||||
- **User Attribution**: Track who made each change
|
||||
- **Type-Safe Database**: Uses sqlc for generated Go code from SQL
|
||||
- **SQLite & PostgreSQL**: Database flexibility for development to production
|
||||
|
||||
# Start with default settings
|
||||
./insertr-server
|
||||
## API Endpoints
|
||||
|
||||
# Start with custom port and database
|
||||
./insertr-server --port 8080 --db ./content.db
|
||||
```
|
||||
|
||||
### Development
|
||||
```bash
|
||||
# Install dependencies
|
||||
go mod tidy
|
||||
|
||||
# Run directly with go
|
||||
go run ./cmd/server --port 8080
|
||||
```
|
||||
|
||||
## 📊 API Endpoints
|
||||
|
||||
The server implements the exact API contract expected by both the Go CLI client and JavaScript browser client:
|
||||
|
||||
### Content Retrieval
|
||||
### Content Operations
|
||||
- `GET /api/content?site_id={site}` - Get all content for a site
|
||||
- `GET /api/content/{id}?site_id={site}` - Get single content item
|
||||
- `GET /api/content/bulk?site_id={site}&ids[]={id1}&ids[]={id2}` - Get multiple items
|
||||
|
||||
### Content Modification
|
||||
- `GET /api/content/bulk?site_id={site}&ids[]={id1}&ids[]={id2}` - Get multiple content items
|
||||
- `POST /api/content` - Create new content
|
||||
- `PUT /api/content/{id}?site_id={site}` - Update existing content
|
||||
- `PUT /api/content/{id}?site_id={site}` - Update existing content
|
||||
- `DELETE /api/content/{id}?site_id={site}` - Delete content
|
||||
|
||||
### System
|
||||
- `GET /health` - Health check endpoint
|
||||
### Version Control
|
||||
- `GET /api/content/{id}/versions?site_id={site}` - Get version history
|
||||
- `POST /api/content/{id}/rollback?site_id={site}` - Rollback to specific version
|
||||
|
||||
## 🗄️ Database
|
||||
### Health & Status
|
||||
- `GET /health` - Server health check
|
||||
|
||||
Uses SQLite by default for simplicity. The database schema:
|
||||
## User Attribution
|
||||
|
||||
```sql
|
||||
CREATE TABLE content (
|
||||
id TEXT NOT NULL,
|
||||
site_id TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
type TEXT NOT NULL CHECK (type IN ('text', 'markdown', 'link')),
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id, site_id)
|
||||
);
|
||||
All content operations support user attribution via the `X-User-ID` header:
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://localhost:8080/api/content/hero-title?site_id=demo" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-ID: john@example.com" \
|
||||
-d '{"value": "Updated content"}'
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
## Quick Start
|
||||
|
||||
### Command Line Options
|
||||
- `--port` - Server port (default: 8080)
|
||||
- `--db` - SQLite database path (default: ./insertr.db)
|
||||
```bash
|
||||
# Build server
|
||||
go build -o insertr-server ./cmd/server
|
||||
|
||||
### CORS
|
||||
Currently configured for development with `Access-Control-Allow-Origin: *`.
|
||||
For production, configure CORS appropriately.
|
||||
# Start server
|
||||
./insertr-server --port 8080
|
||||
|
||||
## 🧪 Testing
|
||||
# Check health
|
||||
curl http://localhost:8080/health
|
||||
```
|
||||
|
||||
### API Testing Examples
|
||||
## Development
|
||||
|
||||
### Using sqlc
|
||||
|
||||
```bash
|
||||
# Install sqlc
|
||||
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
|
||||
|
||||
# Generate Go code from SQL
|
||||
sqlc generate
|
||||
|
||||
# Build with generated code
|
||||
go build ./cmd/server
|
||||
```
|
||||
|
||||
### Database Schema
|
||||
|
||||
See `db/schema/schema.sql` for the complete schema. Key tables:
|
||||
|
||||
- `content` - Current content versions
|
||||
- `content_versions` - Complete version history
|
||||
|
||||
### Example Version Control Workflow
|
||||
|
||||
```bash
|
||||
# Create content
|
||||
curl -X POST "http://localhost:8080/api/content" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"id":"hero-title","value":"Welcome!","type":"text"}'
|
||||
-H "X-User-ID: alice@example.com" \
|
||||
-d '{
|
||||
"id": "hero-title",
|
||||
"site_id": "demo",
|
||||
"value": "Original Title",
|
||||
"type": "text"
|
||||
}'
|
||||
|
||||
# Get content
|
||||
curl "http://localhost:8080/api/content/hero-title?site_id=demo"
|
||||
|
||||
# Update content
|
||||
# Update content (creates version)
|
||||
curl -X PUT "http://localhost:8080/api/content/hero-title?site_id=demo" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"value":"Updated Welcome!"}'
|
||||
-H "X-User-ID: bob@example.com" \
|
||||
-d '{"value": "Updated Title"}'
|
||||
|
||||
# View version history
|
||||
curl "http://localhost:8080/api/content/hero-title/versions?site_id=demo"
|
||||
|
||||
# Rollback to version 1
|
||||
curl -X POST "http://localhost:8080/api/content/hero-title/rollback?site_id=demo" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-ID: admin@example.com" \
|
||||
-d '{"version_id": 1}'
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
```bash
|
||||
# From project root
|
||||
./test-integration.sh
|
||||
```
|
||||
|
||||
## 🏗️ Architecture Integration
|
||||
|
||||
This server bridges the gap between:
|
||||
|
||||
1. **Browser Editor** (`lib/`) - JavaScript client that saves edits
|
||||
2. **CLI Enhancement** (`insertr-cli/`) - Go client that pulls content during builds
|
||||
3. **Static Site Generation** - Enhanced HTML with database content
|
||||
|
||||
### Content Flow
|
||||
```
|
||||
Browser Edit → HTTP Server → SQLite Database
|
||||
↓
|
||||
CLI Build Process ← HTTP Server ← SQLite Database
|
||||
↓
|
||||
Enhanced Static Site
|
||||
```
|
||||
|
||||
## 🚀 Production Deployment
|
||||
|
||||
### Docker (Recommended)
|
||||
```dockerfile
|
||||
FROM golang:1.21-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN go build -o insertr-server ./cmd/server
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /app/insertr-server .
|
||||
EXPOSE 8080
|
||||
CMD ["./insertr-server"]
|
||||
```
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
- `PORT` - Server port
|
||||
- `DB_PATH` - Database file path
|
||||
- `CORS_ORIGIN` - Allowed CORS origin for production
|
||||
- `PORT` - Server port (default: 8080)
|
||||
- `DB_PATH` - SQLite database file path (default: ./insertr.db)
|
||||
|
||||
### Health Monitoring
|
||||
The `/health` endpoint returns JSON status for monitoring:
|
||||
```json
|
||||
{"status":"healthy","service":"insertr-server"}
|
||||
### Command Line Flags
|
||||
```bash
|
||||
./insertr-server --help
|
||||
```
|
||||
|
||||
## 🔐 Security Considerations
|
||||
## Production Deployment
|
||||
|
||||
### Current State (Development)
|
||||
- Open CORS policy
|
||||
- No authentication required
|
||||
- SQLite database (single file)
|
||||
|
||||
### Production TODO
|
||||
- [ ] JWT/OAuth authentication
|
||||
- [ ] PostgreSQL database option
|
||||
- [ ] Rate limiting
|
||||
- [ ] Input validation and sanitization
|
||||
- [ ] HTTPS enforcement
|
||||
- [ ] Configurable CORS origins
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Fully functional development server
|
||||
**Next**: Production hardening and authentication
|
||||
1. **Database**: Consider PostgreSQL for production scale
|
||||
2. **Authentication**: Integrate with your auth system via middleware
|
||||
3. **CORS**: Configure appropriate CORS policies
|
||||
4. **SSL**: Serve over HTTPS
|
||||
5. **Monitoring**: Add logging and metrics collection
|
||||
Reference in New Issue
Block a user