diff --git a/.env.development.example b/.env.development.example new file mode 100644 index 00000000..9963999f --- /dev/null +++ b/.env.development.example @@ -0,0 +1,21 @@ +# .env.development.example +# Example environment variables for local development + +DATABASE_URL=postgresql://postgres:starter@localhost:5432/hc_rails_starter_development +# HCA OAuth +HCA_CLIENT_ID= +HCA_CLIENT_SECRET= +HCA_COMMUNITY=1 # this allows for testing with non-HQ HCA applications. +# It removes phone numbers, birthdays and addresses from oauth scopes. + +# Slack bot token for profile sync +SLACK_BOT_TOKEN= + +# Geocoding API (Hack Club service) +GEOCODER_API_KEY= + +# External API key for /api/v1 endpoints +EXTERNAL_API_KEY=dev_api_key + +# Optional: URL to ping for uptime monitoring (leave empty if not using) +# UPTIME_WORKER_PING_URL= diff --git a/.gitignore b/.gitignore index a2be965a..2fa66fce 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ node_modules/ .env .env.* !.env.example +!.env.development.example # Database /db/*.sqlite3 diff --git a/README.md b/README.md index 0436cb15..0cba2335 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,14 @@ -# Hack Club Rails Starter Template +# Forge -This template is a very opinionated starting point for my Hack Club programs written in Rails. It is heavily inspired by, with code used from, previous Hack Club programs and services such as the Summer of Making, HCB, and Submit, as well as [24c02/thirdrail](https://github.com/24c02/thirdrail). +Welcome to Forge! Forge is a [Hack Club](https://hackclub.com) YSWS program for teens to build hardware projects. -Is it good? I don't know, but it's good enough for me. +[Start forgin' it](https://forge.hackclub.com/?utm_source=github_readme) -## Features +## Security -- HCA OAuth authentication with automatic Slack profile sync -- Role-based access control (Admin, Reviewer, User) via Pundit -- Project CRUD with tagging, visibility controls, and soft delete -- Ship review workflow (pending, approved, returned, rejected) with frozen data snapshots and encrypted storage -- Admin dashboard for managing users, projects, ships, and background jobs -- Audit trails via PaperTrail -- File-based Markdown documentation with caching and auto-generated navigation -- Ahoy analytics with visit tracking, geolocation, and UTM attribution -- Rack::Attack rate limiting and request filtering -- Solid Queue, Solid Cache, and Solid Cable for jobs, caching, and WebSockets -- Inertia.js with React 19, Vite, and TypeScript -- Tailwind CSS 4 -- Sentry error tracking, Skylight performance monitoring -- Active Storage with Cloudflare R2 and image variant processing -- Kamal deployment with Thruster for HTTP caching/compression +Security vulnerabilities should never be reported on slack or via github issues! Please report all security issues to [https://security.hackclub.com](https://security.hackclub.com) -## Local Development Setup +## Contributing +Please see [the contributing tab](https://github.com/hackclub/forge?tab=contributing-ov-file#) -### 1. Prerequisites - -- Ruby (see `.ruby-version` or Gemfile) -- Node.js (for Vite and frontend dependencies) -- Bundler (`gem install bundler`) -- Docker (for running Postgres) - -### 2. Start Postgres with Docker - -You can spin up a local Postgres instance using Docker: - -```sh -docker run -d \ - --name hc-rails-starter-postgres \ - -e POSTGRES_USER=postgres \ - -e POSTGRES_PASSWORD=starter \ - -e POSTGRES_DB=hc_rails_starter_development \ - -p 5432:5432 \ - postgres:15 -``` - -Update your `.env` file with the database URL: - -``` -DATABASE_URL=postgresql://postgres:starter@localhost:5432/hc_rails_starter_development -``` - -### 3. Install dependencies - -```sh -bundle install -npm install -``` - -### 4. Setup credentials - -The template ships with a placeholder `config/credentials.yml.enc`. Delete it and generate fresh credentials for your project: - -```sh -rm config/credentials.yml.enc -bin/rails credentials:edit -``` - -Then generate Active Record encryption keys and paste them into the credentials file: - -```sh -bin/rails db:encryption:init -``` - -Copy the output into your credentials file so it looks like: - -```yaml -active_record_encryption: - primary_key: - deterministic_key: - key_derivation_salt: -``` - -This creates `config/master.key` (keep this secret, never commit it) and a new `config/credentials.yml.enc`. - -### 5. Setup the database - -```sh -bin/rails db:setup -``` - -### 6. Start the Rails server - -```sh -bin/dev -``` - -### Cloudflare R2 (Production) - -Active Storage is configured to use Cloudflare R2 in production. Development uses local disk storage by default. To set up R2 for production, create an R2 bucket and API token in the Cloudflare dashboard, then set these environment variables: - -``` -R2_ACCESS_KEY_ID=your_access_key_id -R2_SECRET_ACCESS_KEY=your_secret_access_key -R2_BUCKET=your_bucket_name -R2_ENDPOINT=https://.r2.cloudflarestorage.com -``` - ---- - -See `.env.development.example` for required environment variables. - - -cacaw +We're always looking for people to help with the platform! PRs are welcome. Local development and deployment instructions can be found [here](https://github.com/hackclub/forge/blob/main/development.md). PRs are welcome! \ No newline at end of file diff --git a/app/controllers/markdown_controller.rb b/app/controllers/markdown_controller.rb index d0b92000..ee8f0a9e 100644 --- a/app/controllers/markdown_controller.rb +++ b/app/controllers/markdown_controller.rb @@ -20,7 +20,7 @@ def show content_html = helpers.render_markdown_file(path) file_meta = helpers.guide_metadata_for(path) meta = helpers.docs_meta_for_url("/docs#{slug == 'index' ? '' : "/#{slug}"}") - page_title = file_meta[:title].presence || meta&.dig(:title).presence || slug.tr("-_/", " ").split.map(&:capitalize).join(" ") + page_title = meta&.dig(:title).presence || file_meta[:title].presence || slug.tr("-_/", " ").split.map(&:capitalize).join(" ") render inertia: "Markdown/Show", props: { content_html: content_html, diff --git a/app/helpers/markdown_helper.rb b/app/helpers/markdown_helper.rb index bcde031e..71f70f1c 100644 --- a/app/helpers/markdown_helper.rb +++ b/app/helpers/markdown_helper.rb @@ -1,6 +1,7 @@ require "redcarpet" require "uri" require "digest" +require "yaml" module MarkdownHelper def self.canonical_base_url @@ -116,7 +117,8 @@ def render_markdown_file(path, base_url: nil) def docs_metadata(base:, url_prefix:, default_index_title: "") paths = Dir.glob(base.join("**/*.md").to_s) - stats = paths.map { |p| [ p, File.mtime(p).to_i ] }.sort_by(&:first) + config_paths = Dir.glob(base.join("**/config.yaml").to_s) + stats = (paths + config_paths).uniq.map { |p| [ p, File.mtime(p).to_i ] }.sort_by(&:first) return build_docs_metadata(base, url_prefix, default_index_title, paths) if Rails.env.development? stats_digest = Digest::SHA256.hexdigest(stats.flatten.join("|")) @@ -147,6 +149,7 @@ def build_docs_metadata(base, url_prefix, default_index_title, paths) end meta = parse_guide_metadata(p) + meta = merge_docs_metadata(meta, docs_config_metadata_for_path(p)) if File.basename(p) == "index.md" fallback_title = if slug.blank? default_index_title else @@ -154,7 +157,7 @@ def build_docs_metadata(base, url_prefix, default_index_title, paths) end title = meta[:title].presence || fallback_title desc = meta[:description].presence - prio = meta[:priority] + prio = meta[:priority].nil? ? 0 : meta[:priority].to_i unlisted = meta[:unlisted] || false items << { title: title, path: url, description: desc, slug: slug, file: p, priority: prio, unlisted: unlisted } end @@ -167,9 +170,8 @@ def docs_section_metadata end def docs_menu_items - docs_section_metadata + sorted_docs_items(docs_section_metadata) .reject { |i| i[:slug].blank? || i[:unlisted] } - .sort_by { |h| [ h[:priority].nil? ? Float::INFINITY : h[:priority].to_i, h[:title].downcase ] } .map { |i| { title: i[:title], path: i[:path], description: i[:description] } } end @@ -191,9 +193,8 @@ def menu_items_for(url_path) base = Rails.root.join("docs", section) return [] unless File.directory?(base) - docs_metadata(base: base, url_prefix: url_path, default_index_title: section.titleize) + sorted_docs_items(docs_metadata(base: base, url_prefix: url_path, default_index_title: section.titleize)) .reject { |i| i[:slug].blank? || i[:unlisted] } - .sort_by { |h| [ h[:priority].nil? ? Float::INFINITY : h[:priority].to_i, h[:title].downcase ] } .map { |i| { title: i[:title], path: i[:path], description: i[:description] } } end @@ -212,41 +213,109 @@ def build_docs_sidebar_nodes(base, rel_dir) dir = rel_dir.blank? ? base : base.join(rel_dir) entries = Dir.children(dir).sort_by(&:downcase) - folders = entries.select { |name| File.directory?(dir.join(name)) } - files = entries.select { |name| name.end_with?(".md") } - - folder_nodes = folders.map do |folder_name| - child_rel_dir = rel_dir.blank? ? folder_name : File.join(rel_dir, folder_name) - child_nodes = build_docs_sidebar_nodes(base, child_rel_dir) - folder_index_path = dir.join(folder_name, "index.md") - folder_meta_title = File.exist?(folder_index_path) ? parse_guide_metadata(folder_index_path)[:title].presence : nil - - { - type: "folder", - title: folder_meta_title || humanize_sidebar_name(folder_name), - path: docs_path_for_sidebar(child_rel_dir), - children: child_nodes - } + nodes = entries.filter_map do |name| + entry_path = dir.join(name) + + if File.directory?(entry_path) + child_rel_dir = rel_dir.blank? ? name : File.join(rel_dir, name) + folder_meta = docs_directory_metadata(entry_path) + + { + type: "folder", + title: folder_meta[:title].presence || humanize_sidebar_name(name), + path: docs_path_for_sidebar(child_rel_dir), + priority: folder_meta[:priority].nil? ? 0 : folder_meta[:priority].to_i, + children: build_docs_sidebar_nodes(base, child_rel_dir) + } + elsif name.end_with?(".md") && !(rel_dir.present? && File.basename(name, ".md") == "index") + file_rel_path = rel_dir.blank? ? name : File.join(rel_dir, name) + file_meta = docs_page_metadata(entry_path) + + { + type: "page", + title: file_meta[:title].presence || humanize_sidebar_name(File.basename(name, ".md")), + path: docs_path_for_sidebar(file_rel_path), + priority: file_meta[:priority].nil? ? 0 : file_meta[:priority].to_i + } + end + end + + if rel_dir.blank? + sorted_docs_items(nodes.select { |item| item[:type] == "page" }) + + sorted_docs_items(nodes.select { |item| item[:type] == "folder" }) + else + sorted_docs_items(nodes) end + end + + def sorted_docs_items(items) + items.sort_by { |item| [ -(item[:priority] || 0).to_i, item[:title].to_s.downcase, item[:path].to_s ] } + end + + def docs_page_metadata(path) + meta = parse_guide_metadata(path) + return meta unless File.basename(path) == "index.md" + + merge_docs_metadata(meta, docs_config_metadata_for_path(path)) + end + + def docs_directory_metadata(dir) + index_path = dir.join("index.md") + index_meta = File.exist?(index_path) ? parse_guide_metadata(index_path) : {} + + merge_docs_metadata(index_meta, docs_config_metadata(dir)) + end + + def docs_config_metadata_for_path(path) + docs_config_metadata(Pathname.new(path).dirname) + end - visible_files = files.reject { |file_name| rel_dir.present? && File.basename(file_name, ".md") == "index" } + def docs_config_metadata(dir) + config_path = dir.join("config.yaml") + return default_docs_metadata unless File.exist?(config_path) - sorted_files = visible_files.sort_by do |file_name| - [ File.basename(file_name, ".md") == "index" ? 0 : 1, file_name.downcase ] + if Rails.env.development? + build_docs_config_metadata(config_path) + else + key = [ "docs_yaml_meta", config_path.to_s, File.mtime(config_path).to_i ] + Rails.cache.fetch(key) { build_docs_config_metadata(config_path) } end + end + + def build_docs_config_metadata(config_path) + raw = YAML.safe_load(File.read(config_path)) + data = raw.is_a?(Hash) ? raw : {} + + { + title: data["title"].presence, + description: data["description"].presence, + priority: parse_priority_value(data["priority"]) + } + rescue Errno::ENOENT, Psych::SyntaxError + default_docs_metadata + end - page_nodes = sorted_files.map do |file_name| - file_rel_path = rel_dir.blank? ? file_name : File.join(rel_dir, file_name) - file_path = dir.join(file_name) - meta_title = parse_guide_metadata(file_path)[:title].presence - { - type: "page", - title: meta_title || humanize_sidebar_name(File.basename(file_name, ".md")), - path: docs_path_for_sidebar(file_rel_path) - } + def merge_docs_metadata(*sources) + merged = default_docs_metadata + + sources.compact.each do |source| + merged[:title] = source[:title] if source[:title].present? + merged[:description] = source[:description] if source[:description].present? + merged[:priority] = source[:priority] unless source[:priority].nil? + merged[:unlisted] = true if source[:unlisted] end - rel_dir.blank? ? (page_nodes + folder_nodes) : (folder_nodes + page_nodes) + merged + end + + def parse_priority_value(value) + Integer(value) + rescue ArgumentError, TypeError + nil + end + + def default_docs_metadata + { title: nil, description: nil, priority: nil, unlisted: false } end def docs_path_for_sidebar(rel_path) diff --git a/app/javascript/pages/Projects/Show.tsx b/app/javascript/pages/Projects/Show.tsx index 0358d648..b0c405b7 100644 --- a/app/javascript/pages/Projects/Show.tsx +++ b/app/javascript/pages/Projects/Show.tsx @@ -514,7 +514,7 @@ export default function ProjectsShow({ <>

