diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index 65d653a6da81fea5b15834ccedecd63583ef90f9..1f5980c2acd18f2193c9f7192a805769f18a6131 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -10,7 +10,7 @@ const nodemon = require('gulp-nodemon');
 
 const Cache = require('gulp-file-cache');
 
-const jsdoc = require('gulp-jsdoc3');
+const docco = require('gulp-docco');
 
 const cache = new Cache();
 
@@ -38,12 +38,14 @@ function compile() {
 
 gulp.task('build', compile);
 
-gulp.task('doc', (cb) => {
-    let config = require('./jsdoc.json');
-    gulp.src(['README.md', './src/**/*.js'], {read: false})
-        .pipe(jsdoc(config, cb));
+gulp.task('docco', () => {
+    gulp.src('./src/**/*.js')
+        .pipe(docco())
+        .pipe(gulp.dest('./docs'));
 });
 
+gulp.task('doc', ['docco']);
+
 gulp.task('test', () => {
   gulp.src('test/test.js', {read: false})
     .pipe(mocha())
diff --git a/package.json b/package.json
index 87652e4ad3aadf65ba1a5cdf3b06b8f20da31854..5973ed2a9f2897def179077fada4c2075032f841 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
     "gulp": "^3.9.1",
     "gulp-babel": "^6.1.2",
     "gulp-cli": "^1.2.2",
+    "gulp-docco": "0.0.4",
     "gulp-eslint": "^3.0.1",
     "gulp-file-cache": "0.0.1",
     "gulp-jsdoc3": "^0.3.0",
diff --git a/src/libs/app.js b/src/libs/app.js
index 8022c769b3557c3029b11edf46afe1235a596fcf..c16c805f3ff2ac360d62fcdf3d771bcd5c5e366c 100644
--- a/src/libs/app.js
+++ b/src/libs/app.js
@@ -18,25 +18,30 @@ const mongoose = require('./db/mongoose');
 
 const db = mongoose();
 
+// Set default node environment
 process.env.NODE_ENV = process.env.NODE_ENV || 'development';
 
+// Parse json received in requests
 app.use(bodyParser.json());
 app.use(bodyParser.urlencoded({ extended: false }));
 app.use(cookieParser());
+// Enable Cross-Origin Resource Sharing (CORS)
 app.use(cors());
 app.use(methodOverride());
+// Enable cache for 1 day
 app.use(cache('1 day'));
+// Enable maximum compression
 app.use(compression(9));
 app.use(api);
 
-// catch 404 and forward to error handler
+// Catch 404 and forward to error handler
 app.use((req, res, next) => {
     res.status(404);
     log.debug('%s %d %s', req.method, res.statusCode, req.url);
     res.json({ error: 'Not found' }).end();
 });
 
-// error handlers
+// Error handlers
 app.use((err, req, res, next) => {
     res.status(err.status || 500);
     log.error('%s %d %s', req.method, res.statusCode, err.message);
diff --git a/src/libs/config.js b/src/libs/config.js
index ef5a26cddbb3946b89ac690e8cf52d28884463aa..5aea5a9ca50efd0dac2253dd23690229431236dc 100644
--- a/src/libs/config.js
+++ b/src/libs/config.js
@@ -1,5 +1,6 @@
 const nconf = require('nconf');
 
+// Exports the config.json as an object with get functions
 nconf.argv()
     .env()
     .file({ file: `${process.cwd()}/config.json` });
diff --git a/src/libs/db/monet.js b/src/libs/db/monet.js
index 1cf874cc9ca5a2ada3e20bdd077c34fbcfbe8226..dd7e620adcf5b6a1dbe29358697fa71a3970ea03 100644
--- a/src/libs/db/monet.js
+++ b/src/libs/db/monet.js
@@ -4,10 +4,12 @@ const libs = `${process.cwd()}/libs`;
 
 const config = require(`${libs}/config`);
 
+// Connection options
 const poolOptions = {
     nrConnections: config.get('monetdb:nrConnections'),
 };
 
+// Configuration options
 const options = {
     host: config.get('monetdb:host'),
     port: config.get('monetdb:port'),
@@ -16,6 +18,7 @@ const options = {
     password: config.get('monetdb:password'),
 };
 
+// Connection singleton
 const conn = new MonetDBPool(poolOptions, options);
 conn.connect();
 
diff --git a/src/libs/db/mongoose.js b/src/libs/db/mongoose.js
index 13b3950da47638b2183ffb5e9c72dab41303c6d3..b1a078fd26b5a13c987c5c3e17a899cd0f10cdf2 100644
--- a/src/libs/db/mongoose.js
+++ b/src/libs/db/mongoose.js
@@ -7,8 +7,10 @@ const log = require(`${libs}/log`)(module);
 const mongoose = require('mongoose');
 
 module.exports = () => {
+    // Get mongodb URI (ip and port) in config file
     const mongoUri = config.get('mongodb:uri');
     log.debug(`Connecting to MongDB on URI ${mongoUri}`);
+    // Connection singleton
     const db = mongoose.connect(mongoUri);
 
     mongoose.connection.once('open', () => { log.info("MongoDB connected"); });
diff --git a/src/libs/db/query_exec.js b/src/libs/db/query_exec.js
index bd921d1d02deec90101260046707b7929434a10a..71ae6d9824ac304eb5fd4e4d0e122b16d8d159a2 100644
--- a/src/libs/db/query_exec.js
+++ b/src/libs/db/query_exec.js
@@ -1,40 +1,41 @@
+
 const libs = `${process.cwd()}/libs`;
 
 const log = require(`${libs}/log`)(module);
 
 const conn = require(`${libs}/db/monet`);
 
-/**
- * Promise that executes an SQL query with optional parameters
- *
- * Examples:
- *   Query with no parameters:
- *     execSqlQuery('SELECT * FROM people');
- *   Query with one parameter:
- *     execSqlQuery('SELECT name, age FROM people WHERE id = ?', [1]);
- *   Query with more than one parameter:
- *     execSqlQuery('SELECT name, age FROM people WHERE city = ? AND age > ?', ['São Paulo', 35]);
- *
- * @param {string} sqlQuery       - SQL query to be executed by the Promise
- * @param {array}  sqlQueryParams - SQL query parameters
- */
+ // Promise that executes an SQL query with optional parameters
+ // ```
+ // Examples:
+ //   Query with no parameters:
+ //     execSqlQuery('SELECT * FROM people');
+ //   Query with one parameter:
+ //     execSqlQuery('SELECT name, age FROM people WHERE id = ?', [1]);
+ //   Query with more than one parameter:
+ //     execSqlQuery('SELECT name, age FROM people WHERE city = ? AND age > ?', ['São Paulo', 35]);
+ // ```
 function execSqlQuery(sqlQuery, sqlQueryParams = []) {
     log.debug(`Executing SQL query '${sqlQuery}' with params '${sqlQueryParams}'`);
     return new Promise((resolve, reject) => {
+        // Prepare statement
         conn.prepare(sqlQuery, true).then(
             (dbQuery) => {
+                // Execute query
                 dbQuery.exec(sqlQueryParams).then(
+                    // Success
                     (dbResult) => {
                         log.debug(`Query result: ${dbResult.data}`);
                         log.debug(dbResult.data);
                         resolve(dbResult.data);
                     },
+                    // Error
                     (dbError) => {
                         log.error(`SQL query execution error: ${dbError.message}`);
                         reject(new Error(dbError.message));
                     }
                 );
-                // release resources allocated for prepared statement
+                // Release resources allocated for prepared statement
                 conn.release();
             }
         );
diff --git a/src/libs/middlewares/dimensions.js b/src/libs/middlewares/dimensions.js
index 618a510e028742dbbf4a8e9ca04d19d936d9e39e..6d66e901fa835845e304b79ae54a398afc0103da 100644
--- a/src/libs/middlewares/dimensions.js
+++ b/src/libs/middlewares/dimensions.js
@@ -1,23 +1,5 @@
-/**
-* Dimensions middleware
-*
-* EXAMPLE:
-* Use it with no parameters to get all the dimensions specified
-* app.get('/', dimensions(), function(req, res, next){})
-*
-* Use it with an array of accepted values
-* app.get('/', dimensions(['year', 'location']), function(req, res, next){})
-*
-* Use it globally
-* app.use(dimensions())
-*/
 
-/**
- * This function returns the intersection of two arrays
- * @param  {array} a [description]
- * @param  {array} b [description]
- * @return {array}   [description]
- */
+// This function returns the intersection of two arrays
 function intersect(a, b) {
     let t;
     if (b.length > a.length) {
@@ -26,23 +8,35 @@ function intersect(a, b) {
     return a.filter((e) => b.indexOf(e) !== -1);
 }
 
+// Dimensions middleware
+// ```
+// EXAMPLE:
+// Use it with no parameters to get all the dimensions specified
+// app.get('/', dimensions(), function(req, res, next){})
+//
+// Use it with an array of accepted values
+// app.get('/', dimensions(['year', 'location']), function(req, res, next){})
+//
+// Use it globally
+// app.use(dimensions())
+// ```
 function dimensions(dims) {
     return (req, res, next) => {
         req.dims = {};
         if (req.query.dims) {
+            // Split the string and get all dimensions.
+            // Example string: 'state:41,year:2013,urban'
             const params = req.query.dims.split(',');
             const dimObj = {};
+            // For each dimension in the array see if there is a value associated
             for (const param of params) {
                 const kv = param.split(':');
                 dimObj[kv[0]] = (typeof kv[1] === 'undefined') ? null : kv[1];
             }
-            // for(let i=0; i<params.length; ++i) {
-            //     let kv = params[i].split(':');
-            //     dimObj[kv[0]] = (typeof kv[1] === 'undefined') ? null : kv[1];
-            // }
 
             // If the dims array exists and is not empty
             if (typeof dims !== 'undefined' && dims.length > 0) {
+                // Intersect the two arrays
                 const intersection = intersect(dims, Object.keys(dimObj));
                 for (let i = 0; i < intersection.length; ++i) {
                     req.dims[intersection[i]] = dimObj[intersection[i]];
diff --git a/src/libs/middlewares/query.js b/src/libs/middlewares/query.js
index 74a0c505cf02285dde3a35c0d0fc6365b8b4ce86..a3435dec4c2d2f37a167b6749e1c6aea0b9d1368 100644
--- a/src/libs/middlewares/query.js
+++ b/src/libs/middlewares/query.js
@@ -2,12 +2,7 @@ const libs = `${process.cwd()}/libs`;
 const log = require(`${libs}/log`)(module);
 const execQuery = require(`${libs}/db/query_exec`);
 
-/**
- * Middleware that executes a query defined by a squel object in req.sql
- * @param  {Object}   req  [description]
- * @param  {Object}   res  [description]
- * @param  {Function} next [description]
- */
+ // Middleware that executes a query defined by a squel object in req.sql
 function query(req, res, next) {
     log.debug(req.sql);
     execQuery(req.sql.text, req.sql.values).then((result) => {
diff --git a/src/libs/middlewares/response.js b/src/libs/middlewares/response.js
index 0b91b39e92f6c73555f3d2f0a6eef5dd11caeb93..d93961442e3b7e6dd14d6eb9c6e634e04957b758 100644
--- a/src/libs/middlewares/response.js
+++ b/src/libs/middlewares/response.js
@@ -3,10 +3,8 @@ const log = require(`${libs}/log`)(module);
 const xml = require('js2xmlparser');
 const csv = require('csv-express');
 
-/**
- * Custom generic middleware used to send api responses
- * @param  {string} value text to be used in the xml response
- */
+ // Custom generic middleware used respond requests.
+ // The function reads the req.query.format param and respond in json, xml or csv
 function response(value) {
     return (req, res, next) => {
         log.debug(req.query.format);
diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 06953296641bdfa2cf76154bca9e593f17fcc540..914abaa77d6c4acaca36fb07a7f1c9eeeeddfbc6 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -12,11 +12,11 @@ const city = require('./city');
 
 const school = require('./school');
 
+// API status route
 api.get('/api/v1', (req, res) => {
     res.json({ msg: 'SimCAQ API is running' });
 });
 
-// mount API routes
 api.use('/api/v1/enrollment', enrollment);
 api.use('/api/v1/state', state);
 api.use('/api/v1/region', region);
diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js
index 030aa3cecda6c538a45d12543aa6d9449e685937..cb55e2209d795ac359a287a392a6df1a00f6438f 100644
--- a/src/libs/routes/city.js
+++ b/src/libs/routes/city.js
@@ -10,23 +10,27 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
+// Return all cities
 cityApp.get('/', (req, res, next) => {
     req.sql = squel.select().from('municipios').toParam();
     next();
 }, query, response('city'));
 
+// Return a specific city by it's id
 cityApp.get('/:id', (req, res, next) => {
     req.sql = squel.select().from('municipios').where('pk_municipio_id = ?',
         parseInt(req.params.id, 10)).toParam();
     next();
 }, query, response('city'));
 
+// Return a specific city by it's IBGE code
 cityApp.get('/ibge/:id', (req, res, next) => {
     req.sql = squel.select().from('municipios').where('codigo_ibge = ?',
         req.params.id).toParam();
     next();
 }, query, response('city'));
 
+// Return all the cities from a specific state
 cityApp.get('/state/:id', (req, res, next) => {
     req.sql = squel.select().from('municipios').where('fk_estado_id = ?',
         parseInt(req.params.id, 10)).toParam();
diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 0ec49b84abb4dac94d3bce2b838c6c51ac038175..6b37b35c4af4983329221759e98ba43989ca3956 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -35,45 +35,36 @@ function filter(req, q) {
     }
 }
 
-/**
- * Complete range of the enrollments dataset
- *
- * Returns a tuple of start and ending years of the complete enrollments dataset.
- */
+// Complete range of the enrollments dataset.
+// Returns a tuple of start and ending years of the complete enrollments dataset.
 enrollmentApp.get('/year_range', (req, res, next) => {
     req.sql = squel.select()
-        .from('turmas')
-        .field('MIN(turmas.ano_censo)', 'start_year')
-        .field('MAX(turmas.ano_censo)', 'end_year')
-        .toParam();
+    .from('turmas')
+    .field('MIN(turmas.ano_censo)', 'start_year')
+    .field('MAX(turmas.ano_censo)', 'end_year')
+    .toParam();
 
     next();
 }, query, response('range'));
 
-/**
- * Returns all educational levels avaible
- *
- */
+// Returns all educational levels avaible
 enrollmentApp.get('/education_level', (req, res, next) => {
     req.sql = squel.select()
-        .from('etapa_ensino')
-        .field('pk_etapa_ensino_id', 'id')
-        .field('desc_etapa', 'name')
-        .toParam();
+    .from('etapa_ensino')
+    .field('pk_etapa_ensino_id', 'id')
+    .field('desc_etapa', 'name')
+    .toParam();
 
     next();
 }, query, response('education_level'));
 
-/**
- * Returns all adm dependency
- *
- */
+// Returns all adm dependencies
 enrollmentApp.get('/adm_dependency', (req, res, next) => {
     req.sql = squel.select()
-        .from('dependencia_adms')
-        .field('pk_dependencia_adm_id', 'id')
-        .field('nome', 'name')
-        .toParam();
+    .from('dependencia_adms')
+    .field('pk_dependencia_adm_id', 'id')
+    .field('nome', 'name')
+    .toParam();
 
     next();
 }, query, response('adm_dependency'));
@@ -125,9 +116,9 @@ enrollmentApp.use('/', (req, res, next) => {
     if (typeof params.aggregate !== 'undefined' && params.aggregate === 'region') {
         log.debug('Using enrollments query for regions');
         const q = squel.select().from('mat_regioes')
-            .field('name')
-            .field('SUM(total)', 'total')
-            .field('ano_censo', 'year');
+        .field('name')
+        .field('SUM(total)', 'total')
+        .field('ano_censo', 'year');
 
         filter(req, q);
 
@@ -144,9 +135,9 @@ enrollmentApp.use('/', (req, res, next) => {
     if (typeof params.aggregate !== 'undefined' && params.aggregate === 'state') {
         log.debug('Using enrollments query for states');
         const q = squel.select().from('mat_estados')
-            .field('name')
-            .field('SUM(total)', 'total')
-            .field('ano_censo', 'year');
+        .field('name')
+        .field('SUM(total)', 'total')
+        .field('ano_censo', 'year');
 
         filter(req, q);
 
@@ -163,9 +154,9 @@ enrollmentApp.use('/', (req, res, next) => {
     if (typeof params.aggregate !== 'undefined' && params.aggregate === 'city') {
         log.debug('Using enrollments query for cities');
         const q = squel.select().from('mat_municipios')
-            .field('name')
-            .field('SUM(total)', 'total')
-            .field('ano_censo', 'year');
+        .field('name')
+        .field('SUM(total)', 'total')
+        .field('ano_censo', 'year');
 
         filter(req, q);
 
@@ -182,9 +173,9 @@ enrollmentApp.use('/', (req, res, next) => {
     if (typeof params.aggregate !== 'undefined' && params.aggregate === 'school') {
         log.debug('Using enrollments query for schools');
         const q = squel.select().from('mat_escolas')
-            .field('name')
-            .field('SUM(total)', 'total')
-            .field('ano_censo', 'year');
+        .field('name')
+        .field('SUM(total)', 'total')
+        .field('ano_censo', 'year');
 
         filter(req, q);
 
@@ -201,8 +192,8 @@ enrollmentApp.use('/', (req, res, next) => {
     if (typeof params.aggregate === 'undefined') {
         log.debug('Using enrollments query for the whole country');
         const q = squel.select().from('turmas').field("'Brasil'", 'name')
-            .field('COALESCE(SUM(num_matriculas),0)', 'total')
-            .field('ano_censo', 'year');
+        .field('COALESCE(SUM(num_matriculas),0)', 'total')
+        .field('ano_censo', 'year');
 
         filter(req, q);
 
@@ -216,27 +207,4 @@ enrollmentApp.get('/', (req, res, next) => {
     next();
 }, query, response('enrollments'));
 
-// enrollmentApp.get('/', (req, res, next) => {
-//     log.debug(`Request parameters: ${req}`);
-//     if (typeof req.sqlQuery === 'undefined') {
-//         // Should only happen if there is a bug in the chaining of the
-//         // '/enrollments' route, since when no +aggregate+ parameter is given,
-//         // it defaults to use the query for the whole country.
-//         log.error('BUG -- No SQL query was found to be executed!');
-//         next('Internal error, request could not be satisfied at this moment. Please, '
-//             + 'try again later');
-//     } else {
-//         log.debug('SQL query: ${ req.sqlQuery }?');
-//         log.debug(req.sqlQuery);
-//         dbQuery(req.sqlQuery).then((result) => {
-//             req.result = result;
-//             return response(req, res);
-//         }, (error) => {
-//             log.error(`[${req.originalUrl}] SQL query error: ${error}`);
-//             next('Internal error, request could not be satisfied at this moment. Please, '
-//                 + 'try again later');
-//         });
-//     }
-// });
-
 module.exports = enrollmentApp;
diff --git a/src/libs/routes/region.js b/src/libs/routes/region.js
index 754cd6164725bebf8c5d6cfb387b3f0656eb615b..6efb36c48d1c803aaea8a3b20bb24b4ddd62eb41 100644
--- a/src/libs/routes/region.js
+++ b/src/libs/routes/region.js
@@ -10,11 +10,13 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
+// Get all regions
 regionApp.get('/', (req, res, next) => {
     req.sql = squel.select().from('regioes').toParam();
     next();
 }, query, response('region'));
 
+// Get a region by it's id
 regionApp.get('/:id', (req, res, next) => {
     req.sql = squel.select().from('regioes').where('pk_regiao_id = ?',
         parseInt(req.params.id, 10)).toParam();
diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js
index bf3ee4fb1ec97ad326f68f4d536d27776ad64531..255e595b31b59b61479f45b9f2c155bd1d9c8870 100644
--- a/src/libs/routes/school.js
+++ b/src/libs/routes/school.js
@@ -16,23 +16,26 @@ const response = require(`${libs}/middlewares/response`);
  * A api fica sobrecarregada
  * Pense na cena do elevador de driver mas o elevador é uma bomba de fusão e demora mais que uma luta do DBz
  */
-// schoolApp.get('/', (req, res, next) => {
-//     req.sql = squel.select().from('escolas')
-//         .field('pk_escola_id')
-//         .field('nome_entidade', 'name')
-//         .field('ano_censo', 'year')
-//         .field('fk_cod_estado')
-//         .field('fk_cod_municipio')
-//         .toParam();
-//     next();
-// }, query, response('school'));
+/* schoolApp.get('/', (req, res, next) => {
+*     req.sql = squel.select().from('escolas')
+*         .field('pk_escola_id')
+*         .field('nome_entidade', 'name')
+*         .field('ano_censo', 'year')
+*         .field('fk_cod_estado')
+*         .field('fk_cod_municipio')
+*         .toParam();
+*     next();
+* }, query, response('school'));
+*/
 
+// Get a school by it's id
 schoolApp.get('/:id', (req, res, next) => {
     req.sql = squel.select().from('escolas').where('pk_escola_id = ?',
         parseInt(req.params.id, 10)).toParam();
     next();
 }, query, response('school'));
 
+// Get all schools from a state
 schoolApp.get('/state/:id', (req, res, next) => {
     req.sql = squel.select().from('escolas')
         .field('pk_escola_id')
@@ -46,6 +49,7 @@ schoolApp.get('/state/:id', (req, res, next) => {
     next();
 }, query, response('school'));
 
+// Get all schools from a city
 schoolApp.get('/city/:id', (req, res, next) => {
     req.sql = squel.select().from('escolas')
         .field('pk_escola_id')
diff --git a/src/libs/routes/state.js b/src/libs/routes/state.js
index 637149f1a9b9db0fb90a7ccdfaffb4381c406152..7ee58c575d706d57b02bf51f2b4136bab0d8b57f 100644
--- a/src/libs/routes/state.js
+++ b/src/libs/routes/state.js
@@ -10,17 +10,20 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
+// Get all states
 stateApp.get('/', (req, res, next) => {
     req.sql = squel.select().from('estados').toParam();
     next();
 }, query, response('state'));
 
+// Get a state
 stateApp.get('/:id', (req, res, next) => {
     req.sql = squel.select().from('estados').where('pk_estado_id = ?',
         parseInt(req.params.id, 10)).toParam();
     next();
 }, query, response('state'));
 
+// Get all states from a region
 stateApp.get('/region/:id', (req, res, next) => {
     req.sql = squel.select().from('estados').where('fk_regiao_id = ?',
         parseInt(req.params.id, 10)).toParam();
diff --git a/src/server.js b/src/server.js
index 4dde9b8e4231800ac40678ff66fec3086ffcd6af..d9e37caca1a103588bc2ecb90bc0034cea1d3efd 100644
--- a/src/server.js
+++ b/src/server.js
@@ -8,8 +8,10 @@ const log = require(`${libs}/log`)(module);
 
 const app = require(`${libs}/app`);
 
+// Set default port: first environment variable PORT, then configuration and last 3000
 app.set('port', process.env.PORT || config.get('port') || 3000);
 
+// Set default ip: first environment variable IOP, then configuration and last '127.0.0.1'
 app.set('ip', process.env.IP || config.get('ip') || '127.0.0.1');
 
 const server = app.listen(app.get('port'), () => {