The data model for the Job Manager subsystem is designed to support all functional requirements while maintaining data integrity, scalability, and performance through database sharding.
User and company data is partitioned across database shards using a Geo-Population Based Sharding Strategy. The system uses the Country of the Company as the primary determinant for sharding, but distributes data based on population density to prevent hotspots.
To prevent data hotspots caused by population variance (e.g., India and China in the same Asia shard would overload it), the system uses a custom routing strategy based on world population data:
The routing mechanism is implemented via a dynamic DataSourceRouter within the Spring Boot application layer.
Context Switching
The router intercepts every database transaction, extracts the shardId from the Country JSON object to determine which shard to access, and routes to it.
Copy
@Componentpublic class DynamicDataSourceRouter extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { String country = ShardContextHolder.getCurrentCountry(); return ShardResolver.resolveShardId(country); }}
Shard Resolution
For new registrations or unauthenticated queries, a static ShardResolver utility maps the input Country to the corresponding Shard ID (1–5) based on the defined grouping logic. This ensures write operations land on the correct shard without requiring a global lookup table.
Copy
public class ShardResolver { public static int resolveShardId(String country) { if (AFRICAN_COUNTRIES.contains(country)) return 1; if (EUROPEAN_COUNTRIES.contains(country)) return 2; if (AMERICAN_COUNTRIES.contains(country)) return 3; if (EAST_ASIAN_COUNTRIES.contains(country)) return 4; return 5; // South/SE Asia & Pacific (default) }}
Country Data Structure
The country attribute is stored as an entity attribute containing the country code and shardId for efficient routing:
Since the Country shard key is mutable, whenever there is an update in the country property, physical migration might be processed to relocate the user’s data.
Same Shard Migration
Cross-Shard Migration
If the profile updates the country field to another country in the same shard region (e.g., from Vietnam to Singapore, both in Shard 5), the system performs a basic UPDATE query in the database.
Copy
UPDATE companiesSET country = '{"code": "SG", "name": "Singapore", "shardId": 5}'WHERE id = :companyId;
This strategy ensures that the database load is distributed more evenly based on actual user population density rather than geographical landmass, optimizing search performance and system resilience.
CREATE TABLE companies ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255), -- NULL for SSO users name VARCHAR(255) NOT NULL, -- Contact Information phone VARCHAR(20), street VARCHAR(255), city VARCHAR(100), country VARCHAR(100) NOT NULL, -- SHARDING KEY -- Authentication sso_provider VARCHAR(50), -- GOOGLE, MICROSOFT, FACEBOOK, GITHUB sso_user_id VARCHAR(255), is_activated BOOLEAN DEFAULT FALSE, activation_token VARCHAR(255), -- Profile about_us TEXT, who_we_are_looking_for TEXT, logo_url VARCHAR(500), -- Premium is_premium BOOLEAN DEFAULT FALSE, premium_expires_at TIMESTAMP, -- Audit created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), last_login_at TIMESTAMP, -- Indexes INDEX idx_email (email), INDEX idx_country (country), INDEX idx_premium (is_premium, premium_expires_at), INDEX idx_sso (sso_provider, sso_user_id));
Relationships:
One-to-Many with JobPosts
One-to-Many with SearchProfiles
One-to-One with Subscription
One-to-Many with CompanyMedia
Company Media Table
Copy
CREATE TABLE company_media ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, media_type VARCHAR(20) NOT NULL, -- IMAGE, VIDEO media_url VARCHAR(500) NOT NULL, title VARCHAR(255), display_order INT DEFAULT 0, created_at TIMESTAMP DEFAULT NOW(), INDEX idx_company (company_id), INDEX idx_type (company_id, media_type));