one-for-all-framework 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26eab5d2f3279aef8aaf3e4f4f69af60d01c535a8a4ba2f41a82615f77e02732
4
- data.tar.gz: a6760ad95277f885fff52a45427049cb87f3a59e584dc09fffa533c4b7b57bd5
3
+ metadata.gz: 6010d541e08ee4d29882dbfe22d000853a511985f01ee3b18239c57086bd7906
4
+ data.tar.gz: d05cdc0c5df07e8f2d9c0f3715169a3817b04b34da654dc63ce8afbaba0b932a
5
5
  SHA512:
6
- metadata.gz: ac089f1a856bf5b31ffea2561db5a48d2fed567b14be86245c7962965595d9fb80209472d2427a4c10c4f15d17ed48c839897bb3141d0a46f860f43d7014d44b
7
- data.tar.gz: 9f10a41d2e81293e8cfd363253d08fbb1bd1dc595e97cc646b31ce2c36e30807ee385772c9ba903e98e70bec3205e5b265f0a694cdc3d62aaba12e488639eed0
6
+ metadata.gz: 4b84becdb59e23e5177cd6d61b33ae6875cbcdc00a1ab81fe98c4e644c97e1549950cdeef4da11758564cf316d009f69bd69b431d33852e9384383294126acbb
7
+ data.tar.gz: 45544d4a74c6636667674f46b3ede29f4bde1e7a5e14e3f0d9385450b03676e76c4f538169386255d8f5ed1a1c70f971f65c3a88bdb948b6ace802ca8bc05170
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <img src="public/images/logo.png" width="500" height="500" alt="OFA Framework Logo">
3
3
  </p>
4
4
 
5
- # ⚡ One-For-All (OFA) Framework v3.0.0
5
+ # ⚡ One-For-All (OFA) Framework v4.0.0
6
6
 
