feat: complete MongoDB to CouchDB migration

- Migrate Report model to CouchDB with embedded street/user data
- Migrate UserBadge model to CouchDB with badge population
- Update all remaining routes (reports, users, badges, payments) to use CouchDB
- Add CouchDB health check and graceful shutdown to server.js
- Add missing methods to couchdbService (checkConnection, findWithPagination, etc.)
- Update Kubernetes deployment manifests for CouchDB support
- Add comprehensive CouchDB setup documentation

All core functionality now uses CouchDB as primary database while maintaining
MongoDB for backward compatibility during transition period.

🤖 Generated with [AI Assistant]

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
This commit is contained in:
William Valentin
2025-11-01 13:29:48 -07:00
parent 9ac21fca72
commit df94c17e1f
14 changed files with 684 additions and 155 deletions

View File

@@ -412,6 +412,22 @@ class CouchDBService {
return this.isConnected;
}
/**
* Check connection health
*/
async checkConnection() {
try {
if (!this.connection) {
return false;
}
await this.connection.info();
return true;
} catch (error) {
console.error("CouchDB connection check failed:", error.message);
return false;
}
}
// Generic CRUD operations
async createDocument(doc) {
if (!this.isConnected) await this.initialize();
@@ -498,6 +514,62 @@ class CouchDBService {
return await this.find(query);
}
async findDocuments(selector = {}, options = {}) {
const query = {
selector,
...options
};
return await this.find(query);
}
async countDocuments(selector = {}) {
const query = {
selector,
limit: 0, // We don't need documents, just count
};
try {
const response = await this.db.find(query);
return response.total_rows || 0;
} catch (error) {
console.error("Error counting documents:", error.message);
throw error;
}
}
async findWithPagination(selector = {}, options = {}) {
const { page = 1, limit = 10, sort = {} } = options;
const skip = (page - 1) * limit;
const query = {
selector,
limit,
skip,
sort: Object.entries(sort).map(([field, order]) => ({
[field]: order === -1 ? "desc" : "asc"
}))
};
try {
const response = await this.db.find(query);
const totalCount = response.total_rows || 0;
const totalPages = Math.ceil(totalCount / limit);
return {
docs: response.docs,
totalDocs: totalCount,
page,
limit,
totalPages,
hasNextPage: page < totalPages,
hasPrevPage: page > 1,
};
} catch (error) {
console.error("Error finding documents with pagination:", error.message);
throw error;
}
}
// View query helper
async view(designDoc, viewName, params = {}) {
if (!this.isConnected) await this.initialize();