From c140a73055f933f68a8ad26b08b40d94f4c2f218 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 05:01:57 +0000 Subject: [PATCH] Deployed 1b47cac with MkDocs version: 1.6.1 --- .nojekyll | 0 404.html | 792 ++ assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.b425cdc4.min.js | 29 + assets/javascripts/bundle.b425cdc4.min.js.map | 8 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.208ed371.min.js | 42 + .../workers/search.208ed371.min.js.map | 8 + assets/logo-horizontal.svg | 23 + assets/responsive.gif | Bin 0 -> 502471 bytes assets/scalable.gif | Bin 0 -> 796744 bytes assets/scale-and-response.gif | Bin 0 -> 599596 bytes assets/stylesheets/main.26e3688c.min.css | 1 + assets/stylesheets/main.26e3688c.min.css.map | 1 + assets/stylesheets/palette.ecc896b0.min.css | 1 + .../stylesheets/palette.ecc896b0.min.css.map | 1 + css/extra.css | 4 + developer/backend/index.html | 1005 +++ developer/design-system/index.html | 1442 ++++ developer/development-culture/index.html | 1004 +++ developer/devops/index.html | 1214 +++ developer/frontend/index.html | 1303 ++++ developer/github/index.html | 957 +++ developer/installation/index.html | 1136 +++ developer/mkdocs-architecture/index.html | 1111 +++ developer/mkdocs-edit-instructions/index.html | 947 +++ developer/mkdocs-guide/index.html | 944 +++ index.html | 926 +++ joining-the-team/content-writer/index.html | 840 +++ joining-the-team/data-scientist/index.html | 837 ++ joining-the-team/intro/index.html | 935 +++ joining-the-team/other-volunteer/index.html | 837 ++ joining-the-team/product-manager/index.html | 847 +++ joining-the-team/uiux-designer/index.html | 907 +++ joining-the-team/uiux-researcher/index.html | 893 +++ joining-the-team/web-developer/index.html | 913 +++ js/extra.js | 75 + misc/ada-guide/index.html | 925 +++ misc/glossary/index.html | 848 +++ misc/history/index.html | 913 +++ misc/our-process/index.html | 828 ++ misc/research-wiki-template/index.html | 851 +++ misc/security-updates/index.html | 829 ++ misc/the-team/index.html | 901 +++ resources/index.html | 1031 +++ search/search_index.json | 1 + sitemap.xml | 111 + sitemap.xml.gz | Bin 0 -> 464 bytes 79 files changed, 34420 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.b425cdc4.min.js create mode 100644 assets/javascripts/bundle.b425cdc4.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.208ed371.min.js create mode 100644 assets/javascripts/workers/search.208ed371.min.js.map create mode 100644 assets/logo-horizontal.svg create mode 100644 assets/responsive.gif create mode 100644 assets/scalable.gif create mode 100644 assets/scale-and-response.gif create mode 100644 assets/stylesheets/main.26e3688c.min.css create mode 100644 assets/stylesheets/main.26e3688c.min.css.map create mode 100644 assets/stylesheets/palette.ecc896b0.min.css create mode 100644 assets/stylesheets/palette.ecc896b0.min.css.map create mode 100644 css/extra.css create mode 100644 developer/backend/index.html create mode 100644 developer/design-system/index.html create mode 100644 developer/development-culture/index.html create mode 100644 developer/devops/index.html create mode 100644 developer/frontend/index.html create mode 100644 developer/github/index.html create mode 100644 developer/installation/index.html create mode 100644 developer/mkdocs-architecture/index.html create mode 100644 developer/mkdocs-edit-instructions/index.html create mode 100644 developer/mkdocs-guide/index.html create mode 100644 index.html create mode 100644 joining-the-team/content-writer/index.html create mode 100644 joining-the-team/data-scientist/index.html create mode 100644 joining-the-team/intro/index.html create mode 100644 joining-the-team/other-volunteer/index.html create mode 100644 joining-the-team/product-manager/index.html create mode 100644 joining-the-team/uiux-designer/index.html create mode 100644 joining-the-team/uiux-researcher/index.html create mode 100644 joining-the-team/web-developer/index.html create mode 100644 js/extra.js create mode 100644 misc/ada-guide/index.html create mode 100644 misc/glossary/index.html create mode 100644 misc/history/index.html create mode 100644 misc/our-process/index.html create mode 100644 misc/research-wiki-template/index.html create mode 100644 misc/security-updates/index.html create mode 100644 misc/the-team/index.html create mode 100644 resources/index.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..9754a859 --- /dev/null +++ b/404.html @@ -0,0 +1,792 @@ + + + + + + + + + + + + + + + + + + CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.b425cdc4.min.js b/assets/javascripts/bundle.b425cdc4.min.js new file mode 100644 index 00000000..201e5235 --- /dev/null +++ b/assets/javascripts/bundle.b425cdc4.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var M=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?M:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():M))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>M),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=_("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Backend Architecture

+
├── .github/
+│   └── ISSUE_TEMPLATE/
+├── app/ # Backend
+│    ├── config/  # Backend
+│          └── settings.py
+│    ├── frontend/ # Backend
+│    ├── server/  # Backend
+│    ├── .babelrc
+│    ├── manage.py
+│    ├── requirements.txt  # Backend
+│    ├── package.json
+│    ├── package-lock.json
+│    └── webpack.config.js
+├── dev/
+│    ├── django.dockerfile
+│    ├── webpack.dockerfile
+│    └── dev.env
+├── .dockerignore
+├── .gitignore
+├── jsconfig.json
+├── CONTRIBUTING.md
+├── docker-compose.yml
+├── LICENSE
+└── README.md
+
+

Overall project structure

+
├── config/
+│   ├── <Django Project Files>
+├── frontend/
+│   └── <Django App Files>
+├── server/
+│   ├── <Django App Files>
+│   ├─── <RESTFramework Files>
+|   └── templates
+├── manage.py
+└── requirements.txt
+
+

Backend Architecture

+

These diagrams show how data flows through the app: Frontend and Backend UML diagrams

+

Summary

+

Backend Tech Stack: Django, DjangoRESTFramework

+

The backend architecture is consists the the Django config/ project, and the frontend/ and server/ Django apps. In addition to serving as part of our backend, the frontend/ directory also serves our frontend architecture. More about the frontend/ directory as it relates our frontend architecture can be found in our guide on Frontend Architecture.

+

Overview of Directories and Files

+
    +
  • config/: houses the Django project files.
  • +
  • <Django Project Files>: More on the files in this directory can be found in Django's documentation.
  • +
  • <Django App>: currently we have two directories that are Django apps: frontend/ and server/. Within these directories are the default <Django App Files> that are created with every app as well as <RESTFramework Files>.
  • +
  • <Django App Files>: These files make up a Django App. To know more about these apps, read the section about Django App Files.
  • +
  • <RESTFramework Files>: Currently consists of only serializers.py, these files are additional files that support Django via the DjangoRestFramework library.
  • +
  • temaples/: contains swagger templates to host the swagger ui representation of our API.
  • +
  • manage.py: Part of Django, this is the entry point file for starting the Django server. This file handles a lot of critical settings, so be sure to read up on it in Django's documentation.
  • +
  • requirements.txt: A Python file that contains all dependencies for a project. It is the Python equivalent to Javascript's package.json.
  • +
+

Django App Files

+
├── migrations/
+│   └── __init__.py
+├── __init__.py
+├── admin.py
+├── apps.py
+├── models.py
+├── tests.py
+├── urls.py
+└── views.py
+
+

Files generated by Django when creating a new Django app

+

These files uses DjangoRestFramework in order to quickly create an API. The most often editted files here are models.py, urls.py, and views.py. The models define the schema for our database tables. Once the models are made, they are router to views.py where the data is transformed and exposed to our API. It is in views where we create handlers to manage REST operations.

+

Please refer to Django's documentation for more information.

+

Django REST Framework Files

+
├── serializers.py
+
+

RESTFramework files used to create a Django REST API

+

Serializers turn the data from the database into a Python-readable form.

+

Please refer to DjangoRESTFramework's documentation for more information.

+

Additional Resources

+

Django Documentation
+DjangoRestFramework Documentation

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/design-system/index.html b/developer/design-system/index.html new file mode 100644 index 00000000..8484b955 --- /dev/null +++ b/developer/design-system/index.html @@ -0,0 +1,1442 @@ + + + + + + + + + + + + + + + + + + + + + + + + Design System Helper - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + +

Design System Helper

+

This guide is the developer documentation for the CivicTechJobs Design System (CTJ-DS). Inside is not only an overview of our components, but also usage tips, and strategies to translate Figma designs into components for flexible, dynamic web pages.

+

Concepts

+

To understand our Design System, these are some overarching concepts to keep in mind when working with the DS.

+

Implementing from Figma to Frontend Development

+

UI designers specialize in turning project requirements into graphical interfaces that fits project requirements. Designers, however, are not coders. As a result, here are some development-related aspects of componentization that designers do not consider:

+
    +
  • the way components change as screen size changes
  • +
  • the ease of replicating components in code
  • +
  • the proper way to configure svg assets for development
  • +
+

Because of these factors, the way a prototype is built on Figma does not necessarily translate 1:1 to how the designs should be build as code. For example, Figma designs does not use SCSS mixins to simplify code or percentages as units of size.

+

Likewise, we must contend with the fact that Figma designs are static screens tied to very specific viewport sizes. As developers we need to recreate the Figma designs while also considering the intent behind a design.

+

As a developer, we need to effectively communicate with designers at multiple stage of the Figma design process. This means providing recommendations or alternatives that are simpler and easier for the developer to implement and maintain.

+

At CivicTechJobs, designers use two standard viewport widths when creating our UIs: 1440px for desktop and 375px for mobile. The appearance of the UI beyond these two sizes are determined by us, as developers, as we componentize the Figma designs. Do note though that our screen size of interest changes depending on the stage of our project. Right now, our current size of interest is:

+
1025px and up (or, laptop and up)
+
+

Scalable and Responsive Components

+

When creating or using components, it is good to keep in mind the differences between a scalable component and responsive component.

+

A scalable component:

+
    +
  • takes up a certain fraction of the total screen size
  • +
  • shrinks and grows along with screen size
  • +
  • uses relative CSS sizing units, such as % or vm
  • +
+

+

These columns show scalable behavior. The columns smoothly shrink and grow with the screen size.

+

A responsive component:

+
    +
  • takes up an absolute amount of the screen
  • +
  • remains static until reaching a certain breakpoint
  • +
  • uses static CSS sizing units, such as px
  • +
+

+

These buttons show responsive behavior. The buttons do not change until the screen reaches a certain breakpoint.

+

Scalability and responsiveness are not mutually exclusive. A web page can contain both scalable and responsive components. As a matter of fact, a single component can be both responsive and scalable.

+

+

This card shows both scalable and responsive behavior. The width smoothly change with the screen size, but drastically changes at our max small tablet breakpoint.

+

Only by combining both scalability and responsiveness in our design, can we create a high-quality site. When translating from Figma to code, most of the time, the work is in deciding what part of the Figma design should scale, and what part should be responsive. As a rule of thumb, when designing the transition from the desktop to mobile Figma, scale down empty space and margins, and responsively shrink buttons and text.

+

PropType as Documentation

+

As a small project, React recommends the use of PropTypes as our type checking library.

+

By using PropTypes, we have an easy way to look up hints on how to use our components.

+
Button.propTypes = {
+  addClass: PropTypes.string,
+  color: PropTypes.oneOf(["primary", "primary-dark"]),
+  disabled: PropTypes.bool,
+  href: PropTypes.string,
+  length: PropTypes.oneOf(["", "long"]),
+  onClick: PropTypes.func,
+  size: PropTypes.oneOf(["sm", "md", "lg", "icon"]),
+  target: PropTypes.oneOf([
+    "_blank",
+    "_self",
+    "_parent",
+    "_top",
+    PropTypes.string,
+  ]),
+};
+
+

For this <Button> component, PropTypes provide clues on the component's props. From these hints, a developer can guess that a small, long button would be declared as <Button size="sm" length="long">

+

Because comprehensive documentation is difficult for a small team to maintain, we rely on PropTypes and cleanly written code to provide clues on how to use each component. We recommend new developers take time to play with the components in components/ to fully understand how to utilize them. You can use the /demo web endpoint and Demo.js when developing to play around with our components.

+

Components

+

While we can use pure CSS as our styling sheet, using SCSS with React components allows us to standardize our components in a powerful way. Componentization allows:

+
    +
  • quick customizations through React props
  • +
  • standardizations to our components for accessibility
  • +
  • reuse of the same component across multiple pages
  • +
  • updating designs by simply editing the base component
  • +
+

Because of these benefits, we use a component-first approach to developing web pages. Please componentize as much as possible and use them to build high-quality web pages!

+

As a note, the DS is put together based on industry trends and practices. If you have ever explored Bootstrap, MUI, or Atlassian Design System, you will see many similarities between their components and ours.

+

Mixins and Classes

+

Most of our styles have a class and mixin equivalent. The class, for the most part, is created from just declaring the mixin inside the class.

+
@mixin hidden {
+  display: none;
+}
+
+.hidden {
+  @include hidden;
+}
+
+

Above is the hidden mixin definition. Below is the hidden mixin declaration as part of the .hidden class.

+

These are both provided to suit different use cases. For example, the class version is best suited for declaring inside of React components or HTML elements as part of the addClass prop or className attribute. On the other hand, the mixin version is best used when adding it to your own custom style, such as with media queries.

+
.my-own-custom-class {
+  @include breakpoint-media-max("smtablet") {
+    @include hidden; // Do this
+    @extend .hidden; // Do not do this, will break
+
+    @include col-size(6); // Do this
+    @extend .col-6; // Do not do this, will break
+  }
+}
+
+

Please use the mixin version when you want your own custom style to inherit from an existing style!

+

Layout and Columns

+

As with most design systems, we use a standard 12-column system to subdivide our layouts. Each column, without spacing, is worth *8.33% of its container's width**. This means that columns are, by default, scalable.

+

To use of our column classes, first declare a parent container with the .flex-container class. Then use col-* classes in each children, replacing the * with the number for the column size.

+ + +

We need to use a parent .flex-container with col-* classes to subdivide the UI.

+

Our 12-column system can be used in conjunction with .row and nested .col-* to further subdivide the UI, and create more complex layouts.

+ + +

With .flex-container, .row, and .col-*, we can create complex layouts that fit our purposes.

+
+
*Note: Although Figma uses 12 columns to subdivide the entire screen, our column classes subdivides the container. This means that we can divide the whole screen into columns, and then divide each column even further to achieve our desired ratios.
+
+

Smart Spacing

+
+

"99% of the time, you'll want to reclaim space from padding, margins, or empty space as screen size shrinks."

+
+

The spacing utilities are classified by attributes and size.

+

Table of Spacing Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Spacing attribute (margins)Meaning|Spacing attribute (padding)Meaning
mall margins|pall paddings
mtmargin-top|ptpadding-top
mrmargin-right|prpadding-right
mbmargin-bottom|pbpadding-bottom
mlmargin-left|plpadding-left
mxmargin-left and -right|pxpadding-left and -right
mymargin-top and -bottom|pypadding-top and -bottom
+

Table of Spacing Sizes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Spacing sizeActual size (px)
00px
18px
216px
324px
432px
540px
+

Tables showing the different way we classifies our spacing utilities. As an example, .px-4 sets the left and right padding as 32px.

+

Because our DS is based on a 12-column system, spacing utilities are made such that adding them on would not alter the 12-column system. For that reason, it is optimal to use the spacing utilities whenever possible over setting custom margins or padding.

+ + +

Add margins responsibly. Try to use the spacing utilities over creating custom margin classes.

+

As an example, if Figma indicates a 10px left margin, use either .ml-1 or .ml-2. Other times, however, Figma designs show spacing that falls outside of our size range. In this scenario, rather than set a specific margin, try to use centering instead, as large spaces are usually not a result of spacing, but of centering.

+

By being smart about the way we include spacing, we ensure scalability and reduce the maintenance cost of our code.

+

Responsive Mixins

+
+

"When using responsive mixins, order matters! Always declare them from big to small."

+
+

Several of our components have *-responsive mixins at the end of the .scss file. These act as helpers to quickly create responsiveness into our components, keeping our code simple to understand.

+

These mixins always use max-width in its media query (as we use a desktop-first approach), so order matters! To use them properly, specify a default* and declare screen size from largest to smallest:

+ + +

DO: specify a default on top and declare *-responsive mixins from large to small screen sizes.

+

DON'T: declare *-responsive mixins without a default on top or from a smaller to larger screen size.

+
+
*Note: There is one caveat to that as some components come with their own default. For example, buttons take a size prop, in which you declare a default already. Therefore when using the responsive mixin for button size, there is no need to declare a top level default in the scss code.
+
+

SVGs as Components and as Data-URLs

+

SVG assets are read into our codebase as React components (or inline SVG) or data-urls.

+

As React components:

+
    +
  • specified with a starting uppercase
  • +
  • allows the use of React props to dynamically alter the component
  • +
  • requires editing stroke and fill values to inherit to allow passing in props
  • +
  • requires a wrapper element to add additional styling
  • +
  • are imported directly from the image file
  • +
  • difficult to work with by provide lots of customization
  • +
+

As Data-urls:

+
    +
  • specified with a starting lowercase
  • +
  • are used as the src in img tags, to allow quick width/length adjustments
  • +
  • difficult to dynamically change
  • +
  • simple to declare and use
  • +
  • are imported with ?url qualifiers
  • +
  • not customizable beyond width and height
  • +
+
// COP Icons
+import CopIconData from "./svgs/cop-icon-datascience.svg";
+import CopIconEngineering from "./svgs/cop-icon-engineering.svg";
+import CopIconOps from "./svgs/cop-icon-ops.svg";
+import CopIconProduct from "./svgs/cop-icon-product.svg";
+import CopIconUiux from "./svgs/cop-icon-uiux.svg";
+
+import copIconData from "./svgs/cop-icon-datascience.svg?url";
+import copIconEngineering from "./svgs/cop-icon-engineering.svg?url";
+import copIconOps from "./svgs/cop-icon-ops.svg?url";
+import copIconProduct from "./svgs/cop-icon-product.svg?url";
+import copIconUiux from "./svgs/cop-icon-uiux.svg?url";
+
+

The top icons are imported from the image file as SVG components (or inline SVG). The bottom icons are the same file imported as data-urls. Notice how the latter import file adds "?url".

+

When using our SVG assets make sure to use the best import for the job. In some cases, however, neither of these imports are optimal to use. For example the SVG itself might be incorrectly formatted.

+

+

This SVG contains extra spaces, especially on the bottom. This image is impossible to center correctly without adding unnecessary margins.

+

In this case, rather than calculating some difficult to maintain, complex spacing, simply request the design team to provide a better SVG or edit the SVG yourself and send a copy to the design team.

+

Troubleshooting Errors

+
You may not @extend selectors across media queries.
+

This happens when @extend is used inside of media queries. An example using our DS,

+
.header-logo-desktop {
+  @include breakpoint-media-max("smtablet") {
+    @extend .hidden;
+  }
+}
+
+

Using @extend inside of a media query will result in an error. Instead, use a mixin declaration with @include instead. Most classes in the DS include an equivalent mixin for this specific purpose.

+
.header-logo-desktop {
+  @include breakpoint-media-max("smtablet") {
+    @include hidden;
+  }
+}
+
+

This works because it declares a mixin rather than extend the class!

+

To avoid these errors, it is encouraged to use the mixin rather than the class version of a specific style for inheritance whenever possible!

+

For more information visit this documentation and this Stack Overflow question.

+

Resources

+

Atomic Design
+Atlassian Design System
+Bootstrap
+Material-UI

+

Note: If embeds are out-of-date, and you have no access to the originals, please fork and replace them through CodeSandbox!

+

CodeSandbox

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/development-culture/index.html b/developer/development-culture/index.html new file mode 100644 index 00000000..f92b2524 --- /dev/null +++ b/developer/development-culture/index.html @@ -0,0 +1,1004 @@ + + + + + + + + + + + + + + + + + + + + + + + + Development Culture - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Development Culture

+

At CivicTechJobs, the developers of our team have 3 key tasks:

+
    +
  • Make issues
  • +
  • Resolve issues
  • +
  • Review code
  • +
+

This guide will discuss how each of these work at CivicTechJobs. If you have any questions be sure to let us know! We strive to create an inclusive space for developers to learn and achieve their goals.

+

Make Issues

+
+

To make an issue, follow this guide from GitHub, or take a look at this section of the CONTRIBUTING.md.

+
+

At CivicTechJobs, updating the project starts with creating an issue outlining the situation and changes needed to resolve the situation. When writing an issue, a good rule of thumb is to write as if another developer would be the one to work on the issue. Therefore, being thorough is better than brief. Some good guidelines to follow:

+
    +
  • Write a brief, two sentence summary for the overview. Be sure to note why these changes is needed.
  • +
  • In the overview, use language with little jargon.
  • +
  • Action items are usually step by step instructions or a list of requirements.
  • +
  • Longer explanations or useful documentation, if needed, are placed in the Instruction/Resources section.
  • +
  • Dependencies should 90% of the time be another issue. If this issue does not exist, it should probably be made and referenced as a dependency.
  • +
  • Likewise, the dependency should reference the issue it is a dependency for so that there is a trail to release issues with dependencies.
  • +
  • Check out examples of developer issues, such as this, for how to structure and word issues.
  • +
+

After writing out the issue, be sure to add labels. At minimum, we need three labels, one each from the "size", "role" and "feature/p-feature" series. In most cases, you should not create your own label. If you are unsure what labels to place, it is okay to leave it be, as another team member will help you when they notice the issue lacks certain labels.

+

Once an issue is created, and placed in the Project Management project board, the developer is mostly done with the issue. If the issue contains a dependency, it will move into the "Ice Box" column via GitHub automation, or "New Issue Approval", otherwise.

+

On rare occasions, a project manager, or other team members, might ping you with questions on the issue. Perhaps the team member did not understand the jargon, or the instructions were unclear. In that case, read their concerns carefully and either answer with a comment, or edit the original issue. Eventually, the issue will be approved, prioritized, and released into the "Prioritized Backlog" column, where developers can work on it.

+

Resolve Issues

+
+

To resolve an issue, take a look at this section of the CONTRIBUTING.md.

+
+

When choosing an issue to work on from the "Prioritized Backlog" column, it is good to note the "role" and "size" label. This signals the expertise required and time commitment needed to resolve the issue. As a rule of thumb, a smaller issue should take a week, and a larger issue, two or three weeks. This should give you a good idea on what issues is best for you to take at the moment. If you are completely new, we recommend taking smaller issues to understand your limits before pushing them further. That said, you are free to work on whatever you want.

+

On occasion, when an issue is being worked on for an inordinate amount of time, the team might request an update on your progress. When giving your progress, it is courteous to give an ETA on the issue, and evaluate on your ability to resolve the issue in a reasonable timeframe. If an issue is taking far too long, it might be wise to abandon the issue and work on something that might bring more value to you and the team.

+

Also, one final note: Do not contact the team via email or Slack to review your pull request unless it as been 72 hours since it was opened! The team will occasionally comb for pull requests and review them. If you want to move on to another issue, consider reviewing another developer's pull request (if you are part of the team), contribute to other open source projects, or ask the team for additional tasks.

+

Most issues can be divided into two broad types: frontend issues, and backend issues.

+

Frontend issues

+
    +
  • Usually involves the appearance of the site
  • +
  • Usually easier than backend issues
  • +
  • Requires little research
  • +
  • Is occasionally an audit
  • +
  • May involve documentation
  • +
+

When working on frontend issues, there will usually be a link to the Figma design. Figma often contains multiple prototypes and future prototypes. When looking for our current design, go to the bottom right corner and look for a pink rectangle. Anything within that represents our most up-to-date design. Use that as a reference for your frontend issues. If the pink rectangle is not there, please request the UI design team to put a pink rectangle on the latest approved design.

+

On rare circumstances, designs can change in the middle of work. This is something that happens as part of development, but will often be telegraphed during meetings. If a design change, you are free to reassess and abandon your current issue, or code pragmatically to ensure your work would not need a massive overhaul.

+

Backend issues

+
    +
  • Usually involves research and discussion
  • +
  • Can also pertain to GitHub Actions
  • +
  • Usually takes some time
  • +
  • May involve documentation
  • +
+

Review Code

+
+

To review code, please take a look at this GitHub documentation, and this portion of our CONTRIBUTING.md.

+
+

Code that should be reviewed is found in the pull request tab. These are issues that require someone to look over for several criteria:

+
    +
  • Applicability: Were the correct changes made? Where new lines added or removed that are extraneous to the issue?
  • +
  • Brokenness: Did the changes break the site? Is the changes responsive to view-port changes?
  • +
  • Cleanliness: Is the new code programmatic or messy? Would the code be hard to maintain in the long run?
  • +
+

When code meets all three criteria, it can then be merged and made a part of the site. Otherwise, the review should indicate changes that needs to be made.

+

As an advanced project, CivicTechJobs have certain expectations for our developers. One of these is that issues of size 1 or 2 is small enough that we "pre-review" them. This means that we are confident that the developer can resolve these issues without review. Therefore, these issues can be merged directly into our codebase upon resolution. That said, it is still fine to request the team to review your code if feedback is desired.

+

Important: Although issues can be pre-reviewed, do not make a habit of merging without making a pull request. There will be times when you performed an accidental merge, which could be a pain to fix on the command-line.

+

As one final note, code can be merged solely on one approved review but it is fine to request more reviewers or ask for the team to review it during a developer meeting.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/devops/index.html b/developer/devops/index.html new file mode 100644 index 00000000..2a820371 --- /dev/null +++ b/developer/devops/index.html @@ -0,0 +1,1214 @@ + + + + + + + + + + + + + + + + + + + + + + + + DevOps Architecture - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + +

DevOps Architecture

+
├── .github/
+│   └── ISSUE_TEMPLATE/
+├── app/
+│    ├── config/
+│          └── settings.py
+│    ├── frontend/
+│    ├── server/
+│    ├── .babelrc
+│    ├── manage.py
+│    ├── requirements.txt
+│    ├── package.json
+│    ├── package-lock.json
+│    └── webpack.config.js
+├── dev/ # DevOps
+│    ├── django.dockerfile
+│    ├── webpack.dockerfile
+│    └── dev.env
+├── .dockerignore # DevOps
+├── .gitignore
+├── jsconfig.json
+├── CONTRIBUTING.md
+├── docker-compose.yml # DevOps
+├── LICENSE
+└── README.md
+
+

Overall project structure

+
├── dev/
+│    ├── django.dockerfile
+│    ├── webpack.dockerfile
+│    └── dev.env.example
+├── .dockerignore
+├── docker-compose.yml
+├── alias-config.txt
+└── alias.sh
+
+

DevOps Architecture

+

Summary

+

DevOps Tech Stack: Docker, Gunicorn, Nginx, PostgreSQL, test

+

Our devops files can be thought of as a set of files needed to create an exact replica of our environments for our developers. Although the overall structure appears deceptively basic, it only represents a fraction of our devops files. Several of our files, such as the ones that construct our staging environment, contains sensitive information, and as such as not placed in our public repository. For most frontend and backend work, there is never a need to access these files.

+
+
*Note: On the rare occasions that there is a need to access the sensitive files for environments other than development, please consult the development lead of the project. They will know exactly what files you need, and what permissions you need to access them.
+
+

Overview of Directories and Files

+
    +
  • dev/: contains two dockerfiles and an env file. django.dockerfile contains information for our Django server setup. webpack.dockerfile contains information to start our webpack watch plugin. dev.env.example is an example of the env file needed to configure our dev environment.
  • +
  • .dockerignore: This file tells Docker to ignore certain files when building the container. These are usually files that pertain to docker or git, which are not important when building the webserver.
  • +
  • docker-compose.yml: Contains instructions for docker when we run "docker compose". To know more about what each line does, please consult Docker's documentation.
  • +
  • alias.sh: Contains a shell script that allows for cumbersome commands to be executed with less typing by leveraging the aliases listed in alias-config.txt
  • +
+

Docker

+

Docker is a platform that allows packaging and virtualizing applications within a container. This gives developers the powerful ability to collaborate in a stable, synchonized environment, and deploying web applications with the greatest of ease. We will not be going too much into Docker here, but we will explain in greater depth some of the Docker configurations we have made.

+

docker-compose.yml

+

This file contains configuration directions for docker compose. It consists of three services: pgdb (our database), webpack (our webpack bundler), and django (our django server). The webpack and django service relies in separate dockerfiles, located in the dev directory to build the container. This separation of dockerfiles enable each container to be build with its own set of dependencies. It also makes rebuilding the container simple when dependencies are migrated to a newer version.

+

For those of you used to creating applications without Docker, most would run webpack and django in separate terminals, so that they can both run at the same time. For the purposes of brevity, the different services can be considered to be Docker's way of running separate terminals.

+

One will also notice that the Django command uses a placeholder server name, 0.0.0.0:8000. This placeholder is important, since Docker creates an isolated environment. As a result, servers that are run in Docker does not recognize a browser from outside of that environment. Without this server name, localhost:8000 will not reach the server, as the server would recognize your browser as coming from a foreign machine. Therefore, all warnings related to 0.0.0.0, should they pop-up, should be ignored.

+

*.dockerfile

+

Dockerfiles are files that define how a container is built. Although containerization is a deep concept, to put it briefly, you can think of containers as separate "mini-computers", each programmed to do one thing. Some containers, such as our pgdb container does not require a dockerfile to configure it, as it works out of the box. On the otherhand, our webpack and django containers need dockerfile to built out the files we need to run it effectively.

+
FROM node:latest
+
+WORKDIR /code
+
+
+# install app dependencies
+COPY ./package.json ./
+COPY ./package-lock.json ./
+RUN npm install
+
+
+# add app
+COPY . .
+
+

Sample dockerfile that copies the package.json from a project and installs all dependencies.

+

Dockerfiles are usually named as just dockerfile, as that is the default name that docker looks for when constructing our builds. Since our project requires multiple dockerfiles, we name them with .dockerfile extensions, a convention that allows VSCode to detect dockerfiles and use appropriate syntax highlighting.

+

Do note that docker and dockerfiles can be fickle to work with, especially on old devices. Further down this documentation are various tips and commands that can be used with docker to help debug your code. But as always, consulting official documentation is the best way to get accurate, up-to-date information.

+

Environments

+

Development

+

Our development environment is entirely defined by our docker-compose.yml, and the files inside of dev/. More information about those files can be found above.

+

Of note, however, is the dev.env.example file. This file is only a sample, but lists out all the environmental variables needed to run our site. While most of them are prefilled, some uses <> to indicate placeholders, which must be filled in by the developer.

+

Staging

+

More information on our staging files can be found with our staging files. To access this information, please ask for the required permissions from the development lead.

+

Useful Commands

+
docker compose down -v
+
+

Useful to completely remove a container and related volumes. This is helpful when fiddling with database settings, which often breaks the database. This command allows the container to be restarted fresh.

+
docker compose -f <filename> <docker command>
+
+

Use this to specify an alternate docker-compose file to run your commands, such as docker-compose-other.yml. This is useful if you want to test out docker for yourself.

+
docker compose run <container> <command>
+
+

This is useful to run one time commands inside your container. Some good commands to run are:

+
    +
  • python manage.py makemigrations
  • +
  • python manage.py migrate
  • +
  • python manage.py createsuperruser
  • +
  • pip install -r requirements.txt
  • +
  • npm install
  • +
+
docker exec -it <container> sh
+
+

Use this to do heavier debugging inside of your container. What this does is open the shell inside of the container's "mini-computer". This allows you to explore the files inside the container to see if it matches what you would expect after building is finished. This command only works when a container is running, so use docker compose run -d to run your container in the background beforehand.

+
docker compose build --progress=plain
+
+

Sometimes when a build is happening, the logs are too opaque to debug if a step goes wrong. This commands makes the logs a bit more verbose so that you might have an easier time debugging.

+

Alias Shell Script

+

For convenience, we have created a shell script that allows for longer commands to be executed with less typing. The script is capable of executing any of the commands listed in alias-config.txt without having to type out the entire command.

+

alias.sh

+

To use this script, run bash alias.sh $arg or ./alias.sh $arg where $arg is the alias of the command you wish to execute. For example, try running bash alias.sh test.

+

alias-config.txt

+

This file contains many of the important commands you will need when developing for this project. Note that each command starts with a single word followed by a : and then a command. You must follow this pattern when adding additional commands to the file. Please note that any docker run commands must use the -T flag to allocate a pusedo-TTY or the command will not work.

+

Additional Resources

+

Docker Documentation

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/frontend/index.html b/developer/frontend/index.html new file mode 100644 index 00000000..394a5b6b --- /dev/null +++ b/developer/frontend/index.html @@ -0,0 +1,1303 @@ + + + + + + + + + + + + + + + + + + + + + + + + Frontend Architecture - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + +

Frontend Architecture

+
├── .github/
+│   └── ISSUE_TEMPLATE/
+├── app/
+│    ├── config/
+│          └── settings.py
+│    ├── frontend/ # Frontend
+│    ├── server/
+|    ├── tests/  # Frontend
+|    ├── .babelrc  # Frontend
+|    ├── .jest.config.js  # Frontend
+│    ├── manage.py
+│    ├── requirements.txt
+│    ├── package.json # Frontend
+│    ├── package-lock.json # Frontend
+│    └── webpack.config.js # Frontend
+├── dev/
+│    ├── django.dockerfile
+│    ├── webpack.dockerfile
+│    └── dev.env
+├── .dockerignore
+├── .gitignore
+├── jsconfig.json
+├── CONTRIBUTING.md
+├── docker-compose.yml
+├── LICENSE
+└── README.md
+
+

Overall project structure

+
├── frontend/
+│   ├── src/
+│       ├── assets/
+│       ├── components/
+│           ├── Apps.js
+│           └── <Components>/
+│       ├── context/
+│           ├── QualifiersContext.tsx
+│       ├── pages/
+│       ├── templates/
+│           └── index.html
+│       ├── index.js
+│       └── index.scss
+│   ├── static
+│   └── templates
+├── tests/
+├── .babelrc
+├── .jest.config.js
+├── package-lock.json
+├── package.json
+└── webpack.config.js
+
+

Frontend Architecture

+

These diagrams show how data flows through the app: Frontend and Backend UML diagrams

+

Summary

+

Frontend Tech Stack: React, Babel, webpack, Jest, React Testing Library, HTML, SCSS, JS, TailwindCSS

+

The over ninety percent of our frontend architecture is housed in our frontend/ directory. This directory is a Django app, which is a set of files that can be ported to any Django-based application.

+

Since our frontend is a Django app, it takes advantage of the way Django serves its static assets. Every Django app, by default, looks to the templates/* directory within the app for the html template file to serve. This template usually contains <script> and <style> tags denoting the location of SCSS and JS files. In Django, these files are usually located inside the static/* directory. Likewise, our frontend app store our templates and static assets within these directories.

+

Despite these similiarties, however, the files in these two directories should never be manipulated by a developer. These files are automatically generated by an application called webpack via configurations in webpack.config.js and .babelrc.

+

The files that should be manipulated by developers are housed within the src/ directory. Inside of here are directories for assets/, componenents/, pages/, router, and templates/. Each of these directories contains the files which webpack reads and then bundle into output files for the static/ and template/ directories.

+
+
*Note: The templates/ and static/ directories contain within them a frontend/ directory in order to namespace template and static files. Although this serves little purpose for our project, it is a Django convention that prevents Django from confusing the templates/ and static/ directories from the frontend app vs another app.
+
+

Overview of Directories and Files

+
    +
  • frontend/: houses all the frontend files.
  • +
  • frontend/src/: houses all the files for developers to manipulate. The files here are read by webpack before being bundled into the static/ and templates/ directories.
  • +
  • assets/: this is where we store all of our miscellaneous files, such as .jpegs, .svgs, .gifs, etc.
  • +
  • componenents/: this is where we store the files that generate our components, such as buttons and cards. To learn more about this in-depth, read the components section of this guide.
  • +
  • context/: contains the logic and data management utilities related to context providers and consumers. Contexts are used for managing global state within our application, providing a way to pass data through the component tree without having to pass props manually at every level. - COP (Community of Practice) JSON Structure: The COP data represents different communities of practice within our organization, each consisting of various roles and descriptions. Below is the JSON structure of the COP data for QualifierPageRoles.tsx: + { + "COPs": { + "UI/UX": [ + "UI/UX_Designer", + "UX_Researcher", + "UX_Writing", + "UX_Practice_Lead" + ], + "Engineering": [ + "Back_End_Developer", + "Front_End_Developer", + "Full_Stack_Developer", + "Engineering_Practice_Lead" + ], + "Data_Science": [ + "Data_Scientist", + "Data_Analyst", + "Data_Engineer", + "Data_Science_Practice_Lead" + ], + "Project/Product_Management": [ + "Product_Manager", + "Project_Manager", + "Business_Analyst", + "Product_Owner", + "Special_Projects_Coordinator", + "Product_Management_Practice_Lead" + ], + "DevOps": [ + "Site_Reliability_Engineer", + "Data_Engineer", + "Database_Architect", + "Security_Engineer", + "DevOps_Practice_Lead" + ] + } + }
  • +
  • pages/: contains the React files that pools together various components to generate a page.
  • +
  • router/: contains the routing logic for the project. It uses the React-Router library.
  • +
  • templates/: contains HTML files that are then generated into the regular templates directory. To learn more about how webpack bundle our files, read the webpack section of this guide.
  • +
  • index.js: this file serves as the entry point for all other js files*. This file is read by webpack, and then bundled into code in the static directory.
  • +
  • index.scss: this file serves as the entry point for all other scss files*.
  • +
  • frontend/static/: automatically generated by webpack, DO NOT EDIT
  • +
  • frontend/templates/: automatically generated by webpack, DO NOT EDIT
  • +
  • tests/: contains our test files. To run these files simply use docker compose run webpack npm run test.
  • +
  • .babelrc: Babel's configuration. To learn more about this, please visit babel's documentation.
  • +
  • .jest.config.js: Jest's configuration. To learn more about configuring Jest, please visit jest's documentation.
  • +
  • package-lock.json & package.json: These files are created by npm to keep track of dependencies. Please visit npm's documentation to understand them.
  • +
  • webpack.config.js: webpack's configuration. To learn more about configuring webpack, please visit their documentation. To learn about our specific configuration, see the below guide.
  • +
+
*Note: This is technically a lie. In actuality, index.js, reads index.s as well as the React files, making it the only entryway for all files bundled in the src/ directory.
+

Components Directory

+
├── components/
+│   ├── Basics/
+│       ├── Colors.scss
+│       └── Titles.scss
+│   ├── Buttons/
+│       ├── Button.js
+│       └── Button.scss
+│   ├── Cards/
+│       ├── Cards.js
+│       └── Cards.scss
+│   └── <Components>/
+
+

A closer look at a theoretical expansion of the components directory

+

The components directory contains our site components. Each directory in here represents a different class of components, such as Buttons/* or Cards/*. Within these directories are the files necessary that creates these components. Likewise, the special Basics/ directory contains small CSS classes that are reused, but not, technically, components, such as text-size or text-colors.

+
*Note: These files are capitalized to follow React convention for components. When making new components, please make sure to follow this convention. This convention is in place to help React differentiate between modules vs other types of imports.
+

Webpack Configurations

+
...
+
+module.exports = {
+    mode: 'development',
+    entry: {
+        index: "./frontend/src/index.js"
+    },
+    output: {
+        clean: {
+            keep: '.gitkeep'
+        },
+        filename: '[name].[contenthash].js',
+        path: path.resolve(__dirname, 'frontend/static/frontend'),
+    },
+    devtool: 'inline-source-map',
+    module: {
+        rules: ...
+    },
+    optimization: {
+        moduleIds: 'deterministic',
+        runtimeChunk: 'single',
+        splitChunks: ...
+    },
+    plugins: [
+        new HtmlWebpackPlugin({
+            filename: '../../templates/frontend/index.html',
+            template: '/frontend/src/templates/index.html',
+        }),
+    ],
+    watchOptions: {
+        ignored: /node_modules/,
+    },
+}
+
+

webpack.config.js (truncated)

+

Our webpack.config.js file is one of the most important files to understanding how our frontend architecture comes together. Therefore, this section is dedicated to the settings that we have set for this file. Note that we do not explain all the settings, as some can be found and easily deduced from webpack's configuration and guides documentation.

+
    +
  • entry: the file that is ultimately read by webpack to bundle everything together. This file, index.js imports all dependencies and files that makes up our product. Note that advanced multiple entry is possible, should we ever need it.
  • +
  • output: contains configurations for the files that are generated in the static/ directory
  • +
  • output > clean > keep: clean is usually used to clear away old files before generating new ones (filenames are variable to force browser css/js recacheing). However, keep notes files that should not be removed*.
  • +
  • output > filename: this configures the name of the generated js files. [name] is simply the name of the file noted in the entry configuration, and [contenthash] is a randomly generated string, which forces browser recacheing.
  • +
  • output > path: the directory to place the generated file. This directory is the one that Django, by default, detects its static files.
  • +
  • optimization: this contains a catch-all for various ways to enhance either development or deployment. For more on our current configuration, read this guide.
  • +
  • plugins > HtmlWebpackPlugin: this plugin enables us to dynamically generate templates with the correct <script> and <styles> path by reading the template and outputing it with the path noted by filename. This output path follows Django's default template directory structure.
  • +
  • watchOptions > ignored: configures files to ignore when regenerating watched files.
  • +
+
*Note: The kept .gitkeep file is there to give an empty file for git to preserve the otherwise empty directory when pushed onto GitHub. As you might have guessed, git does not push empty directories.
+

Why do we separate Babel from webpack?

+

If you have explored documentation from webpack, you might learn that the babel-loader in module > rules can accept the settings noted in .babelrc. The reason why we separate these settings into another file is because webpack is not, in theory, the only application that makes use of these settings. Although we have no other apps that makes use of .babelrc at the moment, this can change in the future. Therefore, this separation of files is a form of future proofing.

+

Testing

+

Component Testing

+

Our tests exists inside the tests directory with subdirectories that follows frontend/src. There is also __mock__/ which contains code that bypasses certain tricky imports, such as svg or SCSS assets, which are not needed when testing. In order to understand how to write tests, be sure to take a look at the documentation for React Testing Library, the parent DOM Testing Library, and the support libraries jest-dom and user-event.

+

To run these tests, use the command docker compose run webpack npm run test (or with test:w for watch mode). The tests are run through jest, while the other libraries support react testing by providing functions to render DOM elements and simulate user behavior.

+

Note: jest-environment-jsdom is a library that is absolutely required to link jsdom to jest. It provides the classes necessary for jest to interpret the jsdom environment. This information is listed here as it is not listed in jest's or jsdom's docs.

+

Accessibility Testing

+

In addition to testing the functioning of our components, we also test the accessability of it via the library, @axe-core/react. This library prints out accessibility issues onto the browser console, providing accessibiltiy testing once the HTML has fully rendered. That said, the library is known to give both false positives and false negatives. As always reading the official documentation is best when it comes to resolving these errors.

+

Additional Resources

+

Sass Documentation
+React Documentation
+Webpack Documentation
+@babel/preset-react Documentation
+React Router Documentation
+Jest Documentation
+React Testing Library Documentation
+@axe-core/react Documentation
+WAI-ARIA Authoring Practices 1.1

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/github/index.html b/developer/github/index.html new file mode 100644 index 00000000..a5cbdd5a --- /dev/null +++ b/developer/github/index.html @@ -0,0 +1,957 @@ + + + + + + + + + + + + + + + + + + + + + + + + GitHub Architecture - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

GitHub Architecture

+
├── .github/ # Github
+│   └── ISSUE_TEMPLATE/
+├── app/
+│    ├── config/
+│          └── settings.py
+│    ├── frontend/
+│    ├── server/
+│    ├── .babelrc
+│    ├── manage.py
+│    ├── requirements.txt
+│    ├── package.json
+│    ├── package-lock.json
+│    └── webpack.config.js
+├── dev/
+│    ├── django.dockerfile
+│    ├── webpack.dockerfile
+│    └── dev.env
+├── .dockerignore
+├── .gitignore # Github
+├── jsconfig.json
+├── CONTRIBUTING.md # Github
+├── docker-compose.yml
+├── LICENSE # Github
+└── README.md # Github
+
+

Overall project structure

+
├── .github/
+│   └── ISSUE_TEMPLATE/
+├── .gitignore
+├── CONTRIBUTING.md
+├── LICENSE
+└── README.md/
+
+

GitHub structure

+

Summary

+

Overview of Directories and Files

+
    +
  • LICENSE:
  • +
  • README.md:
  • +
+

GitHub Actions

+

Additional Resources

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/installation/index.html b/developer/installation/index.html new file mode 100644 index 00000000..e3cc354c --- /dev/null +++ b/developer/installation/index.html @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + + + + + + + + + + + Installation Instructions - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + +

Installation Instructions

+

This guide runs through the steps needed to create and run a local version of our project.

+

If you are ever stuck or need clarification, you can contact our team members or the development lead through our Slack or email, and schedule a pair programming session with one of our developers. All of us have been through these steps, and am more than happy to help. By helping you, we can better improve our documentation and grow this project!

+

Required Downloads

+

Git - Windows - macOS - Linux/Unix
+Docker - Windows - macOS - Linux/Unix
+Prettier - VSCode Extension

+
+Note on macOS +The macOS version of git involves downloading extra programs, such as Homebrew. In some cases this program can run up to 8GB of storage space, which might be too much for some. In that scenario, a miniature version of Homebrew can be installed through XCode. But do be warned that the containers for our project takes up a substantial amount of disk space as well. Do consider freeing up your disk space by deleting or backing up unneeded files, like photos or videos, and delete programs that are no longer useful. Your OS's native disk cleaner can also clear out unused cache files. +
+


+

Environmental Setup

+
    +
  1. Fork our repository.
  2. +
  3. Clone our repository to a local version on your PC.
  4. +
  5. Configuring Git to sync your fork with the original repository. When configuring, make sure to not blindly copy and paste the commands without making appropriate edits, especially when it involves your username or the repository name.
  6. +
+

While developing, make sure to create new branches off of the develop branch. To checkout the develop branch into your local repository, you can do the following:

+
    +
  1. Navigate to the root of our directory, CivicTechJobs/, in the terminal.
  2. +
  3. Run git remote add upstream https://github.com/hackforla/CivicTechJobs.git - this command adds the original hackforla CivicTechJobs github repo as a remote to your local repository and names it "upstream".
  4. +
  5. Run git fetch upstream develop - this command fetches the develop branch.
  6. +
  7. Run git checkout -b develop upstream/develop - this command creates and checks out a new branch called "develop" that tracks the upstream develop branch.
  8. +
+

Running Docker

+
    +
  1. Navigate to the root of our directory, CivicTechJobs/, in the terminal.
  2. +
  3. In dev/, create a file named, dev.env.
  4. +
  5. In this newly created file, copy and paste the contents of dev.env.example. Afterwards, you must edit the lines specified below.
  6. +
  7. Move to the frontend directory cd frontend and then npm install. When this is finished, move back to the root directory cd ..
  8. +
  9. Finally, enter docker compose up --watch to run the local server.
  10. +
  11. Visit http://localhost:8000 and you should see the front page of our website!
  12. +
+
+dev.env lines to edit +
    +
  • POSTGRES_DB: a name for your database, such as `postgres`
  • +
  • POSTGRES_USER: a username for your database
  • +
  • POSTGRES_PASSWORD: a password for your database
  • +
  • SECRET_KEY: a random string of length 50. You can use your favorite secret key generator to achieve this. To learn more about how Django generate default keys, see [Python's secrets's library](https://docs.python.org/3/library/secrets.html#secrets.token_urlsafe).
  • +
  • SQL_DATABASE: same as POSTGRES_DB
  • +
  • SQL_USER: same as POSTGRES_USER
  • +
  • SQL_PASSWORD: same as POSTGRES_PASSWORD
  • +
+
+ +
+Note on docker `--watch` flag +

The `--watch` flag enables hot module reloads during development. This flag requires a later version of Docker Compose(2.22.0).

+

If you are running into issues or getting errors running `docker compose up --watch`, please make sure you have installed the latest version of Docker and Docker Desktop on your machine.

+
+


+ + + +

Frequently Asked Questions

+

This section might answer some of the burning questions you have. If you cannot find it here, be sure to contact our team members or the development lead through our Slack or email.

+

Troubleshooting Errors

+
1. The command 'docker' could not be found
+

Make sure to turn on Docker by opening the Docker program on your desktop.

+
2. can't find a suitable configuration file in this directory or any parent: not found
+

Make sure that your terminal location is in a directory with a docker-compose.yml file. And make sure that the file is not hidden.

+
3. code ERR_SOCKET_TIMEOUT
+

This can result for several reasons, such as havin your sockets overloaded. In order to prevent this, the best thing to do is to lower the amount of sockets used when performing npm install. Change this line in docker/webpack:

+

RUN npm install

+

to:

+

RUN npm install --maxsockets=1

+

This should allow docker compose up to work. Be sure to delete the addition once your image and container is set up.

+
4. [dependency] not found
+

This sometimes happen when npm did not install successfully. In this scenario, you need to manually install the dependencies inside the container. Generally the command to run a command inside a container is:

+

docker compose run [container name] [command to run in container]

+

In this scenario, the full command would be:

+

docker compose run webpack npm install

+
5. [webpack-cli] [Error: EACCES: permission denied', open '/code/frontend/templates/frontend/index.html']
+

In this case, the index.html file has incorrect ownership and/or permissions. To fix this, run the following command in the root directory of the CTJ repository:

+

sudo chown -R $USER:$USER

+

This will utilize superuser permissions to change the user and group ownership of all the files and directories in the current directory to the current user.

+

Additional Resources

+

Git Documentation
+Docker Documentation
+Frontend Architecture
+Backend Architecture
+DevOps Architecture
+GitHub Architecture

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/mkdocs-architecture/index.html b/developer/mkdocs-architecture/index.html new file mode 100644 index 00000000..aef9b0f2 --- /dev/null +++ b/developer/mkdocs-architecture/index.html @@ -0,0 +1,1111 @@ + + + + + + + + + + + + + + + + + + + + + + + + MkDocs Architecture - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

MKdocs Architecture

+
├── .github/
+│   ├── ISSUE_TEMPLATE/
+│   └── workflows/
+│       └── mkdocs-build.yml # Docs
+├── backend/
+├── dev/
+├── frontend/
+├── mkdocs/ # Docs
+│   ├── docs/
+│   └── mkdocs.yml # Docs
+├── .dockerignore
+├── .gitignore
+├── CONTRIBUTING.md
+├── docker-compose.yml
+├── docker-compose.docs.yml # Docs
+├── LICENSE
+└── README.md
+
+

Overall project structure

+
├── docs/
+│   ├── assets/
+│   ├── css/
+│   ├── developer/
+│   ├── joining-the-team/
+│   ├── js/
+│   └── misc/
+├── index.md
+├── resources.md
+├── mkdocs.yml
+
+

mkdocs directory structure

+

Summary

+

The MkDocs "sub-project" lives in the mkdocs/ folder. A development server can be run using the docker-compose.docs.yml compose script. The mkdocs is set to automatically deploy to github pages using the mkdocs-build.yml github action.

+

Docker MkDocs

+

It is important to note that we are using Hack for LA's prebuilt docker mkdocs image for convenient setup. Please see the resources below for more information:

+ +

This prebuilt docker image makes it easy to get a mkdocs development server running with one command, without having to install python or mkdocs dependencies on your local machine. It also includes common useful plugins that we dont have to worry about installing ourselves, and already includes the mkdocs-material theme pre-installed.

+

Our project implements the HFLA mkdocs image by pulling it inside the docker-compose.docs.yml file:

+
name: civic-tech-jobs-mkdocs
+
+services:
+  mkdocs:
+    container_name: mkdocs
+    image: hackforlaops/mkdocs:latest
+    command: mkdocs serve -a "0.0.0.0:8005"
+    ports:
+      - "8005:8005"
+    volumes:
+      - ./mkdocs:/app
+    develop:
+      watch:
+        - action: sync
+          path: ./mkdocs
+          target: /app
+
+

Now when we run docker compose up like so:

+
docker-compose -f docker-compose.docs.yml up --watch
+
+

A mkdocs development server is started on http://localhost:8005

+

MkDocs Deployment

+

The url for the github pages site is: https://hackforla.github.io/CivicTechJobs/ (the website you are reading this on right now).

+

Our github repo is set to publish the docs to Github Pages using the gh-pages branch. This setting can be configured in the project's Pages settings.

+

External Resources:

+ +

Relevant PR and Issue:

+ +

The docs are set to automatically deploy to github pages using the mkdocs-build.yml github action. This action builds the mkdocs and saves the static files into the gh-pages branch.

+

Github Action for mkdocs deployment

+

Links to the github action: Build MkDocs site (develop)

+
name: Build MkDocs site (develop)
+
+on:
+  push:
+    branches:
+      - develop
+    paths:
+      - "mkdocs/**/**.md"
+      - "mkdocs/mkdocs.yml"
+  workflow_dispatch:
+
+permissions:
+  contents: write
+
+jobs:
+  deploy-docs:
+    runs-on: ubuntu-latest
+    if: github.actor != 'github-actions[bot]'
+    steps:
+      - uses: actions/checkout@v4
+      - name: Configure Git Credentials
+        run: |
+          git config user.name github-actions[bot]
+          git config user.email 41898282+github-actions[bot]@users.noreply.github.com
+      - uses: actions/setup-python@v5
+        with:
+          python-version: 3.x
+      - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
+      - uses: actions/cache@v4
+        with:
+          key: mkdocs-material-${{ env.cache_id }}
+          path: .cache
+          restore-keys: |
+            mkdocs-material-
+      - name: Install Dependencies
+        run: pip install \
+          mkdocs-material==9.1.17 \
+          mkdocs-autolinks-plugin==0.7.1
+      - name: Publish docs
+        run: |
+          cd mkdocs
+          mkdocs gh-deploy --force
+
+

Workflow Overview

+
    +
  • name: Build MkDocs site - The name of this workflow is "Build MkDocs site."
  • +
  • on: push: - develop - The workflow is triggered when there’s a push to the develop branch. (We will change this to main later)
  • +
  • paths: ... - The workflow will only run if the files being pushed are Markdown files (.md) or the mkdocs.yml configuration file inside the mkdocs directory.
  • +
  • workflow_dispatch: - This allows manual triggering of the workflow via the GitHub Actions interface.
  • +
  • permissions: contents: write - This grants the action permission to write contents to the repository. It's needed for deploying the site, which requires pushing to the gh-pages branch.
  • +
  • runs-on: ubuntu-latest - This specifies that the job will run on the latest Ubuntu environment provided by GitHub Actions.
  • +
  • if: github.actor != 'github-actions[bot]' - This condition ensures that the job doesn’t trigger if the GitHub Actions bot is the one making the changes. This prevents infinite loops where the action keeps triggering itself.
  • +
  • uses: actions/checkout@v4 - This step checks out the repository code so the workflow can access the files.
  • +
  • run: git config user.name github-actions[bot] - Configures Git to use the github-actions[bot] user for any commits or pushes that may happen during the deployment.
  • +
  • git config user.email 41898282+github-actions[bot]@users.noreply.github.com - Sets the email for the github-actions[bot] user.
  • +
  • uses: actions/setup-python@v5 - This sets up a Python environment in the GitHub runner, which is necessary for installing and running MkDocs.
  • +
+

Set environment variable for caching

+
    +
  • run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
  • +
  • This step sets an environment variable called cache_id to the current week of the year (%V). This value will be used as the key for caching to ensure that the cache is updated weekly.
  • +
+

Cache dependencies

+
    +
  • uses: actions/cache@v4 - This step caches dependencies (to speed up future builds) in the .cache directory.
  • +
  • with: key: mkdocs-material-${{ env.cache_id }} - The cache key is based on the cache_id, so the cache is refreshed weekly.
  • +
  • path: .cache - Specifies that the cache should be stored in the .cache directory.
  • +
  • restore-keys: mkdocs-material- - This allows for fallback caching if an exact cache match is not found.
  • +
+

Install Dependencies

+
    +
  • run: pip install mkdocs-material==9.1.17 mkdocs-autolinks-plugin==0.7.1
  • +
  • This installs the necessary dependencies for MkDocs to work. In this case:
  • +
  • mkdocs-material==9.1.17: A popular theme for MkDocs.
  • +
  • mkdocs-autolinks-plugin==0.7.1: A plugin that automatically creates links between pages in your documentation based on their titles.
  • +
+

Publish Documentation

+
    +
  • run: cd mkdocs && mkdocs gh-deploy --force
  • +
  • first it changes to the mkdocs/ directory.
  • +
  • then it deploys the MkDocs site to GitHub Pages using mkdocs gh-deploy --force. The --force flag ensures that the contents of the GitHub Pages branch (gh-pages) are overwritten with the latest deployment.
  • +
+
Summary
+

This workflow automates the process of building and deploying a MkDocs site when changes are pushed to the develop branch. It does the following:

+
    +
  1. Checks out the repository and configures Git for pushing changes.
  2. +
  3. Sets up Python and installs the necessary MkDocs dependencies.
  4. +
  5. Caches dependencies to speed up future builds.
  6. +
  7. Deploys the site to GitHub Pages using mkdocs gh-deploy.
  8. +
+

This workflow ensures the documentation is always up to date and available on GitHub Pages whenever changes are made to relevant Markdown files or the MkDocs configuration.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/mkdocs-edit-instructions/index.html b/developer/mkdocs-edit-instructions/index.html new file mode 100644 index 00000000..02cf2ec9 --- /dev/null +++ b/developer/mkdocs-edit-instructions/index.html @@ -0,0 +1,947 @@ + + + + + + + + + + + + + + + + + + + + + + + + MkDocs - How to Edit - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

How to Publish new Documentation

+

The goal of this page is to document how to create and publish new changes to the CTJ documentation.

+

Writing documentation into mkdocs requires some knowledge of Markdown.

+

Making changes to the mkdocs

+

What you essentially need to know:

+
    +
  • To make changes to the docs, edit the .md files located in the mkdocs/docs/ folder.
  • +
  • To make a new page, create a new .md file in the appropriate folder.
  • +
  • To add or edit links in the navmenu, configure the mkdocs.yml file.
  • +
+

MkDocs provides a development server that makes it convenient to see your changes in localhost before you deploy them to github.

+

For more a detailed editing guide please see the official MkDocs Tutorial

+

Quickstart

+

To start the development server, simply go to the root of your project in the terminal and run the following command:

+
docker-compose -f docker-compose.docs.yml up --watch
+
+

Next, go to http://localhost:8005 in your browser.

+

Now when you save new changes to the .md files, the respective page will automatically be updated in the browser.

+

When you are done editing, the next step is to deploy your changes.

+

Deploying your changes

+

When you are satisfied with your edits, make a pull request so that they can be reviewed.

+

Once the pull request is approved and merged into develop, the changes will be automatically deployed to the official CivicTechJobs documentation site (the site you are reading this page in right now). That's it!

+

If anything goes wrong, you can investigate the workflow in the project's github actions page

+

Note: At the moment, the docs are set to deploy from the develop branch, using the github action located in mkdocs-build.yml. This means that whenever a file is changed inside the mkdocs/ directory, and is merged into the develop branch on github, the changes will be automatically deployed to the official site hosted on github pages. In the near future we will set it to deploy from the main branch.

+

Check out our MkDocs Architecture page for more details on how it all fits together.

+

Recap

+

To sum it all up, you can make changes in 4 easy steps:

+
    +
  1. Start the development server using docker-compose -f docker-compose.docs.yml up --watch
  2. +
  3. Make changes to the .md files and observe them in http://localhost:8005
  4. +
  5. Open a Pull Request with your new changes
  6. +
  7. Merge the Pull Request into the develop branch
  8. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/developer/mkdocs-guide/index.html b/developer/mkdocs-guide/index.html new file mode 100644 index 00000000..0bcfe4e6 --- /dev/null +++ b/developer/mkdocs-guide/index.html @@ -0,0 +1,944 @@ + + + + + + + + + + + + + + + + + + + + + + + + MkDocs - Documentation Guide - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

MkDocs - Documentation Guide

+

We are using mkdocs to handle documentation.

+

Developers should document their architectural and coding decisions, so that other team members can easily reference these docs whenever they are lost or confused or new to the project.

+

What is MKdocs?

+

MkDocs is a static site generator that is designed specifically for building project documentation. It allows you to write documentation using Markdown, a lightweight markup language that's easy to use, and generates a clean, professional website that can be hosted on our project's GitHub Pages.

+

Please see MkDocs - How to Edit for instructions on how to make changes to the CTJ documentation and publish new docs.

+

What should developers document?

+

Code functionality

+
    +
  • Document the purpose and functionality of the code you write. Describe what each module, class, or function does, especially if it might not be obvious at first glance.
  • +
  • Example: If you implement a new API endpoint, document what the endpoint does, the request and response formats, and any important business logic involved.
  • +
+

Setup Instructions

+
    +
  • Make sure to document how to set up the project or new features you add. Include all dependencies, environment variables, and steps to get the project running locally or in production.
  • +
  • Example: If you introduce a new tool like Docker or a new package, make sure to document how to install and configure it.
  • +
+

Common Use Cases

+
    +
  • Document common or important use cases for the code. This is especially useful for other developers who might use your code in the future.
  • +
  • Example: If you build a new utility or library, include examples showing how it should be used.
  • +
+

Troubleshooting

+
    +
  • Include a section for common issues and how to resolve them. This can be a lifesaver for both new developers and anyone maintaining the project.
  • +
  • Example: Document errors or challenges you faced during development and their solutions.
  • +
+

Code Examples

+
    +
  • Where applicable, provide sample code or snippets to explain usage. These examples help future developers quickly understand how to use your components or functions.
  • +
  • Example: If you write a custom hook in React, include an example of how it can be used in a component.
  • +
+

API Documentation

+
    +
  • Ensure that all APIs (REST or GraphQL) have detailed documentation on endpoints, parameters, return types, and possible error codes.
  • +
  • Example: For each API endpoint, include descriptions of what it does, what data it expects, and the structure of its responses.
  • +
+

What are best practices for documentation?

+
    +
  • Keep it updated and consistent.
  • +
  • Be clear and concise.
  • +
  • Write in simple terms.
  • +
  • Use examples.
  • +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..6e8ae96d --- /dev/null +++ b/index.html @@ -0,0 +1,926 @@ + + + + + + + + + + + + + + + + + + + + CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + +

Welcome to the Civictechjobs.org Wiki!

+

Project Definition

+

CivicTechJobs will be a site to find open volunteer positions for projects at hackforla.

+

Introduction To The Project

+

What is Civictechjobs.org?

+

CivicTechJobs will be a platform to help prospective volunteers find interdisciplinary projects that will be useful for their career development while contributing to positive civic impact, and also a CMS (Content Mgmt System) for Hack for LA projects to be able to list their open roles.

+

Why do it?

+

To match the right volunteers with the right projects at hackforla.

+

Hasn't it been done already?

+

Yes, through CoP GitHub pages. However, the process is cumbersome and involves multiple steps to match the candidate with the right role.

+

Read more about what lead up to us developing this project, at our History page.

+

So how is this different?

+

We would like to streamline the process so that Product Managers can post the open oppotunities within their team efficiently, but most importantly a volunteer is able to find the right match with a project based on their skills, and aspirations.

+

Guiding Objectives

+

What are our guiding objectives?

+
    +
  1. Provide product managers ability to post, edit, or close open positions on an easy to use instinctive site (CMS)
  2. +
  3. Assist potential volunteers to self-filter for roles that matches their availability
  4. +
  5. Provide potential volunteers list of open roles with different projects that matches their skills, and interest.
  6. +
+

Project One Sheet

+

You can access our project one sheet here.

+

Key Resources

+

To take a look at some of our key resources:

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/content-writer/index.html b/joining-the-team/content-writer/index.html new file mode 100644 index 00000000..a388db10 --- /dev/null +++ b/joining-the-team/content-writer/index.html @@ -0,0 +1,840 @@ + + + + + + + + + + + + + + + + + + + + + + + + Content Writer - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

Content Writer

+
    +
  1. +

    Review existing copy on the CivicTechJobs.

    +
  2. +
  3. +

    Review the Figma for pages that are not yet published.

    +
  4. +
  5. +

    Review the Project Board and identify an actionable backlog item.

    +
  6. +
  7. +

    Communicate with PM your interest in being assigned a task.

    +
  8. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/data-scientist/index.html b/joining-the-team/data-scientist/index.html new file mode 100644 index 00000000..3511e377 --- /dev/null +++ b/joining-the-team/data-scientist/index.html @@ -0,0 +1,837 @@ + + + + + + + + + + + + + + + + + + + + + + + + Data Scientist - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

Data Scientist

+
    +
  1. +

    Read the Readme.

    +
  2. +
  3. +

    Review the Project Board and identify an actionable backlog item. We are working to resolve some database architecture issues and are not onboarding new data scientist at this time.

    +
  4. +
  5. +

    Communicate with the PM on your interest in being assigned a task.

    +
  6. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/intro/index.html b/joining-the-team/intro/index.html new file mode 100644 index 00000000..5038b041 --- /dev/null +++ b/joining-the-team/intro/index.html @@ -0,0 +1,935 @@ + + + + + + + + + + + + + + + + + + + + + + Intro - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Intro

+ +

DRAFT NOT YET FILLED OUT

+

Introduction

+

Welcome to the Civic Tech Jobs team! This guide will help get you up to speed on what you need to know to get started as a project team member.

+
+

Let's go!

+

If you have not read the Guide for New Volunteers, please do so.

+
    +
  1. Check the Community of Practice -> Open Roles Board for current open roles in the Civic Tech Jobs project.
  2. +
  3. Read Introduction to the Project if you haven't already read it.
  4. +
  5. If interested in joining the team, complete this form Team Roster Onboarding Form.
  6. +
  7. Join the Civic Tech Jobs Slack channel and introduce yourself and mention the role you are interested in. Our PM's will help you get onboarded with the following steps.
  8. +
  9. Accept your Google Drive invite to access the shared folder.
  10. +
  11. Review the Glossary.
  12. +
  13. Attend our monthly all team meeting on the third Tuesday at 5pm PST. You can find the link pinned in our slack channel.
  14. +
+
+

Who are you?

+

Click the link that applies to you to find a sequence of immediate action steps:

+

Web Developer

+

UI/UX Designer

+

UI/UX Researcher

+

Data Scientist

+

Content Writer

+

Product Manager/Owner

+

Other Volunteer

+
+

Accessibility standards

+

Title III of the Americans with Disabilities Act (ADA) requires that all sites be accessible to people with disabilities. The World Wide Web (W3C) Consortium's Web Content Accessibility Guidelines (WCAG) 2.0 Level AA function as the current legal standard for site accessibility.

+

Get acquainted with accessibility: https://www.ada.gov/pcatoolkit/chap5toolkit.htm

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/other-volunteer/index.html b/joining-the-team/other-volunteer/index.html new file mode 100644 index 00000000..4e04f8af --- /dev/null +++ b/joining-the-team/other-volunteer/index.html @@ -0,0 +1,837 @@ + + + + + + + + + + + + + + + + + + + + + + + + Other Volunteer - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

Other Volunteer

+
    +
  1. +

    Get an overview of the project from the Wiki.

    +
  2. +
  3. +

    Review the Project Board.

    +
  4. +
  5. +

    Chat with a [INSERT PROJECT NAME HERE] PM to discuss your interest and background.

    +
  6. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/product-manager/index.html b/joining-the-team/product-manager/index.html new file mode 100644 index 00000000..5dd346b0 --- /dev/null +++ b/joining-the-team/product-manager/index.html @@ -0,0 +1,847 @@ + + + + + + + + + + + + + + + + + + + + + + + + Project Manager - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

Product Manager and Owner

+

Each of the resources below can be considered a work-in-progress. These resources will evolve and adapt as the team and team needs change. Feel free to open an issue with a link to whichever resource needs improvement and a description of the suggested change.

+
    +
  1. +

    Learn how we setup our GitHub Kanban boards and please comment if there is anything in the document that is unclear.

    +
  2. +
  3. +

    This Software Development Lifecycle Diagram is a sample of what the process is generally like at Hack for LA and each project is different.

    +
  4. +
  5. +

    Review our OKRS.

    +
  6. +
  7. +

    Communicate with other product team members and leadership to discuss project priorities and strategic direction.

    +
  8. +
  9. +

    Review the Project Board and the Product Management issues available on that board to identify an actionable backlog item.

    +
  10. +
  11. +

    Review Hack for LA Product Management Templates.

    +
  12. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/uiux-designer/index.html b/joining-the-team/uiux-designer/index.html new file mode 100644 index 00000000..517a145b --- /dev/null +++ b/joining-the-team/uiux-designer/index.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + + + + + + + + + UI/UX Designer - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

UI/UX Designer

+

Starting Checklist

+
    +
  1. +

    Review the UI/UX issues on the Project Management Board and identify an actionable backlog item.

    +
  2. +
  3. +

    Communicate with PM your interest in being assigned a task.

    +
  4. +
  5. +

    Ask your lead to invite you to the Civic Tech Jobs figma workspace

    +
  6. +
  7. Leads should send invite to team members AFTER they have been added to the Google Drive and put their information into the team roster.
  8. +
+

Additional Reading

+
    +
  1. +

    This is a generic software development lifecycle diagram for Hack for LA. We would like to talk to you about how this project is different.

    +
  2. +
  3. +

    Read about WCAG 2.0 accessibility standards.

    +
  4. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/uiux-researcher/index.html b/joining-the-team/uiux-researcher/index.html new file mode 100644 index 00000000..951bd27a --- /dev/null +++ b/joining-the-team/uiux-researcher/index.html @@ -0,0 +1,893 @@ + + + + + + + + + + + + + + + + + + + + + + + + UI/UX Researcher - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/joining-the-team/web-developer/index.html b/joining-the-team/web-developer/index.html new file mode 100644 index 00000000..3dde06ab --- /dev/null +++ b/joining-the-team/web-developer/index.html @@ -0,0 +1,913 @@ + + + + + + + + + + + + + + + + + + + + + + + + Web Developer - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

Web Developer

+

Starting Checklist

+
    +
  1. +

    Read the development Readme and the CONTRIBUTING.md file set up your development environment.

    +
  2. +
  3. +

    Review the project board by the type of issue you are looking for. The Frontend Coding Project Board or the Backend Coding Project Board. Or you can check out the entire project board here.

    +
  4. +
  5. +

    Communicate with the PM about your interest in being assigned a task.

    +
  6. +
  7. +

    Your first commit will likely be an issue labeled good first issue. Check the board for those issues. Don't worry if you don't see anything now, we are working on it.

    +
  8. +
+

Additional Reading

+
    +
  1. +

    Read about WCAG 2.0 accessibility standards and set up third-party tools for compliance testing.

    +
  2. +
  3. +

    Review notes on security updates.

    +
  4. +
  5. +

    Site architecture document is coming soon.

    +
  6. +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/js/extra.js b/js/extra.js new file mode 100644 index 00000000..daa44309 --- /dev/null +++ b/js/extra.js @@ -0,0 +1,75 @@ +document.addEventListener("DOMContentLoaded", (event) => { + if (screen.width > 991) { + openDropdown(); + } +}); + +function openDropdown() { + const dropdowns = document.getElementsByClassName("dropdown"); + for (const dropdown of dropdowns) { + const children = dropdown.children; + + // too buggy, as hover is sensitive to where the mouse moves, and also it is hard to have it disappear on hover + + dropdown.addEventListener("mouseenter", () => { + for (const i of dropdowns) { + const item = i.children; + i.classList.remove("show"); + item[0].removeAttribute("aria-expanded"); + item[1].classList.remove("show"); + } + + dropdown.classList.add("show"); + children[0].setAttribute("aria-expanded", true); // item + children[1].classList.add("show"); + }); + dropdown.addEventListener("mouseleave", () => { + dropdown.classList.remove("show"); + children[0].removeAttribute("aria-expanded"); + children[1].classList.remove("show"); + }); + + const submenulist = children[1].children; + for (const submenu of submenulist) { + const children = submenu.children; + + //might not be the best way to detect whether there is a submenu + if (children.length < 2) { + break; + } + submenu.addEventListener("mouseenter", () => { + for (const i of submenulist) { + const item = i.children; + item[0].classList.remove("open"); + item[1].classList.remove("show"); // will not exist if a sub menu does not exist, need to error catch + } + + children[0].classList.add("open"); + children[1].classList.add("show"); // same as above + + var bounds = children[0].getBoundingClientRect(); + var popupMargin = 10; + var maxBottom = screen.height - popupMargin; + + children[1].style.left = bounds.right + "px"; + if ( + bounds.top + children[0].offsetHeight > maxBottom && + bounds.top > screen.height / 2 + ) { + children[1].style.top = + bounds.bottom - children[0].offsetHeight + "px"; + children[1].style.maxHeight = bounds.bottom - popupMargin + "px"; + } else { + children[1].style.top = bounds.top + "px"; + children[1].style.maxHeight = maxBottom - bounds.top + "px"; + } + }); + + //beta + submenu.addEventListener("mouseleave", () => { + children[0].classList.remove("open"); + children[1].classList.remove("show"); + }); + } + } +} diff --git a/misc/ada-guide/index.html b/misc/ada-guide/index.html new file mode 100644 index 00000000..15769738 --- /dev/null +++ b/misc/ada-guide/index.html @@ -0,0 +1,925 @@ + + + + + + + + + + + + + + + + + + + + + + + + ADA Guide - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

ADA Guide

+

Which accessibility testing tool should you use?

+

Overview

+

There are more than 100 accessibility testing tools. Figuring out which ones to use can be a black hole. For guidance we recommend this article: Which accessibility testing tool should you use?

+

Summary of Article

+

The author recommends using the tools in the following order fixing as you go along, since no one tool catches all the relevant issues

+

aXe +SiteImprove +Tenon +WAVE +Lighthouse

+

But if you want to test your site with other tools, here is a bigger list

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/misc/glossary/index.html b/misc/glossary/index.html new file mode 100644 index 00000000..4d492d98 --- /dev/null +++ b/misc/glossary/index.html @@ -0,0 +1,848 @@ + + + + + + + + + + + + + + + + + + + + + + + + Glossary - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DRAFT NOT YET FILLED OUT

+

Glossary

+

When we have a shiny glossary it will come here.

+ + + + + + + + + + + + + +
+TermAlternate termsOfficial LinkDescription
+ +
+ +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/misc/history/index.html b/misc/history/index.html new file mode 100644 index 00000000..ce8c1234 --- /dev/null +++ b/misc/history/index.html @@ -0,0 +1,913 @@ + + + + + + + + + + + + + + + + + + + + + + + + History - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

History

+

How Hack for LA evolved from in person onboarding to remote, and the iterative approach that we have taken to arrive at the need for a dedicated interface to list volunteer opportunities.

+

Pre-Covid times

+

Hack for LA practiced in person recruiting on onboarding nights. It had its own benefits, like each volunteer felt valued and had agency

+

2020-mid 2021

+

The team later moved on to a new process where the open roles on each team were posted on the Hack For LA site. This led to:

+
    +
  • Some volunteers contacted teams directly and the teams became responsible for all onboarding, which was inefficient use of time, leading to poor cohesiveness of our org (onboarding conducted differently by various people and projects). And some projects got too many volunteers but not the right skill level. Ultimately this method led to high turnover of volunteers and product managers getting burnt out.
  • +
  • Other volunteers attending a Zoom onboarding session (held weekly). In this process the project leads would show up to recruit at the end, but sometimes there would be no one who could fill the domain specific role. This process was also inefficient.
  • +
+

mid 2021- current

+

Hack for LA moved to a new model where all new volunteer attend onboarding and then join a communities of practice (CoP) and no open roles are posted on the hackforla.org site. These CoPs have volunteer opportunity boards so that when project leads recruit, they can go to a larger group of people who are more likely to be a good fit for the role available. Also CoP leads can help provide coaching if someone is unsure of if they are a good fit. Listings at CoP allow the org to determine if the project is actually ready to receive volunteers.

+

The Hack for LA organization team has now green lighted a project to create a dedicated job board page where volunteers can search and find volunteer opportunities that match their goal and aspirations while still maintaining the involvement of onboarding and CoPs.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/misc/our-process/index.html b/misc/our-process/index.html new file mode 100644 index 00000000..7bada109 --- /dev/null +++ b/misc/our-process/index.html @@ -0,0 +1,828 @@ + + + + + + + + + + + + + + + + + + + + + + + + Our Process - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Our Process

+

This page has links and details such as links to a spreadsheet with our research, etc. and what order we did things in. But less narrative and mostly links

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/misc/research-wiki-template/index.html b/misc/research-wiki-template/index.html new file mode 100644 index 00000000..0cdc295d --- /dev/null +++ b/misc/research-wiki-template/index.html @@ -0,0 +1,851 @@ + + + + + + + + + + + + + + + + + + + + + + + + Research Wiki Template - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Template for presenting research on wiki

+
# [Name of Research]
+
+## Research Date:
+
+## Current Status
+
+## Overview Issue #:
+
+## Outstanding task items
+
+## Assets
+
+### Research Plan (including Audience Identification documentation)
+
+### Scripts
+
+### Interview recordings & Transcripts
+
+### Synthesis (Miro or Figjam)
+
+### Presentation of Findings
+
+### Action Items Spreadsheet
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/misc/security-updates/index.html b/misc/security-updates/index.html new file mode 100644 index 00000000..45d9b0fd --- /dev/null +++ b/misc/security-updates/index.html @@ -0,0 +1,829 @@ + + + + + + + + + + + + + + + + + + + + + + + + Security Updates - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Security Updates

+

This project subscribes to GitHub's automated security alerting service. Occasionally the repository home page may have a yellow banner saying "We have found a potential security vulnerability in one of your dependencies" and a link to view the security alert. If you see this, please check our issues list to see if anyone has added an issue for fixing this. If not, please create an issue for this problem. If you feel up to it, please assign the issue to yourself and try to fix it. As with any issue, once you have fixed it on your fork of the repository, push the fixes to your fork and then open a pull request to merge this fix into the main repository.

+

GitHub's "dependabot" may try to generate an automated pull request to fix this issue. Please do not accept this pull request without verifying that it works by applying the update on your local copy of the site.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/misc/the-team/index.html b/misc/the-team/index.html new file mode 100644 index 00000000..303f6972 --- /dev/null +++ b/misc/the-team/index.html @@ -0,0 +1,901 @@ + + + + + + + + + + + + + + + + + + + + + + + + The Team - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

The Team

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameRole
Joyce GuoProduct Manager
Sabrina HeasleyProduct Manager
Salima Yacoubi SoussaneProduct Manager
Bitian ZhangFull Stack Developer
Matt PereiraFull Stack Developer
Will GillisFull Stack Developer
Sarah SangerSoftware Developer
Benny VanSoftware Developer
Jen ChungUX/UI Designer Lead
Tin Wei, ChungUX/UI Designer
Lu FengUX/UI Designer
Gabriel VicencioUX/UI Designer
Melinda SukosdUX Researcher Lead
Leah EllisUX Researcher
Jenn WuUX Researcher
Nga DoUX Researcher
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/resources/index.html b/resources/index.html new file mode 100644 index 00000000..f7044e7c --- /dev/null +++ b/resources/index.html @@ -0,0 +1,1031 @@ + + + + + + + + + + + + + + + + + + + + + + Resources - CivicTechJobs Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 00000000..a5c36e31 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to the Civictechjobs.org Wiki!","text":""},{"location":"#project-definition","title":"Project Definition","text":"

CivicTechJobs will be a site to find open volunteer positions for projects at hackforla.

"},{"location":"#introduction-to-the-project","title":"Introduction To The Project","text":""},{"location":"#what-is-civictechjobsorg","title":"What is Civictechjobs.org?","text":"

CivicTechJobs will be a platform to help prospective volunteers find interdisciplinary projects that will be useful for their career development while contributing to positive civic impact, and also a CMS (Content Mgmt System) for Hack for LA projects to be able to list their open roles.

"},{"location":"#why-do-it","title":"Why do it?","text":"

To match the right volunteers with the right projects at hackforla.

"},{"location":"#hasnt-it-been-done-already","title":"Hasn't it been done already?","text":"

Yes, through CoP GitHub pages. However, the process is cumbersome and involves multiple steps to match the candidate with the right role.

Read more about what lead up to us developing this project, at our History page.

"},{"location":"#so-how-is-this-different","title":"So how is this different?","text":"

We would like to streamline the process so that Product Managers can post the open oppotunities within their team efficiently, but most importantly a volunteer is able to find the right match with a project based on their skills, and aspirations.

"},{"location":"#guiding-objectives","title":"Guiding Objectives","text":""},{"location":"#what-are-our-guiding-objectives","title":"What are our guiding objectives?","text":"
  1. Provide product managers ability to post, edit, or close open positions on an easy to use instinctive site (CMS)
  2. Assist potential volunteers to self-filter for roles that matches their availability
  3. Provide potential volunteers list of open roles with different projects that matches their skills, and interest.
"},{"location":"#project-one-sheet","title":"Project One Sheet","text":"

You can access our project one sheet here.

"},{"location":"#key-resources","title":"Key Resources","text":"

To take a look at some of our key resources:

  • Civictechjobs Google Drive
  • Civictechjobs Figma File
"},{"location":"resources/","title":"Resources","text":"

More resources to be added as project progresses:

"},{"location":"resources/#core-start-here","title":"Core - Start here","text":"
  1. civictechjobs.org
  2. Github Repo
  3. Our Figma
  4. CivicTechJobs Docs
  5. CivicTechJobs Github Wiki
  6. CTJ Core Team
  7. #civictechjobs slack channel (in the Hack For LA organization slack)
  8. #civictechjobs-dev channel
"},{"location":"resources/#project-management","title":"Project Management","text":"
  1. Project Board
  2. Project one sheet
  3. Our Shared Google Drive
  4. GitHub Workflow
  5. Milestones
"},{"location":"resources/#roadmaps","title":"Roadmaps","text":"
  1. CTJ Requirements & Roadmap (Feature Roadmap)
  2. Developer Roadmap \u00b7 Issue #381 \u00b7 hackforla/CivicTechJobs \u00b7 GitHub
"},{"location":"resources/#team-meeting-agendas","title":"Team Meeting Agendas","text":"
  1. CTJ: Monthly All Hands Team Meeting Agenda
  2. CTJ: Leads Agenda
  3. CTJ: Development Meeting Agenda
  4. CTJ: UXR Meeting Agenda
  5. CTJ: PM/ORG Meeting Agenda and Notes
"},{"location":"resources/#design-resources","title":"Design Resources","text":"
  1. Our Figma
  2. Userflow Diagram - OUTDATED
  3. Research Slide Deck
  4. Task and User Flow
  5. HfLA Website Figma - Section for Volunteer Opportunities
"},{"location":"resources/#diagrams","title":"Diagrams","text":"
  1. Frontend and Backend UML diagrams
"},{"location":"resources/#for-developers","title":"For Developers","text":"
  1. Contributing.md
  2. Frontend Architecture
  3. Frontend Resources
  4. Backend Architecture
  5. Backend Resources
  6. DevOps Architecture
  7. DevOps Resources
  8. GitHub Architecture
  9. GitHub Resources
  10. Design System Helper
  11. Design System Resources
  12. Installation Instructions
  13. Installation Resources
  14. Development Culture
"},{"location":"resources/#tools","title":"Tools","text":"
  1. GoFullPage Screenshot Chrome Extension'
"},{"location":"developer/backend/","title":"Backend Architecture","text":"
\u251c\u2500\u2500 .github/\n\u2502   \u2514\u2500\u2500 ISSUE_TEMPLATE/\n\u251c\u2500\u2500 app/ # Backend\n\u2502    \u251c\u2500\u2500 config/  # Backend\n\u2502          \u2514\u2500\u2500 settings.py\n\u2502    \u251c\u2500\u2500 frontend/ # Backend\n\u2502    \u251c\u2500\u2500 server/  # Backend\n\u2502    \u251c\u2500\u2500 .babelrc\n\u2502    \u251c\u2500\u2500 manage.py\n\u2502    \u251c\u2500\u2500 requirements.txt  # Backend\n\u2502    \u251c\u2500\u2500 package.json\n\u2502    \u251c\u2500\u2500 package-lock.json\n\u2502    \u2514\u2500\u2500 webpack.config.js\n\u251c\u2500\u2500 dev/\n\u2502    \u251c\u2500\u2500 django.dockerfile\n\u2502    \u251c\u2500\u2500 webpack.dockerfile\n\u2502    \u2514\u2500\u2500 dev.env\n\u251c\u2500\u2500 .dockerignore\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 jsconfig.json\n\u251c\u2500\u2500 CONTRIBUTING.md\n\u251c\u2500\u2500 docker-compose.yml\n\u251c\u2500\u2500 LICENSE\n\u2514\u2500\u2500 README.md\n

Overall project structure

\u251c\u2500\u2500 config/\n\u2502   \u251c\u2500\u2500 <Django Project Files>\n\u251c\u2500\u2500 frontend/\n\u2502   \u2514\u2500\u2500 <Django App Files>\n\u251c\u2500\u2500 server/\n\u2502   \u251c\u2500\u2500 <Django App Files>\n\u2502   \u251c\u2500\u2500\u2500 <RESTFramework Files>\n|   \u2514\u2500\u2500 templates\n\u251c\u2500\u2500 manage.py\n\u2514\u2500\u2500 requirements.txt\n

Backend Architecture

These diagrams show how data flows through the app: Frontend and Backend UML diagrams

"},{"location":"developer/backend/#summary","title":"Summary","text":"

Backend Tech Stack: Django, DjangoRESTFramework

The backend architecture is consists the the Django config/ project, and the frontend/ and server/ Django apps. In addition to serving as part of our backend, the frontend/ directory also serves our frontend architecture. More about the frontend/ directory as it relates our frontend architecture can be found in our guide on Frontend Architecture.

"},{"location":"developer/backend/#overview-of-directories-and-files","title":"Overview of Directories and Files","text":"
  • config/: houses the Django project files.
  • <Django Project Files>: More on the files in this directory can be found in Django's documentation.
  • <Django App>: currently we have two directories that are Django apps: frontend/ and server/. Within these directories are the default <Django App Files> that are created with every app as well as <RESTFramework Files>.
  • <Django App Files>: These files make up a Django App. To know more about these apps, read the section about Django App Files.
  • <RESTFramework Files>: Currently consists of only serializers.py, these files are additional files that support Django via the DjangoRestFramework library.
  • temaples/: contains swagger templates to host the swagger ui representation of our API.
  • manage.py: Part of Django, this is the entry point file for starting the Django server. This file handles a lot of critical settings, so be sure to read up on it in Django's documentation.
  • requirements.txt: A Python file that contains all dependencies for a project. It is the Python equivalent to Javascript's package.json.
"},{"location":"developer/backend/#django-app-files","title":"Django App Files","text":"
\u251c\u2500\u2500 migrations/\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 __init__.py\n\u251c\u2500\u2500 admin.py\n\u251c\u2500\u2500 apps.py\n\u251c\u2500\u2500 models.py\n\u251c\u2500\u2500 tests.py\n\u251c\u2500\u2500 urls.py\n\u2514\u2500\u2500 views.py\n

Files generated by Django when creating a new Django app

These files uses DjangoRestFramework in order to quickly create an API. The most often editted files here are models.py, urls.py, and views.py. The models define the schema for our database tables. Once the models are made, they are router to views.py where the data is transformed and exposed to our API. It is in views where we create handlers to manage REST operations.

Please refer to Django's documentation for more information.

"},{"location":"developer/backend/#django-rest-framework-files","title":"Django REST Framework Files","text":"
\u251c\u2500\u2500 serializers.py\n

RESTFramework files used to create a Django REST API

Serializers turn the data from the database into a Python-readable form.

Please refer to DjangoRESTFramework's documentation for more information.

"},{"location":"developer/backend/#additional-resources","title":"Additional Resources","text":"

Django Documentation DjangoRestFramework Documentation

"},{"location":"developer/design-system/","title":"Design System Helper","text":"

This guide is the developer documentation for the CivicTechJobs Design System (CTJ-DS). Inside is not only an overview of our components, but also usage tips, and strategies to translate Figma designs into components for flexible, dynamic web pages.

"},{"location":"developer/design-system/#concepts","title":"Concepts","text":"

To understand our Design System, these are some overarching concepts to keep in mind when working with the DS.

"},{"location":"developer/design-system/#implementing-from-figma-to-frontend-development","title":"Implementing from Figma to Frontend Development","text":"

UI designers specialize in turning project requirements into graphical interfaces that fits project requirements. Designers, however, are not coders. As a result, here are some development-related aspects of componentization that designers do not consider:

  • the way components change as screen size changes
  • the ease of replicating components in code
  • the proper way to configure svg assets for development

Because of these factors, the way a prototype is built on Figma does not necessarily translate 1:1 to how the designs should be build as code. For example, Figma designs does not use SCSS mixins to simplify code or percentages as units of size.

Likewise, we must contend with the fact that Figma designs are static screens tied to very specific viewport sizes. As developers we need to recreate the Figma designs while also considering the intent behind a design.

As a developer, we need to effectively communicate with designers at multiple stage of the Figma design process. This means providing recommendations or alternatives that are simpler and easier for the developer to implement and maintain.

At CivicTechJobs, designers use two standard viewport widths when creating our UIs: 1440px for desktop and 375px for mobile. The appearance of the UI beyond these two sizes are determined by us, as developers, as we componentize the Figma designs. Do note though that our screen size of interest changes depending on the stage of our project. Right now, our current size of interest is:

1025px and up (or, laptop and up)\n
"},{"location":"developer/design-system/#scalable-and-responsive-components","title":"Scalable and Responsive Components","text":"

When creating or using components, it is good to keep in mind the differences between a scalable component and responsive component.

A scalable component:

  • takes up a certain fraction of the total screen size
  • shrinks and grows along with screen size
  • uses relative CSS sizing units, such as % or vm

These columns show scalable behavior. The columns smoothly shrink and grow with the screen size.

A responsive component:

  • takes up an absolute amount of the screen
  • remains static until reaching a certain breakpoint
  • uses static CSS sizing units, such as px

These buttons show responsive behavior. The buttons do not change until the screen reaches a certain breakpoint.

Scalability and responsiveness are not mutually exclusive. A web page can contain both scalable and responsive components. As a matter of fact, a single component can be both responsive and scalable.

This card shows both scalable and responsive behavior. The width smoothly change with the screen size, but drastically changes at our max small tablet breakpoint.

Only by combining both scalability and responsiveness in our design, can we create a high-quality site. When translating from Figma to code, most of the time, the work is in deciding what part of the Figma design should scale, and what part should be responsive. As a rule of thumb, when designing the transition from the desktop to mobile Figma, scale down empty space and margins, and responsively shrink buttons and text.

"},{"location":"developer/design-system/#proptype-as-documentation","title":"PropType as Documentation","text":"

As a small project, React recommends the use of PropTypes as our type checking library.

By using PropTypes, we have an easy way to look up hints on how to use our components.

Button.propTypes = {\n  addClass: PropTypes.string,\n  color: PropTypes.oneOf([\"primary\", \"primary-dark\"]),\n  disabled: PropTypes.bool,\n  href: PropTypes.string,\n  length: PropTypes.oneOf([\"\", \"long\"]),\n  onClick: PropTypes.func,\n  size: PropTypes.oneOf([\"sm\", \"md\", \"lg\", \"icon\"]),\n  target: PropTypes.oneOf([\n    \"_blank\",\n    \"_self\",\n    \"_parent\",\n    \"_top\",\n    PropTypes.string,\n  ]),\n};\n

For this <Button> component, PropTypes provide clues on the component's props. From these hints, a developer can guess that a small, long button would be declared as <Button size=\"sm\" length=\"long\">

Because comprehensive documentation is difficult for a small team to maintain, we rely on PropTypes and cleanly written code to provide clues on how to use each component. We recommend new developers take time to play with the components in components/ to fully understand how to utilize them. You can use the /demo web endpoint and Demo.js when developing to play around with our components.

"},{"location":"developer/design-system/#components","title":"Components","text":"

While we can use pure CSS as our styling sheet, using SCSS with React components allows us to standardize our components in a powerful way. Componentization allows:

  • quick customizations through React props
  • standardizations to our components for accessibility
  • reuse of the same component across multiple pages
  • updating designs by simply editing the base component

Because of these benefits, we use a component-first approach to developing web pages. Please componentize as much as possible and use them to build high-quality web pages!

As a note, the DS is put together based on industry trends and practices. If you have ever explored Bootstrap, MUI, or Atlassian Design System, you will see many similarities between their components and ours.

"},{"location":"developer/design-system/#mixins-and-classes","title":"Mixins and Classes","text":"

Most of our styles have a class and mixin equivalent. The class, for the most part, is created from just declaring the mixin inside the class.

@mixin hidden {\n  display: none;\n}\n\n.hidden {\n  @include hidden;\n}\n

Above is the hidden mixin definition. Below is the hidden mixin declaration as part of the .hidden class.

These are both provided to suit different use cases. For example, the class version is best suited for declaring inside of React components or HTML elements as part of the addClass prop or className attribute. On the other hand, the mixin version is best used when adding it to your own custom style, such as with media queries.

.my-own-custom-class {\n  @include breakpoint-media-max(\"smtablet\") {\n    @include hidden; // Do this\n    @extend .hidden; // Do not do this, will break\n\n    @include col-size(6); // Do this\n    @extend .col-6; // Do not do this, will break\n  }\n}\n

Please use the mixin version when you want your own custom style to inherit from an existing style!

"},{"location":"developer/design-system/#layout-and-columns","title":"Layout and Columns","text":"

As with most design systems, we use a standard 12-column system to subdivide our layouts. Each column, without spacing, is worth *8.33% of its container's width**. This means that columns are, by default, scalable.

To use of our column classes, first declare a parent container with the .flex-container class. Then use col-* classes in each children, replacing the * with the number for the column size.

We need to use a parent .flex-container with col-* classes to subdivide the UI.

Our 12-column system can be used in conjunction with .row and nested .col-* to further subdivide the UI, and create more complex layouts.

With .flex-container, .row, and .col-*, we can create complex layouts that fit our purposes.

"},{"location":"developer/design-system/#note-although-figma-uses-12-columns-to-subdivide-the-entire-screen-our-column-classes-subdivides-the-container-this-means-that-we-can-divide-the-whole-screen-into-columns-and-then-divide-each-column-even-further-to-achieve-our-desired-ratios","title":"*Note: Although Figma uses 12 columns to subdivide the entire screen, our column classes subdivides the container. This means that we can divide the whole screen into columns, and then divide each column even further to achieve our desired ratios.","text":""},{"location":"developer/design-system/#smart-spacing","title":"Smart Spacing","text":"

\"99% of the time, you'll want to reclaim space from padding, margins, or empty space as screen size shrinks.\"

The spacing utilities are classified by attributes and size.

Table of Spacing Attributes

Spacing attribute (margins) Meaning | Spacing attribute (padding) Meaning m all margins | p all paddings mt margin-top | pt padding-top mr margin-right | pr padding-right mb margin-bottom | pb padding-bottom ml margin-left | pl padding-left mx margin-left and -right | px padding-left and -right my margin-top and -bottom | py padding-top and -bottom

Table of Spacing Sizes

Spacing size Actual size (px) 0 0px 1 8px 2 16px 3 24px 4 32px 5 40px

Tables showing the different way we classifies our spacing utilities. As an example, .px-4 sets the left and right padding as 32px.

Because our DS is based on a 12-column system, spacing utilities are made such that adding them on would not alter the 12-column system. For that reason, it is optimal to use the spacing utilities whenever possible over setting custom margins or padding.

Add margins responsibly. Try to use the spacing utilities over creating custom margin classes.

As an example, if Figma indicates a 10px left margin, use either .ml-1 or .ml-2. Other times, however, Figma designs show spacing that falls outside of our size range. In this scenario, rather than set a specific margin, try to use centering instead, as large spaces are usually not a result of spacing, but of centering.

By being smart about the way we include spacing, we ensure scalability and reduce the maintenance cost of our code.

"},{"location":"developer/design-system/#responsive-mixins","title":"Responsive Mixins","text":"

\"When using responsive mixins, order matters! Always declare them from big to small.\"

Several of our components have *-responsive mixins at the end of the .scss file. These act as helpers to quickly create responsiveness into our components, keeping our code simple to understand.

These mixins always use max-width in its media query (as we use a desktop-first approach), so order matters! To use them properly, specify a default* and declare screen size from largest to smallest:

DO: specify a default on top and declare *-responsive mixins from large to small screen sizes.

DON'T: declare *-responsive mixins without a default on top or from a smaller to larger screen size.

"},{"location":"developer/design-system/#note-there-is-one-caveat-to-that-as-some-components-come-with-their-own-default-for-example-buttons-take-a-size-prop-in-which-you-declare-a-default-already-therefore-when-using-the-responsive-mixin-for-button-size-there-is-no-need-to-declare-a-top-level-default-in-the-scss-code","title":"*Note: There is one caveat to that as some components come with their own default. For example, buttons take a size prop, in which you declare a default already. Therefore when using the responsive mixin for button size, there is no need to declare a top level default in the scss code.","text":""},{"location":"developer/design-system/#svgs-as-components-and-as-data-urls","title":"SVGs as Components and as Data-URLs","text":"

SVG assets are read into our codebase as React components (or inline SVG) or data-urls.

As React components:

  • specified with a starting uppercase
  • allows the use of React props to dynamically alter the component
  • requires editing stroke and fill values to inherit to allow passing in props
  • requires a wrapper element to add additional styling
  • are imported directly from the image file
  • difficult to work with by provide lots of customization

As Data-urls:

  • specified with a starting lowercase
  • are used as the src in img tags, to allow quick width/length adjustments
  • difficult to dynamically change
  • simple to declare and use
  • are imported with ?url qualifiers
  • not customizable beyond width and height
// COP Icons\nimport CopIconData from \"./svgs/cop-icon-datascience.svg\";\nimport CopIconEngineering from \"./svgs/cop-icon-engineering.svg\";\nimport CopIconOps from \"./svgs/cop-icon-ops.svg\";\nimport CopIconProduct from \"./svgs/cop-icon-product.svg\";\nimport CopIconUiux from \"./svgs/cop-icon-uiux.svg\";\n\nimport copIconData from \"./svgs/cop-icon-datascience.svg?url\";\nimport copIconEngineering from \"./svgs/cop-icon-engineering.svg?url\";\nimport copIconOps from \"./svgs/cop-icon-ops.svg?url\";\nimport copIconProduct from \"./svgs/cop-icon-product.svg?url\";\nimport copIconUiux from \"./svgs/cop-icon-uiux.svg?url\";\n

The top icons are imported from the image file as SVG components (or inline SVG). The bottom icons are the same file imported as data-urls. Notice how the latter import file adds \"?url\".

When using our SVG assets make sure to use the best import for the job. In some cases, however, neither of these imports are optimal to use. For example the SVG itself might be incorrectly formatted.

This SVG contains extra spaces, especially on the bottom. This image is impossible to center correctly without adding unnecessary margins.

In this case, rather than calculating some difficult to maintain, complex spacing, simply request the design team to provide a better SVG or edit the SVG yourself and send a copy to the design team.

"},{"location":"developer/design-system/#troubleshooting-errors","title":"Troubleshooting Errors","text":""},{"location":"developer/design-system/#you-may-not-extend-selectors-across-media-queries","title":"You may not @extend selectors across media queries.","text":"

This happens when @extend is used inside of media queries. An example using our DS,

.header-logo-desktop {\n  @include breakpoint-media-max(\"smtablet\") {\n    @extend .hidden;\n  }\n}\n

Using @extend inside of a media query will result in an error. Instead, use a mixin declaration with @include instead. Most classes in the DS include an equivalent mixin for this specific purpose.

.header-logo-desktop {\n  @include breakpoint-media-max(\"smtablet\") {\n    @include hidden;\n  }\n}\n

This works because it declares a mixin rather than extend the class!

To avoid these errors, it is encouraged to use the mixin rather than the class version of a specific style for inheritance whenever possible!

For more information visit this documentation and this Stack Overflow question.

"},{"location":"developer/design-system/#resources","title":"Resources","text":"

Atomic Design Atlassian Design System Bootstrap Material-UI

Note: If embeds are out-of-date, and you have no access to the originals, please fork and replace them through CodeSandbox!

CodeSandbox

"},{"location":"developer/development-culture/","title":"Development Culture","text":"

At CivicTechJobs, the developers of our team have 3 key tasks:

  • Make issues
  • Resolve issues
  • Review code

This guide will discuss how each of these work at CivicTechJobs. If you have any questions be sure to let us know! We strive to create an inclusive space for developers to learn and achieve their goals.

"},{"location":"developer/development-culture/#make-issues","title":"Make Issues","text":"

To make an issue, follow this guide from GitHub, or take a look at this section of the CONTRIBUTING.md.

At CivicTechJobs, updating the project starts with creating an issue outlining the situation and changes needed to resolve the situation. When writing an issue, a good rule of thumb is to write as if another developer would be the one to work on the issue. Therefore, being thorough is better than brief. Some good guidelines to follow:

  • Write a brief, two sentence summary for the overview. Be sure to note why these changes is needed.
  • In the overview, use language with little jargon.
  • Action items are usually step by step instructions or a list of requirements.
  • Longer explanations or useful documentation, if needed, are placed in the Instruction/Resources section.
  • Dependencies should 90% of the time be another issue. If this issue does not exist, it should probably be made and referenced as a dependency.
  • Likewise, the dependency should reference the issue it is a dependency for so that there is a trail to release issues with dependencies.
  • Check out examples of developer issues, such as this, for how to structure and word issues.

After writing out the issue, be sure to add labels. At minimum, we need three labels, one each from the \"size\", \"role\" and \"feature/p-feature\" series. In most cases, you should not create your own label. If you are unsure what labels to place, it is okay to leave it be, as another team member will help you when they notice the issue lacks certain labels.

Once an issue is created, and placed in the Project Management project board, the developer is mostly done with the issue. If the issue contains a dependency, it will move into the \"Ice Box\" column via GitHub automation, or \"New Issue Approval\", otherwise.

On rare occasions, a project manager, or other team members, might ping you with questions on the issue. Perhaps the team member did not understand the jargon, or the instructions were unclear. In that case, read their concerns carefully and either answer with a comment, or edit the original issue. Eventually, the issue will be approved, prioritized, and released into the \"Prioritized Backlog\" column, where developers can work on it.

"},{"location":"developer/development-culture/#resolve-issues","title":"Resolve Issues","text":"

To resolve an issue, take a look at this section of the CONTRIBUTING.md.

When choosing an issue to work on from the \"Prioritized Backlog\" column, it is good to note the \"role\" and \"size\" label. This signals the expertise required and time commitment needed to resolve the issue. As a rule of thumb, a smaller issue should take a week, and a larger issue, two or three weeks. This should give you a good idea on what issues is best for you to take at the moment. If you are completely new, we recommend taking smaller issues to understand your limits before pushing them further. That said, you are free to work on whatever you want.

On occasion, when an issue is being worked on for an inordinate amount of time, the team might request an update on your progress. When giving your progress, it is courteous to give an ETA on the issue, and evaluate on your ability to resolve the issue in a reasonable timeframe. If an issue is taking far too long, it might be wise to abandon the issue and work on something that might bring more value to you and the team.

Also, one final note: Do not contact the team via email or Slack to review your pull request unless it as been 72 hours since it was opened! The team will occasionally comb for pull requests and review them. If you want to move on to another issue, consider reviewing another developer's pull request (if you are part of the team), contribute to other open source projects, or ask the team for additional tasks.

Most issues can be divided into two broad types: frontend issues, and backend issues.

"},{"location":"developer/development-culture/#frontend-issues","title":"Frontend issues","text":"
  • Usually involves the appearance of the site
  • Usually easier than backend issues
  • Requires little research
  • Is occasionally an audit
  • May involve documentation

When working on frontend issues, there will usually be a link to the Figma design. Figma often contains multiple prototypes and future prototypes. When looking for our current design, go to the bottom right corner and look for a pink rectangle. Anything within that represents our most up-to-date design. Use that as a reference for your frontend issues. If the pink rectangle is not there, please request the UI design team to put a pink rectangle on the latest approved design.

On rare circumstances, designs can change in the middle of work. This is something that happens as part of development, but will often be telegraphed during meetings. If a design change, you are free to reassess and abandon your current issue, or code pragmatically to ensure your work would not need a massive overhaul.

"},{"location":"developer/development-culture/#backend-issues","title":"Backend issues","text":"
  • Usually involves research and discussion
  • Can also pertain to GitHub Actions
  • Usually takes some time
  • May involve documentation
"},{"location":"developer/development-culture/#review-code","title":"Review Code","text":"

To review code, please take a look at this GitHub documentation, and this portion of our CONTRIBUTING.md.

Code that should be reviewed is found in the pull request tab. These are issues that require someone to look over for several criteria:

  • Applicability: Were the correct changes made? Where new lines added or removed that are extraneous to the issue?
  • Brokenness: Did the changes break the site? Is the changes responsive to view-port changes?
  • Cleanliness: Is the new code programmatic or messy? Would the code be hard to maintain in the long run?

When code meets all three criteria, it can then be merged and made a part of the site. Otherwise, the review should indicate changes that needs to be made.

As an advanced project, CivicTechJobs have certain expectations for our developers. One of these is that issues of size 1 or 2 is small enough that we \"pre-review\" them. This means that we are confident that the developer can resolve these issues without review. Therefore, these issues can be merged directly into our codebase upon resolution. That said, it is still fine to request the team to review your code if feedback is desired.

Important: Although issues can be pre-reviewed, do not make a habit of merging without making a pull request. There will be times when you performed an accidental merge, which could be a pain to fix on the command-line.

As one final note, code can be merged solely on one approved review but it is fine to request more reviewers or ask for the team to review it during a developer meeting.

"},{"location":"developer/devops/","title":"DevOps Architecture","text":"
\u251c\u2500\u2500 .github/\n\u2502   \u2514\u2500\u2500 ISSUE_TEMPLATE/\n\u251c\u2500\u2500 app/\n\u2502    \u251c\u2500\u2500 config/\n\u2502          \u2514\u2500\u2500 settings.py\n\u2502    \u251c\u2500\u2500 frontend/\n\u2502    \u251c\u2500\u2500 server/\n\u2502    \u251c\u2500\u2500 .babelrc\n\u2502    \u251c\u2500\u2500 manage.py\n\u2502    \u251c\u2500\u2500 requirements.txt\n\u2502    \u251c\u2500\u2500 package.json\n\u2502    \u251c\u2500\u2500 package-lock.json\n\u2502    \u2514\u2500\u2500 webpack.config.js\n\u251c\u2500\u2500 dev/ # DevOps\n\u2502    \u251c\u2500\u2500 django.dockerfile\n\u2502    \u251c\u2500\u2500 webpack.dockerfile\n\u2502    \u2514\u2500\u2500 dev.env\n\u251c\u2500\u2500 .dockerignore # DevOps\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 jsconfig.json\n\u251c\u2500\u2500 CONTRIBUTING.md\n\u251c\u2500\u2500 docker-compose.yml # DevOps\n\u251c\u2500\u2500 LICENSE\n\u2514\u2500\u2500 README.md\n

Overall project structure

\u251c\u2500\u2500 dev/\n\u2502    \u251c\u2500\u2500 django.dockerfile\n\u2502    \u251c\u2500\u2500 webpack.dockerfile\n\u2502    \u2514\u2500\u2500 dev.env.example\n\u251c\u2500\u2500 .dockerignore\n\u251c\u2500\u2500 docker-compose.yml\n\u251c\u2500\u2500 alias-config.txt\n\u2514\u2500\u2500 alias.sh\n

DevOps Architecture

"},{"location":"developer/devops/#summary","title":"Summary","text":"

DevOps Tech Stack: Docker, Gunicorn, Nginx, PostgreSQL, test

Our devops files can be thought of as a set of files needed to create an exact replica of our environments for our developers. Although the overall structure appears deceptively basic, it only represents a fraction of our devops files. Several of our files, such as the ones that construct our staging environment, contains sensitive information, and as such as not placed in our public repository. For most frontend and backend work, there is never a need to access these files.

"},{"location":"developer/devops/#note-on-the-rare-occasions-that-there-is-a-need-to-access-the-sensitive-files-for-environments-other-than-development-please-consult-the-development-lead-of-the-project-they-will-know-exactly-what-files-you-need-and-what-permissions-you-need-to-access-them","title":"*Note: On the rare occasions that there is a need to access the sensitive files for environments other than development, please consult the development lead of the project. They will know exactly what files you need, and what permissions you need to access them.","text":""},{"location":"developer/devops/#overview-of-directories-and-files","title":"Overview of Directories and Files","text":"
  • dev/: contains two dockerfiles and an env file. django.dockerfile contains information for our Django server setup. webpack.dockerfile contains information to start our webpack watch plugin. dev.env.example is an example of the env file needed to configure our dev environment.
  • .dockerignore: This file tells Docker to ignore certain files when building the container. These are usually files that pertain to docker or git, which are not important when building the webserver.
  • docker-compose.yml: Contains instructions for docker when we run \"docker compose\". To know more about what each line does, please consult Docker's documentation.
  • alias.sh: Contains a shell script that allows for cumbersome commands to be executed with less typing by leveraging the aliases listed in alias-config.txt
"},{"location":"developer/devops/#docker","title":"Docker","text":"

Docker is a platform that allows packaging and virtualizing applications within a container. This gives developers the powerful ability to collaborate in a stable, synchonized environment, and deploying web applications with the greatest of ease. We will not be going too much into Docker here, but we will explain in greater depth some of the Docker configurations we have made.

"},{"location":"developer/devops/#docker-composeyml","title":"docker-compose.yml","text":"

This file contains configuration directions for docker compose. It consists of three services: pgdb (our database), webpack (our webpack bundler), and django (our django server). The webpack and django service relies in separate dockerfiles, located in the dev directory to build the container. This separation of dockerfiles enable each container to be build with its own set of dependencies. It also makes rebuilding the container simple when dependencies are migrated to a newer version.

For those of you used to creating applications without Docker, most would run webpack and django in separate terminals, so that they can both run at the same time. For the purposes of brevity, the different services can be considered to be Docker's way of running separate terminals.

One will also notice that the Django command uses a placeholder server name, 0.0.0.0:8000. This placeholder is important, since Docker creates an isolated environment. As a result, servers that are run in Docker does not recognize a browser from outside of that environment. Without this server name, localhost:8000 will not reach the server, as the server would recognize your browser as coming from a foreign machine. Therefore, all warnings related to 0.0.0.0, should they pop-up, should be ignored.

"},{"location":"developer/devops/#dockerfile","title":"*.dockerfile","text":"

Dockerfiles are files that define how a container is built. Although containerization is a deep concept, to put it briefly, you can think of containers as separate \"mini-computers\", each programmed to do one thing. Some containers, such as our pgdb container does not require a dockerfile to configure it, as it works out of the box. On the otherhand, our webpack and django containers need dockerfile to built out the files we need to run it effectively.

FROM node:latest\n\nWORKDIR /code\n\n\n# install app dependencies\nCOPY ./package.json ./\nCOPY ./package-lock.json ./\nRUN npm install\n\n\n# add app\nCOPY . .\n

Sample dockerfile that copies the package.json from a project and installs all dependencies.

Dockerfiles are usually named as just dockerfile, as that is the default name that docker looks for when constructing our builds. Since our project requires multiple dockerfiles, we name them with .dockerfile extensions, a convention that allows VSCode to detect dockerfiles and use appropriate syntax highlighting.

Do note that docker and dockerfiles can be fickle to work with, especially on old devices. Further down this documentation are various tips and commands that can be used with docker to help debug your code. But as always, consulting official documentation is the best way to get accurate, up-to-date information.

"},{"location":"developer/devops/#environments","title":"Environments","text":""},{"location":"developer/devops/#development","title":"Development","text":"

Our development environment is entirely defined by our docker-compose.yml, and the files inside of dev/. More information about those files can be found above.

Of note, however, is the dev.env.example file. This file is only a sample, but lists out all the environmental variables needed to run our site. While most of them are prefilled, some uses <> to indicate placeholders, which must be filled in by the developer.

"},{"location":"developer/devops/#staging","title":"Staging","text":"

More information on our staging files can be found with our staging files. To access this information, please ask for the required permissions from the development lead.

"},{"location":"developer/devops/#useful-commands","title":"Useful Commands","text":"
docker compose down -v\n

Useful to completely remove a container and related volumes. This is helpful when fiddling with database settings, which often breaks the database. This command allows the container to be restarted fresh.

docker compose -f <filename> <docker command>\n

Use this to specify an alternate docker-compose file to run your commands, such as docker-compose-other.yml. This is useful if you want to test out docker for yourself.

docker compose run <container> <command>\n

This is useful to run one time commands inside your container. Some good commands to run are:

  • python manage.py makemigrations
  • python manage.py migrate
  • python manage.py createsuperruser
  • pip install -r requirements.txt
  • npm install
    docker exec -it <container> sh\n

    Use this to do heavier debugging inside of your container. What this does is open the shell inside of the container's \"mini-computer\". This allows you to explore the files inside the container to see if it matches what you would expect after building is finished. This command only works when a container is running, so use docker compose run -d to run your container in the background beforehand.

    docker compose build --progress=plain\n

    Sometimes when a build is happening, the logs are too opaque to debug if a step goes wrong. This commands makes the logs a bit more verbose so that you might have an easier time debugging.

    "},{"location":"developer/devops/#alias-shell-script","title":"Alias Shell Script","text":"

    For convenience, we have created a shell script that allows for longer commands to be executed with less typing. The script is capable of executing any of the commands listed in alias-config.txt without having to type out the entire command.

    "},{"location":"developer/devops/#aliassh","title":"alias.sh","text":"

    To use this script, run bash alias.sh $arg or ./alias.sh $arg where $arg is the alias of the command you wish to execute. For example, try running bash alias.sh test.

    "},{"location":"developer/devops/#alias-configtxt","title":"alias-config.txt","text":"

    This file contains many of the important commands you will need when developing for this project. Note that each command starts with a single word followed by a : and then a command. You must follow this pattern when adding additional commands to the file. Please note that any docker run commands must use the -T flag to allocate a pusedo-TTY or the command will not work.

    "},{"location":"developer/devops/#additional-resources","title":"Additional Resources","text":"

    Docker Documentation

    "},{"location":"developer/frontend/","title":"Frontend Architecture","text":"
    \u251c\u2500\u2500 .github/\n\u2502   \u2514\u2500\u2500 ISSUE_TEMPLATE/\n\u251c\u2500\u2500 app/\n\u2502    \u251c\u2500\u2500 config/\n\u2502          \u2514\u2500\u2500 settings.py\n\u2502    \u251c\u2500\u2500 frontend/ # Frontend\n\u2502    \u251c\u2500\u2500 server/\n|    \u251c\u2500\u2500 tests/  # Frontend\n|    \u251c\u2500\u2500 .babelrc  # Frontend\n|    \u251c\u2500\u2500 .jest.config.js  # Frontend\n\u2502    \u251c\u2500\u2500 manage.py\n\u2502    \u251c\u2500\u2500 requirements.txt\n\u2502    \u251c\u2500\u2500 package.json # Frontend\n\u2502    \u251c\u2500\u2500 package-lock.json # Frontend\n\u2502    \u2514\u2500\u2500 webpack.config.js # Frontend\n\u251c\u2500\u2500 dev/\n\u2502    \u251c\u2500\u2500 django.dockerfile\n\u2502    \u251c\u2500\u2500 webpack.dockerfile\n\u2502    \u2514\u2500\u2500 dev.env\n\u251c\u2500\u2500 .dockerignore\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 jsconfig.json\n\u251c\u2500\u2500 CONTRIBUTING.md\n\u251c\u2500\u2500 docker-compose.yml\n\u251c\u2500\u2500 LICENSE\n\u2514\u2500\u2500 README.md\n

    Overall project structure

    \u251c\u2500\u2500 frontend/\n\u2502   \u251c\u2500\u2500 src/\n\u2502       \u251c\u2500\u2500 assets/\n\u2502       \u251c\u2500\u2500 components/\n\u2502           \u251c\u2500\u2500 Apps.js\n\u2502           \u2514\u2500\u2500 <Components>/\n\u2502       \u251c\u2500\u2500 context/\n\u2502           \u251c\u2500\u2500 QualifiersContext.tsx\n\u2502       \u251c\u2500\u2500 pages/\n\u2502       \u251c\u2500\u2500 templates/\n\u2502           \u2514\u2500\u2500 index.html\n\u2502       \u251c\u2500\u2500 index.js\n\u2502       \u2514\u2500\u2500 index.scss\n\u2502   \u251c\u2500\u2500 static\n\u2502   \u2514\u2500\u2500 templates\n\u251c\u2500\u2500 tests/\n\u251c\u2500\u2500 .babelrc\n\u251c\u2500\u2500 .jest.config.js\n\u251c\u2500\u2500 package-lock.json\n\u251c\u2500\u2500 package.json\n\u2514\u2500\u2500 webpack.config.js\n

    Frontend Architecture

    These diagrams show how data flows through the app: Frontend and Backend UML diagrams

    "},{"location":"developer/frontend/#summary","title":"Summary","text":"

    Frontend Tech Stack: React, Babel, webpack, Jest, React Testing Library, HTML, SCSS, JS, TailwindCSS

    The over ninety percent of our frontend architecture is housed in our frontend/ directory. This directory is a Django app, which is a set of files that can be ported to any Django-based application.

    Since our frontend is a Django app, it takes advantage of the way Django serves its static assets. Every Django app, by default, looks to the templates/* directory within the app for the html template file to serve. This template usually contains <script> and <style> tags denoting the location of SCSS and JS files. In Django, these files are usually located inside the static/* directory. Likewise, our frontend app store our templates and static assets within these directories.

    Despite these similiarties, however, the files in these two directories should never be manipulated by a developer. These files are automatically generated by an application called webpack via configurations in webpack.config.js and .babelrc.

    The files that should be manipulated by developers are housed within the src/ directory. Inside of here are directories for assets/, componenents/, pages/, router, and templates/. Each of these directories contains the files which webpack reads and then bundle into output files for the static/ and template/ directories.

    "},{"location":"developer/frontend/#note-the-templates-and-static-directories-contain-within-them-a-frontend-directory-in-order-to-namespace-template-and-static-files-although-this-serves-little-purpose-for-our-project-it-is-a-django-convention-that-prevents-django-from-confusing-the-templates-and-static-directories-from-the-frontend-app-vs-another-app","title":"*Note: The templates/ and static/ directories contain within them a frontend/ directory in order to namespace template and static files. Although this serves little purpose for our project, it is a Django convention that prevents Django from confusing the templates/ and static/ directories from the frontend app vs another app.","text":""},{"location":"developer/frontend/#overview-of-directories-and-files","title":"Overview of Directories and Files","text":"
    • frontend/: houses all the frontend files.
    • frontend/src/: houses all the files for developers to manipulate. The files here are read by webpack before being bundled into the static/ and templates/ directories.
    • assets/: this is where we store all of our miscellaneous files, such as .jpegs, .svgs, .gifs, etc.
    • componenents/: this is where we store the files that generate our components, such as buttons and cards. To learn more about this in-depth, read the components section of this guide.
    • context/: contains the logic and data management utilities related to context providers and consumers. Contexts are used for managing global state within our application, providing a way to pass data through the component tree without having to pass props manually at every level. - COP (Community of Practice) JSON Structure: The COP data represents different communities of practice within our organization, each consisting of various roles and descriptions. Below is the JSON structure of the COP data for QualifierPageRoles.tsx: { \"COPs\": { \"UI/UX\": [ \"UI/UX_Designer\", \"UX_Researcher\", \"UX_Writing\", \"UX_Practice_Lead\" ], \"Engineering\": [ \"Back_End_Developer\", \"Front_End_Developer\", \"Full_Stack_Developer\", \"Engineering_Practice_Lead\" ], \"Data_Science\": [ \"Data_Scientist\", \"Data_Analyst\", \"Data_Engineer\", \"Data_Science_Practice_Lead\" ], \"Project/Product_Management\": [ \"Product_Manager\", \"Project_Manager\", \"Business_Analyst\", \"Product_Owner\", \"Special_Projects_Coordinator\", \"Product_Management_Practice_Lead\" ], \"DevOps\": [ \"Site_Reliability_Engineer\", \"Data_Engineer\", \"Database_Architect\", \"Security_Engineer\", \"DevOps_Practice_Lead\" ] } }
    • pages/: contains the React files that pools together various components to generate a page.
    • router/: contains the routing logic for the project. It uses the React-Router library.
    • templates/: contains HTML files that are then generated into the regular templates directory. To learn more about how webpack bundle our files, read the webpack section of this guide.
    • index.js: this file serves as the entry point for all other js files*. This file is read by webpack, and then bundled into code in the static directory.
    • index.scss: this file serves as the entry point for all other scss files*.
    • frontend/static/: automatically generated by webpack, DO NOT EDIT
    • frontend/templates/: automatically generated by webpack, DO NOT EDIT
    • tests/: contains our test files. To run these files simply use docker compose run webpack npm run test.
    • .babelrc: Babel's configuration. To learn more about this, please visit babel's documentation.
    • .jest.config.js: Jest's configuration. To learn more about configuring Jest, please visit jest's documentation.
    • package-lock.json & package.json: These files are created by npm to keep track of dependencies. Please visit npm's documentation to understand them.
    • webpack.config.js: webpack's configuration. To learn more about configuring webpack, please visit their documentation. To learn about our specific configuration, see the below guide.
    "},{"location":"developer/frontend/#note-this-is-technically-a-lie-in-actuality-indexjs-reads-indexs-as-well-as-the-react-files-making-it-the-only-entryway-for-all-files-bundled-in-the-src-directory","title":"*Note: This is technically a lie. In actuality, index.js, reads index.s as well as the React files, making it the only entryway for all files bundled in the src/ directory.","text":""},{"location":"developer/frontend/#components-directory","title":"Components Directory","text":"
    \u251c\u2500\u2500 components/\n\u2502   \u251c\u2500\u2500 Basics/\n\u2502       \u251c\u2500\u2500 Colors.scss\n\u2502       \u2514\u2500\u2500 Titles.scss\n\u2502   \u251c\u2500\u2500 Buttons/\n\u2502       \u251c\u2500\u2500 Button.js\n\u2502       \u2514\u2500\u2500 Button.scss\n\u2502   \u251c\u2500\u2500 Cards/\n\u2502       \u251c\u2500\u2500 Cards.js\n\u2502       \u2514\u2500\u2500 Cards.scss\n\u2502   \u2514\u2500\u2500 <Components>/\n

    A closer look at a theoretical expansion of the components directory

    The components directory contains our site components. Each directory in here represents a different class of components, such as Buttons/* or Cards/*. Within these directories are the files necessary that creates these components. Likewise, the special Basics/ directory contains small CSS classes that are reused, but not, technically, components, such as text-size or text-colors.

    "},{"location":"developer/frontend/#note-these-files-are-capitalized-to-follow-react-convention-for-components-when-making-new-components-please-make-sure-to-follow-this-convention-this-convention-is-in-place-to-help-react-differentiate-between-modules-vs-other-types-of-imports","title":"*Note: These files are capitalized to follow React convention for components. When making new components, please make sure to follow this convention. This convention is in place to help React differentiate between modules vs other types of imports.","text":""},{"location":"developer/frontend/#webpack-configurations","title":"Webpack Configurations","text":"
    ...\n\nmodule.exports = {\n    mode: 'development',\n    entry: {\n        index: \"./frontend/src/index.js\"\n    },\n    output: {\n        clean: {\n            keep: '.gitkeep'\n        },\n        filename: '[name].[contenthash].js',\n        path: path.resolve(__dirname, 'frontend/static/frontend'),\n    },\n    devtool: 'inline-source-map',\n    module: {\n        rules: ...\n    },\n    optimization: {\n        moduleIds: 'deterministic',\n        runtimeChunk: 'single',\n        splitChunks: ...\n    },\n    plugins: [\n        new HtmlWebpackPlugin({\n            filename: '../../templates/frontend/index.html',\n            template: '/frontend/src/templates/index.html',\n        }),\n    ],\n    watchOptions: {\n        ignored: /node_modules/,\n    },\n}\n

    webpack.config.js (truncated)

    Our webpack.config.js file is one of the most important files to understanding how our frontend architecture comes together. Therefore, this section is dedicated to the settings that we have set for this file. Note that we do not explain all the settings, as some can be found and easily deduced from webpack's configuration and guides documentation.

    • entry: the file that is ultimately read by webpack to bundle everything together. This file, index.js imports all dependencies and files that makes up our product. Note that advanced multiple entry is possible, should we ever need it.
    • output: contains configurations for the files that are generated in the static/ directory
    • output > clean > keep: clean is usually used to clear away old files before generating new ones (filenames are variable to force browser css/js recacheing). However, keep notes files that should not be removed*.
    • output > filename: this configures the name of the generated js files. [name] is simply the name of the file noted in the entry configuration, and [contenthash] is a randomly generated string, which forces browser recacheing.
    • output > path: the directory to place the generated file. This directory is the one that Django, by default, detects its static files.
    • optimization: this contains a catch-all for various ways to enhance either development or deployment. For more on our current configuration, read this guide.
    • plugins > HtmlWebpackPlugin: this plugin enables us to dynamically generate templates with the correct <script> and <styles> path by reading the template and outputing it with the path noted by filename. This output path follows Django's default template directory structure.
    • watchOptions > ignored: configures files to ignore when regenerating watched files.
    "},{"location":"developer/frontend/#note-the-kept-gitkeep-file-is-there-to-give-an-empty-file-for-git-to-preserve-the-otherwise-empty-directory-when-pushed-onto-github-as-you-might-have-guessed-git-does-not-push-empty-directories","title":"*Note: The kept .gitkeep file is there to give an empty file for git to preserve the otherwise empty directory when pushed onto GitHub. As you might have guessed, git does not push empty directories.","text":""},{"location":"developer/frontend/#why-do-we-separate-babel-from-webpack","title":"Why do we separate Babel from webpack?","text":"

    If you have explored documentation from webpack, you might learn that the babel-loader in module > rules can accept the settings noted in .babelrc. The reason why we separate these settings into another file is because webpack is not, in theory, the only application that makes use of these settings. Although we have no other apps that makes use of .babelrc at the moment, this can change in the future. Therefore, this separation of files is a form of future proofing.

    "},{"location":"developer/frontend/#testing","title":"Testing","text":""},{"location":"developer/frontend/#component-testing","title":"Component Testing","text":"

    Our tests exists inside the tests directory with subdirectories that follows frontend/src. There is also __mock__/ which contains code that bypasses certain tricky imports, such as svg or SCSS assets, which are not needed when testing. In order to understand how to write tests, be sure to take a look at the documentation for React Testing Library, the parent DOM Testing Library, and the support libraries jest-dom and user-event.

    To run these tests, use the command docker compose run webpack npm run test (or with test:w for watch mode). The tests are run through jest, while the other libraries support react testing by providing functions to render DOM elements and simulate user behavior.

    Note: jest-environment-jsdom is a library that is absolutely required to link jsdom to jest. It provides the classes necessary for jest to interpret the jsdom environment. This information is listed here as it is not listed in jest's or jsdom's docs.

    "},{"location":"developer/frontend/#accessibility-testing","title":"Accessibility Testing","text":"

    In addition to testing the functioning of our components, we also test the accessability of it via the library, @axe-core/react. This library prints out accessibility issues onto the browser console, providing accessibiltiy testing once the HTML has fully rendered. That said, the library is known to give both false positives and false negatives. As always reading the official documentation is best when it comes to resolving these errors.

    "},{"location":"developer/frontend/#additional-resources","title":"Additional Resources","text":"

    Sass Documentation React Documentation Webpack Documentation @babel/preset-react Documentation React Router Documentation Jest Documentation React Testing Library Documentation @axe-core/react Documentation WAI-ARIA Authoring Practices 1.1

    "},{"location":"developer/github/","title":"GitHub Architecture","text":"
    \u251c\u2500\u2500 .github/ # Github\n\u2502   \u2514\u2500\u2500 ISSUE_TEMPLATE/\n\u251c\u2500\u2500 app/\n\u2502    \u251c\u2500\u2500 config/\n\u2502          \u2514\u2500\u2500 settings.py\n\u2502    \u251c\u2500\u2500 frontend/\n\u2502    \u251c\u2500\u2500 server/\n\u2502    \u251c\u2500\u2500 .babelrc\n\u2502    \u251c\u2500\u2500 manage.py\n\u2502    \u251c\u2500\u2500 requirements.txt\n\u2502    \u251c\u2500\u2500 package.json\n\u2502    \u251c\u2500\u2500 package-lock.json\n\u2502    \u2514\u2500\u2500 webpack.config.js\n\u251c\u2500\u2500 dev/\n\u2502    \u251c\u2500\u2500 django.dockerfile\n\u2502    \u251c\u2500\u2500 webpack.dockerfile\n\u2502    \u2514\u2500\u2500 dev.env\n\u251c\u2500\u2500 .dockerignore\n\u251c\u2500\u2500 .gitignore # Github\n\u251c\u2500\u2500 jsconfig.json\n\u251c\u2500\u2500 CONTRIBUTING.md # Github\n\u251c\u2500\u2500 docker-compose.yml\n\u251c\u2500\u2500 LICENSE # Github\n\u2514\u2500\u2500 README.md # Github\n

    Overall project structure

    \u251c\u2500\u2500 .github/\n\u2502   \u2514\u2500\u2500 ISSUE_TEMPLATE/\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 CONTRIBUTING.md\n\u251c\u2500\u2500 LICENSE\n\u2514\u2500\u2500 README.md/\n

    GitHub structure

    "},{"location":"developer/github/#summary","title":"Summary","text":""},{"location":"developer/github/#overview-of-directories-and-files","title":"Overview of Directories and Files","text":"
    • LICENSE:
    • README.md:
    "},{"location":"developer/github/#github-actions","title":"GitHub Actions","text":""},{"location":"developer/github/#additional-resources","title":"Additional Resources","text":""},{"location":"developer/installation/","title":"Installation Instructions","text":"

    This guide runs through the steps needed to create and run a local version of our project.

    If you are ever stuck or need clarification, you can contact our team members or the development lead through our Slack or email, and schedule a pair programming session with one of our developers. All of us have been through these steps, and am more than happy to help. By helping you, we can better improve our documentation and grow this project!

    "},{"location":"developer/installation/#required-downloads","title":"Required Downloads","text":"

    Git - Windows - macOS - Linux/Unix Docker - Windows - macOS - Linux/Unix Prettier - VSCode Extension

    Note on macOS The macOS version of git involves downloading extra programs, such as Homebrew. In some cases this program can run up to 8GB of storage space, which might be too much for some. In that scenario, a miniature version of Homebrew can be installed through XCode. But do be warned that the containers for our project takes up a substantial amount of disk space as well. Do consider freeing up your disk space by deleting or backing up unneeded files, like photos or videos, and delete programs that are no longer useful. Your OS's native disk cleaner can also clear out unused cache files.

    "},{"location":"developer/installation/#environmental-setup","title":"Environmental Setup","text":"
    1. Fork our repository.
    2. Clone our repository to a local version on your PC.
    3. Configuring Git to sync your fork with the original repository. When configuring, make sure to not blindly copy and paste the commands without making appropriate edits, especially when it involves your username or the repository name.

    While developing, make sure to create new branches off of the develop branch. To checkout the develop branch into your local repository, you can do the following:

    1. Navigate to the root of our directory, CivicTechJobs/, in the terminal.
    2. Run git remote add upstream https://github.com/hackforla/CivicTechJobs.git - this command adds the original hackforla CivicTechJobs github repo as a remote to your local repository and names it \"upstream\".
    3. Run git fetch upstream develop - this command fetches the develop branch.
    4. Run git checkout -b develop upstream/develop - this command creates and checks out a new branch called \"develop\" that tracks the upstream develop branch.
    "},{"location":"developer/installation/#running-docker","title":"Running Docker","text":"
    1. Navigate to the root of our directory, CivicTechJobs/, in the terminal.
    2. In dev/, create a file named, dev.env.
    3. In this newly created file, copy and paste the contents of dev.env.example. Afterwards, you must edit the lines specified below.
    4. Move to the frontend directory cd frontend and then npm install. When this is finished, move back to the root directory cd ..
    5. Finally, enter docker compose up --watch to run the local server.
    6. Visit http://localhost:8000 and you should see the front page of our website!
    dev.env lines to edit
    • POSTGRES_DB: a name for your database, such as `postgres`
    • POSTGRES_USER: a username for your database
    • POSTGRES_PASSWORD: a password for your database
    • SECRET_KEY: a random string of length 50. You can use your favorite secret key generator to achieve this. To learn more about how Django generate default keys, see [Python's secrets's library](https://docs.python.org/3/library/secrets.html#secrets.token_urlsafe).
    • SQL_DATABASE: same as POSTGRES_DB
    • SQL_USER: same as POSTGRES_USER
    • SQL_PASSWORD: same as POSTGRES_PASSWORD
    Note on docker `--watch` flag

    The `--watch` flag enables hot module reloads during development. This flag requires a later version of Docker Compose(2.22.0).

    If you are running into issues or getting errors running `docker compose up --watch`, please make sure you have installed the latest version of Docker and Docker Desktop on your machine.

    "},{"location":"developer/installation/#frequently-asked-questions","title":"Frequently Asked Questions","text":"

    This section might answer some of the burning questions you have. If you cannot find it here, be sure to contact our team members or the development lead through our Slack or email.

    "},{"location":"developer/installation/#troubleshooting-errors","title":"Troubleshooting Errors","text":""},{"location":"developer/installation/#1-the-command-docker-could-not-be-found","title":"1. The command 'docker' could not be found","text":"

    Make sure to turn on Docker by opening the Docker program on your desktop.

    "},{"location":"developer/installation/#2-cant-find-a-suitable-configuration-file-in-this-directory-or-any-parent-not-found","title":"2. can't find a suitable configuration file in this directory or any parent: not found","text":"

    Make sure that your terminal location is in a directory with a docker-compose.yml file. And make sure that the file is not hidden.

    "},{"location":"developer/installation/#3-code-err_socket_timeout","title":"3. code ERR_SOCKET_TIMEOUT","text":"

    This can result for several reasons, such as havin your sockets overloaded. In order to prevent this, the best thing to do is to lower the amount of sockets used when performing npm install. Change this line in docker/webpack:

    RUN npm install

    to:

    RUN npm install --maxsockets=1

    This should allow docker compose up to work. Be sure to delete the addition once your image and container is set up.

    "},{"location":"developer/installation/#4-dependency-not-found","title":"4. [dependency] not found","text":"

    This sometimes happen when npm did not install successfully. In this scenario, you need to manually install the dependencies inside the container. Generally the command to run a command inside a container is:

    docker compose run [container name] [command to run in container]

    In this scenario, the full command would be:

    docker compose run webpack npm install

    "},{"location":"developer/installation/#5-webpack-cli-error-eacces-permission-denied-open-codefrontendtemplatesfrontendindexhtml","title":"5. [webpack-cli] [Error: EACCES: permission denied', open '/code/frontend/templates/frontend/index.html']","text":"

    In this case, the index.html file has incorrect ownership and/or permissions. To fix this, run the following command in the root directory of the CTJ repository:

    sudo chown -R $USER:$USER

    This will utilize superuser permissions to change the user and group ownership of all the files and directories in the current directory to the current user.

    "},{"location":"developer/installation/#additional-resources","title":"Additional Resources","text":"

    Git Documentation Docker Documentation Frontend Architecture Backend Architecture DevOps Architecture GitHub Architecture

    "},{"location":"developer/mkdocs-architecture/","title":"MKdocs Architecture","text":"
    \u251c\u2500\u2500 .github/\n\u2502   \u251c\u2500\u2500 ISSUE_TEMPLATE/\n\u2502   \u2514\u2500\u2500 workflows/\n\u2502       \u2514\u2500\u2500 mkdocs-build.yml # Docs\n\u251c\u2500\u2500 backend/\n\u251c\u2500\u2500 dev/\n\u251c\u2500\u2500 frontend/\n\u251c\u2500\u2500 mkdocs/ # Docs\n\u2502   \u251c\u2500\u2500 docs/\n\u2502   \u2514\u2500\u2500 mkdocs.yml # Docs\n\u251c\u2500\u2500 .dockerignore\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 CONTRIBUTING.md\n\u251c\u2500\u2500 docker-compose.yml\n\u251c\u2500\u2500 docker-compose.docs.yml # Docs\n\u251c\u2500\u2500 LICENSE\n\u2514\u2500\u2500 README.md\n

    Overall project structure

    \u251c\u2500\u2500 docs/\n\u2502   \u251c\u2500\u2500 assets/\n\u2502   \u251c\u2500\u2500 css/\n\u2502   \u251c\u2500\u2500 developer/\n\u2502   \u251c\u2500\u2500 joining-the-team/\n\u2502   \u251c\u2500\u2500 js/\n\u2502   \u2514\u2500\u2500 misc/\n\u251c\u2500\u2500 index.md\n\u251c\u2500\u2500 resources.md\n\u251c\u2500\u2500 mkdocs.yml\n

    mkdocs directory structure

    "},{"location":"developer/mkdocs-architecture/#summary","title":"Summary","text":"

    The MkDocs \"sub-project\" lives in the mkdocs/ folder. A development server can be run using the docker-compose.docs.yml compose script. The mkdocs is set to automatically deploy to github pages using the mkdocs-build.yml github action.

    "},{"location":"developer/mkdocs-architecture/#docker-mkdocs","title":"Docker MkDocs","text":"

    It is important to note that we are using Hack for LA's prebuilt docker mkdocs image for convenient setup. Please see the resources below for more information:

    • Hack for LA - docker-mkdocs repo
    • Hack for LA - docker-mkdocs documentation
    • Hack for LA - docker-mkdocs dockerhub image

    This prebuilt docker image makes it easy to get a mkdocs development server running with one command, without having to install python or mkdocs dependencies on your local machine. It also includes common useful plugins that we dont have to worry about installing ourselves, and already includes the mkdocs-material theme pre-installed.

    Our project implements the HFLA mkdocs image by pulling it inside the docker-compose.docs.yml file:

    name: civic-tech-jobs-mkdocs\n\nservices:\n  mkdocs:\n    container_name: mkdocs\n    image: hackforlaops/mkdocs:latest\n    command: mkdocs serve -a \"0.0.0.0:8005\"\n    ports:\n      - \"8005:8005\"\n    volumes:\n      - ./mkdocs:/app\n    develop:\n      watch:\n        - action: sync\n          path: ./mkdocs\n          target: /app\n

    Now when we run docker compose up like so:

    docker-compose -f docker-compose.docs.yml up --watch\n

    A mkdocs development server is started on http://localhost:8005

    "},{"location":"developer/mkdocs-architecture/#mkdocs-deployment","title":"MkDocs Deployment","text":"

    The url for the github pages site is: https://hackforla.github.io/CivicTechJobs/ (the website you are reading this on right now).

    Our github repo is set to publish the docs to Github Pages using the gh-pages branch. This setting can be configured in the project's Pages settings.

    External Resources:

    • MkDocs Documentation | deployment instructions
    • Github Pages documentation

    Relevant PR and Issue:

    • Fix mkdocs deployment #456
    • Feat/fix mkdocs #592

    The docs are set to automatically deploy to github pages using the mkdocs-build.yml github action. This action builds the mkdocs and saves the static files into the gh-pages branch.

    "},{"location":"developer/mkdocs-architecture/#github-action-for-mkdocs-deployment","title":"Github Action for mkdocs deployment","text":"

    Links to the github action: Build MkDocs site (develop)

    name: Build MkDocs site (develop)\n\non:\n  push:\n    branches:\n      - develop\n    paths:\n      - \"mkdocs/**/**.md\"\n      - \"mkdocs/mkdocs.yml\"\n  workflow_dispatch:\n\npermissions:\n  contents: write\n\njobs:\n  deploy-docs:\n    runs-on: ubuntu-latest\n    if: github.actor != 'github-actions[bot]'\n    steps:\n      - uses: actions/checkout@v4\n      - name: Configure Git Credentials\n        run: |\n          git config user.name github-actions[bot]\n          git config user.email 41898282+github-actions[bot]@users.noreply.github.com\n      - uses: actions/setup-python@v5\n        with:\n          python-version: 3.x\n      - run: echo \"cache_id=$(date --utc '+%V')\" >> $GITHUB_ENV\n      - uses: actions/cache@v4\n        with:\n          key: mkdocs-material-${{ env.cache_id }}\n          path: .cache\n          restore-keys: |\n            mkdocs-material-\n      - name: Install Dependencies\n        run: pip install \\\n          mkdocs-material==9.1.17 \\\n          mkdocs-autolinks-plugin==0.7.1\n      - name: Publish docs\n        run: |\n          cd mkdocs\n          mkdocs gh-deploy --force\n

    Workflow Overview

    • name: Build MkDocs site - The name of this workflow is \"Build MkDocs site.\"
    • on: push: - develop - The workflow is triggered when there\u2019s a push to the develop branch. (We will change this to main later)
    • paths: ... - The workflow will only run if the files being pushed are Markdown files (.md) or the mkdocs.yml configuration file inside the mkdocs directory.
    • workflow_dispatch: - This allows manual triggering of the workflow via the GitHub Actions interface.
    • permissions: contents: write - This grants the action permission to write contents to the repository. It's needed for deploying the site, which requires pushing to the gh-pages branch.
    • runs-on: ubuntu-latest - This specifies that the job will run on the latest Ubuntu environment provided by GitHub Actions.
    • if: github.actor != 'github-actions[bot]' - This condition ensures that the job doesn\u2019t trigger if the GitHub Actions bot is the one making the changes. This prevents infinite loops where the action keeps triggering itself.
    • uses: actions/checkout@v4 - This step checks out the repository code so the workflow can access the files.
    • run: git config user.name github-actions[bot] - Configures Git to use the github-actions[bot] user for any commits or pushes that may happen during the deployment.
    • git config user.email 41898282+github-actions[bot]@users.noreply.github.com - Sets the email for the github-actions[bot] user.
    • uses: actions/setup-python@v5 - This sets up a Python environment in the GitHub runner, which is necessary for installing and running MkDocs.

    Set environment variable for caching

    • run: echo \"cache_id=$(date --utc '+%V')\" >> $GITHUB_ENV
    • This step sets an environment variable called cache_id to the current week of the year (%V). This value will be used as the key for caching to ensure that the cache is updated weekly.

    Cache dependencies

    • uses: actions/cache@v4 - This step caches dependencies (to speed up future builds) in the .cache directory.
    • with: key: mkdocs-material-${{ env.cache_id }} - The cache key is based on the cache_id, so the cache is refreshed weekly.
    • path: .cache - Specifies that the cache should be stored in the .cache directory.
    • restore-keys: mkdocs-material- - This allows for fallback caching if an exact cache match is not found.

    Install Dependencies

    • run: pip install mkdocs-material==9.1.17 mkdocs-autolinks-plugin==0.7.1
    • This installs the necessary dependencies for MkDocs to work. In this case:
    • mkdocs-material==9.1.17: A popular theme for MkDocs.
    • mkdocs-autolinks-plugin==0.7.1: A plugin that automatically creates links between pages in your documentation based on their titles.

    Publish Documentation

    • run: cd mkdocs && mkdocs gh-deploy --force
    • first it changes to the mkdocs/ directory.
    • then it deploys the MkDocs site to GitHub Pages using mkdocs gh-deploy --force. The --force flag ensures that the contents of the GitHub Pages branch (gh-pages) are overwritten with the latest deployment.
    "},{"location":"developer/mkdocs-architecture/#summary_1","title":"Summary","text":"

    This workflow automates the process of building and deploying a MkDocs site when changes are pushed to the develop branch. It does the following:

    1. Checks out the repository and configures Git for pushing changes.
    2. Sets up Python and installs the necessary MkDocs dependencies.
    3. Caches dependencies to speed up future builds.
    4. Deploys the site to GitHub Pages using mkdocs gh-deploy.

    This workflow ensures the documentation is always up to date and available on GitHub Pages whenever changes are made to relevant Markdown files or the MkDocs configuration.

    "},{"location":"developer/mkdocs-edit-instructions/","title":"How to Publish new Documentation","text":"

    The goal of this page is to document how to create and publish new changes to the CTJ documentation.

    Writing documentation into mkdocs requires some knowledge of Markdown.

    "},{"location":"developer/mkdocs-edit-instructions/#making-changes-to-the-mkdocs","title":"Making changes to the mkdocs","text":"

    What you essentially need to know:

    • To make changes to the docs, edit the .md files located in the mkdocs/docs/ folder.
    • To make a new page, create a new .md file in the appropriate folder.
    • To add or edit links in the navmenu, configure the mkdocs.yml file.

    MkDocs provides a development server that makes it convenient to see your changes in localhost before you deploy them to github.

    For more a detailed editing guide please see the official MkDocs Tutorial

    "},{"location":"developer/mkdocs-edit-instructions/#quickstart","title":"Quickstart","text":"

    To start the development server, simply go to the root of your project in the terminal and run the following command:

    docker-compose -f docker-compose.docs.yml up --watch\n

    Next, go to http://localhost:8005 in your browser.

    Now when you save new changes to the .md files, the respective page will automatically be updated in the browser.

    When you are done editing, the next step is to deploy your changes.

    "},{"location":"developer/mkdocs-edit-instructions/#deploying-your-changes","title":"Deploying your changes","text":"

    When you are satisfied with your edits, make a pull request so that they can be reviewed.

    Once the pull request is approved and merged into develop, the changes will be automatically deployed to the official CivicTechJobs documentation site (the site you are reading this page in right now). That's it!

    If anything goes wrong, you can investigate the workflow in the project's github actions page

    Note: At the moment, the docs are set to deploy from the develop branch, using the github action located in mkdocs-build.yml. This means that whenever a file is changed inside the mkdocs/ directory, and is merged into the develop branch on github, the changes will be automatically deployed to the official site hosted on github pages. In the near future we will set it to deploy from the main branch.

    Check out our MkDocs Architecture page for more details on how it all fits together.

    "},{"location":"developer/mkdocs-edit-instructions/#recap","title":"Recap","text":"

    To sum it all up, you can make changes in 4 easy steps:

    1. Start the development server using docker-compose -f docker-compose.docs.yml up --watch
    2. Make changes to the .md files and observe them in http://localhost:8005
    3. Open a Pull Request with your new changes
    4. Merge the Pull Request into the develop branch
    "},{"location":"developer/mkdocs-guide/","title":"MkDocs - Documentation Guide","text":"

    We are using mkdocs to handle documentation.

    Developers should document their architectural and coding decisions, so that other team members can easily reference these docs whenever they are lost or confused or new to the project.

    "},{"location":"developer/mkdocs-guide/#what-is-mkdocs","title":"What is MKdocs?","text":"

    MkDocs is a static site generator that is designed specifically for building project documentation. It allows you to write documentation using Markdown, a lightweight markup language that's easy to use, and generates a clean, professional website that can be hosted on our project's GitHub Pages.

    Please see MkDocs - How to Edit for instructions on how to make changes to the CTJ documentation and publish new docs.

    "},{"location":"developer/mkdocs-guide/#what-should-developers-document","title":"What should developers document?","text":"

    Code functionality

    • Document the purpose and functionality of the code you write. Describe what each module, class, or function does, especially if it might not be obvious at first glance.
    • Example: If you implement a new API endpoint, document what the endpoint does, the request and response formats, and any important business logic involved.

    Setup Instructions

    • Make sure to document how to set up the project or new features you add. Include all dependencies, environment variables, and steps to get the project running locally or in production.
    • Example: If you introduce a new tool like Docker or a new package, make sure to document how to install and configure it.

    Common Use Cases

    • Document common or important use cases for the code. This is especially useful for other developers who might use your code in the future.
    • Example: If you build a new utility or library, include examples showing how it should be used.

    Troubleshooting

    • Include a section for common issues and how to resolve them. This can be a lifesaver for both new developers and anyone maintaining the project.
    • Example: Document errors or challenges you faced during development and their solutions.

    Code Examples

    • Where applicable, provide sample code or snippets to explain usage. These examples help future developers quickly understand how to use your components or functions.
    • Example: If you write a custom hook in React, include an example of how it can be used in a component.

    API Documentation

    • Ensure that all APIs (REST or GraphQL) have detailed documentation on endpoints, parameters, return types, and possible error codes.
    • Example: For each API endpoint, include descriptions of what it does, what data it expects, and the structure of its responses.
    "},{"location":"developer/mkdocs-guide/#what-are-best-practices-for-documentation","title":"What are best practices for documentation?","text":"
    • Keep it updated and consistent.
    • Be clear and concise.
    • Write in simple terms.
    • Use examples.
    "},{"location":"joining-the-team/content-writer/","title":"Content Writer","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"joining-the-team/content-writer/#content-writer","title":"Content Writer","text":"
    1. Review existing copy on the CivicTechJobs.

    2. Review the Figma for pages that are not yet published.

    3. Review the Project Board and identify an actionable backlog item.

    4. Communicate with PM your interest in being assigned a task.

    "},{"location":"joining-the-team/data-scientist/","title":"Data Scientist","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"joining-the-team/data-scientist/#data-scientist","title":"Data Scientist","text":"
    1. Read the Readme.

    2. Review the Project Board and identify an actionable backlog item. We are working to resolve some database architecture issues and are not onboarding new data scientist at this time.

    3. Communicate with the PM on your interest in being assigned a task.

    "},{"location":"joining-the-team/intro/","title":"Intro","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"joining-the-team/intro/#introduction","title":"Introduction","text":"

    Welcome to the Civic Tech Jobs team! This guide will help get you up to speed on what you need to know to get started as a project team member.

    "},{"location":"joining-the-team/intro/#lets-go","title":"Let's go!","text":"

    If you have not read the Guide for New Volunteers, please do so.

    1. Check the Community of Practice -> Open Roles Board for current open roles in the Civic Tech Jobs project.
    2. Read Introduction to the Project if you haven't already read it.
    3. If interested in joining the team, complete this form Team Roster Onboarding Form.
    4. Join the Civic Tech Jobs Slack channel and introduce yourself and mention the role you are interested in. Our PM's will help you get onboarded with the following steps.
    5. Accept your Google Drive invite to access the shared folder.
    6. Review the Glossary.
    7. Attend our monthly all team meeting on the third Tuesday at 5pm PST. You can find the link pinned in our slack channel.
    "},{"location":"joining-the-team/intro/#who-are-you","title":"Who are you?","text":"

    Click the link that applies to you to find a sequence of immediate action steps:

    Web Developer

    UI/UX Designer

    UI/UX Researcher

    Data Scientist

    Content Writer

    Product Manager/Owner

    Other Volunteer

    "},{"location":"joining-the-team/intro/#accessibility-standards","title":"Accessibility standards","text":"

    Title III of the Americans with Disabilities Act (ADA) requires that all sites be accessible to people with disabilities. The World Wide Web (W3C) Consortium's Web Content Accessibility Guidelines (WCAG) 2.0 Level AA function as the current legal standard for site accessibility.

    Get acquainted with accessibility: https://www.ada.gov/pcatoolkit/chap5toolkit.htm

    "},{"location":"joining-the-team/other-volunteer/","title":"Other Volunteer","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"joining-the-team/other-volunteer/#other-volunteer","title":"Other Volunteer","text":"
    1. Get an overview of the project from the Wiki.

    2. Review the Project Board.

    3. Chat with a [INSERT PROJECT NAME HERE] PM to discuss your interest and background.

    "},{"location":"joining-the-team/product-manager/","title":"Project Manager","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"joining-the-team/product-manager/#product-manager-and-owner","title":"Product Manager and Owner","text":"

    Each of the resources below can be considered a work-in-progress. These resources will evolve and adapt as the team and team needs change. Feel free to open an issue with a link to whichever resource needs improvement and a description of the suggested change.

    1. Learn how we setup our GitHub Kanban boards and please comment if there is anything in the document that is unclear.

    2. This Software Development Lifecycle Diagram is a sample of what the process is generally like at Hack for LA and each project is different.

    3. Review our OKRS.

    4. Communicate with other product team members and leadership to discuss project priorities and strategic direction.

    5. Review the Project Board and the Product Management issues available on that board to identify an actionable backlog item.

    6. Review Hack for LA Product Management Templates.

    "},{"location":"joining-the-team/uiux-designer/","title":"UI/UX Designer","text":""},{"location":"joining-the-team/uiux-designer/#starting-checklist","title":"Starting Checklist","text":"
    1. Review the UI/UX issues on the Project Management Board and identify an actionable backlog item.

    2. Communicate with PM your interest in being assigned a task.

    3. Ask your lead to invite you to the Civic Tech Jobs figma workspace

    4. Leads should send invite to team members AFTER they have been added to the Google Drive and put their information into the team roster.
    "},{"location":"joining-the-team/uiux-designer/#additional-reading","title":"Additional Reading","text":"
    1. This is a generic software development lifecycle diagram for Hack for LA. We would like to talk to you about how this project is different.

    2. Read about WCAG 2.0 accessibility standards.

    "},{"location":"joining-the-team/uiux-researcher/","title":"UI/UX Researcher","text":""},{"location":"joining-the-team/uiux-researcher/#getting-started","title":"Getting Started","text":""},{"location":"joining-the-team/uiux-researcher/#research-documents","title":"Research Documents","text":"
    • Completed Research
    • In Progress Research
    • Researching being audited
    • WIKI Template for Research
    "},{"location":"joining-the-team/web-developer/","title":"Web Developer","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"joining-the-team/web-developer/#web-developer","title":"Web Developer","text":""},{"location":"joining-the-team/web-developer/#starting-checklist","title":"Starting Checklist","text":"
    1. Read the development Readme and the CONTRIBUTING.md file set up your development environment.

    2. Review the project board by the type of issue you are looking for. The Frontend Coding Project Board or the Backend Coding Project Board. Or you can check out the entire project board here.

    3. Communicate with the PM about your interest in being assigned a task.

    4. Your first commit will likely be an issue labeled good first issue. Check the board for those issues. Don't worry if you don't see anything now, we are working on it.

    "},{"location":"joining-the-team/web-developer/#additional-reading","title":"Additional Reading","text":"
    1. Read about WCAG 2.0 accessibility standards and set up third-party tools for compliance testing.

    2. Review notes on security updates.

    3. Site architecture document is coming soon.

    "},{"location":"misc/ada-guide/","title":"ADA Guide","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"misc/ada-guide/#ada-guide","title":"ADA Guide","text":""},{"location":"misc/ada-guide/#which-accessibility-testing-tool-should-you-use","title":"Which accessibility testing tool should you use?","text":""},{"location":"misc/ada-guide/#overview","title":"Overview","text":"

    There are more than 100 accessibility testing tools. Figuring out which ones to use can be a black hole. For guidance we recommend this article: Which accessibility testing tool should you use?

    "},{"location":"misc/ada-guide/#summary-of-article","title":"Summary of Article","text":"

    The author recommends using the tools in the following order fixing as you go along, since no one tool catches all the relevant issues

    aXe SiteImprove Tenon WAVE Lighthouse

    But if you want to test your site with other tools, here is a bigger list

    "},{"location":"misc/glossary/","title":"Glossary","text":"

    DRAFT NOT YET FILLED OUT

    "},{"location":"misc/glossary/#glossary","title":"Glossary","text":"

    When we have a shiny glossary it will come here.

    Term Alternate terms Official Link Description"},{"location":"misc/history/","title":"History","text":"

    How Hack for LA evolved from in person onboarding to remote, and the iterative approach that we have taken to arrive at the need for a dedicated interface to list volunteer opportunities.

    "},{"location":"misc/history/#pre-covid-times","title":"Pre-Covid times","text":"

    Hack for LA practiced in person recruiting on onboarding nights. It had its own benefits, like each volunteer felt valued and had agency

    "},{"location":"misc/history/#2020-mid-2021","title":"2020-mid 2021","text":"

    The team later moved on to a new process where the open roles on each team were posted on the Hack For LA site. This led to:

    • Some volunteers contacted teams directly and the teams became responsible for all onboarding, which was inefficient use of time, leading to poor cohesiveness of our org (onboarding conducted differently by various people and projects). And some projects got too many volunteers but not the right skill level. Ultimately this method led to high turnover of volunteers and product managers getting burnt out.
    • Other volunteers attending a Zoom onboarding session (held weekly). In this process the project leads would show up to recruit at the end, but sometimes there would be no one who could fill the domain specific role. This process was also inefficient.
    "},{"location":"misc/history/#mid-2021-current","title":"mid 2021- current","text":"

    Hack for LA moved to a new model where all new volunteer attend onboarding and then join a communities of practice (CoP) and no open roles are posted on the hackforla.org site. These CoPs have volunteer opportunity boards so that when project leads recruit, they can go to a larger group of people who are more likely to be a good fit for the role available. Also CoP leads can help provide coaching if someone is unsure of if they are a good fit. Listings at CoP allow the org to determine if the project is actually ready to receive volunteers.

    The Hack for LA organization team has now green lighted a project to create a dedicated job board page where volunteers can search and find volunteer opportunities that match their goal and aspirations while still maintaining the involvement of onboarding and CoPs.

    "},{"location":"misc/our-process/","title":"Our Process","text":"

    This page has links and details such as links to a spreadsheet with our research, etc. and what order we did things in. But less narrative and mostly links

    "},{"location":"misc/research-wiki-template/","title":"Template for presenting research on wiki","text":"
    # [Name of Research]\n\n## Research Date:\n\n## Current Status\n\n## Overview Issue #:\n\n## Outstanding task items\n\n## Assets\n\n### Research Plan (including Audience Identification documentation)\n\n### Scripts\n\n### Interview recordings & Transcripts\n\n### Synthesis (Miro or Figjam)\n\n### Presentation of Findings\n\n### Action Items Spreadsheet\n
    "},{"location":"misc/security-updates/","title":"Security Updates","text":"

    This project subscribes to GitHub's automated security alerting service. Occasionally the repository home page may have a yellow banner saying \"We have found a potential security vulnerability in one of your dependencies\" and a link to view the security alert. If you see this, please check our issues list to see if anyone has added an issue for fixing this. If not, please create an issue for this problem. If you feel up to it, please assign the issue to yourself and try to fix it. As with any issue, once you have fixed it on your fork of the repository, push the fixes to your fork and then open a pull request to merge this fix into the main repository.

    GitHub's \"dependabot\" may try to generate an automated pull request to fix this issue. Please do not accept this pull request without verifying that it works by applying the update on your local copy of the site.

    "},{"location":"misc/the-team/","title":"The Team","text":"Name Role Joyce Guo Product Manager Sabrina Heasley Product Manager Salima Yacoubi Soussane Product Manager Bitian Zhang Full Stack Developer Matt Pereira Full Stack Developer Will Gillis Full Stack Developer Sarah Sanger Software Developer Benny Van Software Developer Jen Chung UX/UI Designer Lead Tin Wei, Chung UX/UI Designer Lu Feng UX/UI Designer Gabriel Vicencio UX/UI Designer Melinda Sukosd UX Researcher Lead Leah Ellis UX Researcher Jenn Wu UX Researcher Nga Do UX Researcher"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..7e701e4b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,111 @@ + + + + https://hackforla.github.io/CivicTechJobs/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/resources/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/backend/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/design-system/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/development-culture/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/devops/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/frontend/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/github/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/installation/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/mkdocs-architecture/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/mkdocs-edit-instructions/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/developer/mkdocs-guide/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/content-writer/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/data-scientist/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/intro/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/other-volunteer/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/product-manager/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/uiux-designer/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/uiux-researcher/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/joining-the-team/web-developer/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/ada-guide/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/glossary/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/history/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/our-process/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/research-wiki-template/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/security-updates/ + 2024-10-10 + + + https://hackforla.github.io/CivicTechJobs/misc/the-team/ + 2024-10-10 + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..917ce413814410e497eb98ec51c6718d38ef622a GIT binary patch literal 464 zcmV;>0Wba^iwFn+83$(q|8r?{Wo=<_E_iKh0L_=pZrd;nfbV^Zz;{_`vBNeb?qR?V zJ9iJDNUY6977dY#o3|hBWZll&!4eEu7HIJU|3n?0-^aMSKxU+LY#!TvvxDR*VCs*} z&zJA!bMxFi97>K1vQy#2$7T?jzFIrabIT|&x`|uLy=6b>2iyCi-M3$w?qR26+2A%? z$03sMmR(r48Js`AQjV_eQHFAAk?c3Tpnm~B{Gb!tgI(nR{@t;R6uPJV(H<3(`6pA&K!NO36?S7)_M~ z(QBq8)kM)vq7D{JEG|YTS`F(U8qa||8<+i{Mb+06(04EhC}uHRE`G5ZS4Gzs44c~P zjWFp^YGeQ-;704$)Dtsjb!V;$EjV$8Jt`iuRE35~GF3%HI?Lulv8X>QbL5mMXf~SB zCD&KRR#WX z#c2BLeT6q?`JGE<#xrUhkCQf5+s6!pFM9Z1O_}t>gYE6~k>&pkvcB|w-u(h?r5$k3 G4*&o-j^alE literal 0 HcmV?d00001