260 lines
5.8 KiB
Markdown
260 lines
5.8 KiB
Markdown
# Tech Stack Comparison: Original vs Simplified
|
|
|
|
## Quick Reference
|
|
|
|
### Original Suggestions → Simplified Alternatives
|
|
|
|
| Requirement | Original Tech | Simplified Tech | Complexity Reduction |
|
|
|------------|--------------|----------------|---------------------|
|
|
| **Workflow Engine** | Camunda / Temporal | Custom Python state machine | 90% simpler |
|
|
| **Document Storage** | AWS S3 / MinIO | Local filesystem + PostgreSQL metadata | 80% simpler |
|
|
| **Search & Duplicate Detection** | Elasticsearch + ML (Sentence-BERT) | PostgreSQL full-text + pg_trgm | 85% simpler |
|
|
| **Event Bus** | Apache Kafka / RabbitMQ | PostgreSQL NOTIFY/LISTEN or in-memory | 90% simpler |
|
|
| **Business Rules** | Drools | Custom Python classes/functions | 70% simpler |
|
|
| **Audit Log** | Separate WORM storage | PostgreSQL append-only table | 60% simpler |
|
|
|
|
---
|
|
|
|
## Detailed Simplifications
|
|
|
|
### 1. Workflow Engine
|
|
|
|
**Original:** Camunda or Temporal
|
|
- Separate service to run
|
|
- Complex BPMN diagrams
|
|
- Additional database
|
|
- Learning curve
|
|
|
|
**Simplified:** Custom Python State Machine
|
|
```python
|
|
# ~100 lines of code
|
|
class InitiativeWorkflow:
|
|
STATES = {
|
|
'DRAFT': ['SUBMITTED'],
|
|
'SUBMITTED': ['UNIT_REVIEW', 'REJECTED'],
|
|
'UNIT_REVIEW': ['COUNCIL_REVIEW', 'REJECTED'],
|
|
'COUNCIL_REVIEW': ['APPROVED', 'REJECTED'],
|
|
'APPROVED': ['FINALIZED', 'APPEAL'],
|
|
'REJECTED': ['APPEAL'],
|
|
'APPEAL': ['APPROVED', 'REJECTED', 'FINALIZED'],
|
|
'FINALIZED': []
|
|
}
|
|
|
|
def can_transition(self, from_state, to_state, user_role):
|
|
return to_state in self.STATES.get(from_state, [])
|
|
```
|
|
|
|
**Savings:**
|
|
- No separate service
|
|
- No BPMN learning
|
|
- Easier to debug
|
|
- Version controlled
|
|
|
|
---
|
|
|
|
### 2. Document Storage
|
|
|
|
**Original:** AWS S3 / MinIO
|
|
- Separate service
|
|
- API calls for every operation
|
|
- Network latency
|
|
- Additional configuration
|
|
|
|
**Simplified:** Local Filesystem
|
|
```
|
|
/initiatives/
|
|
/{initiative_id}/
|
|
/forms/
|
|
/reviews/
|
|
/attachments/
|
|
```
|
|
|
|
**Savings:**
|
|
- Direct file access
|
|
- No API calls
|
|
- Simpler backup (copy folder)
|
|
- No network dependency
|
|
|
|
---
|
|
|
|
### 3. Search & Duplicate Detection
|
|
|
|
**Original:** Elasticsearch + ML Model (Sentence-BERT)
|
|
- Separate service
|
|
- Model training required
|
|
- Complex deployment
|
|
- Resource intensive
|
|
|
|
**Simplified:** PostgreSQL Full-Text + Trigram Similarity
|
|
```sql
|
|
-- Enable extensions
|
|
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
|
|
-- Create index
|
|
CREATE INDEX idx_initiative_description_gin
|
|
ON initiatives USING gin(to_tsvector('english', description));
|
|
|
|
-- Similarity search
|
|
SELECT id, title,
|
|
similarity(description, 'search text') as score
|
|
FROM initiatives
|
|
WHERE similarity(description, 'search text') > 0.3
|
|
ORDER BY score DESC;
|
|
```
|
|
|
|
**Savings:**
|
|
- Built into PostgreSQL
|
|
- No model training
|
|
- No separate service
|
|
- Good enough for local scale
|
|
|
|
---
|
|
|
|
### 4. Event Bus
|
|
|
|
**Original:** Apache Kafka / RabbitMQ
|
|
- Separate service
|
|
- Complex configuration
|
|
- Message persistence
|
|
- Consumer groups
|
|
|
|
**Simplified:** PostgreSQL NOTIFY/LISTEN
|
|
```python
|
|
# Publisher
|
|
async def notify_event(event_type, data):
|
|
await db.execute(
|
|
"SELECT pg_notify('initiative_events', %s)",
|
|
json.dumps({'type': event_type, 'data': data})
|
|
)
|
|
|
|
# Listener
|
|
async def listen_events():
|
|
conn = await asyncpg.connect(...)
|
|
await conn.add_listener('initiative_events', handle_event)
|
|
```
|
|
|
|
**Savings:**
|
|
- No separate service
|
|
- Built into database
|
|
- Persistent (if needed)
|
|
- Simple pub/sub
|
|
|
|
---
|
|
|
|
### 5. Business Rules Engine
|
|
|
|
**Original:** Drools
|
|
- Java-based
|
|
- Separate rule files
|
|
- Complex syntax
|
|
- Additional dependency
|
|
|
|
**Simplified:** Python Functions/Classes
|
|
```python
|
|
class NoveltyChecker:
|
|
def check(self, initiative):
|
|
# Check similarity with existing
|
|
similar = self.find_similar(initiative)
|
|
if similar:
|
|
return ValidationResult(invalid=True, reason="Duplicate found")
|
|
return ValidationResult(valid=True)
|
|
|
|
class ScoringEngine:
|
|
def calculate(self, reviews):
|
|
scores = [r.score for r in reviews if r.score is not None]
|
|
if len(scores) == 0:
|
|
return None
|
|
return sum(scores) / len(scores)
|
|
```
|
|
|
|
**Savings:**
|
|
- Native Python
|
|
- Easy to test
|
|
- Version controlled
|
|
- No external engine
|
|
|
|
---
|
|
|
|
## Resource Usage Comparison
|
|
|
|
### Original Stack
|
|
- PostgreSQL: ~200MB RAM
|
|
- FastAPI: ~100MB RAM
|
|
- Elasticsearch: ~1GB RAM
|
|
- Kafka: ~500MB RAM
|
|
- MinIO: ~200MB RAM
|
|
- **Total: ~2GB RAM minimum**
|
|
|
|
### Simplified Stack
|
|
- PostgreSQL: ~200MB RAM
|
|
- FastAPI: ~100MB RAM
|
|
- **Total: ~300MB RAM**
|
|
|
|
**Savings: 85% less memory**
|
|
|
|
---
|
|
|
|
## Deployment Complexity
|
|
|
|
### Original Stack
|
|
```
|
|
docker-compose.yml:
|
|
- postgres
|
|
- fastapi
|
|
- elasticsearch
|
|
- kafka
|
|
- minio
|
|
- zookeeper (for Kafka)
|
|
|
|
Total: 6+ containers
|
|
```
|
|
|
|
### Simplified Stack
|
|
```
|
|
docker-compose.yml:
|
|
- postgres
|
|
- fastapi
|
|
|
|
Total: 2 containers
|
|
```
|
|
|
|
**Savings: 67% fewer services**
|
|
|
|
---
|
|
|
|
## Maintenance Effort
|
|
|
|
| Task | Original | Simplified | Time Saved |
|
|
|------|----------|------------|------------|
|
|
| Setup | 2-3 days | 2-3 hours | 90% |
|
|
| Debugging | Complex (multiple services) | Simple (2 services) | 70% |
|
|
| Updates | Multiple services | 2 services | 80% |
|
|
| Monitoring | Multiple dashboards | Single dashboard | 75% |
|
|
|
|
---
|
|
|
|
## When to Upgrade
|
|
|
|
Upgrade to original stack only if:
|
|
|
|
1. **Scale:** >10,000 initiatives/year
|
|
2. **Users:** >100 concurrent users
|
|
3. **Performance:** Response time >2s
|
|
4. **Distribution:** Multi-server deployment
|
|
5. **Advanced ML:** Need sophisticated NLP
|
|
|
|
For local application with typical load (<5,000 initiatives/year), simplified stack is optimal.
|
|
|
|
---
|
|
|
|
## Migration Path
|
|
|
|
If you need to scale later:
|
|
|
|
1. **Add Redis** for caching (if slow queries)
|
|
2. **Add Elasticsearch** for advanced search (if PostgreSQL search insufficient)
|
|
3. **Add RabbitMQ** for async processing (if need background jobs)
|
|
4. **Move to S3** for documents (if need cloud storage)
|
|
|
|
But start simple, scale when needed.
|