TekTree Data Models
Version: 1.0.0 Last Updated: 2025-12-16 Status: Foundation (Pre-Implementation)MongoDB Collections
users
Purpose: User accounts and profilesCopy
{
"_id": ObjectId("..."),
"uid": "usr_abc123", // External ID
"email": "user@example.com",
"email_verified": false,
"password_hash": "bcrypt...",
"handle": "johndoe",
"first_name": "John",
"last_name": "Doe",
"avatar": "https://cdn.tektree.com/avatars/...",
"bio": "Software engineer...",
"tier": "pro",
"role": "user", // user, moderator, admin
"created_at": ISODate("2025-01-01T00:00:00Z"),
"updated_at": ISODate("2025-12-16T14:00:00Z"),
"last_login_at": ISODate("2025-12-16T14:00:00Z")
}
// Indexes
db.users.createIndex({ "email": 1 }, { unique: true })
db.users.createIndex({ "handle": 1 }, { unique: true })
db.users.createIndex({ "uid": 1 }, { unique: true })
db.users.createIndex({ "created_at": -1 })
areas
Purpose: Knowledge organization hierarchyCopy
{
"_id": ObjectId("..."),
"title": "Event-Driven Architecture",
"slug": "event-driven-architecture",
"parent_id": ObjectId("..."), // null for top-level
"details": "Exploring event-driven patterns...",
"tags": ["architecture", "events"],
"breadcrumbs": "Programming > Architecture > Event-Driven",
"visibility": "public", // public, private, connections
"created_by": ObjectId("..."), // user _id
"created_at": ISODate("..."),
"updated_at": ISODate("..."),
"follower_count": 234,
"content_count": 45
}
// Indexes
db.areas.createIndex({ "parent_id": 1, "created_at": -1 })
db.areas.createIndex({ "tags": 1 })
db.areas.createIndex({ "created_by": 1 })
db.areas.createIndex({ "slug": 1 })
db.areas.createIndex({ "title": "text", "details": "text" })
questions
Purpose: User questionsCopy
{
"_id": ObjectId("..."),
"title": "How do I implement event sourcing?",
"slug": "how-do-i-implement-event-sourcing",
"body": "I'm building an event-driven system...",
"tags": ["go", "event-sourcing"],
"areas": [ObjectId("..."), ObjectId("...")],
"visibility": "public",
"created_by": ObjectId("..."),
"created_at": ISODate("..."),
"updated_at": ISODate("..."),
"view_count": 234,
"upvote_count": 12,
"downvote_count": 1,
"answer_count": 3,
"accepted_answer_id": ObjectId("..."),
"files": ["file_abc123"],
"status": "open" // open, closed, resolved
}
// Indexes
db.questions.createIndex({ "created_by": 1, "created_at": -1 })
db.questions.createIndex({ "areas": 1, "created_at": -1 })
db.questions.createIndex({ "tags": 1 })
db.questions.createIndex({ "status": 1, "created_at": -1 })
db.questions.createIndex({ "title": "text", "body": "text" })
answers
Purpose: Answers to questionsCopy
{
"_id": ObjectId("..."),
"question_id": ObjectId("..."),
"body": "Here's how you can implement...",
"code_snippets": [
{
"language": "go",
"code": "type Event struct {...}"
}
],
"created_by": ObjectId("..."),
"created_at": ISODate("..."),
"updated_at": ISODate("..."),
"upvote_count": 8,
"downvote_count": 0,
"is_accepted": true
}
// Indexes
db.answers.createIndex({ "question_id": 1, "created_at": -1 })
db.answers.createIndex({ "created_by": 1 })
db.answers.createIndex({ "is_accepted": 1 })
insights
Purpose: Long-form articles and tutorialsCopy
{
"_id": ObjectId("..."),
"title": "Event-Driven Architecture Best Practices",
"slug": "event-driven-architecture-best-practices",
"body": "# Introduction\n\n...",
"insight_type": "article", // article, tutorial, case_study, tool_review
"tags": ["architecture", "events"],
"areas": [ObjectId("...")],
"co_authors": [ObjectId("...")],
"visibility": "public",
"created_by": ObjectId("..."),
"created_at": ISODate("..."),
"updated_at": ISODate("..."),
"published_at": ISODate("..."),
"view_count": 1234,
"like_count": 56,
"comment_count": 12,
"estimated_read_time_minutes": 10,
"featured": false
}
// Indexes
db.insights.createIndex({ "created_by": 1, "published_at": -1 })
db.insights.createIndex({ "areas": 1, "published_at": -1 })
db.insights.createIndex({ "tags": 1 })
db.insights.createIndex({ "featured": 1, "published_at": -1 })
db.insights.createIndex({ "title": "text", "body": "text" })
gamification_profiles
Purpose: User gamification stateCopy
{
"_id": ObjectId("..."),
"user_id": ObjectId("..."),
"total_xp": 50000,
"current_level": 15,
"xp_to_next_level": 1500,
"daily_xp_earned": 150,
"daily_xp_reset_at": ISODate("2025-12-17T00:00:00Z"),
"streak": {
"current": 42,
"longest": 87,
"last_activity_at": ISODate("2025-12-16T20:00:00Z"),
"freezes_available": 6
},
"achievements": ["ach_first_steps", "ach_week_warrior"],
"featured_achievements": ["ach_week_warrior", "ach_top_contributor"],
"leaderboard_opt_out": false,
"updated_at": ISODate("...")
}
// Indexes
db.gamification_profiles.createIndex({ "user_id": 1 }, { unique: true })
db.gamification_profiles.createIndex({ "total_xp": -1 }) // Global leaderboard
db.gamification_profiles.createIndex({ "current_level": -1 })
xp_transactions
Purpose: XP earning history (event sourcing)Copy
{
"_id": ObjectId("..."),
"transaction_id": "xp_txn_abc123",
"user_id": ObjectId("..."),
"amount": 25,
"source": "insight_published",
"related_entity_type": "insight",
"related_entity_id": ObjectId("..."),
"daily_total": 75,
"daily_cap": 500,
"timestamp": ISODate("...")
}
// Indexes
db.xp_transactions.createIndex({ "user_id": 1, "timestamp": -1 })
db.xp_transactions.createIndex({ "transaction_id": 1 }, { unique: true })
db.xp_transactions.createIndex({ "source": 1 })
subscriptions
Purpose: User subscription and billingCopy
{
"_id": ObjectId("..."),
"user_id": ObjectId("..."),
"tier": "pro", // free, pro, team, enterprise
"status": "active", // active, trialing, past_due, canceled
"billing_cycle": "monthly", // monthly, annual
"polar_subscription_id": "sub_polar_xyz",
"current_period_start": ISODate("2025-12-01T00:00:00Z"),
"current_period_end": ISODate("2025-12-31T23:59:59Z"),
"trial_ends_at": null,
"cancel_at": null,
"canceled_at": null,
"created_at": ISODate("..."),
"updated_at": ISODate("...")
}
// Indexes
db.subscriptions.createIndex({ "user_id": 1 }, { unique: true })
db.subscriptions.createIndex({ "status": 1 })
db.subscriptions.createIndex({ "polar_subscription_id": 1 })
events
Purpose: Event sourcing logCopy
{
"_id": ObjectId("..."),
"event_id": "evt_abc123xyz",
"event_type": "user.registered",
"event_version": "1.0.0",
"timestamp": ISODate("..."),
"trace_id": "trace_abc123",
"correlation_id": "corr_xyz789",
"source_service": "user-service",
"producer_id": "user-svc-pod-1",
"metadata": {
"user_id": "usr_123",
"ip_address": "203.0.113.42"
},
"payload": {
"user_id": "usr_abc123",
"email": "user@example.com"
}
}
// Indexes
db.events.createIndex({ "event_id": 1 }, { unique: true })
db.events.createIndex({ "event_type": 1, "timestamp": -1 })
db.events.createIndex({ "trace_id": 1 })
db.events.createIndex({ "timestamp": -1 })
db.events.createIndex({ "payload.user_id": 1, "timestamp": -1 })
Redis Data Structures
Session Storage
Copy
session:{session_id} -> JSON
TTL: 7 days (or 30 days with remember_me)
{
"user_id": "usr_abc123",
"tier": "pro",
"role": "user",
"created_at": 1702742400,
"expires_at": 1703347200
}
Rate Limiting
Copy
ratelimit:{user_id}:{endpoint} -> count
TTL: 60 seconds (sliding window)
ratelimit:usr_abc123:/api/v1/questions -> 5
Quota Tracking
Copy
quota:{user_id}:{quota_type}:{period} -> count
TTL: End of billing period
quota:usr_abc123:questions:2025-12 -> 15
Cache
Copy
cache:user:{user_id} -> JSON
TTL: 5 minutes
cache:question:{question_id} -> JSON
TTL: 5 minutes
Leaderboard (Sorted Sets)
Copy
leaderboard:global -> ZADD user_id score
leaderboard:weekly:2025-W50 -> ZADD user_id score
Document Status: ✅ Complete Related Documents:
ARCHITECTURE_OVERVIEW.md, EVENT_CATALOG.md, API_CONTRACTS.md