Major milestone: Frontend implementation complete for Shattered Void MMO FRONTEND IMPLEMENTATION: - React 18 + TypeScript + Vite development environment - Tailwind CSS with custom dark theme for sci-fi aesthetic - Zustand state management with authentication persistence - Socket.io WebSocket client with auto-reconnection - Protected routing with authentication guards - Responsive design with mobile-first approach AUTHENTICATION SYSTEM: - Login/register forms with comprehensive validation - JWT token management with localStorage persistence - Password strength validation and user feedback - Protected routes and authentication guards CORE GAME INTERFACE: - Colony management dashboard with real-time updates - Resource display with live production tracking - WebSocket integration for real-time game events - Navigation with connection status indicator - Toast notifications for user feedback BACKEND ENHANCEMENTS: - Complete Research System with technology tree (23 technologies) - Fleet Management System with ship designs and movement - Enhanced Authentication with email verification and password reset - Complete game tick integration for all systems - Advanced WebSocket events for real-time updates ARCHITECTURE FEATURES: - Type-safe TypeScript throughout - Component-based architecture with reusable UI elements - API client with request/response interceptors - Error handling and loading states - Performance optimized builds with code splitting Phase 2 Status: Frontend foundation complete (Week 1-2 objectives met) Ready for: Colony management, fleet operations, research interface Next: Enhanced gameplay features and admin interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
192 lines
7.3 KiB
JavaScript
192 lines
7.3 KiB
JavaScript
exports.up = async function (knex) {
|
|
// System configuration with hot-reloading support
|
|
await knex.schema.createTable('system_config', (table) => {
|
|
table.increments('id').primary();
|
|
table.string('config_key', 100).unique().notNullable();
|
|
table.jsonb('config_value').notNullable();
|
|
table.string('config_type', 20).notNullable().checkIn(['string', 'number', 'boolean', 'json', 'array']);
|
|
table.text('description');
|
|
table.boolean('requires_restart').defaultTo(false);
|
|
table.boolean('is_public').defaultTo(false); // Can be exposed to client
|
|
table.timestamp('created_at').defaultTo(knex.fn.now());
|
|
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
|
table.integer('updated_by'); // Will reference admin_users(id) after table creation
|
|
});
|
|
|
|
// Game tick system with user grouping
|
|
await knex.schema.createTable('game_tick_config', (table) => {
|
|
table.increments('id').primary();
|
|
table.integer('tick_interval_ms').notNullable().defaultTo(60000);
|
|
table.integer('user_groups_count').notNullable().defaultTo(10);
|
|
table.integer('max_retry_attempts').notNullable().defaultTo(5);
|
|
table.integer('bonus_tick_threshold').notNullable().defaultTo(3);
|
|
table.boolean('is_active').defaultTo(true);
|
|
table.timestamp('created_at').defaultTo(knex.fn.now());
|
|
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
|
});
|
|
|
|
await knex.schema.createTable('game_tick_log', (table) => {
|
|
table.bigIncrements('id').primary();
|
|
table.bigInteger('tick_number').notNullable();
|
|
table.integer('user_group').notNullable();
|
|
table.timestamp('started_at').notNullable();
|
|
table.timestamp('completed_at');
|
|
table.string('status', 20).notNullable().checkIn(['running', 'completed', 'failed', 'retrying']);
|
|
table.integer('retry_count').defaultTo(0);
|
|
table.text('error_message');
|
|
table.integer('processed_players').defaultTo(0);
|
|
table.jsonb('performance_metrics');
|
|
table.timestamp('created_at').defaultTo(knex.fn.now());
|
|
|
|
table.index(['tick_number']);
|
|
table.index(['user_group']);
|
|
table.index(['status']);
|
|
});
|
|
|
|
// Event system configuration
|
|
await knex.schema.createTable('event_types', (table) => {
|
|
table.increments('id').primary();
|
|
table.string('name', 100).unique().notNullable();
|
|
table.text('description');
|
|
table.string('trigger_type', 20).notNullable().checkIn(['admin', 'player', 'system', 'mixed']);
|
|
table.boolean('is_active').defaultTo(true);
|
|
table.jsonb('config_schema'); // JSON schema for event configuration
|
|
table.timestamp('created_at').defaultTo(knex.fn.now());
|
|
});
|
|
|
|
await knex.schema.createTable('event_instances', (table) => {
|
|
table.bigIncrements('id').primary();
|
|
table.integer('event_type_id').notNullable().references('id').inTable('event_types');
|
|
table.string('name', 200).notNullable();
|
|
table.text('description');
|
|
table.jsonb('config').notNullable();
|
|
table.timestamp('start_time');
|
|
table.timestamp('end_time');
|
|
table.string('status', 20).notNullable().checkIn(['scheduled', 'active', 'completed', 'cancelled']);
|
|
table.integer('created_by'); // Will reference admin_users(id) after table creation
|
|
table.timestamp('created_at').defaultTo(knex.fn.now());
|
|
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
|
|
|
table.index(['event_type_id']);
|
|
table.index(['status']);
|
|
table.index(['start_time']);
|
|
});
|
|
|
|
// Plugin system for extensibility
|
|
await knex.schema.createTable('plugins', (table) => {
|
|
table.increments('id').primary();
|
|
table.string('name', 100).unique().notNullable();
|
|
table.string('version', 20).notNullable();
|
|
table.text('description');
|
|
table.string('plugin_type', 50).notNullable(); // 'combat', 'event', 'resource', etc.
|
|
table.boolean('is_active').defaultTo(false);
|
|
table.jsonb('config');
|
|
table.jsonb('dependencies'); // Array of required plugins
|
|
table.jsonb('hooks'); // Available hook points
|
|
table.timestamp('created_at').defaultTo(knex.fn.now());
|
|
table.timestamp('updated_at').defaultTo(knex.fn.now());
|
|
});
|
|
|
|
// Insert initial system configuration
|
|
await knex('system_config').insert([
|
|
{
|
|
config_key: 'game_tick_interval_ms',
|
|
config_value: JSON.stringify(60000),
|
|
config_type: 'number',
|
|
description: 'Game tick interval in milliseconds',
|
|
is_public: false,
|
|
},
|
|
{
|
|
config_key: 'max_user_groups',
|
|
config_value: JSON.stringify(10),
|
|
config_type: 'number',
|
|
description: 'Maximum number of user groups for tick processing',
|
|
is_public: false,
|
|
},
|
|
{
|
|
config_key: 'max_retry_attempts',
|
|
config_value: JSON.stringify(5),
|
|
config_type: 'number',
|
|
description: 'Maximum retry attempts for failed ticks',
|
|
is_public: false,
|
|
},
|
|
{
|
|
config_key: 'data_retention_days',
|
|
config_value: JSON.stringify(30),
|
|
config_type: 'number',
|
|
description: 'Default data retention period in days',
|
|
is_public: false,
|
|
},
|
|
{
|
|
config_key: 'max_colonies_per_player',
|
|
config_value: JSON.stringify(10),
|
|
config_type: 'number',
|
|
description: 'Maximum colonies a player can own',
|
|
is_public: true,
|
|
},
|
|
{
|
|
config_key: 'starting_resources',
|
|
config_value: JSON.stringify({ scrap: 1000, energy: 500, data_cores: 0, rare_elements: 0 }),
|
|
config_type: 'json',
|
|
description: 'Starting resources for new players',
|
|
is_public: false,
|
|
},
|
|
{
|
|
config_key: 'websocket_ping_interval',
|
|
config_value: JSON.stringify(30000),
|
|
config_type: 'number',
|
|
description: 'WebSocket ping interval in milliseconds',
|
|
is_public: false,
|
|
},
|
|
]);
|
|
|
|
// Insert initial game tick configuration
|
|
await knex('game_tick_config').insert({
|
|
tick_interval_ms: 60000,
|
|
user_groups_count: 10,
|
|
max_retry_attempts: 5,
|
|
bonus_tick_threshold: 3,
|
|
});
|
|
|
|
// Insert initial event types
|
|
await knex('event_types').insert([
|
|
{
|
|
name: 'galaxy_crisis',
|
|
description: 'Major galaxy-wide crisis events',
|
|
trigger_type: 'admin',
|
|
config_schema: JSON.stringify({ duration_hours: { type: 'number', min: 1, max: 168 } }),
|
|
},
|
|
{
|
|
name: 'discovery_event',
|
|
description: 'Random discovery events triggered by exploration',
|
|
trigger_type: 'player',
|
|
config_schema: JSON.stringify({ discovery_type: { type: 'string', enum: ['artifact', 'technology', 'resource'] } }),
|
|
},
|
|
{
|
|
name: 'faction_war',
|
|
description: 'Large-scale conflicts between factions',
|
|
trigger_type: 'mixed',
|
|
config_schema: JSON.stringify({ participating_factions: { type: 'array', items: { type: 'number' } } }),
|
|
},
|
|
]);
|
|
|
|
// Insert initial plugin for basic combat
|
|
await knex('plugins').insert({
|
|
name: 'basic_combat',
|
|
version: '1.0.0',
|
|
description: 'Basic instant combat resolution system',
|
|
plugin_type: 'combat',
|
|
is_active: true,
|
|
config: JSON.stringify({ damage_variance: 0.1, experience_gain: 1.0 }),
|
|
hooks: JSON.stringify(['pre_combat', 'post_combat', 'damage_calculation']),
|
|
});
|
|
};
|
|
|
|
exports.down = async function (knex) {
|
|
await knex.schema.dropTableIfExists('plugins');
|
|
await knex.schema.dropTableIfExists('event_instances');
|
|
await knex.schema.dropTableIfExists('event_types');
|
|
await knex.schema.dropTableIfExists('game_tick_log');
|
|
await knex.schema.dropTableIfExists('game_tick_config');
|
|
await knex.schema.dropTableIfExists('system_config');
|
|
};
|