No journal entries yet.

Add a JOURNAL.md to your repo and click "Sync JOURNAL.md" above.

- See the format guide + See the format guide ) : (

{project.user_display_name} hasn't added a journal entry yet.

diff --git a/development.md b/development.md new file mode 100644 index 00000000..f2ec3fe2 --- /dev/null +++ b/development.md @@ -0,0 +1,95 @@ +# Forge development and deployment + +Forge is written in Rails, heavily inspired by, with code used from, previous Hack Club programs and services such as the Hack Club rails starter template, Summer of Making, HCB, and Submit, as well as [24c02/thirdrail](https://github.com/24c02/thirdrail). + +## Local Development Setup + +### 1. Prerequisites + +- Ruby (see `.ruby-version` or Gemfile) +- Node.js (for Vite and frontend dependencies) +- Bundler (`gem install bundler`) +- Docker (for running Postgres) + +### 2. Start Postgres with Docker + +You can spin up a local Postgres instance using Docker: + +```sh +docker run -d \ + --name hc-rails-starter-postgres \ + -e POSTGRES_USER=postgres \ + -e POSTGRES_PASSWORD=starter \ + -e POSTGRES_DB=hc_rails_starter_development \ + -p 5432:5432 \ + postgres:15 +``` + +Update your `.env` file with the database URL: + +``` +DATABASE_URL=postgresql://postgres:starter@localhost:5432/hc_rails_starter_development +``` + +### 3. Install dependencies + +```sh +bundle install +npm install +``` + +### 4. Setup credentials + +The template ships with a placeholder `config/credentials.yml.enc`. Delete it and generate fresh credentials for your project: + +```sh +rm config/credentials.yml.enc +bin/rails credentials:edit +``` + +Then generate Active Record encryption keys and paste them into the credentials file: + +```sh +bin/rails db:encryption:init +``` + +Copy the output into your credentials file so it looks like: + +```yaml +active_record_encryption: + primary_key: + deterministic_key: + key_derivation_salt: +``` + +This creates `config/master.key` (keep this secret, never commit it) and a new `config/credentials.yml.enc`. + +### 5. Setup the database + +```sh +bin/rails db:setup +``` + +### 6. Start the Rails server + +```sh +bin/dev +``` + +### Cloudflare R2 (Production) + +Active Storage is configured to use Cloudflare R2 in production. Development uses local disk storage by default. To set up R2 for production, create an R2 bucket and API token in the Cloudflare dashboard, then set these environment variables: + +``` +R2_ACCESS_KEY_ID=your_access_key_id +R2_SECRET_ACCESS_KEY=your_secret_access_key +R2_BUCKET=your_bucket_name +R2_ENDPOINT=https://.r2.cloudflarestorage.com +``` + +--- + +See `.env.development.example` for required environment variables. + + +cacaw diff --git a/docs/FAQ.md b/docs/FAQ.md index 2f86f92d..68d612c0 100755 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -8,9 +8,18 @@ Forge is open to builders aged 13 to 18. You must be a member of the Hack Club Slack. +## When does Forge end? + +There's no set date right now, but expect it to last at least until June-July 2026. + ## How much funding can I get? -Theoretically unlimited! The amount depends on the scope of your project and the quality of your documentation. Still try to save cost where you can! +Theoretically unlimited! Depending on the compexity of your project (the tier), you can earn between 4c to 7c per hour. You can then exchance these coins for funding where 1c = 1 USD. + +# What kind of projects can I make? + +You can make anything related to hardware where you put majority of the work in making the hardware side of the project. This includes things like keyboards, 3D printers and custom pcbs. Projects like home servers where you are mainly working on the software aspect are not allowed for Forge. If you are ever unsure of what your project may be considered as, ask in #forge on the Hack Club slack + ## Do I need to know how to code? @@ -41,3 +50,52 @@ Once your project is approved, you'll receive funding through a virtual card on ## Can I work on a team? Each person should pitch their own project. If you're working together, each person should have a distinct contribution and their own project page. + + +## Can I buy parts myself and get reimbursed later? + +This depends on a case-by-case basis. Please ask in #forge-help before you make any purchases as some things you buy may not get approved or your whole project may not be eligible for Forge. + +## Can I get reimbursed for 3D Printed parts! + +Yep! We will partially reimburse you to the nearest 250g of filament. + +## Can I submit an existing project or one that I previously started? + +If it's already finished, unfortunately not, sorry! Start a new project. +If you've just started/are in the middle of designing, you need to have journaled the entire process beforehand. + +If you're almost done designing, unfortunately not. + +## Can I double dip with Stardance, Stasis or any other Hack Club program? + +No! Double-dipping is not allowed. If you have coding time for your project, you can journal it, and get coins to use in the shop! + +## How will I get my 3D printed parts? + +Through **printing legion!** It's an international network of Hack Clubbers 3D printing for each other! Check out [their website](https://printlegion.hackclub.com/) + +## How likely is it that my project will be approved? + +It's hard to say without seeing your project, but generally speaking, as long as you follow the [guidelines](/docs/submission-guidelines) on the submitting page for your project then you're more than likely to be approved! + + +## Are hackatime-banned individuals allowed to participate? + +Sorry, No! + +## Can we use tools like Ergogen? + +You're free to use it to experiment with layouts and make design decisions, but the actual placement of the footprints and schematic has to be done manually by you. + +## Can I journal research? + +Yes! + +## Can I use auto-routing software? + +No. You must do your routing manually. + +## How can I contribute? + +PRs are accepted and appreciated! If you can make art, DM @CAN on Slack! We appreciate all help :) \ No newline at end of file diff --git a/docs/api.md b/docs/Miscellaneous/api.md similarity index 98% rename from docs/api.md rename to docs/Miscellaneous/api.md index 5ba5da06..ca98aef5 100644 --- a/docs/api.md +++ b/docs/Miscellaneous/api.md @@ -41,7 +41,6 @@ GET /api/v1/projects?status=approved&tier=tier_1&per_page=10 "id": 42, "name": "Hex Bot", "subtitle": "Mostly 3D printed 3D printer", - "description": "AI-generated admin summary...", "status": "approved", "tier": "tier_2", "tags": ["3D-printed", "DIY"], diff --git a/docs/Miscellaneous/config.yaml b/docs/Miscellaneous/config.yaml new file mode 100644 index 00000000..2e270d33 --- /dev/null +++ b/docs/Miscellaneous/config.yaml @@ -0,0 +1,2 @@ +title: "Miscellaneous" +priority: -1 \ No newline at end of file diff --git a/docs/design/config.yaml b/docs/design/config.yaml new file mode 100644 index 00000000..ad4cc822 --- /dev/null +++ b/docs/design/config.yaml @@ -0,0 +1 @@ +title: "Design Resources" diff --git a/docs/Design-Resources/cost.md b/docs/design/cost.md similarity index 95% rename from docs/Design-Resources/cost.md rename to docs/design/cost.md index 6cf15c05..8a42a302 100755 --- a/docs/Design-Resources/cost.md +++ b/docs/design/cost.md @@ -20,7 +20,7 @@ That said, please always do what you can to select the cheaper option while maki - Always choosing the cheapest option, such as GSDR, even when it comes at the cost of your time (start a new project in the meantime) - Selecting the cheapest part for whatever you are making. (You don’t need a raspberry pi 5 to blink an LED) -If you are ever stuck on cost optimizing, ask around in #forge, or check out our page on [sourcing parts](/docs/Design-Resources/sourcing-parts)! +If you are ever stuck on cost optimizing, ask around in #forge, or check out our page on [sourcing parts](/docs/design/sourcing-parts)! # How can I use my funds? diff --git a/docs/Design-Resources/sourcing-parts.md b/docs/design/sourcing-parts.md similarity index 98% rename from docs/Design-Resources/sourcing-parts.md rename to docs/design/sourcing-parts.md index ab591560..04982745 100755 --- a/docs/Design-Resources/sourcing-parts.md +++ b/docs/design/sourcing-parts.md @@ -92,7 +92,7 @@ Coming soon. - 3D printed parts (3D printing as a Service, JLC3DP-alike) - [3Ding](https://www.3ding.in/) -> confirmed more vendors? wanna add specific notes for your country? contribute [here](https://github.com/hackclub/forge/edit/main/docs/Design-Resources/sourcing-parts.md)!! You'd be helping a ton of people! +> confirmed more vendors? wanna add specific notes for your country? contribute [here](https://github.com/hackclub/forge/edit/main/docs/design/sourcing-parts.md)!! You'd be helping a ton of people! ## Tips for specific vendors diff --git a/docs/how-it-works.md b/docs/how-it-works.md index 09df3d4c..d5aae71d 100755 --- a/docs/how-it-works.md +++ b/docs/how-it-works.md @@ -6,36 +6,85 @@ Forge will fund as much as you need to build any hardware project! Here's how: -## Step 1: Pitch Your Project -**Note: Pitching is only required for Tier 1 projects only**, lower tier projects can skip straight to step 3. +## Step 3: Start Building + +Once approved, your project page unlocks the **Devlog** section. Document your progress as you build: -Post your pitch in the **#forgery** Slack channel. Your pitch will be automatically picked up and submitted for review. +- Add devlog entries directly on your project page, OR +- Create a `JOURNAL.md` file in your GitHub repo and sync it -You'll get a confirmation reply in your Slack thread, and your project will appear on your Forge dashboard as "Pending Review." +See [JOURNAL.md Format](/docs/requirements/journal-format) for details. + +## Step 4: Ship It + +When you've finished, ship it! This involves publishing your functioning design out there for the world to see. +See [Shipping](/docs/requirements/shipping) for more details. + + + + + + + +## 1. Start a new project! + +### Option 1: on the website + +Create a new project by clicking on button in the bottom left corner: + +![Forge create project button](https://cdn.hackclub.com/019db437-fb7e-7cce-abf5-e515c68f2bf0/image.png) + +Fill in all the details - you can always edit this later! Now it's time to start designing. -**Note: #forgery is a threaded channel ONLY for project pitches! Please use #forge for general discussions.** -See [Pitching Your Project](/docs/Requirements-and-Shipping/pitching) for more information. +### Option 2: make a slack pitch (required for Tier 1 projects) -## Step 2: Get Approved +If you're not too sure on whether your project suits Forge, or want some feedback before you start designing, pitch your project in the **#forgery** channel on slack! Hear feedback from reviewers and other hack clubbers, who can also help you decide which tier your project lies in before you start building! -We will review your pitch. You'll hear back directly in your Slack thread with one of three outcomes: +You'll get a confirmation reply in your Slack thread, and your project will appear on your Forge dashboard as "Pending Review". + +Afterwards, we will review your pitch. You'll hear back directly in your Slack thread with one of three outcomes: - **Approved**: You're good to go! Start building. - **Returned for Changes**: Your pitch needs some adjustments. Read the feedback and re-pitch. - **Rejected**: Your project doesn't fit the program. Don't worry, you can pitch a different project! -## Step 3: Start Building +**Note: #forgery is a threaded channel ONLY for project pitches! Please use #forge for general discussions.** -Once approved, your project page unlocks the **Devlog** section. Document your progress as you build: +See [Pitching Your Project](/docs/requirements/pitching) for more information. + +**Make sure you read over the [project guidelines](/docs/requirements/project-guidelines)** to get an idea of what you can make! + +## 2. Journal your progress! + +Every time you work on your design, make a journal entry in your dashboard! + +Journal entries are how you track your time & progress in Forge. They usually contain what you did during that work session, some interesting things you noticed, and a few images! + +You can: - Add devlog entries directly on your project page, OR - Create a `JOURNAL.md` file in your GitHub repo and sync it -See [JOURNAL.md Format](/docs/Requirements-and-Shipping/journal-format) for details. +See [JOURNAL.md Format](/docs/requirements/journal-format) and [Good Journalling](/docs/requirements/how-to-journal) for details. -## Step 4: Ship It -When you've finished, ship it! This involves publishing your functioning design out there for the world to see. -See [Shipping](/docs/Requirements-and-Shipping/shipping) for more details. +**A great example journal entry can be found [here!](https://hwdocs.hackclub.dev/shipping/example-journal/)** + +## 3. Submit your design, get coins! + +Once you think you're done your project, make sure to go over each item in the **[submission requirements!](/about/submission-guidelines)** It'll ensure that your project is good to ship. Your project will be returned if it does not follow the requirements. + +**Taking the extra few minutes to go through the checklist makes the review process faster for you and everyone else, since it means that we return projects less often.** + +With coins, you can redeem them for funding for your project. If you don't need any more funding, you can spend these in the shop! + +## 4. Build your project, get tickets! + +Order your parts and actually build your project! Make sure you keep journalling! + +At the end, post a demo on reddit or YouTube! You'll get more for your build which you can spend in the shop! + + + diff --git a/docs/index.md b/docs/index.md index 1e588ebd..0d01e221 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,11 +1,15 @@ -| title | Forge Overview | +| title | Welcome to Forge! | | description | FORGE!! | +| priority | 10 | | --- | --- | # Welcome to forge! Forge is a Hack Club YSWS (You ship, we ship) program where teens like yourself can design and build hardware projects, and get them funded! -The docs section is a WIP (poke @cybdo on slack for anything inaccurate or misspelled) +The docs section is forever a WIP (poke @cybdo on slack for anything inaccurate or misspelled) + +in the meantime, check out [hwdocs.hackclub.dev](https://hwdocs.hackclub.dev) by [@alexren](https://github.com/qcoral)! + + -in the meantime, check out [hwdocs.hackclub.dev](https://hwdocs.hackclub.dev) by [@alexren](https://github.com/qcoral)! \ No newline at end of file diff --git a/docs/requirements/config.yaml b/docs/requirements/config.yaml new file mode 100644 index 00000000..299c06f6 --- /dev/null +++ b/docs/requirements/config.yaml @@ -0,0 +1 @@ +title: "Requirements and Shipping" \ No newline at end of file diff --git a/docs/Requirements-and-Shipping/how-to-journal.md b/docs/requirements/how-to-journal.md similarity index 98% rename from docs/Requirements-and-Shipping/how-to-journal.md rename to docs/requirements/how-to-journal.md index 4f1f137e..3e56627f 100644 --- a/docs/Requirements-and-Shipping/how-to-journal.md +++ b/docs/requirements/how-to-journal.md @@ -24,7 +24,7 @@ We’ll be reviewing this way too\! After submitting your design, awesome people 1. Your decisions make sense - we want your project to work! 2. Your work is original -3. Your design is good to [ship](/docs/Requirements-and-Shipping/shipping) +3. Your design is good to [ship](/docs/requirements/shipping) ## How do you Journal? diff --git a/docs/Requirements-and-Shipping/journal-format.md b/docs/requirements/journal-format.md similarity index 100% rename from docs/Requirements-and-Shipping/journal-format.md rename to docs/requirements/journal-format.md diff --git a/docs/Requirements-and-Shipping/pitching.md b/docs/requirements/pitching.md similarity index 88% rename from docs/Requirements-and-Shipping/pitching.md rename to docs/requirements/pitching.md index ba75a97a..c948ddfe 100755 --- a/docs/Requirements-and-Shipping/pitching.md +++ b/docs/requirements/pitching.md @@ -21,10 +21,11 @@ Post your pitch in **#forgery** on the Hack Club Slack. Keep it structured, hone ``` Idea: [Short name for your project] +Proposed tier: [Optional, what tier you think this project should be. Reviewers can change this if they disagree!] I'm designing: [What you're actually building — PCBs, 3D printed parts, firmware, etc.] Inspo / reference: [Links to similar projects or inspiration] Past projects: [Links to things you've built before — helps us gauge your skill level] -Why this is worth more than $200: [Why this project is ambitious/complex] +Why this is worth more than $200: [Why this project is ambitious/complex, required for T1 projects.] Rough BOM: * [Part] $[cost] @@ -57,7 +58,7 @@ Rough BOM: ### Tips - **Show your background.** One project could be next to impossible for one person but easy for another. Past projects help us understand your skill level. -- **Keep costs reasonable.** We [don't have unlimited money](/docs/Design-Resources/cost), and we want to make it last to create as many cool projects as possible! A $100 project with a $900 monitor is not a $1000 project. +- **Keep costs reasonable.** We [don't have unlimited money](/docs/design/cost), and we want to make it last to create as many cool projects as possible! A $100 project with a $900 monitor is not a $1000 project. - **Be specific about what you're designing.** "I'm building a robot" is vague. "I'm designing a custom PCB for motor control, 3D printing the chassis, and writing firmware in Rust" tells us exactly what you're doing. - **Extra detail goes in the thread.** Keep the main pitch concise. If you want to elaborate, reply to your own message in the thread. diff --git a/docs/requirements/project-guidelines.md b/docs/requirements/project-guidelines.md new file mode 100644 index 00000000..48b9befb --- /dev/null +++ b/docs/requirements/project-guidelines.md @@ -0,0 +1,65 @@ +| title | Project Guidelines | +| ----------- | ---------------------------------- | +| description | A guide to Forge projects | + + + +# Project Guidelines! + +adapted from blueprint.hackclub.com + +If you're wondering what you're allowed to build, here's a quick guide on what we generally look for! Please keep in mind these are just guidelines, so always feel free to ask in #forge! + +*above all though, the bottom line is this: build something awesome, something that you would be proud to keep in your room for the next 5 years, and something that you would be proud to show other people* + + + +## Overview + +Here's an overall list of criteria that applies to all tiers, regardless of your budget/points. + +### Originality & idea + +Almost every idea out there has been thought of before - what matters is that when designing it, which means that you do *not* do the following: + +- Directly copy paste schematics +- Directly copy paste layouts +- Directly copy paste entire programs +- Directly copy paste 3D printed / manufactured models (reference parts are OK) +- **In general, do not copy paste stuff directly - use them as references** + +Generally speaking, each project must be closer to a product than a demo - that doesn't mean go ultra advertising mode, but that does mean that a breadboarded together project with no case *doesn't* count. + +Making multiple very-similar projects will also result in a decrease of coins or a rejection (if they are too simillar). + +(more to be added) + + + + +## Examples +**Here are some examples of great projects by Hack Clubbers:** + +- @Ducc's Spotify Display, a Spotify Car Thing Clone +- @Cyao's Icepi Zero, an FPGA development dev board +- @vk6's Ender X4, a 4-toolhead 3D printer + +**Here are some examples of what *not* to build:** + +- Arduino alarm clock +- Humidity display +- Distance sensor + +**Here's some examples of how you could make those projects better:** + +- Arduino alarm clock, but it has custom LED lighting that syncs with the time of day & also has a slide switch instead of a button to control it +- A humidity display that's part of a larger weather station setup and compares the internal readings of your house to the outside world +- A distance sensor that checks if someone is coming to your room & sends an alert to your phone if they do + +**Shipping your project is the process of making it usable & understanding for other people.** It means that someone should be able to look at your README.md file and know *exactly* what they need to do to build & use your project from scratch. + +This is really important! It makes sure that your project is actually real and exists in the world, and not just as a file on your computer. + +*A good read on this can be found here: [what is shipping?](/docs/requirements/shipping)* + + diff --git a/docs/Requirements-and-Shipping/shipping.md b/docs/requirements/shipping.md similarity index 100% rename from docs/Requirements-and-Shipping/shipping.md rename to docs/requirements/shipping.md