7
7
  [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.0.0-red.svg)](https://www.ruby-lang.org/)
8
8
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
@@ -16,7 +16,7 @@
16
16
 
17
17
  - **💎 Premium Aesthetics**: Beautiful Glassmorphism design system included by default with smooth dark/light mode transitions.
18
18
  - **🚀 Blazing Fast**: Built on a modular Nio4r-powered engine for minimal overhead and instant boot times.
19
- - **📂 Multi-Database**: Seamlessly switch between SQLite, MySQL, MariaDB, and MongoDB Atlas.
19
+ - **📂 Multi-Database**: Seamlessly switch and migrate data between SQLite, MySQL, MariaDB, and MongoDB Atlas.
20
20
  - **🛠️ Developer First**: A robust CLI (`ofa`) that handles everything from scaffolding to deployment.
21
21
  - **🔐 Enterprise Ready**: Built-in CSRF protection, secure session management, and input validation.
22
22
  - **🌐 Global Support**: Multi-language (I18n) support and SEO optimization ready.
@@ -52,9 +52,75 @@ Your app is now live at `http://localhost:3000` ⚡
52
52
 
53
53
  ---
54
54
 
55
- ## 🛠️ CLI Power Tools (Detailed Reference)
55
+ ## 🛠️ CLI Deep Dive & Expected Outputs
56
+
57
+ The `ofa` CLI is designed to be interactive and informative. Below is a detailed breakdown of all available commands and the visual feedback they provide.
58
+
59
+ ### 📦 Project & Environment
60
+ #### `ofa init [TYPE]`
61
+ Initialize your workspace. Triggers an interactive wizard for Database and Storage setup.
62
+ * **Output Example:**
63
+ ```text
64
+ 🛠️ Project Configuration
65
+ 💾 Choose Database [1. SQLite, 2. MongoDB Atlas]: 2
66
+ 🔗 Enter MongoDB Connection String: mongodb+srv://...
67
+ 🖼️ Choose Image Storage [1. Local, 2. Cloudinary]: 1
68
+ ✅ Connection string saved to .env
69
+ ✅ Project structure initialized.
70
+ ```
71
+
72
+ #### `ofa run`
73
+ Boots the high-performance Eksa Server engine.
74
+ * **Output Example:**
75
+ ```text
76
+ Starting One-For-All server...
77
+ [INFO] Mendengarkan di TCP: 0.0.0.0:3000
78
+ [EksCent] 2026-05-03 14:40:52 | GET / | Status: 200
79
+ ```
80
+
81
+ ### 🏗️ Generators (Scaffolding)
82
+ #### `ofa g controller NAME`
83
+ * **Output:** `✅ Created app/controllers/blog_controller.rb`
84
+ #### `ofa g model NAME`
85
+ * **Output:** `✅ Created app/models/product.rb`
86
+ #### `ofa g post TITLE [args]`
87
+ Creates a SEO-optimized blog post with metadata.
88
+ * **Example:** `./ofa g post "Hello World" --author Antigravity`
89
+ * **Output:** `✅ Created app/views/posts/hello_world.erb`
90
+
91
+ ### 📂 Database Management
92
+ #### `ofa db switch TYPE [URL]`
93
+ Switches your database adapter on the fly.
94
+ * **Output:** `Switched to mongodb mode.`
95
+
96
+ #### `ofa db migrate-data TYPE [URL]`
97
+ **The most powerful tool.** Moves all data from your current DB to a new one (SQL or MongoDB Atlas).
98
+ * **Output Example:**
99
+ ```text
100
+ 📦 Starting data migration: sqlite -> mongodb...
101
+ Migrating users... 12 rows.
102
+ Migrating posts... 45 rows.
103
+ ✅ Migration successful!
104
+ ```
105
+
106
+ #### `ofa db migrate` (or `ofa migrate`)
107
+ Runs pending database migrations in `db/migrations/`.
108
+ * **Output:** `✅ Migrations completed.`
109
+
110
+ ### 🎨 Customization & Security
111
+ #### `ofa theme NAME`
112
+ Changes the entire UI skin (Modern Glass, Retro, Cyber).
113
+ * **Output:** `✅ Theme set to: retro_terminal`
114
+
115
+ #### `ofa storage NAME`
116
+ Switches between local disk and Cloudinary cloud storage.
117
+ * **Output:** `✅ Storage set to: cloudinary`
118
+
119
+ #### `ofa reset-password USR PWD`
120
+ Securely manages admin credentials.
121
+ * **Output:** `✅ Password for 'admin' updated successfully.`
56
122
 
57
- The `ofa` CLI is the heart of the One-For-All framework. It handles everything from project initialization to production deployment.
123
+ ---
58
124
 
59
125
  ### 📁 Project Lifecycle
60
126
  | Command | Description |
@@ -93,9 +159,10 @@ Fine-tune your application's behavior and appearance without touching the code.
93
159
  ### 🔐 Security & Database
94
160
  | Command | Description |
95
161
  | :--- | :--- |
96
- | `ofa reset-password USR PWD`| **User Management.** Resets a password for an existing admin or creates a new one. <br> *Note:* Enforces strong password rules (8+ chars, 1 uppercase, 1 number). |
97
- | `ofa db switch ADAPTER` | **Hot-swap Database.** Configure your adapter on the fly: `sqlite`, `mysql`, `mariadb`, `postgres`, or `env` (for MongoDB Atlas). |
98
- | `ofa db migrate` | **Database Sync.** Runs all pending migrations in `db/migrations/` to keep your schema up to date. |
162
+ | `ofa reset-password USR PWD`| **Enterprise Recovery.** Resets admin credentials with strict enforcement: 8+ chars, uppercase, and numbers. Powered by BCrypt hashing. |
163
+ | `ofa db migrate-data TYPE [NAME]`| **Zero-Loss Migration.** The ultimate tool to move data (Users, Posts, Products) from SQLite to MongoDB Atlas or other SQL DBs without losing a single record. |
164
+ | `ofa db switch ADAPTER` | **Hot-swap Engine.** Instantly change your database adapter. Supports `sqlite`, `mysql`, `mariadb`, `postgres`, and `mongodb`. |
165
+ | `ofa db migrate` | **Schema Evolution.** Runs all pending migrations. OFA automatically handles table creation for core models during boot for maximum reliability. |
99
166
 
100
167
  ---
101
168
 
data/app/views/docs.erb CHANGED
@@ -1,6 +1,6 @@
1
1
  <div class="space-y-12 pb-20">
2
2
  <div class="text-left">
3
- <div class="badge-premium">Documentation v3.0.0</div>
3
+ <div class="badge-premium">Documentation v4.0.0</div>
4
4
  <h1 class="text-5xl font-black tracking-tighter mb-4 text-slate-700 dark:text-white">Framework <span class="text-primary">Guide</span></h1>
5
5
  <p class="text-xl text-slate-500 max-w-2xl leading-relaxed">Everything you need to know about building premium web applications with the One-For-All framework.</p>
6
6
  </div>
@@ -94,6 +94,27 @@
94
94
  <td class="px-6 py-4 font-mono text-primary">./ofa storage NAME</td>
95
95
  <td class="px-6 py-4 text-slate-600 dark:text-slate-400 text-xs">Hot-swap storage: <code>local</code> or <code>cloudinary</code>.</td>
96
96
  </tr>
97
+ <tr class="bg-slate-500/5"><td colspan="2" class="px-6 py-2 text-[10px] font-black uppercase tracking-tighter text-slate-400">Database & Security</td></tr>
98
+ <tr>
99
+ <td class="px-6 py-4 font-mono text-primary">./ofa db migrate-data TYPE [NAME]</td>
100
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400 text-xs">
101
+ Migrate all data from current DB to a new destination (SQL/Mongo).
102
+ <div class="mt-2 p-2 bg-slate-900 rounded font-mono text-[10px] text-green-400 border border-white/5">
103
+ 📦 Starting data migration: sqlite -> mongo...<br>
104
+ Migrating users... 12 rows.<br>
105
+ ✅ Migration successful!
106
+ </div>
107
+ </td>
108
+ </tr>
109
+ <tr>
110
+ <td class="px-6 py-4 font-mono text-primary">./ofa reset-password USR PWD</td>
111
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400 text-xs">
112
+ Reset admin password (min 8 chars, 1 upper, 1 num).
113
+ <div class="mt-2 p-2 bg-slate-900 rounded font-mono text-[10px] text-green-400 border border-white/5">
114
+ ✅ Password for 'admin' updated successfully.
115
+ </div>
116
+ </td>
117
+ </tr>
97
118
  </tbody>
98
119
  </table>
99
120
  </div>
@@ -145,6 +166,20 @@
145
166
  </div>
146
167
  </div>
147
168
  </div>
169
+
170
+ <div class="glass-panel p-6 space-y-4">
171
+ <h4 class="text-[10px] font-black uppercase tracking-widest text-primary border-b border-white/5 pb-2">Database & Security</h4>
172
+ <div class="space-y-4">
173
+ <div>
174
+ <code class="text-primary font-bold text-xs">./ofa db migrate-data TYPE [NAME]</code>
175
+ <p class="text-slate-500 text-xs mt-1">Migrate data to new DB destination.</p>
176
+ </div>
177
+ <div>
178
+ <code class="text-primary font-bold text-xs">./ofa reset-password USR PWD</code>
179
+ <p class="text-slate-500 text-xs mt-1">Manage admin credentials.</p>
180
+ </div>
181
+ </div>
182
+ </div>
148
183
  </div>
149
184
  </section>
150
185
 
data/app/views/index.erb CHANGED
@@ -1,6 +1,6 @@
1
1
  <div class="text-center space-y-6 max-w-2xl mx-auto py-12">
2
2
  <div class="inline-flex items-center px-4 py-1.5 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-bold uppercase tracking-wider animate-pulse">
3
- Framework Version 3.0.0
3
+ Framework Version 4.0.0
4
4
  </div>
5
5
 
6
6
  <h1 class="text-5xl md:text-7xl font-black tracking-tight leading-tight">
data/bin/ofa CHANGED
@@ -22,7 +22,7 @@ def help
22
22
  puts " / __ \\/ ____/ / | "
23
23
  puts " / / / / /_ / /| | Framework "
24
24
  puts "/ /_/ / __/ / ___ | Premium MVC "
25
- puts "\\____/_/ /_/ |_| v2.0.0 "
25
+ puts "\\____/_/ /_/ |_| v4.0.0 "
26
26
  puts " "
27
27
  puts "✨ One-For-All Framework CLI ✨"
28
28
  puts "-----------------------------"
@@ -39,6 +39,7 @@ def help
39
39
  puts " ofa storage NAME - Set image storage: local, cloudinary"
40
40
  puts " ofa reset-password USR PWD - Reset admin account password"
41
41
  puts " ofa db switch TYPE [NAME] - Switch DB: sqlite, mysql, mariadb, mongodb, postgres"
42
+ puts " ofa db migrate-data TYPE [NAME] - Migrate data to another DB"
42
43
  puts " ofa db migrate - Run database migrations"
43
44
  puts " ofa migrate - Run database migrations (alias for db migrate)"
44
45
  puts " ofa run - Start the application server"
@@ -67,6 +68,117 @@ def run_migrations
67
68
  end
68
69
  end
69
70
 
71
+ def perform_db_migration(target_type, target_name)
72
+ # 1. Initialize source environment
73
+ Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
74
+ require File.join(FRAMEWORK_ROOT, 'config', 'boot')
75
+ source_db = DB
76
+
77
+ puts "📦 Starting data migration: #{DB_CONFIG['adapter']} -> #{target_type}..."
78
+
79
+ # 2. Setup target connection
80
+ target_db = nil
81
+ target_mongo = nil
82
+
83
+ if ['mongodb', 'mongo'].include?(target_type)
84
+ require 'mongo'
85
+ target_mongo = Mongo::Client.new(target_name)
86
+ target_db = Sequel.connect("sqlite://db/data.sqlite3")
87
+ elsif target_type == 'sqlite'
88
+ target_db = Sequel.connect("sqlite://#{target_name || 'db/production.sqlite3'}")
89
+ else
90
+ target_db = Sequel.connect("#{target_type}://root:@localhost/#{target_name}")
91
+ end
92
+
93
+ # 3. Ensure target tables exist
94
+ if target_db
95
+ target_db.extension :pagination
96
+ # Re-use the schema creation logic by mimicking a mini-boot
97
+ # For simplicity, we'll just create core tables if they don't exist
98
+ [:users, :pages, :posts, :projects, :products].each do |table|
99
+ unless target_db.table_exists?(table)
100
+ # Copy schema from source (very basic approach)
101
+ schema = source_db.schema(table)
102
+ target_db.create_table(table) do
103
+ schema.each do |col_name, col_info|
104
+ column col_name, col_info[:db_type], primary_key: col_info[:primary_key], allow_null: col_info[:allow_null]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # 4. Migrate data
112
+ [:users, :pages, :posts, :projects, :products].each do |table|
113
+ print " Migrating #{table}... "
114
+ rows = []
115
+
116
+ # Try fetching from Mongo if it exists
117
+ source_mongo = defined?(MONGO_CLIENT) ? MONGO_CLIENT : nil
118
+ if source_mongo
119
+ begin
120
+ mongo_rows = source_mongo[table].find.to_a
121
+ if mongo_rows.any?
122
+ rows = mongo_rows.map do |r|
123
+ r[:id] = r[:_id].to_s if r[:_id]
124
+ r.delete(:_id)
125
+ r
126
+ end
127
+ end
128
+ rescue
129
+ # Collection might not exist in Mongo, fallback to SQL
130
+ end
131
+ end
132
+
133
+ # Fallback to SQL if no rows found in Mongo
134
+ if rows.empty?
135
+ begin
136
+ rows = source_db[table].all
137
+ rescue
138
+ rows = []
139
+ end
140
+ end
141
+
142
+ # Clear target table before migrating to avoid duplicates
143
+ if target_db && target_db.table_exists?(table)
144
+ target_db[table].delete
145
+ end
146
+
147
+ count = 0
148
+ rows.each do |row|
149
+ if target_type == 'mongodb' && table == :users
150
+ # Users go to Mongo in Mongo mode
151
+ target_mongo[:users].update_one({ username: row[:username] }, { "$set" => row.reject{|k| k == :id} }, { upsert: true })
152
+ elsif target_db
153
+ # Deep cleaning and type conversion for SQLite compatibility
154
+ target_columns = target_db[table].columns
155
+ clean_row = {}
156
+ row.each do |k, v|
157
+ sym_k = k.to_sym
158
+ if target_columns.include?(sym_k) && sym_k != :id
159
+ if v.is_a?(BSON::ObjectId)
160
+ clean_row[sym_k] = v.to_s
161
+ elsif v.is_a?(Time)
162
+ clean_row[sym_k] = v.strftime('%Y-%m-%d %H:%M:%S')
163
+ else
164
+ clean_row[sym_k] = v
165
+ end
166
+ end
167
+ end
168
+ target_db[table].insert(clean_row)
169
+ end
170
+ count += 1
171
+ end
172
+ puts "#{count} rows."
173
+ end
174
+
175
+ # 5. Update configuration to point to new DB
176
+ absolute_ofa_path = File.expand_path(__FILE__)
177
+ system("ruby #{absolute_ofa_path} db switch #{target_type} #{target_name}")
178
+
179
+ puts "✅ Migration successful!"
180
+ end
181
+
70
182
  def ensure_initialized!
71
183
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
72
184
  unless File.exist?(config_path)
@@ -114,7 +226,7 @@ when 'init'
114
226
  puts " / __ \\/ ____/ / | "
115
227
  puts " / / / / /_ / /| | Framework "
116
228
  puts "/ /_/ / __/ / ___ | Premium MVC "
117
- puts "\\____/_/ /_/ |_| v2.0.0 "
229
+ puts "\\____/_/ /_/ |_| v4.0.0 "
118
230
  puts " "
119
231
  puts "Initializing One-For-All project as '#{app_type}' in #{PROJECT_ROOT}..."
120
232
 
@@ -442,8 +554,10 @@ when 'storage'
442
554
  puts "Application storage set to '#{name}'."
443
555
 
444
556
  when 'reset-password'
557
+ ENV['SKIP_MODELS'] = '1'
445
558
  Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
446
559
  require File.join(FRAMEWORK_ROOT, 'config', 'boot')
560
+ require File.join(FRAMEWORK_ROOT, 'app', 'models', 'user.rb')
447
561
  user_name = ARGV.shift
448
562
  new_pwd = ARGV.shift
449
563
  if user_name.nil? || new_pwd.nil?
@@ -479,8 +593,16 @@ when 'db'
479
593
  type = ARGV.shift
480
594
  db_name = ARGV.shift
481
595
  case type
482
- when 'env'
596
+ when 'env', 'mongo', 'mongodb'
483
597
  config = { "adapter" => "env" }
598
+ if db_name && db_name.start_with?('mongodb')
599
+ env_path = File.join(PROJECT_ROOT, '.env')
600
+ env_lines = File.exist?(env_path) ? File.readlines(env_path) : []
601
+ env_lines.reject! { |l| l.start_with?('DATABASE_URL=') }
602
+ env_lines << "DATABASE_URL=#{db_name}\n"
603
+ File.write(env_path, env_lines.join)
604
+ puts "✅ Connection string saved to .env"
605
+ end
484
606
  when 'sqlite'
485
607
  config = { "adapter" => "sqlite", "database" => db_name || "db/development.sqlite3" }
486
608
  else
@@ -490,6 +612,14 @@ when 'db'
490
612
  puts "Switched to #{type} mode."
491
613
  when 'migrate'
492
614
  run_migrations
615
+ when 'migrate-data'
616
+ target_type = ARGV.shift
617
+ target_name = ARGV.shift
618
+ if target_type.nil?
619
+ puts "Usage: ofa db migrate-data TYPE [NAME/URL]"
620
+ exit 1
621
+ end
622
+ perform_db_migration(target_type, target_name)
493
623
  end
494
624
 
495
625
  when 'run'
data/config/database.json CHANGED
@@ -1,4 +1,3 @@
1
1
  {
2
- "adapter": "sqlite",
3
- "database": "db/development.sqlite3"
2
+ "adapter": "env"
4
3
  }
data/config/database.rb CHANGED
@@ -114,6 +114,22 @@ if DB
114
114
  end
115
115
  end
116
116
 
117
+ unless DB.table_exists?(:products)
118
+ DB.create_table :products do
119
+ primary_key :id
120
+ String :name, null: false
121
+ String :slug, null: false, unique: true
122
+ String :description, text: true
123
+ Float :price, default: 0.0
124
+ Integer :stock, default: 0
125
+ String :image_url
126
+ String :category
127
+ TrueClass :is_active, default: true
128
+ DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
129
+ DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
130
+ end
131
+ end
132
+
117
133
  # Quick Migration for existing tables
118
134
  if DB.table_exists?(:pages)
119
135
  DB.alter_table(:pages) { add_column :is_active, TrueClass, default: true unless DB[:pages].columns.include?(:is_active) }
data/db/data.sqlite3 CHANGED
Binary file
Binary file
data/db/target.sqlite3 ADDED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: one-for-all-framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ishikawa Uta
@@ -238,6 +238,7 @@ files:
238
238
  - db/data.sqlite3
239
239
  - db/development.sqlite3
240
240
  - db/migrations/20260502000000_create_products.rb
241
+ - db/target.sqlite3
241
242
  - ofa
242
243
  - public/css/cms.css
243
244
  - public/images/logo.jpg